wall_echain/
lib.rs

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    /// RPC Server URLs
14    pub urls: Vec<String>,
15    /// Re-try quest
16    pub retry: u32,
17    /// ChainId
18    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://cloudflare-eth.com/".to_string(),
106                // "https://eth.rpc.blxrbdn.com".to_string(),
107                "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}