loom_broadcast_flashbots/client/
middleware.rsuse alloy_json_rpc::RpcError;
use alloy_network::Ethereum;
use alloy_provider::Provider;
use alloy_signer_local::PrivateKeySigner;
use alloy_transport::{Transport, TransportErrorKind};
use eyre::Result;
use std::marker::PhantomData;
use thiserror::Error;
use url::Url;
use crate::client::SendBundleResponseType;
use crate::{
client::bundle::{BundleRequest, SimulatedBundle},
client::relay::{Relay, RelayError},
};
#[derive(Debug, Error)]
pub enum FlashbotsMiddlewareError {
#[error("Some parameters were missing")]
MissingParameters,
#[error(transparent)]
RelayError(#[from] RelayError),
#[error(transparent)]
MiddlewareError(#[from] RpcError<TransportErrorKind>),
}
#[derive(Clone)]
pub struct FlashbotsMiddleware<P, T> {
provider: P,
relay: Relay,
simulation_relay: Option<Relay>,
_t: PhantomData<T>,
}
impl<P, T> FlashbotsMiddleware<P, T>
where
T: Transport + Clone,
P: Provider<T, Ethereum> + Send + Sync + Clone + 'static,
{
pub fn new(relay_url: impl Into<Url>, provider: P) -> Self {
Self { provider, relay: Relay::new(relay_url, Some(PrivateKeySigner::random())), simulation_relay: None, _t: PhantomData }
}
pub fn new_no_signer(relay_url: impl Into<Url>, provider: P) -> Self {
Self { provider, relay: Relay::new(relay_url, None), simulation_relay: None, _t: PhantomData }
}
pub fn relay(&self) -> &Relay {
&self.relay
}
pub fn simulation_relay(&self) -> Option<&Relay> {
self.simulation_relay.as_ref()
}
pub fn set_simulation_relay(&mut self, relay_url: impl Into<Url>) {
self.simulation_relay = Some(Relay::new(relay_url, None));
}
pub async fn simulate_bundle(&self, bundle: &BundleRequest) -> Result<SimulatedBundle, FlashbotsMiddlewareError> {
bundle
.target_block()
.and(bundle.simulation_block())
.and(bundle.simulation_timestamp())
.ok_or(FlashbotsMiddlewareError::MissingParameters)?;
self.simulation_relay
.as_ref()
.unwrap_or(&self.relay)
.request("eth_callBundle", [bundle])
.await
.map_err(FlashbotsMiddlewareError::RelayError)
}
pub async fn simulate_local_bundle(&self, bundle: &BundleRequest) -> Result<SimulatedBundle, FlashbotsMiddlewareError> {
match self.provider.client().request("eth_callBundle", [bundle]).await {
Ok(result) => Ok(result),
Err(e) => Err(FlashbotsMiddlewareError::MiddlewareError(e)),
}
}
pub async fn send_bundle(&self, bundle: &BundleRequest) -> Result<(), FlashbotsMiddlewareError> {
bundle.target_block().ok_or(FlashbotsMiddlewareError::MissingParameters)?;
if bundle.min_timestamp().xor(bundle.max_timestamp()).is_some() {
return Err(FlashbotsMiddlewareError::MissingParameters);
}
let _response: SendBundleResponseType =
self.relay.request("eth_sendBundle", [bundle]).await.map_err(FlashbotsMiddlewareError::RelayError)?;
Ok(())
}
}