Core Contracts

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

Inconsistent Emission Rate Configuration Between Gauges and Controller

Summary

Inconsistency in how emission rates are configured and calculated between the Gauges and GaugeController contracts. In this report I'll refer to the RAACGauge but the same issue also effects the RWACGauge.

The RAACGauge uses a maximum weekly emission of 500,000 tokens, while the GaugeController hardcodes a different value of 250,000 tokens for RAAC emissions. The emission in the Gauge itself can be changed via setWeeklyEmission() or setEmission()so it allows dynamic values.

This mismatch can lead to reward calculation errors, failed distributions, and unexpected behavior in the reward system. Because the RAACGaugeuses the emission from the periodState and not the hardcoded value from the GaugeController.

Vulnerability Details

Emission for Gauges is hardcoded in GaugeController:

function _calculateRWAEmission() internal view returns (uint256) {
// Monthly RWA emission calculation
// This should be implemented based on your tokenomics
return 1_000_000 * 10 ** 18; // Example value
}
function _calculateRAACEmission() internal view returns (uint256) {
// Weekly RAAC emission calculation
// This should be implemented based on your tokenomics
return 250_000 * 10 ** 18; // Example value
}

Reward Calculations in GaugeController are based on hardcoded values:

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;
//Reward amount gets passed to Gauge
IGauge(gauge).notifyRewardAmount(reward);
emit RewardDistributed(gauge, msg.sender, reward);
}
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;
// Uses hardcoded value for calculation
@> uint256 periodEmission = g.gaugeType == GaugeType.RWA ? _calculateRWAEmission() : _calculateRAACEmission();
return (periodEmission * gaugeShare * typeShare) / (WEIGHT_PRECISION * WEIGHT_PRECISION);
}

Impact

  • Reward Distribution Failures:

    • GaugeController calculates rewards based on 250K weekly tokens

    • RAACGauge validates against 500K weekly tokens

    • This can lead to transactions reverting due to RewardCapExceeded error

  • Incorrect Reward Calculations:

    • Users may receive different rewards than intended

    • System may distribute fewer tokens than designed

  • No way to keep the values in sync because of hardcoded values

Tools Used

  • Manual Review

  • Foundry

Recommendations

The GaugeController should use the value from the Gauges for it's calculations.

Updates

Lead Judging Commences

inallhonesty Lead Judge 6 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Appeal created

inallhonesty Lead Judge 5 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

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