QuantAMM

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

Failure in `_calculateQuantAMMVariance` Function While Handling Odd Number of Assets

Title

Failure in _calculateQuantAMMVariance Function While Handling Odd Number of Assets

Summary

The _calculateQuantAMMVariance function contains an error when handling pools with an odd number of assets. Specifically, it fails to decrement locals.nMinusOne when lambda is a vector, unlike when lambda is a scalar. This inconsistency results in an out-of-bounds error, causing a Denial of Service (DoS) in operations like CalculateNewWeights.

Vulnerability Details

The _calculateQuantAMMVariance function in the QuantammVarianceBasedRule contract is responsible for computing:

  1. The new intermediate state for the variance update.

  2. The new variances vector based on the intermediate state.

Here's the implementation:

function _calculateQuantAMMVariance(
int256[] memory _newData,
QuantAMMPoolParameters memory _poolParameters
) internal returns (int256[] memory) {
QuantAMMVarianceLocals memory locals;
locals.n = _poolParameters.numberOfAssets;
locals.finalState = new int256[](locals.n);
locals.intermediateVarianceState = _quantAMMUnpack128Array(
intermediateVarianceStates[_poolParameters.pool],
locals.n
);
locals.nMinusOne = locals.n - 1;
locals.notDivisibleByTwo = locals.n % 2 != 0;
locals.convertedLambda = int256(_poolParameters.lambda[0]);
locals.oneMinusLambda = ONE - locals.convertedLambda;
//the packed int256 slot index to store the intermediate variance state
if (_poolParameters.lambda.length == 1) {
//scalar parameters mean the calculation is simplified and even if it increases function and
//contract size it decrease gas computed given iterative design tests
if (locals.notDivisibleByTwo) {
unchecked {
--locals.nMinusOne;
}
}
...
if (locals.notDivisibleByTwo) {
unchecked {
++locals.nMinusOne;
}
locals.intermediateState =
locals.convertedLambda.mul(locals.intermediateVarianceState[locals.nMinusOne]) +
(_newData[locals.nMinusOne] - _poolParameters.movingAverage[locals.n + locals.nMinusOne])
.mul(_newData[locals.nMinusOne] - _poolParameters.movingAverage[locals.nMinusOne])
.div(TENPOWEIGHTEEN); // p(t) - p̅(t - 1))_i * (p(t) - p̅(t))_i
locals.intermediateVarianceState[locals.nMinusOne] = locals.intermediateState;
locals.finalState[locals.nMinusOne] = locals.oneMinusLambda.mul(locals.intermediateState);
intermediateVarianceStates[_poolParameters.pool][locals.storageIndex] = locals
.intermediateVarianceState[locals.nMinusOne];
}
} else {
//vector parameter calculation is the same but we have to keep track of and access the right vector parameter
...
if (locals.notDivisibleByTwo) {
unchecked {
++locals.nMinusOne;
locals.convertedLambda = int256(_poolParameters.lambda[locals.nMinusOne]);
locals.oneMinusLambda = ONE - locals.convertedLambda;
}
...
}
}
return locals.finalState;
}

Root Cause
When lambda is a scalar and the pool has an odd number of assets, locals.nMinusOne is correctly decremented to handle the odd index.
However, when lambda is a vector, the same decrement is not applied, leading to a discrepancy.
This results in an out-of-bounds error when the function attempts to access _poolParameters.lambda[locals.nMinusOne].

Impact

  1. Denial of Service (DoS):
    The function fails with an out-of-bounds revert, disrupting critical operations such as CalculateNewWeights.
    Pools with odd-numbered assets and vector lambda are especially vulnerable.

  2. Operational Failures:
    Any operations relying on _calculateQuantAMMVariance will fail, rendering the pool unable to dynamically adjust weights or perform variance updates.

Tools Used

Manual Review

Recommendations

To resolve the issue, add a decrement for locals.nMinusOne when lambda is a vector, ensuring consistent behavior.

Updates

Lead Judging Commences

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

finding_calculateQuantAMMVariance_revert_when_vector_lambda_and_odd_asset_number

Likelihood: Medium/High, odd asset number + lambda is a vector. Impact: Medium/High, DoS the update.

Support

FAQs

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