Core Contracts

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

Incorrect `minBoost` value in `BaseGauge` blocks all reward distributions

Summary

The minBoost value in BaseGauge is incorrectly set to 1e18 instead of 10000, causing arithmetic overflow in _applyBoost() when calculating boost values. This blocks reward distribution as the getUserWeight() function, which is critical for reward calculations, reverts due to the overflow.

Vulnerability Details

In the BaseGauge constructor, minBoost is set to 1e18:

boostState.maxBoost = 25000; // 2.5x
boostState.minBoost = 1e18; // Incorrect value

This value is used in _applyBoost() which is called by getUserWeight() to calculate rewards. The large value causes arithmetic overflow when multiplying with the base weight, making reward distribution impossible.

function _applyBoost(address account, uint256 baseWeight) internal view virtual returns (uint256) {
if (baseWeight == 0) return 0;
IERC20 veToken = IERC20(IGaugeController(controller).veRAACToken());
uint256 veBalance = veToken.balanceOf(account);
uint256 totalVeSupply = veToken.totalSupply();
// Create BoostParameters struct from boostState
BoostCalculator.BoostParameters memory params = BoostCalculator.BoostParameters({
@> maxBoost: boostState.maxBoost,
@> minBoost: boostState.minBoost,
boostWindow: boostState.boostWindow,
totalWeight: boostState.totalWeight,
totalVotingPower: boostState.totalVotingPower,
votingPower: boostState.votingPower
});
@> uint256 boost = BoostCalculator.calculateBoost(
veBalance,
totalVeSupply,
params
);
return (baseWeight * boost) / 1e18;
}

Then in BoostCalculator.sol, the boost value is calculated as follows:

function calculateBoost(
uint256 veBalance,
uint256 totalVeSupply,
BoostParameters memory params
) internal pure returns (uint256) {
// Return base boost (1x = 10000 basis points) if no voting power
if (totalVeSupply == 0) {
return params.minBoost;
}
// Calculate voting power ratio with higher precision
uint256 votingPowerRatio = (veBalance * 1e18) / totalVeSupply;
// Calculate boost within min-max range
@> uint256 boostRange = params.maxBoost - params.minBoost; // This lines overflows
uint256 boost = params.minBoost + ((votingPowerRatio * boostRange) / 1e18);
// Ensure boost is within bounds
if (boost < params.minBoost) {
return params.minBoost;
}
if (boost > params.maxBoost) {
return params.maxBoost;
}
return boost;
}

The value should be 10000 (1x) like in the BoostController contract, as boost values are meant to be multipliers in basis points.

Impact

The contract is completely broken as users cannot receive rewards due to the arithmetic overflow in the boost calculation. This affects core functionality and leads to locked rewards that cannot be distributed.
Key points:

  • All reward distributions fail due to reverts in getUserWeight()

  • Users cannot claim earned rewards

  • Affects all gauge implementations inheriting from BaseGauge

Tools Used

Manual review

Proof of Concept

Add the following test case to the test/unit/core/governance/gauges/GaugeController.test.js file:

it("call revert due to overflow caused by incorrect minBoost value", async () => {
// reverted with panic code 0x11 (Arithmetic operation overflowed outside of an unchecked block)
// at RWAGauge.calculateBoost (contracts/libraries/governance/BoostCalculator.sol:89)
await expect(rwaGauge.earned(user1.address)).to.be.revertedWithPanic(0x11);
});

Recommendations

Change the minBoost value in the constructor to 10000:

- boostState.minBoost = 1e18;
+ boostState.minBoost = 10000;
Updates

Lead Judging Commences

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

boostState.minBoost is set to 1e18

Support

FAQs

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