QuantAMM

QuantAMM
49,600 OP
View results
Submission Details
Severity: high
Invalid

Flawed Logic in _normalizeWeightUpdates() breaks guardrail and wrong calculation of weights

Summary

Logic in _normalizeWeightUpdates() is flawed. In the UpdateRule.sol file CalculateNewWeights() function calculates the weights. It calls _getWeights() function which is specific to the rule to calculate the updated weights. These weights are unguarded and it will call _guardQuantAMMWeights() as a last function to guard the weights or to make it in limit. This _guardQuantAMMWeights() function contains two functions _clampWeights() to see if the weights go beyond the maximum/minimum weights and another is
_normalizeWeightUpdates() to reduce even further if the weight change is beyond the allowed "speed limit". Logic inside the _normalizeWeightUpdates allows to set the negative weights(Added PoC). These negative weights will be sent back to the CalculateNewWeights() function which sends these weights to _performUpdateAndGetData() function which again calls _calculateMultiplierAndSetWeights() which calls setWeights and set this weights to the pool.

Negative Weight is not allowed in balancer. Negative weights would imply a negative value or debt associated with a token, which is not supported in Balancer’s design. Each token must contribute positively to the pool's total value.

Proof Of Code

function testWeightGuards5TokensClamped3() public view {
int256[] memory prevWeights = new int256[]();
prevWeights[1] = 0.1e18;
prevWeights[2] = 0.1e18;
prevWeights[3] = 0.1e18;
prevWeights[0] = 0.1e18;
prevWeights[4] = 0.6e18;
int256[] memory newWeights = new int256[]();
newWeights[1] = 0.08e18;
newWeights[2] = 0.2e18;
newWeights[3] = 0.05e18;
newWeights[0] = 0.05e18;
newWeights[4] = 0.62e18;
int256 epsilonMax = 0.1e18;
int256 absoluteWeightGuardRail = 0.1e18;
int256[] memory res = mockQuantAMMMathGuard.mockGuardQuantAMMWeights(
newWeights,
prevWeights,
epsilonMax,
absoluteWeightGuardRail
);
console.logInt(res[0]);
console.logInt(res[1]);
console.logInt(res[2]);
console.logInt(res[3]);
console.logInt(res[4]);
}

To test it paste this code inside MathGuard.t.sol file.

Output = -7.5e16, 1e17, 2e17, 1e17, 6.75e17

Now these negative weights will be saved in the pool. When the users calls calculateBlockNormalisedWeight() to get the current weight it converts negative int to unit without proper check

function calculateBlockNormalisedWeight(
int256 weight,
int256 multiplier,
uint256 timeSinceLastUpdate
) internal pure returns (uint256) {
int256 multiplierScaled18 = multiplier * 1e18;
if (multiplier > 0) {
return uint256(weight) + FixedPoint.mulDown(uint256(multiplierScaled18), timeSinceLastUpdate);
} else {
//CYFRIN H02
return uint256(weight) - FixedPoint.mulUp(uint256(-multiplierScaled18), timeSinceLastUpdate);
}
}

Previous audit points for multiplier and fixed but here after converting negative integer of weight to uint256 will give completely wrong value of weight which will be much more high value. Hence wrong value of weights.

Impact

  1. Breaking the GuardRail

  2. Wrong calculation of the weights

Tools Used

Manual Review, Foundry

Recommendations

This test works correctly. Instead of removing extra weights from first element if removed from the highest weight it works properly

function testWeightGuards5TokensClamped2() public view {
int256[] memory prevWeights = new int256[]();
prevWeights[0] = 0.6e18;
prevWeights[1] = 0.1e18;
prevWeights[2] = 0.1e18;
prevWeights[3] = 0.1e18;
prevWeights[4] = 0.1e18;
int256[] memory newWeights = new int256[]();
newWeights[0] = 0.62e18;
newWeights[1] = 0.08e18;
newWeights[2] = 0.2e18;
newWeights[3] = 0.05e18;
newWeights[4] = 0.05e18;
int256 epsilonMax = 0.1e18;
int256 absoluteWeightGuardRail = 0.1e18;
int256[] memory res = mockQuantAMMMathGuard.mockGuardQuantAMMWeights(
newWeights,
prevWeights,
epsilonMax,
absoluteWeightGuardRail
);
console.logInt(res[0]);
console.logInt(res[1]);
console.logInt(res[2]);
console.logInt(res[3]);
console.logInt(res[4]);
}

Output = 5e17, 1e17, 2e17, 1e17, 1e17

Updates

Lead Judging Commences

n0kto Lead Judge 10 months ago
Submission Judgement Published
Invalidated
Reason: Lack of quality

Appeal created

atharv181 Submitter
10 months ago
n0kto Lead Judge
9 months ago
n0kto Lead Judge 9 months ago
Submission Judgement Published
Invalidated
Reason: Lack of quality

Support

FAQs

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