1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
use crate::{
bundle::BundleHash,
jsonrpc::{JsonRpcError, Request, Response},
};
use ethers_core::{types::H256, utils::keccak256};
use ethers_signers::Signer;
use reqwest::{Client, Error as ReqwestError};
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use std::sync::atomic::{AtomicU64, Ordering};
use thiserror::Error;
use url::Url;
#[derive(Debug)]
pub struct Relay<S> {
id: AtomicU64,
client: Client,
url: Url,
signer: S,
}
#[derive(Error, Debug)]
pub enum RelayError<S: Signer> {
#[error(transparent)]
RequestError(#[from] ReqwestError),
#[error(transparent)]
JsonRpcError(#[from] JsonRpcError),
#[error(transparent)]
RequestSerdeJson(#[from] serde_json::Error),
#[error(transparent)]
SignerError(#[from(S::Error)] S::Error),
#[error("Deserialization error: {err}. Response: {text}")]
ResponseSerdeJson {
err: serde_json::Error,
text: String,
},
}
impl<S: Signer> Relay<S> {
pub fn new(url: impl Into<Url>, signer: S) -> Self {
Self {
id: AtomicU64::new(0),
client: Client::new(),
url: url.into(),
signer,
}
}
pub async fn request<T: Serialize + Send + Sync, R: DeserializeOwned>(
&self,
method: &str,
params: T,
) -> Result<R, RelayError<S>> {
let next_id = self.id.load(Ordering::SeqCst) + 1;
self.id.store(next_id, Ordering::SeqCst);
let payload = Request::new(next_id, method, params);
let signature = self
.signer
.sign_message(format!(
"0x{:x}",
H256::from(keccak256(
serde_json::to_string(&payload)
.map_err(RelayError::RequestSerdeJson)?
.as_bytes()
))
))
.await
.map_err(RelayError::SignerError)?;
let res = self
.client
.post(self.url.as_ref())
.header(
"X-Flashbots-Signature",
format!("{:?}:0x{}", self.signer.address(), signature),
)
.json(&payload)
.send()
.await?;
let text = res.text().await?;
let res: Response<R> = serde_json::from_str(&text)
.map_err(|err| RelayError::ResponseSerdeJson { err, text })?;
Ok(res.data.into_result()?)
}
}
impl<S: Signer + Clone> Clone for Relay<S> {
fn clone(&self) -> Self {
Self {
id: AtomicU64::new(0),
client: self.client.clone(),
url: self.url.clone(),
signer: self.signer.clone(),
}
}
}
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct SendBundleResponse {
pub(crate) bundle_hash: BundleHash,
}