Core Contracts

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

The absence of a check for totalSupply limit in the `veRAACToken.increase` function.

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 at L216 on the veRAACToken.sol.

https://github.com/Cyfrin/2025-02-raac/blob/main/contracts/core/tokens/veRAACToken.sol#L215

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,//@audit double add
userLock.end
);
// Update checkpoints
uint256 newPower = uint256(uint128(newBias));
_checkpointState.writeCheckpoint(msg.sender, newPower);
// 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);
}

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:

veRAACToken::increase doesn't check the token supply, making it possible to mint over the MAX

Support

FAQs

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

Give us feedback!