From 97e23a6c8a5f4b5d7e3d8649edd00f58e1326c24 Mon Sep 17 00:00:00 2001 From: Iain Nash Date: Sun, 13 Apr 2025 23:25:47 -0400 Subject: [PATCH 1/7] Adding support to etherscanv2 --- crates/verify/src/etherscan/mod.rs | 96 +++++++++++++++++++++++++++++- crates/verify/src/provider.rs | 21 +++++-- 2 files changed, 108 insertions(+), 9 deletions(-) diff --git a/crates/verify/src/etherscan/mod.rs b/crates/verify/src/etherscan/mod.rs index aad51093886d7..15233d57fc4bc 100644 --- a/crates/verify/src/etherscan/mod.rs +++ b/crates/verify/src/etherscan/mod.rs @@ -11,7 +11,7 @@ use eyre::{eyre, Context, OptionExt, Result}; use foundry_block_explorers::{ errors::EtherscanError, utils::lookup_compiler_version, - verify::{CodeFormat, VerifyContract}, + verify::{self, CodeFormat, VerifyContract}, Client, }; use foundry_cli::utils::{get_provider, read_constructor_args_file, LoadConfig}; @@ -261,7 +261,13 @@ impl EtherscanVerificationProvider { let etherscan_config = config.get_etherscan_config_with_chain(Some(chain))?; let etherscan_api_url = verifier_url - .or_else(|| etherscan_config.as_ref().map(|c| c.api_url.as_str())) + .or_else(|| { + if verifier_type.is_etherscan_v2() { + None + } else { + etherscan_config.as_ref().map(|c| c.api_url.as_str()) + } + }) .map(str::to_owned); let api_url = etherscan_api_url.as_deref(); @@ -272,8 +278,14 @@ impl EtherscanVerificationProvider { let etherscan_key = etherscan_key.or_else(|| etherscan_config.as_ref().map(|c| c.key.as_str())); + + let etherscan_api_version = if verifier_type.is_etherscan_v2() { + foundry_block_explorers::EtherscanApiVersion::V2 + } else { + foundry_block_explorers::EtherscanApiVersion::V1 + }; - let mut builder = Client::builder(); + let mut builder = Client::builder().with_api_version(etherscan_api_version); builder = if let Some(api_url) = api_url { // we don't want any trailing slashes because this can cause cloudflare issues: @@ -466,6 +478,7 @@ async fn ensure_solc_build_metadata(version: Version) -> Result { mod tests { use super::*; use clap::Parser; + use foundry_block_explorers::EtherscanApiVersion; use foundry_common::fs; use foundry_test_utils::{forgetest_async, str}; use tempfile::tempdir; @@ -539,6 +552,83 @@ mod tests { assert!(format!("{client:?}").contains("dummykey")); } + #[test] + fn can_extract_etherscan_v2_verify_config() { + let temp = tempdir().unwrap(); + let root = temp.path(); + + let config = r#" + [profile.default] + + [etherscan] + mumbai = { key = "dummykey", chain = 80001, url = "https://api-testnet.polygonscan.com/" } + "#; + + let toml_file = root.join(Config::FILE_NAME); + fs::write(toml_file, config).unwrap(); + + let args: VerifyArgs = VerifyArgs::parse_from([ + "foundry-cli", + "0xd8509bee9c9bf012282ad33aba0d87241baf5064", + "src/Counter.sol:Counter", + "--verifier", + "etherscan-v2", + "--chain", + "mumbai", + "--root", + root.as_os_str().to_str().unwrap(), + ]); + + let config = args.load_config().unwrap(); + + let etherscan = EtherscanVerificationProvider::default(); + + let client = etherscan + .client( + args.etherscan.chain.unwrap_or_default(), + &args.verifier.verifier, + args.verifier.verifier_url.as_deref(), + args.etherscan.key().as_deref(), + &config, + ) + .unwrap(); + + assert_eq!(client.etherscan_api_url().as_str(), "https://api.etherscan.io/v2/api?chainid=80001"); + assert!(format!("{client:?}").contains("dummykey")); + + let args: VerifyArgs = VerifyArgs::parse_from([ + "foundry-cli", + "0xd8509bee9c9bf012282ad33aba0d87241baf5064", + "src/Counter.sol:Counter", + "--verifier", + "etherscan-v2", + "--chain", + "mumbai", + "--verifier-url", + "https://verifier-url.com/", + "--root", + root.as_os_str().to_str().unwrap(), + ]); + + let config = args.load_config().unwrap(); + + assert_eq!(args.verifier.verifier, VerificationProviderType::EtherscanV2); + + let etherscan = EtherscanVerificationProvider::default(); + let client = etherscan + .client( + args.etherscan.chain.unwrap_or_default(), + &args.verifier.verifier, + args.verifier.verifier_url.as_deref(), + args.etherscan.key().as_deref(), + &config, + ) + .unwrap(); + assert_eq!(client.etherscan_api_url().as_str(), "https://verifier-url.com/"); + assert_eq!(*client.etherscan_api_version(), EtherscanApiVersion::V2); + assert!(format!("{client:?}").contains("dummykey")); + } + #[tokio::test(flavor = "multi_thread")] async fn fails_on_disabled_cache_and_missing_info() { let temp = tempdir().unwrap(); diff --git a/crates/verify/src/provider.rs b/crates/verify/src/provider.rs index 74d2094c41b83..b290916670b03 100644 --- a/crates/verify/src/provider.rs +++ b/crates/verify/src/provider.rs @@ -123,11 +123,12 @@ impl FromStr for VerificationProviderType { fn from_str(s: &str) -> Result { match s { - "e" | "etherscan" => Ok(Self::Etherscan), - "s" | "sourcify" => Ok(Self::Sourcify), - "b" | "blockscout" => Ok(Self::Blockscout), - "o" | "oklink" => Ok(Self::Oklink), - "c" | "custom" => Ok(Self::Custom), + "e" | "etherscan" => Ok(Self::Etherscan), + "ev2" | "etherscan-v2" => Ok(Self::EtherscanV2), + "s" | "sourcify" => Ok(Self::Sourcify), + "b" | "blockscout" => Ok(Self::Blockscout), + "o" | "oklink" => Ok(Self::Oklink), + "c" | "custom" => Ok(Self::Custom), _ => Err(format!("Unknown provider: {s}")), } } @@ -139,6 +140,9 @@ impl fmt::Display for VerificationProviderType { Self::Etherscan => { write!(f, "etherscan")?; } + Self::EtherscanV2 => { + write!(f, "etherscan-v2")?; + } Self::Sourcify => { write!(f, "sourcify")?; } @@ -159,6 +163,7 @@ impl fmt::Display for VerificationProviderType { #[derive(Clone, Debug, Default, PartialEq, Eq, clap::ValueEnum)] pub enum VerificationProviderType { Etherscan, + EtherscanV2, #[default] Sourcify, Blockscout, @@ -208,6 +213,10 @@ impl VerificationProviderType { } pub fn is_etherscan(&self) -> bool { - matches!(self, Self::Etherscan) + matches!(self, Self::Etherscan) || matches!(self, Self::EtherscanV2) + } + + pub fn is_etherscan_v2(&self) -> bool { + matches!(self, Self::EtherscanV2) } } From a98d6d0bd11914d7229921ace8e09495812078da Mon Sep 17 00:00:00 2001 From: Iain Nash Date: Sun, 13 Apr 2025 23:40:35 -0400 Subject: [PATCH 2/7] clippy+fmt --- crates/verify/src/etherscan/mod.rs | 11 ++++++----- crates/verify/src/provider.rs | 10 +++++----- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/crates/verify/src/etherscan/mod.rs b/crates/verify/src/etherscan/mod.rs index 15233d57fc4bc..7a4ac9d76deaa 100644 --- a/crates/verify/src/etherscan/mod.rs +++ b/crates/verify/src/etherscan/mod.rs @@ -11,7 +11,7 @@ use eyre::{eyre, Context, OptionExt, Result}; use foundry_block_explorers::{ errors::EtherscanError, utils::lookup_compiler_version, - verify::{self, CodeFormat, VerifyContract}, + verify::{CodeFormat, VerifyContract}, Client, }; use foundry_cli::utils::{get_provider, read_constructor_args_file, LoadConfig}; @@ -275,10 +275,8 @@ impl EtherscanVerificationProvider { .as_ref() .and_then(|c| c.browser_url.as_deref()) .or_else(|| chain.etherscan_urls().map(|(_, url)| url)); - let etherscan_key = etherscan_key.or_else(|| etherscan_config.as_ref().map(|c| c.key.as_str())); - let etherscan_api_version = if verifier_type.is_etherscan_v2() { foundry_block_explorers::EtherscanApiVersion::V2 } else { @@ -593,7 +591,10 @@ mod tests { ) .unwrap(); - assert_eq!(client.etherscan_api_url().as_str(), "https://api.etherscan.io/v2/api?chainid=80001"); + assert_eq!( + client.etherscan_api_url().as_str(), + "https://api.etherscan.io/v2/api?chainid=80001" + ); assert!(format!("{client:?}").contains("dummykey")); let args: VerifyArgs = VerifyArgs::parse_from([ @@ -611,7 +612,7 @@ mod tests { ]); let config = args.load_config().unwrap(); - + assert_eq!(args.verifier.verifier, VerificationProviderType::EtherscanV2); let etherscan = EtherscanVerificationProvider::default(); diff --git a/crates/verify/src/provider.rs b/crates/verify/src/provider.rs index b290916670b03..1364aac4462de 100644 --- a/crates/verify/src/provider.rs +++ b/crates/verify/src/provider.rs @@ -123,12 +123,12 @@ impl FromStr for VerificationProviderType { fn from_str(s: &str) -> Result { match s { - "e" | "etherscan" => Ok(Self::Etherscan), + "e" | "etherscan" => Ok(Self::Etherscan), "ev2" | "etherscan-v2" => Ok(Self::EtherscanV2), - "s" | "sourcify" => Ok(Self::Sourcify), - "b" | "blockscout" => Ok(Self::Blockscout), - "o" | "oklink" => Ok(Self::Oklink), - "c" | "custom" => Ok(Self::Custom), + "s" | "sourcify" => Ok(Self::Sourcify), + "b" | "blockscout" => Ok(Self::Blockscout), + "o" | "oklink" => Ok(Self::Oklink), + "c" | "custom" => Ok(Self::Custom), _ => Err(format!("Unknown provider: {s}")), } } From 395712a30cf108b21e8a50bd3c745cf3dce81260 Mon Sep 17 00:00:00 2001 From: Iain Nash Date: Tue, 29 Apr 2025 23:04:15 -0400 Subject: [PATCH 3/7] Adding default for v2 and updating configuration to parse etherscan api version from config --- crates/config/src/etherscan.rs | 72 +++++++++++++++++++++++++---- crates/config/src/lib.rs | 73 +++++++++++++++++++++++++++--- crates/verify/src/etherscan/mod.rs | 2 +- 3 files changed, 131 insertions(+), 16 deletions(-) diff --git a/crates/config/src/etherscan.rs b/crates/config/src/etherscan.rs index 099dc0e344c2f..0a9f6a292aebb 100644 --- a/crates/config/src/etherscan.rs +++ b/crates/config/src/etherscan.rs @@ -10,6 +10,8 @@ use figment::{ Error, Metadata, Profile, Provider, }; use heck::ToKebabCase; +use foundry_block_explorers::EtherscanApiVersion; +use inflector::Inflector; use serde::{Deserialize, Deserializer, Serialize, Serializer}; use std::{ collections::BTreeMap, @@ -173,6 +175,9 @@ pub struct EtherscanConfig { /// Etherscan API URL #[serde(default, skip_serializing_if = "Option::is_none")] pub url: Option, + /// Etherscan API Version. Defaults to v2 + #[serde(default, skip_serializing_if = "Option::is_none")] + pub api_version: Option, /// The etherscan API KEY that's required to make requests pub key: EtherscanApiKey, } @@ -188,7 +193,7 @@ impl EtherscanConfig { self, alias: Option<&str>, ) -> Result { - let Self { chain, mut url, key } = self; + let Self { chain, mut url, key, api_version } = self; if let Some(url) = &mut url { *url = interpolate(url)?; @@ -219,17 +224,27 @@ impl EtherscanConfig { match (chain, url) { (Some(chain), Some(api_url)) => Ok(ResolvedEtherscanConfig { api_url, + api_version: api_version.map(|v| v.to_string()), browser_url: chain.etherscan_urls().map(|(_, url)| url.to_string()), key, chain: Some(chain), }), - (Some(chain), None) => ResolvedEtherscanConfig::create(key, chain).ok_or_else(|| { + (Some(chain), None) => ResolvedEtherscanConfig::create( + key, + chain, + api_version.map(|v| v.to_string()), + ) + .ok_or_else(|| { let msg = alias.map(|a| format!(" `{a}`")).unwrap_or_default(); EtherscanConfigError::UnknownChain(msg, chain) }), - (None, Some(api_url)) => { - Ok(ResolvedEtherscanConfig { api_url, browser_url: None, key, chain: None }) - } + (None, Some(api_url)) => Ok(ResolvedEtherscanConfig { + api_url, + browser_url: None, + key, + chain: None, + api_version: api_version.map(|v| v.to_string()), + }), (None, None) => { let msg = alias .map(|a| format!(" for Etherscan config with unknown alias `{a}`")) @@ -251,6 +266,9 @@ pub struct ResolvedEtherscanConfig { pub browser_url: Option, /// The resolved API key. pub key: String, + /// Etherscan API Version. + #[serde(default, skip_serializing_if = "Option::is_none")] + pub api_version: Option, /// The chain name or EIP-155 chain ID. #[serde(default, skip_serializing_if = "Option::is_none")] pub chain: Option, @@ -258,11 +276,16 @@ pub struct ResolvedEtherscanConfig { impl ResolvedEtherscanConfig { /// Creates a new instance using the api key and chain - pub fn create(api_key: impl Into, chain: impl Into) -> Option { + pub fn create( + api_key: impl Into, + chain: impl Into, + api_version: Option>, + ) -> Option { let chain = chain.into(); let (api_url, browser_url) = chain.etherscan_urls()?; Some(Self { api_url: api_url.to_string(), + api_version: api_version.map(|v| v.into()), browser_url: Some(browser_url.to_string()), key: api_key.into(), chain: Some(chain), @@ -294,7 +317,7 @@ impl ResolvedEtherscanConfig { self, ) -> Result { - let Self { api_url, browser_url, key: api_key, chain } = self; + let Self { api_url, browser_url, key: api_key, chain, api_version } = self; let (mainnet_api, mainnet_url) = NamedChain::Mainnet.etherscan_urls().expect("exist; qed"); let cache = chain @@ -310,12 +333,14 @@ impl ResolvedEtherscanConfig { } let api_url = into_url(&api_url)?; + let parsed_api_version = EtherscanApiVersion::try_from(api_version.unwrap_or_default())?; let client = reqwest::Client::builder() .user_agent(ETHERSCAN_USER_AGENT) .tls_built_in_root_certs(api_url.scheme() == "https") .build()?; foundry_block_explorers::Client::builder() .with_client(client) + .with_api_version(parsed_api_version) .with_api_key(api_key) .with_api_url(api_url)? // the browser url is not used/required by the client so we can simply set the @@ -423,12 +448,36 @@ mod tests { chain: Some(Mainnet.into()), url: None, key: EtherscanApiKey::Key("ABCDEFG".to_string()), + api_version: None, }, ); let mut resolved = configs.resolved(); let config = resolved.remove("mainnet").unwrap().unwrap(); - let _ = config.into_client().unwrap(); + // None version = None + assert_eq!(config.api_version, None); + let client = config.into_client().unwrap(); + assert_eq!(*client.etherscan_api_version(), EtherscanApiVersion::V2); + } + + #[test] + fn can_create_v1_client_via_chain() { + let mut configs = EtherscanConfigs::default(); + configs.insert( + "mainnet".to_string(), + EtherscanConfig { + chain: Some(Mainnet.into()), + url: None, + api_version: Some(EtherscanApiVersion::V1), + key: EtherscanApiKey::Key("ABCDEG".to_string()), + }, + ); + + let mut resolved = configs.resolved(); + let config = resolved.remove("mainnet").unwrap().unwrap(); + assert_eq!(config.api_version, Some("v1".to_string())); + let client = config.into_client().unwrap(); + assert_eq!(*client.etherscan_api_version(), EtherscanApiVersion::V1); } #[test] @@ -440,6 +489,7 @@ mod tests { chain: Some(Mainnet.into()), url: Some("https://api.etherscan.io/api".to_string()), key: EtherscanApiKey::Key("ABCDEFG".to_string()), + api_version: None, }, ); @@ -457,6 +507,7 @@ mod tests { EtherscanConfig { chain: Some(Mainnet.into()), url: Some("https://api.etherscan.io/api".to_string()), + api_version: None, key: EtherscanApiKey::Env(format!("${{{env}}}")), }, ); @@ -470,7 +521,8 @@ mod tests { let mut resolved = configs.resolved(); let config = resolved.remove("mainnet").unwrap().unwrap(); assert_eq!(config.key, "ABCDEFG"); - let _ = config.into_client().unwrap(); + let client = config.into_client().unwrap(); + assert_eq!(*client.etherscan_api_version(), EtherscanApiVersion::V2); std::env::remove_var(env); } @@ -484,6 +536,7 @@ mod tests { chain: None, url: Some("https://api.etherscan.io/api".to_string()), key: EtherscanApiKey::Key("ABCDEFG".to_string()), + api_version: None, }, ); @@ -498,6 +551,7 @@ mod tests { chain: None, url: Some("https://api.etherscan.io/api".to_string()), key: EtherscanApiKey::Key("ABCDEFG".to_string()), + api_version: None, }; let resolved = config.clone().resolve(Some("base_sepolia")).unwrap(); assert_eq!(resolved.chain, Some(Chain::base_sepolia())); diff --git a/crates/config/src/lib.rs b/crates/config/src/lib.rs index b7d3f0f7e5c0d..2b8c25d362bc1 100644 --- a/crates/config/src/lib.rs +++ b/crates/config/src/lib.rs @@ -1137,9 +1137,9 @@ impl Config { /// Whether caching should be enabled for the given chain id pub fn enable_caching(&self, endpoint: &str, chain_id: impl Into) -> bool { - !self.no_storage_caching && - self.rpc_storage_caching.enable_for_chain_id(chain_id.into()) && - self.rpc_storage_caching.enable_for_endpoint(endpoint) + !self.no_storage_caching + && self.rpc_storage_caching.enable_for_chain_id(chain_id.into()) + && self.rpc_storage_caching.enable_for_endpoint(endpoint) } /// Returns the `ProjectPathsConfig` sub set of the config. @@ -1403,7 +1403,11 @@ impl Config { // etherscan fallback via API key if let Some(key) = self.etherscan_api_key.as_ref() { let chain = chain.or(self.chain).unwrap_or_default(); - return Ok(ResolvedEtherscanConfig::create(key, chain)); + return Ok(ResolvedEtherscanConfig::create( + key, + chain, + None::, + )); } Ok(None) @@ -2008,8 +2012,8 @@ impl Config { let file_name = block.file_name(); let filepath = if file_type.is_dir() { block.path().join("storage.json") - } else if file_type.is_file() && - file_name.to_string_lossy().chars().all(char::is_numeric) + } else if file_type.is_file() + && file_name.to_string_lossy().chars().all(char::is_numeric) { block.path() } else { @@ -3077,6 +3081,7 @@ mod tests { api_url: mainnet_urls.0.to_string(), chain: Some(NamedChain::Mainnet.into()), browser_url: Some(mainnet_urls.1.to_string()), + api_version: None, key: "FX42Z3BBJJEWXWGYV2X1CIPRSCN".to_string(), } ), @@ -3086,6 +3091,62 @@ mod tests { api_url: mb_urls.0.to_string(), chain: Some(Moonbeam.into()), browser_url: Some(mb_urls.1.to_string()), + api_version: None, + key: "123456789".to_string(), + } + ), + ]) + ); + + Ok(()) + }); + } + + #[test] + fn test_resolve_etherscan_with_versions() { + figment::Jail::expect_with(|jail| { + jail.create_file( + "foundry.toml", + r#" + [profile.default] + + [etherscan] + mainnet = { key = "FX42Z3BBJJEWXWGYV2X1CIPRSCN", api_version = "v2" } + moonbeam = { key = "${_CONFIG_ETHERSCAN_MOONBEAM}", api_version = "v1" } + "#, + )?; + + let config = Config::load().unwrap(); + + assert!(config.etherscan.clone().resolved().has_unresolved()); + + jail.set_env("_CONFIG_ETHERSCAN_MOONBEAM", "123456789"); + + let configs = config.etherscan.resolved(); + assert!(!configs.has_unresolved()); + + let mb_urls = Moonbeam.etherscan_urls().unwrap(); + let mainnet_urls = NamedChain::Mainnet.etherscan_urls().unwrap(); + assert_eq!( + configs, + ResolvedEtherscanConfigs::new([ + ( + "mainnet", + ResolvedEtherscanConfig { + api_url: mainnet_urls.0.to_string(), + chain: Some(NamedChain::Mainnet.into()), + browser_url: Some(mainnet_urls.1.to_string()), + api_version: Some("v2".to_string()), + key: "FX42Z3BBJJEWXWGYV2X1CIPRSCN".to_string(), + } + ), + ( + "moonbeam", + ResolvedEtherscanConfig { + api_url: mb_urls.0.to_string(), + chain: Some(Moonbeam.into()), + browser_url: Some(mb_urls.1.to_string()), + api_version: Some("v1".to_string()), key: "123456789".to_string(), } ), diff --git a/crates/verify/src/etherscan/mod.rs b/crates/verify/src/etherscan/mod.rs index 7a4ac9d76deaa..2907bcc1d0382 100644 --- a/crates/verify/src/etherscan/mod.rs +++ b/crates/verify/src/etherscan/mod.rs @@ -593,7 +593,7 @@ mod tests { assert_eq!( client.etherscan_api_url().as_str(), - "https://api.etherscan.io/v2/api?chainid=80001" + "https://api.etherscan.io/v2/api" ); assert!(format!("{client:?}").contains("dummykey")); From 5866805a31a9b7c0bfbb8ed860ec88f0225b56db Mon Sep 17 00:00:00 2001 From: Iain Nash Date: Tue, 29 Apr 2025 23:52:44 -0400 Subject: [PATCH 4/7] Updating api_version to use new variable and fix merge --- crates/config/src/etherscan.rs | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/crates/config/src/etherscan.rs b/crates/config/src/etherscan.rs index 0a9f6a292aebb..26c2ed7587876 100644 --- a/crates/config/src/etherscan.rs +++ b/crates/config/src/etherscan.rs @@ -9,9 +9,8 @@ use figment::{ value::{Dict, Map}, Error, Metadata, Profile, Provider, }; -use heck::ToKebabCase; use foundry_block_explorers::EtherscanApiVersion; -use inflector::Inflector; +use heck::ToKebabCase; use serde::{Deserialize, Deserializer, Serialize, Serializer}; use std::{ collections::BTreeMap, @@ -195,6 +194,8 @@ impl EtherscanConfig { ) -> Result { let Self { chain, mut url, key, api_version } = self; + let api_version_string = api_version.map(|v| v.to_string()); + if let Some(url) = &mut url { *url = interpolate(url)?; } @@ -224,26 +225,22 @@ impl EtherscanConfig { match (chain, url) { (Some(chain), Some(api_url)) => Ok(ResolvedEtherscanConfig { api_url, - api_version: api_version.map(|v| v.to_string()), + api_version: api_version_string, browser_url: chain.etherscan_urls().map(|(_, url)| url.to_string()), key, chain: Some(chain), }), - (Some(chain), None) => ResolvedEtherscanConfig::create( - key, - chain, - api_version.map(|v| v.to_string()), - ) - .ok_or_else(|| { - let msg = alias.map(|a| format!(" `{a}`")).unwrap_or_default(); - EtherscanConfigError::UnknownChain(msg, chain) - }), + (Some(chain), None) => ResolvedEtherscanConfig::create(key, chain, api_version_string) + .ok_or_else(|| { + let msg = alias.map(|a| format!(" `{a}`")).unwrap_or_default(); + EtherscanConfigError::UnknownChain(msg, chain) + }), (None, Some(api_url)) => Ok(ResolvedEtherscanConfig { api_url, browser_url: None, key, chain: None, - api_version: api_version.map(|v| v.to_string()), + api_version: api_version_string, }), (None, None) => { let msg = alias From 735212e261bbd9255fae2993361644b3ad496145 Mon Sep 17 00:00:00 2001 From: grandizzy Date: Wed, 30 Apr 2025 11:32:12 +0300 Subject: [PATCH 5/7] Use block explorer rev, fix fmt --- Cargo.lock | 3 +-- Cargo.toml | 1 + crates/config/src/lib.rs | 16 ++++++---------- crates/verify/src/etherscan/mod.rs | 5 +---- 4 files changed, 9 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9fec46ff7e011..55b48168a0859 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3698,8 +3698,7 @@ dependencies = [ [[package]] name = "foundry-block-explorers" version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "001678abc9895502532c8c4a1a225079c580655fc82a194e78b06dcf99f49b8c" +source = "git+https://github.com/foundry-rs/block-explorers?rev=8c03122#8c0312275fecf11b2258622fe1f7eba89e8f0a8e" dependencies = [ "alloy-chains", "alloy-json-abi", diff --git a/Cargo.toml b/Cargo.toml index 2d8aeadaa72f2..1fd0b89c1a59a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -324,6 +324,7 @@ jiff = "0.2" idna_adapter = "=1.1.0" [patch.crates-io] +foundry-block-explorers = { git = "https://github.com/foundry-rs/block-explorers", rev = "8c03122" } ## alloy-core # alloy-dyn-abi = { path = "../../alloy-rs/core/crates/dyn-abi" } # alloy-json-abi = { path = "../../alloy-rs/core/crates/json-abi" } diff --git a/crates/config/src/lib.rs b/crates/config/src/lib.rs index 2b8c25d362bc1..67bcff5e7e037 100644 --- a/crates/config/src/lib.rs +++ b/crates/config/src/lib.rs @@ -1137,9 +1137,9 @@ impl Config { /// Whether caching should be enabled for the given chain id pub fn enable_caching(&self, endpoint: &str, chain_id: impl Into) -> bool { - !self.no_storage_caching - && self.rpc_storage_caching.enable_for_chain_id(chain_id.into()) - && self.rpc_storage_caching.enable_for_endpoint(endpoint) + !self.no_storage_caching && + self.rpc_storage_caching.enable_for_chain_id(chain_id.into()) && + self.rpc_storage_caching.enable_for_endpoint(endpoint) } /// Returns the `ProjectPathsConfig` sub set of the config. @@ -1403,11 +1403,7 @@ impl Config { // etherscan fallback via API key if let Some(key) = self.etherscan_api_key.as_ref() { let chain = chain.or(self.chain).unwrap_or_default(); - return Ok(ResolvedEtherscanConfig::create( - key, - chain, - None::, - )); + return Ok(ResolvedEtherscanConfig::create(key, chain, None::)); } Ok(None) @@ -2012,8 +2008,8 @@ impl Config { let file_name = block.file_name(); let filepath = if file_type.is_dir() { block.path().join("storage.json") - } else if file_type.is_file() - && file_name.to_string_lossy().chars().all(char::is_numeric) + } else if file_type.is_file() && + file_name.to_string_lossy().chars().all(char::is_numeric) { block.path() } else { diff --git a/crates/verify/src/etherscan/mod.rs b/crates/verify/src/etherscan/mod.rs index 2907bcc1d0382..4a1d384a9298f 100644 --- a/crates/verify/src/etherscan/mod.rs +++ b/crates/verify/src/etherscan/mod.rs @@ -591,10 +591,7 @@ mod tests { ) .unwrap(); - assert_eq!( - client.etherscan_api_url().as_str(), - "https://api.etherscan.io/v2/api" - ); + assert_eq!(client.etherscan_api_url().as_str(), "https://api.etherscan.io/v2/api"); assert!(format!("{client:?}").contains("dummykey")); let args: VerifyArgs = VerifyArgs::parse_from([ From e2f4f112698760bf87b2402b78aa990592ee4764 Mon Sep 17 00:00:00 2001 From: Iain Nash Date: Wed, 30 Apr 2025 22:57:23 -0400 Subject: [PATCH 6/7] fix api version parsing --- crates/config/src/etherscan.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/crates/config/src/etherscan.rs b/crates/config/src/etherscan.rs index 26c2ed7587876..41161db2472c4 100644 --- a/crates/config/src/etherscan.rs +++ b/crates/config/src/etherscan.rs @@ -330,14 +330,16 @@ impl ResolvedEtherscanConfig { } let api_url = into_url(&api_url)?; - let parsed_api_version = EtherscanApiVersion::try_from(api_version.unwrap_or_default())?; + let parsed_api_version = api_version + .map(EtherscanApiVersion::try_from) + .transpose()?; let client = reqwest::Client::builder() .user_agent(ETHERSCAN_USER_AGENT) .tls_built_in_root_certs(api_url.scheme() == "https") .build()?; foundry_block_explorers::Client::builder() .with_client(client) - .with_api_version(parsed_api_version) + .with_api_version(parsed_api_version.unwrap_or_default()) .with_api_key(api_key) .with_api_url(api_url)? // the browser url is not used/required by the client so we can simply set the From 3d60de4aa858412e435df7b65d7ec572f5845d46 Mon Sep 17 00:00:00 2001 From: Iain Nash Date: Wed, 30 Apr 2025 23:05:09 -0400 Subject: [PATCH 7/7] fix fmt --- crates/config/src/etherscan.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/crates/config/src/etherscan.rs b/crates/config/src/etherscan.rs index 41161db2472c4..917946f1b2bc0 100644 --- a/crates/config/src/etherscan.rs +++ b/crates/config/src/etherscan.rs @@ -330,9 +330,7 @@ impl ResolvedEtherscanConfig { } let api_url = into_url(&api_url)?; - let parsed_api_version = api_version - .map(EtherscanApiVersion::try_from) - .transpose()?; + let parsed_api_version = api_version.map(EtherscanApiVersion::try_from).transpose()?; let client = reqwest::Client::builder() .user_agent(ETHERSCAN_USER_AGENT) .tls_built_in_root_certs(api_url.scheme() == "https")