QuantAMM

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

The loop in function _calculateQuantAMMMovingAverage completes without correctly updating the moving averages, due to accessing the wrong indices.

Summary

https://github.com/Cyfrin/2024-12-quantamm/blob/a775db4273eb36e7b4536c5b60207c9f17541b92/pkg/pool-quantamm/contracts/rules/base/QuantammMathMovingAverage.sol#L23C5-L57C6

The function _calculateQuantAMMMovingAverage needs to use p̅(t - 1).

If the movingAverages array contains both p̅(t) and p̅(t - 1) concatenated, we must ensure we access the correct indices for p̅(t - 1)

The loop completes without correctly updating the moving averages, due to accessing the wrong indices. The movingAverages array contains both p̅(t) and p̅(t - 1) concatenated, but the function does not adjust the indices accordingly when accessing p̅(t - 1).

Vulnerability Details

https://github.com/Cyfrin/2024-12-quantamm/blob/a775db4273eb36e7b4536c5b60207c9f17541b92/pkg/pool-quantamm/contracts/rules/base/QuantammMathMovingAverage.sol#L23C5-L57C6

mapping and comment from @dev below:

mapping(address => int256[]) public movingAverages;

// this can be just the moving averages per token, or if prev moving average is true then it is [...moving averages, ...prev moving averages]

function _calculateQuantAMMMovingAverage(
int256[] memory _prevMovingAverage,
int256[] memory _newData,
int128[] memory _lambda,
uint _numberOfAssets
) internal pure returns (int256[] memory) {
int256[] memory newMovingAverage = new int256[]();
int256 convertedLambda = int256(_lambda[0]);
int256 oneMinusLambda = ONE - convertedLambda;
if (_lambda.length == 1) {
for (uint i; i < _numberOfAssets; ) {
// p̅(t) = p̅(t - 1) + (1 - λ)(p(t) - p̅(t - 1)) - see whitepaper
int256 movingAverageI = _prevMovingAverage[i];
newMovingAverage[i] = movingAverageI + oneMinusLambda.mul(_newData[i] - movingAverageI);
unchecked {
++i;
}
}
} else {
for (uint i; i < _numberOfAssets; ) {
unchecked {
convertedLambda = int256(_lambda[i]);
oneMinusLambda = ONE - convertedLambda;
}
int256 movingAverageI = _prevMovingAverage[i];
// p̅(t) = p̅(t - 1) + (1 - λ)(p(t) - p̅(t - 1))
newMovingAverage[i] = movingAverageI + oneMinusLambda.mul(_newData[i] - movingAverageI);
unchecked {
++i;
}
}
}
return newMovingAverage;
}
  • newMovingAverage: An array to store the new moving averages (p̅(t)) for each asset.

    int256[] memory newMovingAverage = new int256[]();
  • Lambda (λ): Can be scalar or a vector.

  • The function loops over each asset index i from 0 to n - 1.

for (uint i; i < _numberOfAssets; ) {
// Calculations
unchecked {
++i;
}
}

Accessing the Previous Moving Average

int256 movingAverageI = _prevMovingAverage[i];
  • Intended to Retrieve:

    • movingAverageI = p̅_i(t - 1)

  • Actual Behavior:

    • Since _prevMovingAverage contains the concatenated array [p̅(t), p̅(t - 1)]:

      • Indices 0 to n - 1 contain p̅(t)

      • Indices n to 2n - 1 contain p̅(t - 1)

    • Therefore, _prevMovingAverage[i] actually retrieves p̅_i(t), not p̅_i(t - 1).

** Calculating the New Moving Average**

  • Formula in Code:

    newMovingAverage[i] = movingAverageI + oneMinusLambda.mul(_newData[i] - movingAverageI);
  • With Incorrect movingAverageI:

    • Using movingAverageI = p̅_i(t) instead of p̅_i(t - 1).

The loop completes without correctly updating the moving averages, due to accessing the wrong indices.

We're incorrectly using p̅_i(t) in place of p̅_i(t - 1). This means the moving average does not progress correctly from step t - 1 to t. The moving averages remain unchanged or are incorrectly updated.

Impact

The loop completes without correctly updating the moving averages, due to accessing the wrong indices.

Tools Used

Manual Review

Recommendations

// Access p̅_i(t - 1), which is at index n + i
int256 movingAverageI = _prevMovingAverage[_numberOfAssets + i];

Updates

Lead Judging Commences

n0kto Lead Judge 10 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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

Give us feedback!