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 MultiPoolViewer trait implementation for V4 multi-pool
/// viewers Assumes the struct has pools() method returning &[(V4PoolKey,
/// B256)], get_state_view() method, and is_token_a_base field
#[macro_export]
macro_rules! impl_v4_multi_pool_viewer {
    ($struct_name:ident) => {
        impl $struct_name {
            /// Get slot0 data from all pools using StateView contract
            #[tracing::instrument(skip(self), fields(pool_count = self.pools().len()))]
            pub async fn get_slot0s(
                &self,
                block_id: Option<alloy::eips::BlockId>,
            ) -> anyhow::Result<
                Vec<(
                    alloy::primitives::aliases::U160,
                    alloy::primitives::aliases::I24,
                    alloy::primitives::aliases::U24,
                    alloy::primitives::aliases::U24,
                )>,
            > {
                let state_view = self.get_state_view();
                let mut multicall = alloy::providers::Provider::multicall(&self.provider).dynamic();
                if let Some(block_id) = block_id {
                    multicall = multicall.block(block_id);
                }
                tracing::debug!("Building multicall for {} pools", self.pools().len());
                for (_, pool_id) in self.pools() {
                    multicall = multicall.add_dynamic(state_view.getSlot0(*pool_id));
                }
                let result = multicall.aggregate().await?;
                tracing::debug!("Multicall completed with {} results", result.len());

                let slot0s: Vec<(
                    alloy::primitives::aliases::U160,
                    alloy::primitives::aliases::I24,
                    alloy::primitives::aliases::U24,
                    alloy::primitives::aliases::U24,
                )> = result
                    .into_iter()
                    .map(|slot0| (slot0.sqrtPriceX96, slot0.tick, slot0.protocolFee, slot0.lpFee))
                    .collect();

                Ok(slot0s)
            }
        }

        #[async_trait::async_trait]
        impl $crate::traits::pool_viewer::MultiPoolViewer for $struct_name {
            async fn currency0_prices(
                &self,
                block_id: Option<alloy::eips::BlockId>,
            ) -> anyhow::Result<
                Vec<
                    uniswap_sdk_core::prelude::Price<
                        uniswap_sdk_core::prelude::Currency,
                        uniswap_sdk_core::prelude::Currency,
                    >,
                >,
            > {
                let slot0s = self.get_slot0s(block_id).await?;

                tracing::debug!("Calculating prices for {} pools", slot0s.len());
                let prices: Vec<
                    uniswap_sdk_core::prelude::Price<
                        uniswap_sdk_core::prelude::Currency,
                        uniswap_sdk_core::prelude::Currency,
                    >,
                > = slot0s
                    .into_iter()
                    .zip(self.pools().iter())
                    .map(|(slot0, (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(),
                        );
                        price
                    })
                    .collect();
                tracing::debug!("All currency0 prices calculated");
                Ok(prices)
            }

            async fn currency1_prices(
                &self,
                block_id: Option<alloy::eips::BlockId>,
            ) -> anyhow::Result<
                Vec<
                    uniswap_sdk_core::prelude::Price<
                        uniswap_sdk_core::prelude::Currency,
                        uniswap_sdk_core::prelude::Currency,
                    >,
                >,
            > {
                let prices = self.currency0_prices(block_id).await?;

                Ok(prices.into_iter().map(|price| price.invert()).collect())
            }
        }
    };
}