Core Contracts

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

GaugeController::vote allows to vote with less weight than minimum weight MIN_VOTE_WEIGHT leading to invariant breakage

Summary

GaugeController::vote allows to vote with less weight than minimum weight MIN_VOTE_WEIGHT leading to invariant breakage because it doesnt check that weight argument is >= MIN_VOTE_WEIGHT

Vulnerability Details

GaugeController defines MIN_VOTE_WEIGHT variable to define minimum weight allowed to vote in GaugeController::vote function:

/// @notice Minimum vote weight allowed
uint256 public constant MIN_VOTE_WEIGHT = 100; // 1% minimum vote

MIN_VOTE_WEIGHT variable define 1% as the minimum of user total weight to vote.
However vote function doesnt check that weight argument is >= than MIN_VOTE_WEIGHT:
In [1] it only checks that weight is not greather than 100% of user voting power:
Next in [2] and [3] it assigns and updates gauge weight

function vote(address gauge, uint256 weight) external override whenNotPaused {
if (!isGauge(gauge)) revert GaugeNotFound();
[1]> if (weight > WEIGHT_PRECISION) revert InvalidWeight();
//...
[2]> userGaugeVotes[msg.sender][gauge] = weight;
[3]> _updateGaugeWeight(gauge, oldWeight, weight, votingPower);

So, this leads to invariant breakage, allowing users to vote with arbitrary minimum weight values.

The following PoC shows the described scenario with:

  • User with voting power = 1000000000000000000 = 1e18

  • Gauge with initial weight = 0
    User calls GaugeController::vote with weight 0.01% ie
    GaugeController.vote(gauge, 1)\

Call succeeds leading to invariant breakage
After call,
gauge final weight = 100000000000000 (10e13)
ie user voted with 0.01% that is less than MIN_VOTE_WEIGHT
But minimum weight should be 10000000000000000 (1e15)

To run the PoC save the following code in test/unit/core/governance/gauges/GaugeController.test.js under "Weight Management" test cases:

it("It allows to vote with weight less than minimum weight", async () => {
await veRAACToken.connect(user2).burn(
user2.address,
ethers.parseEther("500")
)
await veRAACToken.mint(
user2.address,
ethers.parseEther("1")
)
console.log(
"[i] voting power user2\t",
await veRAACToken.getVotingPower(user2.address)
);
console.log(
"[i] balance for user2\t",
await veRAACToken.balanceOf(user2.address)
);
var weight_before = await gaugeController.getGaugeWeight(await rwaGauge.getAddress());
console.log("[i] weight before vote\t", weight_before);
await gaugeController.connect(user2).vote(
await rwaGauge.getAddress(),
1
)
var weight_after = await gaugeController.getGaugeWeight(await rwaGauge.getAddress());
console.log("[i] weight after vote\t", weight_after);
});

Start a node and Execute test with:

reset; npx hardhat test test/unit/core/governance/gauges/GaugeController.test.js --network localhost

Observe user could vote with weight power less than 1%

Impact

Severity: Lacks of check in GaugeController::vote weight argument allows breaking MIN_VOTE_WEIGHT invariant

Tools Used

Manual Review

Recommendations

Implement MIN_VOTE_WEIGHT check in GaugeController::vote

function vote(address gauge, uint256 weight) external override whenNotPaused {
console.log("======== GaugeController@vote =====");
if (!isGauge(gauge)) revert GaugeNotFound();
if (weight > WEIGHT_PRECISION) revert InvalidWeight();
@> if (weight < MIN_VOTE_WEIGHT) revert InvalidWeight();
Updates

Lead Judging Commences

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

GaugeController::vote lacks minimum weight validation, allowing votes below MIN_VOTE_WEIGHT (1%) despite documentation stating otherwise

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

GaugeController::vote lacks minimum weight validation, allowing votes below MIN_VOTE_WEIGHT (1%) despite documentation stating otherwise

Support

FAQs

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

Give us feedback!