The system has two mechanisms for distributing rewards to gauges:
GaugeController#distributeRewards - Distributes rewards based on gauge weights (callable by anyone)
GaugeController#distributeRevenue - Distributes revenue between veToken holders and gauges (callable by emergency admin)
Both mechanisms ultimately call BaseGauge#notifyRewardAmount to update reward rates.
The GaugeController#distributeRevenue function can override the current reward emission rate set by GaugeController#distributeRewards in the gauge. This occurs because both functions use BaseGauge#notifyRewardAmount to update the reward rate, but do not coordinate their timing or amounts.
When notifyRewardAmount is called, it completely overwrites the previous rewardRate with a new calculation based on the latest amount:
This means if distributeRevenue is called shortly after distributeRewards, the second call will override the reward rate from the first call, potentially leading to incorrect reward distributions. The issue is particularly severe because distributeRewards can be called by any address.
High. Since distributeRewards can be called by any address, this creates a potential denial of service vector where malicious actors could repeatedly override legitimate reward distributions. This could lead to significant disruption of the reward distribution mechanism.
High. Given that distributeRewards is publicly callable and distributeRevenue is a core protocol function, the likelihood of reward rate overrides is high, whether malicious or accidental.
Time t=0: Admin calls distributeRewards(gaugeA) with 1000 tokens
gaugeA.rewardRate is set to 1000/period
Time t=1: Emergency admin calls distributeRevenue(gaugeType, 2000)
For gaugeA, notifyRewardAmount is called with its share of the revenue
gaugeA.rewardRate is overwritten with new rate based only on the revenue share
The original reward rate from distributeRewards is lost, and users will earn rewards only based on the revenue distribution
Alternatively, a malicious actor could:
Monitor for distributeRevenue transactions in the mempool
Front-run with a call to distributeRewards
Cause the revenue distribution to fail or result in incorrect reward rates
Implement reward rate accumulation instead of overwriting in BaseGauge#notifyRewardAmount
Add an admin function to reset reward rates when needed
Also consider adding access control to distributeRewards or implementing rate limiting mechanisms to prevent abuse.
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.