Skip to main content

Basic Ethereum

This tutorial will walk you through how to deploy a sample canister smart contract that can send and receive Ether (ETH) on the Internet Computer.

Architecture

This example internally leverages the threshold ECDSA and HTTPs outcalls features of the Internet Computer.

For a deeper understanding of the ICP < > ETH integration, see the Ethereum integration overview.

Prerequisites

Step 1: Building and deploying sample code

Clone the smart contract

To clone and build the smart contract in Rust:

git clone https://github.com/dfinity/examples
cd examples/rust/basic_ethereum
git submodule update --init --recursive

If you are using MacOS, you'll need to install Homebrew and run brew install llvm to be able to compile the example.

Acquire cycles to deploy

Deploying to the Internet Computer requires cycles (the equivalent of "gas" on other blockchains).

Deploy the smart contract to the Internet Computer

dfx deploy --ic basic_ethereum --argument '(opt record {ethereum_network = opt variant {Sepolia}; ecdsa_key_name = opt variant {TestKey1}})'

What this does

  • dfx deploy tells the command line interface to deploy the smart contract
  • --ic tells the command line to deploy the smart contract to the mainnet ICP blockchain
  • --argument (opt record {ethereum_network = opt variant {Sepolia}; ecdsa_key_name = opt variant {TestKey1}}) initializes the smart contract with the provided arguments:
    • ethereum_network = opt variant {Sepolia}: the canister uses the Ethereum Testnet Sepolia network.
    • ecdsa_key_name = opt variant {TestKey1}: the canister uses a test key for signing via threshold ECDSA that is available on the ICP mainnet. See signing messages for more details.

If successful, you should see an output that looks like this:

Deploying: basic_ethereum
Building canisters...
...
Deployed canisters.
URLs:
Candid:
basic_ethereum: https://a4gq6-oaaaa-aaaab-qaa4q-cai.raw.icp0.io/?id=<YOUR-CANISTER-ID>

Your canister is live and ready to use! You can interact with it using either the command line or using the Candid UI, which is the link you see in the output above.

In the output above, to see the Candid Web UI for your ethereum canister, you would use the URL https://a4gq6-oaaaa-aaaab-qaa4q-cai.raw.icp0.io/?id=<YOUR-CANISTER-ID>. You should see the methods specified in the Candid file basic_ethereum.did.

Step 2: Generating an Ethereum address

An Ethereum address can be derived from an ECDSA public key. To derive a user's specific address, identified on the IC by a principal, the canister uses its own threshold ECDSA public key to derive a new public key deterministically for each requested principal. To retrieve your Ethereum address, you can call the ethereum_address method on the previously deployed canister:

dfx canister --ic call basic_ethereum ethereum_address

This will return an Ethereum address such as ("0x378a452B20d1f06008C06c581b1656BdC5313c0C") that is tied to your principal. Your address will be different. You can view such addresses on any Ethereum block explorer such as Etherscan.

If you want to send some ETH to someone else, you can also use the above method to enquire about their Ethereum address given their IC principal:

dfx canister --ic call basic_ethereum ethereum_address '(opt principal "hkroy-sm7vs-yyjs7-ekppe-qqnwx-hm4zf-n7ybs-titsi-k6e3k-ucuiu-uqe")'

This will return a different Ethereum address as the one above, such as ("0x8d68f7B3cdb40A2E77071077658b01A9EA4B040F").

Step 3: Receiving ETH

Now that you have your Ethereum address, let us send some (Sepolia) ETH to it:

  1. Get some Sepolia ETH if you don't have any. You can for example use this faucet.
  2. Send some Sepolia ETH to the address you obtained in the previous step. You can use any Ethereum wallet (e.g., Metamask) to do so.

Once the transaction has at least one confirmation, which can take a few seconds, you'll be able to see it in your Ethereum address's balance, which should be visible in an Ethereum block explorer, e.g., https://sepolia.etherscan.io/address/0x378a452b20d1f06008c06c581b1656bdc5313c0c.

Step 4: Sending ETH

You can send ETH using the send_eth endpoint on your canister, specifying an Ethereum destination address and an amount in the smallest unit (Wei). For example, to send 1 Wei to 0xdd2851Cdd40aE6536831558DD46db62fAc7A844d, run the following command:

dfx canister --ic call basic_ethereum send_eth '("0xdd2851Cdd40aE6536831558DD46db62fAc7A844d", 1)'

The send_eth endpoint sends ETH by executing the following steps:

  1. Retrieving the transaction count for the sender's address at Latest block height. This is necessary because Ethereum transactions for a given sender's address are ordered by a nonce, which is a monotonically incrementally increasing non-negative counter.
  2. Estimating the current transaction fees. For simplicity, the current gas fees are hard-coded with a generous limit. A real world application would dynamically fetch the latest transaction fees, for example using the eth_feeHistory method in the EVM-RPC canister.
  3. Building an Ethereum transaction (EIP-1559) to send the specified amount to the given receiver's address.
  4. Signing the Ethereum transaction using the sign_with_ecdsa API.
  5. Sending the signed transaction to the Ethereum network using the eth_sendRawTransaction method in the EVM-RPC canister.

The send_eth endpoint returns the hash of the transaction sent to the Ethereum network, which can for example be used to track the transaction on an Ethereum blockchain explorer.

Conclusion

In this tutorial, you were able to:

  • Deploy a canister smart contract on the ICP blockchain that can receive and send ETH.
  • Acquire cycles to deploy the canister to the ICP mainnet.
  • Connect the canister to the Ethereum Sepolia testnet.
  • Send the canister some Sepolia ETH.
  • Use the canister to send ETH to another Ethereum address.

Additional examples regarding the ICP < > ETH integration can be found here.

Security considerations and best practices

If you base your application on this example, we recommend you familiarize yourself with and adhere to the security best practices for developing on the Internet Computer. This example may not implement all the best practices.

For example, the following aspects are particularly relevant for this app: