Skip to content

CompareProtocols

CompareProtocols is the read-only, stateless primitive that compares IL at a price shock and slippage at a trade size between two pools — pools may be different protocols. The one question DeFiPy can answer cleanly because it carries exact-math implementations of all four AMMs in the same process space.

ProtocolRequired call shape
Mixed (any two of V2/V3/Balancer/Stableswap)CompareProtocols(price_shock=0.10, v3_range_pct=0.10).apply(lp_a, lp_b, amount, token_in=None)

token_in defaults to lp_a’s token0 — both pools must contain it.

ParameterTypeDescription
price_shockfloat (default 0.10)Symmetric ±shock magnitude for IL evaluation.
v3_range_pctfloat (default 0.10)Auto-detected V3 range width centered on current tick. Snapped to the pool’s tick_spacing.
ParameterTypeDescription
lp_a, lp_bExchangeTwo pool objects. Each must be one of V2/V3/Balancer/Stableswap.
amountfloatTrade size for slippage evaluation.
token_inERC20 (optional)Token to use as the trade input. Defaults to lp_a.token0. Both pools must contain this token.

The signature is uniform; what diverges is which output fields are populated per protocol:

Protocolil_at_shockslippage_at_amountNotes
Uniswap V2Always populatedAlways populated
Uniswap V3Conditional — None when price_shock > v3_range_pctAlways populatedOut-of-range regime: position has exited the active tick range.
BalancerAlways populatedAlways None (v2.0)CalculateSlippage is V2/V3-only; Balancer slippage closes once Bucket A lands.
StableswapConditional — None on DepegUnreachableErrorAlways None (v2.0)High A + large shock can produce unreachable target state.

Depth-chain composition. Each per-pool metric fans out to the appropriate IL helper by protocol dispatch (isinstance against BalancerExchange / StableswapExchange plus .version for V2/V3); slippage fans out to CalculateSlippage for V2/V3 (None for Bal/Ssw). Results aggregate into a pairwise ProtocolComparison with independent il_advantage and slippage_advantage fields.

No single winner label. Different protocols win on different axes (IL vs slippage vs TVL depth vs reachability). Collapsing to one number hides the trade-off — which is the whole point. Independent advantage fields preserve each axis; callers building a best-of-both-worlds summary consume both.

Advantage labels. Each axis: "pool_a", "pool_b", "tied", or None (when either side is None). "tied" uses an _TIED_EPSILON = 1e-9 floor for IL equality.

V3 range auto-detection. V3 needs a tick range to evaluate IL. The primitive auto-picks a symmetric range of ±v3_range_pct around the pool’s current tick (default ±10%), snapped to tick_spacing. Matches EvaluateTickRanges’s default shock semantics — a “moderate concentration” stance that shows V3’s narrower IL inside the range.

V3 out-of-range regime. When price_shock > v3_range_pct, the shocked price has crossed the position’s tick boundary; IL framing doesn’t apply (the position is now 100% one side). il_at_shock = None in that case; the notes field surfaces this.

Stableswap reachability. If the shock pushes the target past StableswapImpLoss’s reachability bound, DepegUnreachableError is caught and il_at_shock = None — caller’s notes field gets a corresponding entry.

from defipy import CompareProtocols
from defipy.twin import MockProvider, StateTwinBuilder
provider = MockProvider()
builder = StateTwinBuilder()
lp_v2 = builder.build(provider.snapshot("eth_dai_v2"))
lp_bal = builder.build(provider.snapshot("eth_dai_balancer_50_50"))
v2_tokens = lp_v2.factory.token_from_exchange[lp_v2.name]
result = CompareProtocols().apply(
lp_v2,
lp_bal,
amount=10.0,
token_in=v2_tokens["ETH"],
)
print(f"il_advantage: {result.il_advantage}")
print(f"slippage_advantage: {result.slippage_advantage}")
print(f"notes: {result.notes}")
il_advantage: tied slippage_advantage: None notes: ['pool_b: Balancer slippage not computed in v1 (CalculateSlippage is Uniswap-only)']
  • Depth-chain over UniswapImpLoss, BalancerImpLoss, StableswapImpLoss, plus CalculateSlippage for the slippage axis.
  • Composed into by ad-hoc agent flows comparing protocols on the same token pair before deciding where to LP.
  • CompareFeeTiers — V3 fee-tier comparison (single-protocol)
  • CalculateSlippage — slippage leg in isolation
  • The Primitive Contract — cross-cutting invariants
  • MCP tool exposure: Not in the curated 10 — agents typically compose from leaf primitives (Analyze*, CalculateSlippage) for protocol-comparison decisions.