# Transfer USDC on testnet from Ethereum to Avalanche using CCTP V1

This guide demonstrates how to use the [viem](https://viem.sh/) framework and the [CCTP V1 API](/chainaiswap-docs/cross-chain-transfer-protocol/cross-chain-transfer-protocol-v1/cctp-api-hosts-and-endpoints-v1.md) 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](https://github.com/circlefin/evm-cctp-contracts/blob/d1c24577fb627b08483dc42e4d8a37a810b369f7/docs/index.js). The example uses [web3.js](https://web3js.readthedocs.io/en/v1.8.1/getting-started.html) to transfer USDC from a wallet address on Ethereum Sepolia testnet to another wallet address on Avalanche Fuji testnet.

This script has five steps:

{% stepper %}
{% step %}

### Initiate transfer / Approve TokenMessenger

In this 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.

{% code title="approve.js" %}

```javascript
const approveTx = await usdcEthContract.methods
  .approve(ETH_TOKEN_MESSENGER_CONTRACT_ADDRESS, amount)
  .send({ gas: approveTxGas });
```

{% endcode %}
{% endstep %}

{% step %}

### Burn tokens on source chain (depositForBurn)

In this 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.

{% code title="burn.js" %}

```javascript
const burnTx = await ethTokenMessengerContract.methods
  .depositForBurn(
    amount,
    AVAX_DESTINATION_DOMAIN,
    destinationAddressInBytes32,
    USDC_ETH_CONTRACT_ADDRESS,
  )
  .send();
```

{% endcode %}
{% endstep %}

{% step %}

### Extract message and compute hash

In this step, you extract the `messageBytes` emitted by the **MessageSent** event from the `depositForBurn` transaction logs and hash the retrieved `messageBytes` using the **keccak256** hashing algorithm.

{% code title="hashMessage.js" %}

```javascript
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);
```

{% endcode %}
{% endstep %}

{% step %}

### Request attestation from Circle (poll attestation service)

In this 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.

{% hint style="warning" %}
Rate Limit: The 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.
{% endhint %}

{% code title="attestation.js" %}

```javascript
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));
}
```

{% endcode %}
{% endstep %}

{% step %}

### Receive message on destination chain (mint USDC)

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.

{% code title="receiveMessage.js" %}

```javascript
const receiveTx = await avaxMessageTransmitterContract.receiveMessage(
  receivingMessageBytes,
  signature,
);
```

{% endcode %}
{% endstep %}
{% endstepper %}

You have successfully transferred USDC between two EVM-compatible chains using CCTP V1 end-to-end.

This is CCTP V1 version. For the latest version, see [CCTP](https://developers.circle.com/cctp).

***

Previous: [CCTP Limits V1](/chainaiswap-docs/cross-chain-transfer-protocol/cross-chain-transfer-protocol-v1/cctp-limits-v1.md)\
Next: [Transfer USDC on testnet between Noble and Ethereum using CCTP V1](broken://pages/9f156b1f8c37ed259b3c97a7bc11e1a374042b2c)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://chainaiswap.gitbook.io/chainaiswap-docs/cross-chain-transfer-protocol/cross-chain-transfer-protocol-v1/transfer-usdc-on-testnet-from-ethereum-to-avalanche-using-cctp-v1.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
