kabu_broadcast_flashbots/client/
relay.rs

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