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))
}