Summary
Users voting power is not decreased after voting for a gauge, allowing users to simply use all their voting power for as many gauge as they want at the same time.
Vulnerability Details
As we can see in the public and unrestricted vote()
function, while users votes are registered for a specific gauge L197
, users voting power is not decreased.
This means users can vote for another gauge, and at the end distribute more votes than they own.
File: contracts/core/governance/gauges/GaugeController.sol
190: function vote(address gauge, uint256 weight) external override whenNotPaused {
191: if (!isGauge(gauge)) revert GaugeNotFound();
192: if (weight > WEIGHT_PRECISION) revert InvalidWeight();
193:
194: uint256 votingPower = veRAACToken.balanceOf(msg.sender);
195: if (votingPower == 0) revert NoVotingPower();
196:
197: uint256 oldWeight = userGaugeVotes[msg.sender][gauge];
198: userGaugeVotes[msg.sender][gauge] = weight;
199:
200: _updateGaugeWeight(gauge, oldWeight, weight, votingPower);
201:
202: emit WeightUpdated(gauge, oldWeight, weight);
203: }
Impact
Duplication of voting power.
Recommendations
Add a mapping to register how many votes have been distributed by each user, and ensure its never above their vote balance:
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();
+ if(userAllocatedVotes[msg.sender] > votingPower) revert NoVotingPower();
uint256 oldWeight = userGaugeVotes[msg.sender][gauge];
+ if(weight == oldWeight) revert VotesHasNotChanged() ;
userGaugeVotes[msg.sender][gauge] = weight;
+ uint256 delta;
+ if(weight > oldWeight)
+ delta = weight - oldWeight;
+ userAllocatedVotes[msg.sender] += delta;
+ else
+ delta = oldWeight - weight;
+ userAllocatedVotes[msg.sender] -= delta;
_updateGaugeWeight(gauge, oldWeight, weight, votingPower);
emit WeightUpdated(gauge, oldWeight, weight);
}