Description
The veRAACToken contract updates boost state before minting new tokens in the veRAACToken::lock
function. The veRAACToken::_updateBoostState
function uses totalSupply
for boost calculations, but this value hasn't been updated yet by the subsequent _mint
call, leading to incorrect boost ratios.
function lock(uint256 amount, uint256 duration) external {
_lockState.createLock(msg.sender, amount, duration);
@> _updateBoostState(msg.sender, amount);
(int128 bias, int128 slope) = _votingState.calculateAndUpdatePower(...);
uint256 newPower = uint256(uint128(bias));
_checkpointState.writeCheckpoint(msg.sender, newPower);
@> _mint(msg.sender, newPower);
}
function _updateBoostState(address user, uint256 newAmount) internal {
@> _boostState.totalVotingPower = totalSupply();
_boostState.totalWeight = _lockState.totalLocked;
_boostState.updateBoostPeriod();
}
Example:
Initial state:
totalSupply = 1000 veRAACToken
User locks 500 RAAC
Current calculation:
boost = votingPower / totalVotingPower
= 500 / 1000
= 0.5
Correct calculation (should be):
boost = votingPower / totalVotingPower
= 500 / 1500
= 0.33
Risk
Likelihood: High
Occurs on every lock operation
Affects all users creating new locks
No condition to prevent this miscalculation
Impact: Medium
Boosts are calculated with incorrect ratios
Users receive higher boost values than intended
Protocol's reward distribution becomes unbalanced
Recommended Mitigation
This ensures boost calculations use the correct, updated totalSupply value, leading to accurate boost ratios.
function lock(uint256 amount, uint256 duration) external nonReentrant whenNotPaused {
_lockState.createLock(msg.sender, amount, duration);
- _updateBoostState(msg.sender, amount);
(int128 bias, int128 slope) = _votingState.calculateAndUpdatePower(...);
uint256 newPower = uint256(uint128(bias));
_checkpointState.writeCheckpoint(msg.sender, newPower);
_mint(msg.sender, newPower);
+ _updateBoostState(msg.sender, amount);
emit LockCreated(msg.sender, amount, unlockTime);
}