Core Contracts

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

Missing `lastVoteTime` Update in `GaugeController.vote` Function Leads to Repeated Voting.

Summary:

The vote function in the GaugeController contract does not update the lastVoteTime mapping for the voter. This omission allows users to vote repeatedly without respecting the intended VOTE_DELAY, potentially enabling voting exploits and undermining the governance mechanism.

Vulnerability Details:

The vote function is intended to allow veRAACToken holders to vote for gauges. A crucial part of the voting logic is the VOTE_DELAY, which is designed to prevent users from rapidly changing their votes and manipulating the gauge weights. The lastVoteTime mapping is supposed to track the time of a user's last vote, and the vote function will check this timestamp against the current block timestamp to enforce the VOTE_DELAY. However, while the vote function fails to update the lastVoteTime after a successful vote. This means that a user can vote, and then immediately vote again, as the lastVoteTime remains at zero.

function vote(address gauge, uint256 weight) external override whenNotPaused {
// ... other checks ...
uint256 votingPower = veRAACToken.balanceOf(msg.sender);
// ...
_updateGaugeWeight(gauge, oldWeight, weight, votingPower);
// @audit lastVoteTime of user is not updated <--- VULNERABILITY
emit WeightUpdated(gauge, oldWeight, weight);
}

Impact:

The failure to update lastVoteTime has the following negative consequences:

  • Vote Manipulation: Users can repeatedly vote for different gauges or change their vote weights without respecting the VOTE_DELAY. This can be used to manipulate gauge weights and unfairly influence reward distribution.

  • Protocol Instability: The lack of enforced vote delay can lead to unpredictable and volatile gauge weight fluctuations, making it difficult for the protocol to function as intended.

Proof of Concept:

  1. Alice has veRAACTokens and wants to vote for a gauge.

  2. Alice calls vote(gaugeAddress, weight1). The vote is successful.

  3. The lastVoteTime for Alice is not updated.

  4. Alice immediately calls vote(gaugeAddress, weight2) (or votes for a different gauge).

  5. The vote is successful again because the VOTE_DELAY check passes (since lastVoteTime is still its initial value).

  6. Alice can repeat steps 4 and 5 indefinitely, effectively bypassing the VOTE_DELAY and potentially manipulating gauge weights.

Tools Used:

  • Manual code review

Recommended Mitigation:

The vote function should be modified to update the lastVoteTime mapping after a successful vote. The following line should be added immediately before the emit WeightUpdated line:

function vote(address gauge, uint256 weight) external override whenNotPaused {
// ... other checks ...
uint256 votingPower = veRAACToken.balanceOf(msg.sender);
// ...
_updateGaugeWeight(gauge, oldWeight, weight, votingPower);
+ lastVoteTime[msg.sender] = block.timestamp; // Update lastVoteTime
emit WeightUpdated(gauge, oldWeight, weight);
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 7 months ago
Submission Judgement Published
Validated
Assigned finding tags:

GaugeController::vote never enforces VOTE_DELAY or updates lastVoteTime, allowing users to spam votes and manipulate gauge weights without waiting

inallhonesty Lead Judge 7 months ago
Submission Judgement Published
Validated
Assigned finding tags:

GaugeController::vote never enforces VOTE_DELAY or updates lastVoteTime, allowing users to spam votes and manipulate gauge weights without waiting

Support

FAQs

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

Give us feedback!