kabu_broadcast_flashbots/client/
jsonrpc.rs1use std::fmt;
2
3use crate::client::BundleHash;
4use alloy_primitives::U256;
5use serde::{Deserialize, Serialize};
6use serde_json::Value;
7use thiserror::Error;
8#[derive(Serialize, Deserialize, Debug, Clone, Error)]
14pub struct JsonRpcError {
15 pub code: i64,
17 pub message: String,
19 pub data: Option<Value>,
21}
22
23impl fmt::Display for JsonRpcError {
24 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
25 write!(f, "(code: {}, message: {}, data: {:?})", self.code, self.message, self.data)
26 }
27}
28
29fn is_zst<T>(_t: &T) -> bool {
30 std::mem::size_of::<T>() == 0
31}
32
33#[derive(Serialize, Deserialize, Debug)]
34pub struct Request<'a, T> {
36 id: u64,
37 jsonrpc: &'a str,
38 method: &'a str,
39 #[serde(skip_serializing_if = "is_zst")]
40 params: T,
41}
42
43#[derive(Serialize, Deserialize, Debug)]
44pub struct Notification<R> {
46 jsonrpc: String,
47 method: String,
48 pub params: Subscription<R>,
49}
50
51#[derive(Serialize, Deserialize, Debug)]
52pub struct Subscription<R> {
53 pub subscription: U256,
54 pub result: R,
55}
56
57impl<'a, T> Request<'a, T> {
58 pub fn new(id: u64, method: &'a str, params: T) -> Self {
60 Self { id, jsonrpc: "2.0", method, params }
61 }
62}
63
64#[derive(Serialize, Deserialize, Debug, Clone)]
65pub struct Response<T> {
66 #[serde(default)]
67 pub(crate) id: u64,
68 #[serde(default)]
69 jsonrpc: String,
70 #[serde(flatten)]
71 pub data: ResponseData<T>,
72}
73
74#[derive(Serialize, Deserialize, Debug, Clone)]
75#[serde(untagged)]
76pub enum ResponseData<R> {
77 Error { error: JsonRpcError },
78 Success { result: R },
79}
80
81impl<R> ResponseData<R> {
82 pub fn into_result(self) -> Result<R, JsonRpcError> {
84 match self {
85 ResponseData::Success { result } => Ok(result),
86 ResponseData::Error { error } => Err(error),
87 }
88 }
89}
90
91#[derive(Deserialize, Debug, PartialEq, Eq, Hash)]
92#[serde(untagged)]
93pub enum SendBundleResponseType {
94 Integer(u64),
95 BundleHash(BundleHash),
96 String(String),
97 SendBundleResponse(SendBundleResponse),
98 Null(Option<()>),
99}
100
101#[derive(Deserialize, Debug, PartialEq, Eq, Hash)]
102#[serde(rename_all = "camelCase")]
103pub struct SendBundleResponse {
104 #[serde(default)]
105 pub(crate) bundle_hash: Option<BundleHash>,
106}
107
108#[cfg(test)]
109mod tests {
110 use super::*;
111 use alloy_primitives::{hex, TxHash};
112
113 #[test]
114 fn deser_response() {
115 let response: Response<u64> = serde_json::from_str(r#"{"jsonrpc": "2.0", "result": 19, "id": 1}"#).unwrap();
116 assert_eq!(response.id, 1);
117 assert_eq!(response.data.into_result().unwrap(), 19);
118 }
119
120 #[test]
121 fn ser_request() {
122 let request: Request<()> = Request::new(300, "method_name", ());
123 assert_eq!(&serde_json::to_string(&request).unwrap(), r#"{"id":300,"jsonrpc":"2.0","method":"method_name"}"#);
124
125 let request: Request<u32> = Request::new(300, "method_name", 1);
126 assert_eq!(&serde_json::to_string(&request).unwrap(), r#"{"id":300,"jsonrpc":"2.0","method":"method_name","params":1}"#);
127 }
128
129 #[test]
130 fn deser_response_enum() {
131 let response: Response<SendBundleResponseType> = serde_json::from_str(r#"{"jsonrpc": "2.0", "result": 19, "id": 1}"#).unwrap();
132 assert_eq!(response.id, 1);
133 assert_eq!(response.data.into_result().unwrap(), SendBundleResponseType::Integer(19));
134 }
135
136 #[test]
137 fn deser_response_result_null() {
138 let response: Response<SendBundleResponseType> = serde_json::from_str(r#"{"jsonrpc":"2.0","id":2,"result":null}"#).unwrap();
140 assert_eq!(response.id, 2);
141 assert_eq!(response.data.into_result().unwrap(), SendBundleResponseType::Null(None));
142 }
143
144 #[test]
145 fn deser_response_result_string() {
146 let response: Response<SendBundleResponseType> = serde_json::from_str(r#"{"jsonrpc":"2.0","id":1,"result":"nil"}"#).unwrap();
149 assert_eq!(response.id, 1);
150 assert_eq!(response.data.into_result().unwrap(), SendBundleResponseType::String("nil".to_string()));
151 }
152 #[test]
153 fn deser_response_result_send_bundle_response() {
154 let response: Response<SendBundleResponseType> = serde_json::from_str(
155 r#"{"id":1,"result":{"bundleHash":"0xcc6c61428c6516a252768859d167dc8f5c8c8c682334a184710f898e422530f8"},"jsonrpc":"2.0"}"#,
156 )
157 .unwrap();
158 assert_eq!(response.id, 1);
159 assert_eq!(
160 response.data.into_result().unwrap(),
161 SendBundleResponseType::SendBundleResponse(SendBundleResponse {
162 bundle_hash: Some(TxHash::from(hex!("cc6c61428c6516a252768859d167dc8f5c8c8c682334a184710f898e422530f8")))
163 })
164 )
165 }
166 #[test]
167 fn deser_response_result_bundle_hash_response() {
168 let response: Response<SendBundleResponseType> = serde_json::from_str(
169 r#"{"jsonrpc":"2.0","id":1,"result":"0xcc6c61428c6516a252768859d167dc8f5c8c8c682334a184710f898e422530f8"}"#,
170 )
171 .unwrap();
172 assert_eq!(response.id, 1);
173 assert_eq!(
174 response.data.into_result().unwrap(),
175 SendBundleResponseType::BundleHash(TxHash::from(hex!("cc6c61428c6516a252768859d167dc8f5c8c8c682334a184710f898e422530f8")))
176 )
177 }
178
179 }