kabu_defi_pools/loaders/
uniswap3.rs

1use crate::protocols::{fetch_uni3_factory, UniswapV3Protocol};
2use crate::{pool_loader, MaverickPool, PancakeV3Pool, UniswapV3Pool};
3use alloy::primitives::Bytes;
4use alloy::primitives::Log as EVMLog;
5use alloy::sol_types::SolEventInterface;
6use eyre::eyre;
7use futures::Stream;
8use kabu_defi_abi::uniswap3::IUniswapV3Pool::IUniswapV3PoolEvents;
9use kabu_evm_db::KabuDBError;
10use kabu_types_blockchain::{KabuDataTypes, KabuDataTypesEVM, KabuDataTypesEthereum};
11use kabu_types_entities::{get_protocol_by_factory, PoolClass, PoolId, PoolLoader, PoolProtocol, PoolWrapper};
12use revm::DatabaseRef;
13use std::future::Future;
14use std::pin::Pin;
15use std::sync::Arc;
16use tracing::error;
17
18pool_loader!(UniswapV3PoolLoader);
19
20impl<P, N, LDT> PoolLoader<P, N, LDT> for UniswapV3PoolLoader<P, N, LDT>
21where
22    N: Network,
23    P: Provider<N> + Clone + 'static,
24    LDT: KabuDataTypesEVM + 'static,
25{
26    fn get_pool_class_by_log(&self, log_entry: &LDT::Log) -> Option<(PoolId, PoolClass)> {
27        let log_entry: Option<EVMLog> = EVMLog::new(log_entry.address(), log_entry.topics().to_vec(), log_entry.data().data.clone());
28        match log_entry {
29            Some(log_entry) => match IUniswapV3PoolEvents::decode_log(&log_entry) {
30                Ok(event) => match event.data {
31                    IUniswapV3PoolEvents::Swap(_)
32                    | IUniswapV3PoolEvents::Mint(_)
33                    | IUniswapV3PoolEvents::Burn(_)
34                    | IUniswapV3PoolEvents::Initialize(_) => Some((PoolId::Address(log_entry.address), PoolClass::UniswapV3)),
35                    _ => None,
36                },
37                Err(_) => None,
38            },
39            None => None,
40        }
41    }
42
43    fn fetch_pool_by_id<'a>(&'a self, pool_id: PoolId) -> Pin<Box<dyn Future<Output = eyre::Result<PoolWrapper>> + Send + 'a>> {
44        Box::pin(async move {
45            if let Some(provider) = self.provider.clone() {
46                self.fetch_pool_by_id_from_provider(pool_id, provider).await
47            } else {
48                Err(eyre!("NO_PROVIDER"))
49            }
50        })
51    }
52
53    fn fetch_pool_by_id_from_provider<'a>(
54        &'a self,
55        pool_id: PoolId,
56        provider: P,
57    ) -> Pin<Box<dyn Future<Output = eyre::Result<PoolWrapper>> + Send + 'a>> {
58        Box::pin(async move {
59            let pool_address = match pool_id {
60                PoolId::Address(addr) => addr,
61                PoolId::B256(_) => return Err(eyre!("UniswapV3 pools only support Address-based pool IDs")),
62            };
63
64            let factory_address_result = fetch_uni3_factory(provider.clone(), pool_address).await;
65            match factory_address_result {
66                Ok(factory_address) => match get_protocol_by_factory(factory_address) {
67                    PoolProtocol::PancakeV3 => {
68                        Ok(PoolWrapper::new(Arc::new(PancakeV3Pool::fetch_pool_data(provider.clone(), pool_address).await?)))
69                    }
70                    PoolProtocol::Maverick => {
71                        Ok(PoolWrapper::new(Arc::new(MaverickPool::fetch_pool_data(provider.clone(), pool_address).await?)))
72                    }
73                    _ => Ok(PoolWrapper::new(Arc::new(UniswapV3Pool::fetch_pool_data(provider.clone(), pool_address).await?))),
74                },
75                Err(e) => {
76                    error!("Error fetching factory address at {:#20x}: {}", pool_address, e);
77                    Err(eyre!("CANNOT_GET_FACTORY_ADDRESS"))
78                }
79            }
80        })
81    }
82
83    fn fetch_pool_by_id_from_evm(&self, pool_id: PoolId, db: &dyn DatabaseRef<Error = KabuDBError>) -> eyre::Result<PoolWrapper> {
84        let pool_address = match pool_id {
85            PoolId::Address(addr) => addr,
86            PoolId::B256(_) => return Err(eyre!("UniswapV3 pools only support Address-based pool IDs")),
87        };
88        Ok(PoolWrapper::new(Arc::new(UniswapV3Pool::fetch_pool_data_evm(db, pool_address)?)))
89    }
90
91    fn is_code(&self, code: &Bytes) -> bool {
92        UniswapV3Protocol::is_code(code)
93    }
94
95    fn protocol_loader(&self) -> eyre::Result<Pin<Box<dyn Stream<Item = (PoolId, PoolClass)> + Send>>> {
96        Err(eyre!("NOT_IMPLEMENTED"))
97    }
98}