本文为OpenZeppelin开展的EIP-4337审计安全评估,详细分析了智能合约的高严重性问题及其他找出的潜在安全漏洞,提供了相关的修复更新信息和对文档的改进建议,同时提出了对监控合约活动的推荐。全面探讨了包括代码库中的建议更改、bug修复和更新方法。
这份安全评估由 OpenZeppelin 准备。
类型: DeFi
时间范围: 2023-01-09 至 2023-01-27
语言: Solidity
总问题: 27 (23 个已解决, 4 个部分解决)
关键严重性问题: 0 (0 个已解决)
高严重性问题: 1 (1 个已解决)
中等严重性问题: 0 (0 个已解决)
低严重性问题: 12 (10 个已解决, 2 个部分解决)
备注与附加信息: 14 (12 个已解决, 2 个部分解决)
EIP-4337 是一项规范,旨在向以太坊主网添加账户抽象功能,而不修改共识规则。以太坊基金会请求我们审查他们规范的最新修订和参考实现。
我们审计了 eth-infinitism/account-abstraction 仓库的 6dea6d8752f64914dd95d932f673ba0f9ff8e144 提交。
审计的合约包括:
contracts
├── bls
│   ├── BLSAccount.sol
│   ├── BLSAccountFactory.sol
│   ├── BLSSignatureAggregator.sol
│   └── IBLSAccount.sol
├── core
│   ├── BaseAccount.sol
│   ├── BasePaymaster.sol
│   ├── EntryPoint.sol
│   ├── SenderCreator.sol
│   └── StakeManager.sol
├── gnosis
│   ├── EIP4337Fallback.sol
│   ├── EIP4337Manager.sol
│   └── GnosisAccountFactory.sol
├── interfaces
│   ├── IAccount.sol
│   ├── IAggregatedAccount.sol
│   ├── IAggregator.sol
│   ├── ICreate2Deployer.sol
│   ├── IEntryPoint.sol
│   ├── IPaymaster.sol
│   ├── IStakeManager.sol
│   └── UserOperation.sol
├── samples
│   ├── DepositPaymaster.sol
│   ├── IOracle.sol
│   ├── SimpleAccount.sol
│   ├── SimpleAccountFactory.sol
│   ├── TestAggregatedAccount.sol
│   ├── TestAggregatedAccountFactory.sol
│   ├── TestSignatureAggregator.sol
│   ├── TokenPaymaster.sol
│   └── VerifyingPaymaster.sol
└── utils
    └── Exec.sol最初 BLSHelper.sol 包含在范围内,但我们同意在审计过程中优先考虑对其的完整审查。
