QuantAMM

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

OOB array access in `QuantAMMVarianceBasedRule::_calculateQuantAMMVariance` for vector lambda(λ)

Summary

The QuantAMMVarianceBasedRule::_calculateQuantAMMVariance function is DoSed for pools with an odd number of tokens and a vector lambda(λ) parameter due to out of bounds(OOB) array access

Vulnerability Details

In QuantAMMVarianceBasedRule::_calculateQuantAMMVariance,

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;
//...SNIP...
} else {
//vector parameter calculation is the same but we have to keep track of and access the right vector parameter
for (uint i; i < locals.nMinusOne; ) {
unchecked {
locals.convertedLambda = int256(_poolParameters.lambda[i]);
locals.oneMinusLambda = ONE - locals.convertedLambda;
}
// ...SNIP...
unchecked {
i += 2;
++locals.storageIndex;
}
}
if (locals.notDivisibleByTwo) {
unchecked {
@> ++locals.nMinusOne;
locals.convertedLambda = int256(_poolParameters.lambda[locals.nMinusOne]);
locals.oneMinusLambda = ONE - locals.convertedLambda;
}
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];
}
}
return locals.finalState;
}

When number of tokens is odd (for vector lambda(λ) calculation) we see that nMinusOne is incremented before accessing the arrays, this is done to set the variable to the last token index, however, the nMinusOne variable is already at the last token index as we see from line 62

locals.nMinusOne = locals.n - 1;

This means that the increment will cause nMinusOne to exceed the the arrays bounds, DoSing the function.

Impact

High - permanent DOS for vector lambda(λ) pools with odd number of tokens

Tools Used

Manual Review

Recommendations

No need for an increment as nMinusOne is already at the last token index

Updates

Lead Judging Commences

n0kto Lead Judge 10 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.