-
Notifications
You must be signed in to change notification settings - Fork 0
Description
Festive Linen Unicorn
Medium
Some Usual tokens are stuck in UsualSP.sol
Summary
In current implementation, if UsualSP.startRewardDistribution
is called before UsualSP.allocate
, there will some rewardToken stuck in the UsualSP.sol
contract.
Root Cause
I'll use the on-chain tx to explain the issue
After UsualSP
is deployed in tx https://etherscan.io/tx/0x52fbf41f8c8f8f935b448ad8c2c11b86df3ad21727756c9230a5e27ce55afccf, UsualSP.startRewardDistribution
is the first function been called in tx https://etherscan.io/tx/0x26ce95f3b7a9fd0ceb0e32ffd7c6e7a83278edb9fd1096cc4c2408f4fc463d9e, and then UsualSP.allocate
is called in tx https://etherscan.io/tx/0xbcff5d36ffbd70819daf79693d7183aa6dda2aa423100b05fa82905f7188651b, and then UsualSP.startRewardDistribution
is called again in https://etherscan.io/tx/0x117679127b297c0afbe033d7fb564d1b1961edac3f5dd80f986d1befca830178, and then UsualSP.stakeUsualS
is called in tx https://etherscan.io/tx/0x7cdb5ce4ba96f446292c97d93ba61eb0aeef86a9fa9c6ceda779ec4fc2328303.
- while the first
UsualSP.startRewardDistribution
is called, _rewardPerToken is called to calculaterewardPerToken
, because of totalStaked is 0,function _rewardPerToken
will return 0 in RewardAccrualBase.sol#L111.
106 function _rewardPerToken() internal view virtual returns (uint256 rewardPerToken) {
110 if (totalStaked() == 0) {
111 return $.rewardPerTokenStored; <<<--- function will do early return here
112 } else {
...
126 }
127 }
- until UsualSP.stakeUsualS is called ,
$.rewardPerTokenStored
will keep zero because totalStaked will always returns 0
68 function totalStaked() public view override returns (uint256) {
469 UsualSPStorageV0 storage $ = _usualSPStorageV0();
470 return $.usualS.balanceOf(address(this));
471 }
- In such case, until the third
UsualSP.startRewardDistribution
tx, the$.rewardPerToken
will be zero, so the Usual token distributed by the first twoUsualSP.startRewardDistribution
will be now redistributed.
Internal Pre-conditions
None
External Pre-conditions
None
Attack Path
After UsualSP
is deployed in tx https://etherscan.io/tx/0x52fbf41f8c8f8f935b448ad8c2c11b86df3ad21727756c9230a5e27ce55afccf, UsualSP.startRewardDistribution
is the first function been called in tx https://etherscan.io/tx/0x26ce95f3b7a9fd0ceb0e32ffd7c6e7a83278edb9fd1096cc4c2408f4fc463d9e, and then UsualSP.allocate
is called in tx https://etherscan.io/tx/0xbcff5d36ffbd70819daf79693d7183aa6dda2aa423100b05fa82905f7188651b, and then UsualSP.startRewardDistribution
is called again in https://etherscan.io/tx/0x117679127b297c0afbe033d7fb564d1b1961edac3f5dd80f986d1befca830178, and then UsualSP.stakeUsualS
is called in tx https://etherscan.io/tx/0x7cdb5ce4ba96f446292c97d93ba61eb0aeef86a9fa9c6ceda779ec4fc2328303.
Impact
According to https://app.blocksec.com/explorer/tx/eth/0x26ce95f3b7a9fd0ceb0e32ffd7c6e7a83278edb9fd1096cc4c2408f4fc463d9e and https://app.blocksec.com/explorer/tx/eth/0x117679127b297c0afbe033d7fb564d1b1961edac3f5dd80f986d1befca830178, there will be (603890260786742293065600 + 640072478128131577209600) usual been transferred to UsualSP contract
, and according to https://coinmarketcap.com/currencies/usual/, usual's highest price is $1.64, which means there will be (603890260786742293065600 + 640072478128131577209600) *1.64 / 1e18 = 2040098.8918203933 $ stuck UsualSP contract
PoC
As the third UsualSP.startRewardDistribution
is called in https://etherscan.io/tx/0x3ce4db9b3f00fb63d334ef68f463a5342b65152782778da6abd6446550b2af78 in block 21281033
, if we query $.rewardPerTokenStored(whose storage location is 0xece341a81e9ef81761e1d1d3338155bec39de2969454f2b1605e36884716e506)
- before the third startRewardDistribution
>>cast storage -r https://rpc.ankr.com/eth 0xa55AF35E5F4bb6A82E0A290570BcE38Ce2757d37 0xece341a81e9ef81761e1d1d3338155bec39de2969454f2b1605e36884716e506 -b 21281032
0x0000000000000000000000000000000000000000000000000000000000000000
- after the thirs
startRewardDistribution
>>cast storage -r https://rpc.ankr.com/eth 0xa55AF35E5F4bb6A82E0A290570BcE38Ce2757d37 0xece341a81e9ef81761e1d1d3338155bec39de2969454f2b1605e36884716e506 -b 21281034
0x000000000000000000000000000000000000000000000060626ab0b0803049e0
No response
Mitigation
No response