Summary
The _clampWeights() calculates the weights incorrectly.
Vulnerability Details
In _clampWeights(), it normalizes the weights that the sum is ONE and each weight is between absoluteMin and absoluteMax.
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 sumRemainerWeight = ONE;
int256 sumOtherWeights;
for (uint i; i < weightLength; ++i) {
if (_weights[i] < absoluteMin) {
_weights[i] = absoluteMin;
sumRemainerWeight -= absoluteMin;
} else if (_weights[i] > absoluteMax) {
_weights[i] = absoluteMax;
sumOtherWeights += absoluteMax;
}
}
if (sumOtherWeights != 0) {
int256 proportionalRemainder = sumRemainerWeight.div(sumOtherWeights);
for (uint i; i < weightLength; ++i) {
if (_weights[i] != absoluteMin) {
_weights[i] = _weights[i].mul(proportionalRemainder);
}
}
}
}
return _weights;
}
But while calculating sumOtherWeights, it's not updated when the weight is between absoluteMin and absoluteMax.
So sumOtherWeights will be smaller than the expected sum. (sum of all elements except for the min weights)
After applying the proporation, the weight sum will be larger than ONE.
Impact
The _weights will be calculated incorrectly in _clampWeights().
Recommendations
Recommend modifying like this.
for (uint i; i < weightLength; ++i) {
if (_weights[i] < absoluteMin) {
_weights[i] = absoluteMin;
sumRemainerWeight -= absoluteMin;
} else if (_weights[i] > absoluteMax) {
_weights[i] = absoluteMax;
sumOtherWeights += absoluteMax;
}
+ else {
+ sumOtherWeights += _weights[i];
+ }
}