- better documentation for contract to contract example
- document Rust contract for contract to contract example
NEAR's MPC allows a NEAR Account to create derivative accounts (public keys) and signatures of transactions for other blockchains.
Several MPC nodes maintain a single public key. This key is combined with your NEAR AccountId (unique) and a chosen "path" offset (chosen by client). This produces a new and unique public key. The generation of signatures via the MPC nodes can only be authorized by same NEAR Account by calling the sign
method of the MPC contract.
The creation of secp256k1 public keys for Bitcoin and EVM chains is currently supported.
- Obtain the MPC public key (near view [MPC_CONTRACT_ID]
public_key
) and hardcode into.env
or code - Choose a path for the derived account (public key) see: Path naming conventions
- Use
./src/kdf.ts -> generateAddress
to generate the derived account address and public key - Use the
sign
method of./src/near.ts -> sign
which calls the MPC contract to sign payload (hash of TX) - Using a library (ethers/bitcoinjs-lib) combine the transaction and signature to create signed transaction
- Broadcast the transaction e.g.
sendRawTransaction
yarn
NEAR_ACCOUNT_ID="[NEAR_TESTNET_ACCOUNT]"
NEAR_PRIVATE_KEY="[NEAR_ACCOUNT_PRIVATE_KEY]"
MPC_PATH="[MPC_PATH]"
MPC_CHAIN="[ethereum|bitcoin]"
MPC_CONTRACT_ID="multichain-testnet-2.testnet"
MPC_PUBLIC_KEY="secp256k1:4HFcTSodRLVCGNVcGc4Mf2fwBBBxv9jxkGdiW2S2CA1y6UpVVRWKj6RX7d7TDt65k2Bj3w9FU4BGtt43ZvuhCnNt"
TATUM_API_KEY=""
(as a user or dev to verify everything works)
- Read the
Installation
steps and set up all environment variables first with.env
file. - Use the commands to generate addresses first.
- Fund these addresses with the Testnet Faucets provided in the links below.
- Use the commands to send funds from your generated addresses.
yarn start [commands]
- -ea - ethereum addressm (0x165002AA8dC4ED29f9e49793912a2b946a1d971f) bc1qnvmfvqxyfzrl3wjzgs036wyjr7fg7r42kd6nxea - bitcoin testnet address
- -da - dogecoin testnet address
- -ra - ripple testnet address
- -s - sign sample payload using NEAR account
- -etx - send ETH0xEe21B202212B03070B37320E9c2d7041FFcEAd31
- -btx - send BTCbc1p8fmhtw69mn0uzxuep5ngll44m2rsdatfr2zv290ummzlxxde9uus3zg82g
- -dtx - send DOGE (requires API KEY)
- -rtx - send XRP
- --amount - amount to send (ETH or sats)
- --to - destination address
Usage: yarn start [commands]
- -d, -edc - deploy contract
- --to - the contract address to view/call
- -v, -view - view contract state (readonly call)
- -c, -call - call contract method
- --path - path to EVM bytecode file from root of this project
- --method - name of method view/call
- --args - arguments e.g. '{"address":"0xEe21B202212B03070B37320E9c2d7041FFcEAd31"}' in single quotes
- --ret - list of return parameter types (if any) e.g. ['uint256']
After setting up all your environment variables and ensuring your calling EVM address has ETH for gas.
Start by deploying a new NFT contract:
yarn start -d
Check explorer link and make sure contract is deployed successfully.
Take contract address from console result and call:
yarn start -c --to 0x[CONTRACT ADDRESS FROM STEP 1]
This will mint a token to default address 0xEe21B202212B03070B37320E9c2d7041FFcEAd31
.
View the balanance of the default address using:
yarn start -v --to 0x[CONTRACT ADDRESS FROM STEP 1]
Which should output 1
the NFT balance of default address 0xEe21B202212B03070B37320E9c2d7041FFcEAd31
To deploy the NEAR contract use cargo-near
.
Install cargo-near
and near-cli
- cargo-near - NEAR smart contract development toolkit for Rust
- near CLI-rs - Iteract with NEAR blockchain from command line
cargo build
cargo near create-dev-account
cargo near deploy [ACCOUNT_ID]
The NEAR contract has the following features:
sign
method accepts a payload that is the unhashed RLP encoded EVM transaction data e.g.6a627842000000000000000000000000525521d79134822a342d330bd91DA67976569aF1
calls the methodmint
with an address argument of525521d79134822a342d330bd91DA67976569aF1
PUBLIC_RLP_ENCODED_METHOD_NAMES
stores public EVM method name hashes that can be called from this NEAR contract to the destination address e.g. the method namemint
hashes6a627842000000000000000000000000
COST
must be paid in NEARpath
andkey_version
arguments are passed through to MPCsign
call, but in the future could be used as additional features for applications or security
To use, set the following .env
vars accordingly:
NEAR_PROXY_ACCOUNT="true"
NEAR_PROXY_CONTRACT="true"
NEAR_PROXY_ACCOUNT_ID="futuristic-anger.testnet"
NEAR_PROXY_PRIVATE_KEY="ed25519:..."
With NEAR_PROXY_CONTRACT="true"
the script will call sign
method of the proxy contract you deployed using cargo near deploy
.
To verify, send some ETH using yarn start -etx
.
With NEAR_PROXY_ACCOUNT="false"
you will not be able to send ETH using the sign
method of the proxy contract. Why? Because this would mean any NEAR account can send ETH from the derived account of the proxy contract. Oh no! The proxy contract protects against arbitrary transactions using this check:
let owner = env::predecessor_account_id() == env::current_account_id();
// check if rlp encoded eth transaction is calling a public method name
let mut public = false;
for n in PUBLIC_RLP_ENCODED_METHOD_NAMES {
if rlp_payload.find(n).is_some() {
public = true
}
}
// only the NEAR contract owner can call sign of arbitrary payloads for chain signature accounts based on env::current_account_id()
if !public {
require!(
owner,
"only contract owner can sign arbitrary EVM transactions"
);
}
Enjoy!
Live Example - NEAR Testnet, Sepolia, Bitcoin Testnet