审计后,以太坊基金会请求我们审查三个新的拉取请求:
1b85cfb: 创建用户操作哈希缺图的规范结构,以防止不同用户操作之间的可能哈希冲突。19918cd: 将 nonce 独特性验证移至 EntryPoint 合约。这现在防止账户在多个操作之间重用 nonce,但新的“键”和“序列号”区分提供了一定的操作顺序灵活性。9b5f2e4: 为 handleOps 和 handleAggregatedOps 函数添加重入保护和新的 BeforeExecution 事件。这防止了可能出现的事件顺序混淆,若这些函数被递归调用。作为修复审核过程的一部分,以及我们对这些更改的审核,我们审查了影响在范围内合约的拉取请求,直到提交 9b5f2e4。
系统架构在 我们最初的审计报告 中描述,现在包含一系列重要更改。
例如,用户和支付者现在在验证操作时都可以更改 EVM 状态。这更为通用,减轻了支付者可能在未来版本中移除回退功能的需要。为支持此更改,增加了额外的存储限制(在 EIP 中描述),以确保批处理中所有验证访问非重叠的存储插槽。此外,用户操作可以将自己的验证委托给“聚合器”智能合约,这允许所有共享聚合器的操作一起被验证。聚合器遵循与支付者相同的抵押和节流规则。
为了防止可能的混淆,值得指出的是,在此上下文中,“聚合”是指任何可以有效验证独立用户操作的机制。样本 BLSSignatureAggregator 合约有效地验证多个用户操作上的 BLS 签名,但不使用标准的 BLS 签名聚合 技术,该技术产生一个单一消息的组合签名。尽管如此,该系统支持具有任意验证逻辑的账户,因此任何人都可以部署一个接受单一消息的聚合 BLS 签名的账户(例如,生产多重签名钱包)。
还有一些增量更改:
客户报告: 以太坊基金会在审计期间识别了这个问题。
在模拟过程中,EntryPoint 合约 调用发送者合约的视图函数,然后进行 常规验证。由于任何存储插槽的首次访问 成本高于后续访问,因此视图函数可以执行初始的“冷访问”,以允许常规验证函数使用“热访问”。如果不同的Gas费用决定验证函数是否耗尽了Gas,那么在模拟期间,验证将成功,但在链上会失败。在这种情况下,打包者将不得不为失败的交易支付费用。
更新: 已在 拉取请求 #216 中解决,并合并于提交 1f505c5. 聚合器逻辑已重新设计,这使得此问题变得过时。
客户报告: 以太坊基金会在审计前识别了这个问题。
EIP 禁止账户 在验证期间使用 BASEFEE 操作码,以防止他们检测到何时报会离线模拟。然而,EntryPoint 合约 将所需的预资金传递给账户,这个金额 依赖基础费用,从而泄露该值。
更新: 已在 拉取请求 #171 中解决,并合并于提交 b34b7a0. 预资金金额现在使用可能的最大Gas费。
客户报告: 以太坊基金会在审计期间与我们分享了这个问题,随后由 leekt 报告。
VerifyingPaymaster 合约要求可信的签名者签名 用户操作的哈希。然而,签名没有明确说明。尤其是:
更新: 已在 拉取请求 #184 中解决,并合并于提交 48854ef.
EIP4337Manager客户报告: 以太坊基金会在审计期间与我们分享了这个问题,随后由 leekt 报告。
EIP4337Manager 合约旨在增强 GnosisSafe 合约,通过提供一个 用户操作验证函数。安全合约(技术上讲是他们的代理)旨在使用 delegatecall 来访问此函数。
然而,任何人都可以通过 新模块配置管理器合约。由于管理器合约 继承了 GnosisSafe 功能,新的模块可以 触发任意函数调用 并可能自毁合约。这将有效地禁用所有使用它的安全模块。
更新: 已在 拉取请求 #208 中解决,并合并于提交 d92fec8.
客户报告: 以太坊基金会在审计期间识别了这个问题。
EntryPoint 合约有四个地方可供外部函数调用,这些调用可以使用任意长度的消息进行回退,而 EntryPoint 必须将其复制到自己的内存中。每个实例都有不同的实际后果:
callGasLimit。如果在链上发生这种情况,用户(或支付者)仍会为额外消耗的Gas费付费。如果相反,整个批次回退,则 FailedOp 错误将不会返回,因此打包者将无法轻易识别出有问题的操作。FailedOp 错误的情况下回退。更新: 部分通过 拉取请求 #178 的解决,并合并于提交 9c00e78. 只有用户操作的回退原因被限制。
BLSSignatureAggregator 提供了一种机制,允许打包者 验证单个签名,然后再构建批次。成功的操作分组,以便打包者 可以结合他们的签名 进行离线处理,而 EntryPoint 可以 在线验证它们。然而,账户可能构造一个操作,在单个签名检查中通过,但在组合签名检查中仍然失败。
特别是,如果它公开的公钥 在单独验证期间 与在组合验证期间 使用的公钥不同,则尽管签名相同,但这两个验证将不一致。这可能发生,因为 initCode 的 最后 4 个字 与公钥不匹配(因为 initCode 有额外的数据,或者它们没有使用 预期的创建功能)。如果 用户的验证功能 (在单个签名验证期间未调用)更改了通过 getBlsPublicKey 返回的公钥,也可能会发生这种情况。
如果打包者构建了一个包含这些操作的批次,它将无法验证组合签名并将过错归因于聚合器,这将导致聚合器被限流,并且与同一聚合器有关的用户操作将不会被处理。
考虑同步这两个验证函数,以便它们都使用相同的公钥。
更新: 已在 拉取请求 #195 中解决,以及在 拉取请求 #216 的提交 268f103 中,均已合并于提交 1cc1c97 和 1f505c5 之间。
EntryPoint [样本]注释 描述的 SimpleAccount 合约的 initialize 函数宣称应该存在一个机制来替换 EntryPoint 合约。该声明与它所描述的函数行为不符,其实没有机制在不升级整个账户的情况下替换 EntryPoint 合约。
考虑更新该注释以匹配行为,并如果希望该功能则引入一个替换 EntryPoint 合约的机制。
_更新: 已在 拉取请求 #192 中解决,并合并于提交 82685b2. 一个 @dev 注释已添加到 initialize 函数的文档字符串中,以澄清 _entryPoint 存储变量不是初始化程序的参数,因为需要升级才能更改 EntryPoint 地址。_
SIG_VALIDATION_FAILED 常量的文档 阐述 validateUserOp 在签名验证失败时必须返回该值而非回退。SimpleAccount 合约 正确遵循 该规范,但是在 EIP4337Manager 合约中,validateUserOp 函数 在签名验证失败时回退。这意味着 simulateValidation 函数 将回退,而不提供 ValidationResult 对象。
考虑更改逻辑,以便在遇到无效签名时,validateUserOp 返回 SIG_VALIDATION_FAILED。
更新: 已在 拉取请求 #181 中解决,并合并于提交 1dfb173.
EntryPoint 合约 减少操作过期时间戳,以将 0(应解释为“无过期”)转换为最大 uint64 值。然而,所有其他可能的过期值现在都少了一。出于可预测性的考量,建议仅修改 0 时间戳。
更新: 已在 拉取请求 #193 中解决,并合并于提交 973c0ac.
发现代码库中的若干文档字符串和内联评论不正确或误导。特别是:
在 BaseAccount.sol:
sigTimeRange 定义为“本操作的签名和时间范围”,但它包含签名有效性,而非签名本身。在 BLSSignatureAggregator.sol:
simulateUserOperation 的调用,但函数名应为 simulateValidation。在 EIP4337Manager.sol:
GnosisSafeStorage,而实际上继承的是 GnosisSafe。在 EntryPoint.sol:
paymasterAndData 列为被排除在 MemoryUserOp 之外的动态字节数组之一。_validatePaymasterPrepayment 验证支付者是否被抵押,但该函数并未执行此检查。在 IPaymaster.sol:
validUntil 和 validAfter 时间戳长度为 4 字节,但这些是 8 字节(uint64)值。在 IStakeManager.sol:
在 SimpleAccount.sol:
execFromEntryPoint 函数,但该函数不再存在。execute 的文档字符串上说“直接从所有者调用,而不是通过 entryPoint”,但 _requireFromEntryPointOrOwner 函数允许 execute 被 EntryPoint 调用。该注释并未明确它是一个建议,或是强制执行的限制。initialize 函数不符。_requireFromEntryPointOrOwner 函数不符。在 IEntryPoint.sol:
@success 参数的顺序不正。在 UserOperation.sol:
callGasLimit 参数没有 @param 语句。更新: 已在 拉取请求 #194 中解决,并在 拉取请求 #216 中合并,分别合并于提交 faf305e 和 1f505c5.
EIP 规定 在检测到 FailedOp 时,所有来自同一支付者的其他操作应从当前批次中移除。然而,这仅应适用于明确提及支付者的 FailedOp 错误,这意味着支付者存在过错。因无关原因而失败的操作不应惩罚其支付者。EIP 还 声明 userOp 验证不能为空调用 handleOps 方法。该限制也应适用于 handleAggregatedOps。
考虑在 EIP 中澄清这些要点。
更新: 在 拉取请求 #196 中部分解决并在 5929ff8 合并。更新后的 EIP 错误地将 EntryPoint 的 depositTo 函数称为 depositFor。
StakeLocked 事件指定了一个 withdrawTime 参数,但是传递的参数是 新的撤资延迟。考虑重命名事件参数以匹配其实际使用。
更新: 在 拉取请求 #197 中解决并在提交 545a15c 中合并。
在 代码库 中,有几个地方没有文档字符串。例如:
BLSAccount.sol 中的 第 24 行BLSAccount.sol 中的 第 39 行BLSAccount.sol 中的 第 44 行BLSAccount.sol 中的 第 48 行BLSSignatureAggregator.sol 中的 第 20 行BLSSignatureAggregator.sol 中的 第 48 行BLSSignatureAggregator.sol 中的 第 106 行IBLSAccount.sol 中的 第 10 行BasePaymaster.sol 中的 第 24 行BasePaymaster.sol 中的 第 29 行BasePaymaster.sol 中的 第 31 行EntryPoint.sol 中的 第 167 行StakeManager.sol 中的 第 18 行EIP4337Fallback.sol 中的 第 11 行GnosisAccountFactory.sol 中的 第 23 行IStakeManager.sol 中的 第 67 行UserOperation.sol 中的 第 34 行DepositPaymaster.sol 中的 第 73 行SimpleAccount.sol 中的 第 27 行SimpleAccount.sol 中的 第 31 行TestAggregatedAccount.sol 中的 第 23 行TestAggregatedAccount.sol 中的 第 34 行TestSignatureAggregator.sol 中的 第 16 行TestSignatureAggregator.sol 中的 第 28 行TestSignatureAggregator.sol 中的 第 43 行TokenPaymaster.sol 中的 第 40 行Exec.sol 中的 第 6 行请考虑全面记录所有函数及其参数,特别是公共 API。在编写文档字符串时,可以考虑遵循 以太坊自然规范格式 (NatSpec)。
更新: 在 拉取请求 #212 中部分解决并在提交 eeb93b2 合并。对 GnosisAccountFactory.sol 的推荐更改未得到实施。
在 代码库 中,有一些 require 语句缺少错误消息:
BasePaymaster.sol 中的 第 105 行 的 require 语句DepositPaymaster.sol 中的 第 49 行 的 require 语句SimpleAccount.sol 中的 第 137 行 的 require 语句请考虑在 require 语句中包含具体的信息和错误消息,以提高整体代码的清晰度,并在需要时促进故障排除。
更新: 在 拉取请求 #198 中解决并在提交 182b7d3 中合并。向 BasePaymaster.sol 和 DepositPaymaster.sol 的缺失 require 语句添加了错误消息,而在 SimpleAccount.sol 中的 require 语句因代码更改而被消除了。
EIP 声明 一个聚合账户应当支持 getAggregationInfo 函数,并且该函数应返回账户的公钥,并可能还返回其他数据。然而,BLSAccount 合约中并没有包含 getAggregationInfo 函数。考虑将 the getBlsPublicKey 函数 重命名为 getAggregationInfo。
更新: 在 拉取请求 #199 中解决并在提交 12d2ac0 中合并。EIP 现在使用 getBlsPublicKey 函数作为示例。
SimpleAccountFactory 创建一个新的实现合约,但并没有 初始化它。这意味着任何人都可以将实现合约初始化为其拥有者。
后果取决于使用的 OpenZeppelin 合约版本。该项目 要求 4.2 版本 及以后的版本,但 锁定版本 4.8。onlyProxy 修饰符于 4.3.2 版本引入,以保护升级机制。没有这个修饰符,拥有者 被授权 直接调用实现合约的升级函数,从而 允许他们 selfdestruct。
在锁定的版本中,实施的拥有者可以 执行任意调用 来自实现合约,但不应能干扰代理的操作。
尽管如此,为了减少攻击面,考虑限制支持的 OpenZeppelin 合约版本并 在 SimpleAccount 合约的构造函数中禁用初始化器,以防止任何人声称拥有权。
更新: 在 拉取请求 #201 中解决并在提交 4004ebf 中合并。
EntryPoint 合约可以发出一个 FailedOp 错误,其中 reason 参数提供额外的调试信息。然而,有两个位置( 第 375 行 和 第 417 行)不受信任的合约可以提供原因,可能包含误导性的错误代码。例如,发送者 validateUserOp 函数的 revert 可能会返回 "AA90 invalid beneficiary",在模拟时可能导致混淆。
考虑在外部提供的 revert 原因前添加唯一标识的错误代码前缀。
更新: 在 拉取请求 #200 中解决并在提交 3d8f450 中合并。
使用 abi.encodeWithSignature 或 abi.encodeWithSelector 来生成低级调用的 calldata 并不罕见。然而,第一个选项并没有从拼写错误中得到保护,第二个选项也不是类型安全。这导致这两种方法都易出错,应该被视为不安全。
在 EIP4337Manager.sol 中,有一些使用不安全的 ABI 编码的情况:
考虑用 abi.encodeCall 替换所有的 unsafe ABI 编码,abi.encodeCall 检查提供的值是否真正匹配被调用函数预期的类型,并且避免拼写错误。
请注意,与使用字符串字面量作为 abi.encodeCall 输入相关的 错误 在 0.8.13 版本中被修复,因此开发人员在早期版本的 Solidity 中使用此函数时应谨慎。
更新: 在 拉取请求 #220 中解决并在提交 c0a69bf 中合并。第一个示例是无效的建议,因为它正在编码一个错误。
uint/int 为 uint256/int256 [core 和 samples]在 代码库 中,存在多个 int 和 uint 的使用实例,而不是 int256 和 uint256。为了明确性,考虑将所有的 int 替换为 int256,而 uint 替换为 uint256。
更新: 在 拉取请求 #215 中部分解决,已在提交 998fa7d 合并。大多数实例已经处理,但仍然存在一些 uint 类型。
为了提升对给定合同文件是包含核心、样本或测试代码的额外清晰度,请考虑以下建议移动项目文件:
samples 目录中,TestAggregatedAccount.sol、TestAggregatedAccountFactory.sol 和 TestSignatureAggregator.sol 包含类似于在 contracts/test 目录中的测试合同。考虑将这些文件移至 contracts/test 目录。bls 和 gnosis 目录包含样本账户实现,但不位于 samples 目录。考虑将这些项移动到 samples 目录。更新: 在 拉取请求 #217 中解决,并在提交 f82cbbb 中合并。
IAggregatorAccount 接口通过添加能力,来扩展基础的 IAccount 接口,该能力是 公开与账户相关的签名聚合器。为了添加支持处理聚合用户操作,IAccount 中的 validateUserOp 函数现在包含一个 aggregator 地址参数。与聚合器无关的账户 必须为此参数提供空地址。这在基类了解仅与派生类相关的功能时形成了一个反模式。
为了解决此案例和协议将来的增强,考虑在 validateUserOp 中用一个更通用的 extensions 参数来替代 aggregator 参数,用于指定聚合器及任何将来的账户特定扩展。
更新: 在 拉取请求 #216 中解决,并在提交 1f505c5 中合并。
BaseAccount 合约的 packSigTimeRange 函数 隐式假设 时间戳适合用 8 字节表示。考虑通过使用 uint64 参数来强制执行这一假设。
更新: 在 拉取请求 #203 中解决并在提交 fa46d5b 中合并。
BLSAccount 合约 在公钥更改时发出事件,但在 初始化时没有发出。为了完成事件历史,考虑在初始化时也发出事件。
更新: 在 拉取请求 #204 中解决并在提交 2600d7e 中合并。
在 SignatureAggregatorChanged 事件中的 aggregator 参数未被索引。考虑 索引事件参数,以避免阻碍离线服务搜索和筛选特定事件的任务。
更新: 在 拉取请求 #202 中解决并在提交 1633c06 中合并。
为了 favor 明确性和可读性,合约中有几个位置可能受益于更好的命名。我们的建议包括:
在 BaseAccount.sol 中:
packSigTimeRange 函数是内部的,但没有使用前缀“_”。考虑重命名为 _packSigTimeRange。在 BasePaymaster.sol 中:
packSigTimeRange 函数是内部的,但没有使用前缀“_”。考虑重命名为 _packSigTimeRange。在 BLSSignatureAggregator.sol 中:
hashPublicKey 重命名为 publicKeyHash 以保持一致性。在 EIP4337Manager.sol:- 考虑将本地变量 _msgSender 重命名为 msgSender 以保持一致性。
在 IAggregator.sol:
aggregateSignatures 函数的返回值从 aggregatesSignature 重命名为 aggregatedSignature。在 IEntryPoint.sol:
ExecutionResult 错误使用了 validBefore 而不是 validUntil。为了保持一致性,考虑将参数名称改为 validUntil。ReturnInfo 结构体的 文档 指示 validAfter 参数是包括在内的。考虑将其重命名为 validFrom 遍及整个代码库。AggregatorStakeInfo 结构体中,考虑将 actualAggregator 重命名为 aggregator (在 这里 的注释中也同样)。在 SenderCreator.sol:
createSender 函数中,考虑将 initAddress 变量重命名为 factory 以与 EntryPoint 合约 保持一致。在 SimpleAccount.sol:
addDeposit 函数中,考虑将 req 变量重命名为 success。在 StakeManager.sol:
internalIncrementDeposit 是一个内部函数,其前缀使用“internal”而不是“_”。考虑更改为 _incrementDeposit。getStakeInfo 函数是内部的但没有以“_”作为前缀。考虑将函数重命名为 _getStakeInfo。getStakeInfo 的 addr 参数重命名为 account。StakeManager中的 所有实例 中删除 _unstakeDelaySec 的前导下划线,现在不再需要名为 unstakeDelaySec 的存储变量。更新: 在 pull request #221 中解决,并在提交 7bd9909 中合并。
Solidity 风格指南指定了一个 推荐顺序 来布局合约文件中的元素,以便于在可预测的位置找到分组声明。在 代码库 的几个地方没有遵循此建议:
BLSAccount.sol: PublicKeyChanged 事件在两个函数之间定义。BLSSignatureAggregator.sol:常量值 N 在两个函数之间定义。IEntryPoint.sol:从 第 70 行 开始,错误和结构体定义与函数定义混杂。IPaymaster.sol: PostOpMode 枚举在所有函数之后定义。SimpleAccount.sol: _entryPoint 变量、 SimpleAccountInitialized 事件以及 onlyOwner 修饰符在多个函数定义之后定义。为了提高项目的整体可读性,考虑标准化整个代码库的顺序,以符合 Solidity 风格指南的推荐。
更新: 在 pull request #211 中部分解决,并在提交 ca1b649 中合并。在 IEntryPoint.sol 中,错误的定义已被重新定位,但多个结构体的定义仍然夹在函数之间。
StakeManager 允许 存款高达最大 uint112 值,但押金必须严格小于最大 uint112 值。考虑在两种情况下使用相同的最大值以保持一致性。
更新: 在 pull request #209 中解决,并在提交 419b7b0 时完成。
在 代码库 中发现以下 TODO 注释实例:
TODO 注释如果不正式作为问题进行跟踪,更可能被忽视并保持未解决。随着时间的推移,关于最初动机、计划和支持细节的重要信息也可能会丢失。考虑删除所有 TODO 注释实例,并在问题积压中进行跟踪。或者,考虑将每个内嵌的 TODO 链接到相应的问题积压条目。
更新: 在 pull request #218 中解决,并在提交 80d5c89 中合并。第一个例子已过时。其他两个不是 TODO,并改为“注意”。
考虑处理以下排版错误:
在 BaseAccount.sol:
在 BLSAccount.sol:
在 BLSAccountFactory.sol:
BLSHelper.sol:在 BLSSignatureAggregator.sol:
在 DepositPaymaster.sol:
在 EIP4337Manager.sol:
在 EntryPoint.sol:
在 IAccount.sol:
在 IAggregatedAccount.sol:
在 IAggregator.sol:
在 IEntryPoint.sol:
在 IPaymaster.sol:
在 IStakeManager.sol:
在 SimpleAccount.sol:
在 TestAggregatedAccount.sol:
在 TestAggregatedAccountFactory.sol:
在 TokenPaymaster.sol:
在 UserOperation.sol:
更新: 已在 pull request #219 中解决,并在提交 b4ce311 中合并。
在 代码库 中,以下行的导入未使用,可以删除:
console 的 BLSSignatureAggregator.solEIP4337Manager 的 EIP4337Fallback.solExec 的 GnosisAccountFactory.solIAggregator 的 IAggregatedAccount.solUserOperation 的 IAggregatedAccount.solOwnable 的 DepositPaymaster.solBaseAccount 的 TestAggregatedAccount.solSimpleAccount 的 TestSignatureAggregator.solconsole 在 TestSignatureAggregator.solSimpleAccount 的 TokenPaymaster.sol考虑删除未使用的导入,以避免引起混淆,从而降低代码库的整体清晰性和可读性。
更新: 已在 pull request #206 中解决,并在提交 e019bbd 中合并。
ICreate2Deployer.sol 导入已从 EntryPoint.sol 中删除,见 pull request #144,但是该文件仍存在于 interfaces 目录中。没有合约导入此文件。
考虑删除未使用的接口文件。
更新: 已在 pull request #205 中解决,并在提交 679ac11 中合并。
在整个代码库中,已经努力将“钱包”的术语更改单为“帐户”,例如 SimpleWallet 已重命名为 SimpleAccount。然而,某些“钱包”的引用仍然存在于各个注释中:- 第 13 行 的 BLSAccountFactory.sol
为避免混淆,考虑将这些“wallet”替换为“account”。
更新: 在 pull request #210 中解决,并在提交 d6a2db7 合并。
发现一个高严重性问题。提出了几个更改,以改善代码的整体质量并减少攻击面。
虽然审计有助于识别潜在的安全风险,但也鼓励以太坊基金会在其操作中整合对链上合约活动和新 mempool 内活动的自动监控。持续监控已部署的合约有助于识别潜在威胁和影响生产环境的问题。在这种情况下,它也可能提供关于系统如何被使用或误用的有用信息。考虑监控以下项目:
- 原文链接: blog.openzeppelin.com/ei...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
 
                如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!