Core Contracts

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

BaseGauge.sol uses the veToken balance of the users as their voting power

Summary

BaseGauge.sol incorrectly uses the veToken balance of the users as their voting power when voting on direction.

Vulnerability Details

In BaseGauge.sol, there is a function called voteDirection that allows veToken holders to vote on direction:

function voteDirection(uint256 direction) public whenNotPaused updateReward(msg.sender) {
if (direction > 10000) revert InvalidWeight();
uint256 votingPower = IERC20(IGaugeController(controller).veRAACToken()).balanceOf(msg.sender);
if (votingPower == 0) revert NoVotingPower();
totalVotes = processVote(
userVotes[msg.sender],
direction,
votingPower,
totalVotes
);
emit DirectionVoted(msg.sender, direction, votingPower);
}

The issue here is that this function uses the veToken balance of the user as the voting power rather than the actual voting power. In VE tokens, voting power and user balance are distinct concepts, as voting power is also influenced by the passage of time.

Currently, if a user's lock period has ended, they can still vote.

They can call voteDirection and vote based on their balance as voting power, withdraw their RAAC tokens from veRAAC, transfer those RAAC tokens to another account, lock them again with the new address, call voteDirection again, and essentially vote twice.
This happens because the lock period doesn't affect voting power, as it's based solely on the balance.

Impact

Users can double vote.

Tools Used

Manual Review

Recommendations

Use getVotingPower to get the users voting power:

function voteDirection(uint256 direction) public whenNotPaused updateReward(msg.sender) {
if (direction > 10000) revert InvalidWeight();
- uint256 votingPower = IERC20(IGaugeController(controller).veRAACToken()).balanceOf(msg.sender);
+ IveRAACToken veToken = IveRAACToken(address(IGaugeController(controller).veRAACToken()));
+ uint256 votingPower = veToken.getVotingPower(msg.sender, block.timestamp);
if (votingPower == 0) revert NoVotingPower();
totalVotes = processVote(
userVotes[msg.sender],
direction,
votingPower,
totalVotes
);
emit DirectionVoted(msg.sender, direction, votingPower);
}
Updates

Lead Judging Commences

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

BaseGauge::_applyBoost, GaugeController::vote, BoostController::calculateBoost use balanceOf() instead of getVotingPower() for vote-escrow tokens, negating time-decay mechanism

Support

FAQs

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

Give us feedback!