1use crate::context::KabuContext;
4use crate::traits::{ComponentBuilder, DisabledComponent};
5use alloy_network::Ethereum;
6use alloy_provider::Provider;
7use eyre::Result;
8use std::sync::Arc;
9
10use kabu_broadcast_broadcaster::FlashbotsBroadcastComponent;
11use kabu_core_block_history::BlockHistoryComponent;
12use kabu_core_components::Component;
13use kabu_core_router::SwapRouterComponent;
14use kabu_defi_market::{HistoryPoolLoaderComponent, ProtocolPoolLoaderComponent};
15use kabu_defi_pools::PoolLoadersBuilder;
16use kabu_defi_preloader::MarketStatePreloadedOneShotComponent;
17use kabu_defi_price::PriceComponent;
18use kabu_evm_db::{DatabaseKabuExt, KabuDBError};
19use kabu_execution_estimator::EvmEstimatorComponent;
20use kabu_node_debug_provider::DebugProviderExt;
21use kabu_strategy_backrun::StateChangeArbComponent;
22use kabu_strategy_merger::DiffPathMergerComponent;
23use kabu_types_entities::BlockHistoryState;
24use reth::revm::{Database, DatabaseCommit, DatabaseRef};
25use reth_chain_state::CanonStateSubscriptions;
26use reth_ethereum_primitives::EthPrimitives;
27
28#[cfg(feature = "defi-health-monitor")]
29use kabu_defi_health_monitor::PoolHealthMonitorComponent;
30
31pub struct DefaultNetwork;
37
38impl<R, P, DB, Evm> ComponentBuilder<KabuContext<R, P, DB, Evm>> for DefaultNetwork
39where
40 R: CanonStateSubscriptions<Primitives = EthPrimitives> + Send + Sync + Clone + 'static,
41 P: Provider<Ethereum> + DebugProviderExt<Ethereum> + Send + Sync + Clone + 'static,
42 DB: DatabaseRef<Error = KabuDBError>
43 + Database<Error = KabuDBError>
44 + DatabaseCommit
45 + DatabaseKabuExt
46 + BlockHistoryState<EthPrimitives>
47 + Send
48 + Sync
49 + Clone
50 + Default
51 + 'static,
52 Evm: Clone + Send + Sync + 'static,
53{
54 type Component = BlockHistoryComponent<R, P, DB>;
55
56 fn build(self, ctx: &KabuContext<R, P, DB, Evm>) -> Result<Self::Component> {
57 Ok(BlockHistoryComponent::new(ctx.reth_provider.clone(), ctx.provider.clone()).with_config(
58 ctx.config.chain_params.clone(),
59 ctx.market_state.clone(),
60 ctx.block_history.clone(),
61 ctx.channels.market_events.clone(),
62 ))
63 }
64}
65
66pub struct DefaultExecutor;
72
73impl<R, P, DB, Evm> ComponentBuilder<KabuContext<R, P, DB, Evm>> for DefaultExecutor
74where
75 R: Send + Sync + Clone + 'static,
76 P: Provider<Ethereum> + Send + Sync + Clone + 'static,
77 DB: DatabaseRef<Error = KabuDBError>
78 + Database<Error = KabuDBError>
79 + DatabaseCommit
80 + DatabaseKabuExt
81 + BlockHistoryState<EthPrimitives>
82 + Send
83 + Sync
84 + Clone
85 + Default
86 + 'static,
87 Evm: Clone + Send + Sync + 'static,
88{
89 type Component = SwapRouterComponent<DB, EthPrimitives>;
90
91 fn build(self, ctx: &KabuContext<R, P, DB, Evm>) -> Result<Self::Component> {
92 Ok(SwapRouterComponent::new(ctx.channels.signers.clone(), ctx.channels.account_state.clone(), ctx.channels.swap_compose.clone()))
93 }
94}
95
96pub struct DefaultStrategy;
102
103impl<R, P, DB, Evm> ComponentBuilder<KabuContext<R, P, DB, Evm>> for DefaultStrategy
104where
105 R: Send + Sync + Clone + 'static,
106 P: Provider<Ethereum> + DebugProviderExt<Ethereum> + Send + Sync + Clone + 'static,
107 DB: DatabaseRef<Error = KabuDBError>
108 + Database<Error = KabuDBError>
109 + DatabaseCommit
110 + DatabaseKabuExt
111 + BlockHistoryState<EthPrimitives>
112 + Send
113 + Sync
114 + Clone
115 + Default
116 + 'static,
117 Evm: Clone + Send + Sync + 'static,
118{
119 type Component = StateChangeArbComponent<P, Ethereum, DB, EthPrimitives>;
120
121 fn build(self, ctx: &KabuContext<R, P, DB, Evm>) -> Result<Self::Component> {
122 let mut component = StateChangeArbComponent::new(ctx.provider.clone(), ctx.config.backrun_config.clone())
123 .with_market(ctx.market.clone())
124 .with_mempool(ctx.mempool.clone())
125 .with_market_state(ctx.market_state.clone())
126 .with_block_history(ctx.block_history.clone())
127 .with_mempool_events_channel(ctx.channels.mempool_events.clone())
128 .with_market_events_channel(ctx.channels.market_events.clone())
129 .with_swap_compose_channel(ctx.channels.swap_compose.clone())
130 .with_pool_health_monitor_channel(ctx.channels.health_events.clone());
131
132 if let Some(channel) = ctx.blockchain.influxdb_write_channel() {
133 component = component.with_influxdb_channel(channel);
134 }
135
136 Ok(component)
137 }
138}
139
140pub struct DefaultSigner;
146
147impl<R, P, DB, Evm> ComponentBuilder<KabuContext<R, P, DB, Evm>> for DefaultSigner
148where
149 R: Send + Sync + Clone + 'static,
150 P: Provider<Ethereum> + Send + Sync + Clone + 'static,
151 DB: DatabaseRef<Error = KabuDBError>
152 + Database<Error = KabuDBError>
153 + DatabaseCommit
154 + DatabaseKabuExt
155 + BlockHistoryState<EthPrimitives>
156 + Send
157 + Sync
158 + Clone
159 + Default
160 + 'static,
161 Evm: Clone + Send + Sync + 'static,
162{
163 type Component = crate::signer::SignerBridgeComponent<DB>;
164
165 fn build(self, ctx: &KabuContext<R, P, DB, Evm>) -> Result<Self::Component> {
166 Ok(crate::signer::SignerBridgeComponent::new().with_channels(ctx.channels.swap_compose.clone(), ctx.channels.tx_compose.clone()))
167 }
168}
169
170#[derive(Clone)]
176pub struct MarketComponents<P, DB>
177where
178 P: Provider<Ethereum> + Send + Sync + Clone + 'static,
179 DB: Send + Sync + Clone + 'static,
180{
181 preloader: MarketStatePreloadedOneShotComponent<P, Ethereum, DB>,
182 price: PriceComponent<P, Ethereum>,
183 protocol_loader: ProtocolPoolLoaderComponent<P, P, Ethereum>,
184 history_loader: HistoryPoolLoaderComponent<P, P, Ethereum>,
185}
186
187impl<P, DB> Component for MarketComponents<P, DB>
188where
189 P: Provider<Ethereum> + DebugProviderExt<Ethereum> + Send + Sync + Clone + 'static,
190 DB: DatabaseRef<Error = KabuDBError>
191 + Database<Error = KabuDBError>
192 + DatabaseCommit
193 + DatabaseKabuExt
194 + BlockHistoryState<EthPrimitives>
195 + Send
196 + Sync
197 + Clone
198 + Default
199 + 'static,
200{
201 fn spawn(self, executor: reth_tasks::TaskExecutor) -> Result<()> {
202 self.preloader.spawn(executor.clone())?;
203 self.price.spawn(executor.clone())?;
204 self.protocol_loader.spawn(executor.clone())?;
205 self.history_loader.spawn(executor)?;
206 Ok(())
207 }
208
209 fn name(&self) -> &'static str {
210 "MarketComponents"
211 }
212}
213
214pub struct DefaultMarket;
216
217impl<R, P, DB, Evm> ComponentBuilder<KabuContext<R, P, DB, Evm>> for DefaultMarket
218where
219 R: Send + Sync + Clone + 'static,
220 P: Provider<Ethereum> + DebugProviderExt<Ethereum> + Send + Sync + Clone + 'static,
221 DB: DatabaseRef<Error = KabuDBError>
222 + Database<Error = KabuDBError>
223 + DatabaseCommit
224 + DatabaseKabuExt
225 + BlockHistoryState<EthPrimitives>
226 + Send
227 + Sync
228 + Clone
229 + Default
230 + 'static,
231 Evm: Clone + Send + Sync + 'static,
232{
233 type Component = MarketComponents<P, DB>;
234
235 fn build(self, ctx: &KabuContext<R, P, DB, Evm>) -> Result<Self::Component> {
236 let pool_loaders = Arc::new(PoolLoadersBuilder::<_, _, EthPrimitives>::default_pool_loaders(
237 ctx.provider.clone(),
238 ctx.config.pools_config.clone(),
239 ));
240
241 let preloader = MarketStatePreloadedOneShotComponent::new(ctx.provider.clone())
242 .with_copied_account(ctx.config.swap_encoder.get_contract_address())
243 .with_signers(ctx.channels.signers.clone())
244 .with_market_state(ctx.market_state.clone());
245
246 let price = PriceComponent::new(ctx.provider.clone()).only_once().with_market(ctx.market.clone());
247
248 let protocol_loader = ProtocolPoolLoaderComponent::new(ctx.provider.clone(), pool_loaders.clone());
249
250 let history_loader = HistoryPoolLoaderComponent::new(
251 ctx.provider.clone(),
252 pool_loaders,
253 0, 1000, 10, );
257
258 Ok(MarketComponents { preloader, price, protocol_loader, history_loader })
259 }
260}
261
262pub struct DefaultBroadcaster;
268
269impl<R, P, DB, Evm> ComponentBuilder<KabuContext<R, P, DB, Evm>> for DefaultBroadcaster
270where
271 R: Send + Sync + Clone + 'static,
272 P: Provider<Ethereum> + Send + Sync + Clone + 'static,
273 DB: DatabaseRef<Error = KabuDBError>
274 + Database<Error = KabuDBError>
275 + DatabaseCommit
276 + DatabaseKabuExt
277 + BlockHistoryState<EthPrimitives>
278 + Send
279 + Sync
280 + Clone
281 + Default
282 + 'static,
283 Evm: Clone + Send + Sync + 'static,
284{
285 type Component = FlashbotsBroadcastComponent;
286
287 fn build(self, ctx: &KabuContext<R, P, DB, Evm>) -> Result<Self::Component> {
288 let relays = ctx
290 .config
291 .config
292 .builders
293 .iter()
294 .map(|b| kabu_broadcast_broadcaster::RelayConfig {
295 id: b.id as u64,
296 name: b.name.clone(),
297 url: b.url.clone(),
298 no_sign: Some(b.no_sign),
299 })
300 .collect::<Vec<_>>();
301
302 let mut component = FlashbotsBroadcastComponent::new(None, !relays.is_empty())?;
303 component = component.with_relays(relays)?;
304 component = component.with_channel(ctx.channels.tx_compose.clone());
305 Ok(component)
306 }
307}
308
309pub struct DefaultEstimator;
315
316impl<R, P, DB, Evm> ComponentBuilder<KabuContext<R, P, DB, Evm>> for DefaultEstimator
317where
318 R: Send + Sync + Clone + 'static,
319 P: Provider<Ethereum> + DebugProviderExt<Ethereum> + Send + Sync + Clone + 'static,
320 DB: DatabaseRef<Error = KabuDBError>
321 + Database<Error = KabuDBError>
322 + DatabaseCommit
323 + DatabaseKabuExt
324 + BlockHistoryState<EthPrimitives>
325 + Send
326 + Sync
327 + Clone
328 + Default
329 + 'static,
330 Evm: Clone + Send + Sync + 'static,
331{
332 type Component = EvmEstimatorComponent<P, Ethereum, kabu_execution_multicaller::MulticallerSwapEncoder, DB>;
333
334 fn build(self, ctx: &KabuContext<R, P, DB, Evm>) -> Result<Self::Component> {
335 Ok(EvmEstimatorComponent::new_with_provider(ctx.config.swap_encoder.clone(), Some(ctx.provider.clone()))
336 .with_swap_compose_channel(ctx.channels.swap_compose.clone()))
337 }
338}
339
340pub struct DefaultHealthMonitor;
346
347impl<R, P, DB, Evm> ComponentBuilder<KabuContext<R, P, DB, Evm>> for DefaultHealthMonitor
348where
349 R: Send + Sync + Clone + 'static,
350 P: Provider<Ethereum> + Send + Sync + Clone + 'static,
351 DB: DatabaseRef<Error = KabuDBError>
352 + Database<Error = KabuDBError>
353 + DatabaseCommit
354 + DatabaseKabuExt
355 + BlockHistoryState<EthPrimitives>
356 + Send
357 + Sync
358 + Clone
359 + Default
360 + 'static,
361 Evm: Clone + Send + Sync + 'static,
362{
363 #[cfg(feature = "defi-health-monitor")]
364 type Component = PoolHealthMonitorComponent;
365
366 #[cfg(not(feature = "defi-health-monitor"))]
367 type Component = DisabledComponent;
368
369 fn build(self, ctx: &KabuContext<R, P, DB, Evm>) -> Result<Self::Component> {
370 #[cfg(feature = "defi-health-monitor")]
371 {
372 Ok(PoolHealthMonitorComponent::new().with_channels(
373 ctx.market.clone(),
374 ctx.channels.health_events.clone(),
375 ctx.blockchain.influxdb_write_channel(),
376 ))
377 }
378
379 #[cfg(not(feature = "defi-health-monitor"))]
380 {
381 let _ = ctx;
382 Ok(DisabledComponent)
383 }
384 }
385}
386
387#[derive(Clone)]
393pub struct MergerComponents<DB>
394where
395 DB: DatabaseRef<Error = KabuDBError> + Database<Error = KabuDBError> + DatabaseCommit + Send + Sync + Clone + Default + 'static,
396{
397 diff_path: DiffPathMergerComponent<DB>,
398}
399
400impl<DB> Component for MergerComponents<DB>
401where
402 DB: DatabaseRef<Error = KabuDBError> + Database<Error = KabuDBError> + DatabaseCommit + Send + Sync + Clone + Default + 'static,
403{
404 fn spawn(self, executor: reth_tasks::TaskExecutor) -> Result<()> {
405 self.diff_path.spawn(executor)?;
406 Ok(())
407 }
408
409 fn name(&self) -> &'static str {
410 "MergerComponents"
411 }
412}
413
414pub struct DefaultMerger;
416
417impl<R, P, DB, Evm> ComponentBuilder<KabuContext<R, P, DB, Evm>> for DefaultMerger
418where
419 R: Send + Sync + Clone + 'static,
420 P: Provider<Ethereum> + Send + Sync + Clone + 'static,
421 DB: DatabaseRef<Error = KabuDBError>
422 + Database<Error = KabuDBError>
423 + DatabaseCommit
424 + DatabaseKabuExt
425 + BlockHistoryState<EthPrimitives>
426 + Send
427 + Sync
428 + Clone
429 + Default
430 + 'static,
431 Evm: Clone + Send + Sync + 'static,
432{
433 type Component = MergerComponents<DB>;
434
435 fn build(self, ctx: &KabuContext<R, P, DB, Evm>) -> Result<Self::Component> {
436 let diff_path = DiffPathMergerComponent::<DB>::new()
437 .with_market_events_channel(ctx.channels.market_events.clone())
438 .with_compose_channel(ctx.channels.swap_compose.clone());
439
440 Ok(MergerComponents { diff_path })
441 }
442}
443
444pub struct DefaultMonitoring;
450
451impl<R, P, DB, Evm> ComponentBuilder<KabuContext<R, P, DB, Evm>> for DefaultMonitoring
452where
453 R: Send + Sync + Clone + 'static,
454 P: Provider<Ethereum> + Send + Sync + Clone + 'static,
455 DB: DatabaseRef<Error = KabuDBError>
456 + Database<Error = KabuDBError>
457 + DatabaseCommit
458 + DatabaseKabuExt
459 + BlockHistoryState<EthPrimitives>
460 + Send
461 + Sync
462 + Clone
463 + Default
464 + 'static,
465 Evm: Clone + Send + Sync + 'static,
466{
467 type Component = DisabledComponent; fn build(self, ctx: &KabuContext<R, P, DB, Evm>) -> Result<Self::Component> {
470 let _ = ctx;
472 Ok(DisabledComponent)
473 }
474}