Skip to main content
结算一笔 LI.FI Intents 订单最多需要两笔交易:
  1. 提交消息验证证明。
  2. 在资源锁上完结订单。

Oracle 验证

如何转发证明取决于该订单使用的预言机系统。请遵循预言机系统中对应系统的说明。

完结订单

一旦看到 OutputProven 事件,输出即已被验证,此时可以调用 finalise。
finalise 的 ABI 取决于所使用的结算器:InputSettlerCompact 需要签名,InputSettlerEscrow 不需要。 对于 InputSettlerCompact,请提交 StandardOrder、以 bytes.concat(sponsor, allocator) 形式附加的签名、填充的时间戳(可从 OutputFilled 事件中读取)以及求解器的标识符。如果存在多个输出,请始终按其在订单中的位置对列表进行索引。然后调用 finalise。InputSettlerEscrow 的流程相同,只是您不需要提供签名。
如果一个订单包含多个输出,且两个求解器填充了不同的输出,那么第一个输出的求解器就是规范求解器。

签名完结

求解器必须是 finalise 的调用者,因为他们可以重定向资金并修改可选的回调。对某些求解器而言这是不可能的——例如当求解器标识符被设置为一个资金池时。在这种情况下,可以使用 finaliseWithSignature 配合一个 EIP-712 AllowOpen 签名:
之后,任何持有该签名的人都可以使用签名的 destination,以及签名的 call(如果有的话),调用输入结算器的 finalise。

回调

某些求解器可能会使用回调来配置接收到的资金。finalise[WithSignature] 的 call 参数通过 orderFinalised 将提供的负载转发到 destination:
orderFinalised 调用不能失败。 对于同链意图,orderFinalised 在输入被支付给 destination 之后、但在输出证明被验证之前执行。这允许求解器在填充意图之前,在一笔原子交易中收集意图输入。

在 Solana 上结算

标准的 Solana 路径会先验证任何跨链证明,然后在 input_settler_escrow 上调用 finalise。证明的加载和验证可能需要多笔交易。 在 Solana 上开启的订单始终只有一个输出——open 会因交易大小而拒绝更大的订单。同时满足先释放输入条件的同链订单,可以改用先释放输入的结算。
填充记录的求解器 id 是在源链上领取输入的身份——不一定是目标链交易的签名者。对于源自 Solana 的订单,输出 0 必须记录将签署 finalise 的那个 Solana 账户的原始字节——你掌控的密钥,或通过 CPI 签名的程序 PDA。同链的紧凑填充(compact fill)是例外:它们记录的是自己的签名者,并且必须在顶层调用。
根据该输出的 OutputFilledEvent 构建 solve_params,使用事件中确切的 solver 和 timestamp。在 remaining_accounts 中传入对应的 LocalAttestation(同链)或由 Polymer 创建的 Attestation(远程),其后紧跟它的租金退还槽位。

完结所需的账户与检查

只有规范求解器——即输出 0 的求解器——才能调用它。程序会同时检查长度和签名者:
作为调用者,你需要解析以下账户:
  • solver —— 你自己,即交易签名者(输出 0 的求解器)
  • destination 及其代币账户 —— 托管的输入资金的去向;由于你在完结时才选择该地址,因此调用者必须是规范求解器
  • sponsor —— 支付了 open 费用的账户(从 order_context.sponsor 读取);将收到租金退款,若赞助者是可执行账户则改由你收到
  • order_context 及其托管 ATA —— 由 order_id 派生
  • local_consumer —— 托管程序的 ["local_consumer"] PDA(BZfvceVEFY1SYswSRepgfDCbMXTtWfTwwsRXKcTCBVx8),其后是 intents_protocol 程序
  • remaining_accounts —— 先是认证,然后是它的租金退还槽位:[attestation, rent_refund]。只传入认证会以 WrongAttestationCount 失败。
使用哪个认证账户取决于每个输出所在的链:
  • 同链输出(output.chain_id 等于 Solana 链 id):传入该次填充的 LocalAttestation。不涉及任何预言机。在 LI.FI 的规范编码下,托管程序不会消费该认证,因此租金退还槽位会被忽略——传入任意已存在的只读账户即可,例如 system program。
  • 跨链输出:先走预言机流程,让输入侧预言机创建一个 Attestation PDA,然后传入该 PDA。这里的租金退还槽位同样会被忽略。参见上文的 Oracle 验证以及认证中的账户模型。
