Skip to main content
Transfer USDC between Aptos Testnet and Arc Testnet using the CCTP burn-attest-mint flow.
Move scripts for Aptos CCTP transfers are precompiled. They are located in the aptos-cctp GitHub repository. You submit these compiled scripts directly instead of compiling Move source code.
Pick the tab that matches the direction of your transfer.
This quickstart demonstrates how to transfer USDC from Aptos Testnet to Arc Testnet using CCTP. You use the @aptos-labs/ts-sdk library to submit the precompiled Aptos Move script that burns USDC, and viem to mint USDC on Arc Testnet. When you finish, you will have executed a full burn-attest-mint flow.You should be comfortable using a terminal and Node.js. Familiarity with Aptos transactions and basic EVM usage helps you follow and adapt the script. Examples use Arc Testnet as the destination, but you can use any supported EVM blockchain.
The Aptos burn transaction uses a precompiled Move script. Download deposit_for_burn.mv from the aptos-cctp repository and place it in a precompiled-move-scripts directory in your project.

Prerequisites

Before you begin this tutorial, ensure you have:
  • Installed Node.js v22.6+
  • Prepared an Aptos Testnet wallet with the private key available
    • Funded your account with testnet APT from the Aptos Faucet for transaction fees
    • Funded your account with Aptos Testnet USDC from the Circle Faucet
  • Prepared an EVM wallet with the private key available for Arc Testnet
    • Added the Arc Testnet network to your wallet (network details)
    • Funded your wallet with Arc Testnet ETH for gas fees

Step 1: Set up the project

This step shows you how to prepare your project and environment.

1.1. Set up your development environment

Create a new directory, initialize and set up a new Node.js project, and install the required dependencies:
Shell
Copy deposit_for_burn.mv into precompiled-move-scripts/ in your project. The full script in Step 4 reads the bytecode relative to index.ts.

1.2. Initialize and configure the project

This step is optional. It helps prevent missing types in your IDE or editor.
Create a tsconfig.json file:
Then, update the tsconfig.json file:

1.3. Configure environment variables

Open .env in your editor and add:
  • APTOS_PRIVATE_KEY is the private key for the Aptos Testnet account used to sign the burn transaction.
  • EVM_PRIVATE_KEY is the private key for the EVM wallet used to receive USDC on Arc Testnet.
Open .env in your editor rather than writing values with shell commands, and add .env to your .gitignore. This prevents credentials from leaking into your shell history or version control.
The npm run start command loads variables from .env using Node.js native env-file support.
This example uses one or more private keys for local testing. In production, use a secure key management solution and never expose or share private keys.

Step 2: Configure the script

Define the Aptos and Arc Testnet parameters, then configure the wallet clients for each chain.

2.1. Define configuration constants

The script predefines the USDC address, CCTP contract address, transfer amount, and CCTP domain IDs.
TypeScript
APTOS_DOMAIN is the source domain used when requesting the attestation. The destination domain for Arc Testnet is 26. Aptos Testnet USDC uses 6 decimals, so 1_000_000 represents 1 USDC.

2.2. Set up wallet clients

The EVM clients connect to Arc Testnet with viem. The Aptos client uses the Aptos Testnet network and signs transactions with the Aptos account’s Ed25519 private key.
TypeScript

2.3. Format the Arc recipient for Aptos

The Aptos deposit_for_burn.mv script accepts the mint recipient as an Aptos address. An EVM address is converted to a 32-byte Aptos address by left-padding it with zeros.
TypeScript

Step 3: Implement the transfer logic

This step implements the core transfer logic: burn on Aptos, poll for an attestation, then mint on Arc. The precompiled Aptos script withdraws USDC from the account’s primary fungible store, so there is no separate approval transaction.

3.1. Burn USDC on Aptos

Submit deposit_for_burn.mv to burn USDC on Aptos Testnet. The script submits the following parameters:
  • Burn amount: The amount of USDC to burn in Aptos subunits (6 decimals)
  • Destination domain: The target blockchain for minting USDC (26 for Arc Testnet)
  • Mint recipient: The EVM wallet address that receives minted USDC on Arc, represented as a 32-byte Aptos address
  • Destination caller: The Aptos zero address, allowing any caller to submit the receive transaction on Arc
  • Burn token: The Aptos Testnet USDC address
  • Max fee: The maximum fee allowed for the transfer
  • Finality threshold: 2000 for a Standard Transfer
TypeScript

3.2. Retrieve attestation

Retrieve the attestation required to complete the CCTP transfer by calling Circle’s attestation API.
  • Call Circle’s GET /v2/messages API endpoint to retrieve the attestation.
  • Pass APTOS_DOMAIN for the sourceDomain path parameter, using the CCTP domain for Aptos Testnet (9).
  • Pass the Aptos transaction hash returned by burnUSDC as transactionHash.
TypeScript

3.3. Mint USDC on Arc

Call the receiveMessage function from the MessageTransmitterV2 contract deployed on Arc Testnet.
  • Pass the signed attestation and message bytes as parameters.
  • The contract verifies the attestation and mints USDC to the recipient encoded in the CCTP message.
TypeScript

Step 4: Full script

Create an index.ts file in your project directory and paste the full script following. Keep deposit_for_burn.mv in the precompiled-move-scripts directory next to it.
index.ts

Step 5: Test the script

Run the following command to execute the script:
Shell
When the transfer finishes, the console logs a completion message and the relevant transaction hashes. Successful output looks similar to the following:
Shell
Attestation polling can take several minutes depending on network conditions and the finality threshold you chose. The script retries every 2 seconds with no timeout, so allow the process to continue while Iris prepares the attestation.
Rate limit: The attestation service rate limit is 40 requests per second. If you exceed this limit, the service blocks all API requests for the next five minutes and returns an HTTP 429 (Too Many Requests) response.