Supported Chains

Cross402 supports paying from one chain and settling on another, optionally in a different stablecoin. A payment intent declares two chains and (optionally) two assets:

  • payer_chain — where the payer sends stablecoins.
  • target_chain — where the merchant receives stablecoins. Optional; defaults to base.
  • payer_asset — the token the payer signs against. Optional; defaults to "usdc". One of "usdc" | "usdt" | "usdt0".
  • target_asset — the token the merchant receives. Optional; defaults to "usdc". Same allowed values.

Clients that omit payer_asset / target_asset continue to behave exactly as before — both fields default to "usdc" with no change in wire format. See Token × Chain matrix for what's supported per chain.

The set of target chains available to your integration is served by GET /api/chains. If a chain appears in that response, you can use it as a target_chain. Any chain supported as a payer can also be used as a target.

Status legend

  • Live — callable. You can pass the identifier as payer_chain or target_chain and the call will succeed (assuming the usual validation). Treat GET /api/chains as authoritative for the exact set exposed by your deployment.

Payer chains

Chain Identifier Go Constant TS Constant USDC Decimals Status
Solana solana pay.ChainSolanaMainnet Chain.SolanaMainnet 6 Live
Base base pay.ChainBase Chain.Base 6 Live
Ethereum ethereum pay.ChainEthereum Chain.Ethereum 6 Live
Polygon polygon pay.ChainPolygon Chain.Polygon 6 Live
HyperEVM hyperevm pay.ChainHyperEVM Chain.HyperEvm 6 Live
Arbitrum arbitrum pay.ChainArbitrum Chain.Arbitrum 6 Live
BSC bsc pay.ChainBSC Chain.BSC 18 Live
Monad monad pay.ChainMonad Chain.Monad 6 Live
SKALE Base skale-base pay.ChainSKALEBase Chain.SkaleBase 6 Live (payer-only)
MegaETH megaeth pay.ChainMegaETH Chain.MegaEth 18 Live (payer-only)
TRON tron — (USDT-only) 🚩 gated · TRON_ENABLED

TRON is USDT-only (no USDC is wired) and is gated behind the TRON_ENABLED deployment flag — intents naming a TRON chain return 400 while the gate is off. Pass the string literal "tron" as the chain identifier. A Nile testnet variant (tron-nile) mirrors the mainnet wiring.

Per-chain notes for BSC, Monad, SKALE Base, MegaETH, and TRON appear at the end of this page under Per-chain notes.

Target chains

Every payer chain is also a valid target. One caveat applies:

  • GET /api/chains is authoritative. It lists the chains accepted as a target_chain for your deployment. Target chains are validated at intent creation; if you pass an unsupported value, the API returns 400 with an error that lists the currently accepted target chains.
GET /api/chains

Response:

{
  "chains": ["base", "ethereum", "hyperevm", "polygon", "solana", "skale-base", "megaeth"],
  "target_chains": ["base", "ethereum", "hyperevm", "polygon", "solana"]
}

The two lists are independent — chains enumerates valid payer_chain values and target_chains enumerates valid target_chain values. Payer-only chains (e.g. skale-base, megaeth) appear in chains but not in target_chains. The lists are stable per deployment.

Payer × target matrix

Any payer chain can pair with any target chain exposed by your deployment, including same-chain routes (e.g. base → base). The table below covers common combinations. The Payer sig and Target sig columns show the x402 signing flavor used on each leg — the SDK picks these automatically from payment_requirements.

Payer → Target Payer sig Target sig Status
solana → base Solana VT v0 EIP-3009 Live
solana → ethereum Solana VT v0 EIP-3009 Live
base → ethereum EIP-3009 EIP-3009 Live
base → polygon EIP-3009 EIP-3009 Live
polygon → base EIP-3009 EIP-3009 Live
base → solana EIP-3009 Solana VT v0 Live
base → base (same chain) EIP-3009 EIP-3009 Live
polygon → arbitrum EIP-3009 EIP-3009 Live
bsc → base Permit2 + approval extension EIP-3009 Live

