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 #[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}