Summary
Gauges does not interact when veRAACToken.totalSupply() > 0 && gaugeWeight > 0.
Vulnerability Details
BaseGauge.sol#constructor() function is as follows.
constructor(
address _rewardToken,
address _stakingToken,
address _controller,
uint256 _maxEmission,
uint256 _periodDuration
) {
...
@> boostState.maxBoost = 25000;
@> boostState.minBoost = 1e18;
boostState.boostWindow = 7 days;
...
}
As we can see above, maxBoost and minBoost have different decimals.
This is critical error.
This vulnerability causes revert in following code.
BoostCalculator.sol
function calculateBoost(
uint256 veBalance,
uint256 totalVeSupply,
BoostParameters memory params
) internal pure returns (uint256) {
if (totalVeSupply == 0) {
return params.minBoost;
}
uint256 votingPowerRatio = (veBalance * 1e18) / totalVeSupply;
89@> 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;
}
Here, L89 is always reverted by underflow.
So _updateReward() => earned() => getUserWeight() => _applyBoost() => calculateBoost() call is reverted.
Impact
Therefore, BaseGauge.sol#state(), withdraw() can be always reverted by updateReward modifier.
Tools Used
Manual review
Recommendations
Modify code so that maxBoost and minBoost have same decimals as follows.
constructor(
address _rewardToken,
address _stakingToken,
address _controller,
uint256 _maxEmission,
uint256 _periodDuration
) {
...
boostState.maxBoost = 25000;
-- boostState.minBoost = 1e18;
++ boostState.minBoost = 10000;
boostState.boostWindow = 7 days;
...
}