QuantAMM

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

Incorrect weight clamping leads to broken weights calculation

Summary

Incorrect weight clamping in `QuantammMathGuard.sol` will cause incorrect weight calculations for the protocol as the weights are not properly clamped and normalized.

Vulnerability Details

## Root Cause
In `QuantammMathGuard.sol#L32-L70` and `QuantammMathGuard.sol#L14-L30`, the `_clampWeights()` function clamps weights incorrectly, leading to weights that are not properly clamped and normalized.
```solidity
function _guardQuantAMMWeights(
int256[] memory _weights,
int256[] calldata _prevWeights,
int256 _epsilonMax,
int256 _absoluteWeightGuardRail
) internal pure returns (int256[] memory guardedNewWeights) {
_weights = _clampWeights(_weights, _absoluteWeightGuardRail);
guardedNewWeights = _normalizeWeightUpdates(_prevWeights, _weights, _epsilonMax);
}
```
## Internal pre-conditions
1. Admin needs to call `_guardQuantAMMWeights` to set `weights` to be clamped and normalized.
2. `weights` array to contain values that need clamping and normalization.
## External pre-conditions
1. `weights` array needs to contain values that exceed the `absoluteWeightGuardRail`.
## Attack Path
1. Admin calls `_guardQuantAMMWeights` with weights that need clamping.
2. The `_clampWeights` function clamps weights incorrectly.
3. The protocol uses these incorrectly clamped weights, leading to broken weight calculations.

Impact

The protocol suffers from incorrect weight calculations, leading to potential financial losses or incorrect protocol behavior.

Tools Used

Manual

PoC

// Example weights and guard rail
int256[] memory weights = [0.1e18, 0.23e18, 0.23e18, 0.44e18];
int256 absoluteWeightGuardRail = 0.2e18;
// Call the function
int256[] memory clampedWeights = _clampWeights(weights, absoluteWeightGuardRail);
// Expected clamped weights
// {0.2e18, 0.23e18, 0.23e18, 0.40e18} -> {0.2e18, 0.46e18, 0.46e18, 0.80e18}

Recommendations

Modify `QuantammMathGuard.sol#_clampWeights()` function as follows:
```solidity
function _clampWeights(
int256[] memory _weights,
int256 _absoluteWeightGuardRail
) internal pure returns (int256[] memory) {
unchecked {
uint weightLength = _weights.length;
if (weightLength == 1) {
return _weights;
}
int256 absoluteMin = _absoluteWeightGuardRail;
int256 absoluteMax = ONE - (PRBMathSD59x18.fromInt(int256(_weights.length - 1)).mul(_absoluteWeightGuardRail));
int256 aver;
int256 w_min = _weights[0], w_max = _weights[0];
for (uint i = 0; i < weightLength; i++) {
aver += _weights[i];
if (_weights[i] < w_min) w_min = _weights[i];
if (_weights[i] > w_max) w_max = _weights[i];
}
if (w_min >= absoluteMin && w_max <= absoluteMax) {
return _weights;
}
aver /= weightLength;
int256 d_min = aver - w_min;
int256 d_max = w_max - aver;
int256 new_aver = int256(1e18).div(int256(weightLength)); // 1 / n;
int256 n_min = new_aver - absoluteMin;
int256 n_max = absoluteMax - new_aver;
int256 rate;
if (d_min != 0) {
rate = n_min.div(d_min);
} else {
rate = type(int256).max;
}
if (d_max != 0) {
int256 t_rate = n_max.div(d_max);
if (t_rate < rate) {
rate = t_rate;
}
}
for (uint i = 0; i < weightLength; i++) {
_weights[i] = (_weights[i] - aver).mul(rate) + new_aver;
}
}
return _weights;
}
```
Updates

Lead Judging Commences

n0kto Lead Judge 11 months ago
Submission Judgement Published
Invalidated
Reason: Too generic

Support

FAQs

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

Give us feedback!