[Security] Slippage Protection Significantly Weakened in swapAndAdd for Certain Price Ranges
Summary
The swapAndAddCallParameters method in @uniswap/router-sdk has a critical design flaw that can significantly weaken slippage protection from the intended 3% to as much as 30-40% in certain scenarios, particularly when the position's price range causes mintAmountsWithSlippage to return substantially reduced amounts. This creates a large MEV attack surface.
Environment
- Package:
@uniswap/router-sdk
- Version: [Current version]
- Affected Method:
SwapRouter.swapAndAddCallParameters
Problem Description
When using swapAndAddCallParameters , the swap slippage protection ( minimumAmountOut ) can be overridden by a much weaker protection value from mintAmountsWithSlippage , especially when:
- The position's price range is wide or near boundaries
- Multiple trades trigger aggregated slippage check (>2 trades)
- The current pool price is close to the position's range boundaries
Root Cause
The issue occurs in the interaction between three components:
1. Aggregated Slippage Check (swapRouter.ts:432)
const performAggregatedSlippageCheck =
sampleTrade.tradeType === TradeType.EXACT_INPUT && numberOfTrades > 2
// When triggered, individual swaps have amountOutMinimum = 0
2. Minimal Position Construction (swapRouter.ts:618-625)
const minimalPosition = Position.fromAmounts({
pool: position.pool,
tickLower: position.tickLower,
tickUpper: position.tickUpper,
amount0: zeroForOne ? position.amount0 : minimumAmountOut, // Uses swap's minimumAmountOut
amount1: zeroForOne ? minimumAmountOut : position.amount1, // Uses swap's minimumAmountOut
useFullPrecision: false,
})
3. Min Value Selection (approveAndCall.ts:82-87)
let { amount0: amount0Min, amount1: amount1Min } =
position.mintAmountsWithSlippage(slippageTolerance)
// Takes the SMALLER value between two protections
if (JSBI.lessThan(minimalPosition.amount0.quotient, amount0Min)) {
amount0Min = minimalPosition.amount0.quotient
}
if (JSBI.lessThan(minimalPosition.amount1.quotient, amount1Min)) {
amount1Min = minimalPosition.amount1.quotient
}
The problem: mintAmountsWithSlippage can return values much smaller than minimalPosition amounts due to Uniswap V3's concentrated liquidity mechanics. When this happens, the weaker protection overwrites the stronger one.
Reproduction Steps
Scenario Setup
// User wants to swap USDC → cbBTC and add liquidity
const slippageTolerance = new Percent(300, 10000) // 3%
// Position with relatively wide price range
const position = new Position({
pool: cbBTC_USDC_POOL,
tickLower: 62082, // Lower price bound
tickUpper: 75878, // Upper price bound (22% width)
liquidity: DESIRED_LIQUIDITY
})
// Swap trade (3 routes, triggers aggregated slippage check)
const trades = [trade1, trade2, trade3] // numberOfTrades > 2
const { calldata, value } = SwapRouter.swapAndAddCallParameters(
trades,
{ slippageTolerance, ... },
position,
addLiquidityOptions,
ApprovalTypes.MAX,
ApprovalTypes.MAX
)
Expected Protection
Swap slippage: 3%
minimumAmountOut for cbBTC: ~97% of expected output
Final amount1Min should be: ~97% of expected cbBTC
Actual Behavior
Calculation flow:
1. minimumAmountOut (from swap): 1.455 cbBTC (3% slippage)
2. minimalPosition.amount1: 1.455 cbBTC
3. position.mintAmountsWithSlippage(3%): 1.019 cbBTC (30% reduction due to price range)
4. Final amount1Min = min(1.019, 1.455) = 1.019 cbBTC (30% slippage!)
Result: Protection degraded from 3% to 30%
Real-World Example
From an actual on-chain transaction:
User input: 188,088 USDC
Swap amount: 88,740 USDC
Expected remaining for LP: ~99,348 USDC
After mintAmountsWithSlippage:
- amount0Min: 70,609 USDC
- Reduction: (99,348 - 70,609) / 99,348 ≈ 29%
This means:
- User expected: 3% slippage protection
- Actual protection: ~30% slippage (10x weaker!)
Security Impact
Attack Scenario
1. User submits swapAndAdd transaction with 3% slippage
2. MEV bot front-runs: Buys cbBTC to pump price
3. User's swap executes at inflated price:
- Expected: 1.5 cbBTC
- Gets: 1.05 cbBTC (30% loss)
4. Validation:
- Swap check: amountOutMinimum = 0 ✅ (passes)
- LP check: 1.05 >= 1.019 ✅ (passes)
5. MEV bot back-runs: Sells cbBTC for profit
6. Transaction succeeds, user loses 30% instead of max 3%
Risk Assessment
| Condition |
Risk Level |
Potential Loss |
| Normal price range (< 10% reduction) |
🟢 Low |
< 5% |
| Medium price range (10-20% reduction) |
🟡 Medium |
5-15% |
| Wide/boundary range (> 20% reduction) |
🔴 High |
15-40% |
Additional Context
Why mintAmountsWithSlippage Can Reduce Amounts Significantly
The method calculates amounts needed for adding liquidity at price boundaries:
// position.ts:157-205
public mintAmountsWithSlippage(slippageTolerance: Percent) {
const { sqrtRatioX96Upper, sqrtRatioX96Lower } =
this.ratiosAfterSlippage(slippageTolerance)
// Creates positions at price boundaries
// When position is near range boundaries, the amount change is non-linear
// A 3% price change can result in 30%+ amount reduction
}
This is by design for Uniswap V3's concentrated liquidity, but creates a security issue when used to override swap slippage protection.
Observed in Practice
Some implementations appear to add an additional sweepToken validation after swaps:
calldatas = [
swap1, swap2, swap3,
sweepToken(USDC, minimumRemaining), // ← Extra validation step observed
pullTokens,
approve,
mintLP,
sweep
]
This suggests the issue may be known, but the standard SDK implementation does not include this protection.
References
- Code:
sdks/router-sdk/src/swapRouter.ts:563-653
- Related:
sdks/router-sdk/src/approveAndCall.ts:71-113
- V3 SDK Position:
sdks/v3-sdk/src/entities/position.ts:157-205
Thank you for your attention to this security concern. I'm happy to provide more details if needed.
[Security] Slippage Protection Significantly Weakened in swapAndAdd for Certain Price Ranges
Summary
The
swapAndAddCallParametersmethod in@uniswap/router-sdkhas a critical design flaw that can significantly weaken slippage protection from the intended 3% to as much as 30-40% in certain scenarios, particularly when the position's price range causesmintAmountsWithSlippageto return substantially reduced amounts. This creates a large MEV attack surface.Environment
@uniswap/router-sdkSwapRouter.swapAndAddCallParametersProblem Description
When using
swapAndAddCallParameters, the swap slippage protection (minimumAmountOut) can be overridden by a much weaker protection value frommintAmountsWithSlippage, especially when:Root Cause
The issue occurs in the interaction between three components:
1. Aggregated Slippage Check (swapRouter.ts:432)
2. Minimal Position Construction (swapRouter.ts:618-625)
3. Min Value Selection (approveAndCall.ts:82-87)
The problem:
mintAmountsWithSlippagecan return values much smaller thanminimalPositionamounts due to Uniswap V3's concentrated liquidity mechanics. When this happens, the weaker protection overwrites the stronger one.Reproduction Steps
Scenario Setup
Expected Protection
Actual Behavior
Real-World Example
From an actual on-chain transaction:
Security Impact
Attack Scenario
Risk Assessment
Additional Context
Why
mintAmountsWithSlippageCan Reduce Amounts SignificantlyThe method calculates amounts needed for adding liquidity at price boundaries:
This is by design for Uniswap V3's concentrated liquidity, but creates a security issue when used to override swap slippage protection.
Observed in Practice
Some implementations appear to add an additional
sweepTokenvalidation after swaps:This suggests the issue may be known, but the standard SDK implementation does not include this protection.
References
sdks/router-sdk/src/swapRouter.ts:563-653sdks/router-sdk/src/approveAndCall.ts:71-113sdks/v3-sdk/src/entities/position.ts:157-205Thank you for your attention to this security concern. I'm happy to provide more details if needed.