Core Contracts

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

Missing vote delay enforcement in `GaugeController` contract allows rapid gauge weight manipulation

Summary

The GaugeController contract defines a VOTE_DELAY constant of 10 days but fails to implement any mechanism to enforce this delay between votes. This oversight allows users to vote multiple times in rapid succession, potentially manipulating gauge weights and reward distributions.

Vulnerability Details

The contract tracks the last vote time for each user in the lastVoteTime mapping but never enforces the intended delay between votes. While the contract defines constants:

uint256 public constant VOTE_DELAY = 10 days;
uint256 public constant MIN_VOTE_DELAY = 1 days;
uint256 public constant MAX_VOTE_DELAY = 10 days;

The vote() function does not check the time elapsed since the user's last vote:

function vote(address gauge, uint256 weight) external override whenNotPaused {
if (!isGauge(gauge)) revert GaugeNotFound();
if (weight > WEIGHT_PRECISION) revert InvalidWeight();
uint256 votingPower = veRAACToken.balanceOf(msg.sender);
if (votingPower == 0) revert NoVotingPower();
uint256 oldWeight = userGaugeVotes[msg.sender][gauge];
userGaugeVotes[msg.sender][gauge] = weight;
_updateGaugeWeight(gauge, oldWeight, weight, votingPower);
emit WeightUpdated(gauge, oldWeight, weight);
}

Proof of Concept

  1. User holds veRAACToken balance giving them voting power

  2. User calls vote() for Gauge A with weight=5000

  3. User immediately calls vote() again for Gauge A with weight=0

  4. User can repeat this process unlimited times without waiting for any delay

  5. This allows rapid manipulation of gauge weights affecting reward distribution

Impact

  • Users can manipulate gauge weights multiple times per block

  • No cooldown period between votes undermines voting stability

  • Reward distribution can be manipulated through rapid weight changes

  • Violates the intended voting delay mechanism stated in the docs

Tools Used

Manual review

Recommendations

Add vote delay enforcement in the vote() function:

function vote(address gauge, uint256 weight) external override whenNotPaused {
if (!isGauge(gauge)) revert GaugeNotFound();
if (weight > WEIGHT_PRECISION) revert InvalidWeight();
+ uint256 timeSinceLastVote = block.timestamp - lastVoteTime[msg.sender];
+ if (timeSinceLastVote < VOTE_DELAY) revert VoteDelayNotElapsed();
uint256 votingPower = veRAACToken.balanceOf(msg.sender);
if (votingPower == 0) revert NoVotingPower();
uint256 oldWeight = userGaugeVotes[msg.sender][gauge];
userGaugeVotes[msg.sender][gauge] = weight;
_updateGaugeWeight(gauge, oldWeight, weight, votingPower);
+ lastVoteTime[msg.sender] = block.timestamp;
emit WeightUpdated(gauge, oldWeight, weight);
}

Also add the required error:

error VoteDelayNotElapsed();
Updates

Lead Judging Commences

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

GaugeController::vote never enforces VOTE_DELAY or updates lastVoteTime, allowing users to spam votes and manipulate gauge weights without waiting

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

GaugeController::vote never enforces VOTE_DELAY or updates lastVoteTime, allowing users to spam votes and manipulate gauge weights without waiting

Support

FAQs

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