Core Contracts

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

Incorrect check for totalSupply limit in the `veRAACToken.sol`.

Summary

The treasury manages protocol treasury funds with role-based access control. However, SafeERC20 is not utilized in the Treasury.sol. As a result, the treasury will not work well with some wired tokens.

Vulnerability Details

There is a check for totalSupply limit in the veRAACToken.lock() function.

https://github.com/Cyfrin/2025-02-raac/blob/main/contracts/core/collectors/Treasury.sol#L216

if (totalSupply() + amount > MAX_TOTAL_SUPPLY) revert TotalSupplyLimitExceeded();

However, the added amount is a locked amount, not the minted amount.
https://github.com/Cyfrin/2025-02-raac/blob/main/contracts/core/collectors/Treasury.sol#L223-L241

@> uint256 unlockTime = block.timestamp + duration;
// Create lock position
_lockState.createLock(msg.sender, amount, duration);
_updateBoostState(msg.sender, amount);
// Calculate initial voting power
(int128 bias, int128 slope) = _votingState.calculateAndUpdatePower(
msg.sender,
@> amount,
@> unlockTime
);
// Update checkpoints
@> uint256 newPower = uint256(uint128(bias));
_checkpointState.writeCheckpoint(msg.sender, newPower);
// Mint veTokens
@> _mint(msg.sender, newPower);

When the duration is shorter than MAX_LOCK_DURATION, the minted amount is less than the locked amount.
https://github.com/Cyfrin/2025-02-raac/blob/main/contracts/libraries/governance/VotingPowerLib.sol#L75

@> uint256 initialPower = (amount * duration) / MAX_LOCK_DURATION; // Normalize by max duration
@> bias = int128(int256(initialPower));

As a result, totalSupply() + amount will be smaller than the totalSupply() after locking, which could result in an unreasonable revert of locking.

Impact

Unreasonable reverts due to an improper max supply check.

Recommendations

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();
// Do the transfer first - this will revert with ERC20InsufficientBalance if user doesn't have enough tokens
raacToken.safeTransferFrom(msg.sender, address(this), amount);
// Calculate unlock time
uint256 unlockTime = block.timestamp + duration;
// Create lock position
_lockState.createLock(msg.sender, amount, duration);
_updateBoostState(msg.sender, amount);
// Calculate initial voting power
(int128 bias, int128 slope) = _votingState.calculateAndUpdatePower(
msg.sender,
amount,
unlockTime
);
// Update checkpoints
uint256 newPower = uint256(uint128(bias));
_checkpointState.writeCheckpoint(msg.sender, newPower);
+ if (totalSupply() + newPower > MAX_TOTAL_SUPPLY) revert TotalSupplyLimitExceeded();
// Mint veTokens
_mint(msg.sender, newPower);
emit LockCreated(msg.sender, amount, unlockTime);
}
Updates

Lead Judging Commences

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

Incorrect `MAX_TOTAL_SUPPLY` check in the `veRAACToken::lock/extend` function of `veRAACToken` could harm locking functionality

Support

FAQs

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

Give us feedback!