这是一篇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 行的注释指出,如果 from
或 to
地址被“阻止”,则代币转账将被回滚。但是,该函数仅检查 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
中实现不同的检查来允许高估,或者通过实现特殊的 withdrawAll
或 burnAll
函数来实现。
更新: 在 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 中已解决
当 rewards == 0
时,claimRewards
函数 将成功执行。这实际上是一个空操作,但会用不必要的事件排放污染事件日志。
考虑在 claimRewards
中实现对 rewards
金额的健全性检查。
更新: 在 pull request #25 的 commit 0de1f8 中已解决
在整个代码库中,发现了多个未使用的导入实例:
BRLV.sol
的 ECDSAUpgradeable
BRLV.sol
的 ERC4626Upgradeable
BRLY.sol
的 ECDSAUpgradeable
YieldStripping.sol
的 IERC4626Upgradeable
wBRLY.sol
的 ECDSAUpgradeable
考虑删除任何未使用的导入,以提高代码库的整体清晰度和可维护性。
更新: 在 pull request #26 的 commit e69fa0 中已解决
该代码库实现了一个最小的、生息的、rebasing 的 BRL 稳定币代币。它具有基于角色的访问控制、可暂停性和阻止列表机制,以确保符合法规。
审计未发现任何严重、高或中等严重性问题,只有一些低风险和提示严重性发现。提供了建议,使代码库与 Solidity 最佳实践保持一致,并确保清晰、预期的功能。安全的系统运行依赖于以协议最佳利益行事的受信任角色,以及实时监控以有效管理阻止列表。
审计团队赞扬了最小的设计和对经过实战考验的合约的重用,例如 Mountain Protocol 的 USDM 和 OpenZeppelin 的库,这有助于最大限度地减少潜在的漏洞。
- 原文链接: blog.openzeppelin.com/cr...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!