SwapDeposit
Convert a single-token holding into a balanced LP position in one shot. SwapDeposit is a mutating dispatch primitive that internally swaps an optimal fraction of the input, then deposits the resulting two-sided balance. V2/V3 only — see the architectural reason below.
Signature at a glance
Section titled “Signature at a glance”| Protocol | Required call shape |
|---|---|
| Uniswap V2 | SwapDeposit().apply(lp, token_in, user_nm, amount_in) |
| Uniswap V3 | SwapDeposit().apply(lp, token_in, user_nm, amount_in, 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 active liquidity. |
token_in | ERC20 | The single token the user holds and wants to deposit on both sides. |
user_nm | str | Account name receiving the resulting LP credit. |
amount_in | float | Total quantity of token_in available to spend (swap + deposit combined). |
Protocol Variants
Section titled “Protocol Variants”Uniswap V2
Section titled “Uniswap V2”The dispatcher solves a closed-form quadratic for the optimal swap fraction alpha, accounting for V2’s 0.3% fee, then runs:
Swapalpha * amount_inoftoken_infor the other token.lp.quote(...)the matching amount oftoken_inagainst the post-swap reserves.lp.add_liquidity(user_nm, balance0, balance1, balance0, balance1)to mint LP shares.
| Parameter | Type | Notes |
|---|---|---|
| (no extras) | — | Common parameters only. |
from defipy import SwapDeposit
# Hold 1000 DAI; want a balanced ETH/DAI LP positiondeposited = SwapDeposit().apply(lp, dai, "user", 1000)# Returns the total `token_in`-denominated value deposited (swap leg + deposit leg)The closed-form quadratic lives at SwapDeposit._calc_univ2_deposit_portion. It’s the same math the read-only OptimalDepositSplit primitive composes against — same alpha, no mutation.
Uniswap V3
Section titled “Uniswap V3”V3 doesn’t admit a closed-form solution because the in-range liquidity-to-amount relationship varies with the sqrt-price across the range. The dispatcher uses scipy.optimize.minimize(method='Nelder-Mead', bounds=[(0.35, 0.65)]) to find the optimal swap fraction numerically, then:
- Swap that fraction of
token_in. - Compute the in-range liquidity
Lfrom the post-swap balance usingUniV3Helper.calc_Lx/calc_Ly. lp.mint(user_nm, lwr_tick, upr_tick, L)to mint the position.
| Parameter | Type | Notes |
|---|---|---|
lwr_tick | int | Lower tick of the position. Must be tick_spacing-aligned. |
upr_tick | int | Upper tick. |
from defipy import SwapDeposit, UniV3Utils
tick_spacing = 60lwr_tick = UniV3Utils.getMinTick(tick_spacing)upr_tick = UniV3Utils.getMaxTick(tick_spacing)
deposited = SwapDeposit().apply(lp, dai, "user", 1000, lwr_tick, upr_tick)Why no Balancer/Stableswap section
Section titled “Why no Balancer/Stableswap section”SwapDeposit exists because V2/V3 deposits at the pool level need balanced two-sided amounts — providing a single token requires a manual swap step first. Balancer and Stableswap don’t have this constraint: AddLiquidity already accepts a single-token-in call shape and the pool math handles the imbalance against the invariant directly. There’s no swap-then-deposit pattern to abstract because the underlying primitive already does what you’d want.
The dispatcher reflects this — the defipy.process.deposit namespace re-exports only uniswappy.process.deposit.SwapDeposit, so calling SwapDeposit().apply(lp, ...) against a BalancerExchange or StableswapExchange will fail at the version check (no .version attribute on those exchanges). Use AddLiquidity for those protocols.
How SwapDeposit interacts with the rest of the pipeline
Section titled “How SwapDeposit interacts with the rest of the pipeline”Join→AddLiquidity— pool initialized.- Pre-deposit projection —
OptimalDepositSplit(V2 only) projects the samealphaSwapDepositwill use, plus the resulting balance, without mutating. SwapDeposit— execute the zap-in (this primitive).- Post-deposit analytics —
AnalyzePositiondecomposes the resulting position over time.
See also
Section titled “See also”Swap— the swap leg, used standaloneAddLiquidity— the deposit leg, also handles Balancer/Stableswap single-asset addsWithdrawSwap— the inverse zap-out (V2/V3 only)OptimalDepositSplit— non-mutating V2 projection of the same solve- Tutorials → Uniswap V2 — Swap & Deposit — runnable walkthrough
- The Primitive Contract — cross-cutting invariants