Core Contracts

Regnum Aurum Acquisition Corp
HardhatReal World AssetsNFT
77,280 USDC
View results
Submission Details
Severity: medium
Valid

Missing _updateBoostState Call in extend::veRAACToken.sol

Summary

The extend function, which allows a user to extend the duration of an existing lock, does not call _updateBoostState after modifying the user’s voting power and veToken balance. This function updates the lock’s unlock time, recalculates voting power based on the new duration, adjusts the user’s veToken balance via _mint or _burn, and checkpoints the new power. However, unlike the lock and increase functions, it fails to update the boost state (_boostState) to reflect these changes. The _updateBoostState function is responsible for synchronizing the boost-related state—specifically votingPower, totalVotingPower, and totalWeight—and recalculating boost periods.

Vulnerability Details

function extend(uint256 newDuration) external nonReentrant whenNotPaused {
// Extend lock using LockManager
uint256 newUnlockTime = _lockState.extendLock(msg.sender, newDuration);
// Update voting power
LockManager.Lock memory userLock = _lockState.locks[msg.sender];
(int128 newBias, int128 newSlope) = _votingState.calculateAndUpdatePower(
msg.sender,
userLock.amount,
newUnlockTime
);
// Update checkpoints
uint256 oldPower = balanceOf(msg.sender);
uint256 newPower = uint256(uint128(newBias));
_checkpointState.writeCheckpoint(msg.sender, newPower);
// Update veToken balance
if (newPower > oldPower) {
_mint(msg.sender, newPower - oldPower);
} else if (newPower < oldPower) {
_burn(msg.sender, oldPower - newPower);
}
emit LockExtended(msg.sender, newUnlockTime);
}

extend does not invoke _updateBoostState after updating the lock duration and veToken supply, leaving _boostState in an outdated state. Both lock and increase call _updateBoostState to ensure _boostState reflects changes in locked amounts, voting power, and total supply. extend modifies similar state (voting power and totalSupply()) but skips this step, breaking the protocol’s pattern. _boostState relies on totalSupply() (via totalVotingPower) and the user’s voting power, which change in extend due to _mint or _burn, but these updates aren’t captured without _updateBoostState.

Impact

Stale Boost State:

  • _boostState.votingPower: Does not reflect the user’s updated voting power after extending the lock duration, which typically increases power.

  • _boostState.totalVotingPower: Remains outdated, not accounting for minted or burned veTokens, misrepresenting the total veToken supply.

Tools Used

Manual review

Recommendations

Add _updateBoostState:

  • Insert _updateBoostState(msg.sender, userLock.amount) after the veToken balance adjustment (_mint/_burn) to capture the updated voting power and totalSupply():

    solidity

function extend(uint256 newDuration) external nonReentrant whenNotPaused {
uint256 newUnlockTime = _lockState.extendLock(msg.sender, newDuration);
LockManager.Lock memory userLock = _lockState.locks[msg.sender];
(int128 newBias, int128 newSlope) = _votingState.calculateAndUpdatePower(
msg.sender,
userLock.amount,
newUnlockTime
);
uint256 oldPower = balanceOf(msg.sender);
uint256 newPower = uint256(uint128(newBias));
_checkpointState.writeCheckpoint(msg.sender, newPower);
if (newPower > oldPower) {
_mint(msg.sender, newPower - oldPower);
} else if (newPower < oldPower) {
_burn(msg.sender, oldPower - newPower);
}
+ _updateBoostState(msg.sender, userLock.amount); // Fix
emit LockExtended(msg.sender, newUnlockTime);
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 7 months ago
Submission Judgement Published
Validated
Assigned finding tags:

veRAACToken::_updateBoostState not called in extend/withdraw

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.

Give us feedback!