name 和 id 字段(输入名称、节点 id、flow 自身的 id)都是用户自定义的。你在编写时挑选它们;编译器仅用它们来将输出与下游绑定关联起来。请选择简短、有意义的名称,例如 amountIn、swap、zap。当你调试线格式 JSON 时,读到的就是它们。
顶层形态
chainId 是此 Flow 中每个 call 所针对的 EVM 链;资源位于不同链上的输入会在构建时被拒绝。inputs 声明 flow 所消费的具名值;nodes 是有序的 op call 列表。关于每个键逐字段的参考,参见 Flow Schema。
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;关于 guards 的作用,参见 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。
组合到一起
swap-and-zap quickstart 生成的 Flow,在 builder.build() 之后大致如下:
Inputs 和节点绑定携带 resources(代币余额)和 handles(类型化标量)。下一页 Resource Model 介绍它们在运行时如何表现。
另请参阅
- Flow Schema —— 每个键逐字段的参考。
- Resource Model —— resources 和 handles 在运行时如何表现。
- References ——
input.*、context.*和<nodeId>.<port>refs 如何解析。 - Execution Model —— 一个 Flow 如何变成 calldata。

