delegateAndReturn(); }
通过跟踪 rebase 函数,发现 rebase 函数最终调用了 delegateAndReturn 函数,代码如下: function delegateAndReturn() private returns (bytes memory) { (bool success, ) = implementation.delegatecall(msg.data); assembly { let free_mem_ptr := mload(0x40) returndatacopy(free_mem_ptr, 0, returndatasize) switch success case 0 { revert(free_mem_ptr, returndatasize) } default { return(free_mem_ptr, returndatasize) } } } 通过分析代码,可以发现 delegateAndReturn 函数最终使用 delegatecall 的方式调用了 implementation 地址中的逻辑,也就是说,这是一个可升级的合约模型。而真正的 rebase 逻辑位于 YAM.sol 中 , 继续跟进 rebase 函数的具体逻辑,如下: function rebase( uint256 epoch, uint256 indexDelta, bool positive ) external onlyRebaser returns (uint256) { if (indexDelta == 0) { emit Rebase(epoch, yamsScalingFactor, yamsScalingFactor); return totalSupply; } uint256 prevYamsScalingFactor = yamsScalingFactor; if (!positive) { yamsScalingFactor = yamsScalingFactor.mul(BASE.sub(indexDelta)).div(BASE); } else { uint256 newScalingFactor = yamsScalingFactor.mul(BASE.add(indexDelta)).div(BASE); if (newScalingFactor <_maxScalingFactor()) { yamsScalingFactor = newScalingFactor; } else { yamsScalingFactor =_maxScalingFactor(); } } //SlowMist// 问题代码 totalSupply = initSupply.mul(yamsScalingFactor); emit Rebase(epoch, prevYamsScalingFactor, yamsScalingFactor); return totalSupply; } } 通过分析最终的 rebase 函数的逻辑,不难发现代码中根据 yamsScalingFactor 来对 totalSupply 进行调整,由于 yamsScalingFactor 是一个高精度的值,在调整完成后应当除以 BASE 来去除计算过程中的精度,获得正确的值。但是项目方在对 totalSupply 进行调整时,竟忘记了对计算结果进行调整,导致了 totalSupply 意外变大,计算出错误的结果。 分析到这里还没结束,要将漏洞和社区治理关联起来,需要对代码进行进一步的分析。通过观察 rebase 函数的修饰器,不难发现此处限定了只能是 rebaser 进行调用。而 rebaser 是 YAM 中用与实现供应量相关逻辑的合约,也就是说,是 rebaser 合约最终调用了 YAM.sol 合约中的 rebase 函数。通过跟踪相关代码,发现 rebaser 合约中对应供应量调整的逻辑为 rebase 函数,代码如下: (责任编辑:admin1) |