QuantAMM

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

Integer Underflow in calculateBlockNormalisedWeight

Summary

Vulnerability Details

When multiplier is negative, the code calculates uint256(-multiplierScaled18). However, if FixedPoint.mulUp(uint256(-multiplierScaled18), timeSinceLastUpdate) results in a value larger than uint256(weight), the subsequent subtraction will lead to an underflow. Because of the implicit conversion from int256 weight to uint256 weight, weight cannot be negative, making an underflow possible.

function calculateBlockNormalisedWeight(
int256 weight,
int256 multiplier,
uint256 timeSinceLastUpdate
) internal pure returns (uint256) {
//multiplier is always below 1 which is int128, we multiply by 1e18 for rounding as muldown / 1e18 at the end.
int256 multiplierScaled18 = multiplier * 1e18;
if (multiplier > 0) {
return uint256(weight) + FixedPoint.mulDown(uint256(multiplierScaled18), timeSinceLastUpdate);
} else {
//CYFRIN H02
return uint256(weight) - FixedPoint.mulUp(uint256(-multiplierScaled18), timeSinceLastUpdate);
}
}

Impact

Imagine a token in the QuantAMM pool has the following parameters:

  • weight = 50 * 10**18 (representing a weight of 50)

  • multiplier = -2 * 10**16 (representing a multiplier of -0.02 or -2%, designed to decrease the weight over time)

Now, let's say some time has passed, and timeSinceLastUpdate is 3000 (this could represent seconds, blocks, or any relevant time unit).

Calculation Breakdown:

  1. multiplierScaled18 Calculation: multiplierScaled18 = multiplier * 1e18 = -2 * 10^16 * 10^18 = -2 * 10^34

  2. Inside the else Block (Negative Multiplier):

    • uint256(-multiplierScaled18): This converts the negative multiplierScaled18 to a large unsigned integer due to two's complement representation. Let's call this largeUnsignedValue.

    • FixedPoint.mulUp(largeUnsignedValue, timeSinceLastUpdate): This multiplies the large unsigned value by timeSinceLastUpdate (3000), resulting in an even larger unsigned integer. Let's call this hugeUnsignedValue.

    • uint256(weight): The original weight (50 * 10^18) is converted to an unsigned integer. Let's call this weightUnsigned.

    • weightUnsigned - hugeUnsignedValue: This is where the underflow occurs. hugeUnsignedValue is much larger than weightUnsigned. Subtracting a larger unsigned integer from a smaller one causes an underflow, wrapping around and resulting in a very large positive number.

Outcome:

Instead of the weight decreasing to a value around 44 * 10^18 (as would be expected with a -2% decrease over 3000 time units), the function returns a massive, incorrect weight due to the underflow.

\

Tools Used

manual

Recommendations

Updates

Lead Judging Commences

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

Support

FAQs

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