degenbot.balancer.pools ======================= .. py:module:: degenbot.balancer.pools .. autoapi-nested-parse:: Balancer V2 weighted pool implementation. Module Contents --------------- .. py:function:: detect_pow_version(bytecode: str) -> degenbot.balancer.libraries.constants.PowVersion Detect which FixedPoint library version a pool contract uses from its bytecode. V2 (WeightedPool) contracts include fast paths for y == ONE, TWO, FOUR in powDown/powUp. These reference the TWO and FOUR constants, which are absent from V1 (WeightedPool2Tokens) bytecode. The detection works by checking for the TWO constant (0x1bc16d674ec80000) in the deployed bytecode. This constant is used in the `y == TWO` fast-path comparison and does not appear in V1 contracts. :returns: The computed value. .. py:class:: BalancerV2Pool(*args: Any, **kwargs: Any) Bases: :py:obj:`degenbot.types.abstract.AbstractLiquidityPool` BalancerV2Pool class. .. py:attribute:: variant :type: ClassVar[str | None] :value: 'balancer_weighted' .. py:type:: PoolState :canonical: BalancerV2PoolState .. py:attribute:: FEE_DENOMINATOR :value: 1000000000000000000 .. py:attribute:: address :type: degenbot.types.chain.ChecksummedAddress .. py:attribute:: pool_id :type: bytes .. py:attribute:: pool_specialization :type: int .. py:attribute:: vault :type: degenbot.types.chain.ChecksummedAddress .. py:attribute:: scaling_factors :type: tuple[int, ...] .. py:attribute:: fee :type: fractions.Fraction .. py:attribute:: weights :type: tuple[int, ...] .. py:attribute:: pow_version :type: degenbot.balancer.libraries.constants.PowVersion .. 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). Every identity field (vault, pool_id, tokens, weights, scaling_factors, swap_fee, pow_version, address) is read off the handle. :returns: A ``cls`` instance wrapping ``py_pool``. :raises DegenbotValueError: If the handle is not a Balancer weighted pool or any token is not registered. .. py:property:: balances :type: tuple[int, ...] Balances. Read from the Rust core via the ``Pool`` handle (ADR-005 slice 12b). Rust ``BotState`` is the single source of truth for the mutable ``balances`` slot; this getter returns the live tuple. .. py:property:: state :type: PoolState State. Built from one atomic Rust snapshot (``snapshot_balancer_weighted()`` — ``(balances, block)``) so callers see a coherent tuple (no torn read mid-``external_update``). Mirrors V3/V4's ``snapshot_v3()`` and Curve's ``snapshot_curve()`` contract. :raises DegenbotValueError: If the Rust snapshot is absent (the pool is not registered in Rust as a Balancer weighted pool — unreachable for a companion built over a registered handle). .. py:property:: tokens :type: tuple[degenbot.erc20.Erc20Token, ...] Tokens. .. py:method:: calculate_tokens_out_from_tokens_in(token_in: degenbot.erc20.Erc20Token, token_out: degenbot.erc20.Erc20Token, token_in_quantity: int, override_state: PoolState | None = None) -> int Calculate tokens out from tokens in. Thin driver shell over the Rust core: token resolution stays Python-side, the swap math is fully Rust-owned. :returns: The computed integer value. .. py:method:: calculate_tokens_in_from_tokens_out(token_in: degenbot.erc20.Erc20Token, token_out: degenbot.erc20.Erc20Token, token_out_quantity: int, override_state: PoolState | None = None) -> int Compute how many tokens must be sent to take `token_out_quantity` out. Thin driver shell over the Rust core. :returns: The computed integer value. .. py:method:: external_update(update: degenbot.balancer.types.BalancerV2WeightedPoolExternalUpdate) -> None Apply an external state update with new balances. Delegates to the Rust core (``Pool.apply_balancer_weighted_balance_update``) which journals the prior balances (genesis-anchor V2-style discipline) and lands the new balances + ``update_block`` atomically (ADR-005 slice 12b). The ``_state_lock`` + double-check-after-acquire pattern it used to apply is gone — Rust's internal write lock handles atomicity; the registration-state precondition is enforced by the Rust core's silent-no-op-on-older-block contract. :raises DegenbotValueError: If the Rust core rejects the update (the pool is not registered as a Balancer weighted pool — unreachable for a companion built over a registered handle).