wp-evm-algebra-core 0.1.14

Pure data + quote + plan for Algebra-family CL DEXes
Documentation
//! Pure data records for the Algebra family.
//!
//! These are dumb structs with no methods. All operations on them live
//! in `quote`, `plan`, or `hydrate` modules.
//!
//! Covers AlgebraV1.9. Version-specific differences (e.g. Integral's
//! `pluginConfig` field) are handled in separate sub-modules when those
//! deployments are targeted.
//!
//! # `PlanFragment` note
//!
//! `PlanFragment` is re-exported from `waterpump-base::types` — single
//! canonical definition shared across all family crates.
//!
//! # Dynamic-fee note
//!
//! Algebra pools have one pool per token pair and store the current dynamic fee
//! in pool state. Liquidity removal / fee collection records are ABI-identical
//! to Uniswap V3, so those field-identical structs are re-exported from
//! `wp_evm_v3_core::data`; Algebra-specific fee behavior lives in `PoolState`,
//! `Quote`, swap planning, and the fee-less `AddLiquidityParams` below.

use alloy_primitives::{Address, B256, U256};
use wp_evm_algebra_interfaces::farming::IncentiveKey;

/// Snapshot of an Algebra pool's on-chain state at some block.
///
/// Hydrated by `hydrate::pool_state`. Consumed by `quote::*` and `plan::*`.
/// The `fee` field is the current dynamic fee as of the last `globalState()`
/// read; callers who need a fresh fee must re-hydrate.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PoolState {
    pub token0: Address,
    pub token1: Address,
    /// Current dynamic fee (in pips) from `globalState().fee` (V1.9).
    /// Update via re-hydration.
    pub fee: u32,
    pub tick_spacing: i32,
    pub sqrt_price_x96: U256,
    pub liquidity: u128,
    /// Current tick. Informational only — quote functions derive
    /// tick_current from `sqrt_price_x96` via the underlying math.
    pub tick: i32,
    /// Initialized ticks within a window around the current tick.
    /// Empty for minimal hydration (small-amount quotes that stay
    /// within the current tick).
    pub ticks: Vec<TickInfo>,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct TickInfo {
    pub tick: i32,
    pub liquidity_net: i128,
    pub liquidity_gross: u128,
}

/// Per-protocol configuration for an AlgebraV1.9-shaped DEX (e.g.
/// QuickSwap V3 on Polygon).
///
/// Pool addresses are keyed by `(token0, token1)` only; there are no
/// fee tiers.
///
/// Algebra deploys pools through an independent `AlgebraPoolDeployer`
/// contract (not the factory). For off-chain CREATE2 derivation
/// (`pool_address::compute`), the salt is fed into `pool_deployer`,
/// while `factory` is reserved for `factory.poolByPair(...)` lookups.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct AlgebraProtocolConfig {
    pub factory: Address,
    /// CREATE2 deployer — `AlgebraPoolDeployer` contract. Read via
    /// `factory.poolDeployer()` getter when populating a new
    /// protocol facade.
    pub pool_deployer: Address,
    pub router: Address,
    pub position_mgr: Address,
    pub init_code_hash: B256,
    pub multicall: Address,
    /// Optional quoter contract address for online quote path.
    pub quoter: Option<Address>,
    /// Eternal-farming FarmingCenter, if this protocol has farming (None for QuickSwap).
    pub farming_center: Option<Address>,
}

/// A built claim for one incentive: the key + the position token-ids to collect.
#[derive(Debug, Clone)]
pub struct FarmingClaim {
    pub incentive_key: IncentiveKey,
    pub token_ids: Vec<U256>,
}

/// Rectangular earned grid for one pool's active incentive.
/// `reward[i]` / `bonus_reward[i]` align with `token_ids[i]`.
#[derive(Debug, Clone)]
pub struct FarmingEarnedGrid {
    pub pool: Address,
    pub incentive_key: IncentiveKey,
    pub token_ids: Vec<U256>,
    pub reward: Vec<U256>,
    pub bonus_reward: Vec<U256>,
}

/// Parameters for an `exact_in` swap quote/plan.
///
/// Note: no `fee` field — Algebra reads the current fee from pool state.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ExactInParams {
    pub token_in: Address,
    pub token_out: Address,
    pub amount_in: U256,
    pub recipient: Address,
}

/// Parameters for an `exact_out` swap quote/plan.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ExactOutParams {
    pub token_in: Address,
    pub token_out: Address,
    pub amount_out: U256,
    pub recipient: Address,
}

/// Output of a quote computation.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Quote {
    pub amount_in: U256,
    pub amount_out: U256,
    pub sqrt_price_x96_after: U256,
    pub price_impact_bps: u16,
    /// The effective fee used for this quote (from `state.fee`).
    pub effective_fee_pips: u32,
}

/// Parameters for an `add_liquidity` plan (Algebra V1.9 NFPM `mint`).
///
/// Note: **no `fee` field** — Algebra V1.9 pools have one pool per token pair
/// and the fee is dynamic (stored in the pool, not part of pool identity).
/// This is the key ABI difference from Uniswap V3's `MintParams`.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct AddLiquidityParams {
    pub token0: Address,
    pub token1: Address,
    pub tick_lower: i32,
    pub tick_upper: i32,
    pub amount0_desired: U256,
    pub amount1_desired: U256,
    pub recipient: Address,
}

/// Hydrated state of an Algebra V1.9 NFPM position (from `positions(tokenId)`).
///
/// Notably **has no `fee` field** — Algebra V1.9 `positions()` returns 11
/// fields (vs 12 in Uniswap V3 which includes `uint24 fee`).
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PositionState {
    pub token_id: U256,
    pub owner: Address,
    pub token0: Address,
    pub token1: Address,
    pub tick_lower: i32,
    pub tick_upper: i32,
    pub liquidity: u128,
    pub fees_owed_0: U256,
    pub fees_owed_1: U256,
}

/// Re-export of `wp_evm_base::types::PlanFragment`.
///
/// Canonical single definition lives in `waterpump-base`. All family crates
/// re-export from there so the Phase 5 composer can aggregate fragments from
/// multiple families into one `Vec<PlanFragment>`.
pub use wp_evm_base::types::PlanFragment;

/// Re-export field-identical V3 liquidity-management records.
///
/// Algebra V1.9 uses the same `decreaseLiquidity`, `collect`, and
/// `multicall(decreaseLiquidity, collect)` ABI field shapes as Uniswap V3.
/// The Algebra-specific divergence is dynamic pool fees plus fee-less minting,
/// not these remove/collect data records.
pub use wp_evm_v3_core::data::{CollectFeesParams, RemoveAndCollectParams, RemoveLiquidityParams};

#[cfg(test)]
mod tests {
    use super::*;
    use alloy_primitives::{address, U256};

    #[test]
    fn pool_state_constructs() {
        let s = PoolState {
            token0: address!("0x0000000000000000000000000000000000000001"),
            token1: address!("0x0000000000000000000000000000000000000002"),
            fee: 500,
            tick_spacing: 60,
            sqrt_price_x96: U256::from(1u64) << 96,
            liquidity: 0u128,
            tick: 0i32,
            ticks: vec![],
        };
        assert_eq!(s.fee, 500);
    }

    #[test]
    fn plan_fragment_default_is_empty() {
        let f = PlanFragment::default();
        assert!(f.calls.is_empty());
        assert!(f.approvals.is_empty());
        assert_eq!(f.value, U256::ZERO);
    }
}