Across Linea CCTP差异审计

本文是对Across协议的智能合约进行安全审计的报告,重点关注为了集成Circle CCTP V2版本协议对合约所做的修改,以支持在以太坊和Linea区块链之间桥接USDC代币。审计发现了一些低风险问题,包括CCTP版本检查的可靠性问题和文档不足,并提出了相应的改进建议。总体而言,代码变更实现了使用CCTP协议的第二个版本将USDC桥接到Linea区块链的功能。

目录

概要

TypeDeFiTimelineFrom 2025-03-13To 2025-03-18 语言:

         Solidity 问题总数4 (3 已解决, 1 部分解决)严重问题0 (0 已解决)高风险问题0 (0 已解决)中风险问题0 (0 已解决)低风险问题2 (1 已解决, 1 部分解决)说明和补充信息2 (2 已解决)客户端报告问题0 (0 已解决)

范围

我们审计了 across-protocol/contracts 仓库。

审计范围包括对以下文件所做的更改:

 contracts
├── Linea_SpokePool.sol
├── chain-adapters/
│   └── Linea_Adapter.sol
├── libraries/
│   └── CircleCCTPAdapter.sol
└── external/
    └── interfaces/
        └── CCTPInterfaces.sol

位于pull request #921,最终 commit 为 0720878

我们还额外审查了 e5310e0 commit。

系统概述

Across 协议是一种基于意图的桥接协议,它实现了不同区块链之间快速的 token 转移。关于协议如何运作的更多细节,请参考我们之前的审计报告之一

变更概要

为了在以太坊和其他支持 Circle CCTP 协议的区块链之间桥接 USDC token, HubPool 和 SpokePools 都使用了 CircleCCTPAdapter 合约,该合约使用 CCTP 协议的第一个版本 (V1) 实现了 USDC 桥接逻辑。

然而,Linea 区块链不支持 CCTP 的 V1 版本,并且只支持 V2 版本,它使用了一组不同的合约,并导致暴露给用户的 API 不同。 因此,为了支持与 Linea 区块链之间的 USDC 转移,有必要调整 Across 中现有的合约,以便它们能够通过新的 API 与 CCTP 交互。

这些变更涉及对 CircleCCTPAdapterLinea_AdapterLinea_SpokePool 合约的少量修改,并引入了新的 ITokenMessengerV2 接口,以便于与第二版 CCTP TokenMessenger 合约的通信。

安全模型和信任假设

本次审计的重点是对合约进行特定修改,以便与 Linea 上的 CCTP V2 集成。 因此,它仅限于代码库的一小部分,并且是在以下信任假设下进行的。

在整个审计过程中,我们假设所有链上和链下组件与范围内的代码集成时行为正确且符合预期。 特别是,CCTP 协议根据其文档正确且可靠地在以太坊和 Linea 区块链之间转移所需的 USDC 数量。

此外,我们假设范围内的合约将被正确部署并使用正确的参数进行初始化,这对于整个协议的正确运行至关重要。

最后,Linea CCTP 域名 ID 在审计时尚未正式公布,尽管很可能等于 11。因此,假设代码中反映它的常量已正确初始化。

特权角色

在被审查的 pull request 中,协议没有添加任何新的特权角色。

在整个审计过程中,我们假设 Across 协议中已经存在的所有特权实体都将诚实行事,并以协议及其用户的最佳利益行事。

低风险

CCTP 版本检查并非完全可靠

为了确定将用于桥接 USDC 的 CCTP 版本,CircleCCTPAdapter 合约 的构造函数对 CCTP TokenMessenger 的 feeRecipient 函数执行了一个 底层调用。 该检查依赖于以下事实:此函数不存在于 V1 合约中,但存在于 V2 合约中并返回一个非零地址。

但是,由于以下列举的原因,正在执行的检查并非完全可靠。

