既然你已经知道被传递的是什么(resources、handles),本页将介绍把它们接线到一起的 dotpath 语法。ref 是一个包裹在
{ "$ref": "…" } 中的 dotpath 字符串。Ref 让某个 Call 能够将它的某个输入 port 绑定到 Flow 中别处产生的值:一个声明的输入、前一个 call 的输出,或一个运行时上下文值。
该语法识别三种作用域,并保留少量前缀以避免歧义。
三种 ref 作用域
1. input.<name>
引用在 flow.inputs 中声明的一个 flow 级输入。
{ scope: "input", port: "amountIn" }。
2. context.<key>
引用一个运行时上下文值。目前仅识别两个键:
{ scope: "context", key: "sender" }。context.* 下的任何其他键都会被拒绝。
3. <nodeId>.<port>
任何前缀不是 input 或 context 的 ref 都会被视为对另一个 call 的输出 port 的引用。<nodeId> 是你添加该节点时传入的用户自定义 id(例如,builder.lifi.swap('swap', …) 会产生形如 swap.<port> 的 refs)。
{ scope: "output", node: "swap", port: "amountOut" }。
保留前缀
有三个前缀是保留的,不能用作节点 id:input、context 和 literal。Flow 校验会拒绝 id 与其中任何一个匹配的节点。
literal 不是 ref 作用域;它被保留是为了让语法保持无歧义。字面值通过一种独立机制表达,即 LiteralBinding,它与 refs 一起存在于节点的 bind 记录中:
SDK handles 如何变成 refs
合作伙伴代码通常不会直接构造 refs。SDK 为你提供 handles(由 builder 返回的类型化 JavaScript 值),并在序列化 call 时将它们转换为 refs。 Handles 有三种形态:InputHandle。 由builder.inputs.<name>返回。序列化为input.<name>。ResourceInputHandle。InputHandle的一个子类型,用于 resource input,携带资源声明。OutputHandle。 由 op 调用返回。builder.lifi.swap('swap', …).amountOut序列化为swap.amountOut(其中swap是你作为第一个参数传入的用户自定义节点 id)。
bind,SDK 就会生成正确的 $ref 字符串。上下文 refs 通过 builder.context 暴露:
builder.context.sender→{ $ref: "context.sender" }builder.context.executionAddress→{ $ref: "context.executionAddress" }
原始 refs(应急出口)
当你需要引用一个你通过builder.untypedOp(...) 创建的 call 的输出,或引用类型化 API 未涵盖的路径时,使用 raw.ref<T>(path) 来获得一个可被 Bindable<T> 槽位接受的类型化 TypedRef:
raw.ref 不做运行时校验;调用方负责选择正确的类型参数。
小结
- 存在三种作用域:
input.<name>、context.<sender|executionAddress>、<nodeId>.<port>。 <name>和<nodeId>是用户自定义的:你在编写 flow 时挑选它们。literal是一个保留前缀,而不是 ref 作用域。字面值使用LiteralBinding,而不是 ref。- SDK handles 会自动转换为 refs。你几乎不需要手写 ref 字符串。
- 仅当类型化 API 无法表达你所需的 ref 时,才使用
raw.ref<T>(path)。
一旦 Flow 接线完成,你就把它 POST 到 /compose。下一页 Execution Model 介绍这条流水线。

