degenbot.uniswap.v2_liquidity_pool¶

UniswapV2Pool: constant-product AMM with reserve tracking.

Module Contents¶

class degenbot.uniswap.v2_liquidity_pool.UniswapV2Pool(*args: Any, **kwargs: Any)¶

Bases: degenbot.uniswap.v2_pool_state.V2PoolState, degenbot.uniswap.v2_pool_calc.UniswapV2PoolCalc, degenbot.types.abstract.AbstractLiquidityPool

A Uniswap V2-based liquidity pool implementing the x*y=k constant function invariant.

variant: ClassVar[str | None] = None¶
stable_swap: bool = False¶
fee_denominator: int | None = None¶
dex: degenbot.types.DexIdentity¶
address: degenbot._ffi.ChecksummedAddress¶
factory: degenbot._ffi.ChecksummedAddress¶
init_hash: str¶
deployer: degenbot._ffi.ChecksummedAddress¶
name: str¶
type PoolState = UniswapV2PoolState¶
classmethod from_handle(py_pool: degenbot.types.Pool) → Self¶

Wrap a Rust-owned Pool handle as a Python companion.

Internal seam (ADR-005, Polars-style _from_pydf pattern). The handle is self-describing: every identity field (address, factory, fees, tokens, dex preset, stable strategy) is read off it — no identity is passed as constructor args. Rust owns the mutable state (reserves + reorg journal) as V2PoolState and the immutable registration metadata as V2PoolDescriptor; this companion reads both through self._py_pool.

Only Bot.build_pool() (production) and make_v2_pool (tests) should call this — they have already registered the pool (and, per ADR-006, its tokens in the same Bot) and obtained the handle. cls is used so subclasses that only set ClassVars (the documented extension contract) inherit this seam and produce instances of the subclass.

Returns:

A cls instance wrapping py_pool.

Raises:
  • DegenbotValueError – If the handle is not a V2-family pool (py_pool.variant is empty — the PoolEntry is not V2), so the union-handle V2 getters would return empty/default identity.

  • DegenbotValueError – If the handle has no DexIdentity preset (the pool was not registered with a variant) or the pool’s tokens are not registered in the same Bot (ADR-006).

property update_block: degenbot.types.aliases.BlockNumber¶

Update block.

Returns:

The block number of the most recent state update (from Rust).

property reserves_token0: int¶

Reserves token0.

Returns:

The reserve amount for token0 (from Rust).

property reserves_token1: int¶

Reserves token1.

Returns:

The reserve amount for token1 (from Rust).

property state: PoolState¶

State.

Returns:

The current pool state, built from one atomic Rust snapshot (_py_pool.snapshot()) so a Rust-side sync_reserves (pump update) can’t interleave between the reserve reads.

Raises:

DegenbotValueError – If the pool is not registered in Rust (no V2 state to snapshot).

external_update(update: degenbot.uniswap.v2_types.UniswapV2PoolExternalUpdate) → None¶

External update.

Raises:

ExternalUpdateError – If the update is for a past block.

discard_states_before_block(block: degenbot.types.aliases.BlockNumber) → None¶

Discard cached V2 reorg journal deltas earlier than the given block.

Delegates to Pool.discard_before_block (Rust pops journal deltas strictly earlier than the target, keeping the genesis delta + everything at/after the target). The current state is unchanged when the target is at/after the newest delta.

Raises:

NoPoolStateAvailable – If the target is past the newest delta (would remove every known state).

restore_state_before_block(block: degenbot.types.aliases.BlockNumber) → None¶

Restore the V2 pool to the landed-at state just before the target block.

Delegates to Pool.restore_before_block (Rust pops journal deltas at/after the target + reverse-applies them, writing back the pre-target reserves in one write guard). The journal’s update_block lands at the oldest popped delta’s block (the target convention); the restored reserves are the pre-target state.

Raises:

NoPoolStateAvailable – If no state exists prior to the target block (the target is at or before the registration block).

simulate_exact_input_swap(token_in: degenbot.erc20.Erc20Token, token_in_quantity: int, override_state: PoolState | None = None) → degenbot.uniswap.v2_types.UniswapV2PoolSimulationResult¶

Simulate an exact input swap.

Returns:

The simulation result with delta amounts and state transitions.

Raises:

DegenbotValueError – If token_in is unknown.

simulate_exact_output_swap(token_out: degenbot.erc20.Erc20Token, token_out_quantity: int, override_state: PoolState | None = None) → degenbot.uniswap.v2_types.UniswapV2PoolSimulationResult¶

Simulate exact output swap.

Returns:

The simulation result with delta amounts and state transitions.

Raises:

DegenbotValueError – If token_out is unknown.

calculate_tokens_out_from_tokens_in(token_in: degenbot.erc20.Erc20Token, token_in_quantity: int, override_state: degenbot.uniswap.v2_types.UniswapV2PoolState | None = None) → int¶

Calculate the expected token OUTPUT for a target INPUT at current reserves.

Strategy dispatch (ADR-005 slice 7 step 4a fold): Camelot stable pools (stable_swap=True) use the solidly-stable invariant with Camelot’s k/get_y; all other V2 pools fall through to super() — the UniswapV2PoolCalc Rust-delegation path (slice 5) is unperturbed for the volatile majority.

Returns:

The expected output token amount.