Core Contracts

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

Failure to update total locked amount on withdrawal leads to incorrect boost calculations

Description

The veRAACToken::withdraw and veRAACToken::emergencyWithdraw functions delete user lock positions but fail to update the LockState::totalLocked value. This stale value propagates to BoostState::totalWeight, causing inaccurate boost multiplier calculations that affect reward distributions.

Proof of Concept

  1. User creates lock with 1000 RAAC

  2. Protocol shows 1000 RAAC in totalLocked

  3. User waits for lock expiration and withdraws

  4. totalLocked remains at 1000 RAAC despite withdrawal

  5. Boost calculations use incorrect weight values

Relevant code snippets:

// contracts/core/tokens/veRAACToken.sol
function withdraw() external nonReentrant {
// ... existing code ...
delete _lockState.locks[msg.sender]; // Does NOT update totalLocked
}
struct LockState {
uint256 totalLocked; // Never decremented on withdrawal
}

Add this test to veRAACToken.test.js:

it("shows incorrect totalLocked after withdrawal", async () => {
const amount = ethers.parseEther("1000");
const duration = 365 * 24 * 3600;
// Create and withdraw lock
await veRAACToken.connect(users[0]).lock(amount, duration);
await time.increase(duration + 1);
await veRAACToken.connect(users[0]).withdraw();
// Get updated state
const boostState = await veRAACToken.getBoostState();
const lockState = await veRAACToken.getLockPosition(users[0].address);
// Verify incorrect totals
expect(boostState.totalWeight).to.equal(amount); // Should be 0
expect(lockState.amount).to.equal(0); // Correctly deleted
});

Impact

Medium severity - Causes systematic miscalculations in boost multipliers, leading to incorrect reward distributions. While not directly risking fund loss, this undermines protocol economics and user trust.

Recommendation

  • Update locked totals on withdrawal:

// contracts/core/tokens/veRAACToken.sol
function withdraw() external nonReentrant {
// ... existing code ...
+ _lockState.totalLocked -= amount;
delete _lockState.locks[msg.sender];
}
  • Apply same fix to emergencyWithdraw

  • Add validation checks for totalLocked consistency

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!