QuantAMM

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

Liquidity Removal Reverts in `onAfterRemoveLiquidity` Callback Triggered by `removeLiquidityProportional`

Summary

When users call the removeLiquidityProportional function, it triggers the onAfterRemoveLiquidity callback, which calculates fees and attempts to add them back to the pool using vault.addLiquidity. If the fees fall below _MINIMUM_TRADE_AMOUNT of the vault, the addLiquidity function reverts, causing the entire liquidity removal process to fail. This unintentionally locks user funds and imposes additional constraints on liquidity providers.

Vulnerability Details

  • Entry Point: removeLiquidityProportional

    • This function indirectly triggers the onAfterRemoveLiquidity callback, where the issue arises.

  • Callback Function: onAfterRemoveLiquidity

    • This function calculates fees, including the localData.accruedQuantAMMFees and localData.accruedFees, and attempts to reinvest them into the pool via vault.addLiquidity.

    • When the calculated fee amount (e.g., localData.feeAmount.mulDown(localData.adminFeePercent)) is less than _MINIMUM_TRADE_AMOUNT, the addLiquidity call reverts.

  • Unintended Consequences:

    • Users with accrued fees below the threshold cannot successfully remove their liquidity.

    • The _MINIMUM_TRADE_AMOUNT for removing liquidity becomes indirectly tied to accrued fees, deviating from the globally set value.

POC

  • Example Scenarios:

    • minWithdrawalFeeBps = 5 //0.0005%

    • QuantAMMUpliftFeeTake = 200 //2%

    • _MINIMUM_TRADE_AMOUNT = 0.5e18

function test_myTest() public {
uint256[] memory maxAmountsIn = [uint(1e18), uint(1e18)].toMemoryArray();
uint bptAmount = 1e18 * 2;
vm.prank(bob);
upliftOnlyRouter.addLiquidityProportional(pool, maxAmountsIn, bptAmount, false, bytes(""));
vm.stopPrank();
uint256[] memory minAmountsOut = [uint256(0), uint256(0)].toMemoryArray();
vm.startPrank(bob);
upliftOnlyRouter.removeLiquidityProportional(bptAmount, minAmountsOut, false, pool);
vm.stopPrank();
}

Above test will revert with TradeAmountTooSmall() error from the vault.

As the test above the user is allowed to add 1e18 of each token, but not allowed to removeLiquidty
this is because after calculation, one or both of the fees is below the _MINIMUM_TRADE_AMOUNT of the vault.

Hence for such user to remove liquidity, using the above example scenerio, the user need to add almost 2000e18 of each token. users below who dont add up to this amount cannot remove liquidity.

Note: you can manually set the _MINIMUM_TRADE_AMOUNT in the vault just to test as it is 0 be default

_MINIMUM_TRADE_AMOUNT = 0.01e18;//IVaultAdmin(address(vaultExtension)).getMinimumTradeAmount();

Impact

  • Locked Funds: Users unable to meet the _MINIMUM_TRADE_AMOUNT threshold for fees have their liquidity effectively locked.

  • Higher Costs: Users are forced to pay more fees than intended by adding more liquidity to complete their removal process.

  • System Inconsistencies: _MINIMUM_TRADE_AMOUNT behaves differently in the context of fee reinvestment compared to its intended global behavior. This issue forces a new _MINIMUM_TRADE_AMOUNT for liquidity removal to complete

Tools Used

Manual Code Review

Recommendations

  1. Adding liquidity should not go through, if removal will not work with the same amount

Updates

Lead Judging Commences

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

finding_onAfterRemoveLiquidity_not_enough_fee_revert

Likelihood: Medium, when fees are below the _MINIMUM_TRADE_AMOUNT. Impact: Low/Medium, DoS of withdrawal but could be mitigated adding funds or waiting for more benefits.

Appeal created

huntoor Auditor
10 months ago
n0kto Lead Judge
10 months ago
n0kto Lead Judge 10 months ago
Submission Judgement Published
Validated
Assigned finding tags:

finding_onAfterRemoveLiquidity_not_enough_fee_revert

Likelihood: Medium, when fees are below the _MINIMUM_TRADE_AMOUNT. Impact: Low/Medium, DoS of withdrawal but could be mitigated adding funds or waiting for more benefits.

Support

FAQs

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

Give us feedback!