This library enables Internet Computer canisters to sign transactions for EVM-compatible blockchains.
This is a two-part process:
- Create new addresses on the Internet Computer using distributed ECDSA key generation
- Sign transactions with these addresses as the canister itself or in behalve of the canister users using threshold ECDSA signatures
There an example project at ic-evm-sign-starter.
- Create EVM addresses
- Sign EVM transactions
- Manages transaction nonce
- Supports different chain ids
- Takes care of various tx types
Supported Tx Types: Legacy, EIP1559, EIP2930
You can get start quickly with ic-evm-sign-starter.
Run cargo add ic-evm-sign
in your project
Create a new EVM-compatible address from a canister
use ic_evm_sign;
#[update]
async fn create_address() -> Result<String, String> {
let principal_id = ic_cdk::caller();
let response = ic_evm::create_address(principal_id).await
.map_err(|e| format!("Failed to create address {}", e))
.unwrap();
Ok(response.address)
}
Test locally with:
dfx canister call ${canister_name} create_address
Sign an EVM-compatible transaction from a canister
use ic_evm_sign;
#[update]
async fn sign_tx(hex_raw_tx: Vec<u8>) -> Result<String, String> {
let chain_id = 1;
let principal_id = ic_cdk::caller();
let response = ic_evm_sign::sign_transaction(hex_raw_tx, chain_id, principal_id).await
.map_err(|e| format!("Failed to sign transaction {}", e))
.unwrap();
Ok(response.sign_tx)
}
Test it locally with:
dfx canister call ${canister_name} sign_tx '(vec {${hex_raw_tx}}: vec nat8)'
dfx canister call ${canister_name} sign_tx '(vec {236; 128; 133; 5; 66; 135; 40; 189; 130; 117; 48; 148; 112; 153; 121; 112; 197; 24; 18; 220; 58; 1; 12; 125; 1; 181; 14; 13; 23; 220; 121; 200; 136; 13; 224; 182; 179; 167; 100; 0; 0; 0; 128; 128; 128}: vec nat8)'
For transaction hex:
0xec808505428728bd8275309470997970c51812dc3a010c7d01b50e0d17dc79c8880de0b6b3a764000000808080
- Receive principal from the canister
- Creates a new ECDSA public key on IC
- Calculates the EVM address from the public key
- Saves the new address to the canister state based on principal
- Receive a raw transaction, chain id and a principal from the canister
- Gets principal's public key from the canister state
- Prepares "message" to sign from raw transaction and chain id
- Signs "message" to sign and gets transaction signature
- Calculates recovery id from "message" to sign, signature and public key
- And then gets the signed transaction from raw transaction, chain id and recovery id
- Stores the transaction to the canister state based on principal
Use a different EVM-compatible blockchain using chain_id
in:
ic_evm_sign::sign_transaction(hex_raw_tx, chain_id, principal_id)
Find chain ids at: https://chainlist.org
You can sign different transaction types hex by passing their corresponding hex using hex_raw_tx
in:
ic_evm_sign::sign_transaction(hex_raw_tx, chain_id, principal_id)
Find transaction types at: https://github.com/ethereum/execution-specs
- Download the repo with
git clone
- Run unit tests with
cargo test
- Install dependencies with
npm i
ine2e/tests
- Then run the e2e script with
make e2e-test
The code in this library has not been audited (as of 13/1/22). Use it at your own risk. The same applies for ic-evm-sign-starter.
This library was initially incentivized by ICDevs.