QuantAMM

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

Weight clamping function is broken and violates multiple invariants

Summary

The _clampWeights function in QuantAMMMathGuard contract is supposed to enforce individual weight bounds. However its implementation fails critically by violating two fundamental invariants: the total weight sum and maximum weight constraints. The function's rebalancing logic can paradoxically increase weights above their maximum allowed values while attempting to normalize them.

Vulnerability Details

Function _clampWeights in QuantAMMMathGuard is used every time new weights are calculated. Function docs state that:

/// @notice Applies guard rails (min value, max value) to weights and returns the normalized weights

Normalized weights means that their sum should be 1. Even if weights sum was not 1, at least ratio between weights should be correct.

Function implementation has 2 main parts - clamping part and rebalancing part. Problem is in broken rebalancing logic. It can totally distort weight values in multiple ways:

  • weight sum can end up being >1

  • weight can go way outside of guardrails

  • ratio between weights can get totally distorted

Consider this example of 5-asset pool weights, which showcases critical outcome (note, e18 of every weight is omitted for print clarity):

Weights input: [0.61, 0.1, 0.1, 0.1, 0.09] (sum = 1)
absoluteWeightGuardRail = 0.1
-> absoluteMax = 1 - (5-1)*0.1 = 0.6
Expected output: 1st weight gets clamped down to 0.6, last weight gets clamped up to 0.1. Tiny difference (0.01 + 0.01) is rebalanced over other weights to keep the total sum of 1.
Step 1: Initial clamping
- 0.61 > 0.6: set to 0.6, sumOtherWeights = 0.6
- 0.1 = 0.1: keep as is
- 0.1 = 0.1: keep as is
- 0.1 = 0.1: keep as is
- 0.09 < 0.1: set to 0.1, sumRemainerWeight -= 0.1
Interim state: [0.6, 0.1, 0.1, 0.1, 0.1]
Step 2: Rebalancing (sumOtherWeights = 0.6)
sumRemainerWeight = 0.9 (1 - 0.1 for minimum weight)
proportionalRemainder = 0.9/0.6 = 1.5
Only 1st weight is scaled by 1.5, because others are at min weight
Final state after rebalancing:
[0.9, 0.1, 0.1, 0.1, 0.1] (sum = 1.3)

Issues demonstrated by the example:

  1. Total sum is 1.3, which is obviosuly greater than targeted sum of 1

  2. 1st weight is 0.9. That's way above absoluteMax of 0.6. And way worse than initial value of 0.61 which was supposed to be clamped to 0.6

  3. Weight ratios are totally distorted. While 1st weight is supposed to be ~6x the other weights, it actually ended up being 9x greater.

Impact

  • Critical violation of maximum weight constraint: weights can exceed their maximum bounds after rebalancing

  • Broken sum invariant: total weight can exceed 100%

  • Manipulation potential: attackers could exploit these violations for price manipulation

  • Protocol safety: breaks invariants that other contracts might rely on

Even though other parts of code might attempt re-normalization, _clampWeights can distort the weights and their ratios and introduce irreversible calculation mistakes.

Tools Used

Manual code review

Recommendations

Rewrite the rebalancing logic of _clampWeights that properly maintains invariants.

Updates

Lead Judging Commences

n0kto Lead Judge 11 months ago
Submission Judgement Published
Validated
Assigned finding tags:

finding_clampWeights_normalizeWeightUpdates_incorrect_calculation_of_sumOtherWeights_proportionalRemainder

Likelihood: Medium/High, when a weight is above absoluteMax. Impact: Low/Medium, weights deviate much faster, and sum of weights also.

Support

FAQs

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

Give us feedback!