报告清单
| 项目 | 描述 |
|---|---|
| 客户 | Magpie XYZ |
| 目标 | CakePie 合约 |
版本历史
| 版本 | 日期 | 描述 |
|---|---|---|
| 1.0 | 2023年11月30日 | 首次发布 |
1. 引言
1.1 关于目标合约
| 信息 | 描述 |
|---|---|
| 类型 | 智能合约 |
| 语言 | Solidity |
| 方法 | 半自动化和手动验证 |
本次审计的目标是 Magpie XYZ 的 CakePie 合约^1 代码库。CakePie 合约运行一个 CakeRush 活动,用户可以在 CakePie 上将 CAKE 代币或锁定的 CAKE 头寸转换为 CakePie。请注意,本次审计范围仅包括 CakeRush.sol 和 PancakeStakingBNBChain.sol,其他文件均不在审计范围内。
审计过程是迭代的。具体来说,我们将审计修复已发现问题的提交。如果存在新问题,我们将继续此过程。审计期间的提交 SHA 值显示在下表中。我们的审计报告负责初始版本(版本 1)以及用于修复审计报告中问题的(后续版本中的)新代码。

1.2 安全模型
为了评估风险,我们遵循行业和学术界广泛采用的标准或建议,包括 OWASP 风险评级方法^2 和常见漏洞枚举^3。风险的整体严重性由可能性和影响决定。具体来说,可能性用于估计攻击者发现和利用特定漏洞的可能性,而影响则用于衡量成功利用的后果。
在本报告中,可能性和影响均分为两个等级,即高和低,它们的组合显示在表 1.1 中。

