Summary
Users can lock their RAAC tokens and increase the amount of locked RAAC tokens. While the veRAACToken.lock() function includes a check against MAX_TOTAL_SUPPLY, the veRAACToken.increase() function lacks a similar check. This oversight could allow users to increase their locked amount beyond the intended total supply limit.
Vulnerability Details
There is check totalSupply() + amount > MAX_TOTAL_SUPPLY in veRAACToken.lock() function. However, there is no check in veRAACToken.increase() function. This makes users can increase over MAX_TOTAL_SUPPLY.
function lock(uint256 amount, uint256 duration) external nonReentrant whenNotPaused {
if (amount == 0) revert InvalidAmount();
if (amount > MAX_LOCK_AMOUNT) revert AmountExceedsLimit();
>> if (totalSupply() + amount > MAX_TOTAL_SUPPLY) revert TotalSupplyLimitExceeded();
if (duration < MIN_LOCK_DURATION || duration > MAX_LOCK_DURATION)
revert InvalidLockDuration();
...
}
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);
}
There is check for amount in LockManager.increaseLock(), but this only checks against maxLockAmount not MAX_TOTAL_SUPPLY. Therefore, the check against MAX_TOTAL_SUPPLY should be implemented to veRAACToken.increase().
function increaseLock(
LockState storage state,
address user,
uint256 additionalAmount
) internal {
Lock storage lock = state.locks[user];
if (!lock.exists) revert LockNotFound();
if (lock.end <= block.timestamp) revert LockExpired();
>> if (lock.amount + additionalAmount > state.maxLockAmount) revert AmountExceedsLimit();
lock.amount += additionalAmount;
state.totalLocked += additionalAmount;
emit LockIncreased(user, additionalAmount);
}
Impact
Users can increase their locked amounts beyond the maximum limit, potentially leading to an unusable limit for the token supply
Tools Used
Manual Review
Recommendations
Implement the check against MAX_TOTAL_SUPPLY in veRAACToken.increase().
function increase(uint256 amount) external nonReentrant whenNotPaused {
// Increase lock using LockManager
_lockState.increaseLock(msg.sender, amount);
_updateBoostState(msg.sender, locks[msg.sender].amount);
// Update voting power
LockManager.Lock memory userLock = _lockState.locks[msg.sender];
(int128 newBias, int128 newSlope) = _votingState.calculateAndUpdatePower(
msg.sender,
userLock.amount + amount,
userLock.end
);
// Update checkpoints
uint256 newPower = uint256(uint128(newBias));
_checkpointState.writeCheckpoint(msg.sender, newPower);
+ if (totalSupply() + newPower - balanceOf(msg.sender) > MAX_TOTAL_SUPPLY) revert TotalSupplyLimitExceeded();
// Transfer additional tokens and mint veTokens
raacToken.safeTransferFrom(msg.sender, address(this), amount);
_mint(msg.sender, newPower - balanceOf(msg.sender));
emit LockIncreased(msg.sender, amount);
}