diff --git a/ethers-contract/ethers-contract-abigen/src/contract.rs b/ethers-contract/ethers-contract-abigen/src/contract.rs index f287304c..d8b05b92 100644 --- a/ethers-contract/ethers-contract-abigen/src/contract.rs +++ b/ethers-contract/ethers-contract-abigen/src/contract.rs @@ -7,12 +7,9 @@ pub(crate) mod structs; mod types; use super::{util, Abigen}; -use crate::{ - contract::{methods::MethodAlias, structs::InternalStructs}, - rawabi::JsonAbi, -}; +use crate::contract::{methods::MethodAlias, structs::InternalStructs}; use ethers_core::{ - abi::{Abi, AbiParser, ErrorExt, EventExt}, + abi::{Abi, AbiParser, ErrorExt, EventExt, JsonAbi}, macros::{ethers_contract_crate, ethers_core_crate, ethers_providers_crate}, types::Bytes, }; diff --git a/ethers-contract/ethers-contract-abigen/src/contract/structs.rs b/ethers-contract/ethers-contract-abigen/src/contract/structs.rs index 1add4f6a..850f65e8 100644 --- a/ethers-contract/ethers-contract-abigen/src/contract/structs.rs +++ b/ethers-contract/ethers-contract-abigen/src/contract/structs.rs @@ -1,13 +1,12 @@ //! Methods for expanding structs use crate::{ contract::{types, Context}, - rawabi::{Component, RawAbi}, util, }; use ethers_core::{ abi::{ struct_def::{FieldDeclaration, FieldType, StructFieldType, StructType}, - HumanReadableParser, ParamType, SolStruct, + Component, HumanReadableParser, ParamType, RawAbi, SolStruct, }, macros::ethers_contract_crate, }; diff --git a/ethers-contract/ethers-contract-abigen/src/lib.rs b/ethers-contract/ethers-contract-abigen/src/lib.rs index 3c7e537f..3b69d575 100644 --- a/ethers-contract/ethers-contract-abigen/src/lib.rs +++ b/ethers-contract/ethers-contract-abigen/src/lib.rs @@ -16,9 +16,6 @@ pub mod contract; pub use contract::structs::InternalStructs; use contract::Context; -pub mod rawabi; -pub use rawabi::RawAbi; - mod rustfmt; mod source; mod util; diff --git a/ethers-contract/src/lib.rs b/ethers-contract/src/lib.rs index f8672669..27617918 100644 --- a/ethers-contract/src/lib.rs +++ b/ethers-contract/src/lib.rs @@ -49,7 +49,7 @@ pub mod builders { #[cfg(any(test, feature = "abigen"))] #[cfg_attr(docsrs, doc(cfg(feature = "abigen")))] pub use ethers_contract_abigen::{ - Abigen, ContractFilter, ExcludeContracts, InternalStructs, MultiAbigen, RawAbi, SelectContracts, + Abigen, ContractFilter, ExcludeContracts, InternalStructs, MultiAbigen, SelectContracts, }; #[cfg(any(test, feature = "abigen"))] diff --git a/ethers-core/src/abi/mod.rs b/ethers-core/src/abi/mod.rs index a13e729b..547433f2 100644 --- a/ethers-core/src/abi/mod.rs +++ b/ethers-core/src/abi/mod.rs @@ -22,6 +22,10 @@ mod human_readable; pub use human_readable::{ lexer::HumanReadableParser, parse as parse_abi, parse_str as parse_abi_str, AbiParser, }; + +mod raw; +pub use raw::{AbiObject, Component, Item, JsonAbi, RawAbi}; + mod sealed { use ethabi::{Event, Function}; diff --git a/ethers-contract/ethers-contract-abigen/src/rawabi.rs b/ethers-core/src/abi/raw.rs similarity index 93% rename from ethers-contract/ethers-contract-abigen/src/rawabi.rs rename to ethers-core/src/abi/raw.rs index c25618f7..98c4ef7f 100644 --- a/ethers-contract/ethers-contract-abigen/src/rawabi.rs +++ b/ethers-core/src/abi/raw.rs @@ -2,7 +2,7 @@ //! raw content of the ABI. #![allow(missing_docs)] -use ethers_core::types::Bytes; +use crate::types::Bytes; use serde::{ de::{MapAccess, SeqAccess, Visitor}, Deserialize, Deserializer, Serialize, @@ -109,7 +109,7 @@ pub struct Component { /// Represents contract ABI input variants #[derive(Deserialize)] #[serde(untagged)] -pub(crate) enum JsonAbi { +pub enum JsonAbi { /// json object input as `{"abi": [..], "bin": "..."}` Object(AbiObject), /// json array input as `[]` @@ -125,7 +125,7 @@ where } /// Contract ABI and optional bytecode as JSON object -pub(crate) struct AbiObject { +pub struct AbiObject { pub abi: RawAbi, pub bytecode: Option, } @@ -158,7 +158,7 @@ impl<'de> Visitor<'de> for AbiObjectVisitor { where D: Deserializer<'de>, { - Ok(DeserializeBytes(ethers_core::types::deserialize_bytes(deserializer)?.into())) + Ok(DeserializeBytes(crate::types::deserialize_bytes(deserializer)?.into())) } } @@ -204,7 +204,7 @@ impl<'de> Deserialize<'de> for AbiObject { #[cfg(test)] mod tests { use super::*; - use ethers_core::abi::Abi; + use crate::abi::Abi; fn assert_has_bytecode(s: &str) { match serde_json::from_str::(s).unwrap() { @@ -219,14 +219,16 @@ mod tests { #[test] fn can_parse_raw_abi() { - const VERIFIER_ABI: &str = include_str!("../../tests/solidity-contracts/verifier_abi.json"); + const VERIFIER_ABI: &str = + include_str!("../../../ethers-contract/tests/solidity-contracts/verifier_abi.json"); let _ = serde_json::from_str::(VERIFIER_ABI).unwrap(); } #[test] fn can_parse_hardhat_raw_abi() { - const VERIFIER_ABI: &str = - include_str!("../../tests/solidity-contracts/verifier_abi_hardhat.json"); + const VERIFIER_ABI: &str = include_str!( + "../../../ethers-contract/tests/solidity-contracts/verifier_abi_hardhat.json" + ); let _ = serde_json::from_str::(VERIFIER_ABI).unwrap(); } @@ -261,7 +263,9 @@ mod tests { let s = format!(r#"{{"abi": {}, "bytecode" : {{ "object": "{}" }} }}"#, abi_str, code); assert_has_bytecode(&s); - let hh_artifact = include_str!("../../tests/solidity-contracts/verifier_abi_hardhat.json"); + let hh_artifact = include_str!( + "../../../ethers-contract/tests/solidity-contracts/verifier_abi_hardhat.json" + ); match serde_json::from_str::(hh_artifact).unwrap() { JsonAbi::Object(abi) => { assert!(abi.bytecode.is_none()); @@ -274,7 +278,8 @@ mod tests { #[test] fn can_parse_greeter_bytecode() { - let artifact = include_str!("../../tests/solidity-contracts/greeter.json"); + let artifact = + include_str!("../../../ethers-contract/tests/solidity-contracts/greeter.json"); assert_has_bytecode(artifact); } diff --git a/ethers-etherscan/src/contract.rs b/ethers-etherscan/src/contract.rs index 86427cec..86aedda2 100644 --- a/ethers-etherscan/src/contract.rs +++ b/ethers-etherscan/src/contract.rs @@ -1,12 +1,10 @@ use crate::{ source_tree::{SourceTree, SourceTreeEntry}, - utils::{ - deserialize_address_opt, deserialize_stringified_abi, deserialize_stringified_source_code, - }, + utils::{deserialize_address_opt, deserialize_stringified_source_code}, Client, EtherscanError, Response, Result, }; use ethers_core::{ - abi::{Abi, Address}, + abi::{Abi, Address, RawAbi}, types::{serde_helpers::deserialize_stringified_u64, Bytes}, }; use semver::Version; @@ -113,8 +111,8 @@ pub struct Metadata { pub source_code: SourceCodeMetadata, /// The ABI of the contract. - #[serde(rename = "ABI", deserialize_with = "deserialize_stringified_abi")] - pub abi: Abi, + #[serde(rename = "ABI")] + pub abi: String, /// The name of the contract. pub contract_name: String, @@ -179,6 +177,16 @@ impl Metadata { self.source_code.sources() } + /// Parses the Abi String as an [RawAbi] struct. + pub fn raw_abi(&self) -> Result { + Ok(serde_json::from_str(&self.abi)?) + } + + /// Parses the Abi String as an [Abi] struct. + pub fn abi(&self) -> Result { + Ok(serde_json::from_str(&self.abi)?) + } + /// Parses the compiler version. pub fn compiler_version(&self) -> Result { let v = &self.compiler_version; @@ -274,8 +282,13 @@ impl IntoIterator for ContractMetadata { impl ContractMetadata { /// Returns the ABI of all contracts. - pub fn abis(&self) -> Vec<&Abi> { - self.items.iter().map(|c| &c.abi).collect() + pub fn abis(&self) -> Result> { + self.items.iter().map(|c| c.abi()).collect() + } + + /// Returns the raw ABI of all contracts. + pub fn raw_abis(&self) -> Result> { + self.items.iter().map(|c| c.raw_abi()).collect() } /// Returns the combined source code of all contracts. @@ -460,7 +473,7 @@ mod tests { let item = &meta.items[0]; assert!(matches!(item.source_code, SourceCodeMetadata::SourceCode(_))); assert_eq!(item.source_code.sources().len(), 1); - assert_eq!(item.abi, serde_json::from_str(DAO_ABI).unwrap()); + assert_eq!(item.abi().unwrap(), serde_json::from_str(DAO_ABI).unwrap()); }) .await } @@ -497,7 +510,7 @@ mod tests { let item = &meta.items[0]; assert!(matches!(item.source_code, SourceCodeMetadata::SourceCode(_))); assert_eq!(item.source_code.sources().len(), 1); - assert_eq!(item.abi, serde_json::from_str(DAO_ABI).unwrap()); + assert_eq!(item.abi().unwrap(), serde_json::from_str(DAO_ABI).unwrap()); }) .await } diff --git a/ethers-etherscan/src/utils.rs b/ethers-etherscan/src/utils.rs index 8a808dbb..f3588bab 100644 --- a/ethers-etherscan/src/utils.rs +++ b/ethers-etherscan/src/utils.rs @@ -1,5 +1,5 @@ use crate::{contract::SourceCodeMetadata, EtherscanError, Result}; -use ethers_core::{abi::Abi, types::Address}; +use ethers_core::types::Address; use semver::Version; use serde::{Deserialize, Deserializer}; @@ -53,14 +53,6 @@ pub fn deserialize_stringified_source_code<'de, D: Deserializer<'de>>( } } -/// Deserializes as JSON: "\[...\]" -pub fn deserialize_stringified_abi<'de, D: Deserializer<'de>>( - deserializer: D, -) -> std::result::Result { - let s = String::deserialize(deserializer)?; - serde_json::from_str(&s).map_err(serde::de::Error::custom) -} - #[cfg(test)] mod tests { use super::*; @@ -115,19 +107,6 @@ mod tests { assert_eq!(de.address, Some(expected)); } - #[test] - fn can_deserialize_stringified_abi() { - #[derive(Deserialize)] - struct Test { - #[serde(deserialize_with = "deserialize_stringified_abi")] - abi: Abi, - } - - let json = r#"{"abi": "[]"}"#; - let de: Test = serde_json::from_str(json).unwrap(); - assert_eq!(de.abi, Abi::default()); - } - #[test] fn can_deserialize_stringified_source_code() { #[derive(Deserialize)]