The code in the vote()
function does not check if the user’s total votes exceed 100% across all gauges. This allows users to over-allocate their voting power, leading to incorrect gauge weights.
The vote()
function in GaugeController
updates userGaugeVotes[msg.sender][gauge]
directly without adjusting other gauges the user might have voted on. The _updateGaugeWeight()
function then subtracts the old weight and adds the new one for that specific gauge. But there's no mechanism to track the sum of all the user's weights across all gauges.
While the function includes a check to ensure each individual vote weight doesn't exceed WEIGHT_PRECISION (10000, representing 100%), it lacks any mechanism to track or limit the sum of a user's votes across multiple gauges.
In a proper system, each vote should adjust the user's total allocated voting power. For example, when a user changes their vote from Gauge A to Gauge B, the system should subtract their old weight from A and add the new weight to B, ensuring the total doesn't exceed 100%. Without this check, users can allocate more than their available voting power, leading to incorrect gauge weights and manipulation of reward distributions.
Consider this attack scenario:
A user holds 100 veTokens (representing 100% voting power)
The user votes with weight 10000 (100%) for Gauge A
This allocates 100 weight points (10000 * 100 / 10000) to Gauge A
The same user then votes with weight 10000 (100%) for Gauge B
This allocates another 100 weight points to Gauge B
Result: The user has effectively allocated 200 weight points despite only having 100 veTokens worth of voting power
Over-voting distorts gauge weights, causing rewards to be distributed unfairly.
Manual Review
Add a mapping to track total allocated votes per user:
Modify the vote()
function to enforce total vote limits:
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.