Summary
GaugeController.sol
contract defines a vote delay mechanism but fails to enforce it, allowing users to vote multiple times in rapid succession, potentially manipulating gauge weights and reward distributions.
Vulnerability Details
uint256 public constant VOTE_DELAY = 10 days;
mapping(address => uint256) public lastVoteTime;
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];
userGaugeVotes[msg.sender][gauge] = weight;
_updateGaugeWeight(gauge, oldWeight, weight, votingPower);
emit WeightUpdated(gauge, oldWeight, weight);
}
Impact
Users can vote multiple times without any time restriction
Potential for vote manipulation and reward distribution attacks
Undermines the entire voting mechanism's fairness
Could lead to unfair resource allocation in the protocol
Tools Used
Recommendations
function vote(address gauge, uint256 weight) external override whenNotPaused {
if (!isGauge(gauge)) revert GaugeNotFound();
if (weight > WEIGHT_PRECISION) revert InvalidWeight();
if (block.timestamp < lastVoteTime[msg.sender] + VOTE_DELAY)
revert VotingDelayNotElapsed();
uint256 votingPower = veRAACToken.balanceOf(msg.sender);
if (votingPower == 0) revert NoVotingPower();
uint256 oldWeight = userGaugeVotes[msg.sender][gauge];
userGaugeVotes[msg.sender][gauge] = weight;
_updateGaugeWeight(gauge, oldWeight, weight, votingPower);
lastVoteTime[msg.sender] = block.timestamp;
emit WeightUpdated(gauge, oldWeight, weight);
}
error VotingDelayNotElapsed();