Core Contracts

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

Gauge rewards rate can be manipulated

Summary

Gauge rewards can be manipulated. Users may lose some expected rewards.

Vulnerability Details

In GaugeController, we will distribute rewards to gauges according to different gauges' weight. We will calculate the rewardRate via amount / periodDuration.

The problem here is that anyone can trigger distributeRewards() function at any time. Then malicious users can stake into other gauges to decrease the target gauge's weight ratio after we distribute the reward to the target gauge. After that, malicious users can trigger distributeRewards again to update the target gauge's reward rate. The reward rate will be manipulated to be one lower value than expected.

For example:

  1. There are two RAAC gauges, gauge A and gauge B. Assume these two gauges' weight ratio is 50%, 50%.

  2. The owner transfers 250000 * 10**18/2 for gauge A and gauge B and trigger distributeRewards(). After this, gauge stakers start to earn some rewards based on the reward rate.

  3. The malicious users can vote for gauge A to increase gauge A's weight ratio and trigger distributeRewards for gaugeB. Now gaugeB has one less weight ratio, we will get one smaller rewardRate compared with rewardRate from step 2. Then stakers in gauge B will lose some reward tokens.

function distributeRewards(
address gauge
) external override nonReentrant whenNotPaused {
if (!isGauge(gauge)) revert GaugeNotFound();
if (!gauges[gauge].isActive) revert GaugeNotActive();
uint256 reward = _calculateReward(gauge);
IGauge(gauge).notifyRewardAmount(reward);
}
function notifyRewardAmount(uint256 amount) external override onlyController updateReward(address(0)) {
if (amount > periodState.emission) revert RewardCapExceeded();
rewardRate = notifyReward(periodState, amount, periodState.emission, getPeriodDuration());
periodState.distributed += amount;
uint256 balance = rewardToken.balanceOf(address(this));
if (rewardRate * getPeriodDuration() > balance) {
revert InsufficientRewardBalance();
}
lastUpdateTime = block.timestamp;
emit RewardNotified(amount);
}

Impact

Gauge's rewardRate can be manipulated. This will cause that gauge stakers will lose some expected rewards.

Tools Used

Manual

Recommendations

Add some access control for function notifyRewardAmount. Only the admin role can trigger this function.

Updates

Lead Judging Commences

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

GaugeController's distributeRewards lacks time-tracking, allowing attackers to repeatedly distribute full period rewards until hitting emission caps

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

GaugeController's distributeRewards lacks time-tracking, allowing attackers to repeatedly distribute full period rewards until hitting emission caps

Support

FAQs

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