Modes
With
fast, invest what arrived (netOut), not what you burned.
Networks
Bridging is currently mainnet-only, between two chain keys:
Additional chains will be added as they launch —
quote / initiate reject
unsupported chain keys with a 400.
Quickstart (EVM → Solana)
All amounts are USDC base units (6 decimals) as strings —"1000000" is 1 USDC.
Confirm the approval before burning. Wait for the
approvalTx receipt and for the
allowance to be readable on-chain before sending burnTx — load-balanced RPCs lag a few
seconds, and an early burn reverts with ERC20: transfer amount exceeds allowance.Solana-source burns
How a Solana-side burn gets signed depends on whose wallet is burning:- Managed wallet
- BYOW
When See Managed wallets — Withdrawing for the full
withdrawal flow.
sourceAddress is a Cesto-managed Solana wallet (provisioned via users.create
under your API key), Cesto signs and lands the burn server-side — the sponsor pays
the transaction fee and the CCTP message-account rent, so managed wallets need no
SOL. initiate returns { status: 'BURN_SUBMITTED', burnTxHash, burn: null }
instead of an unsigned burn, so skip submitBurn (re-submitting the same hash is
safe/idempotent) and go straight to waitForTransfer:The recipient address
recipient is always a wallet — hex account on EVM, owner wallet on Solana. CCTP mints
into a token account, so for Solana destinations Cesto derives the USDC ATA itself and, if
it’s the user’s first transfer, creates it at mint time (relayer pays the rent — no SOL
needed). quote’s ataExists tells you which case you’re in.
Bridge, then invest
Once a transfer completes, open the position with the arrived amount (netOut, not the
burn amount — fast mode deducts its fee at mint):
- Managed
- BYOW
solana → base back to the user’s EVM wallet (see
Solana-source burns for who signs that burn).
Method reference
bridge.quote(params) → BridgeQuote
BridgeChain
required
base or solana (mainnet).BridgeChain
required
Chain the USDC arrives on.
string
required
USDC base units (6 decimals) as a decimal string.
string
Destination wallet — enables
ataExists for Solana destinations.'standard' | 'fast'
default:"'standard'"
Speed / fee trade-off.
{ mode, amount, maxFee, estimatedFee, netOut, etaSeconds, minFinalityThreshold, ataExists? }.
Creates nothing.
bridge.initiate(params) → { transferId, status, burn, burnTxHash? }
All quote fields (recipient is required here), plus:
string
required
Source-chain wallet that will sign the burn — or a Cesto-managed Solana wallet, in which
case Cesto signs for it.
string
Your user reference, stored on the transfer for reconciliation.
status:
status: 'BURN_TX_BUILT'(default) —burnis{ kind: 'evm', chainId, approvalTx?, burnTx }or{ kind: 'solana', transaction, additionalSignerSecrets }.approvalTxis present only when the current USDC allowance is insufficient — confirm it beforeburnTx.status: 'BURN_SUBMITTED'(managed Solana source wallet) — Cesto signed and landed the burn itself, sponsor paying gas:burnisnullandburnTxHashholds the landed burn signature. SkipsubmitBurnand pollwaitForTransfer.
bridge.submitBurn(transferId, { burnTxHash })
Reports the landed burn. Cesto verifies it against Circle’s attestation (amount, chains,
recipient) and drives the rest in the background.
Circle can take a few seconds to index a fresh burn — short lags are absorbed internally;
on a
404, retry after a few seconds. Re-submitting the same hash is safe (it echoes the
status), and submitBurn is never auto-retried — poll getTransfer instead of re-sending
after a client-side timeout.bridge.getTransfer(transferId) / bridge.waitForTransfer(transferId, options?)
Current status, tx hashes, and — once attested — feeExecuted / netOut decoded from the
CCTP message. waitForTransfer resolves on COMPLETED and rejects with
Cesto.BridgeTransferFailedError on FAILED.
number
default:"5000"
Delay between status polls.
number
default:"1800000"
Max total wait (30 min — beyond standard-mode worst case). A timeout doesn’t stop the
transfer; keep polling
getTransfer.Transfer lifecycle
fast. The two you’ll surface to users: ATTESTING
(“waiting for Circle”, up to ~20 min on standard) and COMPLETED (funds arrived —
netOut, feeExecuted, mintTxHash are final). FAILED is terminal with the reason in
error — a burned amount is never lost (attestations don’t expire); contact Cesto support
with the transferId.
Common errors
Security model
- Non-custodial burn — Cesto builds the burn unsigned; only the user’s wallet signs. (Exception: Cesto-managed Solana wallets, which Cesto signs for by design — the key never leaves Cesto’s custody.)
- Gas-only relayer — the destination mint is permissionless by protocol design; the
relayer pays gas but can only deliver to the
mintRecipientbaked into the message. - Verified before driven — every burn is matched against Circle’s attested message before a mint is attempted; nonces make double-mints impossible.
- Key-scoped — a transfer is visible only to the API key that created it.
Constraints
- USDC only, base units as strings everywhere.
- Relayer-dependent — mints need a configured relayer on the destination chain; without
one,
initiateworks but the mint fails fast with a configuration error. - Funds only — positions are opened separately via Open a Position.