WithdrawSwap
Exit a V2/V3 LP position into a single token. WithdrawSwap is a mutating dispatch primitive that removes liquidity and also swaps the unwanted side back into the requested token, so the user ends up holding only token_out. V2/V3 only — see the architectural reason below.
Signature at a glance
Section titled “Signature at a glance”| Protocol | Required call shape |
|---|---|
| Uniswap V2 | WithdrawSwap().apply(lp, token_out, user_nm, amount_out) |
| Uniswap V3 | WithdrawSwap().apply(lp, token_out, user_nm, amount_out, lwr_tick, upr_tick) |
| Balancer | ❌ Not supported — see “Why no Balancer/Stableswap section” below |
| Stableswap | ❌ Not supported |
Common parameters
Section titled “Common parameters”| Parameter | Type | Description |
|---|---|---|
lp | Exchange | Initialized V2 or V3 pool with the user’s LP shares to burn. |
token_out | ERC20 | The single token the user wants to receive. |
user_nm | str | Account name whose LP shares are burned and who receives token_out. |
amount_out | float | Total quantity of token_out the user expects to walk away with (combined burn + swap). |
Protocol Variants
Section titled “Protocol Variants”Uniswap V2
Section titled “Uniswap V2”The dispatcher computes the optimal split between “burn proceeds” and “swap proceeds” via _calc_univ2_withdraw_portion (closed-form using the pool reserves and the V2 0.997 fee multiplier), then executes:
RemoveLiquidityforp_out * amount_outoftoken_out— returns both tokens.Swapthe other token’s proceeds back intotoken_out.- Combined output is
(swap result) + (RemoveLiquidity's token_out side).
| Parameter | Type | Notes |
|---|---|---|
| (no extras) | — | Common parameters only. |
from defipy import WithdrawSwap
# Burn ETH/DAI LP shares; walk away with only DAIwithdrawn = WithdrawSwap().apply(lp, dai, "user", 1000)# Returns the total DAI received (burn leg + swap leg combined)Uniswap V3
Section titled “Uniswap V3”V3 uses the same two-step pattern, but the burn calculation goes through SettlementLPToken to compute the in-range L from the requested amount_out and the active sqrt-price.
| Parameter | Type | Notes |
|---|---|---|
lwr_tick | int | Lower tick of the position to withdraw from. Must match the original mint. |
upr_tick | int | Upper tick. |
from defipy import WithdrawSwap
WithdrawSwap().apply(lp, eth, "user", 1, lwr_tick, upr_tick)# Burns position liquidity inside [lwr_tick, upr_tick] and swaps the# non-eth side back into ETH; returns total ETH received.Why no Balancer/Stableswap section
Section titled “Why no Balancer/Stableswap section”WithdrawSwap exists because V2/V3’s RemoveLiquidity returns both sides of the pair — getting back to a single asset requires an extra swap. Balancer and Stableswap don’t have this problem: their RemoveLiquidity already supports specifying token_out and returning only that asset (exit_swap_extern_amount_out for Balancer, lp.remove_liquidity(amount, token_out, user) for Stableswap). The pool math handles the imbalance against the invariant directly.
Calling WithdrawSwap().apply(lp, ...) against a BalancerExchange or StableswapExchange will fail at the V2/V3 version check (the dispatcher is V2/V3-specific). Use RemoveLiquidity on those protocols.
How WithdrawSwap interacts with the rest of the pipeline
Section titled “How WithdrawSwap interacts with the rest of the pipeline”Join→AddLiquidity— pool initialized and LP positions held.- Pre-exit analytics —
AnalyzePositiondecomposes IL vs accumulated fees so the user can decide whether to exit;CalculateSlippageprojects the price impact of the internal swap leg. WithdrawSwap— burn + swap to single asset (this primitive).
See also
Section titled “See also”RemoveLiquidity— the burn-only counterpart; also handles Balancer/Stableswap single-asset withdrawalsSwapDeposit— the inverse zap-in (V2/V3 only)AnalyzePosition— non-mutating IL/fee/PnL decomposition before exit- Tutorials → Uniswap V2 — Withdraw & Swap — runnable walkthrough
- The Primitive Contract — cross-cutting invariants