> ## Documentation Index
> Fetch the complete documentation index at: https://docs.li.fi/llms.txt
> Use this file to discover all available pages before exploring further.

# Cross-chain flows

> Sign once on one chain and end up with a position on another. The source flow runs in the user's transaction; the destination flow runs later, from an escrow, once the funds arrive. The same mechanism also runs a destination flow later on the same chain.

> The [Execution Model](https://docs.li.fi/composer/composer-api/concepts/execution-model.md) describes a flow that runs completely inside the one transaction the user signs. This page describes the one exception: a flow whose last part runs later, from an escrow. That later part usually runs on another chain, after a bridge, but it can also run on the flow's own chain.

A plain flow runs inside one transaction on one chain. A **cross-chain flow** adds a second part. The **source flow** runs in the user's transaction and bridges the funds into an **escrow** on the destination chain. Once they land, LI.FI's settlement service runs the **destination flow** from the escrow and pays its gas, so the user needs no native token on the destination chain.

Under the hood, a cross-chain flow is a **continuation**: you add one [`continuation.settle`](https://docs.li.fi/composer/composer-api/ops/continuation-settle) node to the source flow and pass it the destination flow. These pages call that node the **settle node**. To build one, follow [Build a cross-chain flow](https://docs.li.fi/composer/composer-api/guides/build-a-cross-chain-flow.md).

A continuation is not limited to cross-chain flows. The escrow can also live on the source flow's own chain. The user's transaction or a plain transfer from any wallet then funds it, and the destination flow runs later on that same chain. See [Same-chain continuations](#same-chain-continuations). This page uses cross-chain terms because a bridge into an escrow is the most common case.

| Term | Meaning |
| - | - |
| Source flow | The flow the user signs, on the source chain. It ends by sending funds to the escrow. |
| Destination flow | The flow that runs later on the destination chain, from the escrow. API field: `continuationFlow`. |
| Escrow | A one-time account on the destination chain that holds the funds until the destination flow runs. Every compile registers a new one. |
| Settlement service | LI.FI's service that watches the escrow, runs the destination flow from LI.FI's executor and pays its gas, or refunds the escrow. It is separate from the Composer API, with its own availability. |
| Minimum funding | The balance at which the destination flow runs: `escrow.floor`. |
| Minimum received | The least the user receives, checked on chain: `outputs['<settle id>.output'].amount.minimum`. |
| Destination chain | The chain the escrow lives on, where the destination flow runs and the outcome lands. In a [same-chain continuation](#same-chain-continuations), it is the source chain. |

## How a cross-chain flow runs

![Three lanes: Arbitrum source chain, the bridge, and Base destination chain. Step 1, compile, off chain: your backend calls POST /compose, and Composer registers an empty escrow on Base and commits the minimum received. Step 2, sign: the user signs once on Arbitrum; the source flow swaps, then bridges to the escrow, and the user pays gas only there. The bridge is in flight for seconds, depending on the bridge. Step 3, deliver: the USDC lands in the escrow, whose status becomes READY once the minimum funding is met. Step 4, run: LI.FI runs the destination flow and its settlement service pays the gas. Step 5, check: the minimum received is checked, then aUSDC goes to the user. Otherwise, if the destination flow doesn't run before expiry or the run fails, the USDC goes to your refund address on Base. Caption: one signature, gas on Arbitrum only, eventually consistent.](https://mintcdn.com/lifi/_8O8jxzvVRkQz2Ey/images/composer/cross-chain-flow-steps-light.svg?fit=max\&auto=format\&n=_8O8jxzvVRkQz2Ey\&q=85\&s=262f52e2d4b0ebdbba4c6ce5170d7b0a)

1. **Compile registers an escrow.** `POST /compose` proves the destination flow at the minimum funding and registers a fresh escrow on the destination chain with LI.FI's settlement service. The escrow is owned by the signer and holds the terms of the run: the destination flow, the minimum received, the outcome's `destination`, a spending cap, an expiry and a refund address.
2. **The user signs once.** The source flow runs on the source chain and bridges the funds into the escrow. The user pays gas only for this transaction.
3. **The funds land.** Once the balance reaches the minimum funding (`escrow.floor`), the escrow becomes `READY`. A balance below the minimum funding never starts a run.
4. **The destination flow runs.** LI.FI's settlement service takes up to `escrow.cap` from the escrow and runs the destination flow from LI.FI's executor. It pays the gas.
5. **The outcome is checked.** The settlement contract checks the minimum received on chain and forwards the outcome to `destination`. Leftovers go to the `refund` address. If the destination flow doesn't run before expiry, or the run fails, the escrow's balance is refunded to `refund` automatically, on the destination chain.

Each part is atomic on its own chain. The cross-chain flow as a whole is eventually consistent: the total time depends on the bridge and on when the destination flow runs.

## Which cross-chain path?

| You want to… | Use | Escrow? | Example |
| - | - | - | - |
| **Deposit into a supported vault** on another chain | LI.FI API: `GET /v1/quote` to the vault token. See [Cross-chain deposits](https://docs.li.fi/composer/lifi-api/guides/cross-chain-compose.md). | No | USDC on Arbitrum into a Morpho vault on Base |
| **Deliver only:** send tokens to an address on another chain | Composer API: [`lifi.bridge`](https://docs.li.fi/composer/composer-api/ops/lifi-bridge) with a `destination` | No | Send USDC to a wallet on Base |
| **Deliver, then act:** run your own steps when the funds arrive | Composer API: a destination flow with [`continuation.settle`](https://docs.li.fi/composer/composer-api/ops/continuation-settle) | Yes | [Bridge and deposit](https://docs.li.fi/composer/composer-api/recipes/bridge-and-deposit.md), [Pay cross-chain](https://docs.li.fi/composer/composer-api/recipes/pay-cross-chain.md) |

The rest of this page is about the third row. If everything can happen in the user's transaction, use a plain flow instead: a plain flow is atomic, a continuation is not. Nothing guarantees when the destination flow runs either; the fallback is a refund.

## Who runs what

| | Source flow | Destination flow |
| - | - | - |
| What it is | The flow you compile | The settle node's `continuationFlow` |
| Where it runs | The source chain | The destination chain, where the escrow lives |
| Who runs it | The user's [execution proxy](https://docs.li.fi/composer/composer-api/concepts/flow-anatomy.md) | LI.FI's executor, through its own execution proxy |
| When it runs | Inside the user's transaction | Later, once the escrow holds the minimum funding |
| Who pays for its gas | The user | LI.FI's settlement service |

The destination flow is an ordinary flow with one input, the token the escrow receives. The settle node binds the funding, the source flow sends those funds into the escrow, and the destination flow runs from them later.

## Funding the escrow

In a cross-chain flow the escrow is funded **by delivery**: the settle node's `bind.input` is the [future output](https://docs.li.fi/composer/composer-api/ops.md#future-outputs) of a [`lifi.bridge`](https://docs.li.fi/composer/composer-api/ops/lifi-bridge) or a `lifiIntents.order` that has no `destination`. That op delivers straight into the escrow on its destination chain, and the user signs one transaction, on the source chain. The compiler infers the mode from the binding, so the settle node sets no `funding`.

The minimum funding comes from the bridge's or the order's quote, and the funding must carry an enforced minimum. The [op reference](https://docs.li.fi/composer/composer-api/ops/continuation-settle.md#funding-rules) gives the exact rules. The escrow can also be funded on one chain, without a bridge; see [Same-chain continuations](#same-chain-continuations).

## Standard and exact destination flows

A destination flow is standard by default. Set `exact: true` on the settle node to make it exact. The destination flow document is the same in both cases; what the escrow commits to differs.

| | Standard (default) | Exact (`exact: true`) |
| - | - | - |
| The escrow commits to | The minimum received, and the destination flow's balance and allowance predicates | The destination flow's compiled calldata and LI.FI's executor |
| When it runs | LI.FI's settlement service quotes the destination flow again, so a swap or a zap gets a fresh route | LI.FI's executor runs the compiled bytes, unchanged |
| Ops that quote off chain, such as `lifi.swap` | Allowed | Rejected: a quote would not hold until the run |
| Payments to a third party (`core.transfer`, `core.call`) | Rejected | Allowed |
| Funding token | ERC-20 or native coin | ERC-20 only |
| Outcomes | Exactly one | One, or none (`outcomes: []`) |
| Pick it when "done" means | A token or a position reached `destination` | One specific payment or call ran: an invoice payment, a mint, a registration |

A standard destination flow cannot express "pay this invoice": an invoice counts as paid only when one specific call ran. An exact destination flow binds the escrow to its compiled calldata, so the escrow runs only those bytes. The response discloses them in `settlements[<settle id>].binding`, so you can check them before anyone funds the escrow. The op reference lists [which ops a destination flow can run](https://docs.li.fi/composer/composer-api/ops/continuation-settle.md#which-ops-a-destination-flow-can-run) and the [exact rules](https://docs.li.fi/composer/composer-api/ops/continuation-settle.md#exact-destination-flows).

## What is enforced on chain

A contract checks each of these when the destination flow runs:

* **The minimum received.** The settlement contract checks the outcome against the minimum received (`outputs['<settle id>.output'].amount.minimum`) before it forwards the outcome to `destination`. A run that would deliver less reverts.
* **The spending cap.** A run spends at most `escrow.cap`. See [How much a run spends](https://docs.li.fi/composer/composer-api/ops/continuation-settle.md#how-much-a-run-spends).
* **Committed predicates.** Balance and allowance invariants in the destination flow add predicates that the settlement contract checks. The compile response lists them in `verificationByNode['<settle id>'].assertedPredicate`.
* **For exact destination flows: the bytes and the executor.** Only LI.FI's executor (`binding.executionTarget`) can run the escrow, and only with the payload whose hash is `binding.payloadHash`.

For a standard destination flow, the minimum received, the predicates, the spending cap and the refund address are part of the settlement data the escrow commits to at compile time. The calldata that runs is not.

## What is not enforced on chain

* **Leftovers in a standard destination flow.** The transfer of leftovers to `refund` is part of the stored destination flow that LI.FI's settlement service runs; only the minimum received is checked on chain. In an exact destination flow it is inside the bound calldata, so it runs as compiled.
* **Expiry.** The settlement service refuses to run the destination flow after the stored expiry; no contract checks it. Keep `validity.expiresAtMs` as short as the funding allows.
* **Timing.** Nothing guarantees when, or whether, the destination flow runs. If it does not, the escrow is refunded.
* **The expected outcome.** `amount.estimate` on the settle node's output is never enforced. Only `amount.minimum`, the minimum received, is.
* **`fill.validUntilMs`.** The compile response's deadline for submitting the user's transaction is advisory.

> [!WARNING]
>
> Send only the funds the compile plans for, before the escrow expires. Funds that land after expiry are never used for a run, and a balance above `escrow.cap` is not used by the run. The [op reference](https://docs.li.fi/composer/composer-api/ops/continuation-settle.md#how-much-a-run-spends) and [Escrow status](https://docs.li.fi/composer/composer-api/reference/escrow-status.md#typical-paths) say what happens to each. Never fund an escrow from a `status: 'partial'` (HTTP 206) response or from an older compile.

## Lifecycle

[Escrow status](https://docs.li.fi/composer/composer-api/reference/escrow-status.md) reports each escrow's status and owns the lifecycle. On the happy path the escrow reaches `COMPLETED`, and the destination flow runs at most once. A funded escrow whose destination flow does not run before expiry, or whose run fails, is refunded to `refund` automatically and ends `REFUNDED`. An escrow that never received funds has nothing to refund and stays `EXPIRED`.

## Limitations

* **Composer API only.** Continuations, cross-chain or same-chain, are available through `POST /compose`, not through the LI.FI API's `/v1/quote`.
* **One hop.** The outcome lands on the escrow's chain. A destination flow cannot bridge and cannot contain another `continuation.settle`, so a cross-chain flow cannot end on a third chain. Deliver the funds into an escrow on the chain where the outcome must land, and let the destination flow run there.
* **One outcome per settle node.** For a second delivery, add a second settle node.
* **Served chains only.** See [Availability](#availability).

> [!WARNING]
>
> **Smart-contract-wallet signers.** The escrow's `owner` is the signer, and `refund` defaults to the signer: both are the signer's address **on the destination chain**. A smart-contract wallet deployed only on the source chain may have no usable address there. Set `refund` and the outcome's `destination` to addresses you control on the destination chain.

## Availability

Continuations, cross-chain or same-chain, are served on these 13 mainnets. No testnet is served. The settlement contract has the same address on each; see [Addresses](https://docs.li.fi/composer/composer-api/reference/addresses.md#settlement-contract-catvalidatorv2).

| Chain | Chain ID |
| - | - |
| Ethereum | 1 |
| Optimism | 10 |
| BSC | 56 |
| Polygon | 137 |
| HyperEVM | 999 |
| Pharos | 1672 |
| Tempo | 4217 |
| Robinhood Chain | 4663 |
| Arc | 5042 |
| Base | 8453 |
| Plasma | 9745 |
| Arbitrum | 42161 |
| Avalanche | 43114 |

* A settle node whose funding chain or outcome chain is not in this list fails with `validation_error` before any escrow is registered.
* On Tempo and Arc, the native asset is an ERC-20 token. A native outcome on these chains must name that token instead of the zero-address native sentinel: pathUSD (`0x20C0000000000000000000000000000000000000`) on Tempo, USDC (`0x3600000000000000000000000000000000000000`) on Arc. This rule does not affect other outcomes.

## Same-chain continuations

A continuation doesn't need a bridge. Without one, the escrow lives on the source flow's own chain, and the destination flow runs there later, after the user's transaction has ended. LI.FI's settlement service still runs it and pays its gas, and the settlement contract still checks the minimum received. Two funding modes keep a continuation on one chain:

| Use | How it works | Set |
| - | - | - |
| **Pay by transfer** | The source flow does not touch the funds. The compile returns a `fundEscrow` action: a plain ERC-20 `transfer(escrow, amount)` or a native send, marked `submitter: 'anyone'`. Any wallet can send it, for example a payer who scans a QR code, because the escrow credits by balance, not by sender. The destination flow runs once the transfer lands. | `funding: 'external'` on the settle node, and a plain amount for its input |
| **Exact payment on one chain** | The user's transaction ends with a transfer from the execution proxy into an escrow on the same chain, and an exact destination flow runs one specific call later. The transfer moves the realised amount, so when a swap funds the escrow it can receive more than `escrow.amount`. | `exact: true`, with `bind.input` a declared input or an upstream output |

A same-chain continuation that only needs a standard destination flow is usually better as a plain flow: a plain flow runs atomically in the user's transaction.

> [!NOTE]
>
> With pay by transfer, an escrow whose destination flow doesn't run refunds the `refund` address, which defaults to the signer, not to the person who paid. Set `refund` to the payer when you know it.

The guide has short samples in [Other ways to fund the escrow](https://docs.li.fi/composer/composer-api/guides/build-a-cross-chain-flow.md#other-ways-to-fund-the-escrow).

## See also

* [Build a cross-chain flow](https://docs.li.fi/composer/composer-api/guides/build-a-cross-chain-flow.md): step by step.
* [`continuation.settle`](https://docs.li.fi/composer/composer-api/ops/continuation-settle): every config field, rule and error.
* [Escrow status](https://docs.li.fi/composer/composer-api/reference/escrow-status.md): track the escrow.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.