桥接USDC支持审计

本次OpenZeppelin对Across协议的代码变更进行了差异审计,主要集中在pull request 941pull request 944

目录

概要

类型:跨链时间线 开始时间:2025-04-22 结束时间:2025-04-24 语言:Solidity 问题总数:5 (5 个已解决) 严重问题:0 (0 个已解决) 高危问题:0 (0 个已解决) 中危问题:0 (0 个已解决) 低危问题:1 (1 个已解决) 注释和附加信息:2 (2 个已解决) 客户报告问题:2 (2 个已解决)

范围

OpenZeppelin 对 Across Protocol 的 合约仓库 在 commit 77761d7 进行了差异审计。具体来说,审计了 pull request #941pull request #944 引入的更改。

以下文件在审计范围内:

 contracts
├── Lens_SpokePool.sol
├── ZkSync_SpokePool.sol
└── chain-adapters
    ├── ZkStack_Adapter.sol
    └── ZkStack_CustomGasToken_Adapter.sol

系统概述

Across Protocol 是一种跨链桥接协议,可以实现不同区块链之间的快速代币转账。该协议的核心是 Ethereum 主网上的 HubPool 合约,该合约充当系统中所有合约的中央流动性中心和跨链管理员。该池管理部署在各种网络上的 SpokePool 合约,这些合约发起代币存款或充当转账的最终目的地。

pull request #941 中引入的更改增加了对使用 Circle 的桥接 USDC 标准在 Ethereum (L1) 和基于 ZK-Stack 的 rollups (L2) 之间桥接 USDC 代币的支持。以前,桥接是在基于 ZK-Stack 的网络的默认 ERC-20 桥上完成的。桥接的 USDC 标准是完全支持 Circle 的跨链转移协议 (CCTP) 的中间步骤。此 pull request 更新了 L1 和 L2 合约,以便它们以后与 Circle 的 CCTP 兼容。

总而言之,USDC 代币的桥接机制以前仅限于标准 ERC-20 桥,现已得到增强。这些更新引入了对部署期间定义的两个额外路由协议的支持:

  1. 一种为 Circle 的桥接(可升级)USDC 设计的自定义桥接。
  2. Circle 的跨链转移协议 (CCTP) 桥接。

该 pull request 适用于 Lens 协议。但是,当前的实现是模块化的,可以被任何基于 ZK-Stack 的项目采用。

pull request #944 引入的更改实现了早期审计中的一项建议。本质上,SHARED_BRIDGE 全局变量已从 ZkStack_Adapter.sol 合约中删除,而是直接调用 BRIDGE_HUB.sharedBridge()。这样做的动机是避免在 adapter 合约部署后桥接合约地址更新时可能出现的问题。

低风险

自定义 Gas 代币可能会卡在 HubPool

ZkStack_CustomGasToken_Adapter 合约用于将消息从 L1 发送到具有自定义 gas 代币的基于 ZK Stack 的链。此合约中的公共函数预计通过 delegatecall 调用,这将在原始合约的上下文中执行此合约的逻辑。特别是,HubPooldelegatecallrelayTokens 函数。此 relayTokens 函数用于将代币桥接到 ZK Stack 链。此函数调用 _pullCustomGas 以在 第 186 行 定义 txBaseCost,以计算所需的 gas 代币数量,更重要的是,从资助者处提取所需的 gas 代币数量

但是,在使用 CCTP 桥接 进行桥接时,不需要自定义 gas 代币,因此提取的代币最终会卡在 HubPool 中。

此问题也可以推广到其他计算。例如,sharedBridge 仅当 ZkStack_CustomGasToken_Adapter 中的 l1TokenusdcToken 不同时才应定义,并且在使用 ZkStack_Adapter 中的 CCTP 桥接时,不应计算 txBaseCost

考虑仅在需要时在 relayTokens 函数中提取自定义 gas 代币。更一般地,考虑避免不必要的计算来定义稍后将用于降低 gas 成本的变量。

更新: 已在 commit 1725a57pull request #975 中解决。

注释 & 补充信息

缺失和有误导性的文档

在整个代码库中,有一些地方缺少或存在误导性的文档。例如:

  • ZkStack_Adapter.sol第 203 行 的注释没有考虑到在 address(usdcToken) == address(0) 时桥接 USDC 的情况。
  • 类似地,ZkStack_CustomGasToken_Adapter.sol第 247 行 的注释没有考虑到在 address(usdcToken) == address(0) 时桥接 USDC 的情况。
  • 标志 zkUSDCBridgeDisabledcctpUSDCBridgeDisabled 是互斥的,这通过构造函数中的检查来强制执行 [1] [2] [3]。考虑在构造函数的参数文档中明确记录此要求。

