waterpump-evm-pool-sdk 0.1.0

EVM pool SDK — viewers, infusers, harvesters, swappers for Uniswap V3/V4, PancakeSwap, Slipstream, Shadow, Algebra
Documentation
/// Macro to generate PoolViewer trait implementation for V3 pool viewers
/// Assumes the struct has pool_address() method and pool_key() method returning
/// V3PoolKey with token_a and token_b
#[macro_export]
macro_rules! impl_v3_pool_viewer {
    ($struct_name:ident) => {
        #[async_trait::async_trait]
        impl $crate::traits::pool_viewer::PoolViewer for $struct_name {
            #[tracing::instrument(skip(self), fields(pool_address = ?self.pool_address()))]
            async fn currency0_price(&self, block_id: Option<alloy::eips::BlockId>) -> anyhow::Result<uniswap_sdk_core::prelude::Price<uniswap_sdk_core::prelude::Currency, uniswap_sdk_core::prelude::Currency>> {
                let slot0 = self.slot0(block_id).await?;
                let pool_key = self.pool_key();
                let price = $crate::pool_viewers::v3::utils::calculate_price_from_sqrt_price_x96(
                    slot0.sqrtPriceX96,
                    pool_key.token_a.clone(),
                    pool_key.token_b.clone(),
                );
                tracing::debug!(price = %price.to_significant(8, None).unwrap_or_else(|_| "N/A".to_string()), "Currency0 price calculated");
                Ok(price)
            }

            #[tracing::instrument(skip(self), fields(pool_address = ?self.pool_address()))]
            async fn currency1_price(&self, block_id: Option<alloy::eips::BlockId>) -> anyhow::Result<uniswap_sdk_core::prelude::Price<uniswap_sdk_core::prelude::Currency, uniswap_sdk_core::prelude::Currency>> {
                let price = self.currency0_price(block_id).await?.invert();
                tracing::debug!(price = %price.to_significant(8, None).unwrap_or_else(|_| "N/A".to_string()), "Currency1 price calculated (inverted)");
                Ok(price)
            }
        }
    };
}

/// Macro to generate PoolViewer trait implementation for Slipstream pool
/// viewers Assumes the struct has pool_address() method and pool_key() method
/// returning SlipstreamPoolKey with token_a and token_b
#[macro_export]
macro_rules! impl_slipstream_pool_viewer {
    ($struct_name:ident) => {
        #[async_trait::async_trait]
        impl $crate::traits::pool_viewer::PoolViewer for $struct_name {
            #[tracing::instrument(skip(self), fields(pool_address = ?self.pool_address()))]
            async fn currency0_price(&self, block_id: Option<alloy::eips::BlockId>) -> anyhow::Result<uniswap_sdk_core::prelude::Price<uniswap_sdk_core::prelude::Currency, uniswap_sdk_core::prelude::Currency>> {
                let slot0 = self.slot0(block_id).await?;
                let pool_key = self.pool_key();
                let price = $crate::pool_viewers::slipstream::utils::calculate_price_from_sqrt_price_x96(
                    slot0.sqrtPriceX96,
                    pool_key.token_a.clone(),
                    pool_key.token_b.clone(),
                );
                tracing::debug!(price = %price.to_significant(8, None).unwrap_or_else(|_| "N/A".to_string()), "Currency0 price calculated");
                Ok(price)
            }

            #[tracing::instrument(skip(self), fields(pool_address = ?self.pool_address()))]
            async fn currency1_price(&self, block_id: Option<alloy::eips::BlockId>) -> anyhow::Result<uniswap_sdk_core::prelude::Price<uniswap_sdk_core::prelude::Currency, uniswap_sdk_core::prelude::Currency>> {
                let price = self.currency0_price(block_id).await?.invert();
                tracing::debug!(price = %price.to_significant(8, None).unwrap_or_else(|_| "N/A".to_string()), "Currency1 price calculated (inverted)");
                Ok(price)
            }
        }
    };
}

