pink_web3/api/
eth.rs

1//! `Eth` namespace
2
3use crate::prelude::*;
4use crate::types::SyncState;
5use crate::{
6    api::Namespace,
7    helpers::{self, CallFuture},
8    types::{
9        Address, Block, BlockHeader, BlockId, BlockNumber, Bytes, CallRequest, FeeHistory, Filter, Index, Log, Proof,
10        Transaction, TransactionId, TransactionReceipt, TransactionRequest, Work, H256, H520, H64, U256, U64,
11    },
12    Transport,
13};
14
15/// `Eth` namespace
16///
17/// # Example
18/// ```rust
19/// fn get_gas_price() {
20///     use pink_web3::api::{Eth, Namespace};
21///     use pink_web3::transports::pink_http::PinkHttp;
22///     let phttp = PinkHttp::new("http://localhost:3333");
23///     let eth = Eth::new(phttp);
24///     let result = eth.gas_price().resolve();
25///     assert!(result.is_ok());
26/// }
27#[derive(Debug, Clone)]
28pub struct Eth<T> {
29    transport: T,
30}
31
32impl<T: Transport> Namespace<T> for Eth<T> {
33    fn new(transport: T) -> Self
34    where
35        Self: Sized,
36    {
37        Eth { transport }
38    }
39
40    fn transport(&self) -> &T {
41        &self.transport
42    }
43}
44
45impl<T: Transport> Eth<T> {
46    /// Get list of available accounts.
47    pub fn accounts(&self) -> CallFuture<Vec<Address>, T::Out> {
48        CallFuture::new(self.transport.execute("eth_accounts", vec![]))
49    }
50
51    /// Get current block number
52    pub fn block_number(&self) -> CallFuture<U64, T::Out> {
53        CallFuture::new(self.transport.execute("eth_blockNumber", vec![]))
54    }
55
56    /// Call a constant method of contract without changing the state of the blockchain.
57    pub fn call(&self, req: CallRequest, block: Option<BlockId>) -> CallFuture<Bytes, T::Out> {
58        let req = helpers::serialize(&req);
59        let block = block.unwrap_or_else(|| BlockNumber::Latest.into());
60        let block = helpers::serialize(&block);
61
62        CallFuture::new(self.transport.execute("eth_call", vec![req, block]))
63    }
64
65    /// Get coinbase address
66    pub fn coinbase(&self) -> CallFuture<Address, T::Out> {
67        CallFuture::new(self.transport.execute("eth_coinbase", vec![]))
68    }
69
70    /// Compile LLL
71    pub fn compile_lll(&self, code: String) -> CallFuture<Bytes, T::Out> {
72        let code = helpers::serialize(&code);
73        CallFuture::new(self.transport.execute("eth_compileLLL", vec![code]))
74    }
75
76    /// Compile Solidity
77    pub fn compile_solidity(&self, code: String) -> CallFuture<Bytes, T::Out> {
78        let code = helpers::serialize(&code);
79        CallFuture::new(self.transport.execute("eth_compileSolidity", vec![code]))
80    }
81
82    /// Compile Serpent
83    pub fn compile_serpent(&self, code: String) -> CallFuture<Bytes, T::Out> {
84        let code = helpers::serialize(&code);
85        CallFuture::new(self.transport.execute("eth_compileSerpent", vec![code]))
86    }
87
88    /// Call a contract without changing the state of the blockchain to estimate gas usage.
89    pub fn estimate_gas(&self, req: CallRequest, block: Option<BlockNumber>) -> CallFuture<U256, T::Out> {
90        let req = helpers::serialize(&req);
91
92        let args = match block.as_ref() {
93            Some(block) => vec![req, helpers::serialize(block)],
94            None => vec![req],
95        };
96
97        CallFuture::new(self.transport.execute("eth_estimateGas", args))
98    }
99
100    /// Get current recommended gas price
101    pub fn gas_price(&self) -> CallFuture<U256, T::Out> {
102        CallFuture::new(self.transport.execute("eth_gasPrice", vec![]))
103    }
104
105    /// Returns a collection of historical gas information. This can be used for evaluating the max_fee_per_gas
106    /// and max_priority_fee_per_gas to send the future transactions.
107    pub fn fee_history(
108        &self,
109        block_count: U256,
110        newest_block: BlockNumber,
111        reward_percentiles: Option<Vec<f64>>,
112    ) -> CallFuture<FeeHistory, T::Out> {
113        let block_count = helpers::serialize(&block_count);
114        let newest_block = helpers::serialize(&newest_block);
115        let reward_percentiles = helpers::serialize(&reward_percentiles);
116
117        CallFuture::new(
118            self.transport
119                .execute("eth_feeHistory", vec![block_count, newest_block, reward_percentiles]),
120        )
121    }
122
123    /// Get balance of given address
124    pub fn balance(&self, address: Address, block: Option<BlockNumber>) -> CallFuture<U256, T::Out> {
125        let address = helpers::serialize(&address);
126        let block = block.unwrap_or(BlockNumber::Latest);
127        let block = helpers::serialize(&block);
128
129        CallFuture::new(self.transport.execute("eth_getBalance", vec![address, block]))
130    }
131
132    /// Get all logs matching a given filter object
133    pub fn logs(&self, filter: Filter) -> CallFuture<Vec<Log>, T::Out> {
134        let filter = helpers::serialize(&filter);
135        CallFuture::new(self.transport.execute("eth_getLogs", vec![filter]))
136    }
137
138    /// Get block details with transaction hashes.
139    pub fn block(&self, block: BlockId) -> CallFuture<Option<Block<H256>>, T::Out> {
140        let include_txs = helpers::serialize(&false);
141
142        let result = match block {
143            BlockId::Hash(hash) => {
144                let hash = helpers::serialize(&hash);
145                self.transport.execute("eth_getBlockByHash", vec![hash, include_txs])
146            }
147            BlockId::Number(num) => {
148                let num = helpers::serialize(&num);
149                self.transport.execute("eth_getBlockByNumber", vec![num, include_txs])
150            }
151        };
152
153        CallFuture::new(result)
154    }
155
156    /// Get block details with full transaction objects.
157    pub fn block_with_txs(&self, block: BlockId) -> CallFuture<Option<Block<Transaction>>, T::Out> {
158        let include_txs = helpers::serialize(&true);
159
160        let result = match block {
161            BlockId::Hash(hash) => {
162                let hash = helpers::serialize(&hash);
163                self.transport.execute("eth_getBlockByHash", vec![hash, include_txs])
164            }
165            BlockId::Number(num) => {
166                let num = helpers::serialize(&num);
167                self.transport.execute("eth_getBlockByNumber", vec![num, include_txs])
168            }
169        };
170
171        CallFuture::new(result)
172    }
173
174    /// Get number of transactions in block
175    pub fn block_transaction_count(&self, block: BlockId) -> CallFuture<Option<U256>, T::Out> {
176        let result = match block {
177            BlockId::Hash(hash) => {
178                let hash = helpers::serialize(&hash);
179                self.transport.execute("eth_getBlockTransactionCountByHash", vec![hash])
180            }
181            BlockId::Number(num) => {
182                let num = helpers::serialize(&num);
183                self.transport
184                    .execute("eth_getBlockTransactionCountByNumber", vec![num])
185            }
186        };
187
188        CallFuture::new(result)
189    }
190
191    /// Get code under given address
192    pub fn code(&self, address: Address, block: Option<BlockNumber>) -> CallFuture<Bytes, T::Out> {
193        let address = helpers::serialize(&address);
194        let block = block.unwrap_or(BlockNumber::Latest);
195        let block = helpers::serialize(&block);
196
197        CallFuture::new(self.transport.execute("eth_getCode", vec![address, block]))
198    }
199
200    /// Get supported compilers
201    pub fn compilers(&self) -> CallFuture<Vec<String>, T::Out> {
202        CallFuture::new(self.transport.execute("eth_getCompilers", vec![]))
203    }
204
205    /// Get chain id
206    pub fn chain_id(&self) -> CallFuture<U256, T::Out> {
207        CallFuture::new(self.transport.execute("eth_chainId", vec![]))
208    }
209
210    /// Get available user accounts. This method is only available in the browser. With MetaMask,
211    /// this will cause the popup that prompts the user to allow or deny access to their accounts
212    /// to your app.
213    pub fn request_accounts(&self) -> CallFuture<Vec<Address>, T::Out> {
214        CallFuture::new(self.transport.execute("eth_requestAccounts", vec![]))
215    }
216
217    /// Get storage entry
218    pub fn storage(&self, address: Address, idx: U256, block: Option<BlockNumber>) -> CallFuture<H256, T::Out> {
219        let address = helpers::serialize(&address);
220        let idx = helpers::serialize(&idx);
221        let block = block.unwrap_or(BlockNumber::Latest);
222        let block = helpers::serialize(&block);
223
224        CallFuture::new(self.transport.execute("eth_getStorageAt", vec![address, idx, block]))
225    }
226
227    /// Get nonce
228    pub fn transaction_count(&self, address: Address, block: Option<BlockNumber>) -> CallFuture<U256, T::Out> {
229        let address = helpers::serialize(&address);
230        let block = block.unwrap_or(BlockNumber::Latest);
231        let block = helpers::serialize(&block);
232
233        CallFuture::new(self.transport.execute("eth_getTransactionCount", vec![address, block]))
234    }
235
236    /// Get transaction
237    pub fn transaction(&self, id: TransactionId) -> CallFuture<Option<Transaction>, T::Out> {
238        let result = match id {
239            TransactionId::Hash(hash) => {
240                let hash = helpers::serialize(&hash);
241                self.transport.execute("eth_getTransactionByHash", vec![hash])
242            }
243            TransactionId::Block(BlockId::Hash(hash), index) => {
244                let hash = helpers::serialize(&hash);
245                let idx = helpers::serialize(&index);
246                self.transport
247                    .execute("eth_getTransactionByBlockHashAndIndex", vec![hash, idx])
248            }
249            TransactionId::Block(BlockId::Number(number), index) => {
250                let number = helpers::serialize(&number);
251                let idx = helpers::serialize(&index);
252                self.transport
253                    .execute("eth_getTransactionByBlockNumberAndIndex", vec![number, idx])
254            }
255        };
256
257        CallFuture::new(result)
258    }
259
260    /// Get transaction receipt
261    pub fn transaction_receipt(&self, hash: H256) -> CallFuture<Option<TransactionReceipt>, T::Out> {
262        let hash = helpers::serialize(&hash);
263
264        CallFuture::new(self.transport.execute("eth_getTransactionReceipt", vec![hash]))
265    }
266
267    /// Get uncle header by block ID and uncle index.
268    ///
269    /// This method is meant for TurboGeth compatiblity,
270    /// which is missing transaction hashes in the response.
271    pub fn uncle_header(&self, block: BlockId, index: Index) -> CallFuture<Option<BlockHeader>, T::Out> {
272        self.fetch_uncle(block, index)
273    }
274
275    /// Get uncle by block ID and uncle index -- transactions only has hashes.
276    pub fn uncle(&self, block: BlockId, index: Index) -> CallFuture<Option<Block<H256>>, T::Out> {
277        self.fetch_uncle(block, index)
278    }
279
280    fn fetch_uncle<X>(&self, block: BlockId, index: Index) -> CallFuture<Option<X>, T::Out> {
281        let index = helpers::serialize(&index);
282
283        let result = match block {
284            BlockId::Hash(hash) => {
285                let hash = helpers::serialize(&hash);
286                self.transport
287                    .execute("eth_getUncleByBlockHashAndIndex", vec![hash, index])
288            }
289            BlockId::Number(num) => {
290                let num = helpers::serialize(&num);
291                self.transport
292                    .execute("eth_getUncleByBlockNumberAndIndex", vec![num, index])
293            }
294        };
295
296        CallFuture::new(result)
297    }
298
299    /// Get uncle count in block
300    pub fn uncle_count(&self, block: BlockId) -> CallFuture<Option<U256>, T::Out> {
301        let result = match block {
302            BlockId::Hash(hash) => {
303                let hash = helpers::serialize(&hash);
304                self.transport.execute("eth_getUncleCountByBlockHash", vec![hash])
305            }
306            BlockId::Number(num) => {
307                let num = helpers::serialize(&num);
308                self.transport.execute("eth_getUncleCountByBlockNumber", vec![num])
309            }
310        };
311
312        CallFuture::new(result)
313    }
314
315    /// Get work package
316    pub fn work(&self) -> CallFuture<Work, T::Out> {
317        CallFuture::new(self.transport.execute("eth_getWork", vec![]))
318    }
319
320    /// Get hash rate
321    pub fn hashrate(&self) -> CallFuture<U256, T::Out> {
322        CallFuture::new(self.transport.execute("eth_hashrate", vec![]))
323    }
324
325    /// Get mining status
326    pub fn mining(&self) -> CallFuture<bool, T::Out> {
327        CallFuture::new(self.transport.execute("eth_mining", vec![]))
328    }
329
330    /// Start new block filter
331    pub fn new_block_filter(&self) -> CallFuture<U256, T::Out> {
332        CallFuture::new(self.transport.execute("eth_newBlockFilter", vec![]))
333    }
334
335    /// Start new pending transaction filter
336    pub fn new_pending_transaction_filter(&self) -> CallFuture<U256, T::Out> {
337        CallFuture::new(self.transport.execute("eth_newPendingTransactionFilter", vec![]))
338    }
339
340    /// Start new pending transaction filter
341    pub fn protocol_version(&self) -> CallFuture<String, T::Out> {
342        CallFuture::new(self.transport.execute("eth_protocolVersion", vec![]))
343    }
344
345    /// Sends a rlp-encoded signed transaction
346    pub fn send_raw_transaction(&self, rlp: Bytes) -> CallFuture<H256, T::Out> {
347        let rlp = helpers::serialize(&rlp);
348        CallFuture::new(self.transport.execute("eth_sendRawTransaction", vec![rlp]))
349    }
350
351    /// Sends a transaction transaction
352    pub fn send_transaction(&self, tx: TransactionRequest) -> CallFuture<H256, T::Out> {
353        let tx = helpers::serialize(&tx);
354        CallFuture::new(self.transport.execute("eth_sendTransaction", vec![tx]))
355    }
356
357    /// Signs a hash of given data
358    pub fn sign(&self, address: Address, data: Bytes) -> CallFuture<H520, T::Out> {
359        let address = helpers::serialize(&address);
360        let data = helpers::serialize(&data);
361        CallFuture::new(self.transport.execute("eth_sign", vec![address, data]))
362    }
363
364    /// Submit hashrate of external miner
365    pub fn submit_hashrate(&self, rate: U256, id: H256) -> CallFuture<bool, T::Out> {
366        let rate = helpers::serialize(&rate);
367        let id = helpers::serialize(&id);
368        CallFuture::new(self.transport.execute("eth_submitHashrate", vec![rate, id]))
369    }
370
371    /// Submit work of external miner
372    pub fn submit_work(&self, nonce: H64, pow_hash: H256, mix_hash: H256) -> CallFuture<bool, T::Out> {
373        let nonce = helpers::serialize(&nonce);
374        let pow_hash = helpers::serialize(&pow_hash);
375        let mix_hash = helpers::serialize(&mix_hash);
376        CallFuture::new(
377            self.transport
378                .execute("eth_submitWork", vec![nonce, pow_hash, mix_hash]),
379        )
380    }
381
382    /// Get syncing status
383    pub fn syncing(&self) -> CallFuture<SyncState, T::Out> {
384        CallFuture::new(self.transport.execute("eth_syncing", vec![]))
385    }
386
387    /// Returns the account- and storage-values of the specified account including the Merkle-proof.
388    pub fn proof(
389        &self,
390        address: Address,
391        keys: Vec<U256>,
392        block: Option<BlockNumber>,
393    ) -> CallFuture<Option<Proof>, T::Out> {
394        let add = helpers::serialize(&address);
395        let ks = helpers::serialize(&keys);
396        let block = block.unwrap_or(BlockNumber::Latest);
397        let blk = helpers::serialize(&block);
398        CallFuture::new(self.transport.execute("eth_getProof", vec![add, ks, blk]))
399    }
400}
401
402#[cfg(test)]
403mod tests {
404    use super::Eth;
405    use crate::{
406        api::Namespace,
407        rpc::Value,
408        types::{
409            Address, Block, BlockHeader, BlockId, BlockNumber, CallRequest, FeeHistory, FilterBuilder, Log, Proof,
410            SyncInfo, SyncState, Transaction, TransactionId, TransactionReceipt, TransactionRequest, Work, H256, H520,
411            H64, U256,
412        },
413    };
414    use hex_literal::hex;
415
416    // taken from RPC docs.
417    const EXAMPLE_BLOCK: &str = r#"{
418    "number": "0x1b4",
419    "hash": "0x0e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331",
420    "parentHash": "0x9646252be9520f6e71339a8df9c55e4d7619deeb018d2a3f2d21fc165dde5eb5",
421    "mixHash": "0x1010101010101010101010101010101010101010101010101010101010101010",
422    "nonce": "0x0000000000000000",
423    "sealFields": [
424      "0xe04d296d2460cfb8472af2c5fd05b5a214109c25688d3704aed5484f9a7792f2",
425      "0x0000000000000042"
426    ],
427    "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
428    "logsBloom":  "0x0e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331",
429    "transactionsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
430    "receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
431    "stateRoot": "0xd5855eb08b3387c0af375e9cdb6acfc05eb8f519e419b874b6ff2ffda7ed1dff",
432    "miner": "0x4e65fda2159562a496f9f3522f89122a3088497a",
433    "difficulty": "0x27f07",
434    "totalDifficulty": "0x27f07",
435    "extraData": "0x0000000000000000000000000000000000000000000000000000000000000000",
436    "size": "0x27f07",
437    "gasLimit": "0x9f759",
438    "minGasPrice": "0x9f759",
439    "gasUsed": "0x9f759",
440    "timestamp": "0x54e34e8e",
441    "transactions": [],
442    "uncles": []
443  }"#;
444
445    // response from RPC request {"jsonrpc":"2.0","method":"eth_getBlockByNumber","params":["pending", false],"id":1}.
446    const EXAMPLE_PENDING_BLOCK: &str = r#"{
447        "author": "0x0000000000000000000000000000000000000000",
448        "difficulty": "0x7eac2e8c440b2",
449        "extraData": "0xde830207028f5061726974792d457468657265756d86312e34312e30826c69",
450        "gasLimit": "0x974a0a",
451        "gasUsed": "0x44dd8",
452        "hash": null,
453        "logsBloom": null,
454        "miner": "0x0000000000000000000000000000000000000000",
455        "number": null,
456        "parentHash": "0xb4bb0904f19fd05ed527191f21ea27bd4f2d81903f77bfa2626631617001327c",
457        "receiptsRoot": "0x855c8c3b1c985b6bc5fd975a37b764095542b98a177588b887e197fcc5e0a0cd",
458        "sealFields": [],
459        "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
460        "size": "0x8b6",
461        "stateRoot": "0xfa035b07c349fb33768aebeb988639bd2ca7d5284170f29808ead43482a432c5",
462        "timestamp": "0x5ea09b90",
463        "totalDifficulty": "0x332b576efbc4023b848",
464        "transactions": [
465          "0x8e0d2bdfd47d7e68d5c86c30cbe4967ffcf920745a4b8177e1911fafd48e851a",
466          "0x2ac5f94e2d653d64fe89f7af2140600e4b7a59b3345700b5424bd4fae08212af",
467          "0x75d3e2d2ab548f4ca6e9f0c27306cedf28074ce60f39a6e78f56ea3f4a22e2d5",
468          "0xbcdb4f0829c7191a14e03dba0783fb015fa921d06b683e0ce8afb938745f89f7",
469          "0x75cede4d4cdb8402b242a1b1b39a23d537b2fee6a14783eaab67aa1e79bd71cd",
470          "0x50e406de9432a3589681b1eb3093ab6aba0895b5dc755588ca64735386591425",
471          "0x101e8b02d478dfab2266688b53668039107e98feacf085dcf9bfd24f390ec17d",
472          "0x22c75911be879047f4b0480fa07b2c2a77518571fb358d92b47c456d7065a76f",
473          "0x7715b514ba8ead48117b581f9ebcc61696a5b91f9111c55a7087e91474a58ec7",
474          "0x95dd913782cd4bfe5550a8f9102ba821f9a76691780c833d5130e311d62eb638"
475        ],
476        "transactionsRoot": "0x3acac83d7cc227b0c9a9ab1702964e70d7c8d1bfbf0f587b40e2a0aa0048aa44",
477        "uncles": []
478      }"#;
479
480    // taken from RPC docs, but with leading `00` added to `blockHash`
481    // and `transactionHash` fields because RPC docs currently show
482    // 31-byte values in both positions (must be 32 bytes).
483    const EXAMPLE_LOG: &str = r#"{
484    "logIndex": "0x1",
485    "blockNumber":"0x1b4",
486    "blockHash": "0x008216c5785ac562ff41e2dcfdf5785ac562ff41e2dcfdf829c5a142f1fccd7d",
487    "transactionHash":  "0x00df829c5a142f1fccd7d8216c5785ac562ff41e2dcfdf5785ac562ff41e2dcf",
488    "transactionIndex": "0x0",
489    "address": "0x16c5785ac562ff41e2dcfdf829c5a142f1fccd7d",
490    "data":"0x0000000000000000000000000000000000000000000000000000000000000000",
491    "topics": ["0x59ebeb90bc63057b6515673c3ecf9438e5058bca0f92585014eced636878c9a5"]
492  }"#;
493
494    // taken from RPC docs.
495    const EXAMPLE_TX: &str = r#"{
496    "hash": "0xc6ef2fc5426d6ad6fd9e2a26abeab0aa2411b7ab17f30a99d3cb96aed1d1055b",
497    "nonce": "0x0",
498    "blockHash": "0xbeab0aa2411b7ab17f30a99d3cb9c6ef2fc5426d6ad6fd9e2a26a6aed1d1055b",
499    "blockNumber": "0x15df",
500    "transactionIndex": "0x1",
501    "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
502    "to":   "0x85dd43d8a49eeb85d32cf465507dd71d507100c1",
503    "value": "0x7f110",
504    "gas": "0x7f110",
505    "gasPrice": "0x09184e72a000",
506    "input": "0x603880600c6000396000f300603880600c6000396000f3603880600c6000396000f360"
507  }"#;
508
509    // taken from RPC docs.
510    // https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_gettransactionreceipt
511    const EXAMPLE_RECEIPT: &str = r#"{
512    "transactionHash": "0xb903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238",
513    "transactionIndex": "0x1",
514    "from": "0xa7d9ddbe1f17865597fbd27ec712455208b6b76d",
515    "blockNumber": "0xb",
516    "blockHash": "0xc6ef2fc5426d6ad6fd9e2a26abeab0aa2411b7ab17f30a99d3cb96aed1d1055b",
517    "cumulativeGasUsed": "0x33bc",
518    "gasUsed": "0x4dc",
519    "contractAddress": "0xb60e8dd61c5d32be8058bb8eb970870f07233155",
520    "logsBloom":  "0x0e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331",
521    "logs": [],
522    "status": "0x1",
523    "effectiveGasPrice": "0x100"
524  }"#;
525
526    const EXAMPLE_FEE_HISTORY: &str = r#"{
527      "baseFeePerGas": [
528          "0x15f794d04b",
529          "0x1730fe199f",
530          "0x176212b802",
531          "0x165bce08cb",
532          "0x16c6235c9d",
533          "0x1539ff7ccd"
534      ],
535      "gasUsedRatio": [
536          0.722926465013414,
537          0.53306761204479,
538          0.32474768127264964,
539          0.574309529134573,
540          0.2282121795900929
541      ],
542      "oldestBlock": "0xcd1df9"
543  }"#;
544
545    ///taken from RPC docs
546    /// https://eips.ethereum.org/EIPS/eip-1186
547    const EXAMPLE_PROOF: &str = r#"{
548    "address": "0x1234567890123456789012345678901234567890",
549    "accountProof": [
550      "0xf90211a0c3b7e484f7e3258823aee7fada1378f1667757c4a1c3bde259adb4857b481726a0d0f709bf8bd61dd176b876f250638b03e65d367aa0e13f01a122e328e6215603a0d3ca85d7f5f63a6b01d818369c656639087aed983f63906b2eba99bf71255ef3a0d168cf7cc0253337d59fa3ed11bde10744a152fcb644c77bd8babbddf878714da02d4e42471dbdbd96eb3b115877d6b6202450cebee0d96d346d650ebd73eaa96ea07c2a9fbbec5c243327961f1a5ed3ce410dd0b255e4db934e68c2df424ede2a67a00a4ae2f21873ad931752edd3b3cfeffcedf15bb070525450bde50bdce6a78faca023e61f772deb072c430adb4316b65a66d8d3cef73dae7d515938e37c0db5c2f0a0d078fc1c446572cfb172888172287dd243ec085eb54594034926c99a3051230da04182e559c0f1bd6533e52fd995760da41701d37e8e21eab59e63db07e836a80fa0968213088b84869050884d5788ae5669d7d35ac0ddbdab71cfbd241da72df9e0a0bdc9921220e3bb9b4744c1764be9a9d7c22e5007387367285dc8f7495ebc0f21a01bf9c2458bb0c5c8f477734e347fb1f940a493ff0b533fef3c0bce20a5a69628a0626a993a9f6cb9febf4ca826b5731cc2ed85066c253cea94511d28a139445699a032a58d4abc48ee971d839915b0848d26af588b23138df7b072575d2dce3cb829a01b8af404f9cc8dc1590fa6f4ed79ea93a65d1aa152854f510efaceba183c8abb80",
551      "0xf90211a0e1557a91967828ea9eaf9b4c25bb0f079857340c54fa01acf24977f5d4d12ad4a0805a5d2f0d1b8c33c6415d2df4f4d812f4abe6b2d0f9f12196d31bbe5d76e47da0882d8a3a3493a0d76c907b0c2a4c6e3f26ca67a6a37aba6105c428d98ec2f67ea0b8bb9bd971ca68a49135390b03c11e2f7c352c146be2e3f8fff2a311dda5ddf1a01ae7bbab4493b34935640f40c74d7d72079742157ad5040a23f70c64f5153ca7a0574403fc7faa3a262eae412a707a74785a1159027e5b8de9990e1e82278e9691a01edc831a2e842b4d55b009c9831774fd6f17acfdee99f097c4fb20be583911f6a044569f910709fedb1ef83ef29b508e24def8eb9cc876dac0f6fa4f5f791cd719a0ebfdbfe9538bd72dbbeb56024982502950c69d9beb5d0d6d985917120e77e0d5a02c6fdf33ef98ca85a94ac9ed1319832ca5e2b344c1b8d921e77eda35480ba9d0a0c6b20bfc93fa2167bd43fe14cb648eb53c66fd56a3c95d0bd4c0442e86f7e686a01bed6e7e4a83c9aed9b39c49bb29782d63064d5ac425734dbfe4f0367eb29d07a0dede0f30aa107e1383be0a3ac31e0083213c27e1b11912e45e974257fa1d9915a089673bee5c46e4ee86b7e68115bc34b6eb9387e7c0d7300af1c502a8ef14fdf8a07e8e4d1729077f052c82cbd6de80966666514c53072945b53afd55c40b4f3a47a024caac94dd8acbf9c88a149b728115651faebd379f92e0ecc126fb136d5289df80",
552      "0xf89180a057d3fa3f15f8c0e639b1c3ac64e623348f39c5663587003279dcd5cf261489a58080a0b65511b496c46cca3eff9484a1a1961bcf7ae59237da1ead3675eea9b3f8469fa05114cfcd51e3a3735c556d68ac28f83dd28aa1a833425090521f0b9217c2114e8080a0adaeaae85d671adf3b559aaee605156f0c4511f9aa474cbcf6a594b219d216a88080808080808080"
553    ],
554    "balance": "0x2166f8062324c623840",
555    "codeHash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470",
556    "nonce": "0x6c",
557    "storageHash": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
558    "storageProof": [
559      {
560        "key": "0x0000000000000000000000000000000000000000000000000000000000000000",
561        "value": "0x0",
562        "proof": []
563      },
564      {
565        "key": "0x0000000000000000000000000000000000000000000000000000000000000001",
566        "value": "0x0",
567        "proof": []
568      }
569    ]
570  }"#;
571
572    rpc_test! (
573      Eth:accounts => "eth_accounts";
574      Value::Array(vec![Value::String("0x0000000000000000000000000000000000000123".into())]) => vec![Address::from_low_u64_be(0x123)]
575    );
576
577    rpc_test! (
578      Eth:block_number => "eth_blockNumber";
579      Value::String("0x123".into()) => 0x123
580    );
581
582    rpc_test! (
583      Eth:call, CallRequest {
584        from: None, to: Some(Address::from_low_u64_be(0x123)),
585        gas: None, gas_price: None,
586        value: Some(0x1.into()), data: None,
587        transaction_type: None, access_list: None,
588        max_fee_per_gas: None, max_priority_fee_per_gas: None,
589      }, None
590      =>
591      "eth_call", vec![r#"{"to":"0x0000000000000000000000000000000000000123","value":"0x1"}"#, r#""latest""#];
592      Value::String("0x010203".into()) => hex!("010203")
593    );
594
595    rpc_test! (
596      Eth:coinbase => "eth_coinbase";
597      Value::String("0x0000000000000000000000000000000000000123".into()) => Address::from_low_u64_be(0x123)
598    );
599
600    rpc_test! (
601      Eth:compile_lll, "code" => "eth_compileLLL", vec![r#""code""#];
602      Value::String("0x0123".into()) => hex!("0123")
603    );
604
605    rpc_test! (
606      Eth:compile_solidity, "code" => "eth_compileSolidity", vec![r#""code""#];
607      Value::String("0x0123".into()) => hex!("0123")
608    );
609
610    rpc_test! (
611      Eth:compile_serpent, "code" => "eth_compileSerpent", vec![r#""code""#];
612      Value::String("0x0123".into()) => hex!("0123")
613    );
614
615    rpc_test! (
616      Eth:estimate_gas, CallRequest {
617        from: None, to: Some(Address::from_low_u64_be(0x123)),
618        gas: None, gas_price: None,
619        value: Some(0x1.into()), data: None,
620        transaction_type: None, access_list: None,
621        max_fee_per_gas: None, max_priority_fee_per_gas: None,
622      }, None
623      =>
624      "eth_estimateGas", vec![r#"{"to":"0x0000000000000000000000000000000000000123","value":"0x1"}"#];
625      Value::String("0x123".into()) => 0x123
626    );
627
628    rpc_test! (
629      Eth:estimate_gas:optional_to_addr, CallRequest {
630        from: None, to: None,
631        gas: None, gas_price: None,
632        value: Some(0x1.into()), data: None,
633        transaction_type: None, access_list: None,
634        max_fee_per_gas: None, max_priority_fee_per_gas: None,
635      }, None
636      =>
637      "eth_estimateGas", vec![r#"{"value":"0x1"}"#];
638      Value::String("0x5555".into()) => 0x5555
639    );
640
641    rpc_test! (
642      Eth:estimate_gas:for_block, CallRequest {
643        from: None, to: Some(Address::from_low_u64_be(0x123)),
644        gas: None, gas_price: None,
645        value: Some(0x1.into()), data: None,
646        transaction_type: None, access_list: None,
647        max_fee_per_gas: None, max_priority_fee_per_gas: None,
648      }, Some(0x123.into())
649      =>
650      "eth_estimateGas", vec![r#"{"to":"0x0000000000000000000000000000000000000123","value":"0x1"}"#, r#""0x123""#];
651      Value::String("0x123".into()) => 0x123
652    );
653
654    rpc_test! (
655      Eth:gas_price => "eth_gasPrice";
656      Value::String("0x123".into()) => 0x123
657    );
658
659    rpc_test! (
660      Eth:fee_history, 0x3, BlockNumber::Latest, None => "eth_feeHistory", vec![r#""0x3""#, r#""latest""#, r#"null"#];
661      ::serde_json::from_str(EXAMPLE_FEE_HISTORY).unwrap()
662      => ::serde_json::from_str::<FeeHistory>(EXAMPLE_FEE_HISTORY).unwrap()
663    );
664
665    rpc_test! (
666      Eth:balance, Address::from_low_u64_be(0x123), None
667      =>
668      "eth_getBalance", vec![r#""0x0000000000000000000000000000000000000123""#, r#""latest""#];
669      Value::String("0x123".into()) => 0x123
670    );
671
672    rpc_test! (
673      Eth:logs, FilterBuilder::default().build() => "eth_getLogs", vec!["{}"];
674      Value::Array(vec![::serde_json::from_str(EXAMPLE_LOG).unwrap()])
675      => vec![::serde_json::from_str::<Log>(EXAMPLE_LOG).unwrap()]
676    );
677
678    rpc_test! (
679      Eth:block:block_by_hash, BlockId::Hash(H256::from_low_u64_be(0x123))
680      =>
681      "eth_getBlockByHash", vec![r#""0x0000000000000000000000000000000000000000000000000000000000000123""#, r#"false"#];
682      ::serde_json::from_str(EXAMPLE_BLOCK).unwrap()
683      => Some(::serde_json::from_str::<Block<H256>>(EXAMPLE_BLOCK).unwrap())
684    );
685
686    rpc_test! (
687      Eth:block, BlockNumber::Pending
688      =>
689      "eth_getBlockByNumber", vec![r#""pending""#, r#"false"#];
690      ::serde_json::from_str(EXAMPLE_PENDING_BLOCK).unwrap()
691      => Some(::serde_json::from_str::<Block<H256>>(EXAMPLE_PENDING_BLOCK).unwrap())
692    );
693
694    rpc_test! (
695      Eth:block_with_txs, BlockNumber::Pending
696      =>
697      "eth_getBlockByNumber", vec![r#""pending""#, r#"true"#];
698      ::serde_json::from_str(EXAMPLE_BLOCK).unwrap()
699      => Some(::serde_json::from_str::<Block<Transaction>>(EXAMPLE_BLOCK).unwrap())
700    );
701
702    rpc_test! (
703      Eth:block_transaction_count:block_tx_count_by_hash, BlockId::Hash(H256::from_low_u64_be(0x123))
704      =>
705      "eth_getBlockTransactionCountByHash", vec![r#""0x0000000000000000000000000000000000000000000000000000000000000123""#];
706      Value::String("0x123".into()) => Some(0x123.into())
707    );
708
709    rpc_test! (
710      Eth:block_transaction_count, BlockNumber::Pending
711      =>
712      "eth_getBlockTransactionCountByNumber", vec![r#""pending""#];
713      Value::Null => None
714    );
715
716    rpc_test! (
717      Eth:code, H256::from_low_u64_be(0x123), Some(BlockNumber::Pending)
718      =>
719      "eth_getCode", vec![r#""0x0000000000000000000000000000000000000123""#, r#""pending""#];
720      Value::String("0x0123".into()) => hex!("0123")
721    );
722
723    rpc_test! (
724      Eth:compilers => "eth_getCompilers";
725      Value::Array(vec![]) => vec![]
726    );
727
728    rpc_test! (
729      Eth:chain_id => "eth_chainId";
730      Value::String("0x123".into()) => 0x123
731    );
732
733    rpc_test! (
734      Eth:storage, Address::from_low_u64_be(0x123), 0x456, None
735      =>
736      "eth_getStorageAt", vec![
737        r#""0x0000000000000000000000000000000000000123""#,
738        r#""0x456""#,
739        r#""latest""#
740      ];
741      Value::String("0x0000000000000000000000000000000000000000000000000000000000000123".into()) => H256::from_low_u64_be(0x123)
742    );
743
744    rpc_test! (
745      Eth:transaction_count, Address::from_low_u64_be(0x123), None
746      =>
747      "eth_getTransactionCount", vec![r#""0x0000000000000000000000000000000000000123""#, r#""latest""#];
748      Value::String("0x123".into()) => 0x123
749    );
750
751    rpc_test! (
752      Eth:transaction:tx_by_hash, TransactionId::Hash(H256::from_low_u64_be(0x123))
753      =>
754      "eth_getTransactionByHash", vec![r#""0x0000000000000000000000000000000000000000000000000000000000000123""#];
755      ::serde_json::from_str(EXAMPLE_TX).unwrap()
756      => Some(::serde_json::from_str::<Transaction>(EXAMPLE_TX).unwrap())
757    );
758
759    rpc_test! (
760      Eth:transaction:tx_by_block_hash_and_index, TransactionId::Block(
761        BlockId::Hash(H256::from_low_u64_be(0x123)),
762        5.into()
763      )
764      =>
765      "eth_getTransactionByBlockHashAndIndex", vec![r#""0x0000000000000000000000000000000000000000000000000000000000000123""#, r#""0x5""#];
766      Value::Null => None
767    );
768
769    rpc_test! (
770      Eth:transaction:tx_by_block_no_and_index, TransactionId::Block(
771        BlockNumber::Pending.into(),
772        5.into()
773      )
774      =>
775      "eth_getTransactionByBlockNumberAndIndex", vec![r#""pending""#, r#""0x5""#];
776      ::serde_json::from_str(EXAMPLE_TX).unwrap()
777      => Some(::serde_json::from_str::<Transaction>(EXAMPLE_TX).unwrap())
778    );
779
780    rpc_test! (
781      Eth:transaction_receipt, H256::from_low_u64_be(0x123)
782      =>
783      "eth_getTransactionReceipt", vec![r#""0x0000000000000000000000000000000000000000000000000000000000000123""#];
784      ::serde_json::from_str(EXAMPLE_RECEIPT).unwrap()
785      => Some(::serde_json::from_str::<TransactionReceipt>(EXAMPLE_RECEIPT).unwrap())
786    );
787
788    rpc_test! (
789      Eth:uncle:uncle_by_hash, BlockId::Hash(H256::from_low_u64_be(0x123)), 5
790      =>
791      "eth_getUncleByBlockHashAndIndex", vec![r#""0x0000000000000000000000000000000000000000000000000000000000000123""#, r#""0x5""#];
792      ::serde_json::from_str(EXAMPLE_BLOCK).unwrap()
793      => Some(::serde_json::from_str::<Block<H256>>(EXAMPLE_BLOCK).unwrap())
794    );
795
796    rpc_test! (
797      Eth:uncle_header:uncle_header_by_hash, BlockId::Hash(H256::from_low_u64_be(0x123)), 5
798      =>
799      "eth_getUncleByBlockHashAndIndex", vec![r#""0x0000000000000000000000000000000000000000000000000000000000000123""#, r#""0x5""#];
800      ::serde_json::from_str(EXAMPLE_BLOCK).unwrap()
801      => Some(::serde_json::from_str::<BlockHeader>(EXAMPLE_BLOCK).unwrap())
802    );
803
804    rpc_test! (
805      Eth:uncle:uncle_by_no, BlockNumber::Earliest, 5
806      =>
807      "eth_getUncleByBlockNumberAndIndex", vec![r#""earliest""#, r#""0x5""#];
808      Value::Null => None
809    );
810
811    rpc_test! (
812      Eth:uncle_count:uncle_count_by_hash, BlockId::Hash(H256::from_low_u64_be(0x123))
813      =>
814      "eth_getUncleCountByBlockHash", vec![r#""0x0000000000000000000000000000000000000000000000000000000000000123""#];
815      Value::String("0x123".into())=> Some(0x123.into())
816    );
817
818    rpc_test! (
819      Eth:uncle_count:uncle_count_by_no, BlockNumber::Earliest
820      =>
821      "eth_getUncleCountByBlockNumber", vec![r#""earliest""#];
822      Value::Null => None
823    );
824
825    rpc_test! (
826      Eth:work:work_3 => "eth_getWork";
827      Value::Array(vec![
828        Value::String("0x0000000000000000000000000000000000000000000000000000000000000123".into()),
829        Value::String("0x0000000000000000000000000000000000000000000000000000000000000456".into()),
830        Value::String("0x0000000000000000000000000000000000000000000000000000000000000789".into()),
831      ]) => Work {
832        pow_hash: H256::from_low_u64_be(0x123),
833        seed_hash: H256::from_low_u64_be(0x456),
834        target: H256::from_low_u64_be(0x789),
835        number: None,
836      }
837    );
838
839    rpc_test! (
840      Eth:work:work_4 => "eth_getWork";
841      Value::Array(vec![
842        Value::String("0x0000000000000000000000000000000000000000000000000000000000000123".into()),
843        Value::String("0x0000000000000000000000000000000000000000000000000000000000000456".into()),
844        Value::String("0x0000000000000000000000000000000000000000000000000000000000000789".into()),
845        Value::Number(5.into()),
846      ]) => Work {
847        pow_hash: H256::from_low_u64_be(0x123),
848        seed_hash: H256::from_low_u64_be(0x456),
849        target: H256::from_low_u64_be(0x789),
850        number: Some(5),
851      }
852    );
853
854    rpc_test! (
855      Eth:hashrate => "eth_hashrate";
856      Value::String("0x123".into()) => 0x123
857    );
858
859    rpc_test! (
860      Eth:mining => "eth_mining";
861      Value::Bool(true) => true
862    );
863
864    rpc_test! (
865      Eth:new_block_filter => "eth_newBlockFilter";
866      Value::String("0x123".into()) => 0x123
867    );
868    rpc_test! (
869      Eth:new_pending_transaction_filter => "eth_newPendingTransactionFilter";
870      Value::String("0x123".into()) => 0x123
871    );
872
873    rpc_test! (
874      Eth:protocol_version => "eth_protocolVersion";
875      Value::String("0x123".into()) => "0x123"
876    );
877
878    rpc_test! (
879      Eth:send_raw_transaction, hex!("01020304")
880      =>
881      "eth_sendRawTransaction", vec![r#""0x01020304""#];
882      Value::String("0x0000000000000000000000000000000000000000000000000000000000000123".into()) => H256::from_low_u64_be(0x123)
883    );
884
885    rpc_test! (
886      Eth:send_transaction, TransactionRequest {
887        from: Address::from_low_u64_be(0x123), to: Some(Address::from_low_u64_be(0x123)),
888        gas: None, gas_price: Some(0x1.into()),
889        value: Some(0x1.into()), data: None,
890        nonce: None, condition: None,
891        transaction_type: None, access_list: None,
892        max_fee_per_gas: None, max_priority_fee_per_gas: None,
893      }
894      =>
895      "eth_sendTransaction", vec![r#"{"from":"0x0000000000000000000000000000000000000123","to":"0x0000000000000000000000000000000000000123","gasPrice":"0x1","value":"0x1"}"#];
896      Value::String("0x0000000000000000000000000000000000000000000000000000000000000123".into()) => H256::from_low_u64_be(0x123)
897    );
898
899    rpc_test! (
900      Eth:sign, H256::from_low_u64_be(0x123), hex!("01020304")
901      =>
902      "eth_sign", vec![r#""0x0000000000000000000000000000000000000123""#, r#""0x01020304""#];
903      Value::String("0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000123".into()) => H520::from_low_u64_be(0x123)
904    );
905
906    rpc_test! (
907      Eth:submit_hashrate, 0x123, H256::from_low_u64_be(0x456)
908      =>
909      "eth_submitHashrate", vec![r#""0x123""#, r#""0x0000000000000000000000000000000000000000000000000000000000000456""#];
910      Value::Bool(true) => true
911    );
912
913    rpc_test! (
914      Eth:submit_work, H64::from_low_u64_be(0x123), H256::from_low_u64_be(0x456), H256::from_low_u64_be(0x789)
915      =>
916      "eth_submitWork", vec![r#""0x0000000000000123""#, r#""0x0000000000000000000000000000000000000000000000000000000000000456""#, r#""0x0000000000000000000000000000000000000000000000000000000000000789""#];
917      Value::Bool(true) => true
918    );
919
920    rpc_test! (
921      Eth:syncing:syncing => "eth_syncing";
922      serde_json::json!({"startingBlock": "0x384","currentBlock": "0x386","highestBlock": "0x454"}) => SyncState::Syncing(SyncInfo { starting_block: 0x384.into(), current_block: 0x386.into(), highest_block: 0x454.into()})
923    );
924
925    rpc_test! {
926      Eth:syncing:not_syncing => "eth_syncing";
927      Value::Bool(false) => SyncState::NotSyncing
928    }
929
930    rpc_test! {
931        Eth:proof, Address::from_low_u64_be(0x123), [U256::from(0x123)], BlockNumber::Latest
932        =>
933        "eth_getProof", vec![r#""0x0000000000000000000000000000000000000123""#, r#"["0x123"]"#, r#""latest""#];
934      ::serde_json::from_str(EXAMPLE_PROOF).unwrap()
935      => Some(::serde_json::from_str::<Proof>(EXAMPLE_PROOF).unwrap())
936    }
937}