1use log::debug;
2use serde_json::Value;
3use types::JsonRpc;
4
5use crate::{http::http_send, types::JsonRpcRequest};
6
7mod http;
8pub mod types;
9mod utils;
10
11#[derive(Debug, Clone)]
12pub struct Wall {
13 pub urls: Vec<String>,
15 pub retry: u32,
17 pub id: String,
19}
20
21impl Wall {
22 pub fn new(urls: Vec<String>, retry: Option<u32>, id: Option<String>) -> Self {
23 Wall {
24 urls,
25 retry: retry.unwrap_or(3),
26 id: id.unwrap_or("1".to_string()),
27 }
28 }
29
30 pub async fn get_latest_number(&self) -> Option<JsonRpc> {
31 self.send_rpc_request("eth_blockNumber", vec![]).await
32 }
33
34 pub async fn get_transactions_for_block(&self, number: &str, is_show: bool) -> Option<JsonRpc> {
35 self.send_rpc_request(
36 "eth_getBlockByNumber",
37 vec![Value::String(number.to_string()), Value::Bool(is_show)],
38 )
39 .await
40 }
41
42 pub async fn get_transaction_receipt_for_hash(&self, hash: &str) -> Option<JsonRpc> {
43 self.send_rpc_request(
44 "eth_getTransactionReceipt",
45 vec![Value::String(hash.to_string())],
46 )
47 .await
48 }
49
50 pub async fn get_logs(
51 &self,
52 from_block: Option<String>,
53 to_block: Option<String>,
54 address: Option<Vec<String>>,
55 topics: Option<Vec<String>>,
56 ) -> Option<JsonRpc> {
57 let mut params = serde_json::Map::new();
58
59 if let Some(from_block) = from_block {
60 params.insert("fromBlock".to_string(), Value::String(from_block));
61 }
62
63 if let Some(to_block) = to_block {
64 params.insert("toBlock".to_string(), Value::String(to_block));
65 }
66
67 if let Some(address) = address {
68 params.insert(
69 "address".to_string(),
70 Value::Array(address.into_iter().map(Value::String).collect()),
71 );
72 }
73
74 if let Some(topics) = topics {
75 params.insert(
76 "topics".to_string(),
77 Value::Array(topics.into_iter().map(Value::String).collect()),
78 );
79 }
80
81 self.send_rpc_request("eth_getLogs", vec![Value::Object(params)])
82 .await
83 }
84
85 async fn send_rpc_request(&self, method: &str, params: Vec<Value>) -> Option<JsonRpc> {
86 let query = JsonRpcRequest {
87 method: method.to_string(),
88 params: Value::Array(params),
89 id: self.id.parse().unwrap(),
90 jsonrpc: "2.0".to_string(),
91 };
92
93 debug!("🔧 Query: {:?}", query);
94
95 http_send(self.urls.as_ref(), self.retry, query).await
96 }
97}
98
99#[cfg(test)]
100mod tests {
101 use super::Wall;
102 fn init() -> Wall {
103 Wall::new(
104 vec![
105 "https://rpc.builder0x69.io".to_string(),
108 ],
109 None,
110 None,
111 )
112 }
113
114 #[async_std::test]
115 async fn test_get_latest_number() {
116 let bs = init();
117 assert_eq!(bs.get_latest_number().await.unwrap().result.is_some(), true);
118 }
119
120 #[async_std::test]
121 async fn test_get_transactions_for_block() {
122 let bs = init();
123
124 assert_eq!(
125 bs.get_transactions_for_block("0xe5b544", false)
126 .await
127 .unwrap()
128 .result
129 .is_some(),
130 true
131 )
132 }
133
134 #[async_std::test]
135 async fn test_get_transactions_for_block_error() {
136 let bs = init();
137
138 println!(
139 "{:?}",
140 bs.get_transactions_for_block("1233333", false).await
141 );
142 assert_eq!(
143 bs.get_transactions_for_block("1233333", false)
144 .await
145 .is_some(),
146 false
147 )
148 }
149
150 #[async_std::test]
151 async fn test_get_transaction_receipt_for_hash_error() {
152 let bs = init();
153
154 println!(
155 "{:?}",
156 bs.get_transaction_receipt_for_hash(
157 "0x890137f33ba2ddfa9778d55336e83bcac477232d1de7abb3f3dca0ae019798"
158 )
159 .await
160 );
161 assert_eq!(
162 false,
163 bs.get_transaction_receipt_for_hash(
164 "0x890137f33ba2ddfa9778d55336e83bcac477232d1de7abb3f3dca0ae019798"
165 )
166 .await
167 .unwrap()
168 .result
169 .is_some()
170 );
171 }
172
173 #[async_std::test]
174 async fn test_get_transaction_receipt_for_hash() {
175 let bs = init();
176 assert_eq!(
177 true,
178 bs.get_transaction_receipt_for_hash(
179 "0x80fdaa7f5f54cbe28b84f41afb9543cf0c9eb0d9f4b8a620c2fb5faf0b1c2810"
180 )
181 .await
182 .unwrap()
183 .result
184 .is_some()
185 );
186 }
187
188 #[async_std::test]
189 async fn test_get_logs() {
190 let bs = init();
191 assert_eq!(
192 true,
193 bs.get_logs(
194 Some("0x1068F10".to_string()),
195 Some("0x1068F11".to_string()),
196 Some(vec!["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2".to_owned()]),
197 None
198 )
199 .await
200 .is_some()
201 )
202 }
203}