This is CCTP V1 version. For the latest version, see CCTP.
This guide demonstrates how to use the viem framework and
the CCTP V1 API in a simple script that enables a user to
transfer USDC from a wallet address on the Ethereum Sepolia testnet to
another wallet address on the Avalanche Fuji testnet.
To get started with CCTP V1, follow the example script provided
on GitHub.
The example uses
web3.js to
transfer USDC from a wallet address on Ethereum Sepolia testnet to another
wallet address on Avalanche Fuji testnet.
The script has five steps:
- In this first step, you initiate a transfer of USDC from one blockchain to
another, and specify the recipient wallet address on the destination chain.
This step approves the Ethereum Sepolia TokenMessenger contract to
withdraw USDC from the provided Ethereum Sepolia wallet address.
const approveTx = await usdcEthContract.methods
.approve(ETH_TOKEN_MESSENGER_CONTRACT_ADDRESS, amount)
.send({ gas: approveTxGas });
- In this second step, you facilitate a burn of the specified amount of USDC on
the source chain. This step executes the
depositForBurn function on the
Ethereum Sepolia TokenMessenger contract deployed on
Sepolia testnet.
const burnTx = await ethTokenMessengerContract.methods
.depositForBurn(
amount,
AVAX_DESTINATION_DOMAIN,
destinationAddressInBytes32,
USDC_ETH_CONTRACT_ADDRESS,
)
.send();
- In this third step, you make sure you have the correct message and hash it.
This step extracts
messageBytes emitted by the MessageSent event from
depositForBurn transaction logs and hashes the retrieved messageBytes
using the keccak256 hashing algorithm.
const transactionReceipt = await web3.eth.getTransactionReceipt(
burnTx.transactionHash,
);
const eventTopic = web3.utils.keccak256("MessageSent(bytes)");
const log = transactionReceipt.logs.find((l) => l.topics[0] === eventTopic);
const messageBytes = web3.eth.abi.decodeParameters(["bytes"], log.data)[0];
const messageHash = web3.utils.keccak256(messageBytes);
- In this fourth step, you request the attestation from Circle, which provides
authorization to mint the specified amount of USDC on the destination chain.
This step polls the attestation service to acquire the signature using the
messageHash from the previous step.
Rate LimitThe attestation service rate limit is 35 requests per second. If you exceed 35
requests per second, the service blocks all API requests for the next 5 minutes
and returns an HTTP 429 response.
let attestationResponse = { status: "pending" };
while (attestationResponse.status != "complete") {
const response = await fetch(
`https://iris-api-sandbox.circle.com/attestations/${messageHash}`,
);
attestationResponse = await response.json();
await new Promise((r) => setTimeout(r, 2000));
}
- In this final step, you enable USDC to be minted on the destination chain.
This step calls the
receiveMessage function on the Avalanche Fuji
MessageTransmitter contract to receive USDC at the Avalanche Fuji wallet
address.
const receiveTx = await avaxMessageTransmitterContract.receiveMessage(
receivingMessageBytes,
signature,
);
You have successfully transferred USDC between two EVM-compatible chains using
CCTP V1 end-to-end.