Scenario
A payer holds ETH on Arbitrum. A merchant must receive exactly 990 USDC on Base, and a platform takes a 10 USDC fee. The payer signs one transaction on Arbitrum. A LI.FI Intents order delivers exactly 1,000 USDC into an escrow on Base, and an exact destination flow splits it and pays both recipients.What this recipe represents. Any payment that must land as exact amounts at specific addresses on another chain: an invoice with a platform fee, a payout split, a subscription charge.Here the destination flow is two plain transfers, so the recipe runs as is. In production you would usually replace them with one call to your own payment or invoice contract (
core.call). The escrow commits to the exact bytes either way, so nobody can change the recipients or the amounts after the payer signs.core.transfer and core.call. An exact destination flow (exact: true) binds the escrow to its compiled bytes. See Standard and exact destination flows.
Full example
Install withnpm install @lifi/composer-sdk @lifi/compose-spec viem; see Before you start for versions and the server-side API key. Set LIFI_API_KEY and PRIVATE_KEY in your environment.
- The Intents order delivers exactly the total. With
exactAmountOutand nodestination, the Intents solver delivers exactly 1,000 USDC into the escrow on Base, andescrow.flooris exactly the total, with no margin. - Split the total first. A run spends
min(escrow balance, escrow.cap), the cap is 10% above the expected funding, and anyone can send tokens to the escrow. A single split at 990 USDC would give the fee recipient 10 USDC plus any extra, up to 110 USDC. Splitting off the 1,000 USDC total first keeps both payments exact: the extra stays in the proxy and goes torefund. outcomes: []. Everything is paid out, so nothing comes back on Base, and the response has nooutputs['settle.output']. A zero-outcome exact destination flow must run on the funding chain.sweepTo: ownerreturns the order’s unspent Arbitrum USDC to the payer in the same transaction. All slack (swap slippage, the Intents solver’s price, your sizing buffer) comes back there, not on Base.
Run it
Save the file aspay-cross-chain.mts, add the submit loop from Bridge and deposit at step 4, and run it:
What to check
settlements.settle.escrow.flooris exactly1000000000: an exact-output order adds no margin.settlements.settle.bindingis present: the escrow is bound to the compiled transfers. Optional: verify the binding before funding.actionsholds theexecutetransaction on Arbitrum and nofundEscrow: one signature.- The escrow reaches
COMPLETED(Escrow status), and Base shows two USDC transfers from the proxy of LI.FI’s executor: 990 to the payee and 10 to the fee recipient. An escrow that is stillEXPIRED90 minutes after its expiry was never funded, for example because no Intents solver filled the order. - An unfilled order keeps the payer’s Arbitrum USDC locked in the LI.FI Intents escrow on Arbitrum. Nothing refunds it automatically. After the order expires (48 hours after it opens), anyone can call
lifiIntents.refund, which pays the order’s user: the signer’s wallet on Arbitrum. For an earlier refund, runlifiIntents.attestNonFillon Base after the fill deadline, thenlifiIntents.refundOnNonFillon Arbitrum. See Track and refund the order.
Troubleshooting
Every other settle-node error is in
continuation.settle errors.
Related
- Cross-chain flows: standard and exact destination flows.
continuation.settle: the exact rules.- Bridge and deposit: a standard destination flow funded by a bridge.

