- 从各种来源收集用户意图。
- 实时向已连接的解算器广播这些意图。
- 跟踪所有交易的链上状态。
虽然订单服务器凭借其内置的安全辅助功能是推荐的集成接口,但需要注意的是——对于链上订单——订单服务器完全是可选的。然而,并非所有意图都在链上发出,lintent.org 并不在链上发出意图。在链上发出的意图需要经过填充并进行非常彻底的验证。
订单订阅
有 2 种方式可以收集订单:通过 websocket 订阅(订单会被推送),或通过 GET 端点。建议通过 websocket 订阅获取推送的订单。这两种方式都可以在 lintent.org 演示实现中找到。 如果您过于频繁地使用 GET 端点,您可能会被限流或暂时超时。您可以在 https://order-dev.li.fi/docs 上找到关于 api 接口的 swagger 文档。您可能会通过 WebSocket 接口多次收到同一个订单。每当从一个真实来源摄取意图时,都可能发生这种情况。二次发出可能包含额外的上下文。在消费 WebSocket 意图时,请使用 orderId 来识别意图。
订单服务器事件
连接到订单服务器后,订单服务器将持续发送 ping 消息,客户端应使用pong 进行响应。这用于断开行为异常的客户端,并用于调试目的。您可以在此处找到示例实现。
对于订单收集,重要的事件是 user:vm-order-submit。返回的数据与提交时的格式类似。
订单验证
LI.FI Intents 允许高度可定制的订单。因此,您应添加进一步的验证,以确保您支持转发给您的订单。正确验证订单非常重要。 下文中,术语”白名单”是指由您信任并验证过的。当某个代币_必须_被列入白名单时,意味着您信任该代币。如果某个验证层被列入白名单,意味着您信任该验证层,以此类推。白名单并不意味着由某个中心化实体授权;它意味着由您信任。 以下尝试列出解算器必须实现的验证的详尽清单。虽然该清单可能看起来过多,但您很可能已经为其中大部分实现了检查。通用验证
fillDeadline:确保您有足够的时间填充订单:- 在目标链上填充的时间,包括潜在的源链最终性。
expiry:确保您有足够的时间填充、转发和领取订单:- 在目标链上填充的时间,包括潜在的源链最终性。
- 将消息验证证明发送到输入链的时间。
- 验证送达后领取订单的时间。
- 验证层:确保您支持向验证层提交证明(如果不是自动的,还需转发)。此外,
inputOracle和output.oracle必须属于同一个验证层。 - 确保您已将每个
input代币列入白名单。如果某个输入代币是恶意的,订单可能无法领取。此外,对于像 USDC 这样可被列入黑名单的代币,请确保您不在黑名单上。- 如果订单的输入或输出中包含 0 数量的某个您未列入白名单的代币,该订单可能无法填充。在填充包含不熟悉代币的订单时请务必小心。
- 对于每个输出:
output.chainId已列入白名单。output.oracle和inputOracle就originChainId和output.chainId而言配置正确。链上配置是不可变的,因此这对每个链对只需做一次。output.settler已列入白名单。output.context可解码,且订单类型受支持并与output.settler兼容。output.token已列入白名单。此外,对于像 USDC 这样可被列入黑名单的代币,请确保您和接收方都不在黑名单上。- 如果订单的输入或输出中包含 0 数量的某个您未列入白名单的代币,该订单可能无法填充。在填充包含不熟悉代币的订单时请务必小心。
- 您有足够的代币用于
output.amount。 - 如果输出包含
calldata,请确保您能够原子性地执行它以及其他输出。对于不同链上的输出,如果存在calldata,您可能必须将接收方列入白名单。- 在 OP 链上,CrossL2Inbox 需要在整个调用树中被列入黑名单。如果其他链上存在类似的合约,它们也需要被列入黑名单。
call.length和context.length都不超过 65’535 字节长。- 根据订单类型验证上下文。具体针对 Bitcoin,请确保编码的乘数是相对于 Bitcoin 值的。
- 如果订单有多个输出,请确保您能够填充所有输出,且第一个输出设置为您的解算器标识符。如果所有输出都在同一条链上,可以使用
fillBatch作为一种保护措施。 - 如果 InputSettler 有任何费用,请检查是否有即将发生的费用变更。
代币输入以 uint256 提供。这是资源锁和跨链地址的标准格式。对于 EVM,前 12 字节代表一个潜在的 lock tag,地址是最后 20 字节。同样的 20-byte-in-
bytes32 规则也适用于 Tron——base58 的 0x41 版本字节从不出现在链上(参见 Tron vs EVM)。Escrow 验证
- 确保没有任何输入代币是转账时收费(fee on transfer)的。
- 确保每个
inputs代币的高 12 字节中没有设置任何位。 - 确保订单已经被打开,可以通过
event Open或function orderStatus,或者您在填充订单之前通过function openFor打开订单。
Compact 验证
- 确保每个
input代币使用相同的 AllocatorId。如果 lockId 不同,则应检查每个 lockId 的锁过期时间。或者,检查是否所有 lockId 都相等。 - 确保资源锁的潜在
reset period延伸到expiry之后,并且没有活跃的提款。 - 确保
allocatorID已列入白名单。分配器可以阻止领取的处理(通过撤回签名或重用 nonce)。- allocatorID 是
inputs的lock tag(前 12 字节)的一部分。 - 可选地,确保用户有足够的代币。不过这应该已经由分配器验证过了。
- allocatorID 是
- 确保用户提供了 ECDSA 签名或者他们注册了列入白名单的 emissary或者您在填充领取之前在链上注册了该领取。
- 注意:如果采取了这些操作中的任何一个,则可以假定签名是可信的。
- emissary 签名无法在链上注册。必须信任 emissary 不会撤回签名。
- 验证
allocatorData。您可能需要进行链上调用。 - 验证分配器
nonce之前未被任何用户使用过。订单 nonce 不是用户 nonce。
签名验证
StandardOrder 将用于对接输入链上的所有函数。此外,一旦填充了签名,它就允许人们验证订单的有效性。
StandardOrder 结构体将被签名并作为见证存储在相应的锁/领取结构中。对于 TheCompact,这是:
链上订单广播
当意图在链上注册时,可以通过输入结算合约上的IntentRegistered 事件进行广播:
在收集无需许可的订单时,请确保它们经过正确验证和共同签名。订单服务器有助于验证,但在链上,可能会发出潜在的欺诈性消息。

