Summary
Users could vote more frequently than intended since the vote delay constraints are not being enforced despite being defined
Vulnerability Details
The GaugeController
contract defines the following constants:
uint256 public constant VOTE_DELAY = 10 days;
uint256 public constant MIN_VOTE_DELAY = 1 days;
uint256 public constant MAX_VOTE_DELAY = 10 days;
And maintains a mapping to track last vote times:
mapping(address => uint256) public lastVoteTime;
However, in the vote()
function implementation:
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);
}
it never enforces:
The minimum time that must elapse between votes (MIN_VOTE_DELAY
)
The standard voting delay period (VOTE_DELAY
)
The maximum allowed delay (MAX_VOTE_DELAY
)
Updates to the lastVoteTime
mapping
The intended 10-day delay between votes was likely designed to provide stability and prevent rapid changes in gauge weights. Without this enforcement, the governance system becomes unstable and unpredictable.
Impact
Users can vote repeatedly in quick succession, manipulating gauge weights and reward distributions more frequently than the protocol design intended
Tools Used
Manua Review
Recommendations
function vote(address gauge, uint256 weight) external override whenNotPaused {
// Existing checks
if (!isGauge(gauge)) revert GaugeNotFound();
if (weight > WEIGHT_PRECISION) revert InvalidWeight();
+ // Add vote delay enforcement
+ uint256 timeElapsed = block.timestamp - lastVoteTime[msg.sender];
+ if (timeElapsed < VOTE_DELAY) revert VoteDelayNotElapsed();
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);
+ // Update last vote time
+ lastVoteTime[msg.sender] = block.timestamp;
}
.