Rewards accrued during the period of _totalSupply = 0 will get lost forever.
Summary
During the period of _totalSupply = 0, rewards will continue to accrue but are not distributed to any staker, as a result, these rewards will get lost forever. Loss of funds for the protocol.
Given the 100% loss nature during this period, but the relative low probability of its occurence, I give a balanced ranking of medium.
Root Cause
During the period of _totalSupply = 0, rewards will continue to accrue but are not distributed to any staker.
rewardPerTokenStored remains the same. No distribution to stakers.
lastUpdateTime will be updated, means accrue happens. The remaining reward period periodFinish - lastUpdateTime will be shortened.
Some time passes while _supply = 0 when there is an ongoing rewardRate != 0.
Attack Path
Below our POC shows how the rewards might get lost:
Bob stakes 50000000 ether of staking tokens;
After 10512000 secs, 5000000000000 reward tokens are sent to the StakingRewards contract, initiating a reward stream of with a reward rate of 8267195.
After 1 day, Bob withdraws 50000000 ether of staking tokens and gets 714250000000 reward tokens.
After 356 days (an exaggeration but this is the period that rewards get lost), we call k.rewards.notifyRewardAmount(0) to start a new reward stream only using the remaining rewards in the StakingRewards, if any.
Although there is 4285750000000 reward tokens in the StakingRewards, they are stuck and not available for future dispense, as confirmed by rewardRate = 0. The following experiment further confirms future staking cannot get reward.
Bob stakes another 50000000 ether of staking tokens and wait for one day to withdraw them and get reward. This time, he gets 0 reward since rewardRate = 0. This further confirms that the remaining rewards (4285750000000) are all lost in the contract during that 356 days. They are lost forever and are not available for future dispense.
Impact
Rewards accrued during the period of _totalSupply = 0 will get lost forever. This is a loss for the protocol.
Introduce a new state variable called "remaining". When _supply = 0, accrued rewards should be added to remaining. Rewards accrued in remaining can be dispensed in another new stream.
chaduke
Medium
Rewards accrued during the period of _totalSupply = 0 will get lost forever.
Summary
During the period of
_totalSupply = 0
, rewards will continue to accrue but are not distributed to any staker, as a result, these rewards will get lost forever. Loss of funds for the protocol.Given the 100% loss nature during this period, but the relative low probability of its occurence, I give a balanced ranking of
medium
.Root Cause
During the period of
_totalSupply = 0
, rewards will continue to accrue but are not distributed to any staker.rewardPerTokenStored
remains the same. No distribution to stakers.lastUpdateTime
will be updated, means accrue happens. The remaining reward periodperiodFinish - lastUpdateTime
will be shortened.https://github.com/sherlock-audit/2024-06-makerdao-endgame/blob/main/endgame-toolkit/src/synthetix/StakingRewards.sol#L191-L199
Internal pre-conditions
_supply = 0.
External pre-conditions
Some time passes while _supply = 0 when there is an ongoing rewardRate != 0.
Attack Path
Below our POC shows how the rewards might get lost:
StakingRewards
contract, initiating a reward stream of with a reward rate of 8267195.k.rewards.notifyRewardAmount(0)
to start a new reward stream only using the remaining rewards in theStakingRewards
, if any.StakingRewards
, they are stuck and not available for future dispense, as confirmed byrewardRate = 0
. The following experiment further confirms future staking cannot get reward.rewardRate = 0
. This further confirms that the remaining rewards (4285750000000) are all lost in the contract during that 356 days. They are lost forever and are not available for future dispense.Impact
Rewards accrued during the period of _totalSupply = 0 will get lost forever. This is a loss for the protocol.
PoC
run
forge test --match-test testLostReward1 -vv
.Mitigation
Introduce a new state variable called "remaining". When
_supply = 0
, accrued rewards should be added toremaining
. Rewards accrued inremaining
can be dispensed in another new stream.