> ## 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.

# Flow Structure

> 一份 Flow 文档的形态：inputs、calls，以及它们之间的绑定。

**Flow** 是一份描述多步骤 DeFi 操作的不可变 JSON 文档。每个 Flow 都由三部分组成：版本头、声明的 **inputs**，以及一个有序的 op **calls** 列表（也称为*节点（nodes）*）。

Flow 中所有的 `name` 和 `id` 字段（输入名称、节点 id、flow 自身的 `id`）都是**用户自定义的**。你在编写时挑选它们；编译器仅用它们来将输出与下游绑定关联起来。请选择简短、有意义的名称，例如 `amountIn`、`swap`、`zap`。当你调试线格式 JSON 时，读到的就是它们。

## 顶层形态

```json theme={"system"}
{
  "version": 1,
  "id": "swap-and-zap-weth-to-aave",
  "chainId": 1,
  "inputs": [ /* FlowInput[] */ ],
  "nodes":  [ /* Call[] */ ]
}
```

`chainId` 是此 Flow 中每个 call 所针对的 EVM 链；资源位于不同链上的输入会在构建时被拒绝。`inputs` 声明 flow 所消费的具名值；`nodes` 是有序的 op call 列表。关于每个键逐字段的参考，参见 [Flow Schema](/composer/composer-api/reference/flow-wire-format)。

## Inputs

每个输入要么是一个 **resource input**（一个代币，采用线性消费），要么是一个 **handle input**（一个类型化标量，如 `uint256` 或 `address`，采用复制模式）。

Resource input 在整个 flow 中携带一份余额。默认情况下，恰好有一个下游 call 消费它。复制模式绑定可以在不消费的情况下读取某个资源 —— 例如 `core.approve` 会引用某个资源以授权某个 spender，同时把余额留给之后的消费型绑定使用。同一资源的复制模式读取可以与一个消费型绑定共存。op manifest 的 port 元数据决定哪个绑定消费、哪个仅读取。

Handle input 是非线性的：一个表示截止时间或滑点容差的 `uint256` 可以被接入到每个需要它的 op 中。

## Calls（nodes）

一个 `Call` 是单次 op 调用。`nodes` 的顺序就是编译器降级它们的顺序。每个 call 都有一个用户自定义的 `id`（被下游 call 以 `<id>.<port>` 形式引用）、一个来自 manifest 的 `op` 名称、一个将其输入 port 接入到 refs 或字面值的 `bind` 映射、op 特定的 `config`，以及可选的、用于强制不变量的 `guards`。

关于 ref 语法，参见 [References](/composer/composer-api/concepts/ref-grammar)；关于 guards 的作用，参见 [Guards](/composer/composer-api/concepts/simulation-and-guards)。

## Ports 与 handles

Op 在 manifest 中声明类型化的输入和输出 **ports**。每个 port 都有一个**类型**（resource 或 handle）、resource port 的一个**模式**（消费型还是只读），以及一个**可用性**（输入还是输出）。SDK 会为这些 port 交给你 **handles**（`builder.inputs.amountIn`，或某个之前 op 调用返回的对象），并在序列化 Flow 时将它们转换为线格式的 `$ref` 字符串。校验器会拒绝 handle 类型或模式与 port 不匹配的绑定。

关于作用域规则、保留前缀和 handle 到 ref 的转换，参见 [References](/composer/composer-api/concepts/ref-grammar)。

## 组合到一起

`swap-and-zap` quickstart 生成的 Flow，在 `builder.build()` 之后大致如下：

```json theme={"system"}
{
  "version": 1,
  "id": "swap-and-zap-weth-to-aave",
  "chainId": 1,
  "inputs": [
    {
      "name": "amountIn",
      "resource": { "kind": "erc20", "token": "0xC02a…Cc2", "chainId": 1 }
    }
  ],
  "nodes": [
    {
      "id": "swap",
      "op": "lifi.swap",
      "bind":   { "amountIn": { "$ref": "input.amountIn" } },
      "config": { "resourceOut": { "kind": "erc20", "token": "0xA0b8…eB48", "chainId": 1 }, "slippage": 0.03 }
    },
    {
      "id": "zap",
      "op": "lifi.zap",
      "bind":   { "amountIn": { "$ref": "swap.amountOut" } },
      "config": { "resourceOut": { "kind": "erc20", "token": "0x98C2…6F5c", "chainId": 1 } },
      "guards": [ { "kind": "slippage", "port": "amountOut", "bps": 100 } ]
    }
  ]
}
```

> Inputs 和节点绑定携带 **resources**（代币余额）和 **handles**（类型化标量）。下一页 [Resource Model](/composer/composer-api/concepts/resources-and-ports) 介绍它们在运行时如何表现。

## 另请参阅

* [Flow Schema](/composer/composer-api/reference/flow-wire-format) —— 每个键逐字段的参考。
* [Resource Model](/composer/composer-api/concepts/resources-and-ports) —— resources 和 handles 在运行时如何表现。
* [References](/composer/composer-api/concepts/ref-grammar) —— `input.*`、`context.*` 和 `<nodeId>.<port>` refs 如何解析。
* [Execution Model](/composer/composer-api/concepts/execution-model) —— 一个 Flow 如何变成 calldata。