对于 N 个输出,该指令接收 N 个认证,后跟 N 个租金退还槽位;但源自 Solana 的订单只有一个输出,所以实际上始终是 [attestation, rent_refund]。完整的账户列表见 input_settler_escrow 的 IDL,所有 remaining_accounts 布局见 Solana IDL 包。

先释放输入的 Solana 结算

此路径适用于单输出的 Solana → Solana Escrow 订单,条件是 callback_data 为空、context 为限价或独占限价类型,且输出结算器的状态 PDA 出现在全部三个身份字段中。 该交易会在交付输出之前先释放输入。你的中间指令可以把这笔输入转换成所需的输出。 该交易按以下顺序携带这些顶层指令:
finalise_with_prefill 会扫描 Instructions sysvar,寻找该交易后续部分中恰好一个匹配的紧凑填充(compact fill)。它会在释放托管资金之前,验证重建出的订单和填充账户。 如果该填充或某个中间指令失败,整笔交易都会回滚。
这里的”紧凑(Compact)“指的是更小的指令负载,而非 The Compact。Solana 上仍然只有一种输入结算器——Escrow,没有资源锁。

构建紧凑填充

传入 order_id 以及六个订单字段:nonce、expires、fill_deadline、输入金额、输出金额和定价 context。其余字段由程序重建: 对限价订单使用空 context。对独占限价订单,使用 0xe0 || exclusive_for || start_time。只有当你的签名密钥就是该订单的 exclusive_for 值时,才能使用简写形式。
  • 将两条结算指令都保持在顶层。 通过 CPI 调用二者中任何一个都会失败。在 finalise_with_prefill 之后,必须恰好包含一个匹配的紧凑填充。
  • 使用规范的关联代币账户。 在填充执行之前,你的输出账户必须已经存在并持有该输出金额。原生 SOL 则来自你的签名账户。
  • 为账户创建付费。 你可能需要为输入目的地、接收方代币账户以及 fill_record 支付租金。紧凑填充不会创建认证。当 fill_deadline + 48 小时过后,你可以通过 close_fill_record 收回 fill_record 的租金。
  • 永远不要单独发送紧凑填充。 如果同一笔交易中前面没有匹配的 finalise_with_prefill,输出仍会被支付,但没有任何东西能证明这次填充,你之后也就无法领取输入。
  • 让一切都放进一笔交易。 Solana 交易上限为 1,232 字节。必要时使用版本化交易和预先创建好的地址查找表。
  • 在 fill_deadline 之前提交。 该截止时间是包含边界的;晚于此时间的填充会导致整笔交易回滚。
  • 关注 FinalisedEvent。 此路径发出的事件与 finalise 相同;其 settler 字段是该订单的 order_context PDA。它不携带金额——请从托管程序的 transfer_checked 内部指令中读取。索引器必须忽略来自失败交易的事件。
失败代码和常见修复方法见 先释放输入结算的错误。 完整的验证模型见 Solana 程序。

Solana 退款

有两条无需许可的退款路径可以将托管资金退还给用户,并且两者都会永久关闭该订单:
  • 从 expires 起,任何人都可以调用 refund(order)。
  • 更早的时候,一旦 fill_deadline 已过且某个输出被证明未被填充,任何人都可以调用 refund_on_non_fill(order, output_index)——无需等到过期。与 finalise 一样,它需要托管程序的 local_consumer PDA,以及 remaining_accounts = [attestation, rent_refund]。对于 Solana 输出,未填充证明(attest_not_filled)只能在 fill_deadline 之后 48 小时内创建;如果错过该窗口,订单将在 expires 时退款。
请尽快完结。一旦退款完成,即使你已经填充了部分输出,你的偿付也会消失——完结与这两种退款是互斥的。请在 fill_deadline 之前填充每一个输出,并在 expires 之前尽早完结。
这两条路径都记录在 Solana 程序中。