wp-solana-pool-traits 0.1.1

Traits and utilities for Solana liquidity pool operations: PoolViewer, PoolInfuser, PositionViewer
Documentation
use anyhow::Result;
use async_trait::async_trait;
use rust_decimal::Decimal;
use solana_sdk::{pubkey::Pubkey, signature::Keypair};
use wp_solana_rpc::RpcContext;

use crate::types::{
    liquidity::{
        AddBatchLiquidityResult, AddLiquidityResult, CollectResult, IncreaseLiquidityParam,
        RemoveBatchLiquidityResult, RemoveLiquidityResult, SimulateAddLiquidityResult,
        SimulateCollectResult, SimulateRemoveLiquidityResult,
    },
    CurrencyAmount,
};

/// Parameters for adding liquidity including amounts and price range
/// Matches Orca SDK's open_position_instructions and
/// increase_liquidity_instructions APIs
#[derive(Debug, Clone)]
pub struct AddLiquidityParams {
    /// Lower price bound for the position (for mint) or None (for increase)
    pub lower_price: Option<f64>,
    /// Upper price bound for the position (for mint) or None (for increase)
    pub upper_price: Option<f64>,
    /// Liquidity parameter specifying how much to add (TokenA, TokenB, or
    /// Liquidity amount)
    pub liquidity_param: IncreaseLiquidityParam,
    /// Specific options for adding liquidity (mint or increase)
    pub specific_opts: AddLiquiditySpecificOptions,
}

/// Options for minting a new position
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct MintSpecificOptions {}

/// Options for increasing liquidity in an existing position
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct IncreaseSpecificOptions {
    /// The mint address of the position NFT to increase liquidity for.
    pub position_mint: Pubkey,
}

/// Specific options for adding liquidity (either mint or increase).
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum AddLiquiditySpecificOptions {
    /// Open a new position.
    Mint,
    /// Increase an existing position.
    Increase(IncreaseSpecificOptions),
}

/// Options for adding liquidity
#[derive(Debug, Clone, PartialEq)]
pub struct AddLiquidityOptions {
    /// How much the pool price is allowed to move (as a decimal, e.g., 0.01 for
    /// 1%)
    pub slippage_tolerance: Decimal,
}

/// Individual position item for batch liquidity operations
#[derive(Debug, Clone)]
pub struct AddBatchLiquidityItem {
    /// Lower price bound (for mint) or None (for increase)
    pub lower_price: Option<f64>,
    /// Upper price bound (for mint) or None (for increase)
    pub upper_price: Option<f64>,
    /// Liquidity parameter specifying how much to add (TokenA, TokenB, or
    /// Liquidity amount)
    pub liquidity_param: IncreaseLiquidityParam,
    /// Specific options for adding liquidity (mint or increase)
    pub specific_opts: AddLiquiditySpecificOptions,
}

/// Parameters for batch adding liquidity (multiple positions in one
/// transaction)
#[derive(Debug, Clone)]
pub struct AddBatchLiquidityParams {
    /// Individual position items
    pub items: Vec<AddBatchLiquidityItem>,
}

/// Parameters for collecting fees from a position
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct CollectParams {
    /// The mint address of the position NFT to collect for
    pub position_mint: Pubkey,
    /// The account that should receive the tokens
    pub recipient: Pubkey,
}

/// Options for collecting fees from a position
#[derive(Debug, Clone, Default, PartialEq)]
pub struct CollectOptions {
    /// Expected value of tokens owed A, including as-of-yet-unaccounted-for
    /// fees
    pub expected_amount_a: Option<CurrencyAmount>,
    /// Expected value of tokens owed B, including as-of-yet-unaccounted-for
    /// fees
    pub expected_amount_b: Option<CurrencyAmount>,
    /// Optional authority pubkey (if None, will use SDK default)
    pub authority: Option<Pubkey>,
}

/// Amount specification for removing liquidity
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum RemoveLiquidityAmount {
    /// Remove a specific amount of liquidity
    Liquidity(u128),
    /// Remove a percentage of liquidity (in basis points, where 10000 = 100%)
    Bps(u16),
}

/// Parameters for removing liquidity from a position
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RemoveLiquidityParams {
    /// The mint address of the position NFT to remove liquidity from
    pub position_mint: Pubkey,
    /// The amount of liquidity to remove (either specific amount or percentage
    /// in BPS)
    pub liquidity: RemoveLiquidityAmount,
    /// The account that should receive the tokens
    pub recipient: Pubkey,
    /// When the transaction expires, in Unix timestamp seconds
    pub deadline: Option<u64>,
}

/// Options for removing liquidity from a position
#[derive(Debug, Clone, PartialEq)]
pub struct RemoveLiquidityOptions {
    /// How much the pool price is allowed to move (as a decimal, e.g., 0.01 for
    /// 1%)
    pub slippage_tolerance: Decimal,
    /// Whether the position should be closed if all liquidity is being removed
    pub close_position: bool,
}