考虑解决上述实例并更新文档以反映功能的最新更改。

更新: 已在 commit fa39e0dpull request #973 中解决。

从 L1 中继代币,通过 CCTP 中继 USDC 时,会发出空的交易哈希

relayTokens 函数 [1] [2] 用于将代币从 L1 桥接到 ZK Stack。这两个实例都定义了一个 txHash 变量 [1] [2],该变量稍后将被分配给初始化桥接交易时 BRIDGE_HUB 返回的交易哈希值。但是,在这两种情况下 [1] [2],当启用 CCTP 时,会使用 _transferUsdc 函数,从而绕过 BRIDGE_HUB。但是,此函数不返回交易哈希,导致 relayTokens 函数发出一个空的 ZkStackMessageRelayed 事件 [1] [2]。这种行为可能会让用户感到困惑,尤其是在尝试基于发出的哈希索引事件时。

如果没有任何链下组件依赖于发出的事件,请考虑删除发出的事件以避免混淆。否则,请考虑为 ZkStackMessageRelayed 事件添加详尽的文档,概述其预期行为。

更新: 已在 commit cc4fa0apull request #976 和 commit 1a23663pull request #982 中解决。

客户报告

通过自定义桥接的 USDC 中继器退款中存在潜在的回退

executeSlowRelayLeaf 函数 用于执行存储为根包一部分的叶子,以退还中继器。这将向中继器发送他们发送给接收者的金额,外加中继器费用。此函数将调用 _distributeRelayerRefunds。如果叶子中要退还的金额为正数,则发送 L2 -> L1 消息,通过调用 _bridgeTokensToHubPool 函数,通过链特定的桥接方法将代币桥接回来。

但是,如果要桥接的 l2TokenAddress 是 USDC 代币,并且正在使用 ZK Stack 自定义 USDC 桥接,则通过 ZkSync_SpokePool第 154 行 上的自定义 ZK Stack USDC 桥接提款时,退款将回退,因为调用者(在这种情况下是 HubPool)尚未授予 zkUSDCBridge 足够的批准,以将代币从 HubPool 转移到桥接。

通过在调用 withdraw 函数之前批准 zkUSDCBridge 所需的 amountToReturn USDC,问题已与 pull request #967 一起交付。

更新: 已在 commit 0bcd27apull request #967 中解决。

通过具有自定义 Gas 代币的共享桥接限制 USDC 桥接

ZkStack_CustomGasToken_Adapter 合约中,relayTokens 函数 促进了将代币桥接到基于 ZK Stack 的链。为了执行此函数,ZkStack_CustomGasToken_Adapter 合约首先CUSTOM_GAS_TOKEN_FUNDER 中提取所需数量的自定义 gas 代币。随后,它应批准计算出的 txBaseCost 以供 sharedBridge 使用。

但是,在 第 230 行,没有批准向预期的 sharedBridge 合约支付 txBaseCost 金额,而是错误地将批准定向到 USDC_SHARED_BRIDGE 合约。这将导致 relayTokens 函数失败,特别是在尝试通过共享桥接桥接 USDC 时,因为 sharedBridge 将没有必要的授权来扣除自定义 gas 代币中的 txBaseCost

考虑将自定义 gas 代币的 txBaseCost 金额的批准定向到 sharedBridge 合约地址,而不是 USDC_SHARED_BRIDGE 合约地址。

更新: 已在 commit 6db3e38pull request #981 中解决。

结论

OpenZeppelin 对 pull request #941pull request #944 中引入的 Across Protocol 合约的更改进行了差异审计。主要更新包括对 Ethereum 和基于 ZK-Stack 的链之间的 USDC 代币桥接的模块化支持,特别是为了满足使用 Circle 的桥接(可升级)USDC 标准的 Lens (L2) 的需求。尽管目前适用于 Lens 协议,但添加的模块化是以这样一种方式实现的,即它可以为任何需要自定义其 USDC 桥接逻辑的基于 ZK-Stack 的项目重用。

总的来说,该实现被认为是合理的。仅报告了一个客户报告的问题和一个低风险问题,以及旨在改进文档的各种建议。感谢 Across Protocol 团队在整个审计过程中的响应。

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

0 条评论

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