Crown BRL 稳定币审计

这是一篇OpenZeppelin对 crown-xyz 项目的 BRL 稳定币智能合约代码的审计报告。该报告评估了 BRLV, BRLY, YieldStripping, wBRLY 等合约,发现了一些低风险问题和建议,例如代码注释错误、缺少文档字符串、命名规范问题、未使用变量和多余的import。审计未发现任何严重或高风险漏洞。

目录

总结

TypeStablecoinsTimelineFrom 2025-07-15To 2025-07-18LanguagesSolidityTotal Issues8 (8 resolved)Critical Severity Issues0 (0 resolved)High Severity Issues0 (0 resolved)Medium Severity Issues0 (0 resolved)Low Severity Issues3 (3 resolved)Notes & Additional Information5 (5 resolved)

范围

OpenZeppelin 审计了 crown-xyz/crown-contracts 仓库,提交哈希为 13631ab

审计范围包括以下文件:

 contracts
├── BRLV.sol
├── BRLY.sol
├── YieldStripping.sol
└── wBRLY.sol

BRLY.sol 是相对于 USDM.sol 在提交哈希为 2f0e2f0 时的差异审计,而 wBRLY.sol 是相对于 wUSDM.sol 在提交哈希为 78c6556 时的差异审计。

系统概述

这是对 4 个文件的简要审计,其中 2 个文件是根据现有的 USDM 代码库进行差异审计的。BRLY 是一种类似于 USDM 代币的 rebasing 代币,增加了诸如最大奖励乘数增量比率及其设置函数等功能。此函数确保新的奖励比率不超过现有的最大值,以避免有利的即时存款攻击。BRLY 合约还添加了一个函数,该函数在 burning 期间转换为 shares 时将值向上取整。这有助于确保舍入误差有利于协议的偿付能力。

BRLV 是一个代币化的 vault,它以 BRLY 作为底层资产。它继承了 YieldStripping 合约,允许等量交换底层资产,该底层资产应为具有收益的 ERC-20 代币。BRLV 可以被认为是 ERC-4626 vault 的简化版本,因为由 rebasing 产生的任何溢出代币供应将被保留以供后续分配。额外的收益由具有权限的申领工作流程分配。

安全模型和信任假设

正在审查的合约建立在相当标准的模块上,如 ERC-4626 vault 和 ERC-20。此外,它们使用 OpenZeppelin 的 UUPS 可升级模式,以便将来进行逻辑升级。

特权角色

在整个代码库中,识别出多个特权角色:

  • CLAIM_ROLE
  • UPGRADE_ROLE
  • PAUSE_ROLE
  • DEFAULT_ADMIN_ROLE
  • ORACLE_ADMIN_ROLE
  • MINTER_ROLE
  • BURNER_ROLE

假设以上列出的角色将被授予受信任的账户,这些账户将始终表现良好。

低风险

不正确的注释

BRLV.sol 中,第 123 行的注释指出,如果 fromto 地址被“阻止”,则代币转账将被回滚。但是,该函数仅检查 from 地址是否被阻止第 127 行的注释也反映了这一点,该注释指出只有发送者被阻止。

考虑更改第 123 行中的注释以反映该函数的实际行为,或者为 to 地址实现单独的检查并删除第 127 行中的注释。

更新:pull request #19 的 commit 3d0a80 中已解决

缺失的文档字符串

在整个审计范围内的代码库中,发现了多个缺少文档字符串的实例。例如,在 YieldStripping.sol第 107 行 中。

考虑彻底记录所有属于任何合约公共 API 的函数(及其参数)。实现敏感功能的函数,即使不是公共的,也应明确记录。在编写文档字符串时,请考虑遵循 Ethereum Natural Specification Format (NatSpec)。

更新:pull request #20 的 commit fb9260 中已解决

_burn 中的舍入误差可能导致账户中留下极少量代币

_burn 函数是 withdraw 和访问控制的 burn 流程所必需的。在 withdraw 流程中,用户必须请求提取一定数量的 assets,这些 assets 将转换为 shares,然后从他们的帐户中 burned。但是,由于 maxWithdrawal 限制convertToSharesRoundUp 的使用(这仍然会导致一些舍入误差),用户几乎不可能提取他们的全部 shares 余额。访问控制的 burn 函数也容易在尝试 burn 帐户中的所有 shares 时在帐户中留下一些极少量代币。这部分是由于 convertToSharesRoundUp 函数造成的。

在这两种情况下,由于 rebasing 代币的性质,为帐户指定的 assets 可能对应于与交易包含在区块中时预期的不同的 shares 数量。最后,_burn 中的检查 accountShares < shares 意味着高估 assets 不是 burn 代币的可行方法,因为如果进行高估,执行将回滚。

考虑实现一些 burn 用户帐户中所有 shares 的流程。这将使合约能够更干净地运行并减少丢失的代币。例如,可以通过在 _burn 中实现不同的检查来允许高估,或者通过实现特殊的 withdrawAllburnAll 函数来实现。

更新: 在 pull request #21 的 commit 20d92a 中已解决。

提示 & 补充信息

YieldStrippable.sol 应该被重命名

YieldStrippable.sol 仅包含 IYieldStrippable 接口。

为了更好地遵循最佳实践命名标准并提高代码库的清晰度,请考虑将 YieldStrippable.sol 重命名为 IYieldStrippable.sol 并更改 YieldStripping.sol 中的导入 以匹配新的文件名。

更新:pull request #22 的 commit 596b36 中已解决

IBRLY 应该放在单独的文件中

IBRLY 接口BRLV.sol 中与BRLV 合约 一起声明。

考虑将 IBRLY 接口分离到其自己的文件 IBRLY.sol 中。这样做将有助于提高代码库的清晰度和可维护性。

更新:pull request #23 的 commit 404523 中已解决

_tryGetAssetDecimals 未被使用

YieldStripping.sol 中的 _tryGetAssetDecimals 函数未被使用。

考虑删除任何未使用的代码,以提高代码库的清晰度和可维护性。

更新:pull request #24 的 commit 9f4098 中已解决

可以申领 0 奖励

rewards == 0 时,claimRewards 函数 将成功执行。这实际上是一个空操作,但会用不必要的事件排放污染事件日志。

考虑在 claimRewards 中实现对 rewards 金额的健全性检查。

更新:pull request #25 的 commit 0de1f8 中已解决

未使用的导入

在整个代码库中,发现了多个未使用的导入实例:

考虑删除任何未使用的导入,以提高代码库的整体清晰度和可维护性。

更新:pull request #26 的 commit e69fa0 中已解决

结论

该代码库实现了一个最小的、生息的、rebasing 的 BRL 稳定币代币。它具有基于角色的访问控制、可暂停性和阻止列表机制,以确保符合法规。

审计未发现任何严重、高或中等严重性问题,只有一些低风险和提示严重性发现。提供了建议,使代码库与 Solidity 最佳实践保持一致,并确保清晰、预期的功能。安全的系统运行依赖于以协议最佳利益行事的受信任角色,以及实时监控以有效管理阻止列表。

审计团队赞扬了最小的设计和对经过实战考验的合约的重用,例如 Mountain Protocol 的 USDM 和 OpenZeppelin 的库,这有助于最大限度地减少潜在的漏洞。

与专家交谈

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

0 条评论

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