Core Contracts

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

Front-running and Manipulation Vulnerabilities in GaugeController::_distributeToGauges Leading to Reward Distribution Exploitation

Summary

The GaugeController::_distributeToGauges function is vulnerable to front-running and manipulation attacks due to its two-pass distribution mechanism and lack of slippage protection, allowing attackers to extract excess rewards.

Vulnerability Details

function _distributeToGauges(GaugeType gaugeType, uint256 amount) internal {
uint256 totalTypeWeight = 0;
uint256[] memory gaugeWeights = new uint256[](_gaugeList.length);
uint256 activeGaugeCount = 0;
for (uint256 i = 0; i < _gaugeList.length; i++) {
address gauge = _gaugeList[i];
if (gauges[gauge].isActive && gauges[gauge].gaugeType == gaugeType) {
gaugeWeights[i] = gauges[gauge].weight;
totalTypeWeight += gaugeWeights[i];
activeGaugeCount++;
}
}
if (totalTypeWeight == 0 || activeGaugeCount == 0) return;
for (uint256 i = 0; i < _gaugeList.length; i++) {
address gauge = _gaugeList[i];
if (gauges[gauge].isActive && gauges[gauge].gaugeType == gaugeType) {
uint256 gaugeShare = (amount * gaugeWeights[i]) / totalTypeWeight;
IGauge(gauge).notifyRewardAmount(gaugeShare);
}
}
}

The key vulnerabilities are:

  1. Weight calculations and distributions occur in separate loops, allowing state changes between them

  2. No minimum reward amount validation

  3. No checks for gauge weight manipulation between loops

  4. External calls to gauges can lead to reentrancy

PoC

it("should allow reward manipulation through weight changes", async function() {
await gaugeController.connect(admin).addGauge(gauge1.address, GaugeType.RAAC, 100);
await gaugeController.connect(admin).addGauge(gauge2.address, GaugeType.RAAC, 100);
await gaugeController.vote(attacker, gauge1.address, 100);
await gauge1.setWeight(1000);
await gaugeController.distributeRevenue(GaugeType.RAAC, ethers.parseEther("1000"));
await gauge1.setWeight(0);
const gauge1Rewards = await rewardToken.balanceOf(gauge1.address);
expect(gauge1Rewards).to.be.gt(ethers.parseEther("500"));
});

Impact

  • Malicious actors can manipulate reward distribution

  • Unfair reward allocation between gauges

  • Potential reward theft through front-running

  • System instability through weight manipulation

Tools Used

  • Manual code review

  • Hardhat for testing

  • Tenderly for transaction simulation

Recommendations

  1. Implement an atomic reward distribution process

  2. Add minimum and maximum weight change limits

  3. Implement distribution checkpoints to prevent manipulation

  4. Add slippage protection for reward calculations

function _distributeToGauges(GaugeType gaugeType, uint256 amount) internal {
bytes32 distributionHash = _createDistributionSnapshot();
for (uint256 i = 0; i < _gaugeList.length; i++) {
if (_validateGaugeDistribution(gaugeList[i], distributionHash)) {
_distributeReward(gaugeList[i], distributionHash);
}
}
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 3 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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