Scenario
A user holds USDC on Arbitrum and wants an Aave USDC position (aBasUSDC) on Base, with one signature on Arbitrum and no gas on Base. The bridged USDC lands after the Arbitrum transaction has ended, so no node in that transaction can deposit it.
A cross-chain flow closes the gap. A lifi.bridge with no destination delivers the USDC into an escrow on Base. Once it lands, LI.FI’s settlement service runs the destination flow, one lifi.zap into Aave, and the settlement contract checks the minimum received before it delivers the aBasUSDC to the user.
Build a cross-chain flow explains each step of this file.
Full example
Install withnpm install @lifi/composer-sdk @lifi/compose-spec viem; see Before you start for versions and the API key. The example signs with a private key through viem. Set LIFI_API_KEY and PRIVATE_KEY in your environment; never ship either to a browser.
Run it
Save the file asbridge-and-deposit.mts and run it:
What to check
settlements.settle.escrow.chainIdis8453: the escrow is on Base.escrow.flooris the minimum funding, derived from the bridge’s quote; see Funding rules.outputs['settle.output'].amount.minimumis the minimum received, the only amount the settlement contract enforces. Show it to the user as the guarantee;amount.estimateis not enforced.actionsholds the approval of Arbitrum USDC (if the proxy needs one), thenexecute, all on Arbitrum. There is nofundEscrowaction, because the bridge funds the escrow.outputs['bridge.amountOut']reportsrole: 'consumed'andconsumedBy: 'settle'.- The escrow status reaches
COMPLETED, withdestinationTxHashset. An escrow atREADYor later means the bridge has delivered, even if LI.FI still reportsPENDING. Escrow status maps each status to what to show your user.
- No
destinationon the bridge makes it deliver into the escrow. A bridge withoutdestinationmust feed a settle node; on its own it fails withvalidation_error. - No
fundingon the settle node. Bridge funding is inferred from the binding, and any authoredfundingvalue is rejected. - One hour of validity. The expiry must leave room for the bridge; the settlement service may shorten it, and the stored value is
escrow.expiresAtMs. refund: owner. The escrow lives on Base, so the refund address must be one you control on Base. For a smart-contract wallet that exists only on Arbitrum, set another address.- Only positions LI.FI can reach. The destination flow’s
lifi.zapneeds a synchronousenter-positionrouting edge on Base for the landing token. Pick targets fromGET /compose/zap-packs; the compile proves the destination flow and fails if no route exists.
FAILED, the escrow never receives funds: it has nothing to refund and stays EXPIRED after its expiry. Stop polling the escrow and read the transfer’s substatus in the LI.FI status response. A bridge that refunds on Arbitrum returns the USDC to the user’s execution proxy (result.userProxy), the bridge call’s sender, not to the wallet. lifi.bridge: Track the delivery shows how to move it back to the wallet.
If the bridged USDC lands but the destination flow doesn’t run, or a run ultimately fails, the USDC is refunded automatically to refund on Base; no user action is needed.
Troubleshooting
Every other settle-node error is in
continuation.settle errors.
Related
- Build a cross-chain flow: this flow, step by step.
continuation.settle: every config field and port.- Pay cross-chain: an exact destination flow funded by a LI.FI Intents order.

