QuantAMM

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

Precision Loss in Weight Normalization Leads to Pool Destabilization

Vulnerability Details

The QuantAMM protocol implements dynamic weight adjustment through various update rules (MomentumUpdateRule, AntimomentumUpdateRule, etc.) that inherit from the base QuantAMMGradientBasedRule contract. These rules adjust pool weights based on price movements and market signals to optimize pool performance.

The core weight adjustment mechanism relies on a normalization process to maintain proper weight balance across assets. This process is implemented in each rule's _getWeights() function, which calculates new weights using price gradients, moving averages, and rule-specific parameters.

An issue exists in the weight normalization implementation where division operations are performed before multiplication in fixed-point arithmetic calculations. In MomentumUpdateRule._getWeights():

MomentumUpdateRule.sol#L97-L105

if (locals.kappaStore.length == 1) {
locals.normalizationFactor /= int256(locals.prevWeightLength);
locals.res = _prevWeights[locals.i] +
locals.kappaStore[0].mul(locals.newWeights[locals.i] - locals.normalizationFactor);
}

This pattern appears across all update rules, creating systemic precision loss that compounds with each weight update cycle. In fixed-point arithmetic, performing division before multiplication can lose up to 18 decimal places of precision per operation. The lost precision accumulates through both the normalization calculations and subsequent weight adjustments.

Impact

High severity as precision loss compounds over time, leading to pool weight imbalances that can cause significant value loss for LPs through incorrect price calculations and arbitrage opportunities. The systemic nature affects all gradient-based rules and becomes more severe with frequent updates and multiple tokens.

Proof of Concept

Consider a two-token pool scenario:

  1. Initial setup:

    • Pool weights: [5e18, 5e18] (50-50 split)

    • Price gradients: [1e17, 2e17]

    • Kappa parameter: 1e17

  2. First update cycle:

    • normalizationFactor = (1e17 + 2e17) / 2 // Truncates to 1e17

    • weight[0] = 5e18 + 1e17 * (1e17 - 1e17) = 5e18

    • weight[1] = 5e18 + 1e17 * (2e17 - 1e17) = 5.1e18

    • // Total weights: 101%

  3. Subsequent updates compound the error:

    • Cycle 2: [5e18, 5.21e18] (102.1%)

    • Cycle 3: [5e18, 5.33e18] (103.3%)

    • Each cycle increases weight imbalance

  4. Impact materializes:

    • Pool invariant broken

    • Incorrect price calculations

    • Arbitrage opportunities emerge

    • LP value erosion accelerates

Tools Used

Manual Review

Recommendation

Restructure the weight normalization calculation to perform all multiplications before any division operations. This can be achieved by first accumulating the total weighted adjustments through multiplication, then performing a single division at the end for normalization, which will minimize precision loss and prevent the compounding of rounding errors across multiple update cycles.

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.

invalid_sum_of_weights_can_exceeds_one_no_guard

According the sponsor and my understanding, sum of weights does not have to be exactly 1 to work fine. So no real impact here. Please provide a PoC showing a realistic impact if you disagree. This PoC cannot contains negative weights because they will be guarded per clampWeights.

Support

FAQs

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