Core Contracts

Regnum Aurum Acquisition Corp
HardhatReal World AssetsNFT
77,280 USDC
View results
Submission Details
Severity: medium
Valid

Gauge emissions revert when emissions are higher than the leftover buffer instead of depositing the difference

Summary

Gauge reward distribution will fail instead of filling the buffer, despite the gauge being eligible for the buffer

Details

Whenever distributeRewards is called in GaugeController.sol, fixed emissions are split across all active gauges, according to their weight

function _calculateReward(address gauge) internal view returns (uint256) {
Gauge storage g = gauges[gauge];
uint256 totalWeight = getTotalWeight();
if (totalWeight == 0) return 0;
uint256 gaugeShare = (g.weight * WEIGHT_PRECISION) / totalWeight;
uint256 typeShare = (typeWeights[g.gaugeType] * WEIGHT_PRECISION) / MAX_TYPE_WEIGHT;
uint256 periodEmission = g.gaugeType == GaugeType.RWA ? _calculateRWAEmission() : _calculateRAACEmission();
return (periodEmission * gaugeShare * typeShare) / (WEIGHT_PRECISION * WEIGHT_PRECISION);
}

Afterwards, the gauge receives it's rewards through notifyRewardAmount. During the execution, the amount being supplied is checked whether it surpasses the state max emission

if (amount > maxEmission) revert RewardCapExceeded();
@> if (amount + state.distributed > state.emission) {
revert RewardCapExceeded();
}

This is incorrect since amount is an arbitrary number which fluctuates constantly based on gauges' weights. There is no guarantee that all notifyRewardAmount calls will always sum up perfectly.
An example:

  1. Gauge has state.emission = 2000, state.distributed = 1500, all previous emissions supplied in 500 token increments

  2. Gauge's weight increases (due to user voting) and is now eligible for rewards = 550

  3. distributeRewards is called, 550 tokens are attempted to be sent to the gauge, yet it reverts in the snippet above since 550 + 1500 > 2000

Gauges will hardly ever hit their max emissions, despite being eligible to do so. These rewards are lost for the gauge voters and stakers.

Impact

Loss of rewards, logic error

Mitigation

Instead of reverting, fill the buffer

Updates

Lead Judging Commences

inallhonesty Lead Judge 7 months ago
Submission Judgement Published
Validated
Assigned finding tags:

BaseGauge::notifyReward reverts when calculated rewards exceed emission cap remainder instead of accepting partial rewards up to the cap limit

inallhonesty Lead Judge 7 months ago
Submission Judgement Published
Validated
Assigned finding tags:

BaseGauge::notifyReward reverts when calculated rewards exceed emission cap remainder instead of accepting partial rewards up to the cap limit

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.

Give us feedback!