in onAfterRemoveLiquidity() during _vault.addLiquidity() made to the admin, maxAmountsIn will cause reverts in multiple circumstances
In onAfterRemoveLiquidity(), amountsOutRaw can round down when calculating exitFee here
That exitFee is then used to get accruedQuantAMMFees (used as maxAmountIn during _vault.addLiquidity())
Both of the above variables are the actual tokens of the Pool that will be used during liquidity addition
amountsOutRaw array can have low decimal tokens like USDC for example that will most likely have slight truncation during fee calculation
Now during minBptAmountOut calculations in _vault.addLiquidity() to the admin
There can be cases where BPT amounts are perfectly divisible and doesn't round down
This is likely to happen since during Liquidity addition BPT is calculated and then stay unchanged after that, but Pool reserves change by swapping and weight changes
So during swapping balances corresponding to those BPT change by wei through the invariant swap formula
BPT tokens are 18 decimals and less likely to round down in that calculation
The above condition will create a situation where during _vault.addLiquidity() the minBptAmountOut was accurate but the call will provide less than needed maxAmountsIn causing a revert of the txn
The above temporary DOS can be mitigated by user repeatedly trying to adjust bptAmountIn that rounds down (to have consistent double rounding down in onAfterRemoveLiquidity()) during his call to removeLiquidityProportional()
1- Token A (USDC, 6 decimals):
amountsOutRaw[0] = 100.000123 USDC (100_000_123)
2- Token B (WETH, 18 decimals):
amountsOutRaw[1] = 0.100000000000000123 WETH (100_000_000_000_000_123)
Parameters:
feePercentage = 0.02e18 (2%)
adminFeePercent = 0.5e18 (50%)
feeAmount = 20 (perfect number, no decimals)
Calculation flow with rounding:
1- For USDC:
exitFee = 100_000_123 × 0.02e18 / 1e18 = 2_000_002 (rounded down)
accruedQuantAMMFees[0] = 2_000_002 × 0.5e18 / 1e18 = 1_000_001
2- For WETH:
exitFee = 100_000_000_000_000_123 × 0.02e18 / 1e18 = 2_000_000_000_000_002
accruedQuantAMMFees[1] = 2_000_000_000_000_002 × 0.5e18 / 1e18 = 1_000_000_000_000_001
3- BPT calculation:
feeAmount = 2e18 (perfect number)
minBptAmountOut = 20 × 0.5e18 / 1e18 = 1e18 (no rounding needed)
Txn reverting due to minBptAmountOut not reached with the provided accruedQuantAMMFees as maxAmountsIn
Please notice that simply rounding Up won't work for the same reason (a variable will be perfect % and will not benefit from
mulUpwhile other variable gets benefited frommulUpcause it would have been truncated otherwise) and this issue sequence will always happen and is different from issues simply stating that adminFees should rounUp
Multiple txn reverts in multiple circumstances affecting the availability of removeLiquidityProportional() (temporary DOS)
Manual review
Build a logic that
Doesn't pass maxAmountsIn or pass a very high amount, doesn't matter
uses returned amountsIn used from addLiquidity() and then use those to remove it from hookAdjustedAmountsOutRaw
Likelihood: High, multiple rounding down and little value can trigger the bug Impact: High, DoS the removal.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.