swap-and-zap 配方的形态相同。到最后你将得到一个 ComposeCompileResult,其中包含可供签名的 transactionRequest.data(calldata)。
有关 inputs、handle、materialiser、guard、前置条件(precondition)和提交的完整讲解,请在阅读本页后参见 Build a Flow。
先决条件
- Node.js ≥ 20 和一个 TypeScript 项目(
tsc、tsx或ts-node都可以)。 - 一个在 Ethereum 主网上持有少量 WETH 的 EVM 账户(本示例使用
1WETH 作为演示)。 - 签名者的
0x前缀地址。本快速入门不会发送交易;它止步于已编译的 calldata。签名者接线(viem、ethers 等)在 Build a Flow 中介绍。 - 一个 LI.FI API key。Composer 处于技术预览阶段,每个请求都经过认证。在 portal.li.fi 注册,并从你的仪表盘创建一个 key。
基础 URL。 公开的 compose 端点由一个专用主机提供;SDK 默认为
https://composer.li.quest。如果你的集成使用暂存或内部环境,请向你的 LI.FI 联系人索取正确的 baseUrl。步骤
1
Install the SDK
@lifi/composer-sdk 包已发布在 npm 上。在稳定版本发布之前,请锁定 alpha 范围。2
Create the SDK
createComposeSdk 返回一个句柄,其中包含一个 flow 工厂、一个低层 client,以及一个用于自定义 transport 的 request 辅助函数。在技术预览期间,apiKey 是必需的。3
Build the flow
一个 Flow 就是你在这里构建的文档:一个有序的步骤列表,会编译成一笔交易。你先声明它的 inputs,然后在 builder 上链式调用 operations。有关 import 和地址常量,请参见下方的完整示例。
- 一个 input 是 flow 所消费的值。这里的
amountIn是一个 resource —— 一个代币余额(1 WETH),Composer 会在它于各步骤之间移动时对其进行跟踪。(Input 也可以是普通的标量,比如一个uint256或一个address。) - 一个 operation(op)是 flow 中的一个具名步骤,比如一次交换或一次存入。
builder.lifi.swap和builder.lifi.zap都是 op;zap将swap的输出绑定为它自己的输入,把两者串接在一起。这两个只是完整 op 目录中的一小部分。
4
Compile the flow
builder.compile(run) 会将 flow 发送到 POST /compose,对其进行模拟,并返回一个 ComposeCompileResult,其中包含你的用户签名所需的 calldata。这里的 inputs 映射为 flow 声明的每个 input 提供了具体的运行时值。directDeposit 是一个 materialiser —— 一个小描述符,告诉 Composer 在执行时如何获取代币(这里是通过 transferFrom 将恰好 1 WETH 拉进代理)。sweepTo 说明当 flow 结束时剩余余额去往何处。result.transactionRequest 就是你交给钱包的东西:to 地址是你的每用户执行代理 —— 与 userProxy 相同的值。在代理首次使用时,它反而是代理工厂,工厂会部署你的代理并在一笔交易中运行 flow。无论哪种方式,代理都会 delegatecall 共享的 Composer VM,因此 flow 在你自己代理的余额和存储上下文中执行。每条链上的 VM 和代理工厂地址在 Addresses 页面上。除了 transactionRequest,结果还携带 userProxy(执行地址)、producedResources(每个终端资源的模拟金额),以及签名者必须首先授予的任何 approvals。完整示例
改编自composer-sdk-examples 仓库中的 swapAndZap.ts:
完整示例增加了步骤中没有的一个术语:一个 guard。zap 上的
guards.slippage({ port: 'amountOut', bps: 100 }) 是一个 Composer 在执行期间强制执行的不变量 —— 这里是对 zap 输出的 1% 滑点下限 —— 因此 flow 会安全地失败,而不是以糟糕的条件执行。交换不需要 guard:它的 slippage: 0.03 配置已经将一个下限烘焙进了报价。SDK 构建了什么
builder.compile(run) 不只是调用端点 —— 它会将带类型的 builder 状态序列化为线格式(wire-format)的 Flow 文档,将其发送到 POST /compose,并解析响应。如果你想看看线上实际是什么样子,把 builder.compile(run) 换成 builder.build():
amountIn)、节点 id(swap、zap)和 $ref 都恰好是你在上面 builder 中所写的 —— SDK 不会重命名或重写。有关完整的线格式参考,请参见 Flow Structure。
你拿回了什么
ComposeCompileResult 是一个基于 status 的可辨识联合(discriminated union)。在读取形态专属字段之前先对它进行分支:
status: 'success' 时,载荷包含:
transactionRequest——{ to, data, value, gasLimit? }。to是你的执行代理(在代理首次使用时是代理工厂);data是代理 delegatecall 进 VM 的 calldata。userProxy—— 预测的执行代理地址(由代理工厂派生的一个确定性的每签名者合约;参见 Account model)。producedResources—— 终端资源名称到每个资源记录的映射。模拟金额位于<resource>.simulated?.amountOut和<resource>.simulated?.amountOutMin。approvals—— 签名者在执行交易之前必须授予的 ERC-20 授权(不需要时省略)。priceImpact—— 当在 run 上设置了maxPriceImpactBps时,可选的美元价格影响明细。
status: 'partial' 时,载荷还额外携带 error({ kind, message })和 simulationRevert。仅当你在 run 上传入 simulationPolicy: 'allow-revert' 时才会返回这种形态;在默认的 'strict' 策略下,回滚会转而抛出一个 ComposeError。
后续步骤
你现在已经在实践中见过每一个核心概念 —— Flow、operation、resource、input、materialiser、guard。上面的示例足以开始试用。当你想要全面了解其中任何一个时,以下页面会更深入:- Build a Flow —— inputs、handle、materialiser、guard、前置条件和提交的完整讲解。
- Flow Structure —— 你的 builder 所产生的 JSON 文档形态。
- References —— handle 如何在线上变成
$ref字符串。 - Recipes —— 三种典型的 flow 形态(Dust Sweep、Swap and Deposit、Split Deposits)。

