Core Contracts

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

notifyRewardAmount may always revert if the rewardAmount is greater than periodState.emission

Summary and Vulnerability Details

The amountin the notifyRewardAmount function in the BaseGuage.sol comes from the calculation in the GuageController.sol. In the guageController it can be seen that this depends on the weight ratio of that specific guage that determines how much reward it deserves. Now, if this weight ratio is high enough to cause the amount > periodState.emission in the BaseGuage, the rewards will never reach the guage. This will force the users to reduce the weight ratio of that guage: which essentially means that the users are forced to burn/withdraw their veRAAC tokens (to reduce their power and vote again in the GuageController to reduce the weight). This is unintended and can take a long time since the veRAAC tokens are essentially locked for a certain duration.

Vulnerability Details

As mentioned above, the issue arises when the calculated amount in the GuageController exceeds the periodState.emission in the BaseGuage.sol. This allows malicious users to vote for a guage and increase its weight, thus causing the rewards to not be able to come for the guage. This will grief the users.

In the BaseGuage.sol it can be seen that if amount > periodState.emission it will revert.

function notifyRewardAmount(uint256 amount) external override onlyController updateReward(address(0)) {
if (amount > periodState.emission) revert RewardCapExceeded();

In the guageController.sol it can be seen that the rewards are calculated according to the weightRatio of the guage

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);
}

Further to reduce the weight ratio of the guage, the only way is to reduce their votingpower (burn/ withdraw veRAAC token).

function _updateGaugeWeight(
address gauge,
uint256 oldWeight,
uint256 newWeight,
uint256 votingPower
) internal {
Gauge storage g = gauges[gauge];
uint256 oldGaugeWeight = g.weight;
uint256 newGaugeWeight = oldGaugeWeight - (oldWeight * votingPower / WEIGHT_PRECISION)
+ (newWeight * votingPower / WEIGHT_PRECISION);
g.weight = newGaugeWeight;
g.lastUpdateTime = block.timestamp;
}


Note that the max amount is > periodState.emission of the respective RWA and RAAC guages so this attack is possible

Note: this issue is present in the notifyReward function too in the Baseguage.sol

Impact

dos the reward addition into the guage.


Tools Used

manual review

Recommendations

if the amount > periodState.emission cap it to periodState.emission

Updates

Lead Judging Commences

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

BaseGauge::notifyRewardAmount reverts when calculated reward exceeds emission cap, preventing popular gauges from receiving any rewards

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

BaseGauge::notifyRewardAmount reverts when calculated reward exceeds emission cap, preventing popular gauges from receiving any rewards

Support

FAQs

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

Give us feedback!