Core Contracts

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

Underflow Bug in Boost Calculation (BaseGauge.sol)

Summary

An underflow bug exists in BoostCalculator.calculateBoost(), which is caused by the incorrect initialization of boostState.minBoost = 1e18 in BaseGauge.sol. When executing:

BoostCalculator.sol#L89

uint256 boostRange = params.maxBoost - params.minBoost;

this results in an underflow since params.minBoost (1e18) is significantly larger than params.maxBoost (25000). This will cause the contract to revert, breaking all reward distribution calculations and making the contract completely unusable until the issue is fixed by the admin via setBoostParameters().

Vulnerability Details

Here's the root cause due to the incorrect minBoost initialization:

BaseGauge.sol#L140-L142

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

It should have been initialized as 1000 but instead a way inflated 1e18 so much bigger than that of maxBoost.

Apparently, all functions, i.e. stake(), withdraw(), getreward(), and voteDirection() with the modifier updateReward(msg.sender) visibility are going to revert readily.

This is because when earned() is triggered to calculate earned rewards for the user's account:

BaseGauge.sol#L583-L587

function earned(address account) public view returns (uint256) {
return (getUserWeight(account) *
(getRewardPerToken() - userStates[account].rewardPerTokenPaid) / 1e18
) + userStates[account].rewards;
}

getUserWeight() gets invoked:

BaseGauge.sol#L594-L597

function getUserWeight(address account) public view virtual returns (uint256) {
uint256 baseWeight = _getBaseWeight(account);
return _applyBoost(account, baseWeight);
}

After getting the baseweight via _getBaseWeight, _applyBoost() is called next:

BaseGauge.sol#L229-L253

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

As can be seen from the logic above, minBoost will be assigned 1e18 serving as part of the params inputted as the third parameter in BoostCalculator.calculateBoost():

BoostCalculator.sol#L76-L101

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

Clearly, boostRange = params.maxBoost - params.minBoost is going to revert because 25000 - 1e18 is going to incur an underflow.

Impact

Boost calculations will readily fail causing DoS to all functions with updateReward visibility.

Tools Used

Recommendations

Consider making the following fix:

BaseGauge.sol#L142

- 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.