/// Macro to generate PoolViewer trait implementation for PancakeSwap V3 pool
/// viewers Assumes the struct has pool_address() method and pool_key() method
/// returning V3PoolKey with token_a and token_b
/// Note: PancakeSwap V3 uses the same interface as Uniswap V3
#[macro_export]
macro_rules! impl_pancake_v3_pool_viewer {
    ($struct_name:ident) => {
        #[async_trait::async_trait]
        impl $crate::traits::pool_viewer::PoolViewer for $struct_name {
            #[tracing::instrument(skip(self), fields(pool_address = ?self.pool_address()))]
            async fn currency0_price(&self, block_id: Option<alloy::eips::BlockId>) -> anyhow::Result<uniswap_sdk_core::prelude::Price<uniswap_sdk_core::prelude::Currency, uniswap_sdk_core::prelude::Currency>> {
                let slot0 = self.slot0(block_id).await?;
                let pool_key = self.pool_key();
                let price = $crate::pool_viewers::v3::utils::calculate_price_from_sqrt_price_x96(
                    slot0.sqrtPriceX96,
                    pool_key.token_a.clone(),
                    pool_key.token_b.clone(),
                );
                tracing::debug!(price = %price.to_significant(8, None).unwrap_or_else(|_| "N/A".to_string()), "Currency0 price calculated");
                Ok(price)
            }

            #[tracing::instrument(skip(self), fields(pool_address = ?self.pool_address()))]
            async fn currency1_price(&self, block_id: Option<alloy::eips::BlockId>) -> anyhow::Result<uniswap_sdk_core::prelude::Price<uniswap_sdk_core::prelude::Currency, uniswap_sdk_core::prelude::Currency>> {
                let price = self.currency0_price(block_id).await?.invert();
                tracing::debug!(price = %price.to_significant(8, None).unwrap_or_else(|_| "N/A".to_string()), "Currency1 price calculated (inverted)");
                Ok(price)
            }
        }
    };
}

/// Macro to generate PoolViewer trait implementation for Ramses V3 pool
/// viewers Assumes the struct has pool_address() method and pool_key() method
/// returning V3PoolKey with token_a and token_b
/// Note: Ramses V3 uses the same interface as Uniswap V3 (IRamsesV3PoolState is
/// compatible with IUniswapV3Pool), so we use uniswap_lens bindings
#[macro_export]
macro_rules! impl_shadow_pool_viewer {
    ($struct_name:ident) => {
        #[async_trait::async_trait]
        impl $crate::traits::pool_viewer::PoolViewer for $struct_name {
            #[tracing::instrument(skip(self), fields(pool_address = ?self.pool_address()))]
            async fn currency0_price(&self, block_id: Option<alloy::eips::BlockId>) -> anyhow::Result<uniswap_sdk_core::prelude::Price<uniswap_sdk_core::prelude::Currency, uniswap_sdk_core::prelude::Currency>> {
                let slot0 = self.slot0(block_id).await?;
                let pool_key = self.pool_key();
                let price = $crate::pool_viewers::v3::utils::calculate_price_from_sqrt_price_x96(
                    slot0.sqrtPriceX96,
                    pool_key.token_a.clone(),
                    pool_key.token_b.clone(),
                );
                tracing::debug!(price = %price.to_significant(8, None).unwrap_or_else(|_| "N/A".to_string()), "Currency0 price calculated");
                Ok(price)
            }

            #[tracing::instrument(skip(self), fields(pool_address = ?self.pool_address()))]
            async fn currency1_price(&self, block_id: Option<alloy::eips::BlockId>) -> anyhow::Result<uniswap_sdk_core::prelude::Price<uniswap_sdk_core::prelude::Currency, uniswap_sdk_core::prelude::Currency>> {
                let price = self.currency0_price(block_id).await?.invert();
                tracing::debug!(price = %price.to_significant(8, None).unwrap_or_else(|_| "N/A".to_string()), "Currency1 price calculated (inverted)");
                Ok(price)
            }
        }
    };
}

