LPQuote
LPQuote is the read-only quoting class for V2/V3 LP state. Unlike the other Core primitives, it doesn’t follow the ClassName().apply(...) shape — it exposes a small set of named methods, each answering a specific question about an existing pool. It never mutates state.
Constructor
Section titled “Constructor”LPQuote(quote_opposing=True, include_fee=False)| Parameter | Type | Description |
|---|---|---|
quote_opposing | bool | When True (default), get_amount returns the opposing-token amount. When False, it returns the input amount unchanged — useful as a passthrough in code that conditionally quotes. |
include_fee | bool | V2-only. When True, get_amount uses fee-aware lp.get_amount_out0/1. When False (default), it uses the no-fee proportional formula (amount_in * res_other) / res_in — the paper value. See the paper-vs-settlement note below. |
Method index
Section titled “Method index”LPQuote exposes seven methods, grouped here by the question each one answers:
| Question | Method | Returns |
|---|---|---|
What’s the spot price of tkn? | get_price(lp, tkn, lwr_tick=None, upr_tick=None) | float — tkn price in opposing-token units |
How much of tkn is in the pool? | get_reserve(lp, tkn, lwr_tick=None, upr_tick=None) | float — V2 reserve or V3 virtual reserve |
| Token amount → opposing-token amount? | get_amount(lp, tkn, amount_in, lwr_tick=None, upr_tick=None) | float — opposing-token output |
| LP shares → opposing-token amount? | get_amount_from_lp(lp, tkn, amount_lp_in, lwr_tick=None, upr_tick=None) | float — opposing-token equivalent |
| Token amount → LP shares? | get_lp_from_amount(lp, tkn, amount_in, lwr_tick=None, upr_tick=None) | float — LP-share equivalent |
Token amount → liquidity (raw L)? | get_liquidity(lp, tkn, amount_in) | float — pool-share-scaled liquidity |
| What’s the other token in the pair? | get_opposing_token(lp, tkn) | ERC20 |
Common parameters
Section titled “Common parameters”| Parameter | Type | Description |
|---|---|---|
lp | Exchange | Initialized V2 or V3 pool with active liquidity. |
tkn | ERC20 | The “input” or “anchor” token for the quote. The opposing token is inferred from the pool. |
lwr_tick, upr_tick | int (optional, V3 only) | The tick range to quote against. Required for V3 amount queries; defaulted to None for V2 calls. |
The remaining parameter on each method is the input amount, with semantics named in the method (token amount, LP-share amount, etc.).
Per-method detail
Section titled “Per-method detail”get_price(lp, tkn, lwr_tick=None, upr_tick=None)
Section titled “get_price(lp, tkn, lwr_tick=None, upr_tick=None)”Spot price of tkn, expressed in opposing-token units. Computed as reserve_opposing / reserve_tkn. Returns 0 if either reserve is zero (degenerate pool).
from defipy import LPQuote
# V2: price of ETH in DAIprice = LPQuote().get_price(lp, eth)
# V3: same call, ticks not required because pool's slot0 carries the spotprice = LPQuote().get_price(lp_v3, eth)get_reserve(lp, tkn, lwr_tick=None, upr_tick=None)
Section titled “get_reserve(lp, tkn, lwr_tick=None, upr_tick=None)”The amount of tkn in the pool. V2 returns the actual reserve in human units; V3 returns the virtual reserve — the amount the pool would hold if all in-range liquidity were collapsed into a constant-product position at the current sqrt-price. Tick-range arguments are accepted but only used by indexed-token paths (when tkn.type == 'index').
reserve = LPQuote().get_reserve(lp, eth)# V3 virtual reserve when lp is a UniswapV3Exchangereserve = LPQuote().get_reserve(lp_v3, eth, lwr_tick, upr_tick)get_amount(lp, tkn, amount_in, lwr_tick=None, upr_tick=None)
Section titled “get_amount(lp, tkn, amount_in, lwr_tick=None, upr_tick=None)”How much of the opposing token would amount_in of tkn exchange for? V2 uses either the no-fee proportional formula or the fee-aware lp.get_amount_out0/1 depending on include_fee. V3 routes through UniV3Helper().quote(lp, tkn, amount_in, lwr_tick, upr_tick) — ticks are required.
# V2 paper value (no fee)out = LPQuote().get_amount(lp, dai, 1000)
# V2 settlement value (fee-aware)out = LPQuote(include_fee=True).get_amount(lp, dai, 1000)
# V3 — ticks requiredout = LPQuote().get_amount(lp_v3, dai, 1000, lwr_tick, upr_tick)get_amount_from_lp(lp, tkn, amount_lp_in, lwr_tick=None, upr_tick=None)
Section titled “get_amount_from_lp(lp, tkn, amount_lp_in, lwr_tick=None, upr_tick=None)”Given a quantity of LP shares, return the equivalent amount of the opposing token (or, if quote_opposing=False, the equivalent amount of tkn itself). Composes RebaseIndexToken for the LP→token leg, then get_amount for the token→opposing-token leg.
opposing_amt = LPQuote().get_amount_from_lp(lp, eth, 100)# 100 LP shares; how much DAI does that translate to?get_lp_from_amount(lp, tkn, amount_in, lwr_tick=None, upr_tick=None)
Section titled “get_lp_from_amount(lp, tkn, amount_in, lwr_tick=None, upr_tick=None)”The inverse of get_amount_from_lp. Given a token amount, return the LP-share quantity it corresponds to via SettlementLPToken().apply(...).
lp_shares = LPQuote().get_lp_from_amount(lp, dai, 1000)get_liquidity(lp, tkn, amount_in)
Section titled “get_liquidity(lp, tkn, amount_in)”Compute the proportional LP-share amount for a given token reserve quantity using the V2-style formula amount_in * total_supply / reserve_token. V2-natural; on V3 the result is structural (uses lp.total_supply and lp.reserve0/reserve1 if present), but in practice the more useful V3 query is get_lp_from_amount.
get_opposing_token(lp, tkn)
Section titled “get_opposing_token(lp, tkn)”Returns the other ERC20 in the pool’s pair. Helper used internally by the amount methods, exposed so user code doesn’t have to inspect lp.token0 / lp.token1 directly.
Per-protocol availability
Section titled “Per-protocol availability”| Protocol | Status |
|---|---|
| Uniswap V2 | ✅ All methods |
| Uniswap V3 | ✅ All methods (amount-style methods require lwr_tick / upr_tick) |
| Balancer | 🔜 v2.1 — see “What’s coming in v2.1” below |
| Stableswap | 🔜 v2.1 |
What’s coming in v2.1
Section titled “What’s coming in v2.1”The architectural intent is full cross-protocol LPQuote — same call shapes, dispatching to Balancer and Stableswap pools through the existing methods. The API surface will be add-only: existing V2/V3 calls won’t change, and existing user code won’t break. The Core Primitives availability matrix on Core Primitives tracks the wiring status.
How LPQuote interacts with the rest of the pipeline
Section titled “How LPQuote interacts with the rest of the pipeline”LPQuote is read-only, so it has no place in the mutate-the-pool pipeline. It’s the read substrate every other primitive sits on:
- The Agentic Primitives (
AnalyzePosition,SimulatePriceMove, etc.) all reach throughLPQuotefor cross-protocol-safe state reads rather than callinglp.get_amount_outdirectly. SwapDepositandWithdrawSwapuseLPQuoteto project the post-swap state during the closed-form / numeric solves for the optimal fraction.- Tutorials lean on
LPQuote.get_priceandget_reservefor any state read in code samples that should work on both V2 and V3.
When v2.1 lands, LPQuote will work the same way against LiveProvider-built twins (i.e. real chain reads) as it does against MockProvider snapshots today.
See also
Section titled “See also”Swap— mutating counterpart toget_amountAnalyzePosition— built on top ofLPQuotereadsSimulatePriceMove— non-mutating projection that usesLPQuoteinternally- Core Primitives — narrative overview with the cross-protocol availability matrix
- The Primitive Contract — cross-cutting invariants