kabu_core_topology/
topology.rs

1use std::collections::HashMap;
2use std::sync::Arc;
3
4use crate::topology_config::TransportType;
5use crate::topology_config::{BroadcasterConfig, ClientConfig, EncoderConfig, EstimatorConfig, SignersConfig, TopologyConfig};
6use alloy_primitives::Address;
7use alloy_provider::network::Ethereum;
8use alloy_provider::{Network, Provider, ProviderBuilder, RootProvider};
9use alloy_rpc_client::ClientBuilder;
10use alloy_transport_ipc::IpcConnect;
11use alloy_transport_ws::WsConnect;
12use eyre::{eyre, Result};
13use kabu_broadcast_accounts::{InitializeSignersOneShotBlockingActor, NonceAndBalanceMonitorActor, TxSignersActor};
14use kabu_broadcast_broadcaster::FlashbotsBroadcastActor;
15use kabu_broadcast_flashbots::Flashbots;
16use kabu_core_actors::{Accessor, Actor, Consumer, Producer, SharedState, WorkerResult};
17use kabu_core_block_history::BlockHistoryActor;
18use kabu_core_blockchain::{Blockchain, BlockchainState, Strategy};
19use kabu_core_mempool::MempoolActor;
20use kabu_defi_health_monitor::PoolHealthMonitorActor;
21use kabu_defi_market::{HistoryPoolLoaderOneShotActor, NewPoolLoaderActor, PoolLoaderActor, ProtocolPoolLoaderOneShotActor};
22use kabu_defi_pools::PoolLoadersBuilder;
23use kabu_defi_preloader::MarketStatePreloadedOneShotActor;
24use kabu_defi_price::PriceActor;
25use kabu_evm_db::{DatabaseKabuExt, KabuDBError};
26use kabu_execution_estimator::{EvmEstimatorActor, GethEstimatorActor};
27use kabu_execution_multicaller::MulticallerSwapEncoder;
28use kabu_node_actor_config::NodeBlockActorConfig;
29use kabu_node_json_rpc::{NodeBlockActor, NodeMempoolActor};
30use kabu_types_blockchain::{KabuDataTypes, KabuDataTypesEthereum};
31use kabu_types_entities::pool_config::PoolsLoadingConfig;
32use kabu_types_entities::{BlockHistoryState, MarketState, PoolLoaders, SwapEncoder, TxSigners};
33use revm::{Database, DatabaseCommit, DatabaseRef};
34use tokio::task::JoinHandle;
35use tracing::{error, info, warn};
36
37pub struct Topology<
38    DB: Clone + Send + Sync + 'static,
39    E: Send + Sync + Clone + 'static = MulticallerSwapEncoder,
40    P: Provider<N> + Send + Sync + Clone + 'static = RootProvider,
41    N: Network = Ethereum,
42    LDT: KabuDataTypes = KabuDataTypesEthereum,
43> {
44    config: TopologyConfig,
45    clients: HashMap<String, RootProvider<N>>,
46    blockchains: HashMap<String, Blockchain>,
47    blockchain_states: HashMap<String, BlockchainState<DB, LDT>>,
48    strategies: HashMap<String, Strategy<DB>>,
49    signers: HashMap<String, SharedState<TxSigners>>,
50    multicaller_encoders: HashMap<String, Address>,
51    default_blockchain_name: Option<String>,
52    default_multicaller_encoder_name: Option<String>,
53    default_signer_name: Option<String>,
54    swap_encoder: E,
55    pool_loaders: Arc<PoolLoaders<P, N, LDT>>,
56}
57
58impl<
59        DB: Database<Error = KabuDBError>
60            + DatabaseRef<Error = KabuDBError>
61            + DatabaseCommit
62            + DatabaseKabuExt
63            + BlockHistoryState<KabuDataTypesEthereum>
64            + Default
65            + Send
66            + Sync
67            + Clone
68            + 'static,
69        E: SwapEncoder + Send + Sync + Clone + 'static,
70        P: Provider<Ethereum> + Send + Sync + Clone + 'static,
71    > Topology<DB, E, P, Ethereum, KabuDataTypesEthereum>
72{
73    pub fn from_config(config: TopologyConfig) -> Topology<DB, MulticallerSwapEncoder> {
74        let encoder = MulticallerSwapEncoder::default();
75        let pool_loaders = Arc::new(PoolLoadersBuilder::<RootProvider>::new().build());
76
77        Topology::<DB, MulticallerSwapEncoder> {
78            config,
79            clients: HashMap::new(),
80            blockchains: HashMap::new(),
81            blockchain_states: HashMap::new(),
82            strategies: HashMap::new(),
83            signers: HashMap::new(),
84            multicaller_encoders: HashMap::new(),
85            default_blockchain_name: None,
86            default_multicaller_encoder_name: None,
87            default_signer_name: None,
88            swap_encoder: encoder,
89            pool_loaders,
90        }
91    }
92
93    pub fn with_swap_encoder<NE: SwapEncoder + Send + Sync + Clone + 'static>(
94        self,
95        swap_encoder: NE,
96    ) -> Topology<DB, NE, P, Ethereum, KabuDataTypesEthereum> {
97        //let swap_encoder = Arc::new(swap_encoder);
98        Topology {
99            config: self.config,
100            clients: self.clients,
101            blockchains: self.blockchains,
102            blockchain_states: self.blockchain_states,
103            strategies: self.strategies,
104            signers: self.signers,
105            multicaller_encoders: self.multicaller_encoders,
106            default_blockchain_name: self.default_blockchain_name,
107            default_multicaller_encoder_name: self.default_multicaller_encoder_name,
108            default_signer_name: self.default_signer_name,
109            pool_loaders: self.pool_loaders,
110            swap_encoder,
111        }
112    }
113
114    pub fn with_pool_loaders<NP: Provider + Send + Sync + Clone + 'static>(
115        self,
116        pool_loaders: PoolLoaders<NP, Ethereum, KabuDataTypesEthereum>,
117    ) -> Topology<DB, E, NP, Ethereum, KabuDataTypesEthereum> {
118        Topology {
119            config: self.config,
120            clients: self.clients,
121            blockchains: self.blockchains,
122            blockchain_states: self.blockchain_states,
123            strategies: self.strategies,
124            signers: self.signers,
125            multicaller_encoders: self.multicaller_encoders,
126            default_blockchain_name: self.default_blockchain_name,
127            default_multicaller_encoder_name: self.default_multicaller_encoder_name,
128            default_signer_name: self.default_signer_name,
129            swap_encoder: self.swap_encoder,
130            pool_loaders: Arc::new(pool_loaders),
131        }
132    }
133
134    pub async fn start_clients(self) -> Result<Self> {
135        let mut clients = HashMap::new();
136        for (name, v) in self.config.clients.iter() {
137            let config_params = v.clone();
138
139            info!("Connecting to {name} : {v:?}");
140
141            let client = match config_params.transport {
142                TransportType::Ipc => {
143                    info!("Starting IPC connection");
144
145                    let transport = IpcConnect::from(config_params.url);
146                    ClientBuilder::default().ipc(transport).await
147                }
148                _ => {
149                    info!("Starting WS connection");
150                    let transport = WsConnect::new(config_params.url);
151                    ClientBuilder::default().ws(transport).await
152                }
153            };
154
155            let client = match client {
156                Ok(client) => client,
157                Err(e) => {
158                    error!("Error connecting to {name} error : {}", e);
159                    continue;
160                }
161            };
162
163            let provider = ProviderBuilder::<_, _, Ethereum>::new().disable_recommended_fillers().connect_client(client);
164
165            clients.insert(name.clone(), provider);
166        }
167        Ok(Topology { clients, ..self })
168    }
169
170    pub fn build_blockchains(self) -> Self {
171        let mut multicaller_encoders = HashMap::new();
172        let mut strategies = HashMap::new();
173        let mut blockchains = HashMap::new();
174        let mut blockchain_states = HashMap::new();
175        let mut signers = HashMap::new();
176
177        let mut default_blockchain_name: Option<String> = None;
178        let mut default_multicaller_encoder_name: Option<String> = None;
179        let mut default_signer_name: Option<String> = None;
180
181        for (k, v) in self.config.encoders.iter() {
182            match v {
183                EncoderConfig::SwapStep(c) => {
184                    if let Ok(address) = c.address.parse() {
185                        multicaller_encoders.insert(k.clone(), address);
186                        default_multicaller_encoder_name = Some(k.clone());
187                    }
188                }
189            }
190        }
191
192        for (k, params) in self.config.blockchains.iter() {
193            let blockchain = Blockchain::new(params.chain_id.unwrap_or(1) as u64);
194            let market_state = MarketState::new(DB::default());
195            let blockchain_state = BlockchainState::<DB, KabuDataTypesEthereum>::new_with_market_state(market_state);
196            let strategy = Strategy::<DB>::new();
197
198            blockchains.insert(k.clone(), blockchain);
199
200            blockchain_states.insert(k.clone(), blockchain_state);
201            strategies.insert(k.clone(), strategy);
202
203            default_blockchain_name = Some(k.clone());
204        }
205
206        for (name, params) in self.config.signers.iter() {
207            match params {
208                SignersConfig::Env(_params) => {
209                    let signers_state = SharedState::new(TxSigners::new());
210                    signers.insert(name.clone(), signers_state);
211                    default_signer_name = Some(name.clone());
212                }
213            }
214        }
215
216        Self {
217            blockchains,
218            blockchain_states,
219            multicaller_encoders,
220            strategies,
221            signers,
222            default_multicaller_encoder_name,
223            default_blockchain_name,
224            default_signer_name,
225            ..self
226        }
227    }
228
229    pub async fn start_actors(&self) -> Result<Vec<JoinHandle<WorkerResult>>> {
230        let mut tasks: Vec<JoinHandle<WorkerResult>> = Vec::new();
231
232        if self.clients.is_empty() {
233            return Err(eyre!("NO_CLIENTS_CONNECTED"));
234        }
235
236        for (k, _params) in self.config.blockchains.iter() {
237            let blockchain = self.get_blockchain(Some(k))?;
238            let blockchain_state = self.get_blockchain_state(Some(k))?;
239            let client = self.get_client(None)?;
240
241            info!("Starting block history actor {k}");
242            let mut block_history_actor = BlockHistoryActor::new(client);
243            match block_history_actor
244                .access(blockchain.latest_block())
245                .access(blockchain_state.market_state())
246                .access(blockchain_state.block_history())
247                .consume(blockchain.new_block_headers_channel())
248                .consume(blockchain.new_block_with_tx_channel())
249                .consume(blockchain.new_block_logs_channel())
250                .consume(blockchain.new_block_state_update_channel())
251                .produce(blockchain.market_events_channel())
252                .start()
253            {
254                Ok(r) => {
255                    tasks.extend(r);
256                    info!("Block history actor started successfully")
257                }
258                Err(e) => {
259                    panic!("{}", e)
260                }
261            }
262
263            info!("Starting mempool actor {k}");
264            let mut mempool_actor = MempoolActor::new();
265            match mempool_actor
266                .access(blockchain.mempool())
267                .consume(blockchain.new_mempool_tx_channel())
268                .consume(blockchain.new_block_headers_channel())
269                .consume(blockchain.new_block_with_tx_channel())
270                .produce(blockchain.mempool_events_channel())
271                .produce(blockchain.influxdb_write_channel())
272                .start()
273            {
274                Ok(r) => {
275                    tasks.extend(r);
276                    info!("Mempool actor started successfully")
277                }
278                Err(e) => {
279                    panic!("{}", e)
280                }
281            }
282
283            info!("Starting pool monitor monitor actor {k}");
284            let mut new_pool_health_monior_actor = PoolHealthMonitorActor::new();
285            match new_pool_health_monior_actor
286                .access(blockchain.market())
287                .consume(blockchain.health_monitor_channel())
288                .produce(blockchain.influxdb_write_channel())
289                .start()
290            {
291                Ok(r) => {
292                    tasks.extend(r);
293                    info!("Pool monitor monitor actor started")
294                }
295                Err(e) => {
296                    panic!("PoolHealthMonitorActor error {e}")
297                }
298            }
299        }
300
301        for (name, params) in self.config.signers.iter() {
302            let signers = self.get_signers(Some(name))?;
303            match params {
304                SignersConfig::Env(params) => {
305                    info!("Starting initialize env signers actor {name}");
306                    let blockchain = self.get_blockchain(params.blockchain.as_ref())?;
307
308                    let mut initialize_signers_actor = InitializeSignersOneShotBlockingActor::new_from_encrypted_env();
309                    match initialize_signers_actor.access(signers.clone()).access(blockchain.nonce_and_balance()).start_and_wait() {
310                        Ok(_) => {
311                            info!("Signers have been initialized")
312                        }
313                        Err(e) => {
314                            panic!("Cannot initialize signers {e}");
315                        }
316                    }
317
318                    let mut signers_actor = TxSignersActor::new();
319                    match signers_actor.consume(blockchain.tx_compose_channel()).produce(blockchain.tx_compose_channel()).start() {
320                        Ok(r) => {
321                            tasks.extend(r);
322                            info!("Signers actor has been started")
323                        }
324                        Err(e) => {
325                            panic!("Cannot start signers actor {e}")
326                        }
327                    }
328                }
329            }
330        }
331
332        if let Some(preloader_actors) = &self.config.preloaders {
333            for (name, params) in preloader_actors {
334                info!("Starting market state preload actor {name}");
335
336                let blockchain_state = self.get_blockchain_state(params.blockchain.as_ref())?;
337                let client = self.get_client(params.client.as_ref())?;
338                let signers = self.get_signers(params.signers.as_ref())?;
339
340                let mut market_state_preload_actor = MarketStatePreloadedOneShotActor::new(client)
341                    .with_signers(signers.clone())
342                    .with_copied_account(self.get_multicaller_address(None)?);
343                match market_state_preload_actor.access(blockchain_state.market_state()).start_and_wait() {
344                    Ok(_) => {
345                        info!("Market state preload actor executed successfully")
346                    }
347                    Err(e) => {
348                        panic!("MarketStatePreloadedOneShotActor : {e}")
349                    }
350                }
351            }
352        } else {
353            warn!("No preloader in config")
354        }
355
356        if let Some(node_block_actors) = &self.config.actors.node {
357            for (name, params) in node_block_actors {
358                let client = self.get_client(params.client.as_ref())?;
359                let blockchain = self.get_blockchain(params.blockchain.as_ref())?;
360                let client_config = self.get_client_config(params.client.as_ref())?;
361
362                info!("Starting node actor {name}");
363
364                if client_config.db_path.is_none() {
365                    let mut node_block_actor = NodeBlockActor::new(client, NodeBlockActorConfig::all_enabled());
366                    match node_block_actor
367                        .produce(blockchain.new_block_headers_channel())
368                        .produce(blockchain.new_block_with_tx_channel())
369                        .produce(blockchain.new_block_logs_channel())
370                        .produce(blockchain.new_block_state_update_channel())
371                        .start()
372                    {
373                        Ok(r) => {
374                            tasks.extend(r);
375                            info!("Node actor started successfully for : {} @ {}", name, blockchain.chain_id())
376                        }
377                        Err(e) => {
378                            panic!("{}", e)
379                        }
380                    }
381                }
382            }
383        }
384
385        if let Some(node_mempool_actors) = &self.config.actors.mempool {
386            for (name, params) in node_mempool_actors {
387                let blockchain = self.get_blockchain(params.blockchain.as_ref())?;
388                match self.get_client(params.client.as_ref()) {
389                    Ok(client) => {
390                        println!("Starting node mempool actor {name}");
391                        let mut node_mempool_actor = NodeMempoolActor::new(client).with_name(name.clone());
392                        match node_mempool_actor.produce(blockchain.new_mempool_tx_channel()).start() {
393                            Ok(r) => {
394                                tasks.extend(r);
395                                info!("Node mempool actor started successfully {name}")
396                            }
397                            Err(e) => {
398                                panic!("{}", e)
399                            }
400                        }
401                    }
402                    Err(e) => {
403                        error!("Skipping mempool actor for {} @ {} : {}", name, blockchain.chain_id(), e)
404                    }
405                }
406            }
407        }
408
409        if let Some(price_actors) = &self.config.actors.price {
410            for (name, c) in price_actors {
411                let client = self.get_client(c.client.as_ref())?;
412                let blockchain = self.get_blockchain(c.blockchain.as_ref())?;
413                info!("Starting price actor");
414                let mut price_actor = PriceActor::new(client);
415                match price_actor.access(blockchain.market()).start() {
416                    Ok(r) => {
417                        tasks.extend(r);
418                        info!("Price actor has been initialized : {}", name)
419                    }
420                    Err(e) => {
421                        panic!("Cannot initialize price actor {name} : {e}");
422                    }
423                }
424            }
425        } else {
426            warn!("No price actor in config")
427        }
428
429        if let Some(node_balance_actors) = &self.config.actors.noncebalance {
430            for (name, c) in node_balance_actors {
431                let client = self.get_client(c.client.as_ref())?;
432                let blockchain = self.get_blockchain(c.blockchain.as_ref())?;
433
434                info!("Starting nonce and balance monitor actor {name}");
435                let mut nonce_and_balance_monitor = NonceAndBalanceMonitorActor::new(client);
436                match nonce_and_balance_monitor
437                    .access(blockchain.nonce_and_balance())
438                    .access(blockchain.latest_block())
439                    .consume(blockchain.market_events_channel())
440                    .start()
441                {
442                    Ok(r) => {
443                        tasks.extend(r);
444                        info!("Nonce monitor has been initialized {name} for {}", blockchain.chain_id())
445                    }
446                    Err(e) => {
447                        panic!("Cannot initialize nonce and balance monitor {name} : {e}");
448                    }
449                }
450            }
451        } else {
452            warn!("No nonce and balance actors in config");
453        }
454
455        if let Some(broadcaster_actors) = &self.config.actors.broadcaster {
456            for (name, params) in broadcaster_actors {
457                match params {
458                    BroadcasterConfig::Flashbots(params) => {
459                        let client = self.get_client(params.client.as_ref())?;
460                        let blockchain = self.get_blockchain(params.blockchain.as_ref())?;
461
462                        let flashbots_client = Flashbots::new(client, "https://relay.flashbots.net", None).with_default_relays();
463                        let mut flashbots_actor = FlashbotsBroadcastActor::new(flashbots_client, true);
464                        match flashbots_actor.consume(blockchain.tx_compose_channel()).start() {
465                            Ok(r) => {
466                                tasks.extend(r);
467                                info!("Flashbots broadcaster actor {name} started successfully for {}", blockchain.chain_id())
468                            }
469                            Err(e) => {
470                                panic!("Error starting flashbots broadcaster actor {name} for {} : {}", blockchain.chain_id(), e)
471                            }
472                        }
473                    }
474                }
475            }
476        } else {
477            warn!("No broadcaster actors in config")
478        }
479
480        if let Some(pool_actors) = &self.config.actors.pools {
481            let mut blockchains = HashMap::new();
482
483            for (name, params) in pool_actors {
484                let client = self.get_client(params.client.as_ref())?;
485                let blockchain = self.get_blockchain(params.blockchain.as_ref())?;
486                let blockchain_state = self.get_blockchain_state(params.blockchain.as_ref())?;
487
488                let pool_loaders = self.pool_loaders.clone();
489
490                blockchains.insert(blockchain.chain_id(), blockchain);
491                if params.history {
492                    info!("Starting history pools loader {name}");
493
494                    let mut history_pools_loader_actor = HistoryPoolLoaderOneShotActor::new(client.clone(), pool_loaders.clone());
495                    match history_pools_loader_actor.produce(blockchain.tasks_channel()).start() {
496                        Ok(r) => {
497                            tasks.extend(r);
498                            info!("History pool loader actor started successfully {name}")
499                        }
500                        Err(e) => {
501                            panic!("HistoryPoolLoaderOneShotActor : {e}")
502                        }
503                    }
504                }
505                if params.protocol {
506                    info!("Starting curve pools loader {name}");
507
508                    let mut curve_pools_loader_actor = ProtocolPoolLoaderOneShotActor::new(client.clone(), pool_loaders.clone());
509                    match curve_pools_loader_actor.produce(blockchain.tasks_channel()).start() {
510                        Err(e) => {
511                            panic!("CurvePoolLoaderOneShotActor : {e}")
512                        }
513                        Ok(r) => {
514                            tasks.extend(r);
515                            info!("Curve pool loader actor started successfully")
516                        }
517                    }
518                }
519
520                if params.new {
521                    info!("Starting new pool loader actor {name}");
522                    let mut new_pool_actor = NewPoolLoaderActor::new(pool_loaders.clone());
523                    match new_pool_actor.consume(blockchain.new_block_logs_channel()).produce(blockchain.tasks_channel()).start() {
524                        Ok(r) => {
525                            tasks.extend(r);
526                            info!("New pool actor started")
527                        }
528                        Err(e) => {
529                            panic!("NewPoolLoaderActor : {e}")
530                        }
531                    }
532                }
533
534                info!("Starting pool loader actor {name}");
535                let mut pool_loader_actor = PoolLoaderActor::new(client.clone(), pool_loaders.clone(), PoolsLoadingConfig::new());
536                match pool_loader_actor
537                    .access(blockchain.market())
538                    .access(blockchain_state.market_state())
539                    .consume(blockchain.tasks_channel())
540                    .produce(blockchain.market_events_channel())
541                    .start()
542                {
543                    Ok(r) => {
544                        tasks.extend(r);
545                        info!("Pool loader actor started successfully")
546                    }
547                    Err(e) => {
548                        panic!("PoolLoaderActor : {e}")
549                    }
550                }
551            }
552        } else {
553            warn!("No pool loader actors in config")
554        }
555
556        if let Some(estimator_actors) = &self.config.actors.estimator {
557            for (name, params) in estimator_actors {
558                match params {
559                    EstimatorConfig::Evm(params) => {
560                        let client = params.client.as_ref().map(|x| self.get_client(Some(x))).transpose()?; //   topology.get_client(params.client.as_ref())?;
561
562                        let blockchain = self.get_blockchain(params.blockchain.as_ref())?;
563                        let strategy = self.get_strategy(params.blockchain.as_ref())?;
564                        let multicaller_address = self.get_multicaller_address(params.encoder.as_ref())?;
565
566                        let mut encoder = self.swap_encoder.clone();
567                        encoder.set_address(multicaller_address);
568
569                        let mut evm_estimator_actor = EvmEstimatorActor::new_with_provider(encoder, client);
570                        match evm_estimator_actor
571                            .consume(strategy.swap_compose_channel())
572                            .produce(strategy.swap_compose_channel())
573                            .produce(blockchain.health_monitor_channel())
574                            .produce(blockchain.influxdb_write_channel())
575                            .start()
576                        {
577                            Ok(r) => {
578                                tasks.extend(r);
579                                info!("EVM estimator actor started successfully {name} @ {}", blockchain.chain_id())
580                            }
581                            Err(e) => {
582                                panic!("Error starting EVM estimator actor {name} @ {} : {}", blockchain.chain_id(), e)
583                            }
584                        }
585                    }
586                    EstimatorConfig::Geth(params) => {
587                        let client = self.get_client(params.client.as_ref())?;
588                        let blockchain = self.get_blockchain(params.blockchain.as_ref())?;
589                        let strategy = self.get_strategy(params.blockchain.as_ref())?;
590                        let multicaller_address = self.get_multicaller_address(params.encoder.as_ref())?;
591
592                        let mut encoder = self.swap_encoder.clone();
593                        encoder.set_address(multicaller_address);
594
595                        let flashbots_client = Arc::new(Flashbots::new(client, "https://relay.flashbots.net", None).with_default_relays());
596
597                        let mut geth_estimator_actor = GethEstimatorActor::new(flashbots_client, encoder);
598                        match geth_estimator_actor.consume(strategy.swap_compose_channel()).produce(strategy.swap_compose_channel()).start()
599                        {
600                            Ok(r) => {
601                                tasks.extend(r);
602                                info!("Geth estimator actor started successfully {name} @ {}", blockchain.chain_id())
603                            }
604                            Err(e) => {
605                                panic!("Error starting Geth estimator actor for {name} @ {} : {}", blockchain.chain_id(), e)
606                            }
607                        }
608                    }
609                }
610            }
611        } else {
612            warn!("No estimator actors in config")
613        }
614
615        Ok(tasks)
616    }
617
618    pub fn get_client(&self, name: Option<&String>) -> Result<RootProvider> {
619        match self.clients.get(name.unwrap_or(&"local".to_string())) {
620            Some(a) => Ok(a.clone()),
621            None => Err(eyre!("CLIENT_NOT_FOUND")),
622        }
623    }
624
625    pub fn get_client_config(&self, name: Option<&String>) -> Result<ClientConfig> {
626        match self.config.clients.get(name.unwrap_or(&"local".to_string())) {
627            Some(a) => Ok(a.clone()),
628            None => Err(eyre!("CLIENT_NOT_FOUND")),
629        }
630    }
631
632    pub fn get_blockchain(&self, name: Option<&String>) -> Result<&Blockchain> {
633        match self.blockchains.get(name.unwrap_or(&self.default_blockchain_name.clone().unwrap())) {
634            Some(a) => Ok(a),
635            None => Err(eyre!("BLOCKCHAIN_NOT_FOUND")),
636        }
637    }
638
639    pub fn get_blockchain_state(&self, name: Option<&String>) -> Result<&BlockchainState<DB, KabuDataTypesEthereum>> {
640        match self.blockchain_states.get(name.unwrap_or(&self.default_blockchain_name.clone().unwrap())) {
641            Some(a) => Ok(a),
642            None => Err(eyre!("BLOCKCHAIN_NOT_FOUND")),
643        }
644    }
645
646    pub fn get_strategy(&self, name: Option<&String>) -> Result<&Strategy<DB>> {
647        match self.strategies.get(name.unwrap_or(&self.default_blockchain_name.clone().unwrap())) {
648            Some(a) => Ok(a),
649            None => Err(eyre!("BLOCKCHAIN_NOT_FOUND")),
650        }
651    }
652
653    pub fn get_multicaller_address(&self, name: Option<&String>) -> Result<Address> {
654        match self.multicaller_encoders.get(name.unwrap_or(&self.default_multicaller_encoder_name.clone().unwrap())) {
655            Some(multicaller_address) => Ok(*multicaller_address),
656            None => Err(eyre!("ENCODER_NOT_FOUND")),
657        }
658    }
659
660    pub fn get_signers(&self, name: Option<&String>) -> Result<SharedState<TxSigners>> {
661        match self.signers.get(name.unwrap_or(&self.default_multicaller_encoder_name.clone().unwrap())) {
662            Some(a) => Ok(a.clone()),
663            None => Err(eyre!("SIGNERS_NOT_FOUND")),
664        }
665    }
666    pub fn get_blockchain_mut(&mut self, name: Option<&String>) -> Result<&mut Blockchain> {
667        match self.blockchains.get_mut(name.unwrap_or(&self.default_blockchain_name.clone().unwrap())) {
668            Some(a) => Ok(a),
669            None => Err(eyre!("CLIENT_NOT_FOUND")),
670        }
671    }
672}