Core Contracts

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

Incorrect Power Calculation Causes Token Burns on Lock Extension

Summary

A critical vulnerability in veRAACToken causes accidental token burning during lock extensions. When users extend their locks, the contract incorrectly compares their initial balance to a new voting power calculation, resulting in unintended loss of tokens.

Vulnerability Details

The vulnerability occurs in three key steps:

Lock extension calculates total new duration:

// LockManager.sol
uint256 remainingDuration = lock.end - block.timestamp;
uint256 totalNewDuration = remainingDuration + extensionDuration;

New voting power is calculated based on this duration:

// VotingPowerLib.sol
uint256 duration = unlockTime - block.timestamp;
uint256 initialPower = (amount * duration) / MAX_LOCK_DURATION;

The critical flaw is in the comparison and burning logic when calling veRAACToken.extend():

function extend(uint256 newDuration) external nonReentrant whenNotPaused {
// Extend lock using LockManager
uint256 newUnlockTime = _lockState.extendLock(msg.sender, newDuration);
// Update voting power
LockManager.Lock memory userLock = _lockState.locks[msg.sender];
// @audit using the remainingTime + additional duration here.
(int128 newBias, int128 newSlope) = _votingState.calculateAndUpdatePower(
msg.sender,
userLock.amount,
newUnlockTime
);
// Update checkpoints
// @audit Static amount from initial mint
uint256 oldPower = balanceOf(msg.sender);
// @audit Based on remaining + extension time
uint256 newPower = uint256(uint128(newBias));
_checkpointState.writeCheckpoint(msg.sender, newPower);
// Update veToken balance
if (newPower > oldPower) {
_mint(msg.sender, newPower - oldPower);
} else if (newPower < oldPower) {
// @audit This will always execute
_burn(msg.sender, oldPower - newPower);
}
emit LockExtended(msg.sender, newUnlockTime);
}

PoC

  1. User locks 1000 tokens for 4 years (1460 days)

    • Initial power = 1000 veTokens (1000 * 1460 / 1460)

  2. After 3 years, user extends for 2 more years

    • Remaining time = 1 year (365 days)

    • Extension = 2 years (730 days)

    • Total new duration = 1095 days

    • New power = 750 veTokens (1000 * 1095 / 1460)

  3. Result: 250 veTokens are burned (1000 - 750)

  4. User lost 250 veTokens when extending his locked position.

Impact

  • Users automatically lose voting power when extending their locks, directly contradicting the protocol's incentive mechanism

  • Earlier extensions result in larger token burns, discouraging users from extending their locks proactively

  • Governance participation is negatively impacted as users lose voting power for attempting to increase their commitment to the protocol

Tools Used

Manual Review

Recommendations

Keep the original minted amount and only mint additional tokens if the new duration would result in more voting power:

function extend(uint256 newDuration) external nonReentrant whenNotPaused {
...
if (newPower > oldPower) {
_mint(msg.sender, newPower - oldPower);
- } else if (newPower < oldPower) {
- _burn(msg.sender, oldPower - newPower);
}
...
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 7 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement
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
holydevoti0n Submitter
7 months ago
inallhonesty Lead Judge
7 months ago
inallhonesty Lead Judge 6 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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

Give us feedback!