Building a Cross-Chain ETH Payment and E-Commerce Platform on the Internet Computer: A Step-by-Step Tutorial

Step 10: Integrating with ICRC Standard

In this step, we’ll integrate our canister with the ckETH ICRC standard to show the balance and enable ETH withdrawal.

Adding Ledger Feature to b3_utils

First, add the “ledger” feature to the b3_utils crate in your Cargo.toml:

b3_utils = { version = "0.8.0", features = ["ledger"] }

Setting Up Ledger and Minter Constants

Add the following lines at the top of your Rust code to specify the ledger and minter canister IDs:

const LEDGER: &str = "apia6-jaaaa-aaaar-qabma-cai";
const MINTER: &str = "jzenf-aiaaa-aaaar-qaa7q-cai";

Creating the Balance Function

Understanding the Function

The balance function uses the ICRC1 trait from b3_utils to fetch the balance of the canister in ckETH.

Here’s the code snippet for the function:

use b3_utils::ledger::{ICRCAccount, ICRC1};
use candid::Principal;

#[ic_cdk::update]
async fn balance() -> Nat {
    let account = ICRCAccount::new(ic_cdk::id(), None);

    ICRC1::from(LEDGER).balance_of(account).await.unwrap()
}

Testing the ckETH Balance Function

  1. Deploy to Mainnet: Run yarn deploy hello --network=ic to upgrade canister.

  2. Open Candid UI: Navigate to the Candid UI and test the balance function. Note that the minting process might take some time.

Creating the Transfer Function

Understanding the Function

The transfer function allows the canister to transfer a specified amount of ckETH to another account.
The function uses the ICRC1 trait from b3_utils to transfer the specified amount of ckETH to the recipient.

Here’s the code snippet for the function:

use b3_utils::ledger::{ICRC1TransferArgs, ICRC1TransferResult};
use std::str::FromStr;

#[ic_cdk::update]
async fn transfer(to: String, amount: Nat) -> ICRC1TransferResult {
    let to = ICRCAccount::from_str(&to).unwrap();

    let transfer_args = ICRC1TransferArgs {
        to,
        amount,
        from_subaccount: None,
        fee: None,
        memo: None,
        created_at_time: None,
    };

    ICRC1::from(LEDGER).transfer(transfer_args).await.unwrap()
}

Testing the Transfer Function

  1. Deploy to Mainnet: Run yarn deploy hello --network=ic to upgrade canister.

  2. Open Candid UI: Navigate to the Candid UI and test the transfer function by passing the recipient’s ICRCAccount comptible format string and the amount of ckETH to transfer.

Approving the Minter to Spend ckETH

Understanding the Function

The approve function uses the ICRC2 trait from b3_utils to approve the minter to spend your ckETH. This is a one-time action if you approve a large amount.

Here’s the code snippet for the function:

use b3_utils::ledger::{ICRC2ApproveArgs, ICRC2ApproveResult, ICRC2};

#[ic_cdk::update]
async fn approve(amount: Nat) -> ICRC2ApproveResult {
    let minter = Principal::from_text(&MINTER).unwrap();

    let spender = ICRCAccount::new(minter, None);

    let args = ICRC2ApproveArgs {
        amount,
        spender,
        created_at_time: None,
        expected_allowance: None,
        expires_at: None,
        fee: None,
        memo: None,
        from_subaccount: None,
    };

    ICRC2::from(LEDGER).approve(args).await.unwrap()
}

Testing the Approve Function

  1. Deploy to Mainnet: Again upgrade the canister using yarn deploy hello --network=ic.

  2. Open Candid UI: Navigate to the Candid UI and test the approve function.

3 Likes