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
use std::sync::Arc;

use brontes_types::{
    db::traits::LibmdbxReader,
    mev::{AtomicArbType, Bundle, BundleData, MevType},
    normalized_actions::Action,
    BlockTree,
};
use lazy_static::lazy_static;

/// Defines precedence rules among different MEV types for the purpose of
/// deduplication.
///
/// This macro creates a static reference (`MEV_DEDUPLICATION_FILTER`) that maps
/// a list of subordinate MEV types to each dominant MEV type. These rules are
/// used to determine which MEV types should be considered for deduplication
/// when multiple types are present for overlapping transactions.
///
/// # Usage
/// ```ignore
/// define_mev_precedence!(
///     SubordinateMevType1, SubordinateMevType2 => DominantMevType;
/// );
/// ```
/// In this example, `DominantMevType` takes precedence over
/// `SubordinateMevType1` and `SubordinateMevType2` for deduplication purposes.
///
/// Example of defining multiple precedence rules:
/// ```ignore
/// define_mev_precedence!(
///     Backrun => Sandwich;
///     Backrun => Jit;
///     Backrun => JitSandwich;
/// );
/// ```
/// In these examples, `Backrun` is considered subordinate to `Sandwich`, `Jit`,
/// `JitSandwich`.  
#[macro_export]
macro_rules! define_mev_precedence {
    ($($($subordinate_mev_type:ident),+ => $dominant_mev_type:ident;)+) => {
        lazy_static! {
            pub static ref MEV_DEDUPLICATION_FILTER:
                &'static [(MevType, FilterFn, Vec<MevType>)] = {
                &*Box::leak(Box::new([
                    $((
                        MevType::$dominant_mev_type,
                        get_filter_fn(MevType::$dominant_mev_type),
                        vec![$(MevType::$subordinate_mev_type),+],
                    ),)+
                ]))
            };
        }
    };
}

pub type FilterFn = Option<
    Box<
        dyn Fn(Arc<BlockTree<Action>>, Arc<Box<dyn LibmdbxReader>>, [&Bundle; 2]) -> bool
            + Send
            + Sync,
    >,
>;

pub fn get_filter_fn(mev_type: MevType) -> FilterFn {
    match mev_type {
        MevType::AtomicArb => Some(Box::new(atomic_dedup_fn)),
        _ => None,
    }
}

/// returns true if should dedup.
pub fn atomic_dedup_fn(
    _tree: Arc<BlockTree<Action>>,
    _db: Arc<Box<dyn LibmdbxReader>>,
    bundles: [&Bundle; 2],
) -> bool {
    let [atomic, other] = bundles;

    if matches!(other.data, BundleData::CexDex(_)) {
        let atomic_data = match &atomic.data {
            BundleData::AtomicArb(data) => data,
            _ => {
                return false;
            }
        };

        if atomic_data.arb_type == AtomicArbType::Triangle {
            return false;
        }
        // if the cex dex has a higher value. then use that.
        if other.header.profit_usd >= atomic.header.profit_usd {
            return false
        }
        // if the cex dex isn't a known fund ignore
        if !other.header.fund.is_none() {
            return false
        }
    }

    true
}

define_mev_precedence!(
    // will filter out unless function says otherwise
    CexDexTrades => AtomicArb;

    // filter out all atomic arbs that we kept as cex dex
    AtomicArb => CexDexTrades;
    Unknown, SearcherTx => CexDexQuotes;
    Unknown, SearcherTx => CexDexTrades;
    Unknown, SearcherTx => AtomicArb;
    Unknown, SearcherTx, AtomicArb => Jit;
    Unknown, SearcherTx, AtomicArb, CexDexQuotes,CexDexTrades  => Liquidation;
    Unknown, SearcherTx, AtomicArb, CexDexQuotes,CexDexTrades  => Sandwich;
    Unknown, SearcherTx, AtomicArb, Jit, CexDexQuotes, CexDexTrades=> JitCexDex;
    Unknown, SearcherTx, AtomicArb, CexDexQuotes, CexDexTrades, Jit, Sandwich => JitSandwich;
);