txboost_rs/
middleware.rs

1use crate::{
2    bundle::{SendBundleRequest, SimulateBundleRequest, StateBlockNumber},
3    relay::{Relay, RelayError},
4};
5use ethers::{
6    core::types::U64,
7    providers::{Middleware, MiddlewareError},
8    signers::Signer,
9};
10use serde::{de, Deserialize, Deserializer, Serialize};
11use thiserror::Error;
12
13#[derive(Debug, Error)]
14pub enum TxBoostMiddlewareError<M: Middleware> {
15    /// The relay responded with an error.
16    #[error(transparent)]
17    RelayError(#[from] RelayError),
18    #[error("{0}")]
19    MiddlewareError(M::Error),
20    #[error("Failed to simulate bundle")]
21    BundleSimError,
22}
23
24impl<M: Middleware> MiddlewareError for TxBoostMiddlewareError<M> {
25    type Inner = M::Error;
26
27    fn from_err(src: M::Error) -> TxBoostMiddlewareError<M> {
28        TxBoostMiddlewareError::MiddlewareError(src)
29    }
30
31    fn as_inner(&self) -> Option<&Self::Inner> {
32        match self {
33            TxBoostMiddlewareError::MiddlewareError(e) => Some(e),
34            _ => None,
35        }
36    }
37}
38
39#[derive(Debug)]
40pub struct TxBoostMiddleware<M, S> {
41    inner: M,
42    relay: Relay<S>,
43    simulation_relay: Option<Relay<S>>,
44}
45
46impl<M: Middleware, S: Signer> TxBoostMiddleware<M, S> {
47    pub fn new(inner: M, relay: Relay<S>, simulation_relay: Option<Relay<S>>) -> Self {
48        Self {
49            inner,
50            relay,
51            simulation_relay,
52        }
53    }
54
55    pub fn relay(&self) -> &Relay<S> {
56        &self.relay
57    }
58
59    pub fn simulation_relay(&self) -> Option<&Relay<S>> {
60        self.simulation_relay.as_ref()
61    }
62
63    pub fn into_inner(self) -> M {
64        self.inner
65    }
66
67    pub async fn simulate_bundle(
68        &self,
69        bundle: &SimulateBundleRequest,
70    ) -> Result<SimulatedBundleResponse, TxBoostMiddlewareError<M>> {
71        self.simulation_relay
72            .as_ref()
73            .unwrap_or(&self.relay)
74            .request("eth_callBundle", [bundle])
75            .await
76            .map_err(TxBoostMiddlewareError::RelayError)?
77            .ok_or(TxBoostMiddlewareError::BundleSimError)
78    }
79
80    pub async fn send_bundle(
81        &self,
82        bundle: &SendBundleRequest,
83    ) -> Result<SendBundleResponse, TxBoostMiddlewareError<M>> {
84        self.relay
85            .request("eth_sendBundle", [bundle])
86            .await
87            .map_err(TxBoostMiddlewareError::RelayError)?
88            .ok_or(TxBoostMiddlewareError::BundleSimError)
89    }
90}
91
92fn de_from_str<'de, D>(deserializer: D) -> Result<U64, D::Error>
93where
94    D: Deserializer<'de>,
95{
96    let s = String::deserialize(deserializer)?;
97
98    U64::from_str_radix(&s, 16).map_err(de::Error::custom)
99}
100
101#[derive(Debug, Clone, Serialize, Deserialize)]
102pub struct SimulatedBundleResponse {
103    txs: Vec<String>,
104    #[serde(deserialize_with = "de_from_str")]
105    block_number: U64,
106    state_block_number: StateBlockNumber,
107    #[serde(skip_serializing_if = "Option::is_none")]
108    timestamp: Option<u64>,
109}
110
111#[derive(Debug, Clone, Serialize, Deserialize)]
112pub struct SendBundleResponse {
113    pub bundle_gas_price: String,
114    pub bundle_hash: String,
115    pub coinbase_diff: String,
116    pub eth_sent_to_coinbase: String,
117    pub gas_fees: String,
118    pub results: Vec<SendBundleResult>,
119    pub state_block_number: u64,
120    pub total_gas_used: u64,
121}
122
123#[derive(Debug, Clone, Serialize, Deserialize)]
124pub struct SendBundleResult {
125    pub bundle_hash: String,
126    pub coinbase_diff: String,
127    pub eth_sent_to_coinbase: String,
128    pub gas_fees: String,
129    pub state_block_number: u64,
130    pub total_gas_used: u64,
131}