以太坊 - Linea TGE审计

该文档是OpenZeppelin对Consensys/linea-tokens代码仓库的一次安全审计报告,涵盖了Linea L1和L2上的ERC-20代币合约以及一个L2上的空投合约。审计期间发现了一些低风险问题,如文档字符串不完整、代码优化空间和不确定的许可协议,但没有发现高危或严重漏洞。报告总结了审计范围、系统概述、安全模型、问题详情以及修复情况。

目录

概要

TypeLayer 2 & RollupsTimelineFrom 2025-07-22To 2025-07-24LanguagesSolidityTotal Issues10 (5 resolved, 1 partially resolved)Critical Severity Issues0 (0 resolved)High Severity Issues0 (0 resolved)Medium Severity Issues0 (0 resolved)Low Severity Issues3 (1 resolved, 1 partially resolved)Notes & Additional Information6 (3 resolved)

范围

OpenZeppelin 审计了 Consensys/linea-tokens 仓库,提交版本为 44640f0。此外,pull rquest #10 审计至提交版本 86605a9,而 pull request #11 审计至提交版本 b9aad54

更新: 我们已经完成了对所有提交内容的审查,并最终确定了审计报告。最终审查的提交版本为 91036da。我们注意到自 44640f0 以来,范围内文件的其他更改与和我们同时进行的审计结果相关。

此外,我们已经验证了已部署的字节码与 commit 91036da 的代码相匹配。

以下文件在审计范围内:

 src
├── L1
│   ├── LineaToken.sol
│   └── interfaces
│       └── ILineaToken.sol
├── L2
│   ├── L2LineaToken.sol
│   └── interfaces
│       └── IL2LineaToken.sol
├── airdrops
│   └── TokenAirdrop.sol
└── interfaces
    ├── IGenericErrors.sol
    └── IMessageService.sol

系统概述

该系统包括两个部署在以太坊 L1 和 Linea L2 上的 ERC-20 代币合约,以及一个部署在 L2 上的空投合约。这些合约共同实现了跨链代币铸造、供应同步以及基于预定义的外部信号的结构化空投分配。

  • L1 代币合约LineaToken,是一个可升级的 ERC-20 合约,具有可燃烧的、基于许可的批准和基于角色的访问控制。它支持通过 MINTER_ROLE 进行受控铸造,并使用 Linea 的消息服务将总供应量更新传播到 L2 对应方。
  • L2 代币合约L2LineaToken,是 L1 代币的桥接版本。它包括 ERC20VotesUpgradeable,允许投票权委托以及与依赖于代币加权治理或基于身份的实用程序的应用程序集成。
  • TokenAirdrop 合约部署在 L2 上,允许符合条件的用户认领 L2 代币的分配。它不是依赖于白名单或 Merkle 根,而是根据用户在最多三个外部合约中的余额动态计算分配。这些外部合约不代表可转让的代币,可能仅用作确定资格或按比例分配的参考点。该设计假设这些合约的余额对每个用户都是不可变的,这确保了空投的公平性以及对女巫攻击或重放攻击的抵抗力。

这种结构支持安全、模块化和可升级的分配系统,该系统将 L1-L2 代币流与透明且可编程的空投逻辑连接起来。

安全模型和信任假设

