Core Contracts

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

Missing totalLocked Management in `veRAACToken` Leads to DoS and bypassed limits

Summary

Two critical issues in the veRAACToken contract's lock management:

1) The check against maxTotalLocked is missing when locking RAAC tokens allowing unlimited total locks, and 2) totalLocked is never decreased on withdrawals, leading to a permanent DoS condition when the inflated totalLocked reaches the maxTotalLockedset by the veRAACTokenwhich is currently 1B.

Vulnerability Details

The maxTotalLocked check is commented out in the LockManager library. This check is missing for both functions: increaseLockand createLock:

function createLock(
LockState storage state,
address user,
uint256 amount,
uint256 duration
) internal returns (uint256 end) {
...
// @audit-issue missing maxTotalLocked validation
state.totalLocked += amount;
...
}
function increaseLock(
LockState storage state,
address user,
uint256 additionalAmount
) internal {
// ...
// Maximum total locked amount check is disabled
// if (state.totalLocked + additionalAmount > state.maxTotalLocked) revert AmountExceedsLimit();
lock.amount += additionalAmount;
state.totalLocked += additionalAmount;
}

However, in the withdrawal functions in veRAACToken.sol, the contract only deletes the lock data without decreasing the totalLocked:

// In withdraw() function
delete _lockState.locks[msg.sender];
delete _votingState.points[msg.sender];
// Missing: _lockState.totalLocked -= amount;
// In emergencyWithdraw() function
delete _lockState.locks[msg.sender];
delete _votingState.points[msg.sender];
// Missing: _lockState.totalLocked -= amount;

The totalLocked value is critical as it's used in boost calculations:

function _updateBoostState(address user, uint256 newAmount) internal {
// ...
// @audit-issue Uses inflated totalLocked value
_boostState.totalWeight = _lockState.totalLocked;
// ...
}

Impact

  • The lack of validation of max amount minted allows users to bypass the maxTotalLocked limit (1B tokens) set in veRAACToken.

  • Once the check for the maxTotalLocked is implemented, the system will permanently DoS when totalLocked reaches the maxTotalLockedas it never decreases when withdrawals are made.

  • Incorrect boost calculations as _boostState.totalWeight uses an inflated totalLocked value.

Tools Used

Manual Review

Recommendations

Implement the check for maxTotalLockedin LockManager:

function createLock(
LockState storage state,
address user,
uint256 amount,
uint256 duration
) internal returns (uint256 end) {
...
+ if (state.totalLocked + amount > state.maxTotalLocked) revert AmountExceedsLimit();
...
}
function increaseLock(
LockState storage state,
address user,
uint256 additionalAmount
) internal {
+ if (state.totalLocked + additionalAmount > state.maxTotalLocked) revert AmountExceedsLimit();
...
}

Add totalLockeddecrease in both withdraw functions:

function withdraw() external nonReentrant {
...
+ _lockState.totalLocked -= amount;
...
}
function emergencyWithdraw() external nonReentrant {
...
+ _lockState.totalLocked -= amount;
...
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 7 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Appeal created

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

`veRAACToken::lock` function doesn't check MAX_TOTAL_LOCKED_AMOUNT

veRAACToken::withdraw / emergencyWithdraw doesn't substract the `_lockState.totalLocked`

Support

FAQs

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

Give us feedback!