Skip to content

Latest commit

 

History

History
31 lines (21 loc) · 2.52 KB

006.md

File metadata and controls

31 lines (21 loc) · 2.52 KB

Ancient Denim Horse

Medium

GovernanceStaker.sol - initial reward period will not distribute all rewards

Summary

As the staking contract strongly inherits the mechanism of Synthetix, it also contains it's bug where a portion of the rewards from the initial period remain undistributed until a new cycle is started. This bug will occur not just on the initial period, but on every instance of a fresh reward period where the earning power starts from 0, possibly from user withdraws or users moving to a delegatee that is yet to become eligible.

Vulnerability Detail

Let's consider that the contract starts off fresh, it notifies the very first rewards and therefore has no deposits yet so the totalEarningPower is 0 and the checkpoint is at the current timestamp X. We have our first depositor some time after the notification of rewards at timestamp Y, which tries to update the global index but since all of the values are fresh, there are 0 rewards accumulated. The period finishes and the user withdraws and claims his funds. rewardPerTokenAccumulated() will calculate the reward as the rate * (period_end - Y) / totalEarningPower and _checkpointReward() will use that reward per token to calculate our reward against our earning power. However as the reward is only updated for the period of (end - Y), this means that the rewards allocated for the time (Y - X) do not get distributed. This is a bug that will definitely occur on the initial period and every time that the earning power is reset to 0 which can be a result of both withdrawals between periods and changing of delegatees to ones that are yet to be eligible.

Those rewards will not get transferred over to the next period as remainingRewards, since the contract logic thinks they have been distributed, they will sit inside the contract balance, since only verified contracts can notify rewards and they cannot notify new rewards without doing a transfer.

Impact

Rewards need to be re-notified or otherwise get left undistributed inside of the contract.

Code Snippet

https://github.com/sherlock-audit/2024-11-tally/blob/main/staker/src/GovernanceStaker.sol#L430-L461 https://github.com/sherlock-audit/2024-11-tally/blob/main/staker/src/GovernanceStaker.sol#L303-L308

Tool used

Manual Review

Recommendation

As the following Synthetix write-up recommends https://0xmacro.com/blog/synthetix-staking-rewards-issue-inefficient-reward-distribution/ - consider defining rewardEndTime in the first stake() that is done after notifyRewardAmount(), when total earning power is 0.