Skip to main content
This walkthrough runs the complete Swaps lifecycle against Base mainnet: set your fee once, quote 100 USDC into WETH, execute the quote from a Turnkey wallet, and poll until the swap settles onchain. Prerequisites
  • A Pay As You Go, Pro, or Enterprise parent organization
  • A Turnkey API key pair
  • A wallet account holding USDC on Base, plus ETH on Base for gas if you don’t sponsor
  • An EVM wallet account in your parent organization if you want to charge a client fee. Omit the fee configuration to swap with a client fee of 0.
1

Initialize the client

All requests go through the generic request method of TurnkeyClient, stamped by your API key. Execution confirms asynchronously, so define a polling helper here as well.
2

Configure your fee

One-time setup on your parent organization: your rate in basis points and the wallet account that collects it. The configuration applies to every swap under the parent organization, and quotes reflect it from this point on; without one, quotes carry a client fee of 0.
3

Request a quote

USDC has 6 decimals, so 100 USDC is "100000000" raw units. Both chains derive from the CAIP-19 identifiers — matching prefixes here (eip155:8453) make this a same-chain swap.
4

Show the user the quote

Quoted amounts are already net of all fees — Turnkey’s and yours — so outputAmount is what the recipient receives. Check expiresAt before executing; an expired quote fails, and a fresh quote is more likely to fill.
5

Execute the swap

Execution is pinned to the quote: pass its quoteId and restate the economics the user was shown. Turnkey constructs the transaction, batches any required ERC-20 approval into it, signs with the wallet derived from the quote, and broadcasts. The signer is not resupplied here — it comes from the bound quote.With sponsor: false, the wallet pays its own gas. Set it to true to have Gas Station cover it (requires gas sponsorship enabled for your organization).
6

Poll to settlement

ACTIVITY_STATUS_COMPLETED on the execute activity only means the swap was accepted and enqueued. Poll get_swap_status with the swapRequestId until it reports a terminal state — that’s the only place the actual settled amount appears.
This Base example is same-chain, so FAILED is ORIGIN_TRANSACTION_FAILED and has no refund. PROVIDER_FILL_FAILED and refund enrichment apply to cross-chain swaps. See What FAILED means.

Going cross-chain

The same code runs a cross-chain EVM ↔ EVM swap — only the outputToken changes. Give it a different EVM CAIP-2 prefix — say USDC on Arbitrum, eip155:42161/erc20:<USDC_ON_ARBITRUM> — and omit destinationAddress. Asset identifiers come from list_supported_assets. For EVM ↔ SVM, change the output protocol as well — say Solana USDC, solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/token:EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v — and set destinationAddress on both the quote and the execute to a raw Solana address. Do not pass a wallet account ID, a private key ID, or a CAIP identifier. After broadcast:
  • The swap stays PENDING past origin-chain inclusion until the destination leg settles, so poll every 5–10 seconds rather than every second.
  • On COMPLETED, destinationTxHashes carries the destination-chain transactions. swapKind in the response tells you which model applied.
  • On FAILED, refund fields can arrive after the status flip. Keep polling if refund is absent.

Dive deeper

Swaps overview

— Fee model, chains, routes, and the full API surface.

Enable swaps

— Fee configuration and the fee receiver.

Get a quote

— Quote fields, expiry, and slippage.

Execute a swap

— Gas sponsorship, approvals, and the trust boundary.

Track swap status

— Lifecycle states, failures, and refunds.