use alloy::{network::Network, primitives::Address, providers::Provider};
use anyhow::{Context, Result};
use tracing::{debug, instrument};
use uniswap_lens::bindings::ierc20::IERC20::IERC20Instance;
use uniswap_sdk_core::{
prelude::{Currency, Token},
token,
};
use uniswap_v3_sdk::prelude::FeeAmount;
#[cfg(feature = "slipstream")]
use waterpump_evm_core::pool_key::SlipstreamPoolKey;
use waterpump_evm_core::pool_key::V3PoolKey;
#[cfg(feature = "algebra")]
use crate::types::quickswap_pool_key::QuickswapPoolKey;
#[instrument(skip(provider), fields(pool_address = ?pool_address, chain_id = chain_id))]
pub async fn get_pool_underlying_currencies_v3<P: Provider<N>, N: Network>(
provider: &P,
pool_address: Address,
chain_id: u64,
) -> Result<(Currency, Currency)> {
use uniswap_lens::bindings::iuniswapv3pool::IUniswapV3Pool::IUniswapV3PoolInstance;
let pool_contract = IUniswapV3PoolInstance::new(pool_address, provider);
let multicall = provider.multicall().add(pool_contract.token0()).add(pool_contract.token1());
let (token0_address, token1_address) =
multicall.aggregate().await.context("Failed to call token0()")?;
debug!(
token0_address = ?token0_address,
token1_address = ?token1_address,
"Retrieved token addresses from pool"
);
let token0_contract = IERC20Instance::new(token0_address, provider);
let token1_contract = IERC20Instance::new(token1_address, provider);
let multicall = provider
.multicall()
.add(token0_contract.decimals())
.add(token0_contract.symbol())
.add(token1_contract.decimals())
.add(token1_contract.symbol());
let (token0_decimals, token0_symbol, token1_decimals, token1_symbol) =
multicall.aggregate().await.context("Failed to call token0 decimals()")?;
debug!(
token0_decimals = token0_decimals,
token0_symbol = %token0_symbol,
token1_decimals = token1_decimals,
token1_symbol = %token1_symbol,
"Retrieved token metadata"
);
let token0: Currency = token!(
chain_id,
&format!("{:x}", token0_address),
token0_decimals,
&token0_symbol,
&token0_symbol
)
.into();
let token1: Currency = token!(
chain_id,
&format!("{:x}", token1_address),
token1_decimals,
&token1_symbol,
&token1_symbol
)
.into();
Ok((token0, token1))
}
#[instrument(skip(provider), fields(pool_address = ?pool_address, chain_id = chain_id))]
pub async fn get_pool_key_v3<P: Provider<N>, N: Network>(
provider: &P,
pool_address: Address,
chain_id: u64,
) -> Result<V3PoolKey> {
use uniswap_lens::bindings::iuniswapv3pool::IUniswapV3Pool::IUniswapV3PoolInstance;
let (token0, token1) =
get_pool_underlying_currencies_v3(provider, pool_address, chain_id).await?;
let contract = IUniswapV3PoolInstance::new(pool_address, provider);
let fee = contract.fee().call().await?;
let fee_amount: FeeAmount = fee.into();
Ok(V3PoolKey { token_a: token0, token_b: token1, fee: fee_amount })
}
#[cfg(feature = "slipstream")]
#[instrument(skip(provider), fields(pool_address = ?pool_address, chain_id = chain_id))]
pub async fn get_pool_key_slipstream<P: Provider<N>, N: Network>(
provider: &P,
pool_address: Address,
chain_id: u64,
) -> Result<SlipstreamPoolKey> {
use waterpump_evm_slipstream_client::interfaces::ICLPool::ICLPoolInstance;
let (token0, token1) =
get_pool_underlying_currencies_v3(provider, pool_address, chain_id).await?;
let pool_contract = ICLPoolInstance::new(pool_address, provider);
let tick_spacing = pool_contract.tickSpacing().call().await?;
Ok(SlipstreamPoolKey { token_a: token0, token_b: token1, tick_spacing })
}
#[cfg(feature = "algebra")]
#[instrument(skip(provider), fields(pool_address = ?pool_address, chain_id = chain_id))]
pub async fn get_pool_key_quickswap<P: Provider<N>, N: Network>(
provider: &P,
pool_address: Address,
chain_id: u64,
) -> Result<QuickswapPoolKey> {
let (token0, token1) =
get_pool_underlying_currencies_v3(provider, pool_address, chain_id).await?;
let deployer = waterpump_evm_algebra_client::addresses::get_deployment_addresses(chain_id)
.with_context(|| format!("Quickswap addresses not found for chain_id: {}", chain_id))?
.pool_deployer;
Ok(QuickswapPoolKey { token_a: token0, token_b: token1, deployer })
}