QuantAMM

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

Incorrect calculation in `QuantAMMMathGuard._clampWeights`

Summary

The QuantAMMMathGuard._clampWeights function should prevent _weights being less than absoluteWeightGuardRail value and more than absoluteMax value. The problem is the sumOtherWeights does not include weights which were not adjusted. This way the proportionalRemainder might exceed ONE which causes some _weights exceeds absoluteMax and the sum of weights exceeds ONE. At the same time the _normalizeWeightUpdates function can catch only small rounding errors.

Vulnerability Details

Let we have three tokens with _weights[0] < absoluteMin, _weights[1] > absoluteMax and absoluteMin < _weights[2] < absoluteMax.
When using the functional implementation we will receive:

absoluteMax = ONE - 2 * absoluteMin

proportionalRemainder = (ONE - absoluteMin) / (ONE - 2 * absoluteMin)

This way the proportionalRemainder > ONE. So the _weights[1] = absoluteMax * proportionalRemainder > absoluteMax.

function _clampWeights(
int256[] memory _weights,
int256 _absoluteWeightGuardRail
) internal pure returns (int256[] memory) {
unchecked {
uint weightLength = _weights.length;
if (weightLength == 1) {
return _weights;
}
int256 absoluteMin = _absoluteWeightGuardRail;
int256 absoluteMax = ONE -
(PRBMathSD59x18.fromInt(int256(_weights.length - 1)).mul(_absoluteWeightGuardRail));
int256 sumRemainerWeight = ONE;
int256 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;//@audit should include weights which were not adjusted
}
}
if (sumOtherWeights != 0) {
>> int256 proportionalRemainder = sumRemainerWeight.div(sumOtherWeights);
for (uint i; i < weightLength; ++i) {
if (_weights[i] != absoluteMin) {
_weights[i] = _weights[i].mul(proportionalRemainder);
}
}
}
}
return _weights;
}

Impact

Unexpected behavior, incorrect rebalancing, invariants breaking. Potential asset losses.

Tools used

Manual Review

Recommendations

Consider including weights which were not adjusted in the sumOtherWeights variable:

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;//@audit should include weights which were not adjusted
- }
+ } 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.