kabu_defi_market/
required_pools_actor.rs

1use alloy_network::Network;
2use alloy_primitives::Address;
3use alloy_provider::Provider;
4use eyre::Result;
5use kabu_core_components::Component;
6use reth_tasks::TaskExecutor;
7use revm::DatabaseRef;
8use revm::{Database, DatabaseCommit};
9use std::marker::PhantomData;
10use std::sync::Arc;
11use tokio::sync::RwLock;
12use tracing::{debug, error, info};
13
14use crate::pool_loader_actor::fetch_and_add_pool_by_pool_id;
15
16use kabu_core_blockchain::{Blockchain, BlockchainState};
17use kabu_evm_db::KabuDBError;
18use kabu_node_debug_provider::DebugProviderExt;
19use kabu_types_market::MarketState;
20use kabu_types_market::required_state::{RequiredState, RequiredStateReader};
21use kabu_types_market::{Market, PoolClass, PoolId, PoolLoaders};
22use reth_node_types::NodePrimitives;
23
24async fn required_pools_loader_worker<P, N, DB, NP>(
25    client: P,
26    pool_loaders: Arc<PoolLoaders<P, N, NP>>,
27    pools: Vec<(PoolId, PoolClass)>,
28    required_state: Option<RequiredState>,
29    market: Arc<RwLock<Market>>,
30    market_state: Arc<RwLock<MarketState<DB>>>,
31) -> Result<String>
32where
33    N: Network<TransactionRequest = alloy_rpc_types::TransactionRequest>,
34    P: Provider<N> + DebugProviderExt<N> + Send + Sync + Clone + 'static,
35    DB: Database<Error = KabuDBError> + DatabaseRef<Error = KabuDBError> + DatabaseCommit + Send + Sync + Clone + 'static,
36    NP: NodePrimitives + 'static,
37{
38    for (pool_id, pool_class) in pools {
39        debug!(class=%pool_class, %pool_id, "Loading pool");
40        match fetch_and_add_pool_by_pool_id(client.clone(), market.clone(), market_state.clone(), pool_loaders.clone(), pool_id, pool_class)
41            .await
42        {
43            Ok(_) => {
44                info!(class=%pool_class, %pool_id, "pool loaded")
45            }
46            Err(error) => {
47                error!(%error, "load_pool_with_provider")
48            }
49        }
50    }
51    //
52    //
53    //     match pool_class {
54    //         PoolClass::UniswapV2 | PoolClass::UniswapV3 => {
55    //             if let Err(error) =
56    //                 fetch_and_add_pool_by_pool_id(client.clone(), market.clone(), market_state.clone(), pool_address, pool_class).await
57    //             {
58    //                 error!(%error, address = %pool_address, "fetch_and_add_pool_by_address")
59    //             }
60    //         }
61    //         PoolClass::Curve => {
62    //             if let Ok(curve_contract) = CurveProtocol::get_contract_from_code(client.clone(), pool_address).await {
63    //                 let curve_pool = CurvePool::<P, T, N>::fetch_pool_data_with_default_encoder(client.clone(), curve_contract).await?;
64    //                 fetch_state_and_add_pool(client.clone(), market.clone(), market_state.clone(), curve_pool.into()).await?
65    //             } else {
66    //                 error!("CURVE_POOL_NOT_LOADED");
67    //             }
68    //         }
69    //         _ => {
70    //             error!("Unknown pool class")
71    //         }
72    //     }
73    //     debug!(class=%pool_class, address=%pool_address, "Loaded pool");
74    // }
75
76    if let Some(required_state) = required_state {
77        let update = RequiredStateReader::fetch_calls_and_slots(client.clone(), required_state, None).await?;
78        market_state.write().await.apply_geth_update(update);
79    }
80
81    Ok("required_pools_loader_worker".to_string())
82}
83
84pub struct RequiredPoolLoaderActor<P, N, DB, NP>
85where
86    N: Network,
87    P: Provider<N> + DebugProviderExt<N> + Send + Sync + Clone + 'static,
88    DB: Database + DatabaseRef + DatabaseCommit + Clone + Send + Sync + 'static,
89    NP: NodePrimitives + 'static,
90{
91    client: P,
92    pool_loaders: Arc<PoolLoaders<P, N, NP>>,
93    pools: Vec<(PoolId, PoolClass)>,
94    required_state: Option<RequiredState>,
95
96    market: Option<Arc<RwLock<Market>>>,
97
98    market_state: Option<Arc<RwLock<MarketState<DB>>>>,
99    _n: PhantomData<N>,
100}
101
102impl<P, N, DB, NP> RequiredPoolLoaderActor<P, N, DB, NP>
103where
104    N: Network,
105    P: Provider<N> + DebugProviderExt<N> + Send + Sync + Clone + 'static,
106    DB: Database + DatabaseRef + DatabaseCommit + Clone + Send + Sync + 'static,
107    NP: NodePrimitives + 'static,
108{
109    pub fn new(client: P, pool_loaders: Arc<PoolLoaders<P, N, NP>>) -> Self {
110        Self { client, pools: Vec::new(), pool_loaders, required_state: None, market: None, market_state: None, _n: PhantomData }
111    }
112
113    pub fn with_pool_address(self, address: Address, pool_class: PoolClass) -> Self {
114        let mut pools = self.pools;
115        pools.push((PoolId::Address(address), pool_class));
116        Self { pools, ..self }
117    }
118
119    pub fn on_bc(self, bc: &Blockchain<NP>, state: &BlockchainState<DB, NP>) -> Self {
120        Self { market: Some(bc.market()), market_state: Some(state.market_state_commit()), ..self }
121    }
122
123    pub fn with_required_state(self, required_state: RequiredState) -> Self {
124        Self { required_state: Some(required_state), ..self }
125    }
126}
127
128impl<P, N, DB, NP> Component for RequiredPoolLoaderActor<P, N, DB, NP>
129where
130    N: Network<TransactionRequest = alloy_rpc_types::TransactionRequest>,
131    P: Provider<N> + DebugProviderExt<N> + Send + Sync + Clone + 'static,
132    DB: Database<Error = KabuDBError> + DatabaseRef<Error = KabuDBError> + DatabaseCommit + Send + Sync + Clone + 'static,
133    NP: NodePrimitives + 'static,
134{
135    fn spawn(self, executor: TaskExecutor) -> Result<()> {
136        let _name = self.name();
137        let client = self.client;
138        let pool_loaders = self.pool_loaders;
139        let pools = self.pools;
140        let required_state = self.required_state;
141        let market = self.market.ok_or_else(|| eyre::eyre!("market not set"))?;
142        let market_state = self.market_state.ok_or_else(|| eyre::eyre!("market_state not set"))?;
143
144        executor.spawn(async move {
145            if let Err(e) = required_pools_loader_worker(client, pool_loaders, pools, required_state, market, market_state).await {
146                error!("Required pools loader worker failed: {}", e);
147            }
148        });
149
150        Ok(())
151    }
152    fn name(&self) -> &'static str {
153        "RequiredPoolLoaderActor"
154    }
155}