MBlockerge branch 'master' of github.com:gakonst/ethers-rs
This commit is contained in:
commit
1ef7735e3d
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
### Unreleased
|
### Unreleased
|
||||||
|
|
||||||
|
- Add `evm.deployedBytecode.immutableReferences` output selector [#1523](https://github.com/gakonst/ethers-rs/pull/1523)
|
||||||
- Added `get_erc1155_token_transfer_events` function for etherscan client [#1503](https://github.com/gakonst/ethers-rs/pull/1503)
|
- Added `get_erc1155_token_transfer_events` function for etherscan client [#1503](https://github.com/gakonst/ethers-rs/pull/1503)
|
||||||
- Add support for Geth `debug_traceTransaction` [#1469](https://github.com/gakonst/ethers-rs/pull/1469)
|
- Add support for Geth `debug_traceTransaction` [#1469](https://github.com/gakonst/ethers-rs/pull/1469)
|
||||||
- Use correct, new transaction type for `typool_content` RPC endpoint [#1501](https://github.com/gakonst/ethers-rs/pull/1501)
|
- Use correct, new transaction type for `typool_content` RPC endpoint [#1501](https://github.com/gakonst/ethers-rs/pull/1501)
|
||||||
|
|
|
@ -77,7 +77,7 @@ impl Context {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl #ethers_contract::EthLogDecode for #enum_name {
|
impl #ethers_contract::EthLogDecode for #enum_name {
|
||||||
fn decode_log(log: &#ethers_core::abi::RawLog) -> Result<Self, #ethers_core::abi::Error>
|
fn decode_log(log: &#ethers_core::abi::RawLog) -> ::std::result::Result<Self, #ethers_core::abi::Error>
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
|
|
|
@ -91,7 +91,7 @@ impl Context {
|
||||||
/// let msg = greeter_contract.greet().call().await.unwrap();
|
/// let msg = greeter_contract.greet().call().await.unwrap();
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn deploy<T: #ethers_core::abi::Tokenize >(client: ::std::sync::Arc<M>, constructor_args: T) -> Result<#ethers_contract::builders::ContractDeployer<M, Self>, #ethers_contract::ContractError<M>> {
|
pub fn deploy<T: #ethers_core::abi::Tokenize >(client: ::std::sync::Arc<M>, constructor_args: T) -> ::std::result::Result<#ethers_contract::builders::ContractDeployer<M, Self>, #ethers_contract::ContractError<M>> {
|
||||||
let factory = #ethers_contract::ContractFactory::new(#get_abi, #get_bytecode, client);
|
let factory = #ethers_contract::ContractFactory::new(#get_abi, #get_bytecode, client);
|
||||||
let deployer = factory.deploy(constructor_args)?;
|
let deployer = factory.deploy(constructor_args)?;
|
||||||
let deployer = #ethers_contract::ContractDeployer::new(deployer);
|
let deployer = #ethers_contract::ContractDeployer::new(deployer);
|
||||||
|
@ -219,7 +219,7 @@ impl Context {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl #ethers_core::abi::AbiDecode for #enum_name {
|
impl #ethers_core::abi::AbiDecode for #enum_name {
|
||||||
fn decode(data: impl AsRef<[u8]>) -> Result<Self, #ethers_core::abi::AbiError> {
|
fn decode(data: impl AsRef<[u8]>) -> ::std::result::Result<Self, #ethers_core::abi::AbiError> {
|
||||||
#(
|
#(
|
||||||
if let Ok(decoded) = <#struct_names as #ethers_core::abi::AbiDecode>::decode(data.as_ref()) {
|
if let Ok(decoded) = <#struct_names as #ethers_core::abi::AbiDecode>::decode(data.as_ref()) {
|
||||||
return Ok(#enum_name::#variant_names(decoded))
|
return Ok(#enum_name::#variant_names(decoded))
|
||||||
|
|
|
@ -152,7 +152,7 @@ pub fn derive_tokenizeable_impl(input: &DeriveInput) -> proc_macro2::TokenStream
|
||||||
#tokenize_predicates
|
#tokenize_predicates
|
||||||
{
|
{
|
||||||
|
|
||||||
fn from_token(token: #core_crate::abi::Token) -> Result<Self, #core_crate::abi::InvalidOutputType> where
|
fn from_token(token: #core_crate::abi::Token) -> ::std::result::Result<Self, #core_crate::abi::InvalidOutputType> where
|
||||||
Self: Sized {
|
Self: Sized {
|
||||||
#from_token_impl
|
#from_token_impl
|
||||||
}
|
}
|
||||||
|
@ -174,7 +174,7 @@ fn tokenize_unit_type(name: &Ident) -> TokenStream {
|
||||||
let ethers_core = ethers_core_crate();
|
let ethers_core = ethers_core_crate();
|
||||||
quote! {
|
quote! {
|
||||||
impl #ethers_core::abi::Tokenizable for #name {
|
impl #ethers_core::abi::Tokenizable for #name {
|
||||||
fn from_token(token: #ethers_core::abi::Token) -> Result<Self, #ethers_core::abi::InvalidOutputType> where
|
fn from_token(token: #ethers_core::abi::Token) -> ::std::result::Result<Self, #ethers_core::abi::InvalidOutputType> where
|
||||||
Self: Sized {
|
Self: Sized {
|
||||||
if let #ethers_core::abi::Token::Tuple(tokens) = token {
|
if let #ethers_core::abi::Token::Tuple(tokens) = token {
|
||||||
if !tokens.is_empty() {
|
if !tokens.is_empty() {
|
||||||
|
@ -210,7 +210,7 @@ fn tokenize_unit_type(name: &Ident) -> TokenStream {
|
||||||
fn tokenize_enum<'a>(
|
fn tokenize_enum<'a>(
|
||||||
enum_name: &Ident,
|
enum_name: &Ident,
|
||||||
variants: impl Iterator<Item = &'a Variant> + 'a,
|
variants: impl Iterator<Item = &'a Variant> + 'a,
|
||||||
) -> Result<TokenStream, Error> {
|
) -> ::std::result::Result<TokenStream, Error> {
|
||||||
let ethers_core = ethers_core_crate();
|
let ethers_core = ethers_core_crate();
|
||||||
|
|
||||||
let mut into_tokens = TokenStream::new();
|
let mut into_tokens = TokenStream::new();
|
||||||
|
@ -252,7 +252,7 @@ fn tokenize_enum<'a>(
|
||||||
Ok(quote! {
|
Ok(quote! {
|
||||||
impl #ethers_core::abi::Tokenizable for #enum_name {
|
impl #ethers_core::abi::Tokenizable for #enum_name {
|
||||||
|
|
||||||
fn from_token(token: #ethers_core::abi::Token) -> Result<Self, #ethers_core::abi::InvalidOutputType> where
|
fn from_token(token: #ethers_core::abi::Token) -> ::std::result::Result<Self, #ethers_core::abi::InvalidOutputType> where
|
||||||
Self: Sized {
|
Self: Sized {
|
||||||
#from_tokens
|
#from_tokens
|
||||||
Err(#ethers_core::abi::InvalidOutputType("Failed to decode all type variants".to_string()))
|
Err(#ethers_core::abi::InvalidOutputType("Failed to decode all type variants".to_string()))
|
||||||
|
|
|
@ -27,7 +27,7 @@ pub(crate) struct Contracts {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Contracts {
|
impl Contracts {
|
||||||
pub(crate) fn expand(self) -> Result<TokenStream2, syn::Error> {
|
pub(crate) fn expand(self) -> ::std::result::Result<TokenStream2, syn::Error> {
|
||||||
let mut expansions = Vec::with_capacity(self.inner.len());
|
let mut expansions = Vec::with_capacity(self.inner.len());
|
||||||
|
|
||||||
// expand all contracts
|
// expand all contracts
|
||||||
|
|
|
@ -95,7 +95,7 @@ pub fn derive_trait_impls(
|
||||||
}
|
}
|
||||||
|
|
||||||
impl #core_crate::abi::AbiDecode for #struct_name {
|
impl #core_crate::abi::AbiDecode for #struct_name {
|
||||||
fn decode(bytes: impl AsRef<[u8]>) -> Result<Self, #core_crate::abi::AbiError> {
|
fn decode(bytes: impl AsRef<[u8]>) -> ::std::result::Result<Self, #core_crate::abi::AbiError> {
|
||||||
#decode_impl
|
#decode_impl
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ pub fn derive_codec_impl(input: &DeriveInput) -> proc_macro2::TokenStream {
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
impl #core_crate::abi::AbiDecode for #name {
|
impl #core_crate::abi::AbiDecode for #name {
|
||||||
fn decode(bytes: impl AsRef<[u8]>) -> Result<Self, #core_crate::abi::AbiError> {
|
fn decode(bytes: impl AsRef<[u8]>) -> ::std::result::Result<Self, #core_crate::abi::AbiError> {
|
||||||
if let #core_crate::abi::ParamType::Tuple(params) = <Self as #core_crate::abi::AbiType>::param_type() {
|
if let #core_crate::abi::ParamType::Tuple(params) = <Self as #core_crate::abi::AbiType>::param_type() {
|
||||||
let tokens = #core_crate::abi::decode(¶ms, bytes.as_ref())?;
|
let tokens = #core_crate::abi::decode(¶ms, bytes.as_ref())?;
|
||||||
Ok(<Self as #core_crate::abi::Tokenizable>::from_token(#core_crate::abi::Token::Tuple(tokens))?)
|
Ok(<Self as #core_crate::abi::Tokenizable>::from_token(#core_crate::abi::Token::Tuple(tokens))?)
|
||||||
|
|
|
@ -95,7 +95,7 @@ pub(crate) fn derive_eth_event_impl(input: DeriveInput) -> TokenStream {
|
||||||
#abi.into()
|
#abi.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decode_log(log: &#core_crate::abi::RawLog) -> Result<Self, #core_crate::abi::Error> where Self: Sized {
|
fn decode_log(log: &#core_crate::abi::RawLog) -> ::std::result::Result<Self, #core_crate::abi::Error> where Self: Sized {
|
||||||
#decode_log_impl
|
#decode_log_impl
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -605,3 +605,16 @@ fn eth_display_works_on_ethers_bytes() {
|
||||||
let s = format!("{}", call);
|
let s = format!("{}", call);
|
||||||
assert_eq!(s, "0xaaaaaa");
|
assert_eq!(s, "0xaaaaaa");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn can_use_result_name() {
|
||||||
|
abigen!(
|
||||||
|
ResultContract,
|
||||||
|
r#"[
|
||||||
|
struct Result {uint256 result;}
|
||||||
|
result(Result result) (uint256)
|
||||||
|
]"#,
|
||||||
|
);
|
||||||
|
|
||||||
|
let _call = ResultCall { result: Result { result: U256::zero() } };
|
||||||
|
}
|
||||||
|
|
|
@ -764,11 +764,13 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_next_block_base_fee() {
|
fn test_next_block_base_fee() {
|
||||||
// <https://etherscan.io/block/14402566>
|
// <https://etherscan.io/block/14402566>
|
||||||
let mut block_14402566 = Block::<TxHash>::default();
|
let block_14402566: Block<TxHash> = Block {
|
||||||
block_14402566.number = Some(U64::from(14402566u64));
|
number: Some(U64::from(14402566u64)),
|
||||||
block_14402566.base_fee_per_gas = Some(U256::from(36_803_013_756u128));
|
base_fee_per_gas: Some(U256::from(36_803_013_756u128)),
|
||||||
block_14402566.gas_limit = U256::from(30_087_887u128);
|
gas_limit: U256::from(30_087_887u128),
|
||||||
block_14402566.gas_used = U256::from(2_023_848u128);
|
gas_used: U256::from(2_023_848u128),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
assert_eq!(block_14402566.base_fee_per_gas, Some(U256::from(36_803_013_756u128)));
|
assert_eq!(block_14402566.base_fee_per_gas, Some(U256::from(36_803_013_756u128)));
|
||||||
assert_eq!(block_14402566.gas_target(), U256::from(15_043_943u128));
|
assert_eq!(block_14402566.gas_target(), U256::from(15_043_943u128));
|
||||||
|
@ -776,11 +778,13 @@ mod tests {
|
||||||
assert_eq!(block_14402566.next_block_base_fee(), Some(U256::from(32_821_521_542u128)));
|
assert_eq!(block_14402566.next_block_base_fee(), Some(U256::from(32_821_521_542u128)));
|
||||||
|
|
||||||
// https://etherscan.io/block/14402712
|
// https://etherscan.io/block/14402712
|
||||||
let mut block_14402712 = Block::<TxHash>::default();
|
let block_14402712: Block<TxHash> = Block {
|
||||||
block_14402712.number = Some(U64::from(14402712u64));
|
number: Some(U64::from(14402712u64)),
|
||||||
block_14402712.base_fee_per_gas = Some(U256::from(24_870_031_149u128));
|
base_fee_per_gas: Some(U256::from(24_870_031_149u128)),
|
||||||
block_14402712.gas_limit = U256::from(30_000_000u128);
|
gas_limit: U256::from(30_000_000u128),
|
||||||
block_14402712.gas_used = U256::from(29_999_374u128);
|
gas_used: U256::from(29_999_374u128),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
assert_eq!(block_14402712.base_fee_per_gas, Some(U256::from(24_870_031_149u128)));
|
assert_eq!(block_14402712.base_fee_per_gas, Some(U256::from(24_870_031_149u128)));
|
||||||
assert_eq!(block_14402712.gas_target(), U256::from(15_000_000u128));
|
assert_eq!(block_14402712.gas_target(), U256::from(15_000_000u128));
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
//! Some convenient serde helpers
|
//! Some convenient serde helpers
|
||||||
|
|
||||||
use crate::types::{BlockNumber, U256};
|
use crate::types::{BlockNumber, U256};
|
||||||
use ethabi::ethereum_types::FromDecStrErr;
|
|
||||||
use serde::{Deserialize, Deserializer};
|
use serde::{Deserialize, Deserializer};
|
||||||
use std::convert::TryFrom;
|
use std::{
|
||||||
|
convert::{TryFrom, TryInto},
|
||||||
|
str::FromStr,
|
||||||
|
};
|
||||||
|
|
||||||
/// Helper type to parse both `u64` and `U256`
|
/// Helper type to parse both `u64` and `U256`
|
||||||
#[derive(Copy, Clone, Deserialize)]
|
#[derive(Copy, Clone, Deserialize)]
|
||||||
|
@ -22,7 +24,21 @@ impl From<Numeric> for U256 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Helper type to parse both `u64` and `U256`
|
impl FromStr for Numeric {
|
||||||
|
type Err = String;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
if let Ok(val) = s.parse::<u128>() {
|
||||||
|
Ok(Numeric::U256(val.into()))
|
||||||
|
} else if s.starts_with("0x") {
|
||||||
|
U256::from_str(s).map(Numeric::U256).map_err(|err| err.to_string())
|
||||||
|
} else {
|
||||||
|
U256::from_dec_str(s).map(Numeric::U256).map_err(|err| err.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Helper type to parse numeric strings, `u64` and `U256`
|
||||||
#[derive(Deserialize, Debug, Clone)]
|
#[derive(Deserialize, Debug, Clone)]
|
||||||
#[serde(untagged)]
|
#[serde(untagged)]
|
||||||
pub enum StringifiedNumeric {
|
pub enum StringifiedNumeric {
|
||||||
|
@ -32,7 +48,7 @@ pub enum StringifiedNumeric {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<StringifiedNumeric> for U256 {
|
impl TryFrom<StringifiedNumeric> for U256 {
|
||||||
type Error = FromDecStrErr;
|
type Error = String;
|
||||||
|
|
||||||
fn try_from(value: StringifiedNumeric) -> Result<Self, Self::Error> {
|
fn try_from(value: StringifiedNumeric) -> Result<Self, Self::Error> {
|
||||||
match value {
|
match value {
|
||||||
|
@ -41,14 +57,71 @@ impl TryFrom<StringifiedNumeric> for U256 {
|
||||||
StringifiedNumeric::String(s) => {
|
StringifiedNumeric::String(s) => {
|
||||||
if let Ok(val) = s.parse::<u128>() {
|
if let Ok(val) = s.parse::<u128>() {
|
||||||
Ok(val.into())
|
Ok(val.into())
|
||||||
|
} else if s.starts_with("0x") {
|
||||||
|
U256::from_str(&s).map_err(|err| err.to_string())
|
||||||
} else {
|
} else {
|
||||||
U256::from_dec_str(&s)
|
U256::from_dec_str(&s).map_err(|err| err.to_string())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Supports parsing numbers as strings
|
||||||
|
///
|
||||||
|
/// See <https://github.com/gakonst/ethers-rs/issues/1507>
|
||||||
|
pub fn deserialize_stringified_numeric<'de, D>(deserializer: D) -> Result<U256, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
let num = StringifiedNumeric::deserialize(deserializer)?;
|
||||||
|
num.try_into().map_err(serde::de::Error::custom)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Supports parsing numbers as strings
|
||||||
|
///
|
||||||
|
/// See <https://github.com/gakonst/ethers-rs/issues/1507>
|
||||||
|
pub fn deserialize_stringified_numeric_opt<'de, D>(
|
||||||
|
deserializer: D,
|
||||||
|
) -> Result<Option<U256>, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
if let Some(num) = Option::<StringifiedNumeric>::deserialize(deserializer)? {
|
||||||
|
num.try_into().map(Some).map_err(serde::de::Error::custom)
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Supports parsing u64
|
||||||
|
///
|
||||||
|
/// See <https://github.com/gakonst/ethers-rs/issues/1507>
|
||||||
|
pub fn deserialize_stringified_u64<'de, D>(deserializer: D) -> Result<u64, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
let num = StringifiedNumeric::deserialize(deserializer)?;
|
||||||
|
let num: U256 = num.try_into().map_err(serde::de::Error::custom)?;
|
||||||
|
num.try_into().map_err(serde::de::Error::custom)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Supports parsing u64
|
||||||
|
///
|
||||||
|
/// See <https://github.com/gakonst/ethers-rs/issues/1507>
|
||||||
|
pub fn deserialize_stringified_u64_opt<'de, D>(deserializer: D) -> Result<Option<u64>, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
if let Some(num) = Option::<StringifiedNumeric>::deserialize(deserializer)? {
|
||||||
|
let num: U256 = num.try_into().map_err(serde::de::Error::custom)?;
|
||||||
|
let num: u64 = num.try_into().map_err(serde::de::Error::custom)?;
|
||||||
|
Ok(Some(num))
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Helper type to deserialize sequence of numbers
|
/// Helper type to deserialize sequence of numbers
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
#[serde(untagged)]
|
#[serde(untagged)]
|
||||||
|
@ -94,6 +167,42 @@ where
|
||||||
Ok(num)
|
Ok(num)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Helper type to parse numeric strings, `u64` and `U256`
|
||||||
|
#[derive(Deserialize, Debug, Clone)]
|
||||||
|
#[serde(untagged)]
|
||||||
|
pub enum StringifiedBlockNumber {
|
||||||
|
Numeric(StringifiedNumeric),
|
||||||
|
BlockNumber(BlockNumber),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<StringifiedBlockNumber> for BlockNumber {
|
||||||
|
type Error = String;
|
||||||
|
|
||||||
|
fn try_from(value: StringifiedBlockNumber) -> Result<Self, Self::Error> {
|
||||||
|
match value {
|
||||||
|
StringifiedBlockNumber::Numeric(num) => {
|
||||||
|
let num = U256::try_from(num)
|
||||||
|
.and_then(|num| u64::try_from(num).map_err(str::to_string))?;
|
||||||
|
Ok(BlockNumber::Number(num.into()))
|
||||||
|
}
|
||||||
|
StringifiedBlockNumber::BlockNumber(b) => Ok(b),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Supports parsing block number as strings
|
||||||
|
///
|
||||||
|
/// See <https://github.com/gakonst/ethers-rs/issues/1507>
|
||||||
|
pub fn deserialize_stringified_block_number<'de, D>(
|
||||||
|
deserializer: D,
|
||||||
|
) -> Result<BlockNumber, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
let num = StringifiedBlockNumber::deserialize(deserializer)?;
|
||||||
|
num.try_into().map_err(serde::de::Error::custom)
|
||||||
|
}
|
||||||
|
|
||||||
/// Various block number representations, See [`lenient_block_number()`]
|
/// Various block number representations, See [`lenient_block_number()`]
|
||||||
#[derive(Clone, Copy, Deserialize)]
|
#[derive(Clone, Copy, Deserialize)]
|
||||||
#[serde(untagged)]
|
#[serde(untagged)]
|
||||||
|
|
|
@ -547,7 +547,7 @@ mod tests {
|
||||||
|
|
||||||
let addresses = raw_addresses
|
let addresses = raw_addresses
|
||||||
.iter()
|
.iter()
|
||||||
.map(|addr| NameOrAddress::Address(Address::from_str(*addr).unwrap()));
|
.map(|addr| NameOrAddress::Address(Address::from_str(addr).unwrap()));
|
||||||
|
|
||||||
// decoding will do sender recovery and we don't expect any of these to error, so we should
|
// decoding will do sender recovery and we don't expect any of these to error, so we should
|
||||||
// check that the address matches for each decoded transaction
|
// check that the address matches for each decoded transaction
|
||||||
|
|
|
@ -1,17 +1,15 @@
|
||||||
|
use crate::{Client, EtherscanError, Query, Response, Result};
|
||||||
|
use ethers_core::{
|
||||||
|
abi::Address,
|
||||||
|
types::{serde_helpers::*, BlockNumber, Bytes, H256, U256},
|
||||||
|
};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
use std::{
|
use std::{
|
||||||
borrow::Cow,
|
borrow::Cow,
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
fmt::{Display, Error, Formatter},
|
fmt::{Display, Error, Formatter},
|
||||||
};
|
};
|
||||||
|
|
||||||
use ethers_core::{
|
|
||||||
abi::Address,
|
|
||||||
types::{BlockNumber, Bytes, H256, U256, U64},
|
|
||||||
};
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
use crate::{Client, EtherscanError, Query, Response, Result};
|
|
||||||
|
|
||||||
/// The raw response from the balance-related API endpoints
|
/// The raw response from the balance-related API endpoints
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
pub struct AccountBalance {
|
pub struct AccountBalance {
|
||||||
|
@ -100,6 +98,7 @@ impl<T> GenesisOption<T> {
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct NormalTransaction {
|
pub struct NormalTransaction {
|
||||||
pub is_error: String,
|
pub is_error: String,
|
||||||
|
#[serde(deserialize_with = "deserialize_stringified_block_number")]
|
||||||
pub block_number: BlockNumber,
|
pub block_number: BlockNumber,
|
||||||
pub time_stamp: String,
|
pub time_stamp: String,
|
||||||
#[serde(with = "jsonstring")]
|
#[serde(with = "jsonstring")]
|
||||||
|
@ -108,12 +107,16 @@ pub struct NormalTransaction {
|
||||||
pub nonce: GenesisOption<U256>,
|
pub nonce: GenesisOption<U256>,
|
||||||
#[serde(with = "jsonstring")]
|
#[serde(with = "jsonstring")]
|
||||||
pub block_hash: GenesisOption<U256>,
|
pub block_hash: GenesisOption<U256>,
|
||||||
pub transaction_index: Option<U64>,
|
#[serde(deserialize_with = "deserialize_stringified_u64_opt")]
|
||||||
|
pub transaction_index: Option<u64>,
|
||||||
#[serde(with = "jsonstring")]
|
#[serde(with = "jsonstring")]
|
||||||
pub from: GenesisOption<Address>,
|
pub from: GenesisOption<Address>,
|
||||||
pub to: Option<Address>,
|
pub to: Option<Address>,
|
||||||
|
#[serde(deserialize_with = "deserialize_stringified_numeric")]
|
||||||
pub value: U256,
|
pub value: U256,
|
||||||
|
#[serde(deserialize_with = "deserialize_stringified_numeric")]
|
||||||
pub gas: U256,
|
pub gas: U256,
|
||||||
|
#[serde(deserialize_with = "deserialize_stringified_numeric_opt")]
|
||||||
pub gas_price: Option<U256>,
|
pub gas_price: Option<U256>,
|
||||||
#[serde(rename = "txreceipt_status")]
|
#[serde(rename = "txreceipt_status")]
|
||||||
pub tx_receipt_status: String,
|
pub tx_receipt_status: String,
|
||||||
|
@ -121,21 +124,26 @@ pub struct NormalTransaction {
|
||||||
pub input: GenesisOption<Bytes>,
|
pub input: GenesisOption<Bytes>,
|
||||||
#[serde(with = "jsonstring")]
|
#[serde(with = "jsonstring")]
|
||||||
pub contract_address: GenesisOption<Address>,
|
pub contract_address: GenesisOption<Address>,
|
||||||
|
#[serde(deserialize_with = "deserialize_stringified_numeric")]
|
||||||
pub gas_used: U256,
|
pub gas_used: U256,
|
||||||
|
#[serde(deserialize_with = "deserialize_stringified_numeric")]
|
||||||
pub cumulative_gas_used: U256,
|
pub cumulative_gas_used: U256,
|
||||||
pub confirmations: U64,
|
#[serde(deserialize_with = "deserialize_stringified_u64")]
|
||||||
|
pub confirmations: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The raw response from the internal transaction list API endpoint
|
/// The raw response from the internal transaction list API endpoint
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct InternalTransaction {
|
pub struct InternalTransaction {
|
||||||
|
#[serde(deserialize_with = "deserialize_stringified_block_number")]
|
||||||
pub block_number: BlockNumber,
|
pub block_number: BlockNumber,
|
||||||
pub time_stamp: String,
|
pub time_stamp: String,
|
||||||
pub hash: H256,
|
pub hash: H256,
|
||||||
pub from: Address,
|
pub from: Address,
|
||||||
#[serde(with = "jsonstring")]
|
#[serde(with = "jsonstring")]
|
||||||
pub to: GenesisOption<Address>,
|
pub to: GenesisOption<Address>,
|
||||||
|
#[serde(deserialize_with = "deserialize_stringified_numeric")]
|
||||||
pub value: U256,
|
pub value: U256,
|
||||||
#[serde(with = "jsonstring")]
|
#[serde(with = "jsonstring")]
|
||||||
pub contract_address: GenesisOption<Address>,
|
pub contract_address: GenesisOption<Address>,
|
||||||
|
@ -143,7 +151,9 @@ pub struct InternalTransaction {
|
||||||
pub input: GenesisOption<Bytes>,
|
pub input: GenesisOption<Bytes>,
|
||||||
#[serde(rename = "type")]
|
#[serde(rename = "type")]
|
||||||
pub result_type: String,
|
pub result_type: String,
|
||||||
|
#[serde(deserialize_with = "deserialize_stringified_numeric")]
|
||||||
pub gas: U256,
|
pub gas: U256,
|
||||||
|
#[serde(deserialize_with = "deserialize_stringified_numeric")]
|
||||||
pub gas_used: U256,
|
pub gas_used: U256,
|
||||||
pub trace_id: String,
|
pub trace_id: String,
|
||||||
pub is_error: String,
|
pub is_error: String,
|
||||||
|
@ -154,35 +164,46 @@ pub struct InternalTransaction {
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct ERC20TokenTransferEvent {
|
pub struct ERC20TokenTransferEvent {
|
||||||
|
#[serde(deserialize_with = "deserialize_stringified_block_number")]
|
||||||
pub block_number: BlockNumber,
|
pub block_number: BlockNumber,
|
||||||
pub time_stamp: String,
|
pub time_stamp: String,
|
||||||
pub hash: H256,
|
pub hash: H256,
|
||||||
|
#[serde(deserialize_with = "deserialize_stringified_numeric")]
|
||||||
pub nonce: U256,
|
pub nonce: U256,
|
||||||
pub block_hash: H256,
|
pub block_hash: H256,
|
||||||
pub from: Address,
|
pub from: Address,
|
||||||
pub contract_address: Address,
|
pub contract_address: Address,
|
||||||
pub to: Option<Address>,
|
pub to: Option<Address>,
|
||||||
|
#[serde(deserialize_with = "deserialize_stringified_numeric")]
|
||||||
pub value: U256,
|
pub value: U256,
|
||||||
pub token_name: String,
|
pub token_name: String,
|
||||||
pub token_symbol: String,
|
pub token_symbol: String,
|
||||||
pub token_decimal: String,
|
pub token_decimal: String,
|
||||||
pub transaction_index: U64,
|
#[serde(deserialize_with = "deserialize_stringified_u64")]
|
||||||
|
pub transaction_index: u64,
|
||||||
|
#[serde(deserialize_with = "deserialize_stringified_numeric")]
|
||||||
pub gas: U256,
|
pub gas: U256,
|
||||||
|
#[serde(deserialize_with = "deserialize_stringified_numeric_opt")]
|
||||||
pub gas_price: Option<U256>,
|
pub gas_price: Option<U256>,
|
||||||
|
#[serde(deserialize_with = "deserialize_stringified_numeric")]
|
||||||
pub gas_used: U256,
|
pub gas_used: U256,
|
||||||
|
#[serde(deserialize_with = "deserialize_stringified_numeric")]
|
||||||
pub cumulative_gas_used: U256,
|
pub cumulative_gas_used: U256,
|
||||||
/// deprecated
|
/// deprecated
|
||||||
pub input: String,
|
pub input: String,
|
||||||
pub confirmations: U64,
|
#[serde(deserialize_with = "deserialize_stringified_u64")]
|
||||||
|
pub confirmations: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The raw response from the ERC721 transfer list API endpoint
|
/// The raw response from the ERC721 transfer list API endpoint
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct ERC721TokenTransferEvent {
|
pub struct ERC721TokenTransferEvent {
|
||||||
|
#[serde(deserialize_with = "deserialize_stringified_block_number")]
|
||||||
pub block_number: BlockNumber,
|
pub block_number: BlockNumber,
|
||||||
pub time_stamp: String,
|
pub time_stamp: String,
|
||||||
pub hash: H256,
|
pub hash: H256,
|
||||||
|
#[serde(deserialize_with = "deserialize_stringified_numeric")]
|
||||||
pub nonce: U256,
|
pub nonce: U256,
|
||||||
pub block_hash: H256,
|
pub block_hash: H256,
|
||||||
pub from: Address,
|
pub from: Address,
|
||||||
|
@ -193,23 +214,31 @@ pub struct ERC721TokenTransferEvent {
|
||||||
pub token_name: String,
|
pub token_name: String,
|
||||||
pub token_symbol: String,
|
pub token_symbol: String,
|
||||||
pub token_decimal: String,
|
pub token_decimal: String,
|
||||||
pub transaction_index: U64,
|
#[serde(deserialize_with = "deserialize_stringified_u64")]
|
||||||
|
pub transaction_index: u64,
|
||||||
|
#[serde(deserialize_with = "deserialize_stringified_numeric")]
|
||||||
pub gas: U256,
|
pub gas: U256,
|
||||||
|
#[serde(deserialize_with = "deserialize_stringified_numeric_opt")]
|
||||||
pub gas_price: Option<U256>,
|
pub gas_price: Option<U256>,
|
||||||
|
#[serde(deserialize_with = "deserialize_stringified_numeric")]
|
||||||
pub gas_used: U256,
|
pub gas_used: U256,
|
||||||
|
#[serde(deserialize_with = "deserialize_stringified_numeric")]
|
||||||
pub cumulative_gas_used: U256,
|
pub cumulative_gas_used: U256,
|
||||||
/// deprecated
|
/// deprecated
|
||||||
pub input: String,
|
pub input: String,
|
||||||
pub confirmations: U64,
|
#[serde(deserialize_with = "deserialize_stringified_u64")]
|
||||||
|
pub confirmations: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The raw response from the ERC1155 transfer list API endpoint
|
/// The raw response from the ERC1155 transfer list API endpoint
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct ERC1155TokenTransferEvent {
|
pub struct ERC1155TokenTransferEvent {
|
||||||
|
#[serde(deserialize_with = "deserialize_stringified_block_number")]
|
||||||
pub block_number: BlockNumber,
|
pub block_number: BlockNumber,
|
||||||
pub time_stamp: String,
|
pub time_stamp: String,
|
||||||
pub hash: H256,
|
pub hash: H256,
|
||||||
|
#[serde(deserialize_with = "deserialize_stringified_numeric")]
|
||||||
pub nonce: U256,
|
pub nonce: U256,
|
||||||
pub block_hash: H256,
|
pub block_hash: H256,
|
||||||
pub from: Address,
|
pub from: Address,
|
||||||
|
@ -220,20 +249,27 @@ pub struct ERC1155TokenTransferEvent {
|
||||||
pub token_value: String,
|
pub token_value: String,
|
||||||
pub token_name: String,
|
pub token_name: String,
|
||||||
pub token_symbol: String,
|
pub token_symbol: String,
|
||||||
pub transaction_index: U64,
|
#[serde(deserialize_with = "deserialize_stringified_u64")]
|
||||||
|
pub transaction_index: u64,
|
||||||
|
#[serde(deserialize_with = "deserialize_stringified_numeric")]
|
||||||
pub gas: U256,
|
pub gas: U256,
|
||||||
|
#[serde(deserialize_with = "deserialize_stringified_numeric_opt")]
|
||||||
pub gas_price: Option<U256>,
|
pub gas_price: Option<U256>,
|
||||||
|
#[serde(deserialize_with = "deserialize_stringified_numeric")]
|
||||||
pub gas_used: U256,
|
pub gas_used: U256,
|
||||||
|
#[serde(deserialize_with = "deserialize_stringified_numeric")]
|
||||||
pub cumulative_gas_used: U256,
|
pub cumulative_gas_used: U256,
|
||||||
/// deprecated
|
/// deprecated
|
||||||
pub input: String,
|
pub input: String,
|
||||||
pub confirmations: U64,
|
#[serde(deserialize_with = "deserialize_stringified_u64")]
|
||||||
|
pub confirmations: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The raw response from the mined blocks API endpoint
|
/// The raw response from the mined blocks API endpoint
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct MinedBlock {
|
pub struct MinedBlock {
|
||||||
|
#[serde(deserialize_with = "deserialize_stringified_block_number")]
|
||||||
pub block_number: BlockNumber,
|
pub block_number: BlockNumber,
|
||||||
pub time_stamp: String,
|
pub time_stamp: String,
|
||||||
pub block_reward: String,
|
pub block_reward: String,
|
||||||
|
@ -739,8 +775,12 @@ mod tests {
|
||||||
),
|
),
|
||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
.await;
|
.await
|
||||||
assert!(txs.is_ok());
|
.unwrap();
|
||||||
|
let tx = txs.get(0).unwrap();
|
||||||
|
assert_eq!(tx.gas_used, 93657u64.into());
|
||||||
|
assert_eq!(tx.nonce, 10u64.into());
|
||||||
|
assert_eq!(tx.block_number, 2228258u64.into());
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,15 +70,11 @@ impl Client {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use std::time::Duration;
|
|
||||||
|
|
||||||
use serial_test::serial;
|
|
||||||
|
|
||||||
use ethers_core::types::Chain;
|
|
||||||
|
|
||||||
use crate::tests::run_at_least_duration;
|
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::tests::run_at_least_duration;
|
||||||
|
use ethers_core::types::Chain;
|
||||||
|
use serial_test::serial;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
#[serial]
|
#[serial]
|
||||||
|
|
|
@ -52,13 +52,10 @@ impl Client {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use std::time::Duration;
|
|
||||||
|
|
||||||
use serial_test::serial;
|
|
||||||
|
|
||||||
use crate::{tests::run_at_least_duration, Chain};
|
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::{tests::run_at_least_duration, Chain};
|
||||||
|
use serial_test::serial;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
#[serial]
|
#[serial]
|
||||||
|
|
|
@ -427,6 +427,7 @@ pub enum DeployedBytecodeOutputSelection {
|
||||||
SourceMap,
|
SourceMap,
|
||||||
LinkReferences,
|
LinkReferences,
|
||||||
GeneratedSources,
|
GeneratedSources,
|
||||||
|
ImmutableReferences,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Serialize for DeployedBytecodeOutputSelection {
|
impl Serialize for DeployedBytecodeOutputSelection {
|
||||||
|
@ -465,6 +466,9 @@ impl fmt::Display for DeployedBytecodeOutputSelection {
|
||||||
DeployedBytecodeOutputSelection::GeneratedSources => {
|
DeployedBytecodeOutputSelection::GeneratedSources => {
|
||||||
f.write_str("evm.deployedBytecode.generatedSources")
|
f.write_str("evm.deployedBytecode.generatedSources")
|
||||||
}
|
}
|
||||||
|
DeployedBytecodeOutputSelection::ImmutableReferences => {
|
||||||
|
f.write_str("evm.deployedBytecode.immutableReferences")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -487,6 +491,9 @@ impl FromStr for DeployedBytecodeOutputSelection {
|
||||||
"evm.deployedBytecode.generatedSources" => {
|
"evm.deployedBytecode.generatedSources" => {
|
||||||
Ok(DeployedBytecodeOutputSelection::GeneratedSources)
|
Ok(DeployedBytecodeOutputSelection::GeneratedSources)
|
||||||
}
|
}
|
||||||
|
"evm.deployedBytecode.immutableReferences" => {
|
||||||
|
Ok(DeployedBytecodeOutputSelection::ImmutableReferences)
|
||||||
|
}
|
||||||
s => Err(format!("Invalid deployedBytecode selection: {}", s)),
|
s => Err(format!("Invalid deployedBytecode selection: {}", s)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -573,4 +580,13 @@ mod tests {
|
||||||
let s = serde_json::to_string(&empty).unwrap();
|
let s = serde_json::to_string(&empty).unwrap();
|
||||||
assert_eq!(s, r#"{"contract.sol":{"*":[]}}"#);
|
assert_eq!(s, r#"{"contract.sol":{"*":[]}}"#);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn deployed_bytecode_from_str() {
|
||||||
|
assert_eq!(
|
||||||
|
DeployedBytecodeOutputSelection::from_str("evm.deployedBytecode.immutableReferences")
|
||||||
|
.unwrap(),
|
||||||
|
DeployedBytecodeOutputSelection::ImmutableReferences
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue