From ff66008cbe0badffda50e0f283f06339828a8781 Mon Sep 17 00:00:00 2001 From: Jacob <93085583+cobward@users.noreply.github.com> Date: Tue, 23 Aug 2022 17:17:00 +0100 Subject: [PATCH] Fix 'get_transactions' response. (#1632) * Fix 'get_transactions' response. * Add some explanation to GenesisOption. * One-line-ifying * Update changelog --- CHANGELOG.md | 1 + ethers-core/src/types/mod.rs | 2 +- ethers-etherscan/src/account.rs | 116 ++++++++++++++++++++++++++------ 3 files changed, 99 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 49a7e13f..75cbb6a8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -82,6 +82,7 @@ - Fix handling of Websocket connection errors [#1287](https://github.com/gakonst/ethers-rs/pull/1287) - Add Arithmetic Shift Right operation for I256 [#1323](https://github.com/gakonst/ethers-rs/issues/1323) - [#1535](https://github.com/gakonst/ethers-rs/pull/1535) Add support to Aurora and Aurora testnet networks. +- [#1632](https://github.com/gakonst/ethers-rs/pull/1632) Re-export `H32` from `ethabi`. ## ethers-contract-abigen diff --git a/ethers-core/src/types/mod.rs b/ethers-core/src/types/mod.rs index c03e9a7a..9c10f25f 100644 --- a/ethers-core/src/types/mod.rs +++ b/ethers-core/src/types/mod.rs @@ -5,7 +5,7 @@ pub type Selector = [u8; 4]; /// A transaction Hash pub use ethabi::ethereum_types::H256 as TxHash; -pub use ethabi::ethereum_types::{Address, Bloom, H160, H256, H512, H64, U128, U256, U64}; +pub use ethabi::ethereum_types::{Address, Bloom, H160, H256, H32, H512, H64, U128, U256, U64}; pub mod transaction; pub use transaction::{ diff --git a/ethers-etherscan/src/account.rs b/ethers-etherscan/src/account.rs index 8893a2c1..9ba5caa3 100644 --- a/ethers-etherscan/src/account.rs +++ b/ethers-etherscan/src/account.rs @@ -1,7 +1,7 @@ use crate::{Client, EtherscanError, Query, Response, Result}; use ethers_core::{ abi::Address, - types::{serde_helpers::*, BlockNumber, Bytes, H256, U256}, + types::{serde_helpers::*, BlockNumber, Bytes, H256, H32, U256}, }; use serde::{Deserialize, Serialize}; use std::{ @@ -17,7 +17,7 @@ pub struct AccountBalance { pub balance: String, } -mod jsonstring { +mod genesis_string { use super::*; use serde::{ de::{DeserializeOwned, Error as _}, @@ -52,9 +52,9 @@ mod jsonstring { { let json = Cow::<'de, str>::deserialize(deserializer)?; if !json.is_empty() && !json.starts_with("GENESIS") { - let value = - serde_json::from_str(&format!("\"{}\"", &json)).map_err(D::Error::custom)?; - Ok(GenesisOption::Some(value)) + serde_json::from_str(&format!("\"{}\"", &json)) + .map(GenesisOption::Some) + .map_err(D::Error::custom) } else if json.starts_with("GENESIS") { Ok(GenesisOption::Genesis) } else { @@ -63,7 +63,82 @@ mod jsonstring { } } -/// Possible values for some field responses +mod json_string { + use super::*; + use serde::{ + de::{DeserializeOwned, Error as _}, + ser::Error as _, + Deserializer, Serializer, + }; + + pub fn serialize(value: &Option, serializer: S) -> std::result::Result + where + T: Serialize, + S: Serializer, + { + let json = match value { + Option::None => Cow::from(""), + Option::Some(value) => serde_json::to_string(value).map_err(S::Error::custom)?.into(), + }; + serializer.serialize_str(&json) + } + + pub fn deserialize<'de, T, D>(deserializer: D) -> std::result::Result, D::Error> + where + T: DeserializeOwned, + D: Deserializer<'de>, + { + let json = Cow::<'de, str>::deserialize(deserializer)?; + if json.is_empty() { + Ok(Option::None) + } else { + serde_json::from_str(&format!("\"{}\"", &json)) + .map(Option::Some) + .map_err(D::Error::custom) + } + } +} + +mod hex_string { + use super::*; + use serde::{ + de::{DeserializeOwned, Error as _}, + ser::Error as _, + Deserializer, Serializer, + }; + + pub fn serialize(value: &Option, serializer: S) -> std::result::Result + where + T: Serialize, + S: Serializer, + { + let json = match value { + Option::None => Cow::from("0x"), + Option::Some(value) => serde_json::to_string(value).map_err(S::Error::custom)?.into(), + }; + serializer.serialize_str(&json) + } + + pub fn deserialize<'de, T, D>(deserializer: D) -> std::result::Result, D::Error> + where + T: DeserializeOwned, + D: Deserializer<'de>, + { + let json = Cow::<'de, str>::deserialize(deserializer)?; + if json.is_empty() || json == "0x" { + Ok(Option::None) + } else { + serde_json::from_str(&format!("\"{}\"", &json)) + .map(Option::Some) + .map_err(D::Error::custom) + } + } +} + +/// Possible values for some field responses. +/// +/// Transactions from the Genesis block may contain fields that do not conform to the expected +/// types. #[derive(Debug)] pub enum GenesisOption { None, @@ -101,15 +176,15 @@ pub struct NormalTransaction { #[serde(deserialize_with = "deserialize_stringified_block_number")] pub block_number: BlockNumber, pub time_stamp: String, - #[serde(with = "jsonstring")] + #[serde(with = "genesis_string")] pub hash: GenesisOption, - #[serde(with = "jsonstring")] - pub nonce: GenesisOption, - #[serde(with = "jsonstring")] - pub block_hash: GenesisOption, + #[serde(with = "json_string")] + pub nonce: Option, + #[serde(with = "json_string")] + pub block_hash: Option, #[serde(deserialize_with = "deserialize_stringified_u64_opt")] pub transaction_index: Option, - #[serde(with = "jsonstring")] + #[serde(with = "genesis_string")] pub from: GenesisOption
, pub to: Option
, #[serde(deserialize_with = "deserialize_stringified_numeric")] @@ -120,16 +195,19 @@ pub struct NormalTransaction { pub gas_price: Option, #[serde(rename = "txreceipt_status")] pub tx_receipt_status: String, - #[serde(with = "jsonstring")] - pub input: GenesisOption, - #[serde(with = "jsonstring")] - pub contract_address: GenesisOption
, + pub input: Bytes, + #[serde(with = "json_string")] + pub contract_address: Option
, #[serde(deserialize_with = "deserialize_stringified_numeric")] pub gas_used: U256, #[serde(deserialize_with = "deserialize_stringified_numeric")] pub cumulative_gas_used: U256, #[serde(deserialize_with = "deserialize_stringified_u64")] pub confirmations: u64, + #[serde(with = "hex_string")] + pub method_id: Option, + #[serde(with = "json_string")] + pub function_name: Option, } /// The raw response from the internal transaction list API endpoint @@ -141,13 +219,13 @@ pub struct InternalTransaction { pub time_stamp: String, pub hash: H256, pub from: Address, - #[serde(with = "jsonstring")] + #[serde(with = "genesis_string")] pub to: GenesisOption
, #[serde(deserialize_with = "deserialize_stringified_numeric")] pub value: U256, - #[serde(with = "jsonstring")] + #[serde(with = "genesis_string")] pub contract_address: GenesisOption
, - #[serde(with = "jsonstring")] + #[serde(with = "genesis_string")] pub input: GenesisOption, #[serde(rename = "type")] pub result_type: String,