A malicious user can flip the epoch before the rewardAdmin
calls the addReward()
function, causing users who cancel their stake in the current epoch to be unable to obtain the rewards corresponding to that epoch.
In the FjordStaking
contract, the rewardAdmin
adds rewards to the current epoch by calling the addReward()
function. The _checkEpochRollover()
function is responsible for updating the epoch number.
The rewardAdmin
calls the FjordStaking::addReward()
function, which transfers tokens first and then calls _checkEpochRollover()
to update rewardPerToken[i]
. However, if the epoch is rolled over in advance, the code within the if (latestEpoch > currentEpoch)
block will not be executed as expected.
Relevant Code Snippet:
The _checkEpochRollover()
function is called not only in addReward()
but is also used as a modifier (checkEpochRollover()
) in multiple functions callable by the user:
Due to this design, a malicious user can stake a small amount of tokens before the rewardAdmin
calls addReward()
, thereby triggering the epoch rollover prematurely. This behavior will cause the rewards added by addReward()
to enter the next epoch rather than the expected current epoch. As a result, users who cancel their stake in the current epoch will miss out on these rewards.
Please add the code to test/unit/unstake.t.sol
and execute it:
https://github.com/Cyfrin/2024-08-fjord/blob/0312fa9dca29fa7ed9fc432fdcd05545b736575d/src/FjordStaking.sol#L755-L768
https://github.com/Cyfrin/2024-08-fjord/blob/0312fa9dca29fa7ed9fc432fdcd05545b736575d/src/FjordStaking.sol#L691-L724
https://github.com/Cyfrin/2024-08-fjord/blob/0312fa9dca29fa7ed9fc432fdcd05545b736575d/src/FjordStaking.sol#L368-L391
https://github.com/Cyfrin/2024-08-fjord/blob/0312fa9dca29fa7ed9fc432fdcd05545b736575d/src/FjordStaking.sol#L315-L318
Malicious users can flip the epoch before the rewardAdmin
calls addReward()
, which causes users who cancel their stake in the current epoch to miss out on rewards they should have received, leading to incorrect reward distribution and financial losses for users.
Manual Review
Since the _checkEpochRollover()
function is only executed once per epoch rollover, consider running a trusted and reliable off-chain bot. This bot should call addReward()
to add rewards and trigger the epoch rollover as soon as the epoch meets the rollover criteria. Alternatively, you could add additional conditions to the _checkEpochRollover()
function to allow users to call it with a delay, ensuring that addReward()
is prioritized.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.