Core Contracts

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

Emissions are distributed incorrectly.

Bug description

When distributing rewards to a gauge, _calculateReward function is used to determine the amount to distribute.

GaugeController.sol#L360-L372

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

The important thing to note is the way period emission is assigned.

uint256 periodEmission = g.gaugeType == GaugeType.RWA
? _calculateRWAEmission()
: _calculateRAACEmission();

As we can see, it depends on the gauge type, since the period emission is already chosen based on the gauge type, the gauge’s reward should be calculated by its share relative to the total weight within its own gauge type. However, that's not the case, as in the following line, the gauge share is determined based on its share compared to total weights of ALL gauges no matter the type.

uint256 gaugeShare = (g.weight * WEIGHT_PRECISION) / totalWeight;

Next, the function determines the typeShare that will be used to calculate rewards. This is redundant because the period emission already reflects the emission amount allocated for that gauge type. The intended behavior should be that if, for instance, RWA gauges receive 500 tokens in total, then each RWA gauge should receive an amount proportional to its weight relative to the total RWA gauges weight. Instead, the current logic calculates it as:

500 * (g.weight / totalWeight) * (typeShare / MAX_TYPE_WEIGHT)

This will dilute rewards for a gauge, as the weight used to calculate its share includes all gauges. Additionally, the rewards will be diluted further by multiplying by typeShare, which serves a purpose of splitting rewards between gauge types, while rewards are already split by assigning an emission for a particular gauge type.

Impact

Dilution of rewards for a gauge.

Recommended Mitigation

Calculate gaugeShare using total weights of all gauges withing its type, instead of totalWeight of all gauges. Remove the type share from calculations as emissions are already split between each gauge type.

Updates

Lead Judging Commences

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

GaugeController::_calculateReward uses combined weight of all gauge types instead of type-specific weights, causing incorrect reward distribution between RWA and RAAC gauges

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

GaugeController::_calculateReward uses combined weight of all gauge types instead of type-specific weights, causing incorrect reward distribution between RWA and RAAC gauges

Support

FAQs

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

Give us feedback!