Summary
In the lock function, there is a check to prevent users from depositing above the Max total supply of veRAACtoken but the check inaccurately checks if the veRAACtoken + RAAC token amount is greater than the max supply.
Vulnerability Details
The total supply will return the Vote power amount which is the VeRAAC token amount note the user deposits RAAC token therefore the check is wrong as we are adding different parameters to compare with veRAAC max total supply
* @notice Creates a new lock position for RAAC tokens
* @dev Locks RAAC tokens for a specified duration and mints veRAAC tokens representing voting power
* @param amount The amount of RAAC tokens to lock
* @param duration The duration to lock tokens for, in seconds
*/
function lock(uint256 amount, uint256 duration) external nonReentrant whenNotPaused {
if (amount == 0) revert InvalidAmount();
if (amount > MAX_LOCK_AMOUNT) revert AmountExceedsLimit();
@audit>> if (totalSupply() + amount > MAX_TOTAL_SUPPLY) revert TotalSupplyLimitExceeded();
if (duration < MIN_LOCK_DURATION || duration > MAX_LOCK_DURATION)
revert InvalidLockDuration();
* @notice Gets the total voting power of all veRAAC tokens
@audit>> * @dev Returns the total supply of veRAAC tokens
* @return The total voting power across all holders
*/
function getTotalVotingPower() external view override returns (uint256) {
@audit>> return totalSupply();
}
Hence the check is comparing
veRAAC tokens + RAAC token > veRAAC token Max supply => wrong
E.g
Alice locks 10 RAAC for 2 years and gets 5 vote power
Max supply is 20 vote power
Bob tries to lock 30 RAAC for 2 years also to get 15 vote power
5 vote power + 30 RAAC > 20 votepower will revert.........
Impact
Legit calls to lock tokens will revert even when the max supply is not yet reached
Tools Used
Manual Review
Recommendations
Check the Max supply with the users new power instead
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();
raacToken.safeTransferFrom(msg.sender, address(this), amount);
uint256 unlockTime = block.timestamp + duration;
_lockState.createLock(msg.sender, amount, duration);
_updateBoostState(msg.sender, amount);
(int128 bias, int128 slope) = _votingState.calculateAndUpdatePower(
msg.sender,
amount,
unlockTime
);
uint256 newPower = uint256(uint128(bias));
_checkpointState.writeCheckpoint(msg.sender, newPower);
++ if (totalSupply() + newPower > MAX_TOTAL_SUPPLY) revert TotalSupplyLimitExceeded();
_mint(msg.sender, newPower);
emit LockCreated(msg.sender, amount, unlockTime);
}