Core Contracts

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

Incorrect Voting Power Value Used When Voting in GaugeController

Summary

The GaugeController contract uses balanceOf() instead of getVotingPower() to determine user voting weights, causing voting power to not properly decay with time as intended in the vote-escrow model.

Impact:

HIGH

  • Users' voting power does not decay linearly with time as intended

  • Undermines the vote-escrow mechanism where voting power should decrease as lock expiration approaches

  • Allows for disproportionate voting influence with nearly expired locks

Details

GaugeController:L194

// In GaugeController.sol
function vote(address gauge, uint256 weight) external override whenNotPaused {
// ...
uint256 votingPower = veRAACToken.balanceOf(msg.sender); // @audit uses static balance instead of decaying power
if (votingPower == 0) revert NoVotingPower();
// ...
}

The issue is that balanceOf() returns the raw locked amount, while getVotingPower() returns the time-weighted voting power that properly decays:

// In veRAACToken.sol
function balanceOf(address account) public view override returns (uint256) {
return _balances[account]; // Static balance
}
function getVotingPower(address account) public view returns (uint256) {
return _votingState.getCurrentPower(account, block.timestamp); // Time-decaying power
}

Recommended Fix:

function vote(address gauge, uint256 weight) external override whenNotPaused {
if (!isGauge(gauge)) revert GaugeNotFound();
if (weight > WEIGHT_PRECISION) revert InvalidWeight();
// Use getVotingPower instead of balanceOf
uint256 votingPower = veRAACToken.getVotingPower(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);
}

References

  • Curve's GaugeController implementation which properly uses time-decaying voting power

The fix should be prioritized as it impacts core governance functionality.

Updates

Lead Judging Commences

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

BaseGauge::_applyBoost, GaugeController::vote, BoostController::calculateBoost use balanceOf() instead of getVotingPower() for vote-escrow tokens, negating time-decay mechanism

Support

FAQs

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