/// Individual position item for batch remove liquidity operations
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RemoveBatchLiquidityItem {
    /// The mint address of the position NFT to remove liquidity from
    pub position_mint: Pubkey,
    /// The amount of liquidity to remove (either specific amount or percentage
    /// in BPS)
    pub liquidity: RemoveLiquidityAmount,
    /// Whether the position should be closed if all liquidity is being removed
    pub close_position: bool,
}

/// Parameters for batch removing liquidity (multiple positions in one
/// transaction)
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RemoveBatchLiquidityParams {
    /// The account that should receive the tokens
    pub recipient: Pubkey,
    /// When the transaction expires, in Unix timestamp seconds
    pub deadline: Option<u64>,
    /// Individual position items
    pub items: Vec<RemoveBatchLiquidityItem>,
}

/// Trait for managing liquidity positions in Solana pools (Orca Whirlpools,
/// etc.) Uses RpcClient directly to match Orca SDK requirements
#[async_trait]
pub trait PoolInfuser: Send + Sync {
    /// Add liquidity to the pool (mint new position or increase existing
    /// position)
    async fn add_liquidity(
        &self,
        ctx: &RpcContext,
        payer: &Keypair,
        params: AddLiquidityParams,
        options: AddLiquidityOptions,
    ) -> Result<AddLiquidityResult>;

    /// Add batch liquidity to the pool (multiple positions in one transaction)
    ///
    /// This is more efficient than adding liquidity individually.
    async fn add_batch_liquidity(
        &self,
        ctx: &RpcContext,
        payer: &Keypair,
        params: AddBatchLiquidityParams,
        options: AddLiquidityOptions,
    ) -> Result<AddBatchLiquidityResult>;

    /// Remove liquidity from a position
    async fn remove_liquidity(
        &self,
        ctx: &RpcContext,
        payer: &Keypair,
        params: RemoveLiquidityParams,
        options: RemoveLiquidityOptions,
    ) -> Result<RemoveLiquidityResult>;

    /// Remove batch liquidity from multiple positions in one transaction
    ///
    /// This is more efficient than removing liquidity individually.
    async fn remove_batch_liquidity(
        &self,
        ctx: &RpcContext,
        payer: &Keypair,
        params: RemoveBatchLiquidityParams,
        options: RemoveLiquidityOptions,
    ) -> Result<RemoveBatchLiquidityResult>;

    /// Collect fees from a position
    async fn collect(
        &self,
        ctx: &RpcContext,
        payer: &Keypair,
        params: CollectParams,
        options: CollectOptions,
    ) -> Result<CollectResult>;

    /// Calculate the required amounts for adding liquidity
    async fn calculate_add_liquidity_amounts(
        &self,
        ctx: &RpcContext,
        amount: CurrencyAmount,
        lower_price: f64,
        upper_price: f64,
    ) -> Result<(CurrencyAmount, CurrencyAmount)>;

    /// Simulate adding liquidity without executing the transaction
    ///
    /// This method builds the transaction instructions and simulates execution
    /// to verify the transaction would succeed and estimate compute units.
    ///
    /// # Arguments
    /// * `ctx` - The RPC context to use for simulation
    /// * `payer` - The keypair that will pay for the transaction fees
    /// * `params` - Parameters for adding liquidity
    /// * `options` - Options for adding liquidity
    ///
    /// # Returns
    /// The simulation result containing execution status, logs, compute units
    /// used, and parsed event data if available
    async fn simulate_add_liquidity(
        &self,
        ctx: &RpcContext,
        payer: &Keypair,
        params: AddLiquidityParams,
        options: AddLiquidityOptions,
    ) -> Result<SimulateAddLiquidityResult>;

    /// Simulate removing liquidity without executing the transaction
    ///
    /// This method builds the transaction instructions and simulates execution
    /// to verify the transaction would succeed and estimate compute units.
    ///
    /// # Arguments
    /// * `ctx` - The RPC context to use for simulation
    /// * `payer` - The keypair that will pay for the transaction fees
    /// * `params` - Parameters for removing liquidity
    /// * `options` - Options for removing liquidity
    ///
    /// # Returns
    /// The simulation result containing execution status, logs, compute units
    /// used, and parsed event data if available
    async fn simulate_remove_liquidity(
        &self,
        ctx: &RpcContext,
        payer: &Keypair,
        params: RemoveLiquidityParams,
        options: RemoveLiquidityOptions,
    ) -> Result<SimulateRemoveLiquidityResult>;

    /// Simulate collecting fees without executing the transaction
    ///
    /// This method builds the transaction instructions and simulates execution
    /// to verify the transaction would succeed and estimate compute units.
    ///
    /// # Arguments
    /// * `ctx` - The RPC context to use for simulation
    /// * `payer` - The keypair that will pay for the transaction fees
    /// * `params` - Parameters for collecting fees
    /// * `options` - Options for collecting fees
    ///
    /// # Returns
    /// The simulation result containing execution status, logs, compute units
    /// used, and fees quote data
    async fn simulate_collect(
        &self,
        ctx: &RpcContext,
        payer: &Keypair,
        params: CollectParams,
        options: CollectOptions,
    ) -> Result<SimulateCollectResult>;
}