Skip to main content
Transfer USDC between Starknet Sepolia and Arc Testnet using the CCTP burn-attest-mint flow.
On Starknet, CCTP uses Cairo contracts and a combined TokenMessengerMinterV2. Before you integrate beyond these examples, read CCTP Starknet contracts and interfaces.
Pick the tab that matches the direction of your transfer.
This quickstart demonstrates how to transfer USDC from Starknet Sepolia to Arc Testnet using CCTP. You use starknet.js to approve and burn USDC on Starknet, 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 Starknet account contracts 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.

Prerequisites

Before you begin this tutorial, ensure you have:
  • Installed Node.js v22.6+
  • Prepared a Starknet Sepolia account with the address and private key available
    • Funded your account with testnet STRK from the Starknet faucet for transaction fees
    • Funded your account with Starknet Sepolia 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

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:
  • EVM_PRIVATE_KEY is the private key for the EVM wallet used to receive USDC on Arc Testnet.
  • STARKNET_PRIVATE_KEY is the private key for the Starknet Sepolia account used to sign the burn transaction.
  • STARKNET_RPC_URL is optional. The script defaults to a public Starknet Sepolia RPC endpoint.
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 Starknet and Arc Testnet parameters, then configure the wallet clients for each chain.

2.1. Define configuration constants

The script predefines the USDC and CCTP contract addresses, transfer amount, and CCTP domain IDs. Replace STARKNET_ACCOUNT_ADDRESS with your Starknet Sepolia account address. Starknet account addresses are not derived from the private key alone, so you set the address as a constant.
TypeScript
STARKNET_DOMAIN is the source domain used when requesting the attestation. The destination domain for Arc Testnet is 26. Starknet Sepolia 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 Starknet client uses starknet.js with your account address and private key. The script loads the contract ABI from the network with getClassAt.
TypeScript

2.3. Format the Arc recipient for Starknet

deposit_for_burn accepts the mint recipient as a 32-byte felt. An EVM address is left-padded with zeros to 32 bytes.
TypeScript

Step 3: Implement the transfer logic

This step implements the core transfer logic: approve and burn on Starknet, poll for an attestation, then mint on Arc.

3.1. Approve USDC on Starknet

Grant approval for the TokenMessengerMinterV2 contract to withdraw USDC from your Starknet account. This allows the contract to burn USDC when you initiate the transfer.
TypeScript

3.2. Burn USDC on Starknet

Call deposit_for_burn to burn USDC on Starknet. You specify the following parameters:
  • Burn amount: The amount of USDC to burn in Starknet 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, left-padded to 32 bytes
  • Burn token: The Starknet Sepolia USDC address
  • Destination caller: The zero address, allowing any caller to submit the receive transaction on Arc
  • Max fee / finality threshold: This example uses Fast Transfer. For live fee values and allowance checks, see Get the fee for your transfer and Get the fast transfer allowance.
TypeScript

3.3. 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 STARKNET_DOMAIN for the sourceDomain path parameter, using the CCTP domain for Starknet (25).
  • Pass the Starknet transaction hash returned by burnUSDC as transactionHash.
TypeScript

3.4. 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.
index.ts

Step 5: Test the script

Replace STARKNET_ACCOUNT_ADDRESS in index.ts with your Starknet Sepolia account address, then run:
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.