Summary
Using the updateUserBoost function, an user who does not have the veToken balance, can still get the free boost value of 1000.
Vulnerability Details
The contract BoostController manages boost calculations and delegations for the RAAC protocol. It implements Curve-style boost mechanics with max 2.5x multiplier.
The function updateUserBoost is used to update the boost value for a user in a specific pool. This calls the function _calculateBoost to get the new boost based on current veToken balance.
function updateUserBoost(address user, address pool) external override nonReentrant whenNotPaused {
if (paused()) revert EmergencyPaused();
if (user == address(0)) revert InvalidPool();
if (!supportedPools[pool]) revert PoolNotSupported();
UserBoost storage userBoost = userBoosts[user][pool];
PoolBoost storage poolBoost = poolBoosts[pool];
uint256 oldBoost = userBoost.amount;
uint256 newBoost = _calculateBoost(user, pool, 10000); @@ audit find
userBoost.amount = newBoost;
userBoost.lastUpdateTime = block.timestamp;
if (newBoost >= oldBoost) {
poolBoost.totalBoost = poolBoost.totalBoost + (newBoost - oldBoost);
} else {
poolBoost.totalBoost = poolBoost.totalBoost - (oldBoost - newBoost);
}
poolBoost.workingSupply = newBoost;
poolBoost.lastUpdateTime = block.timestamp;
emit BoostUpdated(user, pool, newBoost);
emit PoolBoostUpdated(pool, poolBoost.totalBoost, poolBoost.workingSupply);
}
_calculateBoost takes the user, pool and the magic number value 1000. if we look at the _calculateBoost, for non balance user, it still returns this 1000
function _calculateBoost(
address user,
address pool,
uint256 amount
) internal view returns (uint256) {
if (amount == 0) revert InvalidBoostAmount();
if (!supportedPools[pool]) revert PoolNotSupported();
(uint256 totalWeight, uint256 totalVotingPower, uint256 votingPower) = updateTotalWeight();
uint256 userBalance = IERC20(address(veToken)).balanceOf(user);
uint256 totalSupply = IERC20(address(veToken)).totalSupply();
if (userBalance == 0 || totalSupply == 0) {
return amount;---------------------<<< refer here
}
.............................
Impact
Without having any veToken balance, user still be updated with boost value of 1000.
Tools Used
Manual review.
Recommendations
Check if user has the actual balance of veToken before inside the function updateUserBoost