degenbot.uniswap.v2_liquidity_pool ================================== .. py:module:: degenbot.uniswap.v2_liquidity_pool .. autoapi-nested-parse:: UniswapV2Pool: constant-product AMM with reserve tracking. Module Contents --------------- .. py:class:: UniswapV2Pool(*args: Any, **kwargs: Any) Bases: :py:obj:`degenbot.uniswap.v2_pool_state.V2PoolState`, :py:obj:`degenbot.uniswap.v2_pool_calc.UniswapV2PoolCalc`, :py:obj:`degenbot.types.abstract.AbstractLiquidityPool` A Uniswap V2-based liquidity pool implementing the x*y=k constant function invariant. .. py:attribute:: variant :type: ClassVar[str | None] :value: None .. py:attribute:: stable_swap :type: bool :value: False .. py:attribute:: fee_denominator :type: int | None :value: None .. py:attribute:: dex :type: degenbot.types.DexIdentity .. py:attribute:: address :type: degenbot._ffi.ChecksummedAddress .. py:attribute:: factory :type: degenbot._ffi.ChecksummedAddress .. py:attribute:: init_hash :type: str .. py:attribute:: deployer :type: degenbot._ffi.ChecksummedAddress .. py:attribute:: name :type: str .. py:type:: PoolState :canonical: UniswapV2PoolState .. py:method:: from_handle(py_pool: degenbot.types.Pool) -> Self :classmethod: 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. :raises 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). .. py:property:: update_block :type: degenbot.types.aliases.BlockNumber Update block. :returns: The block number of the most recent state update (from Rust). .. py:property:: reserves_token0 :type: int Reserves token0. :returns: The reserve amount for token0 (from Rust). .. py:property:: reserves_token1 :type: int Reserves token1. :returns: The reserve amount for token1 (from Rust). .. py:property:: state :type: 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). .. py:method:: external_update(update: degenbot.uniswap.v2_types.UniswapV2PoolExternalUpdate) -> None External update. :raises ExternalUpdateError: If the update is for a past block. .. py:method:: 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). .. py:method:: 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). .. py:method:: 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. .. py:method:: 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. .. py:method:: 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.