waterpump-evm-pool-sdk 0.1.0

EVM pool SDK — viewers, infusers, harvesters, swappers for Uniswap V3/V4, PancakeSwap, Slipstream, Shadow, Algebra
Documentation
use alloy::{
    primitives::{Address, U256},
    rpc::types::Log,
};
use alloy_sol_types::sol;
use anyhow::{anyhow, Result};

// Uniswap V3 NonfungiblePositionManager event definitions.
// These events are emitted by the position manager contract when position
// operations occur.
sol! {
    interface INonfungiblePositionManagerEvents {
        /// @notice Emitted when liquidity is increased for a position NFT
        /// @dev Also emitted when a token is minted
        /// @param tokenId The ID of the token for which liquidity was increased
        /// @param liquidity The amount by which liquidity for the NFT position was increased
        /// @param amount0 The amount of token0 that was paid for the increase in liquidity
        /// @param amount1 The amount of token1 that was paid for the increase in liquidity
        event IncreaseLiquidity(
            uint256 indexed tokenId,
            uint128 liquidity,
            uint256 amount0,
            uint256 amount1
        );

        /// @notice Emitted when liquidity is decreased for a position NFT
        /// @param tokenId The ID of the token for which liquidity was decreased
        /// @param liquidity The amount by which liquidity for the NFT position was decreased
        /// @param amount0 The amount of token0 that was accounted for the decrease in liquidity
        /// @param amount1 The amount of token1 that was accounted for the decrease in liquidity
        event DecreaseLiquidity(
            uint256 indexed tokenId,
            uint128 liquidity,
            uint256 amount0,
            uint256 amount1
        );

        /// @notice Emitted when tokens are collected for a position NFT
        /// @dev The amounts reported may not be exactly equivalent to the amounts transferred, due to rounding behavior
        /// @param tokenId The ID of the token for which underlying tokens were collected
        /// @param recipient The address of the account that received the collected tokens
        /// @param amount0 The amount of token0 owed to the position that was collected
        /// @param amount1 The amount of token1 owed to the position that was collected
        event Collect(
            uint256 indexed tokenId,
            address recipient,
            uint256 amount0,
            uint256 amount1
        );
    }
}

/// Decoded IncreaseLiquidity event data
#[derive(Debug, Clone)]
pub struct IncreaseLiquidityEvent {
    pub token_id: U256,
    pub liquidity: u128,
    pub amount0: U256,
    pub amount1: U256,
}

/// Decoded DecreaseLiquidity event data
#[derive(Debug, Clone)]
pub struct DecreaseLiquidityEvent {
    pub token_id: U256,
    pub liquidity: u128,
    pub amount0: U256,
    pub amount1: U256,
}

/// Decoded Collect event data
#[derive(Debug, Clone)]
pub struct CollectEvent {
    pub token_id: U256,
    pub recipient: Address,
    pub amount0: U256,
    pub amount1: U256,
}

/// Decode IncreaseLiquidity event from a log
///
/// # Arguments
///
/// * `log` - The log containing the event data
/// * `position_manager_address` - The address of the NonfungiblePositionManager
///   contract
///
/// # Returns
///
/// Returns the decoded IncreaseLiquidity event data if found, or an error if:
/// - The event is from an unexpected contract address
/// - The event cannot be decoded
pub fn decode_increase_liquidity_event(
    log: &Log,
    position_manager_address: Address,
) -> Result<IncreaseLiquidityEvent> {
    // Verify the event is from the expected position manager address
    if log.address() != position_manager_address {
        return Err(anyhow!(
            "IncreaseLiquidity event from unexpected address: expected {:?}, got {:?}",
            position_manager_address,
            log.address()
        ));
    }

    let event = log
        .log_decode::<INonfungiblePositionManagerEvents::IncreaseLiquidity>()
        .map(|decoded| decoded.inner)
        .map_err(|e| anyhow!("Not an IncreaseLiquidity event: {:?}", e))?;

    Ok(IncreaseLiquidityEvent {
        token_id: event.tokenId,
        liquidity: event.liquidity,
        amount0: event.amount0,
        amount1: event.amount1,
    })
}

/// Decode DecreaseLiquidity event from a log
///
/// # Arguments
///
/// * `log` - The log containing the event data
/// * `position_manager_address` - The address of the NonfungiblePositionManager
///   contract
///
/// # Returns
///
/// Returns the decoded DecreaseLiquidity event data if found, or an error if:
/// - The event is from an unexpected contract address
/// - The event cannot be decoded
pub fn decode_decrease_liquidity_event(
    log: &Log,
    position_manager_address: Address,
) -> Result<DecreaseLiquidityEvent> {
    // Verify the event is from the expected position manager address
    if log.address() != position_manager_address {
        return Err(anyhow!(
            "DecreaseLiquidity event from unexpected address: expected {:?}, got {:?}",
            position_manager_address,
            log.address()
        ));
    }

    let event = log
        .log_decode::<INonfungiblePositionManagerEvents::DecreaseLiquidity>()
        .map(|decoded| decoded.inner)
        .map_err(|e| anyhow!("Not a DecreaseLiquidity event: {:?}", e))?;

    Ok(DecreaseLiquidityEvent {
        token_id: event.tokenId,
        liquidity: event.liquidity,
        amount0: event.amount0,
        amount1: event.amount1,
    })
}

/// Decode Collect event from a log
///
/// # Arguments
///
/// * `log` - The log containing the event data
/// * `position_manager_address` - The address of the NonfungiblePositionManager
///   contract
///
/// # Returns
///
/// Returns the decoded Collect event data if found, or an error if:
/// - The event is from an unexpected contract address
/// - The event cannot be decoded
pub fn decode_collect_event(log: &Log, position_manager_address: Address) -> Result<CollectEvent> {
    // Verify the event is from the expected position manager address
    if log.address() != position_manager_address {
        return Err(anyhow!(
            "Collect event from unexpected address: expected {:?}, got {:?}",
            position_manager_address,
            log.address()
        ));
    }

    let event = log
        .log_decode::<INonfungiblePositionManagerEvents::Collect>()
        .map(|decoded| decoded.inner)
        .map_err(|e| anyhow!("Not a Collect event: {:?}", e))?;

    Ok(CollectEvent {
        token_id: event.tokenId,
        recipient: event.recipient,
        amount0: event.amount0,
        amount1: event.amount1,
    })
}