Skip to main content

FX trading

FX runs across two rails behind one flow: the AMM (indicative quotes, gasless Permit2 relay) and RFQ (firm market-maker quotes, on-chain escrow). Both are non-custodial — you sign the value operation yourself.
Supported assets are environment-specific. Call GET /currencies for the live set. Sepolia currently serves e.g. USDC, USDT, EURC; symbols like EURx are not valid and return 400 unsupported_asset. The examples below use USDC → EURC.
Signer + permissions. Value ops are signed by one of your registered signer wallets — your primary by default; pass source_wallet to target a specific one. The account must be permitted (KYC / launch-access) for the action, or the op is refused fail-closed with 403 "Source wallet is not permitted for swap|pay". Register a signer first via POST /wallets.

The flow

Order states: quoted → accepted → awaiting_funding → funded → settling → settled (or failed / expired / refunded). route is "amm" or "rfq"; RFQ quotes are firm, AMM quotes indicative.

AMM — gasless relay

The accept response returns a permit2_witness payload:
Sign the order as a Permit2 PermitWitnessTransferFrom using witnessTypeString, then POST /fx/orders/{id}/submit { signature }. The relayer only broadcasts your signed order — it cannot move funds without your signature, and the on-chain contract rejects a signature that doesn’t match the exact order.

RFQ — self-broadcast escrow funding

RFQ differs at the submit step: you broadcast the escrow-funding transaction (the MM settles against it), then post its tx_hash. The accept response’s signing.funding carries everything you need.
1

Sign the Permit2 witness

Sign a Permit2 PermitWitnessTransferFrom with your registered signer (= quote.taker), same Permit2 domain as the AMM path, witness type RfqEscrowFunding(address signer,bytes32 executionId,address escrow,bytes32 quoteHash,address token,uint256 amount,uint256 deadline,uint256 nonce).
2

Broadcast the funding tx yourself

Call escrowQuoteWithPermit2(quote, providerSignature, funding, permit2Signature) on funding.escrow. This tx costs you gas — RFQ funding is not relayed.
3

Submit the tx hash

POST /fx/orders/{id}/submit { "tx_hash": "0x…" } — the backend verifies the on-chain QuoteEscrowed event before advancing to funded → settled.
The RfqEscrowFunding field order must match witnessTypeString exactly, or the escrow rejects the signature.