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.