Solidity 中函数返回的值是 abi.encode 编码的,这意味着 feeRecipient 函数返回的地址将用 0 填充到 32 字节的开头。 此外,将 bytes 对象转换为 bytes20 将返回该对象的前 20 个字节,其中包括 12 个字节的填充,因此,在此检查中只会考虑返回地址的前 8 个字节。 如果返回的 feeRecipient 的前 8 个字节等于 0,则合约将错误地假设它应该使用 CCTP V1。

此外,虽然检查了调用是否成功,但没有验证返回数据的大小是否正确。 因此,如果在返回数据大小不同的情况下,检查 可以成功。 特别是,对于长度为 0 的返回数据,此检查的正确性取决于从空 bytes 对象到 bytes20 的转换总是返回 0。

最后,要调用的合约仍然可以有一个返回 32 字节数据的 fallback 函数。 如果该数据的最后 20 个字节中至少有 1 个非零,则即使目标合约未实现 feeRecipient 函数,检查仍然会成功。

考虑在将 feeRecipient 转换为地址之前将其转换为 uint160,以便检索完整地址。 此外,考虑验证底层调用返回的数据长度,以便更好地处理返回意外大小数据的情况。 此外,考虑实现一种更强大的机制来确定要使用的 CCTP 版本。

更新:pull request #921 的 commit d9d4707 中已部分解决。 从底层调用返回的数据的转换已修复,并且已向返回数据的长度添加了额外的验证。 CCTP 版本的检查仍然有可能无法确定正确的版本,但这种情况发生的可能性很小,并且 Risk Labs 团队已接受该风险。

文档不足

CircleCCTPAdapter 合约的 _transferUsdc 函数 负责使用 CCTP 协议在不同的区块链之间桥接 USDC。 为了做到这一点,它会查询 CCTPTokenMessenger 合约以获取 TokenMinter 的地址,确定每个消息的当前燃烧限制在必要时拆分 USDC 存款

但是,用于检索 minter 地址的 cctpTokenMessenger 变量的类型为 ITokenMessenger,它表示 TokenMessenger 合约的第 1 版,但实际上它可能指向 TokenMessengerV2 合约。 由于 TokenMessengerTokenMessengerV2 合约都定义了正在使用的 localMinter 函数,因此函数调用对于这两种情况都会成功,但这种隐式行为可以反映在注释中。 此外,此函数返回的 localMinter 的类型为 ITokenMinterITokenMinterV2,具体取决于调用的 TokenMessenger 的版本。 虽然两个版本的 TokenMinter 合约都暴露了 burnLimitsPerMessage 函数,但这一事实并不明显,也可以记录下来。

考虑改进 _transferUsdc 函数中的文档,以提高代码库的可读性和可维护性。

更新:pull request #921 的 commit d9d4707 中已解决。

说明和补充信息

误导性注释

在整个代码库中,发现了几个误导性注释的实例: - 注释 中指出 minFinalityThreshold 参数对于标准转移可以设置为 20 000,而正确值为 2 000。 - 注释 指的是 l1Token,但是代码检查 l2TokenAddress 是否为 usdcToken 的地址。 因此,在注释中,l1Token 应更改为 l2Token

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

更新:pull request #921 的 commit b135917 中已解决。

排印错误

在整个代码库中,发现了几个排印错误的实例:

CircleCCTPAdapter.sol 文件中: - 在 第 70 行 中,应将 "its" 更正为 "it is"。 - 在 第 116 行 中,应将 "to bridged" 更正为 "to bridge"。 - 在 第 124 行 中,该行开头有多余的空格,可以将其删除。

考虑修复所有排印错误,以提高代码库的可读性。

更新:pull request #921 的 commit 63231d9 中已解决。

结论

添加到代码的更改使合约能够利用 CCTP 协议的第二个版本将 USDC 桥接到 Linea 区块链以及从 Linea 区块链桥接 USDC,同时仍然允许对其他区块链使用该协议的第一个版本。

在整个审计过程中,没有发现任何重大问题。

在整个参与过程中,Risk Labs 团队提供了很大的帮助,及时且详细地回答了我们的所有问题。

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

0 条评论

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