AddLiquidity
Contribute liquidity to a pool that already has a price. AddLiquidity is a mutating dispatch primitive — every protocol accepts a single-token-in call shape, but the meaning of “what’s calculated for you” varies. See The Primitive Contract for the cross-cutting invariants every dispatcher follows.
Signature at a glance
Section titled “Signature at a glance”| Protocol | Required call shape |
|---|---|
| Uniswap V2 | AddLiquidity().apply(lp, token_in, user_nm, amount_in) |
| Uniswap V3 | AddLiquidity().apply(lp, token_in, user_nm, amount_in, lwr_tick, upr_tick) |
| Balancer | AddLiquidity(kind=Proc.ADDTKN).apply(lp, token_in, user_nm, amount_in) |
| Stableswap | AddLiquidity().apply(lp, token_in, user_nm, amount_in) |
Common parameters
Section titled “Common parameters”| Parameter | Type | Description |
|---|---|---|
lp | Exchange | Initialized pool object. Must already have liquidity (post-Join). |
token_in | ERC20 | The token being deposited. Determines which side of the pair (V2/V3) or which vault asset (Balancer/Stableswap) the user is funding. |
user_nm | str | Account name credited with the resulting LP shares. |
amount_in | float | Quantity of token_in to deposit. The pool resolves what’s needed for the other side internally. |
Protocol Variants
Section titled “Protocol Variants”Uniswap V2
Section titled “Uniswap V2”Single-token-in, two-sided deposit. The dispatcher calls lp.quote(amount_in, reserve_in, reserve_out) to compute the matching amount of the other token at the current price ratio, then both balances go into lp.add_liquidity(...). The user effectively pays both tokens, but only specifies one.
| Parameter | Type | Notes |
|---|---|---|
| (no extras) | — | Just the common parameters above. |
from defipy import AddLiquidity
# Add 10 ETH-worth — the matching DAI amount is computed from current reservesAddLiquidity().apply(lp, eth, "user", 10)The user must already hold the matching amount of the other token; the dispatcher does not swap to obtain it. If you want swap-and-deposit in one shot, use SwapDeposit.
Returns {token0: balance0, token1: balance1}.
Uniswap V3
Section titled “Uniswap V3”Single-token-in deposit into a specific tick range. The dispatcher computes the in-range liquidity L from amount_in and the active sqrt-price (UniV3Helper.calc_Lx or calc_Ly depending on which side token_in is), then calls lp.mint(user_nm, lwr_tick, upr_tick, L).
| Parameter | Type | Notes |
|---|---|---|
lwr_tick | int | Lower tick of the range. Must be tick_spacing-aligned. |
upr_tick | int | Upper tick. Must be > lwr_tick and tick_spacing-aligned. |
from defipy import AddLiquidity, UniV3Utils
tick_spacing = 60lwr_tick = UniV3Utils.getMinTick(tick_spacing)upr_tick = UniV3Utils.getMaxTick(tick_spacing)
AddLiquidity().apply(lp, eth, "user", 10, lwr_tick, upr_tick)Balancer
Section titled “Balancer”Single-asset deposit against a vault. The constructor kind parameter selects the deposit mode:
Proc.ADDTKN(default) — pass a token amount; pool computes the LP shares to mint vialp.join_swap_extern_amount_in(amount_in, token_in, user_nm).Proc.ADDSHARES— pass desired LP shares; pool computes the required token amount vialp.join_swap_pool_amount_out(amount_in, token_in, user_nm). The third positional arg is now the share amount you want to receive.
| Parameter | Type | Notes |
|---|---|---|
| (no extras) | — | The constructor kind selects mode; apply() itself takes the common parameters only. |
from defipy import AddLiquidityfrom balancerpy.enums import Proc
# Default: deposit 1 ETH; receive whatever shares the pool issuesAddLiquidity().apply(lp, eth, "user", 1)
# Inverted: receive exactly 5 shares; pay whatever ETH is requiredAddLiquidity(kind=Proc.ADDSHARES).apply(lp, eth, "user", 5)The pool internally handles the imbalance — that’s why Balancer doesn’t need a separate SwapDeposit primitive (see the SwapDeposit page for the architectural reason).
Stableswap
Section titled “Stableswap”Single-asset deposit against a Stableswap vault. The dispatcher calls lp.add_liquidity(amount_in, token_in, user_nm). There is no kind parameter on Stableswap’s AddLiquidity constructor — token-amount-in is the only exposed mode.
| Parameter | Type | Notes |
|---|---|---|
| (no extras) | — | Common parameters only. |
from defipy import AddLiquidity
AddLiquidity().apply(lp, dai, "user", 1000)Like Balancer, the pool absorbs the imbalance internally — single-asset adds are first-class on Stableswap.
How AddLiquidity interacts with the rest of the pipeline
Section titled “How AddLiquidity interacts with the rest of the pipeline”Join— pool must be initialized first.AddLiquidity— additional LPs contribute liquidity (this primitive).- Pre-deposit analytics —
OptimalDepositSplit(V2-only) projects the optimal split before depositing;EvaluateRebalanceprojects whether re-adding into a different range/composition is worth the cost. - Post-deposit analytics —
AnalyzePositiondecomposes IL vs fees over time.
See also
Section titled “See also”Join— first-mint counterpartRemoveLiquidity— the inverse operationSwapDeposit— single-sided V2/V3 deposit (does the swap-to-balance for you)OptimalDepositSplit— non-mutating projection for V2 deposits- Tutorials → Uniswap V2 — runnable end-to-end walkthrough
- The Primitive Contract — cross-cutting invariants