在审计期间,做出了以下信任假设:

  • 在空投中被引用为 PRIMARY_FACTOR_ADDRESSPRIMARY_CONDITIONAL_MULTIPLIER_ADDRESSSECONDARY_FACTOR_ADDRESS 的合约必须满足特定要求,以确保分配的完整性:

    • 所有三个合约必须提供 ERC-20 标准的 balanceOf 功能的接口。
    • 这些代币必须是 soulbound (不可转让的),以防止用户通过在钱包之间移动余额来滥用该系统。
    • PRIMARY_FACTOR_ADDRESSSECONDARY_FACTOR_ADDRESS 必须与空投代币具有相同的小数位数。
    • PRIMARY_CONDITIONAL_MULTIPLIER_ADDRESS 必须具有 9 个小数位,因为它用作乘数并除以 1e9 的固定分母。
    • PRIMARY_FACTOR_ADDRESSPRIMARY_CONDITIONAL_MULTIPLIER_ADDRESS 之间的余额乘法不得溢出 uint256 值。这一点尤其关键,因为在 这一行 中完成了乘法运算。
    • 合约所有者必须避免设置不受真实用户控制的地址。由于可以代表任何地址进行认领,因此添加未拥有的地址将导致不可挽回的代币损失(如果有人要认领它)。
  • 与系统交互的交易应消耗少于 250,000 gas,以保持与 Linea 的消息服务基础设施的兼容性,并从 L1 → L2 消息的免费邮递员执行中受益。

  • 部署和配置过程必须遵循特定的顺序以确保正确性:

    1. L1 和 L2 代币合约应分别首先部署在以太坊主网和 Linea 上。
    2. 在 Linea 上,桥合约所有者必须调用 setCustomContract 以将 L1 代币合约注册为相应 L2 代币的指定目标。
    3. 应该在 Linea 代币桥上调用 confirmDeployment 函数,以通知主网桥 L2 上的部署已完成。这将更新 nativeToBridgedToken 映射以反映 DEPLOYED_STATUS
    4. 一旦桥接设置完成,就可以在 Linea 上部署空投合约,并且可以将代币资金转移到该合约。

此部署顺序保证了安全的空投初始化、一致的桥接逻辑以及 L1 和 L2 状态之间的安全同步。

特权角色

在系统中识别出以下特权角色:

  • LineaToken (L1) 定义了两个角色:

    • DEFAULT_ADMIN_ROLE,用于管理角色和管理设置。
    • MINTER_ROLE,用于铸造新代币。
  • L2LineaToken 仅接受来自 Linea 的官方代币桥和消息服务的消息。
  • TokenAirdrop 由在部署时分配的单个所有者管理。在认领窗口关闭后,此所有者有权提取未认领的代币,并且可以在认领期结束后触发合约的 withdraw 函数。
  • 通过 MessageServiceBase 修饰符(onlyMessagingServiceonlyAuthorizedRemoteSender)强制执行跨链信任边界,确保只有经过身份验证的 L1/L2 消息服务和发送者才能调用跨链同步逻辑。

低风险

不完整的文档字符串

在整个代码库中,发现了以下不完整的文档字符串实例:

考虑彻底记录作为合约公共 API 一部分的事件(及其参数)。编写文档字符串时,请考虑遵循 以太坊自然规范格式 (NatSpec)。

更新: 已在 pull request #16 中解决。

用于 PRIMARY_FACTOR_ADDRESSPRIMARY_CONDITIONAL_MULTIPLIER_ADDRESS 检查的优化

TokenAirdrop 合约包含 这两个 require 语句。目的是确保 _primaryFactorAddress_primaryConditionalMultiplierAddress 都已设置(非零)或都未设置(零)。这样可以防止仅初始化其中一个地址而未初始化另一个地址。但是,这两个条件在逻辑上是冗余的,可以简化。此外,根据构造函数强制执行的保证,还可以简化 calculateAllocation 函数中的后续逻辑。

考虑将 TokenAirdrop 构造函数中的两个 require 语句替换为单个等效条件,该条件确保两个地址都已设置或都未设置。此外,简化 calculateAllocation 中的条件以仅检查两个地址中的一个。

更新: 已在 pull request #10 中部分解决。虽然 calculateAllocation 中的检查已简化,但可以进一步简化构造函数中的 require 语句。

浮动 Pragma

应修复 Pragma 指令以清楚地标识将编译合约的 Solidity 版本。

在整个代码库中,发现了多个浮动 pragma 指令的实例:

考虑使用固定的 pragma 指令。

更新: 已确认,但未解决。该团队表示:

已确认:这些故意保持开放状态,供其他人在未来/更高版本的合约中使用。顶层可部署文件将指示编译器版本,该版本已设置为没有浮动 pragma。预计不会有任何变化。

说明 & 补充信息

对父合约的模糊调用

L2LineaToken 合约中,super.nonces 调用是模糊的。

考虑避免对父合约进行模糊调用,并明确指定正在调用哪个父合约的函数。

更新: 已确认,但未解决。该团队表示:

已确认:当删除 super. 并显式使用 permit 时,投票 nonces 将被绕过。保持原样更安全。

更新状态但没有事件发出的函数

在整个代码库中,发现了多个更新状态但没有事件发出的函数的实例:

