Skip to main content

Making ckERC20 transactions

Advanced
Ethereum
Tutorial

Overview

There are several different ways to interact with ckERC20 tokens:

  • Converting ckERC20 to ERC-20 tokens
  • Converting ERC-20 to ckERC20 tokens
  • Transferring ckERC20 tokens
  • Viewing ckERC20 token transactions

Converting ERC-20 tokens to ckERC20 tokens

The list of supported ckERC20 tokens can be obtained by running the following command:

dfx canister --ic call sv3dd-oaaaa-aaaar-qacoa-cai get_minter_info

Note that ERC-20 tokens can only be converted if the ICRC ledger suite for the corresponding ckERC20 token exists.

The return value contains a vector supported_ckerc20_tokens, which lists all ckERC20 tokens. The return value also contains the field erc20_helper_contract_address, which states the helper smart contract address on Ethereum used in the conversion flows.

The ckERC20 helper contract addresses can be found below:

Ethereum chainHelper smart contract
Ethereum Mainnet0x6abDA0438307733FC299e9C229FD3cc074bD8cC0
Ethereum Testnet Sepolia0x674Cdbe64Df412DA9bAb1596e00c1520979B5A23

Note that the helper smart contract might change. It is therefore recommended to request the ckETH minter info and extract the helper smart contract address from the response to assure you have the latest contract address.

If the targeted ckERC20 token is listed, download the ckETH repository. Then, navigate into the subdirectory for either the mainnet (ic/rs/ethereum/cketh/mainnet) or testnet (ic/rs/ethereum/cketh/testnet).

Create an Ethereum transaction that calls the approve function on the corresponding ERC-20 contract address, allowing the helper smart contract to withdraw some of the user's funds.

The next step is to call the deposit function of the helper smart contract, specifying the ERC-20 smart contract address, the amount to be deposited, and the principal ID that should be credited for the deposit. The principal ID must be encoded as a bytes32 array. A convenient way to obtain the correct encoding is to use the Principal → Bytes32 conversion function on the ckETH minter dashboard.

If your encoded principal ID is incorrect, funds will be lost.

No further user action is required. The icrc1_balance_of function can be called on the corresponding ckERC20 ledger to check if the ckERC20 tokens have been minted, which usually takes about 20 minutes.

Converting ckERC20 tokens to ERC-20 tokens

Since the user must pay the transaction fees, the icrc2_approve function must be called on the ckETH ledger, allowing the ckETH minter to spend some of the user's ckETH tokens. For example, the following command approves the ckETH minter to take up to 1 ckETH from the user's account.

dfx canister --ic call ledger icrc2_approve "(record { spender = record { owner = principal \"$(dfx canister id minter --ic)\" }; amount = 1_000_000_000_000_000_000:nat })"

The user must further approve the ckETH minter to transfer the desired amount of the targeted ckERC20 token:

dfx canister --ic call CKERC20_LEDGER icrc2_approve "(record { spender = record { owner = principal \"$(dfx canister id minter --ic)\" }; amount = CKERC20_TOKEN_AMOUNT:nat })"

The placeholder CKERC20_LEDGER must be replaced by the canister ID of the corresponding ckERC20 ledger and CKERC20_TOKEN_AMOUNT must be replaced by the desired amount, denominated in the smallest unit of the token. For example, USDC and ckUSDC use 6 decimals, so 1 USDC must be written as 1_000_000.

The last step is to call the withdraw_erc20 function on the ckETH minter as follows.

dfx canister --ic call minter withdraw_erc20 "(record { amount = CKERC20_TOKEN_AMOUNT:nat; ckerc20_ledger_id = principal \"CKERC20_LEDGER\"; recipient = \"ETH_ADDRESS\"})"

As before, CKERC20_TOKEN_AMOUNT and CKERC20_LEDGER must be replaced by the desired amount in the smallest unit and the canister ID of the ckERC20 ledger, respectively. Lastly, ETH_ADDRESS must be replaced by the desired Ethereum destination address.

Transferring ckERC20 tokens

ckERC20 tokens are ICRC-1 and ICRC-2 compliant and can therefore be transferred by calling the icrc1_transfer function.

dfx canister --ic call CKERC20_LEDGER "(record { to = DESTINATION_ACCOUNT; amount = AMOUNT:nat})"

The placeholders CKERC20_LEDGER, DESTINATION_ACCOUNT, and AMOUNT must be replaced by the canister ID of the targeted ckERC20 ledger, the destination account, and the desired amount, respectively. More information about the icrc1_tranfer function can be found in the ICRC-1 standard specification.

Transferring ckERC20 tokens incurs a small fee. The exact amount depends on the specific ckERC20 token. The transfer fee can be obtained by calling the icrc1_metadata function on the ckERC20 ledger. The response contains the fee under the key icrc1:fee.

Viewing ckERC20 token transactions

The Internet Computer dashboard shows the transactions of all ckERC20 tokens:

Alternatively, the history of transactions can be obtained from the index canister of the ckERC20 ledger suite. The following command can be used to retrieve the canister IDs of all canisters in the ledger suite of a particular ckERC20 token.

dfx canister --network ic call LSO canister_ids "(record { chain_id = CHAIN_ID:nat; address = "ERC_20_CONTRACT_ADDRESS"})"

Replace the following values:

  • LSO: The canister ID of the ledger suite orchestrator associated with the targeted Ethereum network (vxkom-oyaaa-aaaar-qafda-cai for Ethereum mainnet).

  • CHAIN_ID: The chain ID of the targeted Ethereum network (chain_id = 1 for Ethereum mainnet).

  • ERC_20_CONTRACT_ADDRESS: The corresponding ERC-20 smart contract address (address = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48" for USDC).