Skip to main content

alloy_provider/ext/mev/
mod.rs

1mod with_auth;
2
3pub use self::with_auth::{
4    sign_flashbots_payload, verify_flashbots_signature, FlashbotsSignatureError, MevBuilder,
5};
6use crate::Provider;
7use alloy_network::Network;
8use alloy_primitives::{hex, TxHash};
9use alloy_rpc_types_mev::{
10    EthBundleHash, EthCallBundle, EthCallBundleResponse, EthCancelBundle,
11    EthCancelPrivateTransaction, EthSendBlobs, EthSendBundle, EthSendEndOfBlockBundle,
12    EthSendPrivateTransaction, MevSendBundle, PrivateTransactionPreferences, SimBundleResponse,
13};
14
15/// The HTTP header used for Flashbots signature authentication.
16pub const FLASHBOTS_SIGNATURE_HEADER: &str = "x-flashbots-signature";
17
18/// This module provides support for interacting with non-standard MEV-related RPC endpoints.
19///
20/// # Important Notes
21///
22/// MEV operations are extremely time-sensitive and should be executed as quickly as possible.
23/// Bundle submissions have strict timing requirements and may fail if submitted too late.
24///
25/// ## Common Limitations
26///
27/// - Bundle size limits vary by relay (typically 1-10 transactions)
28/// - Timeout constraints apply to simulation and execution
29/// - Rate limiting may be enforced by MEV relays
30/// - Authentication is required for most operations
31///
32/// See [Flashbots documentation](https://docs.flashbots.net/flashbots-auction/searchers/advanced/rpc-endpoint) for detailed limitations.
33#[cfg_attr(target_family = "wasm", async_trait::async_trait(?Send))]
34#[cfg_attr(not(target_family = "wasm"), async_trait::async_trait)]
35pub trait MevApi<N>: Send + Sync {
36    /// Simulates a bundle of transactions using the `eth_callBundle` RPC method.
37    fn call_bundle(
38        &self,
39        bundle: EthCallBundle,
40    ) -> MevBuilder<(EthCallBundle,), Option<EthCallBundleResponse>>;
41
42    /// Sends a MEV bundle using the `eth_sendBundle` RPC method.
43    /// Returns the resulting bundle hash on success.
44    ///
45    /// # Timing Critical
46    ///
47    /// Bundle submission is extremely time-sensitive. Submit as early as possible
48    /// in the block interval to maximize inclusion probability.
49    fn send_bundle(
50        &self,
51        bundle: EthSendBundle,
52    ) -> MevBuilder<(EthSendBundle,), Option<EthBundleHash>>;
53
54    /// Cancels a previously sent MEV bundle using the `eth_cancelBundle` RPC method.
55    fn cancel_bundle(&self, replacement_uuid: String) -> MevBuilder<(EthCancelBundle,), ()>;
56
57    /// Sends blob transaction permutations using the `eth_sendBlobs` RPC method.
58    fn send_blobs(&self, blobs: EthSendBlobs) -> MevBuilder<(EthSendBlobs,), ()>;
59
60    /// Sends a private transaction using the `eth_sendPrivateTransaction` RPC method.
61    fn send_private_transaction(
62        &self,
63        private_tx: EthSendPrivateTransaction,
64    ) -> MevBuilder<(EthSendPrivateTransaction,), Option<TxHash>>;
65
66    /// Sends a private transaction using the `eth_sendPrivateRawTransaction` RPC method.
67    fn send_private_raw_transaction(
68        &self,
69        encoded_tx: &[u8],
70        preferences: Option<PrivateTransactionPreferences>,
71    ) -> MevBuilder<(String, Option<PrivateTransactionPreferences>), Option<TxHash>>;
72
73    /// Cancels a previously sent private transaction using the `eth_cancelPrivateTransaction` RPC
74    /// method.
75    fn cancel_private_transaction(
76        &self,
77        tx_hash: TxHash,
78    ) -> MevBuilder<(EthCancelPrivateTransaction,), bool>;
79
80    /// Sends end-of-block bundle using the `eth_sendEndOfBlockBundle` RPC method.
81    /// Returns the resulting bundle hash on success.
82    fn send_end_of_block_bundle(
83        &self,
84        bundle: EthSendEndOfBlockBundle,
85    ) -> MevBuilder<(EthSendEndOfBlockBundle,), Option<EthBundleHash>>;
86
87    /// Sends a MEV bundle using the `mev_sendBundle` RPC method.
88    /// Returns the resulting bundle hash on success.
89    ///
90    /// # Timing Critical
91    ///
92    /// Bundle submission is extremely time-sensitive. Submit as early as possible
93    /// in the block interval to maximize inclusion probability.
94    fn send_mev_bundle(
95        &self,
96        bundle: MevSendBundle,
97    ) -> MevBuilder<(MevSendBundle,), Option<EthBundleHash>>;
98
99    /// Simulates a MEV bundle using the `mev_simBundle` RPC method.
100    /// Returns the simulation result on success.
101    ///
102    /// # Matched Bundles Only
103    ///
104    /// Only matched bundles can be simulated. The `bundle` must contain only signed
105    /// transactions ([`BundleItem::Tx`]) or nested bundles ([`BundleItem::Bundle`]) that
106    /// themselves contain only signed transactions. Bundles containing a transaction hash
107    /// ([`BundleItem::Hash`]) are considered "unmatched" and will cause the call to error.
108    ///
109    /// [`BundleItem::Tx`]: alloy_rpc_types_mev::BundleItem::Tx
110    /// [`BundleItem::Bundle`]: alloy_rpc_types_mev::BundleItem::Bundle
111    /// [`BundleItem::Hash`]: alloy_rpc_types_mev::BundleItem::Hash
112    fn sim_mev_bundle(
113        &self,
114        bundle: MevSendBundle,
115    ) -> MevBuilder<(MevSendBundle,), Option<SimBundleResponse>>;
116}
117
118#[cfg_attr(target_family = "wasm", async_trait::async_trait(?Send))]
119#[cfg_attr(not(target_family = "wasm"), async_trait::async_trait)]
120impl<N, P> MevApi<N> for P
121where
122    N: Network,
123    P: Provider<N>,
124{
125    fn call_bundle(
126        &self,
127        bundle: EthCallBundle,
128    ) -> MevBuilder<(EthCallBundle,), Option<EthCallBundleResponse>> {
129        MevBuilder::new_rpc(self.client().request("eth_callBundle", (bundle,)))
130    }
131
132    fn send_bundle(
133        &self,
134        bundle: EthSendBundle,
135    ) -> MevBuilder<(EthSendBundle,), Option<EthBundleHash>> {
136        MevBuilder::new_rpc(self.client().request("eth_sendBundle", (bundle,)))
137    }
138
139    fn cancel_bundle(&self, replacement_uuid: String) -> MevBuilder<(EthCancelBundle,), ()> {
140        MevBuilder::new_rpc(
141            self.client().request("eth_cancelBundle", (EthCancelBundle { replacement_uuid },)),
142        )
143    }
144
145    fn send_blobs(&self, blobs: EthSendBlobs) -> MevBuilder<(EthSendBlobs,), ()> {
146        MevBuilder::new_rpc(self.client().request("eth_sendBlobs", (blobs,)))
147    }
148
149    fn send_private_transaction(
150        &self,
151        private_tx: EthSendPrivateTransaction,
152    ) -> MevBuilder<(EthSendPrivateTransaction,), Option<TxHash>> {
153        MevBuilder::new_rpc(self.client().request("eth_sendPrivateTransaction", (private_tx,)))
154    }
155
156    fn send_private_raw_transaction(
157        &self,
158        encoded_tx: &[u8],
159        preferences: Option<PrivateTransactionPreferences>,
160    ) -> MevBuilder<(String, Option<PrivateTransactionPreferences>), Option<TxHash>> {
161        let rlp_hex = hex::encode_prefixed(encoded_tx);
162        MevBuilder::new_rpc(
163            self.client().request("eth_sendPrivateRawTransaction", (rlp_hex, preferences)),
164        )
165    }
166
167    fn cancel_private_transaction(
168        &self,
169        tx_hash: TxHash,
170    ) -> MevBuilder<(EthCancelPrivateTransaction,), bool> {
171        MevBuilder::new_rpc(
172            self.client().request(
173                "eth_cancelPrivateTransaction",
174                (EthCancelPrivateTransaction { tx_hash },),
175            ),
176        )
177    }
178
179    fn send_end_of_block_bundle(
180        &self,
181        bundle: EthSendEndOfBlockBundle,
182    ) -> MevBuilder<(EthSendEndOfBlockBundle,), Option<EthBundleHash>> {
183        MevBuilder::new_rpc(self.client().request("eth_sendEndOfBlockBundle", (bundle,)))
184    }
185
186    fn send_mev_bundle(
187        &self,
188        bundle: MevSendBundle,
189    ) -> MevBuilder<(MevSendBundle,), Option<EthBundleHash>> {
190        MevBuilder::new_rpc(self.client().request("mev_sendBundle", (bundle,)))
191    }
192
193    fn sim_mev_bundle(
194        &self,
195        bundle: MevSendBundle,
196    ) -> MevBuilder<(MevSendBundle,), Option<SimBundleResponse>> {
197        MevBuilder::new_rpc(self.client().request("mev_simBundle", (bundle,)))
198    }
199}