From df5d76b73f3526da058eea0ded3eec6775585bbd Mon Sep 17 00:00:00 2001 From: DaniPopes <57450786+DaniPopes@users.noreply.github.com> Date: Wed, 28 Sep 2022 13:22:04 +0000 Subject: [PATCH 1/6] fix: docs --- common/src/abi.rs | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/common/src/abi.rs b/common/src/abi.rs index 7c5c80f950276..1d05bcc2e0bda 100644 --- a/common/src/abi.rs +++ b/common/src/abi.rs @@ -99,23 +99,25 @@ pub fn parse_tokens<'a, I: IntoIterator>( /// cleans up potential shortcomings of the ethabi Tokenizer /// /// For example: parsing a string array with a single empty string: `[""]`, is returned as +/// /// ```text /// [ -// String( -// "\"\"", -// ), -// ], +/// String( +/// "\"\"", +/// ), +/// ], /// ``` -/// +/// /// But should just be +/// /// ```text /// [ -// String( -// "", -// ), -// ], +/// String( +/// "", +/// ), +/// ], /// ``` -/// +/// /// This will handle this edge case pub fn sanitize_token(token: Token) -> Token { match token { From 7da978a4098537bae3254fe54109fb94c2a46b52 Mon Sep 17 00:00:00 2001 From: DaniPopes <57450786+DaniPopes@users.noreply.github.com> Date: Wed, 28 Sep 2022 13:22:19 +0000 Subject: [PATCH 2/6] refactor: etherscan --- cast/src/lib.rs | 53 +++++-------- cli/src/cmd/forge/verify/etherscan.rs | 2 +- common/src/abi.rs | 9 +-- common/src/compile.rs | 107 +++++++++++--------------- evm/src/trace/identifier/etherscan.rs | 64 +++++---------- 5 files changed, 85 insertions(+), 150 deletions(-) diff --git a/cast/src/lib.rs b/cast/src/lib.rs index 56bf33dc6d9e6..586ba0e2ef9b2 100644 --- a/cast/src/lib.rs +++ b/cast/src/lib.rs @@ -1,6 +1,7 @@ //! Cast //! //! Contains core function implementation for `cast` + use crate::rlp_converter::Item; use base::{Base, NumberWithBase, ToBase}; use chrono::NaiveDateTime; @@ -16,7 +17,7 @@ use ethers_core::{ parse_bytes32_string, parse_units, rlp, Units, }, }; -use ethers_etherscan::Client; +use ethers_etherscan::{errors::EtherscanError, Client}; use ethers_providers::{Middleware, PendingTransaction}; use eyre::{Context, Result}; use foundry_common::{abi::encode_args, fmt::*}; @@ -1254,45 +1255,37 @@ impl SimpleCast { let client = Client::new(chain, api_key)?; // get the source - let contract_source = match client.contract_source_code(address).await { - Ok(src) => src, - Err(ethers_etherscan::errors::EtherscanError::InvalidApiKey) => { - eyre::bail!("Invalid Etherscan API key. Did you set it correctly? You may be using an API key for another Etherscan API chain (e.g. Ethereum API key for Polygonscan).") + let source = match client.contract_source_code(address).await { + Ok(source) => source, + Err(EtherscanError::InvalidApiKey) => { + eyre::bail!("Invalid Etherscan API key. Did you set it correctly? You may be using an API key for another Etherscan API chain (e.g. Etherscan API key for Polygonscan).") + } + Err(EtherscanError::ContractCodeNotVerified(address)) => { + eyre::bail!("Contract source code at {:?} on {} not verified. Maybe you have selected the wrong chain?", address, chain) } Err(err) => { eyre::bail!(err) } }; - if contract_source - .items - .iter() - .any(|item| item.abi == "Contract source code not verified") - { - eyre::bail!("Contract source code at {:?} on {} not verified. Maybe you have selected the wrong chain?", address, chain) - } - - let contract_source_names = contract_source + let names = source .items .iter() .map(|item| item.contract_name.clone()) .collect::>(); - let mut abis = Vec::with_capacity(contract_source.items.len()); - for item in &contract_source.items { - abis.push(serde_json::from_str(&item.abi)?); - } + // TODO: Abi to RawAbi ? + let abis = source.abis().iter().cloned().map(|_| todo!()).collect(); - (abis, contract_source_names) + (abis, names) } }; contract_abis .iter() - .zip(&contract_names) - .map(|(contract_abi, contract_name)| { - let interface_source = - foundry_utils::abi::abi_to_solidity(contract_abi, contract_name)?; - Ok(InterfaceSource { name: contract_name.to_owned(), source: interface_source }) + .zip(contract_names) + .map(|(contract_abi, name)| { + let source = foundry_utils::abi::abi_to_solidity(contract_abi, &name)?; + Ok(InterfaceSource { name, source }) }) .collect::>>() } @@ -1471,14 +1464,8 @@ impl SimpleCast { etherscan_api_key: String, ) -> Result { let client = Client::new(chain, etherscan_api_key)?; - let meta = client.contract_source_code(contract_address.parse()?).await?; - let code = meta.source_code(); - - if code.is_empty() { - return Err(eyre::eyre!("unverified contract")) - } - - Ok(code) + let metadata = client.contract_source_code(contract_address.parse()?).await?; + Ok(metadata.source_code()) } /// Fetches the source code of verified contracts from etherscan and expands the resulting @@ -1504,7 +1491,7 @@ impl SimpleCast { ) -> eyre::Result<()> { let client = Client::new(chain, etherscan_api_key)?; let meta = client.contract_source_code(contract_address.parse()?).await?; - let source_tree = meta.source_tree()?; + let source_tree = meta.source_tree(); source_tree.write_to(&output_directory)?; Ok(()) } diff --git a/cli/src/cmd/forge/verify/etherscan.rs b/cli/src/cmd/forge/verify/etherscan.rs index 8b25fa9c091dc..0785d3db67d26 100644 --- a/cli/src/cmd/forge/verify/etherscan.rs +++ b/cli/src/cmd/forge/verify/etherscan.rs @@ -8,8 +8,8 @@ use cast::SimpleCast; use ethers::{ abi::Function, etherscan::{ - contract::{CodeFormat, VerifyContract}, utils::lookup_compiler_version, + verify::{CodeFormat, VerifyContract}, Client, }, prelude::artifacts::StandardJsonCompilerInput, diff --git a/common/src/abi.rs b/common/src/abi.rs index 1d05bcc2e0bda..90a783db11f7c 100644 --- a/common/src/abi.rs +++ b/common/src/abi.rs @@ -266,15 +266,8 @@ pub async fn get_func_etherscan( let client = Client::new(chain, etherscan_api_key)?; let metadata = &client.contract_source_code(contract).await?.items[0]; - let abi = if metadata.implementation.is_empty() { - serde_json::from_str(&metadata.abi)? - } else { - let implementation = metadata.implementation.parse::
()?; - client.contract_abi(implementation).await? - }; - let empty = vec![]; - let funcs = abi.functions.get(function_name).unwrap_or(&empty); + let funcs = metadata.abi.functions.get(function_name).unwrap_or(&empty); for func in funcs { let res = encode_args(func, args); diff --git a/common/src/compile.rs b/common/src/compile.rs index 0dba4dd913efb..6ccce7d83188f 100644 --- a/common/src/compile.rs +++ b/common/src/compile.rs @@ -1,20 +1,19 @@ //! Support for compiling [ethers::solc::Project] use crate::{term, TestFunctionExt}; use comfy_table::{modifiers::UTF8_ROUND_CORNERS, presets::UTF8_FULL, *}; +use ethers_etherscan::contract::Metadata; use ethers_solc::{ - artifacts::{BytecodeObject, Contract, ContractBytecodeSome, Source, Sources}, + artifacts::{BytecodeObject, Contract, ContractBytecodeSome}, report::NoReporter, - Artifact, ArtifactId, FileFilter, Graph, Project, ProjectCompileOutput, Solc, + Artifact, ArtifactId, FileFilter, Graph, Project, ProjectCompileOutput, ProjectPathsConfig, + Solc, }; -use foundry_config::Config; -use semver::Version; +use eyre::Result; use std::{ collections::BTreeMap, fmt::Display, - io::Write, path::{Path, PathBuf}, }; -use tempfile::NamedTempFile; /// Helper type to configure how to compile a project /// @@ -35,7 +34,7 @@ impl ProjectCompiler { } /// Compiles the project with [`Project::compile()`] - pub fn compile(self, project: &Project) -> eyre::Result { + pub fn compile(self, project: &Project) -> Result { self.compile_with(project, |prj| Ok(prj.compile()?)) } @@ -48,7 +47,7 @@ impl ProjectCompiler { self, project: &Project, filter: F, - ) -> eyre::Result { + ) -> Result { self.compile_with(project, |prj| Ok(prj.compile_sparse(filter)?)) } @@ -63,9 +62,9 @@ impl ProjectCompiler { /// .compile_with(&config.project().unwrap(), |prj| Ok(prj.compile()?)).unwrap(); /// ``` #[tracing::instrument(target = "forge::compile", skip_all)] - pub fn compile_with(self, project: &Project, f: F) -> eyre::Result + pub fn compile_with(self, project: &Project, f: F) -> Result where - F: FnOnce(&Project) -> eyre::Result, + F: FnOnce(&Project) -> Result, { if !project.paths.has_input_files() { println!("Nothing to compile"); @@ -237,14 +236,14 @@ pub fn compile( project: &Project, print_names: bool, print_sizes: bool, -) -> eyre::Result { +) -> Result { ProjectCompiler::new(print_names, print_sizes).compile(project) } /// Compiles the provided [`Project`], throws if there's any compiler error and logs whether /// compilation was successful or if there was a cache hit. /// Doesn't print anything to stdout, thus is "suppressed". -pub fn suppress_compile(project: &Project) -> eyre::Result { +pub fn suppress_compile(project: &Project) -> Result { let output = ethers_solc::report::with_scoped( ðers_solc::report::Report::new(NoReporter::default()), || project.compile(), @@ -265,7 +264,7 @@ pub fn suppress_compile(project: &Project) -> eyre::Result pub fn suppress_compile_sparse( project: &Project, filter: F, -) -> eyre::Result { +) -> Result { let output = ethers_solc::report::with_scoped( ðers_solc::report::Report::new(NoReporter::default()), || project.compile_sparse(filter), @@ -285,7 +284,7 @@ pub fn compile_files( project: &Project, files: Vec, silent: bool, -) -> eyre::Result { +) -> Result { let output = if silent { ethers_solc::report::with_scoped( ðers_solc::report::Report::new(NoReporter::default()), @@ -317,7 +316,7 @@ pub fn compile_target( project: &Project, silent: bool, verify: bool, -) -> eyre::Result { +) -> Result { let graph = Graph::resolve(&project.paths)?; // Checking if it's a standalone script, or part of a project. @@ -335,62 +334,44 @@ pub fn compile_target( } } -/// Compile from etherscan bytecode. +/// Creates and compiles a project from an Etherscan source. pub async fn compile_from_source( - contract_name: String, - source: String, - // has the contract been optimized before submission to etherscan - optimization: bool, - runs: u32, - version: String, -) -> eyre::Result<(ArtifactId, ContractBytecodeSome)> { - let mut file = NamedTempFile::new()?; - writeln!(file, "{}", source.clone())?; - - let target_contract = dunce::canonicalize(file.path())?; - let mut project = Config::default().ephemeral_no_artifacts_project()?; - - if optimization { - project.solc_config.settings.optimizer.enable(); - project.solc_config.settings.optimizer.runs(runs as usize); - } else { - project.solc_config.settings.optimizer.disable(); - } - - project.solc = if let Some(solc) = Solc::find_svm_installed_version(&version)? { - solc - } else { - let v: Version = version.trim_start_matches('v').parse()?; - Solc::install(&Version::new(v.major, v.minor, v.patch)).await? - }; - - let mut sources = Sources::new(); - sources.insert(target_contract, Source { content: source }); + metadata: &Metadata, +) -> Result<(ArtifactId, ContractBytecodeSome)> { + let root = tempfile::tempdir()?; + let root_path = root.path(); + let project = etherscan_project(metadata, root_path)?; - let project_output = project.compile_with_version(&project.solc, sources)?; + let project_output = project.compile()?; if project_output.has_compiler_errors() { eyre::bail!(project_output.to_string()) } - let (artifact_id, bytecode) = project_output + let (artifact_id, contract) = project_output .into_contract_bytecodes() - .filter_map(|(artifact_id, contract)| { - if artifact_id.name != contract_name { - None - } else { - Some(( - artifact_id, - ContractBytecodeSome { - abi: contract.abi.unwrap(), - bytecode: contract.bytecode.unwrap().into(), - deployed_bytecode: contract.deployed_bytecode.unwrap().into(), - }, - )) - } - }) - .into_iter() - .next() + .find(|(artifact_id, _)| artifact_id.name == metadata.contract_name) .expect("there should be a contract with bytecode"); + let bytecode = ContractBytecodeSome { + abi: contract.abi.unwrap(), + bytecode: contract.bytecode.unwrap().into(), + deployed_bytecode: contract.deployed_bytecode.unwrap().into(), + }; + + root.close()?; + Ok((artifact_id, bytecode)) } + +/// Creates a [Project] from an Etherscan source. +pub fn etherscan_project(metadata: &Metadata, target_path: impl AsRef) -> Result { + let target_path = dunce::canonicalize(target_path.as_ref())?; + metadata.source_tree().write_to(&target_path)?; + + let paths = ProjectPathsConfig::builder().build_with_root(target_path); + + let version = &metadata.compiler_version; + let solc = Solc::find_or_install_svm_version(version)?; + + Ok(metadata.project_builder()?.paths(paths).solc(solc).ephemeral().no_artifacts().build()?) +} diff --git a/evm/src/trace/identifier/etherscan.rs b/evm/src/trace/identifier/etherscan.rs index f5e747811864b..e23c1222ede43 100644 --- a/evm/src/trace/identifier/etherscan.rs +++ b/evm/src/trace/identifier/etherscan.rs @@ -1,8 +1,8 @@ use super::{AddressIdentity, TraceIdentifier}; - use ethers::{ - abi::{Abi, Address}, + abi::Address, etherscan, + etherscan::contract::Metadata, prelude::{ artifacts::ContractBytecodeSome, contract::ContractMetadata, errors::EtherscanError, ArtifactId, @@ -39,7 +39,7 @@ pub struct EtherscanIdentifier { /// After the first [EtherscanError::InvalidApiKey] this will get set to true, so we can /// prevent any further attempts invalid_api_key: Arc, - pub contracts: BTreeMap, + pub contracts: BTreeMap, pub sources: BTreeMap, } @@ -72,21 +72,14 @@ impl EtherscanIdentifier { let contracts_iter = self .contracts .iter() - // filter out vyper files and invalid source - .filter(|(_, (_, source_code, _, _, version))| { - !source_code.starts_with("{{") && !version.starts_with("vyper") - }); + // filter out vyper files + .filter(|(_, metadata)| !metadata.is_vyper()); let outputs_fut = contracts_iter - .map(|(label, (name, source_code, optimization, runs, version))| { - println!("Compiling: {name} {:?}", label); - compile::compile_from_source( - name.to_string(), - source_code.clone(), - *optimization, - *runs, - version.to_string(), - ) + .clone() + .map(|(address, metadata)| { + println!("Compiling: {} {:?}", metadata.contract_name, address); + compile::compile_from_source(&metadata) }) .collect::>(); @@ -94,19 +87,11 @@ impl EtherscanIdentifier { let artifacts = join_all(outputs_fut).await; // construct the map - let contracts_iter = self - .contracts - .iter() - // filter out vyper files and invalid source - .filter(|(_, (_, source_code, _, _, version))| { - !source_code.starts_with("{{") && !version.starts_with("vyper") - }); - for (compiled, (_, (_, source_code, _, _, _))) in artifacts.into_iter().zip(contracts_iter) - { + for (results, (_, metadata)) in artifacts.into_iter().zip(contracts_iter) { // get the inner type - let compiled = compiled?; - compiled_contracts.insert(compiled.0.clone(), compiled.1.clone()); - sources.insert(compiled.0.to_owned(), source_code.to_owned()); + let (artifact_id, bytecode) = results?; + compiled_contracts.insert(artifact_id.clone(), bytecode); + sources.insert(artifact_id, metadata.source_code()); } Ok((sources, compiled_contracts)) @@ -140,11 +125,10 @@ impl TraceIdentifier for EtherscanIdentifier { } let fut = fetcher - .map(|(address, label, abi, source_code, optimization, runs, version)| { - self.contracts.insert( - address, - (label.to_string(), source_code, optimization, runs, version), - ); + .map(|(address, metadata)| { + let label = metadata.contract_name.clone(); + let abi = metadata.abi.clone(); + self.contracts.insert(address, metadata); AddressIdentity { address, @@ -223,7 +207,7 @@ impl EtherscanFetcher { } impl Stream for EtherscanFetcher { - type Item = (Address, String, Abi, String, bool, u32, String); + type Item = (Address, Metadata); fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { let pin = self.get_mut(); @@ -247,17 +231,7 @@ impl Stream for EtherscanFetcher { match res { Ok(mut metadata) => { if let Some(item) = metadata.items.pop() { - if let Ok(abi) = serde_json::from_str(&item.abi) { - return Poll::Ready(Some(( - addr, - item.contract_name, - abi, - item.source_code, - item.optimization_used.eq("1"), - item.runs.parse::().expect("runs parse error"), - item.compiler_version, - ))) - } + return Poll::Ready(Some((addr, item))) } } Err(EtherscanError::RateLimitExceeded) => { From 4e7c4b297e9e71e0777e274ce5633f8732069c27 Mon Sep 17 00:00:00 2001 From: DaniPopes <57450786+DaniPopes@users.noreply.github.com> Date: Wed, 28 Sep 2022 14:17:09 +0000 Subject: [PATCH 3/6] feat: add etherscan recursive source find method --- common/src/abi.rs | 56 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 45 insertions(+), 11 deletions(-) diff --git a/common/src/abi.rs b/common/src/abi.rs index 90a783db11f7c..7c687493e8609 100644 --- a/common/src/abi.rs +++ b/common/src/abi.rs @@ -8,13 +8,13 @@ use ethers_core::{ types::{Address, Chain, I256, U256}, utils::{hex, to_checksum}, }; -use ethers_etherscan::Client; -use eyre::WrapErr; -use std::str::FromStr; +use ethers_etherscan::{contract::ContractMetadata, errors::EtherscanError, Client}; +use eyre::{ContextCompat, Result, WrapErr}; +use std::{future::Future, pin::Pin, str::FromStr}; /// Given a function and a vector of string arguments, it proceeds to convert the args to ethabi /// Tokens and then ABI encode them. -pub fn encode_args(func: &Function, args: &[impl AsRef]) -> eyre::Result> { +pub fn encode_args(func: &Function, args: &[impl AsRef]) -> Result> { let params = func .inputs .iter() @@ -30,7 +30,7 @@ pub fn encode_args(func: &Function, args: &[impl AsRef]) -> eyre::Result eyre::Result> { +pub fn abi_decode(sig: &str, calldata: &str, input: bool) -> Result> { let func = IntoFunction::into(sig); let calldata = calldata.strip_prefix("0x").unwrap_or(calldata); let calldata = hex::decode(calldata)?; @@ -53,7 +53,7 @@ pub fn abi_decode(sig: &str, calldata: &str, input: bool) -> eyre::Result>( params: I, lenient: bool, -) -> eyre::Result> { +) -> Result> { params .into_iter() .map(|(param, value)| { @@ -96,7 +96,7 @@ pub fn parse_tokens<'a, I: IntoIterator>( .wrap_err("Failed to parse tokens") } -/// cleans up potential shortcomings of the ethabi Tokenizer +/// Cleans up potential shortcomings of the ethabi Tokenizer. /// /// For example: parsing a string array with a single empty string: `[""]`, is returned as /// @@ -205,7 +205,7 @@ impl<'a> IntoFunction for &'a str { } /// Given a function signature string, it tries to parse it as a `Function` -pub fn get_func(sig: &str) -> eyre::Result { +pub fn get_func(sig: &str) -> Result { Ok(match HumanReadableParser::parse_function(sig) { Ok(func) => func, Err(err) => { @@ -227,7 +227,7 @@ pub fn get_func(sig: &str) -> eyre::Result { } /// Given an event signature string, it tries to parse it as a `Event` -pub fn get_event(sig: &str) -> eyre::Result { +pub fn get_event(sig: &str) -> Result { Ok(HumanReadableParser::parse_event(sig)?) } @@ -262,9 +262,10 @@ pub async fn get_func_etherscan( args: &[String], chain: Chain, etherscan_api_key: &str, -) -> eyre::Result { +) -> Result { let client = Client::new(chain, etherscan_api_key)?; - let metadata = &client.contract_source_code(contract).await?.items[0]; + let source = find_source(client, contract).await?; + let metadata = source.items.first().wrap_err("etherscan returned empty metadata")?; let empty = vec![]; let funcs = metadata.abi.functions.get(function_name).unwrap_or(&empty); @@ -279,6 +280,39 @@ pub async fn get_func_etherscan( Err(eyre::eyre!("Function not found in abi")) } +/// If the code at `address` is a proxy, recurse until we find the implementation. +pub fn find_source( + client: Client, + address: Address, +) -> Pin>>> { + Box::pin(async move { + tracing::trace!("find etherscan source for: {:?}", address); + let source = client.contract_source_code(address).await?; + let metadata = source.items.first().wrap_err("Etherscan returned no data")?; + if metadata.proxy == 0 { + Ok(source) + } else { + let implementation = metadata.implementation.unwrap(); + println!( + "Contract at {} is a proxy, trying to fetch source at {:?}...", + address, implementation + ); + match find_source(client, implementation).await { + impl_source @ Ok(_) => impl_source, + Err(e) => { + let err = EtherscanError::ContractCodeNotVerified(address).to_string(); + if e.to_string() == err { + tracing::error!("{}", err); + Ok(source) + } else { + Err(e) + } + } + } + } + }) +} + #[cfg(test)] mod tests { use super::*; From a947dba1e946cd91b98432adbf051ac21ff36c3b Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Thu, 29 Sep 2022 17:40:10 +0200 Subject: [PATCH 4/6] chore(deps): bump ethers --- Cargo.lock | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 03a6de2b27f2c..97b4f0975bb50 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1625,7 +1625,7 @@ dependencies = [ [[package]] name = "ethers" version = "0.17.0" -source = "git+https://github.com/gakonst/ethers-rs#5c762c44d760ed9dad3900be079062174ada0245" +source = "git+https://github.com/gakonst/ethers-rs#62beb6cf53caf9c98f1ce0c793d9992d778cee1f" dependencies = [ "ethers-addressbook", "ethers-contract", @@ -1640,7 +1640,7 @@ dependencies = [ [[package]] name = "ethers-addressbook" version = "0.17.0" -source = "git+https://github.com/gakonst/ethers-rs#5c762c44d760ed9dad3900be079062174ada0245" +source = "git+https://github.com/gakonst/ethers-rs#62beb6cf53caf9c98f1ce0c793d9992d778cee1f" dependencies = [ "ethers-core", "once_cell", @@ -1651,7 +1651,7 @@ dependencies = [ [[package]] name = "ethers-contract" version = "0.17.0" -source = "git+https://github.com/gakonst/ethers-rs#5c762c44d760ed9dad3900be079062174ada0245" +source = "git+https://github.com/gakonst/ethers-rs#62beb6cf53caf9c98f1ce0c793d9992d778cee1f" dependencies = [ "ethers-contract-abigen", "ethers-contract-derive", @@ -1669,7 +1669,7 @@ dependencies = [ [[package]] name = "ethers-contract-abigen" version = "0.17.0" -source = "git+https://github.com/gakonst/ethers-rs#5c762c44d760ed9dad3900be079062174ada0245" +source = "git+https://github.com/gakonst/ethers-rs#62beb6cf53caf9c98f1ce0c793d9992d778cee1f" dependencies = [ "Inflector", "cfg-if 1.0.0", @@ -1692,7 +1692,7 @@ dependencies = [ [[package]] name = "ethers-contract-derive" version = "0.17.0" -source = "git+https://github.com/gakonst/ethers-rs#5c762c44d760ed9dad3900be079062174ada0245" +source = "git+https://github.com/gakonst/ethers-rs#62beb6cf53caf9c98f1ce0c793d9992d778cee1f" dependencies = [ "ethers-contract-abigen", "ethers-core", @@ -1706,7 +1706,7 @@ dependencies = [ [[package]] name = "ethers-core" version = "0.17.0" -source = "git+https://github.com/gakonst/ethers-rs#5c762c44d760ed9dad3900be079062174ada0245" +source = "git+https://github.com/gakonst/ethers-rs#62beb6cf53caf9c98f1ce0c793d9992d778cee1f" dependencies = [ "arrayvec 0.7.2", "bytes", @@ -1737,7 +1737,7 @@ dependencies = [ [[package]] name = "ethers-etherscan" version = "0.17.0" -source = "git+https://github.com/gakonst/ethers-rs#5c762c44d760ed9dad3900be079062174ada0245" +source = "git+https://github.com/gakonst/ethers-rs#62beb6cf53caf9c98f1ce0c793d9992d778cee1f" dependencies = [ "ethers-core", "getrandom 0.2.6", @@ -1753,7 +1753,7 @@ dependencies = [ [[package]] name = "ethers-middleware" version = "0.17.0" -source = "git+https://github.com/gakonst/ethers-rs#5c762c44d760ed9dad3900be079062174ada0245" +source = "git+https://github.com/gakonst/ethers-rs#62beb6cf53caf9c98f1ce0c793d9992d778cee1f" dependencies = [ "async-trait", "auto_impl 0.5.0", @@ -1778,7 +1778,7 @@ dependencies = [ [[package]] name = "ethers-providers" version = "0.17.0" -source = "git+https://github.com/gakonst/ethers-rs#5c762c44d760ed9dad3900be079062174ada0245" +source = "git+https://github.com/gakonst/ethers-rs#62beb6cf53caf9c98f1ce0c793d9992d778cee1f" dependencies = [ "async-trait", "auto_impl 1.0.1", @@ -1815,7 +1815,7 @@ dependencies = [ [[package]] name = "ethers-signers" version = "0.17.0" -source = "git+https://github.com/gakonst/ethers-rs#5c762c44d760ed9dad3900be079062174ada0245" +source = "git+https://github.com/gakonst/ethers-rs#62beb6cf53caf9c98f1ce0c793d9992d778cee1f" dependencies = [ "async-trait", "coins-bip32", @@ -1838,7 +1838,7 @@ dependencies = [ [[package]] name = "ethers-solc" version = "0.17.0" -source = "git+https://github.com/gakonst/ethers-rs#5c762c44d760ed9dad3900be079062174ada0245" +source = "git+https://github.com/gakonst/ethers-rs#62beb6cf53caf9c98f1ce0c793d9992d778cee1f" dependencies = [ "cfg-if 1.0.0", "dunce", From 092d6b0831d735c574e19b2f328033047b24341c Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Thu, 29 Sep 2022 17:41:05 +0200 Subject: [PATCH 5/6] enable feature --- Cargo.lock | 1 + common/Cargo.toml | 2 +- common/src/compile.rs | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 97b4f0975bb50..25805a0111275 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1740,6 +1740,7 @@ version = "0.17.0" source = "git+https://github.com/gakonst/ethers-rs#62beb6cf53caf9c98f1ce0c793d9992d778cee1f" dependencies = [ "ethers-core", + "ethers-solc", "getrandom 0.2.6", "reqwest", "semver", diff --git a/common/Cargo.toml b/common/Cargo.toml index e18269d4352d4..06941d5eed844 100644 --- a/common/Cargo.toml +++ b/common/Cargo.toml @@ -15,7 +15,7 @@ foundry-config = { path = "../config" } ethers-core = { git = "https://github.com/gakonst/ethers-rs", default-features = false } ethers-solc = { git = "https://github.com/gakonst/ethers-rs", default-features = false } ethers-providers = { git = "https://github.com/gakonst/ethers-rs", default-features = false } -ethers-etherscan = { git = "https://github.com/gakonst/ethers-rs", default-features = false } +ethers-etherscan = { git = "https://github.com/gakonst/ethers-rs", default-features = false, features = ["ethers-solc"] } # io reqwest = { version = "0.11", default-features = false } diff --git a/common/src/compile.rs b/common/src/compile.rs index 6c5ad25fc25c5..203a7d288327a 100644 --- a/common/src/compile.rs +++ b/common/src/compile.rs @@ -3,7 +3,7 @@ use crate::{term, TestFunctionExt}; use comfy_table::{modifiers::UTF8_ROUND_CORNERS, presets::UTF8_FULL, *}; use ethers_etherscan::contract::Metadata; use ethers_solc::{ - artifacts::{BytecodeObject, ContractBytecodeSome, Source, Sources}, + artifacts::{BytecodeObject, ContractBytecodeSome}, report::NoReporter, Artifact, ArtifactId, FileFilter, Graph, Project, ProjectCompileOutput, ProjectPathsConfig, Solc, From 2b8d345f3f903f5def0e20d967f99d0d45121791 Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Thu, 29 Sep 2022 17:44:38 +0200 Subject: [PATCH 6/6] chore(clippy): make clippy happy --- evm/src/trace/identifier/etherscan.rs | 2 +- forge/tests/it/repros.rs | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/evm/src/trace/identifier/etherscan.rs b/evm/src/trace/identifier/etherscan.rs index e23c1222ede43..f39fb71f2657a 100644 --- a/evm/src/trace/identifier/etherscan.rs +++ b/evm/src/trace/identifier/etherscan.rs @@ -79,7 +79,7 @@ impl EtherscanIdentifier { .clone() .map(|(address, metadata)| { println!("Compiling: {} {:?}", metadata.contract_name, address); - compile::compile_from_source(&metadata) + compile::compile_from_source(metadata) }) .collect::>(); diff --git a/forge/tests/it/repros.rs b/forge/tests/it/repros.rs index 4fa1d96057d57..4f5805c04e5fb 100644 --- a/forge/tests/it/repros.rs +++ b/forge/tests/it/repros.rs @@ -169,10 +169,8 @@ fn test_issue_3347() { ], anonymous: false, }; - let raw_log = RawLog { - topics: test.logs[0].topics.clone(), - data: test.logs[0].data.clone().to_vec().into(), - }; + let raw_log = + RawLog { topics: test.logs[0].topics.clone(), data: test.logs[0].data.clone().to_vec() }; let log = event.parse_log(raw_log).unwrap(); assert_eq!( log,