Core Contracts

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

Missing TotalLocked Reduction in veRAACToken Withdrawals

Description

The veRAACToken contract contains a critical vulnerability where the total locked token counter (_lockState.totalLocked) is not decreased when users withdraw their tokens. While the contract correctly tracks token deposits by increasing totalLocked, it fails to decrease this during withdrawals, leading to a permanent discrepancy between the tracked total and actual locked tokens.

function withdraw() external nonReentrant {
LockManager.Lock memory userLock = _lockState.locks[msg.sender];
if (userLock.amount == 0) revert LockNotFound();
if (block.timestamp < userLock.end) revert LockNotExpired();
uint256 amount = userLock.amount;
uint256 currentPower = balanceOf(msg.sender);
// CRITICAL: totalLocked not decreased here
delete _lockState.locks[msg.sender];
delete _votingState.points[msg.sender];
_checkpointState.writeCheckpoint(msg.sender, 0);
_burn(msg.sender, currentPower);
raacToken.safeTransfer(msg.sender, amount);
emit Withdrawn(msg.sender, amount);
}

Impact

  • Incorrect total locked token accounting

  • Boost calculations become increasingly inaccurate as more withdrawals occur

  • New deposits might be incorrectly rejected due to inflated totalLocked value

  • Governance calculations relying on total locked amounts become unreliable

  • Protocol economics affected due to incorrect boost multipliers

Fix Recommendation

Add totalLocked reduction in both withdraw functions:

function withdraw() external nonReentrant {
LockManager.Lock memory userLock = _lockState.locks[msg.sender];
if (userLock.amount == 0) revert LockNotFound();
if (block.timestamp < userLock.end) revert LockNotExpired();
uint256 amount = userLock.amount;
uint256 currentPower = balanceOf(msg.sender);
// Add this line to fix the issue
_lockState.totalLocked -= amount;
delete _lockState.locks[msg.sender];
delete _votingState.points[msg.sender];
_checkpointState.writeCheckpoint(msg.sender, 0);
_burn(msg.sender, currentPower);
raacToken.safeTransfer(msg.sender, amount);
emit Withdrawn(msg.sender, amount);
}
function emergencyWithdraw() external nonReentrant {
// ... existing checks ...
uint256 amount = userLock.amount;
uint256 currentPower = balanceOf(msg.sender);
// Add this line to fix the issue
_lockState.totalLocked -= amount;
// ... rest of function ...
}

Tools Used

  • Manual Review

  • Foundry Testing Framework

Updates

Lead Judging Commences

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

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

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

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!