Skip to main content
This guide walks you through the process of creating Unified Crosschain USDC Balances on Solana using Circle Gateway, and performing transfers from EVM to Solana and from Solana to Solana.
Use Unified Balance Kit to simplify this integration.This quickstart uses a manual Gateway integration. It is for learning or for developers who need direct control.To simplify, use Unified Balance Kit to deposit and spend USDC in just a few lines of code.
Select a tab below for the Circle Wallets or self-managed wallet path.

Prerequisites

Before you begin, ensure that you’ve:If you want to try the EVM to Solana transfer, ensure that you’ve:
  • Created an Arc Testnet EVM Developer-Controlled Wallet
  • Created a Solana Devnet Developer-Controlled Wallet to receive the minted USDC
  • Completed the deposit flow from the EVM quickstart first

Add testnet funds to your wallet

To interact with Gateway, you need test USDC and native tokens in your wallet on each chain you deposit from. For direct mints on Solana, the wallet that submits the Solana transaction also needs SOL to create the recipient Associated Token Account and call the Gateway Minter program.
You can skip the destination mint transaction by using the Forwarding Service, which completes the Solana mint for you. The recipient ATA still needs to exist for this quickstart.
Use the Circle Faucet to get test USDC. If you have a Circle Developer Console account, you can use the Console Faucet to get testnet native tokens. In addition, the following faucets can also be used to fund your wallet with testnet native tokens:
Faucet: Arc Testnet (USDC + native tokens)

Step 1. Set up your project

1.1. Create the project and install dependencies

1.2. Configure TypeScript (optional)

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. Set environment variables

Create a .env file in the project directory:
.env
  • CIRCLE_API_KEY is your Circle API key.
  • CIRCLE_ENTITY_SECRET is your Circle entity secret.
  • DEPOSITOR_ADDRESS is the source depositor wallet for the script you are running.
  • RECIPIENT_ADDRESS is the destination wallet that receives the minted USDC.
For transfer-from-sol.ts, both values are Solana addresses.For transfer-from-evm.ts, DEPOSITOR_ADDRESS is an EVM address and RECIPIENT_ADDRESS is a Solana address.
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.

Step 2. Set up the configuration file

The shared Solana configuration and helpers are used by the deposit and transfer scripts.

2.1. Create the configuration file

2.2. Configure Solana settings and Gateway helpers

Add the shared Solana RPC configuration, Gateway addresses, IDLs, attestation decoding helpers, and Circle Wallets signing helpers to config.ts.The local IDL fragments in this example are only the subset needed by the sample code. For canonical static instruction and account definitions, use the onchain IDLs linked from Solana programs and interfaces.
config.ts

Step 3. Deposit into a unified crosschain balance (Circle Wallets)

The deposit script submits a Gateway deposit on Solana Devnet. You can skip to the full deposit script if you prefer.
Do not send USDC directly to the Gateway Wallet address or custody account. You must use a Gateway deposit instruction for the funds to be credited to your unified balance.

3.1. Create the deposit script

3.2. Define constants and helpers

Set the deposit amount near the top of the file, then derive the owner ATA and load the account so the script can validate balance before it builds the Gateway instruction.

3.3. Initialize connection, Anchor client, and validate balance

Initialize the connection, check the source wallet balance, then set up the Anchor client and derive the Gateway PDAs.

3.4. Execute the deposit

After the balance check and PDA derivation, build the Gateway deposit instruction, sign it with Circle Wallets, broadcast it, and wait for Solana confirmation.

3.5. Full deposit script (Circle Wallets)

The script validates the source balance, builds the Gateway deposit instruction, and confirms the deposit on Solana Devnet. Inline comments explain each stage.
deposit.ts

3.6. Run the deposit script

Wait for the required number of block confirmations. Once the deposit transaction is final, your Gateway balance on Solana Devnet will be updated. Solana Devnet transactions typically reach finality in seconds.

3.7. Check the balances on the Gateway Wallet

Create a new file called balances.ts, and add the following code. This script retrieves the USDC balances available from your Gateway Wallet for the DEPOSITOR_ADDRESS currently set in .env.
balances.ts
You can run it to verify your balance on Gateway.

Step 4. Transfer USDC from Solana to Solana

This step transfers USDC from your Solana Devnet Gateway balance to a recipient on Solana Devnet. Both paths create and sign the Solana burn intent first. Direct mint then retrieves the Gateway attestation and calls gatewayMint(...) on Solana Devnet from your wallet, while Forwarding Service lets Circle complete the Solana mint for you.

4.1. Create the Solana transfer script

You can skip to the full transfer script if you prefer.

4.2. Define constants and types

This flow uses the same Solana burn intent layout as the standard Gateway quickstart, but swaps in Circle Wallet signing for both the burn intent and the mint transaction.

4.3. Add helper functions

The helper layer encodes the Solana burn intent, creates a lightweight Anchor provider, and exposes the address conversion utilities required for Gateway minting.

4.4. Initialize connection and create recipient ATA

Before minting to the destination wallet, derive the recipient Associated Token Account and create it idempotently. In this script, the source Developer-Controlled Wallet pays for the account creation.
For transfers to Solana, the destinationRecipient must be an initialized USDC Token Account. If the intended recipient is a standard wallet address, use its Associated Token Account (ATA), not the recipient wallet address itself.

4.5. Create and sign burn intent

Encode the Solana burn intent, prefix the payload, and sign it with the source Developer-Controlled Wallet.

4.6. Request attestation from Gateway API

Submit the signed burn intent to the Gateway API and decode the attestation set that comes back from the response.

4.7. Set up minter client

Once the API returns the attestation, initialize the Gateway Minter program and derive the PDA accounts needed for the Solana mint.
The ordered remaining-account list and PDA derivations are documented in Solana Programs and Interfaces. For static instruction definitions, use the onchain IDLs linked from that page.

4.8. Mint on Solana

Create the mint instruction, sign the transaction with the source Developer-Controlled Wallet, and confirm it on Solana Devnet.This script uses the source Solana wallet as both payer and destinationCaller. The recipient wallet owns the recipient ATA that receives the minted USDC.In this quickstart’s client shape, the instruction accounts are assembled as the fixed gatewayMint accounts first, followed by one ordered triplet per attestation: custody_token_account, destination_recipient, and transfer_spec_hash_account.

4.9. Full Solana transfer script (Circle Wallets)

The script creates the recipient ATA, signs a Solana burn intent, requests a Gateway attestation, and mints on Solana Devnet. Inline comments explain each stage.
transfer-from-sol.ts

4.10. Run the Solana direct-mint script

Run the script to burn from your Solana Devnet Gateway balance and mint to the recipient ATA on Solana Devnet.Confirm these values before running:
  • DEPOSITOR_ADDRESS is the source Solana Devnet wallet
  • RECIPIENT_ADDRESS is the destination Solana Devnet wallet
  • the source depositor has a Gateway balance on Solana Devnet
  • the source Solana wallet can submit the ATA creation and mint transactions on Solana Devnet
Gateway fees are charged per burn intent and are based on the source blockchain you burn from. Choosing where to hold and burn Gateway balances can affect transfer costs. For fee details, see Gateway Fees.
When the transfer succeeds, the script logs the minted amount and Solana Devnet mint transaction hash.