Skip to main content
This guide shows how to transfer USDC crosschain using the Circle Forwarding Service. This example shows a transfer from Base Sepolia to Avalanche Fuji, but you can use the same steps to transfer to any supported destination blockchain, including Solana. When you use the Forwarding Service, Circle handles the mint transaction on the destination blockchain, eliminating the need for you to hold native tokens for gas on the destination blockchain or run multichain infrastructure.

Prerequisites

Before you start, ensure you have:
  • Installed Node.js v22.6+
  • Created a TypeScript project and installed the viem package.
  • Created a wallet with the private key available on the source chain.
  • Funded the wallet with testnet USDC and native tokens for gas fees on the source chain.
  • Created a .env file with your private key and recipient address.

Steps

Use the following steps to transfer USDC with the Forwarding Service.

Step 1. Get CCTP fees from the API

Query the CCTP API for the fees for transferring USDC from Base Sepolia to Avalanche Fuji. This value is passed to the maxFee parameter in the depositForBurnWithHook transaction. The following is an example request using source domain 6 (Base Sepolia) and destination domain 1 (Avalanche Fuji):
Example response:
The forwardFee is the fee charged by the Forwarding Service. The minimumFee is the CCTP protocol fee rate in basis points, applied as a percentage of the transfer amount.
Circle recommends selecting the med fee level or higher from the forwardFee object in the API response. Note that forwardFee values fluctuate based on destination chain gas prices. Make the query immediately before initiating your transfer.
When the destination blockchain is Solana, the forwardFee values include both gas and rent costs. If the recipient does not have an existing USDC Associated Token Account (ATA), add includeRecipientSetup=true to the fee query so the returned fee covers ATA creation:
Unlike EVM destinations, the mintRecipient for Solana must be the recipient’s USDC token account address (ATA), not the wallet address. Derive the ATA from the wallet address and the USDC mint:
If the recipient does not have an existing ATA and you passed includeRecipientSetup=true in the fee query, you must also encode ATA creation fields in the hook data. See Solana hook data for ATA creation for the extended hook data format.

Step 2. Calculate the USDC amounts and fees

Calculate the total fee by combining the protocol fee and the Forwarding Service fee. The maxFee parameter must cover both fees for the transfer to succeed.
In this example, for a 10 USDC transfer with forwarding, the total fee is 0.058843 USDC (0.057543 USDC Forwarding Service fee + 0.0013 USDC CCTP protocol fee). For the recipient to receive 10 USDC, you must burn 10.058843 USDC in total.
If the maxFee parameter is insufficient to cover the both Fast Transfer protocol fee and the Forwarding Service fee, CCTP will prioritize forwarding execution over Fast Transfer. This means that the transfer will execute as a Standard Transfer with the Forwarding Service.

Step 3. Approve the USDC transfer

Grant approval for the TokenMessengerV2 contract deployed on Base to transfer USDC from your wallet. Approve at least totalAmount (including fees) calculated in Step 2.

Step 4. Sign and broadcast a depositForBurnWithHook transaction on the TokenMessengerV2 contract

Create and send a depositForBurnWithHook transaction with the Forwarding Service hook data. The hook data tells the CCTP Forwarding Service to automatically forward the mint transaction on the destination chain. The Forwarding Service hook data is a static 32-byte value containing the magic bytes cctp-forward, version 0, and length 0. For details on the hook format, see Forwarding Service hook format.
When forwarding to Solana, use the same static hook data if the recipient already has a USDC Associated Token Account (ATA). If the recipient does not have an ATA and you included includeRecipientSetup=true in the fee query (see Step 1), construct extended hook data that requests ATA creation:
For the full hook data format, see Solana hook data for ATA creation.
Then, send the depositForBurnWithHook transaction:
Use totalAmount (transfer amount + fees) for the amount parameter. The recipient receives only the transfer amount after fees are deducted.
Once the burn transaction is confirmed on Base, the Circle Forwarding Service automatically handles the attestation and mint transaction on Avalanche. The USDC is minted directly to the mintRecipient address on the destination chain. The recipient receives transferAmount USDC (fees are automatically deducted from the totalAmount on the destination chain).

Step 5. Verify the mint transaction

After the burn transaction is confirmed, query the Circle Iris API to retrieve the forwarding details. The API returns the forwardTxHash, which is the mint transaction hash on the destination chain. The attestation may take time to become available, depending on the destination chain. Poll the API until the message is ready:

Full example code

The following is a complete example of how to transfer USDC from Base Sepolia to Avalanche Fuji using the Forwarding Service. Remember to set the PRIVATE_KEY and DESTINATION_ADDRESS environment variables.
script.ts
Run the script: