Core Contracts

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

Incorrect Voting Power Calculation in veRAACToken

Summary

The calculateVeAmount function in veRAACToken uses a linear calculation that can be manipulated to gain disproportionate voting power through precision loss and lacks important validations.

Vulnerability Details

Found in:

function calculateVeAmount(uint256 amount, uint256 lockDuration) external pure returns (uint256) {
if (amount == 0 || lockDuration == 0) return 0;
if (lockDuration > MAX_LOCK_DURATION) lockDuration = MAX_LOCK_DURATION;
// Calculate voting power as a linear function of lock duration
return (amount * lockDuration) / MAX_LOCK_DURATION;
}

The vulnerability exists because:

  1. Linear calculation (amount * lockDuration) / MAX_LOCK_DURATION is susceptible to:

    • Precision loss due to division after multiplication

    • No minimum lock duration validation

    • No rounding mechanism

    • Potential manipulation through small amounts

  2. Missing critical validations:

    • No check against MIN_LOCK_DURATION (365 days)

    • No minimum power threshold

    • No check for dust amounts

  3. This impacts governance since the voting power is used in:

function getVotingPowerForProposal(
address account,
uint256 proposalId
) external view returns (uint256) {
uint256 snapshotBlock = proposalPowerSnapshots[proposalId];
if (snapshotBlock == 0) revert InvalidProposalId();
return getPastVotes(account, snapshotBlock);
}

Impact

High severity because:

  1. Affects core governance mechanism

  2. Can be exploited to gain disproportionate voting power

  3. Impacts all proposals and voting

  4. No recovery mechanism without contract upgrade

Proof of Concept

function exploitVotingPower() external {
uint256 smallAmount = 100;
uint256 shortDuration = MIN_LOCK_DURATION + 1;
// Due to precision loss, this gives more voting power than intended
uint256 power1 = veRAACToken.calculateVeAmount(smallAmount, shortDuration);
// Creating multiple small locks gives more power than one large lock
uint256 power2 = veRAACToken.calculateVeAmount(smallAmount * 2, shortDuration);
assert(power1 * 2 != power2); // Inequality due to precision loss
}

Recommendation

Implement safer voting power calculation:

function calculateVeAmount(uint256 amount, uint256 lockDuration) external pure returns (uint256) {
if (amount == 0 || lockDuration < MIN_LOCK_DURATION) return 0;
if (lockDuration > MAX_LOCK_DURATION) lockDuration = MAX_LOCK_DURATION;
// Use precision factor to prevent dust
uint256 PRECISION = 1e18;
// Calculate with precision
uint256 power = (amount * PRECISION / MAX_LOCK_DURATION) * lockDuration;
// Apply minimum threshold
if (power < MIN_VOTING_POWER * PRECISION) return 0;
return power / PRECISION;
}

Tools Used

  • Manual code review

  • Control flow analysis

Updates

Lead Judging Commences

inallhonesty Lead Judge 6 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

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