因此,本报告中测量的严重性分为三类:高、中、低。为了完整起见,还使用未定来涵盖风险无法很好确定的情况。
此外,已发现项目的状态将属于以下四类之一:
-
未定 尚未收到回复。
-
已确认 项目已由客户收到,但尚未确认。
-
已确认 项目已由客户承认,但尚未修复。
-
已修复 项目已由客户确认并修复。
2. 发现
总共,我们发现了两个潜在问题。此外,我们还有三项建议和一项说明。
-
高风险:1
-
低风险:1
-
建议:3
-
说明:1
| ID | 严重性 | 描述 | 类别 | 状态 |
|---|---|---|---|---|
| 1 | 低 | 参数重置后可能的状态不一致 | 软件安全 | 已修复 |
| 2 | 高 | 重复申领 mCake 奖励 | 软件安全 | 已修复 |
| 3 | - | 检查初始化函数中的参数 | 建议 | 已确认 |
| 4 | - | 检查 CakeRush 合约中的参数 | 建议 | 已修复 |
| 5 | - | 修饰符中的额外条件 | 建议 | 已确认 |
| 6 | - | 潜在的中心化风险 | 说明 | - |
详细信息将在以下各节中提供。
2.1 软件安全
2.1.1 参数重置后可能的状态不一致
| 项目 | 描述 |
|---|---|
| 严重性 | 低 |
| 状态 | 已在版本 2 中修复 |
| 引入者 | 版本 1 |
描述 CakeRush 合约根据多个参数分配奖励。以下函数允许项目维护者重置某些参数:
function resetMultiplier() external onlyOwner {
uint256 len = rewardMultiplier.length;
for (uint8 i = 0; i < len; ++i) {
rewardMultiplier.pop();
rewardTier.pop();
}
tierLength = 0;
}
function resetTimeWeighting() external onlyOwner {
uint256 len = weightedTime.length;
for (uint8 i = 0; i < len; ++i) {
weightedTime.pop();
weighting.pop();
}
weightLength = 0;
}
列表 2.1:CakeRush.sol
但是,这些函数仅重置参数,而不重置存储在 userInfos 状态变量中的用户信息。因此,CakeRush 合约中的计算可能会因状态不一致而失败。例如,如果参数被重置并设置为不正确的值,Line 155 上的减法可能会因整数下溢而失败。
function quoteConvert(
uint256 _amountToConvert,
address _account
)
external
view
returns (
uint256 newUserFactor,
uint256 newTotalFactor,
uint256 newUserWeightedFactor,
uint256 newWeightedTotalFactor
)
{
if (_amountToConvert == 0 || rewardMultiplier.length == 0 || weighting.length == 0)
return (0, 0, 0, 0);
UserInfo storage userInfo = userInfos[_account];
uint256 accumulated = _amountToConvert + userInfo.converted;
uint256 factorAccuNoWeighting = 0;
uint256 i = 1;
while (i < rewardTier.length && accumulated > rewardTier[i]) {
factorAccuNoWeighting += (rewardTier[i] - rewardTier[i - 1]) * rewardMultiplier[i - 1];
i++;
}
factorAccuNoWeighting += (accumulated - rewardTier[i - 1]) * rewardMultiplier[i - 1];
uint256 factorToEarnNoWeighting = (factorAccuNoWeighting / DENOMINATOR) - userInfo.factor;
列表 2.2:CakeRush.sol
更糟糕的是,如果用户在重置参数后(例如通过回滚之前)立即调用 convert 或 convertWithCakePool,由于 Line 141-142 上的逻辑,合同中记录的总因子和加权因子可能会被重置。
影响 重置参数可能导致状态不一致和不正确。
建议 在清除旧参数后设置新参数。
项目反馈 一旦 Cake Rush 活动开始,乘数将不会被重置。
2.1.2 重复申领 mCake 奖励
| 项目 | 描述 |
|---|---|
| 严重性 | 高 |
| 状态 | 已在版本 3 中修复 |
| 引入者 | 版本 2 |
描述 在合同中锁定 CAKE 代币后,用户可以通过该函数申领 mCake 代币作为奖励。但是,该函数包含一个允许用户多次申领奖励的错误。在下面的代码片段中,如果金额大于用户的,将向用户转账或存入总金额。正确的实现应该只返回,因此当前的实现有效地允许用户反复申领 mCake 奖励。
function claim(bool _isStake) external nonReentrant {
UserInfo storage userInfo = userInfos[msg.sender];
if (claimedMCake[msg.sender] >= userInfo.converted) revert AlreadyClaimed();
if (_isStake && userInfo.converted > 0) {
if (masterCakepie == address(0)) revert MasterCakepieNotSet();
IERC20(mCakeOFT).safeApprove(address(masterCakepie), userInfo.converted);
IMasterCakepie(masterCakepie).depositFor(
address(mCakeOFT),
address(msg.sender),
userInfo.converted
);
} else if (userInfo.converted > 0) {
IERC20(mCakeOFT).transfer(msg.sender, userInfo.converted);
emit Claim(msg.sender, userInfo.converted);
}
claimedMCake[msg.sender] = userInfo.converted;
}
列表 2.3:CakeRush.sol
影响 用户可以反复申领 mCake 奖励。
建议 修改奖励申领逻辑。
2.2 附加建议
2.2.1 检查初始化函数中的参数
| 项目 | 描述 |
|---|---|
| 状态 | 已确认 |
| 引入者 | 版本 1 |
描述 在 CakeRush 和 PancakeStakingBNBChain 合约的初始化函数中,存在一些初始化后无法更改的参数。建议在初始化函数中检查这些参数。
function __CakeRush_init(
address _cake,
address _mCakeOFT,
address _masterCakepie
) public initializer {
__Ownable_init();
__ReentrancyGuard_init();
__Pausable_init();
cake = _cake;
mCakeOFT = _mCakeOFT;
masterCakepie = _masterCakepie;
}
列表 2.4:CakeRush.sol
影响 不适用
建议 检查初始化函数中的参数。
2.2.2 检查 CakeRush 合约中的参数
| 项目 | 描述 |
|---|---|
| 状态 | 已在版本 2 中修复 |
| 引入者 | 版本 1 |
描述 在 CakeRush 合约中,可以添加几个关于奖励分配的参数。但是,没有检查这些参数是否根据合约中的假设正确设置。具体来说,在 setMultipler 和 setTimeWeighting 函数中,必须检查额外的条件(即 rewardTier 和 weightedTime 数组的单调递增属性)。
function setMultiplier(
uint256[] calldata _multiplier,
uint256[] calldata _tier
) external onlyOwner {
if (_multiplier.length == 0 || (_multiplier.length != _tier.length)) revert LengthInvalid();
for (uint8 i = 0; i < _multiplier.length; ++i) {
if (_multiplier[i] == 0) revert InvalidAmount();
rewardMultiplier.push(_multiplier[i]);
rewardTier.push(_tier[i]);
tierLength += 1;
}
}
列表 2.5:CakeRush.sol
影响 不适用
建议 检查设置参数的函数中的参数。
2.2.3 修饰符中的额外条件
| 项目 | 描述 |
|---|---|
| 状态 | 已确认 |
| 引入者 | 版本 1 |
描述 在 CakeRush 合约中,_onlyPancakeStaking 修饰符包含一个不必要的条件。根据此修饰符的语义,检查 msg.sender != pancakeStaking 就足够了。
modifier _onlyPancakeStaking() {
if (pancakeStaking == address(0) || msg.sender != pancakeStaking)
revert OnlyPancakeStaking();
_;
}
列表 2.6:CakeRush.sol
影响 不适用
建议 删除修饰符中的不必要条件。
2.3 说明
2.3.1 潜在的中心化风险
描述 CakeRush 的所有者拥有修改关键配置的重大特权。这造成了单点故障。如果攻击者损害了所有者,他们可能会使整个系统瘫痪。
此外,合同中的 CAKE 代币并未显式处理以将其锁定到 VECake 合约中。相反,CakeRush 允许所有者提取所有这些 CAKE,这意味着所有者必须在提取后锁定 CAKE 代币。但是,逻辑在代码层面并未得到保证,这也带来了中心化方面的担忧。
项目反馈 团队将所有者设置为多重签名以缓解风险。
3. 通知和备注
3.1 免责声明
本审计报告不构成投资建议或个人推荐。它不考虑,也不应被解释为考虑或对代币、代币销售或任何其他产品、服务或资产的潜在经济产生任何影响。任何实体均不应以任何方式依赖本报告,包括用于做出购买或出售任何代币、产品、服务或资产的决定。
本审计报告并非对任何特定项目或团队的认可,报告不保证任何特定项目的安全性。本次审计不保证发现智能合约的所有安全问题,即评估结果不保证不存在任何进一步发现的安全问题。由于一次审计不能被认为是全面的,我们始终建议进行独立的审计和公开的赏金计划,以确保智能合约的安全性。
本次审计的范围仅限于 1.1 节中提到的代码。除非明确说明,否则语言本身(例如 Solidity 语言)、底层编译工具链和计算基础设施的安全性均不在审计范围内。
3.2 审计流程
我们按照以下流程进行审计。
-
漏洞检测 我们首先使用自动代码分析器扫描智能合约,然后手动验证(拒绝或确认)它们报告的问题。
-
语义分析 我们研究智能合约的业务逻辑,并使用自动模糊测试工具(由我们的研究团队开发)对可能的漏洞进行进一步调查。我们还请独立审计师手动分析可能的攻击场景,以交叉检查结果。
-
建议 我们从良好的编程实践的角度为开发人员提供一些有用的建议,包括 Gas 优化、代码风格等。
我们在以下展示主要具体的检查点。
3.2.1 软件安全
-
重入攻击
-
拒绝服务 (DoS)
-
访问控制
-
数据处理和数据流
-
异常处理
-
不可信的外部调用和控制流
-
初始化一致性
-
事件操作
-
易出错的随机性
-
代理系统使用不当
3.2.2 DeFi 安全
-
语义一致性
-
功能一致性
-
权限管理
-
业务逻辑
-
代币操作
-
紧急机制
-
预言机安全
-
白名单和黑名单
-
经济影响
-
批量转账
3.2.3 NFT 安全
-
重复项目
-
代币接收者验证
-
链下元数据安全
3.2.4 附加建议
-
Gas 优化
-
代码质量和风格
注意 以上检查点是主要的。我们可能会根据项目的具体功能在审计过程中使用更多的检查点。