Callers do not choose the signing flavor; the SDK derives it from payment_requirements and the (payer, target) pair. Both legs run through the x402 protocol. See Multi-Chain Settlement for the mechanics.

Token × Chain matrix

Every EVM and Solana chain ships at minimum with USDC. USDT0 (LayerZero's omni-Tether) is wired on the chains where it has a verified deployment; legacy native USDT is wired on Ethereum / BSC / Base / Solana (gated behind USDT_ENABLED), on Polygon / Arbitrum (live, no gate), and on TRON (USDT-only, gated behind TRON_ENABLED). The matrix below is authoritative.

Chain USDC USDT0 USDT (native)
Solana Live 🚩 gated · SPL (same path as USDC)
Base Live 🚩 gated · Permit2 + approval extension
Ethereum Live 🚩 gated · Permit2 + approval extension
Polygon Live (standard EIP-3009) Live · salted EIP-712 domain Live · alias of USDT0 (same contract)
Arbitrum Live Live · domain name="USD₮0" (U+20AE TUGRIK), version="1" alias of USDT0 (same contract, EIP-3009)
Monad Live Live · domain name="USDT0", version="1"
HyperEVM Live Live · domain name="USD₮0", version="1"
MegaETH Live (payer-only) (native USDm) Live · domain name="USDT0", version="1"
BSC Live (Binance-Peg) 🚩 gated · Permit2 + approval extension
SKALE Base Live (payer-only)
TRON 🚩 gated (TRON_ENABLED) · Permit2, one-time approve

Legend: Live = the (chain, asset) pair is callable today. 🚩 gated = wired but gated behind a deployment flag — USDT_ENABLED for Ethereum / BSC / Base / Solana USDT, TRON_ENABLED for TRON; calls return 400 invalid payer_asset (or 400 on the TRON chain itself) while the gate is off. = not wired; 400 payer_asset not configured on chain if requested.

Chain-specific caveats

These are the details you need at signing and display time.

Token contracts and decimals

Always read extra.decimals from the payment_requirements object on the CreateIntent response. Do not hardcode 6. Mainnet token addresses are pinned by the backend per chain.

USDC (default, payerAsset omitted or "usdc")

Chain Decimals Token Mainnet Address Status
Solana 6 USDC EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v Live
Base 6 USDC 0x833589fcd6edb6e08f4c7c32d4f71b54bda02913 Live
Ethereum 6 USDC 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 Live
Polygon 6 USDC 0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359 Live
HyperEVM 6 USDC 0xb88339CB7199b77E23DB6E890353E22632Ba630f Live
Arbitrum 6 USDC 0xaf88d065e77c8cC2239327C5EDb3A432268e5831 Live
Monad 6 USDC 0x754704Bc059F8C67012fEd69BC8A327a5aafb603 Live
SKALE Base 6 USDC.e (Bridged USDC) 0x85889c8c714505E0c94b30fcfcF64fE3Ac8FCb20 Live (payer-only)
BSC 18 Binance-Peg USDC 0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d Live
MegaETH 18 USDm (MegaUSD, native) 0xFAfDdbb3FC7688494971a79cc65DCa3EF82079E7 Live (payer-only)

USDT (payerAsset: "usdt")

USDT payers on BSC, Ethereum, and Base must hold native gas (BNB / ETH) to land a one-time approve(Permit2, amount) before payment. TRON payers need TRX for the same one-time approve. Polygon USDT uses EIP-2612 with a salted domain and Arbitrum USDT uses EIP-3009 — no gas required on either. See USDT Signing for details.

Chain Decimals Token Mainnet Address Payer gas required
BSC 18 USDT (BEP-20) 0x55d398326f99059fF775485246999027B3197955 Yes (BNB)
Ethereum 6 USDT (ERC-20) 0xdAC17F958D2ee523a2206206994597C13D831ec7 Yes (ETH)
Base 6 USDT (ERC-20) 0xfde4C96c8593536E31F229EA8f37b2ADa2699bb2 Yes (ETH)
Polygon 6 USDT (PoS) 0xc2132D05D31c914a87C6611C10748AEb04B58e8F No (EIP-2612 salted, gas sponsored)
Arbitrum 6 USDT (USD₮0 contract) 0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9 No (EIP-3009)
Solana 6 USDT (SPL) Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB No (fee payer sponsored) · 🚩 gated
TRON 6 USDT (TRC-20) TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t One-time (TRX) for approve(Permit2) · 🚩 gated

EIP-712 domain values per asset

Always read extra.name, extra.version, and (where present) extra.domainType from payment_requirements. Never hardcode these — they vary per (chain, asset) deployment:

  • USDC — defaults name = "USD Coin", version = "2". Exceptions: SKALE Base uses "Bridged USDC (SKALE Bridge)", MegaETH native USDm uses "MegaUSD" + version = "1".
  • USDT0name is "USD₮0" (Tugrik U+20AE) on Arbitrum / HyperEVM; plain ASCII "USDT0" on Monad / MegaETH / Polygon. version = "1" everywhere.
  • USDT (native) — on Polygon (alias of USDT0, same contract) it signs via Permit2 + EIP-2612 against the salted EIP-712 domain (name = "USDT0", version = "1"); on Arbitrum it signs EIP-3009 against the USD₮0 domain. Ethereum / BSC / Base USDT settle via Permit2 with the approval extension and have no token EIP-712 domain at all — the only typed data signed is Permit2's own Permit2 domain.

Hardcoding "USD Coin" v2 on SKALE Base or MegaETH produces signatures the on-chain contract rejects.

Per-asset transfer scheme

TransferScheme is per-(chain, asset), not per-chain. The same chain can use different schemes for different assets:

  • EIP-3009 TransferWithAuthorization — Circle USDC on Base / Ethereum / Polygon / HyperEVM / Arbitrum / SKALE Base; USDT0 on Arbitrum / Monad / HyperEVM / MegaETH; native USDT on Arbitrum (same USD₮0 contract).
  • Permit2 + EIP-2612 — USDC on Monad / MegaETH; Polygon USDT / USDT0 (same contract 0xc2132D..., uses EIP-2612 against a salted EIP-712 domain — no EIP-3009). The payer signs the permit off-chain (attached as the eip2612GasSponsoring extension) and the facilitator submits it — gas is sponsored by Cross402.
  • Permit2 + approval extension — legacy native USDT on Ethereum / BSC / Base, and BSC Binance-Peg USDC (no EIP-2612 on any of them). Signalled as assetTransferMethod: "permit2" with extensions: ["eip2612GasSponsoring", "erc20ApprovalGasSponsoring"]. The first payment from a (chain, wallet) pair needs a one-time approve(Permit2, max) — a payer-signed raw transaction relayed by the facilitator via the erc20ApprovalGasSponsoring extension, or an on-chain approve sent by the payer's wallet directly; either way the payer holds native gas. Subsequent payments are signature-only. USDT on these chains is gated behind the USDT_ENABLED deployment flag.
  • TRON Permit2 — USDT on TRON (SUN.io Permit2 deployment). One-time on-chain approve(Permit2, max) prepared/broadcast by the TRON Signing helper API (costs TRX), then off-chain PermitWitnessTransferFrom signatures per payment. Gated behind TRON_ENABLED.
  • Solana SPL — USDC and USDT on Solana; partial-signed VersionedTransaction v0.

The payment_requirements.extra.assetTransferMethod field signals the scheme:

Value Meaning
absent EIP-3009 (default for USDC on most EVM chains)
"permit2" Permit2. extra.extensions lists the accepted gas-sponsoring extensions (EIP-2612 permit vs. raw approve); on TRON, extra additionally carries permit2Address and spender
"eip3009" Explicit EIP-3009 marker (emitted on TRON's eip3009 method only; EVM EIP-3009 leaves the field absent)

See USDT Signing for the full USDT flow.

Polygon: salted EIP-712 domain

Polygon's native Tether contract (0xc2132D05D31c914a87C6611C10748AEb04B58e8F, used as both USDT0 and native USDT) signs against the non-standard Polygon-PoS layout:

EIP712Domain(string name, string version, address verifyingContract, bytes32 salt)

where salt = bytes32(chainID) — chainId moves out of the domain type and into a salt field. The intent response's payment_requirements.extra.domainType == "salted" is the explicit signal to switch the signer's DOMAIN_SEPARATOR construction. Standard chainId-in-domain EIP-712 signatures fail verification against these contracts.

Usage

Specify chains with SDK constants, not hardcoded strings. targetChain is optional.

import { Chain } from '@cross402/usdc';

const intent = await client.createIntent({
  email: "merchant@example.com",
  amount: "100.50",
  payerChain: Chain.Base,
  targetChain: Chain.Ethereum,
});
resp, err := client.CreateIntent(ctx, &pay.CreateIntentRequest{
    Email:       "merchant@example.com",
    Amount:      "100.50",
    PayerChain:  pay.ChainBase,
    TargetChain: pay.ChainEthereum,
})

Per-chain notes

Caveats for chains whose token, signing flavor, or role differ from the default (Circle-native USDC, EIP-3009, payer + target).

BSC

  • Token: Binance-Peg USDC at 0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d, 18 decimals.
  • Signing: Permit2 PermitWitnessTransferFrom. Binance-Peg USDC has no EIP-2612, so a one-time approve(Permit2) must land on-chain first — payer-signed and relayed via the erc20ApprovalGasSponsoring extension, or sent by the payer's wallet directly (BNB gas from the payer either way).
  • Role: payer and target.
  • See BSC Signing for the full flow.

Monad

  • Token: USDC at 0x754704Bc059F8C67012fEd69BC8A327a5aafb603, 6 decimals.
  • Signing: Permit2 PermitWitnessTransferFrom + EIP-2612 Permit. Gas is sponsored by Cross402.
  • Role: payer and target.

SKALE Base

  • Token: USDC.e (Bridged USDC) at 0x85889c8c714505E0c94b30fcfcF64fE3Ac8FCb20, 6 decimals. Not Circle-native USDC.
  • Signing: EIP-3009 TransferWithAuthorization. EIP-712 domain name = "Bridged USDC (SKALE Bridge)", version = "2". Hardcoding "USD Coin" will fail signature verification.
  • Role: payer-only. Cannot be used as target_chain.

MegaETH

  • Token: USDm (MegaUSD, native) at 0xFAfDdbb3FC7688494971a79cc65DCa3EF82079E7, 18 decimals. Not USDC.
  • Signing: Permit2 PermitWitnessTransferFrom + EIP-2612 Permit. EIP-712 domain name = "MegaUSD", version = "1". Gas is sponsored by Cross402.
  • Role: payer-only. Cannot be used as target_chain.

TRON

  • Token: USDT-only — TRC-20 USDT at TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t, 6 decimals. No USDC is wired; requesting payer_asset: "usdc" on TRON fails.
  • Addresses: base58check (T… prefix), not EVM hex. This applies to wallet addresses, the token contract, and the payTo in payment_requirements.
  • Signing: Permit2 PermitWitnessTransferFrom against the SUN.io Permit2 deployment (TTJxU3P8rHycAyFY4kVtGNfmnMH4ezcuM9 on mainnet). payment_requirements.extra carries permit2Address (the EIP-712 verifyingContract) and spender (the x402ExactPermit2Proxy). A one-time on-chain approve(Permit2, max) is required per wallet — prepared and broadcast via the TRON Signing helper API, costing TRX from the payer's wallet. Payments after that are gasless off-chain signatures.
  • Gating: behind the TRON_ENABLED deployment flag — intents naming a TRON payer or target chain return 400 while the gate is off. Treat GET /api/chains as authoritative for whether your deployment exposes TRON.
  • Networks: mainnet (tron) plus the Nile testnet (tron-nile), mirroring the Base / Base-Sepolia split.
  • Role: payer and target (when the deployment wires a TRON proxy wallet).