Summary
In BoostController.sol
, the _calculateBoost
function uses a hardcoded base amount of 10000, leading to incorrect boost scaling. This results in improper reward distribution as boosts aren't calculated based on the actual staked amount.
Vulnerability Details
The problem in _calculateBoost
is: BoostController.sol#_calculateBoost
function _calculateBoost(
address user,
address pool,
uint256 amount
) internal view returns (uint256) {
(uint256 totalWeight, uint256 totalVotingPower, uint256 votingPower) = updateTotalWeight();
uint256 userBalance = IERC20(address(veToken)).balanceOf(user);
uint256 totalSupply = IERC20(address(veToken)).totalSupply();
Impact
uint256 userBalance = IERC20(address(veToken)).balanceOf(user);
Should use veToken.getVotingPower(user)
to account for lock duration.
BoostCalculator.BoostParameters memory params = BoostCalculator.BoostParameters({
maxBoost: boostState.maxBoost,
minBoost: boostState.minBoost,
boostWindow: boostState.boostWindow,
totalWeight: totalWeight,
totalVotingPower: totalVotingPower,
votingPower: votingPower
});
Doesn't properly scale with the input amount parameter.
uint256 maxBoostAmount = amount * MAX_BOOST / 10000;
Uses a fixed divisor of 10000 which doesn't align with the voting power scale.
Tools Used
Manual Review
Recommendations
We should replace the hardcoded value of 10000 with the actual staked amount or relevant parameter. This would make the boost calculation more accurate and fair.
function _calculateBoost(
address user,
address pool,
uint256 stakedAmount
) internal view returns (uint256) {
if (stakedAmount == 0) revert InvalidBoostAmount();
if (!supportedPools[pool]) revert PoolNotSupported();
(uint256 totalWeight, uint256 totalVotingPower, uint256 votingPower) = updateTotalWeight();
uint256 userVotingPower = veToken.getVotingPower(user);
uint256 totalVeSupply = veToken.getTotalVotingPower();
BoostCalculator.BoostParameters memory params = BoostCalculator.BoostParameters({
maxBoost: boostState.maxBoost,
minBoost: boostState.minBoost,
boostWindow: boostState.boostWindow,
totalWeight: totalWeight,
totalVotingPower: totalVotingPower,
votingPower: votingPower
});
uint256 boost = BoostCalculator.calculateBoost(
userVotingPower,
totalVeSupply,
params
);
return (stakedAmount * boost) / PRECISION;
}