The updated intermediate gradient states are stored at incorrect positions in the intermediateGradientStates array. This misalignment leads to corruption of the stored gradient states. Subsequent unpacking will yield incorrect values.
In the _calculateQuantAMMGradient function, the code handles two scenarios:
When the pool uses a scalar lambda (same lambda for all assets).
When the pool uses per-asset lambdas (different lambda for each asset).
The function attempts to optimize gas usage by processing two assets at a time and packing their intermediate gradient states into a single storage slot using the _quantAMMPackTwo128 function.
However, in the per-asset lambda scenario (when _poolParameters.lambda.length > 1), there is a critical indexing error when storing the updated intermediate gradient states back into the intermediateGradientStates mapping.
In the else block (handling per-asset lambdas), the code for storing the packed intermediate gradient states is:
Here, i is used as the index into the intermediateGradientStates array. However, i increments by 2 in each iteration of the loop (since we process two assets at a time). This indexing is incorrect because the intermediateGradientStates array is intended to store packed gradient states, and its length should be approximately half of the number of assets (plus one if the number of assets is odd).
In the corresponding if block (handling scalar lambda), the correct index locals.storageArrayIndex is used:
The locals.storageArrayIndex is correctly incremented by 1 in each loop iteration, which aligns with the storage array's size.
The updated intermediate gradient states are stored at incorrect positions in the intermediateGradientStates array.
Example:
Suppose we have a pool with 5 assets (numberOfAssets = 5) and per-asset lambdas. During the loop:
First Iteration (i = 0):
Process assets 0 and 1.
Store the packed gradient state at index i = 0 (expected storage index should be 0).
Second Iteration (i = 2):
Process assets 2 and 3.
Store the packed gradient state at index i = 2 (expected storage index should be 1).
Outcome:
The storage indices 0 and 2 are used, leaving storage index 1 unused.
The gradient state of assets 2 and 3 is stored at the wrong index, causing misalignment.
Inconsistent storage leads to incorrect unpacking in future calculations.
Subsequent calls to _calculateQuantAMMGradient will use corrupted intermediate gradient states, leading to erroneous gradient computations and potential divergence from expected behavior.
Manual Review
In the per-asset lambda (else) block, the code should use locals.storageArrayIndex instead of i when storing the packed intermediate gradient states.
// Corrected indexing when storing packed values in the per-asset lambda case
intermediateGradientStates[_poolParameters.pool][locals.storageArrayIndex] = _quantAMMPackTwo128(
locals.intermediateGradientState[i],
locals.secondIntermediateValue
);
// Ensure storageArrayIndex is incremented appropriately
unchecked {
i += 2;
++locals.storageArrayIndex;
}
Likelihood: Medium/High, assets>4, lambdas > 1. Impact: Medium/High, DoS update but pool works fine. Pool with 5 assets will use incorrect weights.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.