ethers_flashbots/
relay.rs

1use crate::{
2    bundle::BundleHash,
3    jsonrpc::{JsonRpcError, Request, Response},
4};
5use ethers::core::{
6    types::{H256, U64},
7    utils::keccak256,
8};
9use ethers::signers::Signer;
10use reqwest::{Client, Error as ReqwestError};
11use serde::{de::DeserializeOwned, Deserialize, Serialize};
12use std::sync::atomic::{AtomicU64, Ordering};
13use thiserror::Error;
14use url::Url;
15
16/// A Flashbots relay client.
17///
18/// The client automatically signs every request and sets the Flashbots
19/// authorization header appropriately with the given signer.
20///
21/// **Note**: You probably do not want to use this directly, unless
22/// you want to interact directly with the Relay. Most users should use
23/// [`FlashbotsMiddleware`](crate::FlashbotsMiddleware) instead.
24#[derive(Debug)]
25pub struct Relay<S> {
26    id: AtomicU64,
27    client: Client,
28    url: Url,
29    signer: Option<S>,
30}
31
32/// Errors for relay requests.
33#[derive(Error, Debug)]
34pub enum RelayError<S: Signer> {
35    /// The request failed.
36    #[error(transparent)]
37    RequestError(#[from] ReqwestError),
38    /// The request could not be parsed.
39    #[error(transparent)]
40    JsonRpcError(#[from] JsonRpcError),
41    /// The request parameters were invalid.
42    #[error("Client error: {text}")]
43    ClientError { text: String },
44    /// The request could not be serialized.
45    #[error(transparent)]
46    RequestSerdeJson(#[from] serde_json::Error),
47    /// The request could not be signed.
48    #[error(transparent)]
49    SignerError(#[from(S::Error)] S::Error),
50    /// The response could not be deserialized.
51    #[error("Deserialization error: {err}. Response: {text}")]
52    ResponseSerdeJson {
53        err: serde_json::Error,
54        text: String,
55    },
56}
57
58impl<S: Signer> Relay<S> {
59    /// Initializes a new relay client.
60    pub fn new(url: impl Into<Url>, signer: Option<S>) -> Self {
61        Self {
62            id: AtomicU64::new(0),
63            client: Client::new(),
64            url: url.into(),
65            signer,
66        }
67    }
68
69    /// Sends a request with the provided method to the relay, with the
70    /// parameters serialized as JSON.
71    pub async fn request<T: Serialize + Send + Sync, R: DeserializeOwned>(
72        &self,
73        method: &str,
74        params: T,
75    ) -> Result<Option<R>, RelayError<S>> {
76        let next_id = self.id.load(Ordering::SeqCst) + 1;
77        self.id.store(next_id, Ordering::SeqCst);
78
79        let payload = Request::new(next_id, method, params);
80
81        let mut req = self.client.post(self.url.as_ref());
82
83        if let Some(signer) = &self.signer {
84            let signature = signer
85                .sign_message(format!(
86                    "0x{:x}",
87                    H256::from(keccak256(
88                        serde_json::to_string(&payload)
89                            .map_err(RelayError::RequestSerdeJson)?
90                            .as_bytes()
91                    ))
92                ))
93                .await
94                .map_err(RelayError::SignerError)?;
95
96            req = req.header(
97                "X-Flashbots-Signature",
98                format!("{:?}:0x{}", signer.address(), signature),
99            );
100        }
101
102        let res = req.json(&payload).send().await?;
103        let status = res.error_for_status_ref();
104
105        match status {
106            Err(err) => {
107                let text = res.text().await?;
108                let status_code = err.status().unwrap();
109                if status_code.is_client_error() {
110                    // Client error (400-499)
111                    Err(RelayError::ClientError { text })
112                } else {
113                    // Internal server error (500-599)
114                    Err(RelayError::RequestError(err))
115                }
116            }
117            Ok(_) => {
118                let text = res.text().await?;
119                let res: Response<R> = serde_json::from_str(&text)
120                    .map_err(|err| RelayError::ResponseSerdeJson { err, text })?;
121
122                Ok(res.data.into_result()?)
123            }
124        }
125    }
126}
127
128impl<S: Signer + Clone> Clone for Relay<S> {
129    fn clone(&self) -> Self {
130        Self {
131            id: AtomicU64::new(0),
132            client: self.client.clone(),
133            url: self.url.clone(),
134            signer: self.signer.clone(),
135        }
136    }
137}
138
139#[derive(Deserialize)]
140#[serde(rename_all = "camelCase")]
141pub(crate) struct SendBundleResponse {
142    pub(crate) bundle_hash: Option<BundleHash>,
143}
144
145#[derive(Serialize)]
146#[serde(rename_all = "camelCase")]
147pub(crate) struct GetBundleStatsParams {
148    pub(crate) bundle_hash: BundleHash,
149    pub(crate) block_number: U64,
150}
151
152#[derive(Serialize)]
153#[serde(rename_all = "camelCase")]
154pub(crate) struct GetUserStatsParams {
155    pub(crate) block_number: U64,
156}