Core Contracts

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

Incorrect Voting Power Calculation in GaugeController::vote Function

Summary

The vote function is responsible for allowing users to assign voting weight to a gauge based on their veRAAC token balance. However, instead of using the getVotingPower function to calculate the user's actual locked voting power, the function incorrectly uses balanceOf(msg.sender).

Since balanceOf only checks the user's current balance and does not account for vesting or locked states, users can temporarily acquire veRAAC tokens, vote, and then return or transfer them, while their vote remains counted.

This introduces a vote manipulation vulnerability, where users can borrow, delegate, or transfer tokens solely for the purpose of voting, thus inflating their influence unfairly.

Vulnerability Details

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); // ❌ Incorrect function used
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);
}

The function incorrectly retrieves the user's voting power by calling balanceOf(msg.sender).

balanceOf only returns the current transferable balance but does not check if the tokens are actually locked (which is required for voting).

The function should use getVotingPower(msg.sender), which considers only locked veRAAC tokens.

A user can borrow veRAAC tokens, vote, and then return them, retaining the vote despite no longer holding any tokens. Since there is no verification that tokens remain locked, voting power is artificially inflated.

Impact

Users can temporarily acquire veRAAC tokens, vote, and return them, manipulating voting outcomes.

Tools Used

Manual Review

Recommendations

Use getVotingPower Instead of balanceOf

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.