Core Contracts

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

Wrong MAX_TOTAL_SUPPLY check will block users from locking RAAC tokens

Summary

Wrong max total supply check in lock contract will block users from locking tokens when the max supply is not reached

Vulnerability Details

The protocols lets users lock RAAC tokens in eachange for veRAAC tokens which grant voting power. This can be done via the `veRAACToken::lock()` function.

There is a MAX_TOTAL_SUPPLY of veRAAC tokens that can be minted. There is a check in the lock function that enforces the max supply invariant:

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();

The amount is calculated by combining the totalSupply of veRAAC tokens and the deposited amount of RAAC tokens. However this is wrong since the minted amount is not equal to the deposit amount.

The amount minted is calculated later in the function by

(int128 bias, ) = _votingState.calculateAndUpdatePower(

where bias is the minted amount. bias is less than amount since it is calculated by:

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

Hence it would always be less than amount.

Having all this in mind, totalSupply() + amount > MAX_TOTAL_SUPPLY is calculated wrong since the bias (votingPower) should be added to the totalSupply and not the amount deposited

Impact

Low, DoS

Tools Used

Manual Review

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(); // @audit-issue L : should be + newPower
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, ) = _votingState.calculateAndUpdatePower(
msg.sender,
amount,
unlockTime
);
// Update checkpoints
uint256 newPower = uint256(uint128(bias));
+ if (totalSupply() + newPower > MAX_TOTAL_SUPPLY) revert TotalSupplyLimitExceeded(); // @audit-issue L : should be + newPower
_checkpointState.writeCheckpoint(msg.sender, newPower);
// Mint veTokens
_mint(msg.sender, newPower);
emit LockCreated(msg.sender, amount, unlockTime);
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 6 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.