SVM Spoke 增量审计

OpenZeppelin 对 Across Protocol 的 Solana 跨链桥代码进行了一次审计,主要关注了移除自中继、允许历史完成期限、更新 SVM 接口、移除启用存款路由检查以及测试原生 SOL 存款等方面的更改。审计发现了一个中等严重性和一个低严重性的问题,以及一些需要注意和补充的信息。

目录

总结

TypeCross ChainTimelineFrom 2025-03-31To 2025-04-08LanguagesRustTotal Issues5 (4 resolved, 1 partially resolved)Critical Severity Issues0 (0 resolved)High Severity Issues0 (0 resolved)Medium Severity Issues1 (1 resolved)Low Severity Issues1 (1 resolved)Notes & Additional Information3 (2 resolved, 1 partially resolved)

范围

OpenZeppelin 对 across-protocol/contracts 仓库在 commit 71e990b 处的 solana-march-audit-2 分支进行了差异审计。

审计范围包括以下 pull requests:

  • PR 892: 移除自中继
  • PR 891: 允许存款时使用历史完成截止时间
  • PR 861: 更新 SVM 以匹配新的 EVM 函数接口
  • PR 939: 移除已启用的存款路径检查
  • PR 942: 测试原生 SOL 存款

变更概述

移除自中继

之前,当中继填充期间接收方代币账户与中继者代币账户匹配时,由于接收方和接收者是同一个账户,因此不会发生代币转账。在 solidity 版本中,这是通过提前返回来实现的,这也绕过了消息处理并引入了一个潜在的 bug

已实施的缓解措施是简单地移除提前返回的行为,以便在每种情况下都处理消息。为了与 Solidity 版本保持一致,Solana 代码库中的自中继优化也被移除。

允许存款时使用历史完成截止时间

此更改删除了存款期间完成截止时间的下限,允许截止时间在过去。 这允许中继者乐观地完成存款,这在某些情况下可能是可取的,或者避免因不同链之间块时间戳的差异而导致的同步错误。

更新 SVM 以匹配新的 EVM 函数接口

此更改更新了整个代码库中的命名约定,以匹配 Solidity 对应项。 特别是,所有对 "v3" 的引用都已被删除。

移除已启用的存款路径检查

在 SVM spoke 程序的先前迭代中,存款路径(即,存款的代币类型和目标链)必须由管理员创建并启用。 如果尝试使用尚未启用的路径进行存款,则会生成错误。 正在审查的更改删除了与创建和启用路径账户相关的所有逻辑,有效地删除了围绕哪些代币类型可以发送到哪些链的所有限制。 虽然现在可以使用任何路径,但由于存款人需要将代币发送到金库账户,因此必须初始化金库代币账户 PDA 才能接收代币。 提供了一个辅助脚本 来初始化金库 PDA,任何人都可以执行它。

测试原生 SOL 存款

由于 SVM SpokePool 中的所有代币转账都使用 SPL 代币转账,因此必须包装原生 SOL 才能进行存款。 已经添加了一个演示通过包装进行原生存款的脚本

中等风险

存款代币从存款人代币账户而不是签名人处转移

SpokePool 程序的存款操作旨在从调用者处提取代币(即,签名人),这些代币可以代表任何 depositor 账户进行存款。 但是,当签名者不是存款人时,将使用存款人代币账户作为源地址执行 transfer_from 操作。 除非存款人已将至少输入金额委托给 state PDA,否则此类操作将失败。 这会带来两个后果:

  1. 签名者将无法为另一个账户存款,从而禁用账户能够代表其他人存款的预期功能。
  2. 如果任何代币账户委托给 state PDA,那么任何人都可以调用存款函数,将受害者的账户作为 depositor_token_account 传递,并使用除输入代币和金额之外的任意参数执行成功的存款。 然后,恶意用户可以提交包含他们自己的接收者地址的存款,以窃取存款人资金。 这是可能的,因为 state PDA 作为 authority 和签名者种子 传递给 transfer_checked 调用,当委托给该调用时,将通过 转移验证逻辑。 请注意,这种情况可以通过 Solana 交易中的原生指令批处理来缓解,该批处理通常涉及在一个操作中进行委托和转移,从而降低了抢先交易的可能性,但仍然是可能的。

