Summary
The constructor initializes boostState.minBoost
with a value of 1e18, but it should be set to **1000 or any other value in basis point **to be consistent with the expected precision used in the boost calculation logic. The calculateBoost
function computes the boost range as:
uint256 boostRange = params.maxBoost - params.minBoost;
Since maxBoost
is initialized as 2500 and minBoost
is mistakenly set as 1e18, boostRange
becomes negative (mathematically), but since uint256 cannot hold negative values, the subtraction will underflow and cause the function to revert.
Vulnerability Details
constructor(
address _rewardToken,
address _stakingToken,
address _controller,
uint256 _maxEmission,
uint256 _periodDuration
) {
rewardToken = IERC20(_rewardToken);
stakingToken = IERC20(_stakingToken);
controller = _controller;
_grantRole(DEFAULT_ADMIN_ROLE, msg.sender);
_grantRole(CONTROLLER_ROLE, _controller);
@> boostState.maxBoost = 25000;
@> boostState.minBoost = 1e18;
boostState.boostWindow = 7 days;
uint256 currentTime = block.timestamp;
uint256 nextPeriod = ((currentTime / _periodDuration) * _periodDuration) + _periodDuration;
periodState.periodStartTime = nextPeriod;
periodState.emission = _maxEmission;
TimeWeightedAverage.createPeriod(
periodState.votingPeriod,
nextPeriod,
_periodDuration,
0,
10000
);
}
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();
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;
}
function calculateBoost(
uint256 veBalance,
uint256 totalVeSupply,
BoostParameters memory params
) internal pure returns (uint256) {
if (totalVeSupply == 0) {
return params.minBoost;
}
uint256 votingPowerRatio = (veBalance * 1e18) / totalVeSupply;
@> uint256 boostRange = params.maxBoost - params.minBoost;
uint256 boost = params.minBoost + ((votingPowerRatio * boostRange) / 1e18);
if (boost < params.minBoost) {
return params.minBoost;
}
if (boost > params.maxBoost) {
return params.maxBoost;
}
return boost;
}
Wrong initialization of boostState.minBoost
in the contructor, this will lead to an overflow when the applyBoost()
calls the calculateBoost function.
This will affect any function that calls the _applyBoost, the updateReward is affected, and any function that uses the upatedReward modifier will revert when called.
Impact
Any function that calls _applyBoost()
will revert due to an underflow error in calculateBoost()
.
Users will not receive correct boost calculations, affecting voting weight or rewards.
Tools Used
Manual Review
Recommendations
Modify the constructor to correctly initialize boostState.minBoost
with the precision in basis point: