QuantAMM

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

Loss of Precision in _calculateQuantAMMVariance

Summary

Vulnerability Details

The _calculateQuantAMMVariance function calculates the variance based on the provided price data (_newData), the moving average of previous prices (_poolParameters.movingAverage), and a smoothing factor (lambda). The calculation involves updating an intermediate variance state (locals.intermediateVarianceState) for each asset in the pool.

The problematic line of code updates this intermediate state by adding two terms:

  1. locals.convertedLambda.mul(locals.intermediateVarianceState[i]): This term represents the weighted contribution of the previous variance state.

  2. (_newData[i] - _poolParameters.movingAverage[locals.n + i]).mul(_newData[i] - _poolParameters.movingAverage[i]).div(TENPOWEIGHTEEN): This term represents the contribution of the current price deviation from the moving average. It's in this term that the precision loss occurs.


https://github.com/Cyfrin/2024-12-quantamm/blob/a775db4273eb36e7b4536c5b60207c9f17541b92/pkg/pool-quantamm/contracts/rules/base/QuantammVarianceBasedRule.sol#L81C1-L86C1

The division by TENPOWEIGHTEEN (10^18) is performed after the multiplication of (_newData[i] - _poolParameters.movingAverage[locals.n + i]) and (_newData[i] - _poolParameters.movingAverage[i]). If the product of these two differences is significantly smaller than 10^18, the subsequent division will truncate the fractional part of the result, leading to a loss of precision. This loss accumulates over time and can significantly affect the accuracy of the calculated variance.

Impact

Let's illustrate with an example. Assume:

  • (_newData[i] - _poolParameters.movingAverage[locals.n + i]) = 10^15

  • (_newData[i] - _poolParameters.movingAverage[i]) = 10^15

Then their product is 10^30. Dividing by TENPOWEIGHTEEN (10^18) yields 10^12.

However, if the division were performed before the multiplication, as in:

content_copyaddcompare_arrowsopen_in_full(_newData[i] - _poolParameters.movingAverage[locals.n + i]).div(TENPOWEIGHTEEN).mul(_newData[i] - _poolParameters.movingAverage[i])

The result would be much closer to the true value, preserving more significant digits and reducing the accumulated error over time.

Tools Used

manual

Recommendations

The choice between dividing the first or second term by TENPOWEIGHTEEN should be carefully considered based on the expected magnitudes of _newData and _poolParameters.movingAverage

Updates

Lead Judging Commences

n0kto Lead Judge 7 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity
Assigned finding tags:

Informational or Gas / Admin is trusted / Pool creation is trusted / User mistake / Suppositions

Please read the CodeHawks documentation to know which submissions are valid. If you disagree, provide a coded PoC and explain the real likelyhood and the detailed impact on the mainnet without any supposition (if, it could, etc) to prove your point.

Support

FAQs

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