solana:1151111081099710)。它不是一个兼容 EVM 的运行时:程序取代了合约,账户取代了存储,租金、PDA 和交易大小限制共同塑造了订单的运作方式。高层的心智模型不变——输入结算、输出结算、预言机验证——但许多具体机制有所不同。
本页是一份差异参考:对于每个关注点,说明 EVM 的做法以及 Solana 的替代做法。开头会为来自 EVM 背景的读者提供一份简短的平台入门介绍。
关于 LI.FI 各产品对 Solana 的通用(非 Intents)支持,请参见 Solana 生态系统页面。
概览
下表总结了本页涉及的每一处差异;下方各小节逐一解释。Solana 六十秒入门
Solana 相关页面依赖若干平台基础知识。如果你来自 EVM 背景,以下内容足以让你跟上——每一项都链接到官方文档以供深入了解。- 程序派生地址(PDA)。 一个由程序 id 和一组种子确定性派生出的账户地址。PDA 没有私钥——只有派生它的程序才能为其签名。意图系统在各处使用 PDA:托管、认证和配置全都位于任何人都可以重新计算出的地址上,这正是”账户存在于预期的 PDA 上”本身就能充当证明的原因。Solana 文档:PDA
- 跨程序调用(CPI)。 一个程序在同一笔交易内调用另一个程序上的指令——相当于 Solana 版本的合约调用合约。输出结算器通过 CPI 调用
intents_protocol程序来创建认证账户。Solana 文档:CPI - 关联代币账户(ATA)与租金。 SPL 代币余额存放在独立的代币账户中,而不是钱包地址本身;ATA 是某个 (owner, mint) 对所对应的规范代币账户。每个账户都必须持有一小笔 SOL 押金(“租金”)才能存在——创建账户的人支付租金,账户关闭时会退还给他们。这就是为什么订单会跟踪一个赞助者(在
open时支付租金,并在订单关闭时收回托管代币账户和order_context的租金——consumed_order的租金则是每笔订单永久性的成本),为什么当接收方的 ATA 尚不存在时,求解器可能需要支付租金,也是为什么填充记录和认证会记下由谁支付了它们,以便之后退还租金。SPL 文档:ATA - Anchor。 编写意图相关程序所使用的框架。它声明每条指令所需的账户,为客户端生成一份 IDL(类似于 EVM 的 ABI),并为事件和账户添加判别器前缀。TypeScript 示例使用的是 Anchor 的客户端库
@coral-xyz/anchor。Anchor 文档 remaining_accounts。 Anchor 指令会声明一份固定的账户列表,但调用者可以在末尾追加额外的账户。意图系统用它来处理长度取决于订单的列表——例如finalise时每个输出对应一个认证账户加上一个租金退还账户。- Borsh。 Anchor 用于指令数据、账户和事件的二进制序列化格式。订单 id 就是由它派生的:
order_id = keccak256(borsh_serialize(StandardOrder))。Borsh - Base58 与 bytes32。 Solana 地址是 32 字节的 ed25519 公钥,以 base58 字符串形式展示(例如
EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v)。跨链订单格式将所有地址都存储为原始的 32 字节值:Solana 地址就是 base58 解码后的 32 字节,而 20 字节的 EVM 地址会在左侧补零。 - 可验证操作认证(VAA)。 Wormhole 的签名消息格式——由 Wormhole 守护者网络对某个源链上发生的事件所做的认证。Wormhole 预言机以 VAA 形式发布填充证明。Wormhole 文档:VAA
链 ID
在 API 请求中,Solana 链使用solana 命名空间下、源自 CAIP-2 的 id:
在链上,协议使用的是存储在
intents_protocol 的 ChainId PDA 中的 u128 链 id。出现在 StandardOrder.origin_chain_id 和 MandateOutput.chain_id 中、并被各程序用来校验的,是这个值,而不是 EVM 风格的原生 chainId。
Solana 没有单一的”链 id”——三个命名空间同时存在,每个使用场景都只期望其中一个:
使用了错误命名空间下的值,会以间接的方式失败。以
eip155: 报价一条 Solana 分支会被拒绝,但错误信息说的是资产编码问题,而非命名空间错误。用规范 id 而非 2 去请求 Polymer 证明,会被 Prove API 拒绝——Polymer 流程见预言机系统。
报价
Solana 由标准报价端点POST /api/v1/integrator/quote/request 提供服务——与 EVM 和 Tron 使用的是同一个端点。将 Solana 地址以 base58 格式、配合 solana: CAIP-2 链 id 传入,取回的也是 base58 格式。请求和响应示例见请求报价。Solana 不由旧版 V0 端点提供服务。
对于源自 Solana 的订单,胜出的报价返回的是一笔可直接开启的交易,而不是一个待提交的订单。order.openIntentTx 的字段与 EVM 不同:
to是输入结算器的程序 id,以 base58 表示。data是一个 base58 编码、序列化后的 v0VersionedTransaction,而不是 calldata。它的recentBlockhash是一个全零的占位值(11111111111111111111111111111111),必须在签名前替换为一个新的区块哈希——Solana 的区块哈希大约一分钟后就会过期。computeUnitsRequired是该交易所需计算单元的预估值(十进制字符串)。序列化后的模板不包含 Compute Budget 指令;请在签名前用ComputeBudgetProgram.setComputeUnitLimit重建该消息,如在 Solana 上开启订单所示。checks.allowances始终为[]:SPL 转账发生在open指令内部,因此不存在预先授权的步骤。- 如果设置了
metadata.exclusiveFor,它是在独占窗口内拥有独占填充权的输入链求解器身份。对于源自 Solana 的订单,它必须是将对finalise签名的 base58 格式 Solana 公钥,即使输出在 EVM 上也是如此。
代币支持
xStocks 使用 Token-2022,在某个具体铸币的当前配置兼容时,可以使用标准报价流程。兼容性是针对每个铸币、根据其链上配置逐一评估的。出现以下任一情况时,该铸币会被拒绝:
- 启用了转账钩子 —— 转账钩子扩展设置了钩子程序。该扩展存在但未配置程序时,铸币仍视为兼容。
- 非零转账手续费 —— 转账手续费扩展在当前或计划中的纪元设置了大于零的手续费。零手续费配置(如 PYUSD)是兼容的。
- 不可转让 —— 该铸币带有不可转让扩展,因此任何转账都不可能成功。
- 无法解析的铸币 —— 该铸币账户不存在,或不属于已知的代币程序。
结算:仅托管
Solana 只支持托管输入结算器(input_settler_escrow)。不存在 Compact 或资源锁流程,因此 Compact 订单指南不适用于 Solana。
每笔订单一个输入
一笔 Solana 订单只携带恰好一个输入——一个{ token, amount } 对(MandateInput)——而 EVM 订单可以携带一个输入数组。如果你需要花费多种代币,就需要多笔订单。
金额是 u64
Solana 将协议格式中 32 字节的金额字段以及荷兰式拍卖的slope 字段收窄为 u64(SPL 代币的限制);EVM 则将它们视为完整宽度的 uint256。在构造发往 Solana 的跨链荷兰式订单时,请确保 slope 和最大结算金额都落在 u64 范围内,否则该输出将无法被填充。定价公式见拍卖。
订单大小
在 EVM 上,订单大小实际上不受限制。在 Solana 上,整个StandardOrder 都要放进 open 和 finalise 的指令数据中,而 finalise 还会为每个输出附加一个认证账户和一个租金退还账户——这一切都必须塞进 Solana 1,232 字节的交易包中。
托管结算器在 open 时强制执行这一边界:它将 N 个输出对应的完结交易预估为 760 + 302·N + Σ(|callback_data| + |context|) 字节,超过 1,142 字节(数据包上限减去为 compute-budget 指令预留的余量,若赞助者就是用户则会返还 32 字节)就拒绝该订单(FinaliseTxTooLarge)。因此,一笔能够成功开启的订单,总能用一笔”裸”的完结交易完结;只有当你自己追加了额外指令时,才需要重新检查这个边界。
实际后果是:**在 Solana 上开启的订单恰好只有一个输出。**一个输出的预估为 1,062 字节(赞助者即用户时为 1,030 字节),为 callback_data 和 context 留出 80 字节(112 字节)——在没有回调数据时,足以容纳所有订单类型(最大的 context,即独占荷兰式拍卖,为 73 字节)。两个输出的预估至少为 1,332 字节,总会被拒绝。源自其他链的订单不受此限制,可以在 Solana 上交付多个输出。
证明即账户
EVM 把填充证明存放在验证接口背后的合约存储中。Solana 把它们存储为确定性的 PDA 账户:Solana 上的一次填充对应一个LocalAttestation,一次由预言机注册的远程证明对应一个 Attestation。完整的模型——种子、载荷编码和端到端流程——见 Solana 程序中的”认证”。
同链交换
两个平台都支持同链意图,但实现方式不同。 在 Solana 上,这类订单会将输出结算器的状态 PDA 填入全部三个身份槽位(settler、oracle、inputOracle)——见身份矩阵。在标准路径上,fill 会创建一个 LocalAttestation,完结时直接验证该账户——不涉及任何预言机程序。在这种编码下,托管程序不是该认证的消费方,因此该认证的租金不会被退还。在下文的先释放输入路径上,则根本不会创建任何认证。
在 EVM 上,同链被建模为一种预言机配置(输出结算器同时充当预言机)。
两个平台都可以在输出交付之前释放输入,但执行模型不同:
求解器工作流和约束条件见先释放输入的 Solana 结算。
每条指令一次填充
Solana 上没有类似fillOrderOutputs 这样能一次性原子填充多个输出的机制。你需要用各自独立的指令逐一填充每个输出。这一点对于源自其他链、带有多个 Solana 输出的订单才有意义;在 Solana 上开启的订单只有一个输出。
后续步骤
Solana 程序
支撑 Solana 意图的 Anchor 程序、结构体和指令

