Core Contracts

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

gauge's weight will be updated to incorrect values, sometimes will even revert due to flawed calculations

Summary

gauge's weight will be updated to incorrect values, sometimes will even revert due to flawed calculations

Vulnerability Details

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);
emit WeightUpdated(gauge, oldWeight, weight);
}
function _updateGaugeWeight(
address gauge,
uint256 oldWeight,
uint256 newWeight,
uint256 votingPower
) internal {
Gauge storage g = gauges[gauge];
uint256 oldGaugeWeight = g.weight;
uint256 newGaugeWeight = oldGaugeWeight - (oldWeight * votingPower / WEIGHT_PRECISION)
+ (newWeight * votingPower / WEIGHT_PRECISION);
g.weight = newGaugeWeight;
g.lastUpdateTime = block.timestamp;
}

When the user vote, related gauge's weight will be updated. During the update, the user's old gauge weight is subtracted first, and then add the user's new gauge weight. The user's old gauge weight is calculated based on the user's current votingPower, not the user's old votingPower, this may cause 'oldGaugeWeight - (oldWeight * votingPower / WEIGHT_PRECISION)' revert.

Please refer to the following steps for POC:

1, create a new gauge;

2, userA vote to this gauge, weight = 5000, voting power = 100, gauge.weight = (5000 * 100) / 10000 = 50.

3, userA get more voting power, veRAACToken.balanceOf(userA)=200.

4, userA vote again to this gauge, weight = 9000, voting power = 200, for GaugeController.sol#L222, since gauge.weight = 50, (oldWeight votingPower / WEIGHT_PRECISION) = (5000 * 200)/10000 = 100, 50 < 100, will revert.

Impact

gauge's weight will be update to incorrect values, sometimes will even revert.

Tools Used

manually reviewed

Recommendations

define userVotingPower to record user's voting power, and update gauge's weight accoring to user's voting power.

mapping(address => mapping(address => uint256)) public userVotingPower;
uint256 newGaugeWeight = oldGaugeWeight - (oldWeight * userVotingPower[msg.sender][gauge] / WEIGHT_PRECISION)
+ (newWeight * votingPower / WEIGHT_PRECISION);
userVotingPower[msg.sender][gauge] = votingPower;
Updates

Lead Judging Commences

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

GaugeController::_updateGaugeWeight uses current voting power for both old and new vote calculations, causing underflows when voting power increases and incorrect gauge weights

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

GaugeController::_updateGaugeWeight uses current voting power for both old and new vote calculations, causing underflows when voting power increases and incorrect gauge weights

Support

FAQs

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