Summary
The increase
and extend
functions in the veRAACToken
contract do not check the upper limits for lockTime
and totalLockedAmount
. This can lead to exceeding the maximum allowed lock duration and total locked amount, potentially causing issues within the protocol.
Vulnerability Details
The current increase
function in the veRAACToken
contract is:
function increase(uint256 amount) external nonReentrant whenNotPaused {LockManager
_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 function does not check if the total locked amount exceeds the maximum allowed limit.
Similarly, the extend
function in the veRAACToken
contract is:
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);
}
emit LockExtended(msg.sender, newUnlockTime);
}
The function does not check if the new lock duration exceeds the maximum allowed duration.
Links:
https://github.com/Cyfrin/2025-02-raac/blob/89ccb062e2b175374d40d824263a4c0b601bcb7f/contracts/core/tokens/veRAACToken.sol#L282
https://github.com/Cyfrin/2025-02-raac/blob/89ccb062e2b175374d40d824263a4c0b601bcb7f/contracts/core/tokens/veRAACToken.sol#L253
Impact
This issue can lead to exceeding the maximum allowed lock duration and total locked amount, potentially causing issues with token accounting and user balances within the protocol.
Tools Used
Manual code review.
Recommendations
Update the increase
and extend
functions to include checks for the upper limits of lockTime
and totalLockedAmount
. Additionally, update the LockManager
contract to include these checks.
Corrected increase
Function in veRAACToken
function increase(uint256 amount) external nonReentrant whenNotPaused {
if (_lockState.totalLocked + amount > MAX_TOTAL_LOCKED_AMOUNT) revert TotalLockedAmountExceeded();
_lockState.increaseLock(msg.sender, amount);
_updateBoostState(msg.sender, locks[msg.sender].amount);
...
emit LockIncreased(msg.sender, amount);
}
Corrected extend
Function in veRAACToken
function extend(uint256 newDuration) external nonReentrant whenNotPaused {
uint256 newUnlockTime = _lockState.extendLock(msg.sender, newDuration);
if (newUnlockTime > block.timestamp + MAX_LOCK_DURATION) revert InvalidLockDuration();
...
emit LockExtended(msg.sender, newUnlockTime);
}
This ensures that the upper limits for lockTime
and totalLockedAmount
are correctly enforced, leading to accurate token accounting and user balances.