Swap
Exchange one token for another at the pool’s current price. Swap is a mutating dispatch primitive — it routes to the protocol-specific exact-input swap underneath the unified interface. See The Primitive Contract for the cross-cutting invariants every dispatcher follows.
Signature at a glance
Section titled “Signature at a glance”V2/V3 are binary pools (exactly two assets), so the output token is implicit — only token_in is named. Balancer and Stableswap are N-asset pools (N ≥ 2), so both token_in and token_out must be named explicitly.
| Protocol | Required call shape |
|---|---|
| Uniswap V2 | Swap().apply(lp, token_in, user_nm, amount_in) |
| Uniswap V3 | Swap().apply(lp, token_in, user_nm, amount_in, sqrt_price_limit=None) |
| Balancer | Swap().apply(lp, token_in, token_out, user_nm, amount) |
| Stableswap | Swap().apply(lp, token_in, token_out, user_nm, amount) |
Common parameters
Section titled “Common parameters”| Parameter | Type | Description |
|---|---|---|
lp | Exchange | Initialized pool object. Must already have liquidity (post-Join). |
token_in | ERC20 | Token the user is handing over. Direction of the trade is determined by which token is named here. |
user_nm | str | Account name debited for token_in and credited for the output token. |
The trailing parameters and the input-amount conventions diverge per protocol — see below.
Protocol Variants
Section titled “Protocol Variants”Uniswap V2
Section titled “Uniswap V2”Exact-input swap on a constant-product pool. The output token is the other token in the pair (binary pool, so it’s implicit). Returns the integer-floored output amount.
| Parameter | Type | Notes |
|---|---|---|
amount_in | float | Amount of token_in swapped into the pool. The output amount is computed via lp.get_amount_out(...) and floored to an integer in V2. |
from defipy import Swap
# Swap 1000 DAI for ETHout = Swap().apply(lp, dai, "user", 1000)# `out` is the floored amount of ETH receivedUniswap V3
Section titled “Uniswap V3”Exact-input swap inside the pool’s active range. Direction is inferred from whether token_in matches token0 or token1 — swapExact0For1 or swapExact1For0 is invoked accordingly. The optional sqrt_price_limit is the V3 slippage-protection parameter (passing None disables it).
| Parameter | Type | Notes |
|---|---|---|
amount_in | float | Amount of token_in to swap. |
sqrt_price_limit | int (optional) | Lower (or upper) bound on the post-swap sqrt-price, in V3’s Q64.96 fixed-point format. None means no limit. |
from defipy import Swap
# Same call shape as V2 — V3 is figured out from lp.versionSwap().apply(lp, tkn, "user", 1000)
# To enforce a sqrt-price limit, pass it as the fifth positional arg.Balancer
Section titled “Balancer”Exact-input or exact-output swap on an N-asset weighted pool. Because Balancer pools may hold more than two tokens, both token_in and token_out must be named — the pool can’t infer direction. The kind constructor parameter selects the swap mode:
Proc.SWAPOUT(default) — exact-input.amountistoken_inquantity entering the pool.Proc.SWAPIN— exact-output.amountistoken_outquantity leaving the pool.
| Parameter | Type | Notes |
|---|---|---|
token_out | ERC20 | Token the user receives. Required because the pool has N ≥ 2 assets. |
amount | float | Quantity of token_in (SWAPOUT) or token_out (SWAPIN), per the constructor mode. |
from defipy import Swapfrom balancerpy.enums import Proc
# Exact-input: swap exactly 10 DAI for whatever USDC comes outSwap().apply(lp, dai, usdc, "user", 10)
# Exact-output: receive exactly 0.5 ETH; pay whatever DAI is requiredSwap(kind=Proc.SWAPIN).apply(lp, dai, eth, "user", 0.5)Stableswap
Section titled “Stableswap”Exact-input swap on a Stableswap pool with amplification coefficient A. Like Balancer, both tokens must be named. There is no SWAPIN mode on Stableswap — only exact-input is exposed.
| Parameter | Type | Notes |
|---|---|---|
token_out | ERC20 | Token the user receives. |
amount | float | Amount of token_in entering the pool. |
from defipy import Swap
# Stableswap is exact-input only; trades close to peg behave near-linearly,# trades far from peg encounter the depeg basin.Swap().apply(lp, dai, usdc, "user", 10)For analyzing depeg risk before swapping, see AssessDepegRisk — it quantifies exposure as the trade pushes the pool away from the peg.
How Swap interacts with the rest of the pipeline
Section titled “How Swap interacts with the rest of the pipeline”Join— initialize the pool.Swap— exercise the pool with trades (this primitive). Each swap accrues fees and moves the spot price.- Pre-trade analytics (Agentic Primitives) —
CalculateSlippagefor the price-impact and slippage of a proposed swap;DetectMEVfor sandwich-risk exposure. - Post-trade analytics —
AnalyzePositionto decompose any LP’s resulting IL vs fee income.
See also
Section titled “See also”SwapDeposit— swap + deposit in one step (V2/V3 only)WithdrawSwap— burn LP + swap to a single token (V2/V3 only)LPQuote— read-only quoting for a prospective swapCalculateSlippage— non-mutating projection of a swap’s price impact- Tutorials → Uniswap V2 — runnable end-to-end walkthrough
- The Primitive Contract — cross-cutting invariants