kabu_broadcast_flashbots/client/
middleware.rs1use alloy_json_rpc::RpcError;
2use alloy_network::Ethereum;
3use alloy_provider::Provider;
4use alloy_signer_local::PrivateKeySigner;
5use alloy_transport::TransportErrorKind;
6use eyre::Result;
7use thiserror::Error;
8use url::Url;
9
10use crate::client::SendBundleResponseType;
11use crate::{
12 client::bundle::{BundleRequest, SimulatedBundle},
13 client::relay::{Relay, RelayError},
14};
15
16#[derive(Debug, Error)]
18pub enum FlashbotsMiddlewareError {
19 #[error("Some parameters were missing")]
32 MissingParameters,
33 #[error(transparent)]
35 RelayError(#[from] RelayError),
36 #[error(transparent)]
38 MiddlewareError(#[from] RpcError<TransportErrorKind>),
39}
40
41#[derive(Clone)]
42pub struct FlashbotsMiddleware<P> {
43 provider: P,
44 relay: Relay,
45 simulation_relay: Option<Relay>,
46}
47
48impl<P> FlashbotsMiddleware<P>
49where
50 P: Provider<Ethereum> + Send + Sync + Clone + 'static,
51{
52 pub fn new(relay_url: impl Into<Url>, provider: P) -> Self {
56 Self { provider, relay: Relay::new(relay_url, Some(PrivateKeySigner::random())), simulation_relay: None }
57 }
58
59 pub fn new_no_signer(relay_url: impl Into<Url>, provider: P) -> Self {
60 Self { provider, relay: Relay::new(relay_url, None), simulation_relay: None }
61 }
62
63 pub fn relay(&self) -> &Relay {
65 &self.relay
66 }
67
68 pub fn simulation_relay(&self) -> Option<&Relay> {
71 self.simulation_relay.as_ref()
72 }
73
74 pub fn set_simulation_relay(&mut self, relay_url: impl Into<Url>) {
79 self.simulation_relay = Some(Relay::new(relay_url, None));
80 }
81
82 pub async fn simulate_bundle(&self, bundle: &BundleRequest) -> Result<SimulatedBundle, FlashbotsMiddlewareError> {
88 bundle
89 .target_block()
90 .and(bundle.simulation_block())
91 .and(bundle.simulation_timestamp())
92 .ok_or(FlashbotsMiddlewareError::MissingParameters)?;
93
94 self.simulation_relay
95 .as_ref()
96 .unwrap_or(&self.relay)
97 .request("eth_callBundle", [bundle])
98 .await
99 .map_err(FlashbotsMiddlewareError::RelayError)
100 }
101
102 pub async fn simulate_local_bundle(&self, bundle: &BundleRequest) -> Result<SimulatedBundle, FlashbotsMiddlewareError> {
103 match self.provider.client().request("eth_callBundle", [bundle]).await {
104 Ok(result) => Ok(result),
105 Err(e) => Err(FlashbotsMiddlewareError::MiddlewareError(e)),
106 }
107 }
108
109 pub async fn send_bundle(&self, bundle: &BundleRequest) -> Result<(), FlashbotsMiddlewareError> {
115 bundle.target_block().ok_or(FlashbotsMiddlewareError::MissingParameters)?;
117
118 if bundle.min_timestamp().xor(bundle.max_timestamp()).is_some() {
120 return Err(FlashbotsMiddlewareError::MissingParameters);
121 }
122
123 let _response: SendBundleResponseType =
124 self.relay.request("eth_sendBundle", [bundle]).await.map_err(FlashbotsMiddlewareError::RelayError)?;
125
126 Ok(())
127 }
128}