Core Contracts

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

Gauge Weight Manipulation Through Vote Timing

Summary

The GaugeController's voting mechanism contains conflicting vote delay parameters and lacks protection against vote timing manipulation, allowing users to amplify their voting power impact.

Vulnerability Details

In GaugeController.sol, the voting delay parameters are inconsistent:

/// @notice Required delay between votes
uint256 public constant VOTE_DELAY = 10 days;
/// @notice Minimum allowed vote delay
uint256 public constant MIN_VOTE_DELAY = 1 days;
/// @notice Maximum allowed vote delay
uint256 public constant MAX_VOTE_DELAY = 10 days;
/// @notice Minimum vote weight allowed
uint256 public constant MIN_VOTE_WEIGHT = 100; // 1% minimum vote

The issue arises because:

  1. VOTE_DELAY (10 days) conflicts with MIN_VOTE_DELAY (1 day)

  2. Users can vote immediately after MIN_VOTE_DELAY instead of waiting for VOTE_DELAY

  3. No slope calculation for vote weight changes between periods

A malicious user could:

  1. Vote with maximum weight

  2. Wait for MIN_VOTE_DELAY (1 day)

  3. Change vote to manipulate gauge weights

  4. Repeat this process every day instead of every 10 days as intended

Impact

  • Gauge weights can be manipulated more frequently than intended

  • Voting power can be artificially amplified through timing

  • Time-weighted average calculations become less reliable

Proof of Concept

// Attacker contract
contract GaugeManipulator {
GaugeController public controller;
function manipulateVotes(address gauge) external {
// Day 1: Vote maximum weight
controller.vote(gauge, 10000);
// Day 2: Wait minimum delay and flip vote
// This can be repeated daily instead of every 10 days
controller.vote(gauge, 0);
}
}

Recommendation

Implement consistent vote delay enforcement:

function vote(address gauge, uint256 weight) external {
require(block.timestamp >= lastVoteTime[msg.sender] + VOTE_DELAY, "Must wait full delay");
require(weight >= MIN_VOTE_WEIGHT, "Weight too low");
// Add slope calculation for weight changes
uint256 oldWeight = userGaugeVote[msg.sender][gauge];
uint256 slope = (weight > oldWeight) ? weight - oldWeight : oldWeight - weight;
require(slope <= MAX_WEIGHT_SLOPE, "Change too large");
userGaugeVote[msg.sender][gauge] = weight;
lastVoteTime[msg.sender] = block.timestamp;
emit VoteCast(msg.sender, gauge, weight, slope);
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 6 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 6 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.