The BaseGauge contract updates the global timestamp (lastUpdateTime) using lastTimeRewardApplicable()
, which caps the time at periodFinish()
if the reward period has ended. However, when updating an individual user’s reward state in _updateReward
, the contract sets the user’s lastUpdateTime
directly to block.timestamp
. Under active reward periods this is equivalent, but after the period ends (when block.timestamp
> periodFinish()
), this inconsistency can lead to a slight over-calculation of rewards for that user.
What Happens:
The function getRewardPerToken()
calculates accrued rewards based on the difference between lastTimeRewardApplicable()
and lastUpdateTime.
In _updateReward
, the global lastUpdateTime is updated to lastTimeRewardApplicable(), ensuring that reward accrual does not count time beyond the reward period.
However, for per-user updates, state.lastUpdateTime is set to block.timestamp rather than the effective value from lastTimeRewardApplicable().
Why This Is Problematic:
Under normal conditions (when block.timestamp < periodFinish()
), both block.timestamp and lastTimeRewardApplicable() are equal.
Once the reward period ends (block.timestamp > periodFinish()
), lastTimeRewardApplicable() returns periodFinish(), while block.timestamp remains higher.
This causes the user’s recorded lastUpdateTime to be higher than the global lastUpdateTime, leading to a small discrepancy when calculating the rewards earned since the last update.
Given that the reward accrual formulas depend on a consistent timestamp for both global and per-user state, this inconsistency may result in either an over- or under-calculation of rewards for users immediately after the reward period ends.
Users may receive slightly more or less reward than intended if their lastUpdateTime is based on block.timestamp instead of the capped periodFinish() value once the reward period has ended.
Manual review
Modify the _updateReward function so that the user’s state.lastUpdateTime is set to lastTimeRewardApplicable() rather than block.timestamp.
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.