Core Contracts

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

Boost Mechanism In `BaseGauge::_applyBoost` Rendered Ineffective Due to Incorrect Scaling

Summary

The final boost calculation in BaseGauge::_applyBoost return statement incorrectly divides by 1e18 when working with BPS values, effectively zeroing out any boost applied to users' weights.

Vulnerability Details

[](https://github.com/Cyfrin/2025-02-raac/blob/89ccb062e2b175374d40d824263a4c0b601bcb7f/contracts/core/governance/gauges/BaseGauge.sol#L252)

In BaseGauge._applyBoost, the final calculation in the return statement divides by 1e18 when both input values are in BPS format (10_000 = 100%):

function _applyBoost(address account, uint256 baseWeight) internal view virtual returns (uint256) {
// ... boost calculation logic ...
uint256 boost = BoostCalculator.calculateBoost(
veBalance,
totalVeSupply,
params
);
// @audit - Both inputs are in BPS but divided by 1e18
@> return (baseWeight * boost) / 1e18; // This zeroes out the result
}

BoostCalculator::calculateBoost ecompares boost against minBoost and maxBoost which are BPS

[](https://github.com/Cyfrin/2025-02-raac/blob/89ccb062e2b175374d40d824263a4c0b601bcb7f/contracts/libraries/governance/BoostCalculator.sol#L92-L98)

function calculateBoost(
uint256 veBalance,
uint256 totalVeSupply,
BoostParameters memory params
) internal pure returns (uint256) {
....
// Ensure boost is within bounds
if (boost < params.minBoost) {
return params.minBoost;
}
if (boost > params.maxBoost) {
return params.maxBoost;
}
return boost;
}

Example:

Example with real values:
minBoost = 10000 (1x in BPS)
maxBoost = 25000 (2.5x in BPS)
baseWeight = 5000 (0.5 in BPS)
// User has 50% of total veToken supply
veBalance = 500e18
totalVeSupply = 1000e18
// calculateBoost returns 17500 (1.75x in BPS)
boost = 17500
// Final calculation in _applyBoost
finalWeight = (baseWeight * boost) / 1e18
= (5000 * 17500) / 1e18
= 87500000 / 1000000000000000000
= 0 // Should be (5000 * 17500) / 10000 = 8750
Result: Users get 0 weight instead of 8750 (proper boosted weight)

Impact

  • All user boost calculations effectively return 0 or a tiny fraction of what they should be

  • Users receive significantly reduced rewards compared to what they should get based on their veToken balance

  • The entire boost mechanism, which is core to the gauge system's incentive structure, is rendered ineffective

Tools Used

Foundry

Recommendations

Replace the 1e18 division in the return statement with BPS division:

function _applyBoost(address account, uint256 baseWeight) internal view virtual returns (uint256) {
// ... boost calculation logic ...
- return (baseWeight * boost) / 1e18;
+ return (baseWeight * boost) / 10_000; // Use BPS division
}
Updates

Lead Judging Commences

inallhonesty Lead Judge about 1 month ago
Submission Judgement Published
Validated
Assigned finding tags:

BaseGauge reward calculations divide by 1e18 despite using 1e4 precision weights, causing all user weights to round down to zero and preventing reward distribution

Support

FAQs

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