diff --git a/crates/chisel/src/opts.rs b/crates/chisel/src/opts.rs index aba12f8920b01..b57314e09da5c 100644 --- a/crates/chisel/src/opts.rs +++ b/crates/chisel/src/opts.rs @@ -1,9 +1,6 @@ use clap::{Parser, Subcommand}; -use foundry_cli::opts::{BuildOpts, GlobalArgs}; -use foundry_common::{ - evm::EvmArgs, - version::{LONG_VERSION, SHORT_VERSION}, -}; +use foundry_cli::opts::{BuildOpts, EvmArgs, GlobalArgs}; +use foundry_common::version::{LONG_VERSION, SHORT_VERSION}; use std::path::PathBuf; foundry_config::impl_figment_convert!(Chisel, build, evm); diff --git a/crates/cli/src/opts/evm.rs b/crates/cli/src/opts/evm.rs new file mode 100644 index 0000000000000..e2e22f7d343ff --- /dev/null +++ b/crates/cli/src/opts/evm.rs @@ -0,0 +1,356 @@ +//! CLI arguments for configuring the EVM settings. + +use alloy_primitives::{Address, B256, U256}; +use clap::Parser; +use eyre::ContextCompat; +use foundry_config::{ + Chain, Config, + figment::{ + self, Metadata, Profile, Provider, + error::Kind::InvalidType, + value::{Dict, Map, Value}, + }, +}; +use serde::Serialize; + +use foundry_common::shell; + +/// `EvmArgs` and `EnvArgs` take the highest precedence in the Config/Figment hierarchy. +/// +/// All vars are opt-in, their default values are expected to be set by the +/// [`foundry_config::Config`], and are always present ([`foundry_config::Config::default`]) +/// +/// Both have corresponding types in the `evm_adapters` crate which have mandatory fields. +/// The expected workflow is +/// 1. load the [`foundry_config::Config`] +/// 2. merge with `EvmArgs` into a `figment::Figment` +/// 3. extract `evm_adapters::Opts` from the merged `Figment` +/// +/// # Example +/// +/// ```ignore +/// use foundry_config::Config; +/// use forge::executor::opts::EvmOpts; +/// use foundry_cli::opts::EvmArgs; +/// # fn t(args: EvmArgs) { +/// let figment = Config::figment_with_root(".").merge(args); +/// let opts = figment.extract::().unwrap(); +/// # } +/// ``` +#[derive(Clone, Debug, Default, Serialize, Parser)] +#[command(next_help_heading = "EVM options", about = None, long_about = None)] // override doc +pub struct EvmArgs { + /// Fetch state over a remote endpoint instead of starting from an empty state. + /// + /// If you want to fetch state from a specific block number, see --fork-block-number. + #[arg(long, short, visible_alias = "rpc-url", value_name = "URL")] + #[serde(rename = "eth_rpc_url", skip_serializing_if = "Option::is_none")] + pub fork_url: Option, + + /// Fetch state from a specific block number over a remote endpoint. + /// + /// See --fork-url. + #[arg(long, requires = "fork_url", value_name = "BLOCK")] + #[serde(skip_serializing_if = "Option::is_none")] + pub fork_block_number: Option, + + /// Number of retries. + /// + /// See --fork-url. + #[arg(long, requires = "fork_url", value_name = "RETRIES")] + #[serde(skip_serializing_if = "Option::is_none")] + pub fork_retries: Option, + + /// Initial retry backoff on encountering errors. + /// + /// See --fork-url. + #[arg(long, requires = "fork_url", value_name = "BACKOFF")] + #[serde(skip_serializing_if = "Option::is_none")] + pub fork_retry_backoff: Option, + + /// Explicitly disables the use of RPC caching. + /// + /// All storage slots are read entirely from the endpoint. + /// + /// This flag overrides the project's configuration file. + /// + /// See --fork-url. + #[arg(long)] + #[serde(skip)] + pub no_storage_caching: bool, + + /// The initial balance of deployed test contracts. + #[arg(long, value_name = "BALANCE")] + #[serde(skip_serializing_if = "Option::is_none")] + pub initial_balance: Option, + + /// The address which will be executing tests/scripts. + #[arg(long, value_name = "ADDRESS")] + #[serde(skip_serializing_if = "Option::is_none")] + pub sender: Option
, + + /// Enable the FFI cheatcode. + #[arg(long)] + #[serde(skip)] + pub ffi: bool, + + /// Use the create 2 factory in all cases including tests and non-broadcasting scripts. + #[arg(long)] + #[serde(skip)] + pub always_use_create_2_factory: bool, + + /// The CREATE2 deployer address to use, this will override the one in the config. + #[arg(long, value_name = "ADDRESS")] + #[serde(skip_serializing_if = "Option::is_none")] + pub create2_deployer: Option
, + + /// Sets the number of assumed available compute units per second for this provider + /// + /// default value: 330 + /// + /// See also --fork-url and + #[arg(long, alias = "cups", value_name = "CUPS", help_heading = "Fork config")] + #[serde(skip_serializing_if = "Option::is_none")] + pub compute_units_per_second: Option, + + /// Disables rate limiting for this node's provider. + /// + /// See also --fork-url and + #[arg( + long, + value_name = "NO_RATE_LIMITS", + help_heading = "Fork config", + visible_alias = "no-rate-limit" + )] + #[serde(skip)] + pub no_rpc_rate_limit: bool, + + /// All ethereum environment related arguments + #[command(flatten)] + #[serde(flatten)] + pub env: EnvArgs, + + /// Whether to enable isolation of calls. + /// In isolation mode all top-level calls are executed as a separate transaction in a separate + /// EVM context, enabling more precise gas accounting and transaction state changes. + #[arg(long)] + #[serde(skip)] + pub isolate: bool, + + /// Whether to enable Celo precompiles. + #[arg(long)] + #[serde(skip)] + pub celo: bool, +} + +// Make this set of options a `figment::Provider` so that it can be merged into the `Config` +impl Provider for EvmArgs { + fn metadata(&self) -> Metadata { + Metadata::named("Evm Opts Provider") + } + + fn data(&self) -> Result, figment::Error> { + let value = Value::serialize(self)?; + let error = InvalidType(value.to_actual(), "map".into()); + let mut dict = value.into_dict().ok_or(error)?; + + if shell::verbosity() > 0 { + // need to merge that manually otherwise `from_occurrences` does not work + dict.insert("verbosity".to_string(), shell::verbosity().into()); + } + + if self.ffi { + dict.insert("ffi".to_string(), self.ffi.into()); + } + + if self.isolate { + dict.insert("isolate".to_string(), self.isolate.into()); + } + + if self.celo { + dict.insert("celo".to_string(), self.celo.into()); + } + + if self.always_use_create_2_factory { + dict.insert( + "always_use_create_2_factory".to_string(), + self.always_use_create_2_factory.into(), + ); + } + + if self.no_storage_caching { + dict.insert("no_storage_caching".to_string(), self.no_storage_caching.into()); + } + + if self.no_rpc_rate_limit { + dict.insert("no_rpc_rate_limit".to_string(), self.no_rpc_rate_limit.into()); + } + + if let Some(fork_url) = &self.fork_url { + dict.insert("eth_rpc_url".to_string(), fork_url.clone().into()); + } + + Ok(Map::from([(Config::selected_profile(), dict)])) + } +} + +/// Configures the executor environment during tests. +#[derive(Clone, Debug, Default, Serialize, Parser)] +#[command(next_help_heading = "Executor environment config")] +pub struct EnvArgs { + /// EIP-170: Contract code size limit in bytes. Useful to increase this because of tests. By + /// default, it is 0x6000 (~25kb). + #[arg(long, value_name = "CODE_SIZE")] + #[serde(skip_serializing_if = "Option::is_none")] + pub code_size_limit: Option, + + /// The chain name or EIP-155 chain ID. + #[arg(long, visible_alias = "chain-id", value_name = "CHAIN")] + #[serde(rename = "chain_id", skip_serializing_if = "Option::is_none", serialize_with = "id")] + pub chain: Option, + + /// The gas price. + #[arg(long, value_name = "GAS_PRICE")] + #[serde(skip_serializing_if = "Option::is_none")] + pub gas_price: Option, + + /// The base fee in a block. + #[arg(long, visible_alias = "base-fee", value_name = "FEE")] + #[serde(skip_serializing_if = "Option::is_none")] + pub block_base_fee_per_gas: Option, + + /// The transaction origin. + #[arg(long, value_name = "ADDRESS")] + #[serde(skip_serializing_if = "Option::is_none")] + pub tx_origin: Option
, + + /// The coinbase of the block. + #[arg(long, value_name = "ADDRESS")] + #[serde(skip_serializing_if = "Option::is_none")] + pub block_coinbase: Option
, + + /// The timestamp of the block. + #[arg(long, value_name = "TIMESTAMP")] + #[serde(skip_serializing_if = "Option::is_none")] + pub block_timestamp: Option, + + /// The block number. + #[arg(long, value_name = "BLOCK")] + #[serde(skip_serializing_if = "Option::is_none")] + pub block_number: Option, + + /// The block difficulty. + #[arg(long, value_name = "DIFFICULTY")] + #[serde(skip_serializing_if = "Option::is_none")] + pub block_difficulty: Option, + + /// The block prevrandao value. NOTE: Before merge this field was mix_hash. + #[arg(long, value_name = "PREVRANDAO")] + #[serde(skip_serializing_if = "Option::is_none")] + pub block_prevrandao: Option, + + /// The block gas limit. + #[arg(long, visible_aliases = &["block-gas-limit", "gas-limit"], value_name = "BLOCK_GAS_LIMIT")] + #[serde(skip_serializing_if = "Option::is_none")] + pub block_gas_limit: Option, + + /// The memory limit per EVM execution in bytes. + /// If this limit is exceeded, a `MemoryLimitOOG` result is thrown. + /// + /// The default is 128MiB. + #[arg(long, value_name = "MEMORY_LIMIT")] + #[serde(skip_serializing_if = "Option::is_none")] + pub memory_limit: Option, + + /// Whether to disable the block gas limit checks. + #[arg(long, visible_aliases = &["no-block-gas-limit", "no-gas-limit"])] + #[serde(skip_serializing_if = "std::ops::Not::not")] + pub disable_block_gas_limit: bool, + + /// Whether to enable tx gas limit checks as imposed by Osaka (EIP-7825). + #[arg(long, visible_alias = "tx-gas-limit")] + #[serde(skip_serializing_if = "std::ops::Not::not")] + pub enable_tx_gas_limit: bool, +} + +impl EvmArgs { + /// Ensures that fork url exists and returns its reference. + pub fn ensure_fork_url(&self) -> eyre::Result<&String> { + self.fork_url.as_ref().wrap_err("Missing `--fork-url` field.") + } +} + +/// We have to serialize chain IDs and not names because when extracting an EVM `Env`, it expects +/// `chain_id` to be `u64`. +fn id(chain: &Option, s: S) -> Result { + if let Some(chain) = chain { + s.serialize_u64(chain.id()) + } else { + // skip_serializing_if = "Option::is_none" should prevent this branch from being taken + unreachable!() + } +} + +#[cfg(test)] +mod tests { + use super::*; + use foundry_config::NamedChain; + + #[test] + fn compute_units_per_second_skips_when_none() { + let args = EvmArgs::default(); + let data = args.data().expect("provider data"); + let dict = data.get(&Config::selected_profile()).expect("profile dict"); + assert!( + !dict.contains_key("compute_units_per_second"), + "compute_units_per_second should be skipped when None" + ); + } + + #[test] + fn compute_units_per_second_present_when_some() { + let args = EvmArgs { compute_units_per_second: Some(1000), ..Default::default() }; + let data = args.data().expect("provider data"); + let dict = data.get(&Config::selected_profile()).expect("profile dict"); + let val = dict.get("compute_units_per_second").expect("cups present"); + assert_eq!(val, &Value::from(1000u64)); + } + + #[test] + fn can_parse_chain_id() { + let args = EvmArgs { + env: EnvArgs { chain: Some(NamedChain::Mainnet.into()), ..Default::default() }, + ..Default::default() + }; + let config = Config::from_provider(Config::figment().merge(args)).unwrap(); + assert_eq!(config.chain, Some(NamedChain::Mainnet.into())); + + let env = EnvArgs::parse_from(["foundry-cli", "--chain-id", "goerli"]); + assert_eq!(env.chain, Some(NamedChain::Goerli.into())); + } + + #[test] + fn test_memory_limit() { + let args = EvmArgs { + env: EnvArgs { chain: Some(NamedChain::Mainnet.into()), ..Default::default() }, + ..Default::default() + }; + let config = Config::from_provider(Config::figment().merge(args)).unwrap(); + assert_eq!(config.memory_limit, Config::default().memory_limit); + + let env = EnvArgs::parse_from(["foundry-cli", "--memory-limit", "100"]); + assert_eq!(env.memory_limit, Some(100)); + } + + #[test] + fn test_chain_id() { + let env = EnvArgs::parse_from(["foundry-cli", "--chain-id", "1"]); + assert_eq!(env.chain, Some(Chain::mainnet())); + + let env = EnvArgs::parse_from(["foundry-cli", "--chain-id", "mainnet"]); + assert_eq!(env.chain, Some(Chain::mainnet())); + let args = EvmArgs { env, ..Default::default() }; + let config = Config::from_provider(Config::figment().merge(args)).unwrap(); + assert_eq!(config.chain, Some(Chain::mainnet())); + } +} diff --git a/crates/cli/src/opts/mod.rs b/crates/cli/src/opts/mod.rs index 3b6b914c14aaa..b52464eae81f0 100644 --- a/crates/cli/src/opts/mod.rs +++ b/crates/cli/src/opts/mod.rs @@ -1,6 +1,7 @@ mod build; mod chain; mod dependency; +mod evm; mod global; mod rpc; mod transaction; @@ -8,6 +9,7 @@ mod transaction; pub use build::*; pub use chain::*; pub use dependency::*; +pub use evm::*; pub use global::*; pub use rpc::*; pub use transaction::*; diff --git a/crates/common/src/evm.rs b/crates/common/src/evm.rs index c5efa28afb927..4860fd9903abb 100644 --- a/crates/common/src/evm.rs +++ b/crates/common/src/evm.rs @@ -1,359 +1,6 @@ -//! CLI arguments for configuring the EVM settings. +//! Common EVM-related types shared across crates. -use alloy_primitives::{Address, B256, U256, map::HashMap}; -use clap::Parser; -use eyre::ContextCompat; -use foundry_config::{ - Chain, Config, - figment::{ - self, Metadata, Profile, Provider, - error::Kind::InvalidType, - value::{Dict, Map, Value}, - }, -}; -use serde::Serialize; - -use crate::shell; +use alloy_primitives::{Address, map::HashMap}; /// Map keyed by breakpoints char to their location (contract address, pc) pub type Breakpoints = HashMap; - -/// `EvmArgs` and `EnvArgs` take the highest precedence in the Config/Figment hierarchy. -/// -/// All vars are opt-in, their default values are expected to be set by the -/// [`foundry_config::Config`], and are always present ([`foundry_config::Config::default`]) -/// -/// Both have corresponding types in the `evm_adapters` crate which have mandatory fields. -/// The expected workflow is -/// 1. load the [`foundry_config::Config`] -/// 2. merge with `EvmArgs` into a `figment::Figment` -/// 3. extract `evm_adapters::Opts` from the merged `Figment` -/// -/// # Example -/// -/// ```ignore -/// use foundry_config::Config; -/// use forge::executor::opts::EvmOpts; -/// use foundry_common::evm::EvmArgs; -/// # fn t(args: EvmArgs) { -/// let figment = Config::figment_with_root(".").merge(args); -/// let opts = figment.extract::().unwrap(); -/// # } -/// ``` -#[derive(Clone, Debug, Default, Serialize, Parser)] -#[command(next_help_heading = "EVM options", about = None, long_about = None)] // override doc -pub struct EvmArgs { - /// Fetch state over a remote endpoint instead of starting from an empty state. - /// - /// If you want to fetch state from a specific block number, see --fork-block-number. - #[arg(long, short, visible_alias = "rpc-url", value_name = "URL")] - #[serde(rename = "eth_rpc_url", skip_serializing_if = "Option::is_none")] - pub fork_url: Option, - - /// Fetch state from a specific block number over a remote endpoint. - /// - /// See --fork-url. - #[arg(long, requires = "fork_url", value_name = "BLOCK")] - #[serde(skip_serializing_if = "Option::is_none")] - pub fork_block_number: Option, - - /// Number of retries. - /// - /// See --fork-url. - #[arg(long, requires = "fork_url", value_name = "RETRIES")] - #[serde(skip_serializing_if = "Option::is_none")] - pub fork_retries: Option, - - /// Initial retry backoff on encountering errors. - /// - /// See --fork-url. - #[arg(long, requires = "fork_url", value_name = "BACKOFF")] - #[serde(skip_serializing_if = "Option::is_none")] - pub fork_retry_backoff: Option, - - /// Explicitly disables the use of RPC caching. - /// - /// All storage slots are read entirely from the endpoint. - /// - /// This flag overrides the project's configuration file. - /// - /// See --fork-url. - #[arg(long)] - #[serde(skip)] - pub no_storage_caching: bool, - - /// The initial balance of deployed test contracts. - #[arg(long, value_name = "BALANCE")] - #[serde(skip_serializing_if = "Option::is_none")] - pub initial_balance: Option, - - /// The address which will be executing tests/scripts. - #[arg(long, value_name = "ADDRESS")] - #[serde(skip_serializing_if = "Option::is_none")] - pub sender: Option
, - - /// Enable the FFI cheatcode. - #[arg(long)] - #[serde(skip)] - pub ffi: bool, - - /// Use the create 2 factory in all cases including tests and non-broadcasting scripts. - #[arg(long)] - #[serde(skip)] - pub always_use_create_2_factory: bool, - - /// The CREATE2 deployer address to use, this will override the one in the config. - #[arg(long, value_name = "ADDRESS")] - #[serde(skip_serializing_if = "Option::is_none")] - pub create2_deployer: Option
, - - /// Sets the number of assumed available compute units per second for this provider - /// - /// default value: 330 - /// - /// See also --fork-url and - #[arg(long, alias = "cups", value_name = "CUPS", help_heading = "Fork config")] - #[serde(skip_serializing_if = "Option::is_none")] - pub compute_units_per_second: Option, - - /// Disables rate limiting for this node's provider. - /// - /// See also --fork-url and - #[arg( - long, - value_name = "NO_RATE_LIMITS", - help_heading = "Fork config", - visible_alias = "no-rate-limit" - )] - #[serde(skip)] - pub no_rpc_rate_limit: bool, - - /// All ethereum environment related arguments - #[command(flatten)] - #[serde(flatten)] - pub env: EnvArgs, - - /// Whether to enable isolation of calls. - /// In isolation mode all top-level calls are executed as a separate transaction in a separate - /// EVM context, enabling more precise gas accounting and transaction state changes. - #[arg(long)] - #[serde(skip)] - pub isolate: bool, - - /// Whether to enable Celo precompiles. - #[arg(long)] - #[serde(skip)] - pub celo: bool, -} - -// Make this set of options a `figment::Provider` so that it can be merged into the `Config` -impl Provider for EvmArgs { - fn metadata(&self) -> Metadata { - Metadata::named("Evm Opts Provider") - } - - fn data(&self) -> Result, figment::Error> { - let value = Value::serialize(self)?; - let error = InvalidType(value.to_actual(), "map".into()); - let mut dict = value.into_dict().ok_or(error)?; - - if shell::verbosity() > 0 { - // need to merge that manually otherwise `from_occurrences` does not work - dict.insert("verbosity".to_string(), shell::verbosity().into()); - } - - if self.ffi { - dict.insert("ffi".to_string(), self.ffi.into()); - } - - if self.isolate { - dict.insert("isolate".to_string(), self.isolate.into()); - } - - if self.celo { - dict.insert("celo".to_string(), self.celo.into()); - } - - if self.always_use_create_2_factory { - dict.insert( - "always_use_create_2_factory".to_string(), - self.always_use_create_2_factory.into(), - ); - } - - if self.no_storage_caching { - dict.insert("no_storage_caching".to_string(), self.no_storage_caching.into()); - } - - if self.no_rpc_rate_limit { - dict.insert("no_rpc_rate_limit".to_string(), self.no_rpc_rate_limit.into()); - } - - if let Some(fork_url) = &self.fork_url { - dict.insert("eth_rpc_url".to_string(), fork_url.clone().into()); - } - - Ok(Map::from([(Config::selected_profile(), dict)])) - } -} - -/// Configures the executor environment during tests. -#[derive(Clone, Debug, Default, Serialize, Parser)] -#[command(next_help_heading = "Executor environment config")] -pub struct EnvArgs { - /// EIP-170: Contract code size limit in bytes. Useful to increase this because of tests. By - /// default, it is 0x6000 (~25kb). - #[arg(long, value_name = "CODE_SIZE")] - #[serde(skip_serializing_if = "Option::is_none")] - pub code_size_limit: Option, - - /// The chain name or EIP-155 chain ID. - #[arg(long, visible_alias = "chain-id", value_name = "CHAIN")] - #[serde(rename = "chain_id", skip_serializing_if = "Option::is_none", serialize_with = "id")] - pub chain: Option, - - /// The gas price. - #[arg(long, value_name = "GAS_PRICE")] - #[serde(skip_serializing_if = "Option::is_none")] - pub gas_price: Option, - - /// The base fee in a block. - #[arg(long, visible_alias = "base-fee", value_name = "FEE")] - #[serde(skip_serializing_if = "Option::is_none")] - pub block_base_fee_per_gas: Option, - - /// The transaction origin. - #[arg(long, value_name = "ADDRESS")] - #[serde(skip_serializing_if = "Option::is_none")] - pub tx_origin: Option
, - - /// The coinbase of the block. - #[arg(long, value_name = "ADDRESS")] - #[serde(skip_serializing_if = "Option::is_none")] - pub block_coinbase: Option
, - - /// The timestamp of the block. - #[arg(long, value_name = "TIMESTAMP")] - #[serde(skip_serializing_if = "Option::is_none")] - pub block_timestamp: Option, - - /// The block number. - #[arg(long, value_name = "BLOCK")] - #[serde(skip_serializing_if = "Option::is_none")] - pub block_number: Option, - - /// The block difficulty. - #[arg(long, value_name = "DIFFICULTY")] - #[serde(skip_serializing_if = "Option::is_none")] - pub block_difficulty: Option, - - /// The block prevrandao value. NOTE: Before merge this field was mix_hash. - #[arg(long, value_name = "PREVRANDAO")] - #[serde(skip_serializing_if = "Option::is_none")] - pub block_prevrandao: Option, - - /// The block gas limit. - #[arg(long, visible_aliases = &["block-gas-limit", "gas-limit"], value_name = "BLOCK_GAS_LIMIT")] - #[serde(skip_serializing_if = "Option::is_none")] - pub block_gas_limit: Option, - - /// The memory limit per EVM execution in bytes. - /// If this limit is exceeded, a `MemoryLimitOOG` result is thrown. - /// - /// The default is 128MiB. - #[arg(long, value_name = "MEMORY_LIMIT")] - #[serde(skip_serializing_if = "Option::is_none")] - pub memory_limit: Option, - - /// Whether to disable the block gas limit checks. - #[arg(long, visible_aliases = &["no-block-gas-limit", "no-gas-limit"])] - #[serde(skip_serializing_if = "std::ops::Not::not")] - pub disable_block_gas_limit: bool, - - /// Whether to enable tx gas limit checks as imposed by Osaka (EIP-7825). - #[arg(long, visible_alias = "tx-gas-limit")] - #[serde(skip_serializing_if = "std::ops::Not::not")] - pub enable_tx_gas_limit: bool, -} - -impl EvmArgs { - /// Ensures that fork url exists and returns its reference. - pub fn ensure_fork_url(&self) -> eyre::Result<&String> { - self.fork_url.as_ref().wrap_err("Missing `--fork-url` field.") - } -} - -/// We have to serialize chain IDs and not names because when extracting an EVM `Env`, it expects -/// `chain_id` to be `u64`. -fn id(chain: &Option, s: S) -> Result { - if let Some(chain) = chain { - s.serialize_u64(chain.id()) - } else { - // skip_serializing_if = "Option::is_none" should prevent this branch from being taken - unreachable!() - } -} - -#[cfg(test)] -mod tests { - use super::*; - use foundry_config::NamedChain; - - #[test] - fn compute_units_per_second_skips_when_none() { - let args = EvmArgs::default(); - let data = args.data().expect("provider data"); - let dict = data.get(&Config::selected_profile()).expect("profile dict"); - assert!( - !dict.contains_key("compute_units_per_second"), - "compute_units_per_second should be skipped when None" - ); - } - - #[test] - fn compute_units_per_second_present_when_some() { - let args = EvmArgs { compute_units_per_second: Some(1000), ..Default::default() }; - let data = args.data().expect("provider data"); - let dict = data.get(&Config::selected_profile()).expect("profile dict"); - let val = dict.get("compute_units_per_second").expect("cups present"); - assert_eq!(val, &Value::from(1000u64)); - } - - #[test] - fn can_parse_chain_id() { - let args = EvmArgs { - env: EnvArgs { chain: Some(NamedChain::Mainnet.into()), ..Default::default() }, - ..Default::default() - }; - let config = Config::from_provider(Config::figment().merge(args)).unwrap(); - assert_eq!(config.chain, Some(NamedChain::Mainnet.into())); - - let env = EnvArgs::parse_from(["foundry-common", "--chain-id", "goerli"]); - assert_eq!(env.chain, Some(NamedChain::Goerli.into())); - } - - #[test] - fn test_memory_limit() { - let args = EvmArgs { - env: EnvArgs { chain: Some(NamedChain::Mainnet.into()), ..Default::default() }, - ..Default::default() - }; - let config = Config::from_provider(Config::figment().merge(args)).unwrap(); - assert_eq!(config.memory_limit, Config::default().memory_limit); - - let env = EnvArgs::parse_from(["foundry-common", "--memory-limit", "100"]); - assert_eq!(env.memory_limit, Some(100)); - } - - #[test] - fn test_chain_id() { - let env = EnvArgs::parse_from(["foundry-common", "--chain-id", "1"]); - assert_eq!(env.chain, Some(Chain::mainnet())); - - let env = EnvArgs::parse_from(["foundry-common", "--chain-id", "mainnet"]); - assert_eq!(env.chain, Some(Chain::mainnet())); - let args = EvmArgs { env, ..Default::default() }; - let config = Config::from_provider(Config::figment().merge(args)).unwrap(); - assert_eq!(config.chain, Some(Chain::mainnet())); - } -} diff --git a/crates/forge/src/cmd/config.rs b/crates/forge/src/cmd/config.rs index c337e1fd4facc..49716146c456b 100644 --- a/crates/forge/src/cmd/config.rs +++ b/crates/forge/src/cmd/config.rs @@ -1,8 +1,8 @@ use super::build::BuildArgs; use clap::Parser; use eyre::Result; -use foundry_cli::utils::LoadConfig; -use foundry_common::{evm::EvmArgs, shell}; +use foundry_cli::{opts::EvmArgs, utils::LoadConfig}; +use foundry_common::shell; use foundry_config::fix::fix_tomls; foundry_config::impl_figment_convert!(ConfigArgs, build, evm); diff --git a/crates/forge/src/cmd/test/mod.rs b/crates/forge/src/cmd/test/mod.rs index 0ded30f77e02e..24a7e35b72886 100644 --- a/crates/forge/src/cmd/test/mod.rs +++ b/crates/forge/src/cmd/test/mod.rs @@ -17,12 +17,10 @@ use chrono::Utc; use clap::{Parser, ValueHint}; use eyre::{Context, OptionExt, Result, bail}; use foundry_cli::{ - opts::{BuildOpts, GlobalArgs}, + opts::{BuildOpts, EvmArgs, GlobalArgs}, utils::{self, LoadConfig}, }; -use foundry_common::{ - EmptyTestFilter, TestFunctionExt, compile::ProjectCompiler, evm::EvmArgs, fs, shell, -}; +use foundry_common::{EmptyTestFilter, TestFunctionExt, compile::ProjectCompiler, fs, shell}; use foundry_compilers::{ Language, ProjectCompileOutput, artifacts::output_selection::OutputSelection, compilers::multi::MultiCompiler, multi::MultiCompilerLanguage, utils::source_files_iter, diff --git a/crates/script/src/lib.rs b/crates/script/src/lib.rs index a521702fa2629..2e50ec0fba243 100644 --- a/crates/script/src/lib.rs +++ b/crates/script/src/lib.rs @@ -26,13 +26,13 @@ use eyre::{ContextCompat, Result}; use forge_script_sequence::{AdditionalContract, NestedValue}; use forge_verify::{RetryArgs, VerifierArgs}; use foundry_cli::{ - opts::{BuildOpts, GlobalArgs}, + opts::{BuildOpts, EvmArgs, GlobalArgs}, utils::LoadConfig, }; use foundry_common::{ CONTRACT_MAX_SIZE, ContractsByArtifact, SELECTOR_LEN, abi::{encode_function_args, get_func}, - evm::{Breakpoints, EvmArgs}, + evm::Breakpoints, shell, }; use foundry_compilers::ArtifactId;