QuantAMM

QuantAMM
49,600 OP
View results
Submission Details
Severity: medium
Valid

Incorrect implementation of QuantammMathGuard.sol#_clampWeights.

Summary

In the contract QuantammMathGuard.sol, _clampWeights is implemented wrongly, causing the sum of _weights to be larger than 1 and some weights will be larger than absoluteMax.

Vulnerability Details

The function _clampWeights is used to limit the weights to ensure that each weight does not exceed the predefined minimum and maximum values after being updated. In the implementation, two variables are crucial, namely sumRemainerWeight and sumOtherWeights.

for (uint i; i < weightLength; ++i) {
if (_weights[i] < absoluteMin) {
_weights[i] = absoluteMin;
sumRemainerWeight -= absoluteMin;
} else if (_weights[i] > absoluteMax) {
_weights[i] = absoluteMax;
sumOtherWeights += absoluteMax;
}
}
if (sumOtherWeights != 0) {
int256 proportionalRemainder = sumRemainerWeight.div(sumOtherWeights);
for (uint i; i < weightLength; ++i) {
if (_weights[i] != absoluteMin) {
_weights[i] = _weights[i].mul(proportionalRemainder);
}
}
}

The variable sumRemainerWeight is used to calculate the target value of the sum of the remaining weights(except those below the _absoluteWeightGuardRail). And the variable sumOtherWeights is used to calculate the actual value of the sum of the remaining weights. Later, variable proportionalRemainder is calculated and the role of the variable proportionalRemainder is to scale other weights so that their sum is sumRemainerWeight.

Let me take a example where _absoluteWeightGuardRail = 0.2 and _weights = [0.15, 0.45, 0.15, 0.25]. So the absoluteMin = 0.2 and absoluteMax = 0.4 (1-0.2*3).

(1) For the first weight 0.15, _weights[0] = 0.2 and sumRemainerWeight = 0.8.

(2) For the second weight 0.45, _weights[1] = 0.4 and sumOtherWeights = 0.4.

(3) For the third weight 0.15, _weights[2] = 0.2 and sumRemainerWeight = 0.6.

(4) For the fouth weight 0.25, _weights[3] = 0.25.

So the sumRemainerWeight = 0.6 and sumOtherWeights = 0.4, which calculates the proportionalRemainder = 1.5.

After updating, the _weights will be [0.2, 0.6, 0.2, 0.375], which is amazing!!!

So what's the problem? The answer is that the variable sumOtherWeights is not calculated properly. It leaves out all weights that do not exceed absoluteMax, causing its value to be much smaller than expected.

In the example above, sumOtherWeights should be 0.4+0.25=0.65 and proportionalRemainder will be 12/13. Finally, _weights will be [0.2, 0.37, 0.2, 0.23] whose sum is 1.

Impact

The function _clampWeights will calculate incorrect weights, which will break the core functionality of the protocol.

Tools Used

VScode

Recommendations

The correct implementation should be as follows

for (uint i; i < weightLength; ++i) {
if (_weights[i] < absoluteMin) {
_weights[i] = absoluteMin;
sumRemainerWeight -= absoluteMin;
} else if (_weights[i] > absoluteMax) {
_weights[i] = absoluteMax;
sumOtherWeights += absoluteMax;
} else {
+++ sumOtherWeights += _weights[i];
}
}
Updates

Lead Judging Commences

n0kto Lead Judge 10 months ago
Submission Judgement Published
Validated
Assigned finding tags:

finding_clampWeights_normalizeWeightUpdates_incorrect_calculation_of_sumOtherWeights_proportionalRemainder

Likelihood: Medium/High, when a weight is above absoluteMax. Impact: Low/Medium, weights deviate much faster, and sum of weights also.

Support

FAQs

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

Give us feedback!