Core Contracts

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

_calculateReward return incorrect reward causing `distributeRewards` to always revert.

Rewards are meant to be distributed using distributeRewards to the guage.

function distributeRewards(
address gauge
) external override nonReentrant whenNotPaused {
if (!isGauge(gauge)) revert GaugeNotFound();
if (!gauges[gauge].isActive) revert GaugeNotActive();
@> uint256 reward = _calculateReward(gauge);
if (reward == 0) return;
IGauge(gauge).notifyRewardAmount(reward);
emit RewardDistributed(gauge, msg.sender, reward);
}

The issue is that _calculateReward returns an incorrect value for the rewards periodEmission resulting guage reverts with RewardCapExceeded.

function _calculateReward(address gauge) public 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;
// Calculate period emissions based on gauge type
uint256 periodEmission = g.gaugeType == GaugeType.RWA ? _calculateRWAEmission() : _calculateRAACEmission();
return (periodEmission * gaugeShare * typeShare) / (WEIGHT_PRECISION * WEIGHT_PRECISION);
}

Assuming we have two gauge (A and B), an a monthly emission rate

1_000_000e18 (_calculateRWAEmission)
typeWeight = 5000 => 50%
WEIGHT_PRECISION = 10000 => 100%
MAX_TYPE_WEIGHT = 10000 => 100%

For simplicity, both gauge A and B have g.weight = 5000 (50%)
Then, totalWeight = 10000 = 100%

gaugeShare = (5000 * 10000) / 10000 = 5000 (50%)
typeShare = 5000 (50%)

With periodEmission (monthly) = 1_000_000e18

calculateReward for gauge A = (1_000_000e18 * 5000 * 5000) / (10000 * 10000) = 250_000e18
calculateReward for gauge B = (1_000_000e18 * 5000 * 5000) / (10000 * 10000) = 250_000e18

Within a single distribution both guage A and gauge B would receive a reward of 250_000e18 each totaling 500_000e18 a single period, while the monthly distribution is 1_000_000e18.

Impact

Rewards would not be be distributed within periodEmission leading to reverts on gauge emission cap

Recommendation

The number of rewards to be shared to a guage should also factor the period duration of the emission.

Updates

Lead Judging Commences

inallhonesty Lead Judge 2 months ago
Submission Judgement Published
Invalidated
Reason: Design choice
inallhonesty Lead Judge 2 months ago
Submission Judgement Published
Invalidated
Reason: Design choice

Appeal created

kodyvim Submitter
2 months ago
inallhonesty Lead Judge
about 2 months ago
inallhonesty Lead Judge about 2 months ago
Submission Judgement Published
Validated
Assigned finding tags:

GaugeController::_calculateReward redundantly multiplies by typeShare causing reward reduction since periodEmission is already type-specific

Support

FAQs

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