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 4 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 4 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.