1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
//! The `brontes_inspect` crate is designed to efficiently detect and analyze
//! a block. Emphasizing modularity and ease of use, this crate provides a
//! robust foundation for developing custom inspectors, streamlining the process
//! of complex transaction & block analysis.
//!
//! ## Inspector
//!
//! `Inspector` is a trait defining a method `inspect_block`. This method takes
//! a `BlockTree` and `Metadata` as input and returns a vector of tuples, each
//! containing a `BundleHeader` and a `BundleData`.
//!
//! ```ignore
//! #[async_trait::async_trait]
//! pub trait Inspector: Send + Sync {
//!     type Result: Send + Sync;
//!
//!     async fn inspect_block(
//!         &self,
//!         tree: Arc<BlockTree<Action>>,
//!         metadata: Arc<Metadata>,
//!     ) -> Self::Result;
//! }
//! ```
//!
//! ## Individual Inspectors
//!
//! The `brontes_inspect` crate provides several individual inspectors, each
//! designed to detect a specific type of MEV strategy. These inspectors are
//! defined in their respective modules:
//!
//! - [`atomic_backrun`](atomic_backrun/index.html)
//! - [`cex_dex`](cex_dex/index.html)
//! - [`jit`](jit/index.html)
//! - [`sandwich`](sandwich/index.html)
//! - [`liquidations`](liquidations/index.html)
//! - [`long_tail`](long_tail/index.html)
//!
//! Each inspector implements the `Inspector` trait and provides its own
//! implementation of the `inspect_block` method.
//!
//! ## Composer
//!
//! The `Composer` is a special type of inspector that combines the results of
//! individual inspectors to identify more complex MEV strategies. It takes an
//! array of individual inspectors and a `BlockTree` and `Metadata` as input,
//! running each inspector on the block and collecting their results.
//!
//! ```ignore
//! pub struct Composer<'a, const N: usize> {
//!     inspectors_execution: InspectorFut<'a>,
//!     pre_processing:       BlockPreprocessing,
//! }
//! ```
//!
//! The `Composer` uses  to define a filter that
//! orders results from individual inspectors. This ensures that lower-level
//! actions are composed before higher-level actions, which could affect the
//! composition.

pub mod composer;
pub mod discovery;
pub mod mev_inspectors;
use brontes_metrics::inspectors::OutlierMetrics;
use mev_inspectors::searcher_activity::SearcherActivity;
pub use mev_inspectors::*;

#[cfg(feature = "tests")]
pub mod test_utils;

use alloy_primitives::Address;
use atomic_arb::AtomicArbInspector;
use brontes_types::{
    db::{
        cex::{trades::CexDexTradeConfig, CexExchange},
        metadata::Metadata,
        traits::LibmdbxReader,
    },
    mev::{Bundle, BundleData},
    normalized_actions::Action,
    tree::BlockTree,
    MultiBlockData,
};
use cex_dex::{markout::CexDexMarkoutInspector, quotes::CexDexQuotesInspector};
use jit::JitCexDex;
use liquidations::LiquidationInspector;
use sandwich::SandwichInspector;

use crate::jit::jit_liquidity::JitInspector;

pub trait Inspector: Send + Sync {
    type Result: Send + Sync;

    /// default is 1
    fn block_window(&self) -> usize {
        1
    }
    /// Used for log span so we know which errors come from which inspector
    fn get_id(&self) -> &str;
    fn inspect_block(&self, data: MultiBlockData) -> Self::Result;
    fn get_quote_token(&self) -> Address;
}

#[derive(
    Debug, PartialEq, Clone, Copy, Eq, Hash, strum::Display, strum::EnumString, strum::EnumIter,
)]
pub enum Inspectors {
    AtomicArb,
    CexDex,
    Jit,
    Liquidations,
    Sandwich,
    SearcherActivity,
    CexDexMarkout,
    JitCexDex,
}

type DynMevInspector = &'static (dyn Inspector<Result = Vec<Bundle>> + 'static);

impl Inspectors {
    pub fn init_mev_inspector<DB: LibmdbxReader>(
        &self,
        quote_token: Address,
        db: &'static DB,
        cex_exchanges: &[CexExchange],
        trade_config: CexDexTradeConfig,
        metrics: Option<OutlierMetrics>,
    ) -> DynMevInspector {
        match &self {
            Self::AtomicArb => {
                static_object(AtomicArbInspector::new(quote_token, db, metrics)) as DynMevInspector
            }
            Self::Jit => {
                static_object(JitInspector::new(quote_token, db, metrics)) as DynMevInspector
            }

            Self::CexDex => static_object(CexDexQuotesInspector::new(
                quote_token,
                db,
                cex_exchanges,
                trade_config.quote_offset_from_block_us,
                metrics,
            )) as DynMevInspector,
            Self::Sandwich => {
                static_object(SandwichInspector::new(quote_token, db, metrics)) as DynMevInspector
            }
            Self::Liquidations => {
                static_object(LiquidationInspector::new(quote_token, db, metrics))
                    as DynMevInspector
            }
            Self::SearcherActivity => {
                static_object(SearcherActivity::new(quote_token, db, metrics)) as DynMevInspector
            }
            Self::CexDexMarkout => static_object(CexDexMarkoutInspector::new(
                quote_token,
                db,
                cex_exchanges,
                trade_config,
                metrics,
            )) as DynMevInspector,
            Self::JitCexDex => static_object(JitCexDex {
                cex_dex: CexDexMarkoutInspector::new(
                    quote_token,
                    db,
                    cex_exchanges,
                    trade_config,
                    metrics.clone(),
                ),
                jit:     JitInspector::new(quote_token, db, metrics),
            }) as DynMevInspector,
        }
    }
}

fn static_object<T>(obj: T) -> &'static T {
    &*Box::leak(Box::new(obj))
}