Summary
The _updateBoostState function in the veRAACToken contract incorrectly updates the boost state. When called after increasing the lock amount, the new tokens are not yet minted, leading to an incorrect totalVotingPower being set to the old totalSupply.
Vulnerability Details
The current _updateBoostState function in the veRAACToken contract is:
function _updateBoostState(address user, uint256 newAmount) internal {
_boostState.votingPower = _votingState.calculatePowerAtTimestamp(user, block.timestamp);
_boostState.totalVotingPower = totalSupply();
>> _boostState.totalWeight = _lockState.totalLocked;
_boostState.updateBoostPeriod();
}
When _updateBoostState is called after increasing the lock amount, the new tokens are not yet minted, leading to an incorrect totalVotingPower being set to the old totalSupply.
For instance, in the increase function:
function increase(uint256 amount) external nonReentrant whenNotPaused {
_lockState.increaseLock(msg.sender, amount);
_updateBoostState(msg.sender, locks[msg.sender].amount);
LockManager.Lock memory userLock = _lockState.locks[msg.sender];
(int128 newBias, int128 newSlope) = _votingState.calculateAndUpdatePower(
msg.sender,
userLock.amount + amount,
userLock.end
);
uint256 newPower = uint256(uint128(newBias));
_checkpointState.writeCheckpoint(msg.sender, newPower);
raacToken.safeTransferFrom(msg.sender, address(this), amount);
_mint(msg.sender, newPower - balanceOf(msg.sender));
emit LockIncreased(msg.sender, amount);
}
The totalVotingPower is set to the old totalSupply before the new tokens are minted.
Links:
https://github.com/Cyfrin/2025-02-raac/blob/89ccb062e2b175374d40d824263a4c0b601bcb7f/contracts/core/tokens/veRAACToken.sol#L571
https://github.com/Cyfrin/2025-02-raac/blob/89ccb062e2b175374d40d824263a4c0b601bcb7f/contracts/core/tokens/veRAACToken.sol#L227
https://github.com/Cyfrin/2025-02-raac/blob/89ccb062e2b175374d40d824263a4c0b601bcb7f/contracts/core/tokens/veRAACToken.sol#L241
https://github.com/Cyfrin/2025-02-raac/blob/89ccb062e2b175374d40d824263a4c0b601bcb7f/contracts/core/tokens/veRAACToken.sol#L254
https://github.com/Cyfrin/2025-02-raac/blob/89ccb062e2b175374d40d824263a4c0b601bcb7f/contracts/core/tokens/veRAACToken.sol#L270
Impact
This issue can lead to incorrect boost calculations, potentially affecting the rewards and voting power calculations within the protocol.
Tools Used
Manual code review.
Recommendations
Update the _updateBoostState function to correctly handle the new total supply after minting the new tokens. The corrected function should be:
function _updateBoostState(address user, uint256 newAmount) internal {
_boostState.votingPower = _votingState.calculatePowerAtTimestamp(user, block.timestamp);
_boostState.totalVotingPower = totalSupply() + newAmount;
_boostState.totalWeight = _lockState.totalLocked;
_boostState.updateBoostPeriod();
}
This ensures that the totalVotingPower correctly includes the new minted tokens, leading to accurate boost calculations.