Skip to main content
This recipe moves USDC from one chain to the same USDC on another chain, with an API key and no wallet signature. TetraFi executes the move from one of your workspace’s organisation wallets. Every step comes from one script, samples/http/recipe-cross-chain.sh.
The API may change until launch. Every change is listed in the Changelog.

Before you begin

You need bash, curl, jq and openssl, and an API key with Read quotes, Submit orders and Read orders (Authentication). The key also needs:
  • Venue trading and request signing. A move TetraFi executes for you from an organisation wallet granted to the key is a Basic trade, so the key needs the venue trading scope, its signing secret and venue trading switched on (Trading on your venue accounts).
  • An organisation wallet granted to it. A workspace owner, or an admin who manages credentials, grants the key the organisation wallets it may use, signed in with a second factor (Give a key organisation wallets).
  • Funds on the chain you sell from. The organisation wallet that sells must hold the USDC you move and gas on that chain: it sends the transactions itself.
Then export your environment, as in the Quickstart:
1

Find the chains USDC is on

GET /api/v1/assets lists every deployment of each asset. The chains of USDC’s native variant are the chains you can move it between. The script prints them and checks that both of your chains are among them.
Output on test networks (shortened)
The outputs on this page come from a run on test networks: Ethereum Sepolia (eip155:11155111), Optimism Sepolia (eip155:11155420), Base Sepolia (eip155:84532) and Solana devnet. In production you see main networks, such as Base (eip155:8453).Without TETRAFI_FROM_CHAIN and TETRAFI_TO_CHAIN, the script takes the first two chains listed, which may not be where your wallet holds USDC.
2

Quote the move

POST /api/v1/quotes with the same asset on both sides, each side pinned to its chain, and filters.locations set to ["crossChain"] so only moves between the two chains are quoted (Chains and routes).Pick a quote whose next is order: TetraFi executes it from an organisation wallet, so your key can order it. Its tradingSource names the wallet it trades from (financialAccountId and network), and fundingModel says how the move is funded (Wallets and accounts). The quote’s eta is how long delivery is expected to take.
Output on test networks (shortened)
A venue that cannot quote says why in sources. amountBelowMinimum comes with a detail naming the least you can move.You can send one live quote request every 3 seconds. The script waits details.retryAfter once when it gets 429 QUOTE_RATE_LIMITED.
3

Place the order

POST /api/v1/orders with the quote id and an Idempotency-Key header you generate and keep. A retry with the same key and body returns the first answer instead of moving the funds twice (Idempotency).A bridge that TetraFi trades from your organisation wallet executes within your limit: an order on a quote whose minReceiveRequired is true must carry minReceive, the least you accept to receive (Orders). Without it, the order is refused with 400 MIN_RECEIVE_REQUIRED and nothing is sent. Cross-chain quotes from such a venue are usually indicative, and the script sends minReceive whenever the quote asks for it: the quoted amount less 50 basis points. Change that with TETRAFI_SLIPPAGE_BPS.The script places the order only when you set TETRAFI_PLACE_ORDER=1.
The script prints the order response’s kind, quoteId and operation. A Basic trade’s operation holds the connectionId and operationId you read its status with:
Output (shortened)
4

Follow it until it ends

The order answers as soon as it is accepted. A move executed from an organisation wallet answers "kind": "basicTrade"; read it at its statusUrl every 10 seconds until terminal is true (Order status).While the funds are on their way, the status can read working or outcomeUnknown. Neither is a failure: keep reading, and never place a new order for it. When next says wait, read again after its retryAfter.
Output (shortened)
On test networks, a move from Base Sepolia to Ethereum Sepolia finished about two and a half minutes after the order.
5

Confirm it arrived

The venue trade’s own detail is under operation: executionStatus for the trade and settlementStatus for any later money movement. When the venue reports amounts, dispatch.inputSpent is what you paid and dispatch.outputReceived is what you received. A missing or null amount is unknown, not zero. dispatch.venueOrderId, when present, is the venue’s native order id.bounds.sell.amount is the most the trade spends, every fee charged in it included, and bounds.buy.amount the least it delivers: the limits you accepted, not the amounts that settled. The public response does not document delivery transaction hashes or your organisation wallet’s transaction steps.
Output (shortened)
To confirm arrival independently, check the receiving wallet’s balance on the destination chain in the app. Keep reading the order status if the trade or its money movement is not yet final.

Run the whole script

Progress goes to stderr and the summary to stdout:
Output

If no quote can be ordered

When no quote’s next is order, the script stops and its summary lists why, venue by venue:
Output (shortened)

In the app

On the Trade page, open Advanced filters and set Route to Cross-chain, with a from chain and a to chain.

Next steps

Wallets and accounts

Choose which organisation wallet trades or receives with source and deliverTo.

Order status

Every status a trade can read, and how often to poll.