Circle Gateway marks a new era in crosschain liquidity infrastructure. Learn how you can unify liquidity across multiple chains using Circle’s infrastructure.

Crosschain liquidity management has long been one of the biggest challenges in onchain finance. As developers and institutions expand across multiple ecosystems, managing capital efficiency, settlement risk, and treasury visibility becomes increasingly complex.
Circle Gateway changes that paradigm.
This guide is designed for product and engineering teams who are exploring how to unify liquidity across multiple chains using Circle’s infrastructure. It provides a practical framework for integrating Gateway into your existing systems. You’ll learn when to use it, how it simplifies liquidity operations, and how it unlocks better crosschain user experiences.
After reading this, you’ll have the foundational knowledge to confidently start building with Circle Gateway.
What is Circle Gateway?
While legacy liquidity systems require developers to pre-fund balances on each blockchain, Circle Gateway introduces a unified USDC liquidity layer that can mint and burn on any supported network on demand.
Gateway consolidates your treasury into one single balance — no more parked liquidity or idle capital spread across chains. With a single contract call, you can instantly mint USDC on Arbitrum, Arc, Base, OP Mainnet, Polygon PoS, and more, while maintaining a single balance for reconciliation and accounting.
Its core characteristics include:
- Capital efficiency & chain abstraction: Instead of needing to separately hold USDC on every chain you support, you maintain a single unified balance.
- Instant crosschain availability: After deposit and finality, transfers via Gateway can execute in < 500 ms removing bridging delays.
- Simplicity of integration: A single integration, one set of contracts and API, works across all supported chains.
- Non-custodial & safe: Users retain full control of their assets; moving funds requires explicit user authorization, and there's a fallback withdrawal route if off-chain services are down.
When should you build with Circle Gateway?
Building with Gateway requires rethinking how your system handles liquidity, settlement, and capital deployment. It’s best suited for environments where on-chain fragmentation slows operations or ties up capital.
Consider these key scenarios:
Fragmented crosschain liquidity
Use Gateway when your system must transfer USDC across multiple networks without maintaining prefunded balances.
Example: Crosschain funding and settlements that require just-in-time liquidity delivery.
Capital inefficiency in treasury ops
Use Gateway when managing balances across many chains creates idle capital or reconciliation overhead.
Example: Fintech and PSP platforms centralizing liquidity and minting on demand.
Disconnected payment flows
Use Gateway when multichain payment routing, reconciliation, or settlement leads to operational friction.
Example: Payment infrastructure unifying deposits and settlements across supported chains.
Fragmented user liquidity
Use Gateway when your users need access to USDC across ecosystems but your backend lacks unified liquidity control.
Example: Wallets or embedded finance platforms that serve users on multiple networks.
Gateway Integration Foundations
At its core, Circle Gateway consists of three foundational components:
Gateway Wallet Contracts: Non-custodial smart contracts deployed on multiple chains where users deposit USDC.
Gateway Minter Contracts: Smart contracts that receive attestations from the Gateway system and mint USDC on the destination chain.
Gateway System: An offchain system operated by Circle that provides APIs for initiating transfers, observes onchain events, and manages attestations.
Depositing USDC to Gateway
import { initiateDeveloperControlledWalletsClient } from '@circle-fin/developer-controlled-wallets'
// Gateway contract addresses on Arc Testnet
const GATEWAY_WALLET_ADDRESS = '0x0077777d7EBA4688BDeF3E311b846F25870A19B9'
const USDC_TOKEN_ADDRESS = '0x3600000000000000000000000000000000000000'
async function depositToGateway(walletId: string, amount: string) {
// Initialize Circle client
const client = initiateDeveloperControlledWalletsClient({
apiKey: process.env.CIRCLE_API_KEY!,
entitySecret: process.env.CIRCLE_ENTITY_SECRET!,
})
// Convert USDC to smallest unit (6 decimals)
const amountInSmallestUnit = (parseFloat(amount) * 1_000_000).toString()
// Step 1: Approve Gateway contract to spend USDC
const approvalTx = await client.createContractExecutionTransaction({
walletId,
contractAddress: USDC_TOKEN_ADDRESS,
abiFunctionSignature: 'approve(address,uint256)',
abiParameters: [GATEWAY_WALLET_ADDRESS, amountInSmallestUnit],
fee: { type: 'level', config: { feeLevel: 'MEDIUM' } },
})
console.log('Approval transaction:', approvalTx.data?.id)
// Wait for approval to finalize (5 seconds is typical for testnets)
await new Promise(resolve => setTimeout(resolve, 5000))
// Step 2: Deposit USDC into Gateway
const depositTx = await client.createContractExecutionTransaction({
walletId,
contractAddress: GATEWAY_WALLET_ADDRESS,
abiFunctionSignature: 'deposit(address,uint256)',
abiParameters: [USDC_TOKEN_ADDRESS, amountInSmallestUnit],
fee: { type: 'level', config: { feeLevel: 'MEDIUM' } },
})
console.log('Deposit transaction:', depositTx.data?.id)
return {
approvalTxId: approvalTx.data?.id,
depositTxId: depositTx.data?.id,
}
}Constructing a Burn Intent for Gateway Transfers
import { randomBytes } from 'crypto'
// Gateway contract addresses (testnet)
const GATEWAY_WALLET_ADDRESS = '0x0077777d7EBA4688BDeF3E311b846F25870A19B9'
const GATEWAY_MINTER_ADDRESS = '0x0022222ABE238Cc2C7Bb1f21003F0a260052475B'
// USDC addresses per chain
const USDC_ADDRESSES: Readonly<Record<number, string>> = {
26: '0x3600000000000000000000000000000000000000', // Arc Testnet
1: '0x5425890298aed601595a70AB815c96711a31Bc65', // Avalanche Fuji
6: '0x036CbD53842c5426634e7929541eC2318f3dCF7e', // Base Sepolia
0: '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238', // Ethereum Sepolia
}
// Maximum uint256 value for no expiration
const MAX_UINT256 = ((BigInt(1) << BigInt(256)) - BigInt(1)).toString()
function createBurnIntent(
walletAddress: string,
sourceDomain: number,
destinationDomain: number,
amount: string,
recipient?: string
) {
// Convert USDC to atomic units (6 decimals)
const valueInSmallestUnit = (parseFloat(amount) * 1_000_000).toString()
// Get USDC token addresses for source and destination chains
const sourceTokenAddress = USDC_ADDRESSES[sourceDomain]
const destinationTokenAddress = USDC_ADDRESSES[destinationDomain]
return {
maxBlockHeight: MAX_UINT256, // No expiration
maxFee: '20000', // 0.02 USDC to cover Gateway fees
spec: {
version: 1,
sourceDomain, // e.g., 26 for Arc Testnet
destinationDomain, // e.g., 6 for Base Sepolia
sourceContract: GATEWAY_WALLET_ADDRESS,
destinationContract: GATEWAY_MINTER_ADDRESS,
sourceToken: sourceTokenAddress,
destinationToken: destinationTokenAddress,
sourceDepositor: walletAddress,
destinationRecipient: recipient || walletAddress,
sourceSigner: walletAddress,
destinationCaller: '0x0000000000000000000000000000000000000000', // Anyone can mint
value: valueInSmallestUnit,
salt: '0x' + randomBytes(32).toString('hex'), // Unique salt prevents replay
hookData: '0x', // No hook data
},
}
}
Requesting an Attestation from Gateway API
const GATEWAY_API_URL = 'https://gateway-api-testnet.circle.com/v1'
async function requestAttestation(burnIntent: any, signature: string) {
// Submit signed burn intent to Gateway API
const response = await fetch(`${GATEWAY_API_URL}/transfer`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify([
{
burnIntent: burnIntent, // Your EIP-712 formatted burn intent
signature: signature, // EIP-712 signature from your wallet
},
]),
})
if (!response.ok) {
const errorBody = await response.json()
throw new Error(errorBody.message || 'Gateway API request failed')
}
// Parse the attestation response
const result = await response.json()
return {
attestation: result.attestation, // The attestation bytes
signature: result.signature, // Gateway's signature
}
}
Minting USDC on Destination Chain
import { initiateDeveloperControlledWalletsClient } from '@circle-fin/developer-controlled-wallets'
import { randomBytes } from 'crypto'
// Gateway Minter contract address (same on all chains)
const GATEWAY_MINTER_ADDRESS = '0x0022222ABE238Cc2C7Bb1f21003F0a260052475B'
async function mintOnDestinationChain(
destinationWalletId: string,
attestation: string,
attestationSignature: string
) {
// Initialize Circle client
const client = initiateDeveloperControlledWalletsClient({
apiKey: process.env.CIRCLE_API_KEY!,
entitySecret: process.env.CIRCLE_ENTITY_SECRET!,
})
// Call gatewayMint on the destination chain
const mintResponse = await client.createContractExecutionTransaction({
walletId: destinationWalletId, // Wallet on DESTINATION chain
contractAddress: GATEWAY_MINTER_ADDRESS, // Gateway Minter contract
abiFunctionSignature: 'gatewayMint(bytes,bytes)',
abiParameters: [
attestation, // Attestation from Gateway API
attestationSignature, // Gateway's signature
],
fee: {
type: 'level',
config: {
feeLevel: 'MEDIUM',
},
},
idempotencyKey: randomBytes(16).toString('hex'), // Prevents duplicate txs
})
if (!mintResponse.data?.id) {
throw new Error('Failed to create mint transaction')
}
console.log('Mint transaction ID:', mintResponse.data.id)
return {
transactionId: mintResponse.data.id,
}
}
Conclusion
Circle Gateway marks a new era in multichain liquidity infrastructure. By consolidating fragmented balances into a unified liquidity layer, it empowers builders to move capital more efficiently, manage treasury operations intelligently, and deliver faster, more consistent user experiences across networks.
Whether you’re building crosschain fintech rails, market infrastructure, or embedded stablecoin apps, Gateway is the foundation for programmable liquidity in onchain — giving you the speed of crypto with the reliability of modern finance.
One balance. One API. One USDC experience everywhere.
Check out our quickstart guide here.




