QuantAMM

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

Weight Multiplier Misalignment in QuantAMM's Multi-Token Pools Leads to Systematic Price Curve Distortion

Summary

A vulnerability has been identified in the _splitWeightAndMultipliers function of the QuantAMMWeightedPool contract. The function incorrectly maps multipliers to weights for tokens beyond the first four positions in multi-token pools.

The function accepts an input array structured as:
[w1,w2,w3,w4,w5,w6,w7,w8,m1,m2,m3,m4,m5,m6,m7,m8]

And attempts to reorganize it into two arrays structured as:
[w1,w2,w3,w4,m1,m2,m3,m4] and [w5,w6,w7,w8,m5,m6,m7,m8]

However, the current implementation contains a critical error in its multiplier mapping logic:

https://github.com/Cyfrin/2024-12-quantamm/blob/a775db4273eb36e7b4536c5b60207c9f17541b92/pkg/pool-quantamm/contracts/QuantAMMWeightedPool.sol#L743

uint256 i4 = i + 4;
splitWeights[1][i] = weights[i4]; // Gets weight
splitWeights[1][i + moreThan4Tokens] = weights[i4 + tokenLength]; // Incorrect multiplier mapping

When mapping multipliers for tokens 5-8, the function uses an incorrect offset (i4 + tokenLength) to locate multipliers in the source array. This mathematical error means that for each token index i beyond the first four tokens, its multiplier is being read from position (i + 4) + tokenLength instead of the correct position tokenLength + (i + 4).

For example, in an 8-token pool setup, when attempting to read the multiplier for token 5 (i=0 in the second loop), the function incorrectly reads from position 12 (4 + 0 + 8) instead of position 13 (8 + 4 + 0). This offset error cascades through all remaining tokens, causing a systematic misalignment between weights and their corresponding multipliers.

This misalignment propagates through the pool's core pricing mechanism since weight calculations directly influence the spot price between any two tokens in the pool via the weighted geometric mean formula. The error compounds over time through the weight interpolation mechanism, where each block's actual weight is calculated using these mismatched multipliers. This creates a compounding deviation from the intended weight trajectory, leading to systematic mispricing in any swap involving tokens 5-8 and incorrect valuation of liquidity providers' pool shares.

The severity is amplified by the contract's role in automated market making, where each mispriced trade creates an opportunity for arbitrage against the intended pool behavior, potentially draining value from liquidity providers through mathematically incorrect price curves.

Recommended Mitigation Steps

  1. Modify the multiplier mapping logic in the second loop to correctly access multiplier positions:

function _splitWeightAndMultipliers(
int256[] memory weights
) internal pure returns (int256[][] memory splitWeights) {
uint256 tokenLength = weights.length / 2;
splitWeights = new int256[][]();
splitWeights[0] = new int256[]();
splitWeights[1] = new int256[]();
// Handle first 4 weights and their multipliers
for (uint i; i < 4; ) {
splitWeights[0][i] = weights[i];
splitWeights[0][i + 4] = weights[i + tokenLength];
unchecked { i++; }
}
// Handle remaining weights and their multipliers
uint256 moreThan4Tokens = tokenLength - 4;
for (uint i = 0; i < moreThan4Tokens; ) {
splitWeights[1][i] = weights[i + 4]; // Get weight
splitWeights[1][i + moreThan4Tokens] = weights[i + 4 + tokenLength]; // Get corresponding multiplier
unchecked { i++; }
}
}
  1. Add input validation:

require(weights.length % 2 == 0, "Invalid weights array length");
require(weights.length >= 16, "Insufficient weights and multipliers");
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.