Implementing Chain Signatures
Chain signatures enable NEAR accounts, including smart contracts, to sign and execute transactions across many blockchain protocols.
This unlocks the next level of blockchain interoperability by giving ownership of diverse assets, cross-chain accounts, and data to a single NEAR account.
Create a Chain Signature
There are five steps to create a Chain Signature:
- Deriving the Foreign Address - Derive the address that will be controlled on the target blockchain.
- Creating a Transaction - Create the transaction or message to be signed.
- Requesting a Signature - Call the NEAR MPC contract requesting it to sign the transaction.
- Formatting the Signature - Format the signature from the MPC contract and add it to the transaction.
- Relaying the Signed Transaction - Send the signed transaction to the destination chain for execution.
Diagram of a chain signature in NEAR
The chainsig.js library provides a convenient interface for completing each of these steps.
For building transactions inside of NEAR smart contracts written in Rust, you can use the Omni Transaction library to easily build transactions for different blockchains (like Bitcoin and Ethereum).
There is an MPC contract available on both mainnet
and testnet
:
- Mainnet:
v1.signer
- Testnet:
v1.signer-prod.testnet
The MPC network is made up of 8 nodes.
Chain Adapters
Before being able to use the methods the chainsig.js library provides, we need to instantiate the relevant chain adapter object.
- Ξ EVM
- ₿ Bitcoin
- ◎ Solana
Loading...
The EVM chain adapter takes the MPC contract address
as an argument as well as publicClient
which is constructed from an EVM RPC URL.
To use different EVM networks just specify an RPC URL for the EVM network you require. A list of different EVM RPC URLs can be found here.
Loading...
The Bitcoin chain adapter takes the MPC contract address
as an argument as well as the network
("mainnet", "testnet" or "regtest") and a btcRpcAdapter
which handles communication with the Bitcoin network.
Loading...
The Solana chain adapter takes the MPC contract address
as an argument as well as a connection
which is constructed from a Solana RPC URL. If you want to use Mainnet, then you need to choose a Mainnet RPC.
1. Deriving the Foreign Address
Chain Signatures use derivation paths
to represent accounts on the target blockchain. The foreign address to be controlled can be deterministically derived from:
- The NEAR account calling the MPC contract (e.g.,
example.near
,example.testnet
, etc.) - A derivation path (a string such as
ethereum-1
,ethereum-2
, etc.) - The MPC service's master public key (we don't need to worry about this as it is defined in the library we're using).
To derive the address call the deriveAddressAndPublicKey
method passing the near account Id from which the address is being derived and the derivation path.
- Ξ EVM
- ₿ Bitcoin
- ◎ Solana
Loading...
Loading...
Loading...
On Solana, your address is the same as your public key.
The same NEAR account and path will always produce the same address on the target blockchain.
example.near
+ethereum-1
=0x1b48b83a308ea4beb845db088180dc3389f8aa3b
example.near
+ethereum-2
=0x99c5d3025dc736541f2d97c3ef3c90de4d221315
2. Creating the Transaction
To construct the transaction to be signed use the method prepareTransactionForSigning
.
- Ξ EVM
- ₿ Bitcoin
- ◎ Solana
- Transfer
- Function Call
Constructing a transaction to transfer ETH is very simple. The value
is the amount of ETH in Wei as type BigInt (1 ETH = 1018 Wei).
Loading...
To call a function on a smart contract we need the ABI of the contract, in our repo this is defined in the config.js file (this can be gathered from Remix or using Etherscan).
Then define a Contract
object using the ethers
library
Loading...
Then to construct the transaction
Loading...
This method returns the unsigned transaction
and the transaction hash(es)
(also known as the payload
).
Constructing a transaction to transfer BTC is very simple. The value
is the amount of BTC in satoshis as a string (1 BTC = 100,000,000 sats).
Loading...
This method returns the unsigned transaction
and the transaction hash(es)
(also known as the payload
).
Constructing a transaction to transfer SOL is very simple. The value
is the amount of SOL in lamports as type BigInt (1 SOL = 1,000,000,000 lamports).
Loading...
This method returns the unsigned transaction
.
3. Requesting the Signature
Once the transaction is created and ready to be signed, a signature request is made by calling sign
on the MPC smart contract.
The method requires three parameters:
- The
payload
(or hash) to be signed for the target blockchain - The derivation
path
for the account we want to use to sign the transaction - The
key_version
,0
forSecp256k1
signatures and1
forEd25519
signatures.
- Ξ EVM
- ₿ Bitcoin
- ◎ Solana
Loading...
Loading...
For Bitcoin, it is common to have multiple UTXOs to sign when sending a single transaction. We create a NEAR transaction (to call sign
on the MPC contract) for each UTXO and send them to be signed by the MPC individually. Each signature is then parsed from each transaction outcome to produce an array of signatures.
To get the payload, serialize the transaction to a uint8Array
and then convert it to hex.
Loading...
The contract will take some time to respond, as the sign
method yields execution, waiting for the MPC service to sign the transaction.
4. Formatting the Signature
Once the signature is returned from the MPC it needs to be formatted and added to the transaction to produce a signed transaction.
- Ξ EVM
- ₿ Bitcoin
- ◎ Solana
Loading...
Loading...
For Bitcoin, the array of signatures is added to the transaction to produce a complete signed transaction.
Loading...
5. Relaying the Signed Transaction
Now that we have a signed transaction, we can relay it to the target network using broadcastTx
.
- Ξ EVM
- ₿ Bitcoin
- ◎ Solana
Loading...
Loading...
Loading...
The method returns a transaction hash which can be used to locate the transaction on an explorer.
⭐️ For a deep dive into the concepts of Chain Signatures, see What are Chain Signatures?
⭐️ For a complete example of a NEAR account using chain signatures in a frontend, see our web app example.