Core Contracts

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

DoS in reward-based functions due to underflow in reward calculation

Summary

The boostState.minBoost is set to an excessively high value (1e18), which leads to an underflow during boost calculations, causing the calculation to revert. As such, all reward-based functions are rendered unusable.

Vulnerability Details

In the constructor() of the BaseGauge contract, the following lines initialize the boost parameters:

// Initialize boost parameters
boostState.maxBoost = 25000; // 2.5x
>> boostState.minBoost = 1e18; // @audit Incorrectly initialized

Now, in _applyBoost() function which applies boost multiplier to base weight, the following exist:

// Create BoostParameters struct from boostState
BoostCalculator.BoostParameters memory params = BoostCalculator.BoostParameters({
maxBoost: boostState.maxBoost,
// @audit-info minBoost field set to the above initialized boostState.minBoost
>> minBoost: boostState.minBoost,
boostWindow: boostState.boostWindow,
totalWeight: boostState.totalWeight,
totalVotingPower: boostState.totalVotingPower,
votingPower: boostState.votingPower
});
uint256 boost = BoostCalculator.calculateBoost(
veBalance,
totalVeSupply,
// @audit-info Above created params are passed for calculation
>> params
);

The above called calculateBoost() function from the BoostCalculator library performs the following calculation:

// Calculate boost within min-max range
>> uint256 boostRange = params.maxBoost - params.minBoost; // @audit-issue Underflow

This subtraction will yield a negative value, leading to an underflow error, which will cause the transaction to revert.

Issue Rationale:

The earned() function is used to update the state.rewards for a particular user during rewards update.

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

It invokes getUserWeight() to get the user's current weight including boost:

function getUserWeight(address account) public view virtual returns (uint256) {
uint256 baseWeight = _getBaseWeight(account);
// @audit-issue Revert due to underflow
>> return _applyBoost(account, baseWeight);
}

Since this function relies on the _applyBoost(), the whole rewards update will revert.

Impact

DoS in reward based functions:

The updateReward() modifier is responsible for updating rewards for a user before executing some functions. This is used in stake(), withdraw() and getReward().

As such, since this modifier propagates down to the _applyBoost() which has the underflow issue, these functions will always revert during execution preventing users from accessing them.

Tools Used

Manual Review

Recommendations

Update the initialization value for boostState.minBoost as follows:

// Initialize boost parameters
boostState.maxBoost = 25000; // 2.5x
- boostState.minBoost = 1e18;
+ boostState.minBoost = 1e4; // 1x
Updates

Lead Judging Commences

inallhonesty Lead Judge about 1 month 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.