考虑以与 depositor_token_account 相同的方式验证 signer 代币账户,并从签名者代币账户执行转移。

更新: 已在 pull request #971 中解决,commit 为 58f2665。 团队表示:

我们用两个不同的 PDA 替换了一个“state” PDA——一个用于存款,一个用于 fill_relay。 现在,用户必须先明确委托给正确的 PDA,然后任何人才可以提取他们的代币,从而恢复安全第三方存款并消除单个 authority 被滥用以窃取资金的风险。

低风险

不清晰的金库初始化过程

Pull request #939 移除了 Solana SVM Spoke 中的路径启用功能,允许存款人提供任何输入代币用于任何目标链,而不仅仅是那些启用了路径的代币。 以前,当启用路径时,将创建用于用户存款的金库的关联代币账户 (ATA)。 如果用户尝试存款到禁用的路径,也会生成 DisabledRoute 错误。 由于此时所有路径都将被启用,因此用户可能会尝试提交存款,但未初始化金库 ATA。 这将导致存款交易失败,且没有描述性错误消息。

因此,如果尚未创建金库,则存款人必须自己初始化 PDA,例如,使用 createVault.ts 脚本。 但是,对于大多数用户来说,这不是一个简单的过程,并且可能不清楚为什么存款失败。 这可能导致用户放弃他们的存款尝试并考虑其他桥接解决方案。 更直接的解决方案是在使用 init_if_needed 标志的deposit 期间初始化金库,就像管理员启用路线时 以前完成的那样

考虑添加 init_if_needed 标志或在 deposit 函数的文档字符串中清楚地记录所需的金库创建过程。

更新: 已在 pull request #957 中解决,commit 为 3b8cf77。 团队表示:

我们在 deposit 方法中将 init_if_needed 标志添加到 vault 账户。

说明 & 补充信息

未完成的重命名

Pull request #861 重命名了几个函数和类型,以从 Solana spoke 代码库中删除 "V3" 限定符。 但是,重命名不完整:

考虑更新所有提到 "V3" 的函数和注释,以与代码库的其余部分保持一致。

更新: 已在 pull request #964 中部分解决,commit 为 a78241f。 团队表示:

我们通过从 SVM 代码库的其余部分删除 "V3" 的提及来解决此问题。 唯一的例外是 handle_v3_across_message 函数及其相关的结构体和常量,因为 "V3" 概念也保留在 EVM 中,其中 AcrossMessageHandler 仍然在其接口中具有 handleV3AcrossMessage

误导性的文档

在整个代码库中,发现了多个误导性文档的实例:

  • nativeDeposit.ts第 68 行 说明在启用路由时会创建金库 ATA。 但是,pull request #939 中已删除了路由启用。
  • createVault.ts第 1 行 说该脚本由链管理员使用,但任何人都可以使用它在必要时创建金库 PDA。

考虑更正上述注释以提高代码库的整体清晰度和可读性。

更新: 已在 pull request #963 中解决,commit 为 24017ac。 团队表示:

我们通过澄清脚本中的注释来解决此问题。

命名不一致

fill_relay 函数接受 _relay_hash 参数,但 FillRelay 结构体约束 将其称为 relay_hash(没有前导下划线)。

为了避免混淆,在使用 instruction 约束时,请考虑保持一致的变量名。

更新: 已在 pull request #962 中解决,commit 为 9f8a199。 团队表示:

我们通过在使用 instruction 约束时使用相同的变量名来解决此问题。

结论

审查的更改包括对 SVM Spoke 的增量更新。 它们稍微概括了功能并提高了与 EVM Spoke 的一致性。 代码库中没有发现重大问题。

感谢 Risk Labs 团队提供的广泛文档以及他们在整个审计期间的配合。

  • 原文链接: blog.openzeppelin.com/sv...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
OpenZeppelin
OpenZeppelin
江湖只有他的大名,没有他的介绍。