Lines of code
<https://github.com/code-423n4/2023-03-neotokyo/blob/dfa5887062e47e2d0c801ef33062d44c09f6f36e/contracts/staking/NeoTokyoStaker.sol#L1409>
<https://github.com/code-423n4/2023-03-neotokyo/blob/dfa5887062e47e2d0c801ef33062d44c09f6f36e/contracts/staking/NeoTokyoStaker.sol#L1264>
<https://github.com/code-423n4/2023-03-neotokyo/blob/dfa5887062e47e2d0c801ef33062d44c09f6f36e/contracts/staking/NeoTokyoStaker.sol#L1388-L1392>
The vulnerability relies in: <https://github.com/code-423n4/2023-03-neotokyo/blob/dfa5887062e47e2d0c801ef33062d44c09f6f36e/contracts/staking/NeoTokyoStaker.sol#L1388-L1392>
unchecked {
uint256 share = points * _PRECISION / pool.totalPoints * totalReward;
uint256 daoShare = share * pool.daoTax / (100 * _DIVISOR);
share /= _PRECISION;
daoShare /= _PRECISION;
return ((share - daoShare), daoShare);
}
The problem is that if the pool rewards are very high or/and you have staked you asset for a long time, the shares and daoShare will return 0, disabling you from claiming the staking rewards and it updates the rewards time, therefore losing the rewards: <https://github.com/code-423n4/2023-03-neotokyo/blob/dfa5887062e47e2d0c801ef33062d44c09f6f36e/contracts/staking/NeoTokyoStaker.sol#L1432-L1435>
lastRewardTime[_recipient][AssetType.S1_CITIZEN] = block.timestamp;
lastRewardTime[_recipient][AssetType.S2_CITIZEN] = block.timestamp;
lastRewardTime[_recipient][AssetType.LP] = block.timestamp;
So, if pools have lots of assets and you have been staking for a long time, you will lose all your staking reward. It is impossible to guess the exact amount because the only value that we know is _PRECISION, which is 1e12.
Steps to reproduce the attack:
Stake as much NFTs in the pool
Leave on of the NFTs for letβs say 100 days. You can do that with Foundry or HARDHAT
Letβs say that citizen1 is 100 points and there are 5_000 citizens 1 staked.
Calculation: share: 100 * 1e12 / (5_000 * 100) * 1e18 β> the following will return 0, and also daoshare = 0.
Reward times will be updated
lastRewardTime[_recipient][AssetType.S1_CITIZEN] = block.timestamp;
lastRewardTime[_recipient][AssetType.S2_CITIZEN] = block.timestamp;
lastRewardTime[_recipient][AssetType.LP] = block.timestamp;
Manual
Make a different calculation of the rewards of each pool or increase the _PRECISION param so that it does not return 0
The text was updated successfully, but these errors were encountered:
All reactions