Core Contracts

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

Inconsistent Units in MAX_TOTAL_SUPPLY Check in lock::veRAACTokem

Summary

lock which creates a new lock position by transferring raacToken and minting veTokens, includes a check

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

to ensure the total supply of veTokens doesn’t exceed a cap. However, this check incorrectly adds amount (the number of raacToken being locked) to totalSupply() (the current supply of veeRAAC tokens) instead of adding the minted voting power (newPower), which is what actually increases totalSupply(). Since raacToken and veeRAAC are distinct units—where newPower (veTokens) is derived from amount and duration via a voting power calculation—this introduces an inconsistency in currency, rendering the check ineffective or misleading.

Vulnerability Details

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(); // Problematic check
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);
_mint(msg.sender, newPower); // Increases totalSupply() by newPower
emit LockCreated(msg.sender, amount, unlockTime);
}
  • Unit Mismatch:

    • totalSupply() represents the total number of veeRAAC tokens (veTokens), which are minted based on voting power (newPower).

    • amount is the number of raacToken locked, a different asset/unit.

    • newPower (calculated by _votingState.calculateAndUpdatePower) depends on amount and duration, not a 1:1 mapping with raacToken.

Impact

Ineffective Cap Enforcement:

  • totalSupply() + amount doesn’t accurately predict the post-mint totalSupply(), which increases by newPower. If newPower > amount (e.g., long duration), the cap could be exceeded without reverting; if newPower < amount, valid locks might be rejected unnecessarily.

  • Impact: Fails to enforce MAX_TOTAL_SUPPLY as a veToken cap, allowing over-issuance or blocking legitimate locks.

Could lead to over-Issuance of veTokens

Tools Used

manual review

Recommendations

Use newPower in Check:

  • Replace totalSupply() + amount with totalSupply() + newPower after calculating voting power:

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(); // Problematic check
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));
+ if (totalSupply() + newPower > MAX_TOTAL_SUPPLY) revert TotalSupplyLimitExceeded(); // Fix
_checkpointState.writeCheckpoint(msg.sender, newPower);
_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!