/// Macro to generate PoolViewer trait implementation for Algebra pool viewers.
///
/// Assumes the struct implements `PoolState` (sqrt_price_x96) and has
/// `pool_key()` returning a key with `token_a` and `token_b`.
#[macro_export]
macro_rules! impl_quickswap_pool_viewer {
    ($struct_name:ident) => {
        #[async_trait::async_trait]
        impl $crate::traits::pool_viewer::PoolViewer for $struct_name {
            #[tracing::instrument(skip(self), fields(pool_address = ?self.pool_address()))]
            async fn currency0_price(
                &self,
                block_id: Option<alloy::eips::BlockId>,
            ) -> anyhow::Result<
                uniswap_sdk_core::prelude::Price<
                    uniswap_sdk_core::prelude::Currency,
                    uniswap_sdk_core::prelude::Currency,
                >,
            > {
                let sqrt_price_x96 = $crate::traits::pool_state::PoolState::sqrt_price_x96(self, block_id).await?;
                let pool_key = self.pool_key();
                let price = $crate::pool_viewers::v3::utils::calculate_price_from_sqrt_price_x96(
                    sqrt_price_x96,
                    pool_key.token_a.clone(),
                    pool_key.token_b.clone(),
                );
                tracing::debug!(
                    price = %price.to_significant(8, None).unwrap_or_else(|_| "N/A".to_string()),
                    "Currency0 price calculated"
                );
                Ok(price)
            }

            #[tracing::instrument(skip(self), fields(pool_address = ?self.pool_address()))]
            async fn currency1_price(
                &self,
                block_id: Option<alloy::eips::BlockId>,
            ) -> anyhow::Result<
                uniswap_sdk_core::prelude::Price<
                    uniswap_sdk_core::prelude::Currency,
                    uniswap_sdk_core::prelude::Currency,
                >,
            > {
                let price = self.currency0_price(block_id).await?.invert();
                tracing::debug!(
                    price = %price.to_significant(8, None).unwrap_or_else(|_| "N/A".to_string()),
                    "Currency1 price calculated (inverted)"
                );
                Ok(price)
            }
        }
    };
}

/// Macro to generate PoolViewer trait implementation for V4 pool viewers
/// Assumes the struct has pool_id() method, pool_key() method returning
/// V4PoolKey, and get_pool_manager() method
#[macro_export]
macro_rules! impl_v4_pool_viewer {
    ($struct_name:ident) => {
        #[async_trait::async_trait]
        impl $crate::traits::pool_viewer::PoolViewer for $struct_name {
            async fn currency0_price(
                &self,
                block_id: Option<alloy::eips::BlockId>,
            ) -> anyhow::Result<
                uniswap_sdk_core::prelude::Price<
                    uniswap_sdk_core::prelude::Currency,
                    uniswap_sdk_core::prelude::Currency,
                >,
            > {
                let slot0 = self.slot0(block_id).await?;
                tracing::debug!("Slot0 retrieved: {:?}", slot0);
                let pool_key = self.pool_key();
                let price = $crate::common::v4_utils::calculate_price_from_sqrt_price_x96(
                    slot0.0,
                    pool_key.token_a.clone(),
                    pool_key.token_b.clone(),
                );
                Ok(price)
            }

            async fn currency1_price(
                &self,
                block_id: Option<alloy::eips::BlockId>,
            ) -> anyhow::Result<
                uniswap_sdk_core::prelude::Price<
                    uniswap_sdk_core::prelude::Currency,
                    uniswap_sdk_core::prelude::Currency,
                >,
            > {
                let price = self.currency0_price(block_id).await?;
                Ok(price.invert())
            }
        }
    };
}