Core Contracts

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

Missing Update of User's Gauge Vote Weight in `vote` Function

Summary

In the GaugeController contract, the vote function allows users to allocate weight to a gauge. However, the mapping that should track the user's previous vote weight (userGaugeVotes[msg.sender][gauge]) is never updated after a vote. As a result, each vote is treated as if the user has no previous vote, enabling them to repeatedly vote and inflate the gauge's weight artificially.

Vulnerability Details

What Went Wrong:
The vote function includes the following code:

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];
_updateGaugeWeight(gauge, oldWeight, weight, votingPower);
emit WeightUpdated(gauge, oldWeight, weight);
}

The variable oldWeight is meant to capture the user's previous vote weight so that the gauge's total weight can be adjusted by subtracting the old value and adding the new one. However, the mapping userGaugeVotes[msg.sender][gauge] is never updated after the vote. This means oldWeight is always zero, and the gauge weight update simplifies to:

newGaugeWeight = oldGaugeWeight + (newWeight * votingPower / WEIGHT_PRECISION);

Consequently, users can repeatedly cast votes with non-zero weights and continuously add to the gauge's weight without any subtraction of prior votes.

Why It Matters:
Since gauge weight directly influences reward allocation, this flaw allows a malicious user to inflate the gauge's weight arbitrarily by continuously voting. This manipulation can divert rewards away from honest participants, undermining the fairness of the voting and reward distribution system.

Example Scenario

User Scenario:
Initial Vote: A user votes with a weight of 5000. Ideally, userGaugeVotes[user][gauge] should record 5000, but it remains 0.
Subsequent Vote: The user votes again with a weight of 5000. Since the previous vote was not recorded, the system treats this as an additional 5000 weight.
Result: By repeating this process, the user can inflate the gauge's weight repeatedly, thereby capturing a larger share of rewards.

Impact

Unfair Reward Distribution:
Inflated gauge weights lead to disproportionate rewards for the manipulated gauge, disadvantaging other participants.

Economic Imbalance:
The manipulation skews the reward distribution mechanism, potentially leading to a concentration of rewards among a few malicious users.

Governance Risk:
Excessive gauge weight could influence governance decisions, allowing attackers to exert undue control over protocol parameters and decisions.

Tools Used

Manual Code Review: We analyzed the vote function and the corresponding _updateGaugeWeight logic, identifying that the userGaugeVotes mapping is never updated, allowing repeated inflation of gauge weight.

Recommendations

Update the Vote Mapping:
After processing a vote, update the user's vote weight in the mapping to reflect the new value:
solidity
Copy
Edit
userGaugeVotes[msg.sender][gauge] = weight;
Implement Voting Limits:
Consider adding additional checks to prevent abuse, such as limits on the frequency or cumulative weight a user can assign to a single gauge.

Updates

Lead Judging Commences

inallhonesty Lead Judge
8 months ago
inallhonesty Lead Judge 7 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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

Give us feedback!