This walks through one real transfer end to end: the user holds 2 USDT on Arbitrum and wants USDC in a Solana wallet. It is a cross-asset transfer, which makes it a good second example after the quickstart: the code is nearly identical, but what happens under the hood and what shows up in the quote are different.

1. Connect

Keyless requests work but are rate limited and priced with extra spread. See API keys.

2. Find the tokens

Addresses come from the catalog, never hardcoded. Both tokens have six decimals, so 2 USDT is the base-unit string "2000000".

3. Quote

recipient is the Solana wallet that receives the USDC. refund_address is an Arbitrum address, because refunds are always paid on the source chain in the deposited token.
What comes back for this trade: On a 2 USDT transfer the fixed gas components are the dominant cost, so the percentage difference between amount_in and amount_out is larger than it would be on a bigger trade. Render amount_out and min_amount_out to the user; the breakdown in fee_breakdown.components explains the gap. A quote’s price is fixed when issued. If the user sits on a confirmation screen, re-quote before signing. See Get a quote.

4. Deposit

src_token equals bridge_token_src, so on this lane the quote comes back with direct_transfer: true and the whole deposit collapses into one transaction: a plain ERC-20 transfer of the USDT to the escrow, with the 32-byte quote hash appended after the transfer calldata. No approval, no router call, the cheapest gas of any path.
This works because the indexer watches transfers into the escrow the same way it watches router deposits: it reads the transaction’s calldata, takes the trailing 32 bytes as the quote hash, and attributes the deposit to that order. That is also why the transfer must be the transaction’s own calldata, sent from the user’s wallet straight to the token contract. A transfer routed through a contract wallet or a batching layer hides the calldata and the deposit will not be attributed. The SDK’s ChainAdapter builds exactly this transaction when you pass { directTransfer: quote.directTransfer } to steps. If the flag comes back false, fall back to the router path: approve the vault if the allowance is short, wait for the approval to confirm, then call depositToken with the quote hash. See Deposit on EVM. Either way, deposit exactly amount_in; a different amount is a mismatched deposit and is refunded, not paid out proportionally. There is nothing to do on Solana. No claim, no attestation, no destination transaction. The operator’s fulfillment creates the recipient’s USDC token account if it does not exist yet.

5. Track

Poll GetOrder with the quote hash until the state is terminal. Before the deposit is indexed, the call fails with NotFound; that is expected for the first few seconds, so treat it as “keep polling” rather than an error.
The outcome is fulfilled in the normal case. If the lane is suspended or the peg moves past min_amount_out before fulfillment, the outcome is refunded and the 2 USDT returns to refund_address on Arbitrum, minus the refund fee. See Refunds. The same order is viewable at https://hular.dev/explorer/<quote_hash>.

Full code

A complete Node script. It uses the SDK for the API and viem for the Arbitrum transactions, so it runs standalone with a private key; in a browser app you would replace the viem section with createChainAdapter and the connected wallet, as in the quickstart.
Expected output:
With direct_transfer: true, which is the normal case on this lane, the whole transfer costs the user a single transaction. The approved line only appears on the fallback router path.

Next

Trade types

Guarantee the exact USDC amount with EXACT_OUTPUT.

Fees

What the asset_conversion component covers on this lane.

Deposit on EVM

Permit, permit2, direct transfer, and the swap paths.

Refunds

What happens if the lane cannot fill at the floor.