USDT transactions EVM RPC canister

I have a canister where I want to enable my users to deposit and withdraw usdt. How can I do that using the EVM?

2 Likes

There are a couple of different ways to do this:

  1. Wait until ckUSDT is released :wink:

  2. Create an ETH address based on a public key controlled by your canister, see e.g. oisy-wallet/src/backend/src/lib.rs at cd8e3096a0549fe65aba376189d62718e8daae7f · dfinity/oisy-wallet · GitHub.
    Ideally, you let the payer give you the transaction of the payment. Then you can check the amount and verify the transaction inclusion with the EVM RPC canister.

  3. Another way is to use the eth_getLogs RPC method via the EVM RPC canister and fetch the transfer events from the USDT ERC-20 account with your ETH address as the recipient.

4 Likes

do U know when the ckUSDT will be released?

Hi @AliSci

See this post form Manu

Our current very rough estimate is ~3 months, but of course we may run into unexpected issues that delay things.

Create an ETH address based on a public key controlled by your canister, see e.g. [oisy-wallet/src/backend/src/lib.rs at cd8e3096a0549fe65aba376189d62718e8daae7f · dfinity/oisy-wallet · GitHub ](https://github.com/dfinity/oisy-wallet/blob/cd8e3096a0549fe65aba376189d62718e8daae7f/src/backend/src/lib.rs#L212C4-L212C27).

Hello Dominic, does this mean that:
(1) Create an ETH address based on a public key controlled by my canister;
(2) The payer transfers the asset to the canister-controlled ETH address (this transaction is executed on Ethereum).

BTW, I suppose the gas fee in term of ETH is required when the EVM RPC canister calls the eth_sendRawTransaction function, right? If this is correct, who and how the gas fee is paid to the Ethereum?

Thank you very much.

Exactly!

The canister-controlled ETH address needs ETH to pay for the gas fees.

The most important completely controlled smart contract ETH wallet we have is the ckETH Minter Canister.

1 Like

@domwoe @cryptoschindler @franrappazzini
ckUSDC is released now, but still no documentations Also, I have to make few more steps like swapping?
Also, I talked to mortz and he says

  1. deposit usdc via eth net
  2. swap usdc to ckusdc
  3. conform transaction vis done by particular caller

is it somthing like this

use ic_cdk::export::Principal;
use ic_cdk_macros::{query, update};
use ic_eth::Ethereum;
use std::collections::HashMap;

type EthereumAddress = String;

#[derive(Default)]
struct USDCWallet {
    ethereum_addresses: HashMap<Principal, EthereumAddress>,
    usdc_balances: HashMap<EthereumAddress, u64>,
    ckusdc_balances: HashMap<EthereumAddress, u64>,
}

impl USDCWallet {
    fn new() -> Self {
        Self {
            ethereum_addresses: HashMap::new(),
            usdc_balances: HashMap::new(),
            ckusdc_balances: HashMap::new(),
        }
    }

    fn generate_ethereum_address(&mut self, principal: Principal) -> EthereumAddress {
        let eth_address = self.create_ethereum_address();
        self.ethereum_addresses.insert(principal, eth_address.clone());
        eth_address
    }

    fn create_ethereum_address(&self) -> EthereumAddress {
        // Use ic-eth library to generate a real Ethereum address
        Ethereum::generate_address()
    }

    fn swap_usdc_to_ckusdc(&mut self, eth_address: &EthereumAddress, amount: u64) -> bool {
        if let Some(balance) = self.usdc_balances.get_mut(eth_address) {
            if *balance >= amount {
                *balance -= amount;
                let ckusdc_balance = self.ckusdc_balances.entry(eth_address.clone()).or_insert(0);
                *ckusdc_balance += amount;
                return true;
            }
        }
        false
    }

    fn swap_ckusdc_to_usdc(&mut self, eth_address: &EthereumAddress, amount: u64) -> bool {
        if let Some(balance) = self.ckusdc_balances.get_mut(eth_address) {
            if *balance >= amount {
                *balance -= amount;
                let usdc_balance = self.usdc_balances.entry(eth_address.clone()).or_insert(0);
                *usdc_balance += amount;
                return true;
            }
        }
        false
    }
}

#[update]
fn generate_ethereum_address(principal: Principal) -> EthereumAddress {
    let mut wallet = USDCWallet::new();
    wallet.generate_ethereum_address(principal)
}

#[update]
fn swap_usdc_to_ckusdc(eth_address: EthereumAddress, amount: u64) -> bool {
    let mut wallet = USDCWallet::new();
    wallet.swap_usdc_to_ckusdc(&eth_address, amount)
}

#[update]
fn swap_ckusdc_to_usdc(eth_address: EthereumAddress, amount: u64) -> bool {
    let mut wallet = USDCWallet::new();
    wallet.swap_ckusdc_to_usdc(&eth_address, amount)
}