Core Contracts

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

BaseGauge will distribute incorrect rewards due to decimal mismatch

Summary

The decimal mismatch in BaseGauge.sol will cause incorrect reward distributions for users as the boost calculation uses basis points (10000) instead of the expected 1e18 precision.

Root Cause

In BaseGauge.sol and BoostCalculator.sol, there is a decimal mismatch between the boost calculation and its application:

  1. getUserWeight() works with 18 decimals from the voting power

  2. calculateBoost() returns boost in basis points (10000)

  3. The final calculation in _applyBoost() incorrectly divides by 1e18 instead of the boost precision

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

Impact

Users receive significantly fewer rewards than intended due to the decimal mismatch in the boost calculation. The impact is proportional to the boost amount and affects all users claiming rewards.

PoC

The issue occurs in these steps:

  1. getUserWeight() gets the base weight with 18 decimals

  2. calculateBoost() returns a value in basis points (10000)

  3. _applyBoost() incorrectly divides by 1e18 instead of the boost's precision

  4. This results in much smaller rewards being distributed than intended

Mitigation

Modify _applyBoost() to use the correct precision divisor:

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;
+ return (baseWeight * boost) / WEIGHT_PRECISION;
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 7 months 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.

Give us feedback!