From f3a1332f1ed77715fe58c4b452aa4931f90428e0 Mon Sep 17 00:00:00 2001 From: grandizzy Date: Mon, 11 Nov 2024 10:50:16 +0200 Subject: [PATCH 1/3] fix(cast run): decode traces for non mainnet --- crates/cast/bin/cmd/run.rs | 5 +++++ crates/evm/core/src/opts.rs | 12 ++++++++---- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/crates/cast/bin/cmd/run.rs b/crates/cast/bin/cmd/run.rs index 11c7b507e355..dec7dc169ac3 100644 --- a/crates/cast/bin/cmd/run.rs +++ b/crates/cast/bin/cmd/run.rs @@ -58,6 +58,10 @@ pub struct RunArgs { #[arg(long, short)] label: Vec, + /// Etherscan API key. + #[arg(long)] + pub etherscan_api_key: Option, + #[command(flatten)] rpc: RpcOpts, @@ -98,6 +102,7 @@ impl RunArgs { let figment = Into::::into(&self.rpc).merge(&self); let evm_opts = figment.extract::()?; let mut config = Config::try_from(figment)?.sanitized(); + config.etherscan_api_key = self.etherscan_api_key; let compute_units_per_second = if self.no_rate_limit { Some(u64::MAX) } else { self.compute_units_per_second }; diff --git a/crates/evm/core/src/opts.rs b/crates/evm/core/src/opts.rs index 7a41d075641b..17ecbcca170e 100644 --- a/crates/evm/core/src/opts.rs +++ b/crates/evm/core/src/opts.rs @@ -192,10 +192,6 @@ impl EvmOpts { /// Returns the chain ID from the RPC, if any. pub async fn get_remote_chain_id(&self) -> Option { if let Some(ref url) = self.fork_url { - if url.contains("mainnet") { - trace!(?url, "auto detected mainnet chain"); - return Some(Chain::mainnet()); - } trace!(?url, "retrieving chain via eth_chainId"); let provider = ProviderBuilder::new(url.as_str()) .compute_units_per_second(self.get_compute_units_per_second()) @@ -206,6 +202,14 @@ impl EvmOpts { if let Ok(id) = provider.get_chain_id().await { return Some(Chain::from(id)); } + + // Provider URLs could be of the format `{CHAIN_IDENTIFIER}-mainnet` + // (e.g. Alchemy `opt-mainnet`, `arb-mainnet`), fallback to this method only + // if we're not able to retrieve chain id from `RetryProvider`. + if url.contains("mainnet") { + trace!(?url, "auto detected mainnet chain"); + return Some(Chain::mainnet()); + } } None From 12bbe9e9a6ef64da82e364eee1095e5b11433609 Mon Sep 17 00:00:00 2001 From: grandizzy Date: Mon, 11 Nov 2024 11:27:35 +0200 Subject: [PATCH 2/3] Add test --- crates/cast/tests/cli/main.rs | 31 +++++++++++++++++++++++++++++-- crates/test-utils/src/rpc.rs | 16 +++++++++++++++- 2 files changed, 44 insertions(+), 3 deletions(-) diff --git a/crates/cast/tests/cli/main.rs b/crates/cast/tests/cli/main.rs index 6fb3ddb73c58..4fd5ebd89e81 100644 --- a/crates/cast/tests/cli/main.rs +++ b/crates/cast/tests/cli/main.rs @@ -6,8 +6,8 @@ use anvil::{EthereumHardfork, NodeConfig}; use foundry_test_utils::{ casttest, file, rpc::{ - next_http_rpc_endpoint, next_mainnet_etherscan_api_key, next_rpc_endpoint, - next_ws_rpc_endpoint, + next_etherscan_api_key, next_http_rpc_endpoint, next_mainnet_etherscan_api_key, + next_rpc_endpoint, next_ws_rpc_endpoint, }, str, util::OutputExt, @@ -1503,3 +1503,30 @@ casttest!(fetch_constructor_args_from_etherscan, |_prj, cmd| { "#]]); }); + +// +casttest!(test_non_mainnet_traces, |_prj, cmd| { + cmd.args([ + "run", + "0x8346762a8c1d7ce70be23c1b68ff920ffb6bca8fd62323e6c1d108f209e0b45d", + "--rpc-url", + next_rpc_endpoint(NamedChain::Optimism).as_str(), + "--etherscan-api-key", + next_etherscan_api_key(NamedChain::Optimism).as_str(), + ]) + .assert_success() + .stdout_eq(str![[r#" +Executing previous transactions from the block. +Traces: + [429891] FuturesMarket::modifyPositionWithTracking(79573547589616810 [7.957e16], 0x4b57454e54410000000000000000000000000000000000000000000000000000) + ├─ [9111] SystemStatus::requireFuturesMarketActive(0x7345544800000000000000000000000000000000000000000000000000000000) [staticcall] + │ └─ ← [Stop] + ├─ [2789] SystemStatus::requireSynthActive(0x7345544800000000000000000000000000000000000000000000000000000000) [staticcall] + │ └─ ← [Stop] + ├─ [70705] ExchangeCircuitBreaker::rateWithBreakCircuit(0x7345544800000000000000000000000000000000000000000000000000000000) + │ ├─ [399] SystemStatus::systemSuspended() [staticcall] + │ │ └─ ← [Return] false +... + +"#]]); +}); diff --git a/crates/test-utils/src/rpc.rs b/crates/test-utils/src/rpc.rs index 7f0742143e4c..a974e395406d 100644 --- a/crates/test-utils/src/rpc.rs +++ b/crates/test-utils/src/rpc.rs @@ -1,6 +1,6 @@ //! RPC API keys utilities. -use foundry_config::NamedChain; +use foundry_config::{NamedChain, NamedChain::Optimism}; use rand::seq::SliceRandom; use std::sync::{ atomic::{AtomicUsize, Ordering}, @@ -75,6 +75,10 @@ static ETHERSCAN_MAINNET_KEYS: LazyLock> = LazyLock::new(|| { keys }); +// List of etherscan keys for Optimism. +static ETHERSCAN_OPTIMISM_KEYS: LazyLock> = + LazyLock::new(|| vec!["JQNGFHINKS1W7Y5FRXU4SPBYF43J3NYK46"]); + /// Returns the next index to use. fn next() -> usize { static NEXT_INDEX: AtomicUsize = AtomicUsize::new(0); @@ -127,6 +131,16 @@ pub fn next_mainnet_etherscan_api_key() -> String { ETHERSCAN_MAINNET_KEYS[idx].to_string() } +/// Returns the next etherscan api key for given chain. +pub fn next_etherscan_api_key(chain: NamedChain) -> String { + let keys = match chain { + Optimism => ÐERSCAN_OPTIMISM_KEYS, + _ => ÐERSCAN_MAINNET_KEYS, + }; + let idx = next() % keys.len(); + keys[idx].to_string() +} + fn next_url(is_ws: bool, chain: NamedChain) -> String { use NamedChain::*; From 26ee3d7f397722f91cb67b892ce1780bfafea34c Mon Sep 17 00:00:00 2001 From: grandizzy Date: Mon, 11 Nov 2024 12:54:58 +0200 Subject: [PATCH 3/3] Changes after review: use EtherscanOpts, remove short -e from evm_version Simplify test to avoid rate limiting. --- crates/cast/bin/cmd/run.rs | 14 ++++++++------ crates/cast/tests/cli/main.rs | 18 ++++++++---------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/crates/cast/bin/cmd/run.rs b/crates/cast/bin/cmd/run.rs index dec7dc169ac3..7389d1f35e4d 100644 --- a/crates/cast/bin/cmd/run.rs +++ b/crates/cast/bin/cmd/run.rs @@ -5,7 +5,7 @@ use cast::revm::primitives::EnvWithHandlerCfg; use clap::Parser; use eyre::{Result, WrapErr}; use foundry_cli::{ - opts::RpcOpts, + opts::{EtherscanOpts, RpcOpts}, utils::{handle_traces, init_progress, TraceResult}, }; use foundry_common::{is_known_system_sender, SYSTEM_TRANSACTION_TYPE}; @@ -58,9 +58,8 @@ pub struct RunArgs { #[arg(long, short)] label: Vec, - /// Etherscan API key. - #[arg(long)] - pub etherscan_api_key: Option, + #[command(flatten)] + etherscan: EtherscanOpts, #[command(flatten)] rpc: RpcOpts, @@ -68,7 +67,7 @@ pub struct RunArgs { /// The EVM version to use. /// /// Overrides the version specified in the config. - #[arg(long, short)] + #[arg(long)] evm_version: Option, /// Sets the number of assumed available compute units per second for this provider @@ -102,7 +101,6 @@ impl RunArgs { let figment = Into::::into(&self.rpc).merge(&self); let evm_opts = figment.extract::()?; let mut config = Config::try_from(figment)?.sanitized(); - config.etherscan_api_key = self.etherscan_api_key; let compute_units_per_second = if self.no_rate_limit { Some(u64::MAX) } else { self.compute_units_per_second }; @@ -274,6 +272,10 @@ impl figment::Provider for RunArgs { map.insert("alphanet".into(), self.alphanet.into()); } + if let Some(api_key) = &self.etherscan.key { + map.insert("etherscan_api_key".into(), api_key.as_str().into()); + } + if let Some(evm_version) = self.evm_version { map.insert("evm_version".into(), figment::value::Value::serialize(evm_version)?); } diff --git a/crates/cast/tests/cli/main.rs b/crates/cast/tests/cli/main.rs index 4fd5ebd89e81..29527f7dc3bb 100644 --- a/crates/cast/tests/cli/main.rs +++ b/crates/cast/tests/cli/main.rs @@ -1505,10 +1505,11 @@ casttest!(fetch_constructor_args_from_etherscan, |_prj, cmd| { }); // -casttest!(test_non_mainnet_traces, |_prj, cmd| { +casttest!(test_non_mainnet_traces, |prj, cmd| { + prj.clear(); cmd.args([ "run", - "0x8346762a8c1d7ce70be23c1b68ff920ffb6bca8fd62323e6c1d108f209e0b45d", + "0xa003e419e2d7502269eb5eda56947b580120e00abfd5b5460d08f8af44a0c24f", "--rpc-url", next_rpc_endpoint(NamedChain::Optimism).as_str(), "--etherscan-api-key", @@ -1518,14 +1519,11 @@ casttest!(test_non_mainnet_traces, |_prj, cmd| { .stdout_eq(str![[r#" Executing previous transactions from the block. Traces: - [429891] FuturesMarket::modifyPositionWithTracking(79573547589616810 [7.957e16], 0x4b57454e54410000000000000000000000000000000000000000000000000000) - ├─ [9111] SystemStatus::requireFuturesMarketActive(0x7345544800000000000000000000000000000000000000000000000000000000) [staticcall] - │ └─ ← [Stop] - ├─ [2789] SystemStatus::requireSynthActive(0x7345544800000000000000000000000000000000000000000000000000000000) [staticcall] - │ └─ ← [Stop] - ├─ [70705] ExchangeCircuitBreaker::rateWithBreakCircuit(0x7345544800000000000000000000000000000000000000000000000000000000) - │ ├─ [399] SystemStatus::systemSuspended() [staticcall] - │ │ └─ ← [Return] false + [33841] FiatTokenProxy::fallback(0x111111125421cA6dc452d289314280a0f8842A65, 164054805 [1.64e8]) + ├─ [26673] FiatTokenV2_2::approve(0x111111125421cA6dc452d289314280a0f8842A65, 164054805 [1.64e8]) [delegatecall] + │ ├─ emit Approval(owner: 0x9a95Af47C51562acfb2107F44d7967DF253197df, spender: 0x111111125421cA6dc452d289314280a0f8842A65, value: 164054805 [1.64e8]) + │ └─ ← [Return] true + └─ ← [Return] true ... "#]]);