QuantAMM

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

There is no check for incorrect token indices in the `QuantAMMWeightedPool::onSwap` function.

Summary

The QuantAMMWeightedPool::onSwap function lacks validation for incorrect token indices.This absence of checks could result in errors or unintended behavior when an invalid token index is used.

Vulnerability Details

In the onSwap function, the indexIn and indexOut are passed via a request struct.

Since the protocol allows a maximum of 8 tokens, the indices should be greater than or equal to 0 and less than 8.

However, the function does not implement any check to ensure the indices are within this valid range.

Index out of range can be given to the function.

function onSwap(PoolSwapParams memory request) public view onlyVault returns (uint256) {
QuantAMMBaseInterpolationVariables memory variables = poolSettings.quantAMMBaseInterpolationDetails;
uint256 tokenInWeight;
uint256 tokenOutWeight;
uint256 totalTokens = _totalTokens;
uint40 multiplierTime = uint40(block.timestamp);
if (block.timestamp >= variables.lastPossibleInterpolationTime) {
//we have gone beyond the first variable hitting the guard rail. We cannot interpolate any further and an update is needed
multiplierTime = variables.lastPossibleInterpolationTime;
}
uint256 timeSinceLastUpdate = uint256(multiplierTime - variables.lastUpdateIntervalTime);
@>> // if both tokens are within the first storage elem
@>> if ((request.indexIn < 4 && request.indexOut < 4) || (request.indexIn >= 4 && request.indexOut >= 4)) {
QuantAMMNormalisedTokenPair memory tokenWeights = _getNormalisedWeightPair(
request.indexIn,
request.indexOut,
timeSinceLastUpdate,
totalTokens
);
tokenInWeight = tokenWeights.firstTokenWeight;
tokenOutWeight = tokenWeights.secondTokenWeight;
} else {
tokenInWeight = _getNormalizedWeight(request.indexIn, timeSinceLastUpdate, totalTokens);
tokenOutWeight = _getNormalizedWeight(request.indexOut, timeSinceLastUpdate, totalTokens);
}
if (request.kind == SwapKind.EXACT_IN) {
if (request.amountGivenScaled18 > request.balancesScaled18[request.indexIn].mulDown(maxTradeSizeRatio)) {
revert maxTradeSizeRatioExceeded();
}
uint256 amountOutScaled18 = WeightedMath.computeOutGivenExactIn(
request.balancesScaled18[request.indexIn],
tokenInWeight,
request.balancesScaled18[request.indexOut],
tokenOutWeight,
request.amountGivenScaled18
);
return amountOutScaled18;
} else {
// Cannot exceed maximum out ratio
if (request.amountGivenScaled18 > request.balancesScaled18[request.indexOut].mulDown(maxTradeSizeRatio)) {
revert maxTradeSizeRatioExceeded();
}
uint256 amountInScaled18 = WeightedMath.computeInGivenExactOut(
request.balancesScaled18[request.indexIn],
tokenInWeight,
request.balancesScaled18[request.indexOut],
tokenOutWeight,
request.amountGivenScaled18
);
// Fees are added after scaling happens, to reduce the complexity of the rounding direction analysis.
return amountInScaled18;
}
}

Impact

Without the proper index validation, incorrect values could be calculated, or the function may behave unexpectedly. This could lead to errors or unintended outcomes during the swap process.

Tools Used

Manual review

Recommendations

Add a check to mitigate the bug :-

+ require(indexIn >= 0 && indexIn < 8, "Invalid indexIn: out of range");
+ require(indexOut >= 0 && indexOut < 8, "Invalid indexOut: out of range");
//At the starting of the function.
Updates

Lead Judging Commences

n0kto Lead Judge 10 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.

Support

FAQs

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

Give us feedback!