考虑在每次状态更改时发出事件,以提高代码库的清晰度并使其不易出错。

更新: 已在 pull request #16pull request #10 中解决。

缺少索引事件参数

在整个代码库中,发现了多个事件没有索引参数的实例:

为了提高链下服务搜索和筛选特定事件的能力,请考虑 索引事件参数

更新: 已确认,但未解决。该团队表示:

已确认。事件值本身是可变的(例如,TokenBalanceWithdrawn 可以是任何值),不会通过该值进行事件查询。如果需要,添加索引将是明智的。这些不会进行任何更改。

EIP-6780 之后的 selfdestruct 不会删除代码

预期的行为是,调用 TokenAirdrop.sol 中的 withdraw() 函数应完全删除合约,将任何剩余的 ETH 转移给调用者,并防止进一步与合约地址交互。但是,由于 EIP-6780 中引入的行为更改,使用 selfdestruct(payable(msg.sender)) 不再删除合约的字节码 — 它仅转移 ETH。

考虑用直接的 ETH 转移替换 selfdestruct,以提高代码清晰度并更好地与 EIP-6780 之后的行为保持一致。

更新: 已在 pull request #12 中解决。该团队表示:

已确认:最初我们希望该调用发生在我们的网络上,同时应用伦敦 EVM 版本。这已被移除。

犹豫不决的许可证

在整个代码库中,发现了多个文件具有犹豫不决的 SPDX 许可证的实例:

  • LineaToken.sol 中的 // SPDX-License-Identifier: Apache-2.0 OR MIT SPDX 许可证
  • ILineaToken.sol 中的 // SPDX-License-Identifier: Apache-2.0 OR MIT SPDX 许可证
  • L2LineaToken.sol 中的 // SPDX-License-Identifier: Apache-2.0 OR MIT SPDX 许可证
  • IL2LineaToken.sol 中的 // SPDX-License-Identifier: Apache-2.0 OR MIT SPDX 许可证
  • TokenAirdrop.sol 中的 // SPDX-License-Identifier: Apache-2.0 OR MIT SPDX 许可证
  • IGenericErrors.sol 中的 // SPDX-License-Identifier: Apache-2.0 OR MIT SPDX 许可证
  • IMessageService.sol 中的 // SPDX-License-Identifier: Apache-2.0 OR MIT SPDX 许可证

考虑仅指定一个许可证,以防止可能的许可模糊。

更新: 已确认,但未解决。该团队表示:

已确认:这样做是为了让我们的代码的消费者在将其合并到其代码库中时具有灵活性。目的是应用他们的代码库使用的任何一个。

事件发出中不必要的数据字段

LineaToken.sol 中,emit L1TotalSupplySyncStarted(block.timestamp, totalSupply); 事件发出包含不必要的数据字段,例如 block.numberblock.timestamp

为了提高代码清晰度和可维护性,请考虑从事件发出中删除不必要的数据字段(如 block.numberblock.timestamp),因为它们已包含在区块信息中。

更新: 已在 pull request #15 中解决。该团队表示:

已确认:最初是为了清晰起见,但是,删除它是更好的做法,并且已经完成。

客户端报告

L2LineaToken 不需要 ERC20BurnableUpgradeable 继承

L2LineaToken 合约包含 burn 函数 的自定义实现,该实现具有特定于 Linea 代币桥的额外授权逻辑。因此,从 ERC20BurnableUpgradeable 继承是不必要的,并且引入了代币未使用的额外功能。

Linea 团队在并行审计期间也发现了此问题,并且在 commit b9aad54 中删除了从 ERC20BurnableUpgradeable 的继承。

更新: 已在 commit b9aad54 中解决。

结论

经过审计的系统支持 Linea 代币生成事件 (TGE),从而实现跨链代币铸造、供应同步和空投分配。它包括一个桥接的 ERC-20 代币对和一个空投合约,该合约根据外部参考合约中的余额计算分配。

未发现高风险或严重风险问题。仅报告了轻微的观察结果,主要与处理特定边缘案例和编写文档有关。桥接流程的正确性以及围绕分配输入的假设对于系统的完整性至关重要,应在部署期间仔细监控。

感谢 Linea 团队在整个审计过程中做出的积极响应和合作。

与专家交谈

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

0 条评论

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