degenbot.balancer¶
Balancer V2 weighted and stable pools with swap encoding.
Submodules¶
Package Contents¶
- class degenbot.balancer.BalancerV2Pool(*args: Any, **kwargs: Any)¶
Bases:
degenbot.types.abstract.AbstractLiquidityPoolBalancerV2Pool class.
- type PoolState = BalancerV2PoolState¶
- FEE_DENOMINATOR = 1000000000000000000¶
- fee: fractions.Fraction¶
- pow_version: degenbot.balancer.libraries.constants.PowVersion¶
- classmethod from_handle(py_pool: degenbot.types.Pool) Self¶
Wrap a Rust-owned
Poolhandle as a Python companion.Internal seam (ADR-005, Polars-style
_from_pydfpattern). Every identity field (vault, pool_id, tokens, weights, scaling_factors, swap_fee, pow_version, address) is read off the handle.- Returns:
A
clsinstance wrappingpy_pool.- Raises:
DegenbotValueError – If the handle is not a Balancer weighted pool or any token is not registered.
- property balances: tuple[int, ...]¶
Balances.
Read from the Rust core via the
Poolhandle (ADR-005 slice 12b). RustBotStateis the single source of truth for the mutablebalancesslot; this getter returns the live tuple.
- property state: 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’ssnapshot_v3()and Curve’ssnapshot_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).
- property tokens: tuple[degenbot.erc20.Erc20Token, ...]¶
Tokens.
- 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.
- 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.
- 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_blockatomically (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).
- degenbot.balancer.INVARIANT_V1 = 1¶
- degenbot.balancer.INVARIANT_V2 = 2¶
- class degenbot.balancer.BalancerV2StablePool(*args: Any, **kwargs: Any)¶
Bases:
degenbot.types.abstract.AbstractLiquidityPoolBalancer V2 Stable Pool (MetaStablePool or ComposableStablePool).
Supports token-to-token swaps using StableMath. For ComposableStablePools, the BPT token is automatically dropped from the invariant and swap calculations.
- Swap fee application order:
GIVEN_IN: subtractFee → upscale → compute(outGivenIn) → downscaleDown GIVEN_OUT: upscale → compute(inGivenOut) → downscaleUp → addFee
- Invariant versions:
- V1 (INVARIANT_V1): always-roundDown, D_P accumulation. Used by older
deployed ComposableStablePools (e.g. TUSD BSP, bb-s-USD). Matches the monorepo
_calculate_invariant.- V2 (INVARIANT_V2): roundUp parameter, P_D accumulation. Used by
MetaStablePools and newer deployed pools. The swap path calls with round_up=True. Matches
_calculate_invariant_deployed.
- Rate handling:
ComposableStablePools have time-varying rates (yield accrual in bb-a-* tokens). The deployed contract refreshes rate caches before each swap via
_beforeSwapJoinExit(). For exact-integer matching, inject aBalancerRateProviderthat replicates this cache-aware logic (readgetTokenRateCache, check expiry, callgetRate()if expired). Without a live rate provider, the pool uses construction-time scaling factors and raisesStaleRateResultfor ComposableStablePools to warn that rates may be stale.MetaStablePools have no rate cache — they call
getRate()directly.
- type PoolState = BalancerV2PoolState¶
- FEE_DENOMINATOR = 1000000000000000000¶
- fee: fractions.Fraction¶
- classmethod from_handle(py_pool: degenbot.types.Pool) Self¶
Wrap a Rust-owned
Poolhandle as a Python companion.Internal seam (ADR-005, Polars-style
_from_pydfpattern). Every identity field (vault, pool_id, tokens, amp, scaling_factors, swap_fee, bpt_idx, invariant_version) is read off the handle; the rate provider is the stored I/O trait object (queried viafetch_balancer_stable_rates/balancer_stable_rate_provider_is_static); base scaling factors are derived from token decimals.- Returns:
A
clsinstance wrappingpy_pool.- Raises:
DegenbotValueError – If the handle is not a Balancer stable pool or any token is not registered.
- property balances: tuple[int, ...]¶
Balances.
Read from the Rust core via the
Poolhandle (ADR-005 slice 12d). RustBotStateis the single source of truth for the mutablebalancesslot; this getter returns the live tuple (one U256 per token, including BPT for Composable pools).
- property state: PoolState¶
State.
Built from one atomic Rust snapshot (
snapshot_balancer_stable()—(balances, block)) so callers see a coherent tuple (no torn read mid-external_update). Mirrors V3/V4’ssnapshot_v3()/ Curve’ssnapshot_curve()/ Weighted’ssnapshot_balancer_weighted()contract.- Raises:
DegenbotValueError – If the Rust snapshot is absent (the pool is not registered in Rust as a Balancer stable pool — unreachable for a companion built over a registered handle).
- property tokens: tuple[degenbot.erc20.Erc20Token, ...]¶
Tokens.
- property rate_provider: BalancerRateProvider | None¶
The rate provider for per-block rate resolution, if available.
With the sealed seam (ADR-005) the provider is the stored Rust I/O trait object, queried via the handle. This property returns
Nonewhen the stored provider is static (the no-I/O fallback).
- property requires_io_at_calculation_time: bool¶
Whether this pool may call its rate_provider during swap calculations.
Returns True for ComposableStablePools with a live rate provider (time-varying rates from yield-bearing tokens). Returns False for MetaStablePools and for pools with only a static rate provider.
- 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, block_identifier: int | str | None = None) int¶
Compute the amount of token_out received for a GIVEN_IN swap.
Thin driver shell over the Rust core: token/scale resolution stays Python-side (the MetaStable block-rate lookup is driver data), the swap math is fully Rust-owned.
For ComposableStablePools without a live rate provider the result is wrapped in
StaleRateResultbecause construction-time rates may be stale.- Returns:
The computed integer value (unwrapped from
StaleRateResultsemantics when rates cannot be stale).- Raises:
StaleRateResult – See function documentation.
- 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, block_identifier: int | str | None = None) int¶
Compute how many tokens must be sent to take token_out_quantity out.
Thin driver shell over the Rust core: the MetaStable block-rate resolution stays Python-side, the swap math is fully Rust-owned.
- Returns:
The computed integer value.
- Raises:
StaleRateResult – See function documentation.
- external_update(update: degenbot.balancer.types.BalancerV2StablePoolExternalUpdate) None¶
Apply an external state update with new balances.
Delegates to the Rust core (
Pool.apply_balancer_stable_balance_update) which journals the prior balances (genesis-anchor V2-style discipline) and lands the new balances +update_blockatomically (ADR-005 slice 12d). The_state_lock+ double-check-after-acquire pattern 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 stable pool — unreachable for a companion built over a registered handle).
- class degenbot.balancer.BalancerV2StablePoolExternalUpdate¶
State update for a Balancer V2 stable pool.
amp is currently omitted — stable pools treat amp as immutable after construction in this plan. A future slice may add amp tracking to support A ramping.
- block_number: degenbot.types.aliases.BlockNumber¶