Across for Stablecoins

Move native USDC, USDT0, and USDH across chains with a single Swap API call.

Across moves native stablecoins across every supported chain through one Swap API call — no wrapped tokens. You request a route; Across picks the best settlement path automatically and returns a transaction to execute.

API key required for production. Get your API key and Integrator ID to authenticate your requests.

Select stablecoin routes have zero bridge fees, subsidized by the protocol.

Currently sponsored:

  • USDT / USDT0 → USDC-SPOT, USDC-PERPS on HyperCore from Ethereum, Arbitrum, Monad, Polygon, Unichain

Sponsored routes change over time. To check if a route is currently sponsored, inspect the fees object in the /swap/approval response.

Stablecoin Contract Addresses

Always verify addresses via the /swap/tokens endpoint. Token addresses can change as new deployments roll out.

ChainAddress
Ethereum0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48
Arbitrum0xaf88d065e77c8cC2239327C5EDb3A432268e5831
Base0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913
Optimism0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85
Polygon0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359

Use /swap/tokens?chainId=<id> for the complete list across all supported chains.

ChainAddress
Ethereum0xdAC17F958D2ee523a2206206994597C13D831ec7
Arbitrum0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9
Optimism0x94b008aA00579c1307B0EF2c499aD98a8ce58e58

Use /swap/tokens?chainId=<id> for the complete list.

This is a subset of supported chains. Query /swap/tokens for the full matrix of stablecoins and chains.

Example: Large USDC Transfer

One /swap/approval call quotes the route and returns the transaction(s) to execute. The integration code is the same for every stablecoin route, regardless of size.

usdc-transfer.ts
import { createWalletClient, createPublicClient, http } from "viem";
import { mainnet } from "viem/chains";
import { privateKeyToAccount } from "viem/accounts";

const account = privateKeyToAccount("0xYOUR_PRIVATE_KEY");
const walletClient = createWalletClient({ account, chain: mainnet, transport: http() });
const publicClient = createPublicClient({ chain: mainnet, transport: http() });

const params = new URLSearchParams({
  tradeType: "minOutput",
  originChainId: "1",
  destinationChainId: "42161",
  inputToken: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",   // USDC on Ethereum
  outputToken: "0xaf88d065e77c8cC2239327C5EDb3A432268e5831",   // USDC on Arbitrum
  amount: "1000000000",                                         // 1,000 USDC (6 decimals)
  depositor: account.address,
});

const quote = await fetch(
  `https://app.across.to/api/swap/approval?${params}`,
  { headers: { Authorization: "Bearer YOUR_API_KEY" } },
).then((r) => r.json());

// Execute approvals (if any), then the swap
if (quote.approvalTxns?.length) {
  for (const approvalTx of quote.approvalTxns) {
    const hash = await walletClient.sendTransaction({ to: approvalTx.to, data: approvalTx.data });
    await publicClient.waitForTransactionReceipt({ hash });
  }
}

const hash = await walletClient.sendTransaction({
  to: quote.swapTx.to,
  data: quote.swapTx.data,
  value: quote.swapTx.value ? BigInt(quote.swapTx.value) : 0n,
});

console.log("Transfer tx:", hash);

See the GET /swap/approval API reference for every parameter and the full response shape.

The integration code is identical for every stablecoin route — call /swap/approval, execute any approvals, then send the returned transaction. Across handles settlement behind the scenes.

On this page