diff --git a/Cargo.lock b/Cargo.lock index 1a59256ab49a..2c2721a4d82e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2935,8 +2935,6 @@ dependencies = [ name = "foundry-macros" version = "0.2.0" dependencies = [ - "alloy-dyn-abi", - "alloy-primitives", "ethers-core", "foundry-macros-impl", "serde", diff --git a/crates/anvil/src/eth/backend/mem/mod.rs b/crates/anvil/src/eth/backend/mem/mod.rs index 8ecbc4cb44a5..5fddfe445abb 100644 --- a/crates/anvil/src/eth/backend/mem/mod.rs +++ b/crates/anvil/src/eth/backend/mem/mod.rs @@ -56,7 +56,7 @@ use ethers::{ utils::{hex, keccak256, rlp}, }; use flate2::{read::GzDecoder, write::GzEncoder, Compression}; -use foundry_common::abi::format_token; +use foundry_common::fmt::format_token; use foundry_evm::{ backend::{DatabaseError, DatabaseResult}, constants::DEFAULT_CREATE2_DEPLOYER_RUNTIME_CODE, diff --git a/crates/anvil/src/lib.rs b/crates/anvil/src/lib.rs index b816d53d9a35..45f5c6c2dda6 100644 --- a/crates/anvil/src/lib.rs +++ b/crates/anvil/src/lib.rs @@ -266,24 +266,22 @@ impl NodeHandle { self.config.get_ipc_path() } - /// Returns a Provider for the http endpoint + /// Constructs a [`RetryProvider`] for this handle's HTTP endpoint. pub fn http_provider(&self) -> RetryProvider { - ProviderBuilder::new(self.http_endpoint()) + ProviderBuilder::new(&self.http_endpoint()) .build() - .expect("Failed to connect using http provider") + .expect("failed to build HTTP provider") .interval(Duration::from_millis(500)) } - /// Connects to the websocket Provider of the node - pub async fn ws_provider(&self) -> RetryProvider { - ProviderBuilder::new(self.ws_endpoint()) - .build() - .expect("Failed to connect to node's websocket") + /// Constructs a [`RetryProvider`] for this handle's WS endpoint. + pub fn ws_provider(&self) -> RetryProvider { + ProviderBuilder::new(&self.ws_endpoint()).build().expect("failed to build WS provider") } - /// Connects to the ipc endpoint of the node, if spawned - pub async fn ipc_provider(&self) -> Option { - ProviderBuilder::new(self.config.get_ipc_path()?).build().ok() + /// Constructs a [`RetryProvider`] for this handle's IPC endpoint, if any. + pub fn ipc_provider(&self) -> Option { + ProviderBuilder::new(&self.config.get_ipc_path()?).build().ok() } /// Signer accounts that can sign messages/transactions from the EVM node diff --git a/crates/anvil/src/tasks/mod.rs b/crates/anvil/src/tasks/mod.rs index 5ecbbaeaadfa..429f8d5d3291 100644 --- a/crates/anvil/src/tasks/mod.rs +++ b/crates/anvil/src/tasks/mod.rs @@ -51,9 +51,9 @@ impl TaskManager { /// block /// /// ``` - /// use std::sync::Arc; + /// use anvil::{spawn, NodeConfig}; /// use ethers::providers::Provider; - /// use anvil::{NodeConfig, spawn}; + /// use std::sync::Arc; /// # async fn t() { /// let endpoint = "http://...."; /// let (api, handle) = spawn(NodeConfig::default().with_eth_rpc_url(Some(endpoint))).await; @@ -61,7 +61,6 @@ impl TaskManager { /// let provider = Arc::new(Provider::try_from(endpoint).unwrap()); /// /// handle.task_manager().spawn_reset_on_new_polled_blocks(provider, api); - /// /// # } /// ``` pub fn spawn_reset_on_new_polled_blocks

(&self, provider: P, api: EthApi) @@ -106,8 +105,8 @@ impl TaskManager { /// block /// /// ``` + /// use anvil::{spawn, NodeConfig}; /// use ethers::providers::Provider; - /// use anvil::{NodeConfig, spawn}; /// # async fn t() { /// let (api, handle) = spawn(NodeConfig::default().with_eth_rpc_url(Some("http://...."))).await; /// diff --git a/crates/anvil/tests/it/ipc.rs b/crates/anvil/tests/it/ipc.rs index f5bb19e1de92..b25bbba5249f 100644 --- a/crates/anvil/tests/it/ipc.rs +++ b/crates/anvil/tests/it/ipc.rs @@ -24,7 +24,7 @@ async fn can_get_block_number_ipc() { let block_num = api.block_number().unwrap(); assert_eq!(block_num, U256::zero()); - let provider = handle.ipc_provider().await.unwrap(); + let provider = handle.ipc_provider().unwrap(); let num = provider.get_block_number().await.unwrap(); assert_eq!(num, block_num.as_u64().into()); @@ -34,7 +34,7 @@ async fn can_get_block_number_ipc() { async fn test_sub_new_heads_ipc() { let (api, handle) = spawn(ipc_config()).await; - let provider = handle.ipc_provider().await.unwrap(); + let provider = handle.ipc_provider().unwrap(); let blocks = provider.subscribe_blocks().await.unwrap(); diff --git a/crates/anvil/tests/it/logs.rs b/crates/anvil/tests/it/logs.rs index f0b0877599f7..913015de5edf 100644 --- a/crates/anvil/tests/it/logs.rs +++ b/crates/anvil/tests/it/logs.rs @@ -143,7 +143,7 @@ async fn watch_events() { let mut stream = event.stream().await.unwrap(); // Also set up a subscription for the same thing - let ws = Arc::new(handle.ws_provider().await); + let ws = Arc::new(handle.ws_provider()); let contract2 = SimpleStorage::new(contract.address(), ws); let event2 = contract2.event::(); let mut subscription = event2.subscribe().await.unwrap(); diff --git a/crates/anvil/tests/it/otterscan.rs b/crates/anvil/tests/it/otterscan.rs index 32271f5ec07b..c6643dc2bd1d 100644 --- a/crates/anvil/tests/it/otterscan.rs +++ b/crates/anvil/tests/it/otterscan.rs @@ -122,7 +122,7 @@ contract Contract { let (abi, bytecode, _) = contract.into_contract_bytecode().into_parts(); let (api, handle) = spawn(NodeConfig::test()).await; - let provider = handle.ws_provider().await; + let provider = handle.ws_provider(); let wallets = handle.dev_wallets().collect::>(); let client = Arc::new(SignerMiddleware::new(provider, wallets[0].clone())); @@ -180,7 +180,7 @@ contract Contract { let (abi, bytecode, _) = contract.into_contract_bytecode().into_parts(); let (api, handle) = spawn(NodeConfig::test()).await; - let provider = handle.ws_provider().await; + let provider = handle.ws_provider(); let wallets = handle.dev_wallets().collect::>(); let client = Arc::new(SignerMiddleware::new(provider, wallets[0].clone())); @@ -284,7 +284,7 @@ contract Contract { let (abi, bytecode, _) = contract.into_contract_bytecode().into_parts(); let (api, handle) = spawn(NodeConfig::test()).await; - let provider = handle.ws_provider().await; + let provider = handle.ws_provider(); let wallets = handle.dev_wallets().collect::>(); let client = Arc::new(SignerMiddleware::new(provider, wallets[0].clone())); @@ -373,7 +373,7 @@ contract Contract { let (abi, bytecode, _) = contract.into_contract_bytecode().into_parts(); let (api, handle) = spawn(NodeConfig::test()).await; - let provider = handle.ws_provider().await; + let provider = handle.ws_provider(); let wallet = handle.dev_wallets().next().unwrap(); let client = Arc::new(SignerMiddleware::new(provider, wallet)); diff --git a/crates/anvil/tests/it/pubsub.rs b/crates/anvil/tests/it/pubsub.rs index 49b814113df8..22df53c96825 100644 --- a/crates/anvil/tests/it/pubsub.rs +++ b/crates/anvil/tests/it/pubsub.rs @@ -16,7 +16,7 @@ use std::sync::Arc; async fn test_sub_new_heads() { let (api, handle) = spawn(NodeConfig::test()).await; - let provider = handle.ws_provider().await; + let provider = handle.ws_provider(); let blocks = provider.subscribe_blocks().await.unwrap(); @@ -34,7 +34,7 @@ async fn test_sub_logs_legacy() { abigen!(EmitLogs, "test-data/emit_logs.json"); let (_api, handle) = spawn(NodeConfig::test()).await; - let provider = handle.ws_provider().await; + let provider = handle.ws_provider(); let wallet = handle.dev_wallets().next().unwrap(); let client = Arc::new(SignerMiddleware::new(provider, wallet)); @@ -73,7 +73,7 @@ async fn test_sub_logs() { abigen!(EmitLogs, "test-data/emit_logs.json"); let (_api, handle) = spawn(NodeConfig::test()).await; - let provider = handle.ws_provider().await; + let provider = handle.ws_provider(); let wallet = handle.dev_wallets().next().unwrap(); let client = Arc::new(SignerMiddleware::new(provider, wallet)); @@ -111,7 +111,7 @@ async fn test_sub_logs_impersonated() { abigen!(EmitLogs, "test-data/emit_logs.json"); let (api, handle) = spawn(NodeConfig::test()).await; - let provider = handle.ws_provider().await; + let provider = handle.ws_provider(); // impersonate account let impersonate = Address::random(); @@ -253,7 +253,7 @@ async fn test_subscriptions() { async fn test_sub_new_heads_fast() { let (api, handle) = spawn(NodeConfig::test()).await; - let provider = handle.ws_provider().await; + let provider = handle.ws_provider(); let blocks = provider.subscribe_blocks().await.unwrap(); diff --git a/crates/anvil/tests/it/revert.rs b/crates/anvil/tests/it/revert.rs index c58302c1f153..45da5eb2ef63 100644 --- a/crates/anvil/tests/it/revert.rs +++ b/crates/anvil/tests/it/revert.rs @@ -31,7 +31,7 @@ contract Contract { let (abi, bytecode, _) = contract.into_contract_bytecode().into_parts(); let (_api, handle) = spawn(NodeConfig::test()).await; - let provider = handle.ws_provider().await; + let provider = handle.ws_provider(); let wallet = handle.dev_wallets().next().unwrap(); let client = Arc::new(SignerMiddleware::new(provider, wallet)); @@ -75,7 +75,7 @@ contract Contract { let (abi, bytecode, _) = contract.into_contract_bytecode().into_parts(); let (_api, handle) = spawn(NodeConfig::test()).await; - let provider = handle.ws_provider().await; + let provider = handle.ws_provider(); let wallets = handle.dev_wallets().collect::>(); let client = Arc::new(SignerMiddleware::new(provider, wallets[0].clone())); @@ -107,7 +107,7 @@ async fn test_solc_revert_example() { let (abi, bytecode, _) = contract.into_contract_bytecode().into_parts(); let (_api, handle) = spawn(NodeConfig::test()).await; - let provider = handle.ws_provider().await; + let provider = handle.ws_provider(); let wallets = handle.dev_wallets().collect::>(); let client = Arc::new(SignerMiddleware::new(provider, wallets[0].clone())); @@ -161,7 +161,7 @@ contract Contract { let (abi, bytecode, _) = contract.into_contract_bytecode().into_parts(); let (_api, handle) = spawn(NodeConfig::test()).await; - let provider = handle.ws_provider().await; + let provider = handle.ws_provider(); let wallets = handle.dev_wallets().collect::>(); let client = Arc::new(SignerMiddleware::new(provider, wallets[0].clone())); @@ -208,7 +208,7 @@ contract Contract { let (_api, handle) = spawn(NodeConfig::test()).await; - let provider = handle.ws_provider().await; + let provider = handle.ws_provider(); let wallets = handle.dev_wallets().collect::>(); let client = Arc::new(SignerMiddleware::new(provider, wallets[0].clone())); diff --git a/crates/anvil/tests/it/traces.rs b/crates/anvil/tests/it/traces.rs index d8c08f15e2fa..ee795583b73b 100644 --- a/crates/anvil/tests/it/traces.rs +++ b/crates/anvil/tests/it/traces.rs @@ -72,7 +72,7 @@ contract Contract { let (abi, bytecode, _) = contract.into_contract_bytecode().into_parts(); let (_api, handle) = spawn(NodeConfig::test()).await; - let provider = handle.ws_provider().await; + let provider = handle.ws_provider(); let wallets = handle.dev_wallets().collect::>(); let client = Arc::new(SignerMiddleware::new(provider, wallets[0].clone())); @@ -119,7 +119,7 @@ contract Contract { let (abi, bytecode, _) = contract.into_contract_bytecode().into_parts(); let (_api, handle) = spawn(NodeConfig::test()).await; - let provider = handle.ws_provider().await; + let provider = handle.ws_provider(); let wallets = handle.dev_wallets().collect::>(); let client = Arc::new(SignerMiddleware::new(provider, wallets[0].clone())); diff --git a/crates/anvil/tests/it/transaction.rs b/crates/anvil/tests/it/transaction.rs index b52a058da081..7cb5c4bc6e5a 100644 --- a/crates/anvil/tests/it/transaction.rs +++ b/crates/anvil/tests/it/transaction.rs @@ -357,7 +357,7 @@ async fn can_call_greeter_historic() { #[tokio::test(flavor = "multi_thread")] async fn can_deploy_greeter_ws() { let (_api, handle) = spawn(NodeConfig::test()).await; - let provider = handle.ws_provider().await; + let provider = handle.ws_provider(); let wallet = handle.dev_wallets().next().unwrap(); let client = Arc::new(SignerMiddleware::new(provider, wallet)); @@ -382,7 +382,7 @@ async fn can_deploy_greeter_ws() { #[tokio::test(flavor = "multi_thread")] async fn can_deploy_get_code() { let (_api, handle) = spawn(NodeConfig::test()).await; - let provider = handle.ws_provider().await; + let provider = handle.ws_provider(); let wallet = handle.dev_wallets().next().unwrap(); let client = Arc::new(SignerMiddleware::new(provider, wallet)); @@ -496,7 +496,7 @@ async fn call_past_state() { async fn can_handle_multiple_concurrent_transfers_with_same_nonce() { let (_api, handle) = spawn(NodeConfig::test()).await; - let provider = handle.ws_provider().await; + let provider = handle.ws_provider(); let accounts: Vec<_> = handle.dev_wallets().collect(); let from = accounts[0].address(); @@ -526,7 +526,7 @@ async fn can_handle_multiple_concurrent_transfers_with_same_nonce() { #[tokio::test(flavor = "multi_thread")] async fn can_handle_multiple_concurrent_deploys_with_same_nonce() { let (_api, handle) = spawn(NodeConfig::test()).await; - let provider = handle.ws_provider().await; + let provider = handle.ws_provider(); let wallet = handle.dev_wallets().next().unwrap(); let from = wallet.address(); @@ -560,7 +560,7 @@ async fn can_handle_multiple_concurrent_deploys_with_same_nonce() { #[tokio::test(flavor = "multi_thread")] async fn can_handle_multiple_concurrent_transactions_with_same_nonce() { let (_api, handle) = spawn(NodeConfig::test()).await; - let provider = handle.ws_provider().await; + let provider = handle.ws_provider(); let wallet = handle.dev_wallets().next().unwrap(); let from = wallet.address(); @@ -778,7 +778,7 @@ async fn can_stream_pending_transactions() { spawn(NodeConfig::test().with_blocktime(Some(Duration::from_secs(2)))).await; let num_txs = 5; let provider = handle.http_provider(); - let ws_provider = handle.ws_provider().await; + let ws_provider = handle.ws_provider(); let accounts = provider.get_accounts().await.unwrap(); let tx = TransactionRequest::new().from(accounts[0]).to(accounts[0]).value(1e18 as u64); diff --git a/crates/anvil/tests/it/wsapi.rs b/crates/anvil/tests/it/wsapi.rs index 9bcc0d810c39..f185c6b8ee24 100644 --- a/crates/anvil/tests/it/wsapi.rs +++ b/crates/anvil/tests/it/wsapi.rs @@ -9,7 +9,7 @@ async fn can_get_block_number_ws() { let block_num = api.block_number().unwrap(); assert_eq!(block_num, U256::zero()); - let provider = handle.ws_provider().await; + let provider = handle.ws_provider(); let num = provider.get_block_number().await.unwrap(); assert_eq!(num, block_num.as_u64().into()); @@ -18,7 +18,7 @@ async fn can_get_block_number_ws() { #[tokio::test(flavor = "multi_thread")] async fn can_dev_get_balance_ws() { let (_api, handle) = spawn(NodeConfig::test()).await; - let provider = handle.ws_provider().await; + let provider = handle.ws_provider(); let genesis_balance = handle.genesis_balance(); for acc in handle.genesis_accounts() { diff --git a/crates/binder/src/lib.rs b/crates/binder/src/lib.rs index 8bc3e49067d4..8db7b892167e 100644 --- a/crates/binder/src/lib.rs +++ b/crates/binder/src/lib.rs @@ -40,23 +40,21 @@ impl Binder { /// /// # Example /// - /// ## Local repository + /// Local repository: /// /// ``` - /// # use foundry_binder::Binder; - /// # fn new() { - /// let binder = Binder::new("./aave-v3-core"); - /// # } + /// use foundry_binder::Binder; + /// + /// let binder = Binder::new("./aave-v3-core"); /// ``` /// - /// ## Remote repository with default branch + /// Remote repository with default branch: /// /// ``` - /// # use url::Url; /// use foundry_binder::Binder; - /// # fn new() { - /// let binder = Binder::new(Url::parse("https://github.com/aave/aave-v3-core").unwrap()); - /// # } + /// use url::Url; + /// + /// let binder = Binder::new(Url::parse("https://github.com/aave/aave-v3-core").unwrap()); /// ``` pub fn new(location: impl Into) -> Self { Self { @@ -76,14 +74,14 @@ impl Binder { /// Add a `yarn install` command /// /// ``` - /// # use url::Url; /// use foundry_binder::{Binder, RepositoryBuilder}; - /// # fn new() { + /// use url::Url; + /// /// let binder = Binder::new( /// RepositoryBuilder::new(Url::parse("https://github.com/aave/aave-v3-core").unwrap()) /// .tag("v1.16.0"), - /// ).command(["yarn", "install"]); - /// # } + /// ) + /// .command(["yarn", "install"]); /// ``` #[must_use] pub fn command(mut self, cmd: I) -> Self @@ -122,20 +120,15 @@ impl Binder { /// ## Example /// /// ``` - /// # use url::Url; /// use foundry_binder::{Binder, Config, RepositoryBuilder}; - /// # fn new() { + /// use url::Url; + /// /// let binder = Binder::new( /// RepositoryBuilder::new(Url::parse("https://github.com/aave/aave-v3-core").unwrap()) /// .tag("v1.16.0"), /// ) /// .command(["yarn", "install"]) - /// .config(Config { - /// src: "src".into(), - /// out: "artifacts".into(), - /// ..Default::default() - /// }); - /// # } + /// .config(Config { src: "src".into(), out: "artifacts".into(), ..Default::default() }); /// ``` #[must_use] pub fn config(mut self, config: Config) -> Self { diff --git a/crates/cast/bin/main.rs b/crates/cast/bin/main.rs index fad3ec49da75..60e64c214d34 100644 --- a/crates/cast/bin/main.rs +++ b/crates/cast/bin/main.rs @@ -6,10 +6,11 @@ use ethers::{ core::types::{BlockId, BlockNumber::Latest}, providers::Middleware, }; -use eyre::{Result, WrapErr}; +use eyre::Result; use foundry_cli::{handler, prompt, stdin, utils}; use foundry_common::{ - abi::{format_tokens, get_event}, + abi::get_event, + fmt::format_tokens, fs, selectors::{ decode_calldata, decode_event_topic, decode_function_selector, import_selectors, @@ -123,15 +124,15 @@ async fn main() -> Result<()> { } Subcommands::ToHex(ToBaseArgs { value, base_in }) => { let value = stdin::unwrap_line(value)?; - println!("{}", SimpleCast::to_base(&value, base_in, "hex")?); + println!("{}", SimpleCast::to_base(&value, base_in.as_deref(), "hex")?); } Subcommands::ToDec(ToBaseArgs { value, base_in }) => { let value = stdin::unwrap_line(value)?; - println!("{}", SimpleCast::to_base(&value, base_in, "dec")?); + println!("{}", SimpleCast::to_base(&value, base_in.as_deref(), "dec")?); } Subcommands::ToBase { base: ToBaseArgs { value, base_in }, base_out } => { let (value, base_out) = stdin::unwrap2(value, base_out)?; - println!("{}", SimpleCast::to_base(&value, base_in, &base_out)?); + println!("{}", SimpleCast::to_base(&value, base_in.as_deref(), &base_out)?); } Subcommands::ToBytes32 { bytes } => { let value = stdin::unwrap_line(bytes)?; @@ -174,17 +175,17 @@ async fn main() -> Result<()> { println!("{}", pretty_calldata(&calldata, offline).await?); } Subcommands::Sig { sig, optimize } => { - let sig = stdin::unwrap_line(sig).wrap_err("Failed to read signature")?; - if optimize.is_none() { - println!("{}", SimpleCast::get_selector(&sig, None)?.0); - } else { - println!("Starting to optimize signature..."); - let start_time = Instant::now(); - let (selector, signature) = SimpleCast::get_selector(&sig, optimize)?; - let elapsed_time = start_time.elapsed(); - println!("Successfully generated in {} seconds", elapsed_time.as_secs()); - println!("Selector: {}", selector); - println!("Optimized signature: {}", signature); + let sig = stdin::unwrap_line(sig)?; + match optimize { + Some(opt) => { + println!("Starting to optimize signature..."); + let start_time = Instant::now(); + let (selector, signature) = SimpleCast::get_selector(&sig, opt)?; + println!("Successfully generated in {:?}", start_time.elapsed()); + println!("Selector: {selector}"); + println!("Optimized signature: {signature}"); + } + None => println!("{}", SimpleCast::get_selector(&sig, 0)?.0), } } @@ -453,10 +454,10 @@ async fn main() -> Result<()> { println!("{:?}", parsed_event.signature()); } Subcommands::LeftShift { value, bits, base_in, base_out } => { - println!("{}", SimpleCast::left_shift(&value, &bits, base_in, &base_out)?); + println!("{}", SimpleCast::left_shift(&value, &bits, base_in.as_deref(), &base_out)?); } Subcommands::RightShift { value, bits, base_in, base_out } => { - println!("{}", SimpleCast::right_shift(&value, &bits, base_in, &base_out)?); + println!("{}", SimpleCast::right_shift(&value, &bits, base_in.as_deref(), &base_out)?); } Subcommands::EtherscanSource { address, directory, etherscan } => { let config = Config::from(ðerscan); diff --git a/crates/cast/bin/opts.rs b/crates/cast/bin/opts.rs index 39ac4364045c..d5f0315ef8ed 100644 --- a/crates/cast/bin/opts.rs +++ b/crates/cast/bin/opts.rs @@ -921,7 +921,7 @@ mod tests { "__$_$__$$$$$__$$_$$$_$$__$$___$$(address,address,uint256)".to_string() ); - let selector = SimpleCast::get_selector(&sig, None).unwrap(); + let selector = SimpleCast::get_selector(&sig, 0).unwrap(); assert_eq!(selector.0, "0x23b872dd".to_string()); } _ => unreachable!(), diff --git a/crates/cast/src/base.rs b/crates/cast/src/base.rs index 016d7402aea3..5ec41d04d605 100644 --- a/crates/cast/src/base.rs +++ b/crates/cast/src/base.rs @@ -5,7 +5,7 @@ use ethers_core::{ }; use eyre::Result; use std::{ - convert::{Infallible, TryFrom, TryInto}, + convert::Infallible, fmt::{Binary, Debug, Display, Formatter, LowerHex, Octal, Result as FmtResult, UpperHex}, iter::FromIterator, num::IntErrorKind, @@ -118,9 +118,9 @@ impl From for String { } impl Base { - pub fn unwrap_or_detect(base: Option, s: impl AsRef) -> Result { + pub fn unwrap_or_detect(base: Option<&str>, s: impl AsRef) -> Result { match base { - Some(base) => base.try_into(), + Some(base) => base.parse(), None => Self::detect(s), } } @@ -355,7 +355,7 @@ impl NumberWithBase { /// Parses a string slice into a signed integer. If base is None then it tries to determine base /// from the prefix, otherwise defaults to Decimal. - pub fn parse_int(s: &str, base: Option) -> Result { + pub fn parse_int(s: &str, base: Option<&str>) -> Result { let base = Base::unwrap_or_detect(base, s)?; let (number, is_nonnegative) = Self::_parse_int(s, base)?; Ok(Self { number, is_nonnegative, base }) @@ -363,7 +363,7 @@ impl NumberWithBase { /// Parses a string slice into an unsigned integer. If base is None then it tries to determine /// base from the prefix, otherwise defaults to Decimal. - pub fn parse_uint(s: &str, base: Option) -> Result { + pub fn parse_uint(s: &str, base: Option<&str>) -> Result { let base = Base::unwrap_or_detect(base, s)?; let number = Self::_parse_uint(s, base)?; Ok(Self { number, is_nonnegative: true, base }) diff --git a/crates/cast/src/lib.rs b/crates/cast/src/lib.rs index 4cfe2dc04de2..eff98be4eae2 100644 --- a/crates/cast/src/lib.rs +++ b/crates/cast/src/lib.rs @@ -57,7 +57,7 @@ where /// /// ``` /// use cast::Cast; - /// use ethers_providers::{Provider, Http}; + /// use ethers_providers::{Http, Provider}; /// /// # async fn foo() -> eyre::Result<()> { /// let provider = Provider::::try_from("http://localhost:8545")?; @@ -76,17 +76,17 @@ where /// ```no_run /// use cast::{Cast, TxBuilder}; /// use ethers_core::types::{Address, Chain}; - /// use ethers_providers::{Provider, Http}; - /// use std::{str::FromStr, convert::TryFrom}; + /// use ethers_providers::{Http, Provider}; + /// use std::str::FromStr; /// /// # async fn foo() -> eyre::Result<()> { /// let provider = Provider::::try_from("http://localhost:8545")?; /// let to = Address::from_str("0xB3C95ff08316fb2F2e3E52Ee82F8e7b605Aa1304")?; /// let sig = "function greeting(uint256 i) public returns (string)"; /// let args = vec!["5".to_owned()]; - /// let mut builder = TxBuilder::new(&provider, Address::zero(), Some(to), Chain::Mainnet, false).await?; - /// builder - /// .set_args(sig, args).await?; + /// let mut builder = + /// TxBuilder::new(&provider, Address::zero(), Some(to), Chain::Mainnet, false).await?; + /// builder.set_args(sig, args).await?; /// let builder_output = builder.build(); /// let cast = Cast::new(provider); /// let data = cast.call(builder_output, None).await?; @@ -113,29 +113,26 @@ where if res.is_empty() { // check that the recipient is a contract that can be called if let Some(NameOrAddress::Address(addr)) = tx.to() { - let code = self.provider.get_code(*addr, block).await?; - if code.is_empty() { - eyre::bail!("Contract {:?} does not exist", addr) + if let Ok(code) = self.provider.get_code(*addr, block).await { + if code.is_empty() { + eyre::bail!("contract {addr:?} does not exist") + } } } } return Err(err).wrap_err( - "could not decode output. did you specify the wrong function return data type perhaps?" + "could not decode output; did you specify the wrong function return data type?" ); } }; } + // handle case when return type is not specified Ok(if decoded.is_empty() { format!("{res}\n") } else { // seth compatible user-friendly return type conversions - decoded - .iter() - .map(TokenDisplay) - .map(|token| token.to_string()) - .collect::>() - .join("\n") + decoded.iter().map(format_token).collect::>().join("\n") }) } @@ -146,17 +143,17 @@ where /// ```no_run /// use cast::{Cast, TxBuilder}; /// use ethers_core::types::{Address, Chain}; - /// use ethers_providers::{Provider, Http}; - /// use std::{str::FromStr, convert::TryFrom}; + /// use ethers_providers::{Http, Provider}; + /// use std::str::FromStr; /// /// # async fn foo() -> eyre::Result<()> { /// let provider = Provider::::try_from("http://localhost:8545")?; /// let to = Address::from_str("0xB3C95ff08316fb2F2e3E52Ee82F8e7b605Aa1304")?; /// let sig = "greeting(uint256)(string)"; /// let args = vec!["5".to_owned()]; - /// let mut builder = TxBuilder::new(&provider, Address::zero(), Some(to), Chain::Mainnet, false).await?; - /// builder - /// .set_args(sig, args).await?; + /// let mut builder = + /// TxBuilder::new(&provider, Address::zero(), Some(to), Chain::Mainnet, false).await?; + /// builder.set_args(sig, args).await?; /// let builder_output = builder.peek(); /// let cast = Cast::new(&provider); /// let access_list = cast.access_list(builder_output, None, false).await?; @@ -205,11 +202,11 @@ where /// # Example /// /// ```no_run - /// use cast::{Cast, TxBuilder}; - /// use ethers_core::types::{Chain, Address as eAddress}; /// use alloy_primitives::{Address, U256}; - /// use ethers_providers::{Provider, Http}; - /// use std::{str::FromStr, convert::TryFrom}; + /// use cast::{Cast, TxBuilder}; + /// use ethers_core::types::{Address as eAddress, Chain}; + /// use ethers_providers::{Http, Provider}; + /// use std::str::FromStr; /// /// # async fn foo() -> eyre::Result<()> { /// let provider = Provider::::try_from("http://localhost:8545")?; @@ -221,11 +218,7 @@ where /// let value = U256::from_str("1").unwrap(); /// let nonce = U256::from_str("1").unwrap(); /// let mut builder = TxBuilder::new(&provider, from, Some(to), Chain::Mainnet, false).await?; - /// builder - /// .set_args(sig, args).await? - /// .set_gas(gas) - /// .set_value(value) - /// .set_nonce(nonce); + /// builder.set_args(sig, args).await?.set_gas(gas).set_value(value).set_nonce(nonce); /// let builder_output = builder.build(); /// let cast = Cast::new(provider); /// let data = cast.send(builder_output).await?; @@ -249,7 +242,7 @@ where /// /// ```no_run /// use cast::Cast; - /// use ethers_providers::{Provider, Http}; + /// use ethers_providers::{Http, Provider}; /// /// # async fn foo() -> eyre::Result<()> { /// let provider = Provider::::try_from("http://localhost:8545")?; @@ -275,11 +268,11 @@ where /// # Example /// /// ```no_run + /// use alloy_primitives::U256; /// use cast::{Cast, TxBuilder}; /// use ethers_core::types::{Address, Chain}; - /// use alloy_primitives::U256; - /// use ethers_providers::{Provider, Http}; - /// use std::{str::FromStr, convert::TryFrom}; + /// use ethers_providers::{Http, Provider}; + /// use std::str::FromStr; /// /// # async fn foo() -> eyre::Result<()> { /// let provider = Provider::::try_from("http://localhost:8545")?; @@ -289,9 +282,7 @@ where /// let args = vec!["5".to_owned()]; /// let value = U256::from_str("1").unwrap(); /// let mut builder = TxBuilder::new(&provider, from, Some(to), Chain::Mainnet, false).await?; - /// builder - /// .set_value(value) - /// .set_args(sig, args).await?; + /// builder.set_value(value).set_args(sig, args).await?; /// let builder_output = builder.peek(); /// let cast = Cast::new(&provider); /// let data = cast.estimate(builder_output).await?; @@ -311,7 +302,7 @@ where /// /// ```no_run /// use cast::Cast; - /// use ethers_providers::{Provider, Http}; + /// use ethers_providers::{Http, Provider}; /// /// # async fn foo() -> eyre::Result<()> { /// let provider = Provider::::try_from("http://localhost:8545")?; @@ -478,9 +469,9 @@ where /// /// ```no_run /// use cast::Cast; - /// use ethers_providers::{Provider, Http}; /// use ethers::types::NameOrAddress; - /// use std::{str::FromStr, convert::TryFrom}; + /// use ethers_providers::{Http, Provider}; + /// use std::str::FromStr; /// /// # async fn foo() -> eyre::Result<()> { /// let provider = Provider::::try_from("http://localhost:8545")?; @@ -503,9 +494,9 @@ where /// /// ```no_run /// use cast::Cast; - /// use ethers_providers::{Provider, Http}; /// use ethers_core::types::Address; - /// use std::{str::FromStr, convert::TryFrom}; + /// use ethers_providers::{Http, Provider}; + /// use std::str::FromStr; /// /// # async fn foo() -> eyre::Result<()> { /// let provider = Provider::::try_from("http://localhost:8545")?; @@ -532,9 +523,9 @@ where /// /// ```no_run /// use cast::Cast; - /// use ethers_providers::{Provider, Http}; /// use ethers_core::types::Address; - /// use std::{str::FromStr, convert::TryFrom}; + /// use ethers_providers::{Http, Provider}; + /// use std::str::FromStr; /// /// # async fn foo() -> eyre::Result<()> { /// let provider = Provider::::try_from("http://localhost:8545")?; @@ -560,11 +551,11 @@ where /// # Example /// /// ```no_run + /// use alloy_primitives::{Address, U256}; /// use cast::Cast; - /// use ethers_providers::{Provider, Http}; /// use ethers::types::NameOrAddress; - /// use alloy_primitives::{Address, U256}; - /// use std::{str::FromStr, convert::TryFrom}; + /// use ethers_providers::{Http, Provider}; + /// use std::str::FromStr; /// /// # async fn foo() -> eyre::Result<()> { /// let provider = Provider::::try_from("http://localhost:8545")?; @@ -575,7 +566,10 @@ where /// let computed_address = cast.compute_address(addr, Some(nonce)).await?; /// println!("Computed address for address {} with nonce {}: {}", addr, nonce, computed_address); /// let computed_address_no_nonce = cast.compute_address(addr, None).await?; - /// println!("Computed address for address {} with nonce {}: {}", addr, nonce, computed_address_no_nonce); + /// println!( + /// "Computed address for address {} with nonce {}: {}", + /// addr, nonce, computed_address_no_nonce + /// ); /// # Ok(()) /// # } /// ``` @@ -597,9 +591,9 @@ where /// /// ```no_run /// use cast::Cast; - /// use ethers_providers::{Provider, Http}; /// use ethers_core::types::Address; - /// use std::{str::FromStr, convert::TryFrom}; + /// use ethers_providers::{Http, Provider}; + /// use std::str::FromStr; /// /// # async fn foo() -> eyre::Result<()> { /// let provider = Provider::::try_from("http://localhost:8545")?; @@ -628,9 +622,9 @@ where /// /// ```no_run /// use cast::Cast; - /// use ethers_providers::{Provider, Http}; /// use ethers_core::types::Address; - /// use std::{str::FromStr, convert::TryFrom}; + /// use ethers_providers::{Http, Provider}; + /// use std::str::FromStr; /// /// # async fn foo() -> eyre::Result<()> { /// let provider = Provider::::try_from("http://localhost:8545")?; @@ -654,7 +648,7 @@ where /// /// ```no_run /// use cast::Cast; - /// use ethers_providers::{Provider, Http}; + /// use ethers_providers::{Http, Provider}; /// /// # async fn foo() -> eyre::Result<()> { /// let provider = Provider::::try_from("http://localhost:8545")?; @@ -696,7 +690,7 @@ where /// /// ```no_run /// use cast::Cast; - /// use ethers_providers::{Provider, Http}; + /// use ethers_providers::{Http, Provider}; /// /// # async fn foo() -> eyre::Result<()> { /// let provider = Provider::::try_from("http://localhost:8545")?; @@ -758,12 +752,13 @@ where /// /// ```no_run /// use cast::Cast; - /// use ethers_providers::{Provider, Http}; + /// use ethers_providers::{Http, Provider}; /// /// # async fn foo() -> eyre::Result<()> { /// let provider = Provider::::try_from("http://localhost:8545")?; /// let cast = Cast::new(provider); - /// let result = cast.rpc("eth_getBalance", &["0xc94770007dda54cF92009BFF0dE90c06F603a09f", "latest"]) + /// let result = cast + /// .rpc("eth_getBalance", &["0xc94770007dda54cF92009BFF0dE90c06F603a09f", "latest"]) /// .await?; /// println!("{}", result); /// # Ok(()) @@ -783,9 +778,9 @@ where /// /// ```no_run /// use cast::Cast; - /// use ethers_providers::{Provider, Http}; /// use ethers_core::types::{Address, H256}; - /// use std::{str::FromStr, convert::TryFrom}; + /// use ethers_providers::{Http, Provider}; + /// use std::str::FromStr; /// /// # async fn foo() -> eyre::Result<()> { /// let provider = Provider::::try_from("http://localhost:8545")?; @@ -835,18 +830,20 @@ where /// /// ```no_run /// use cast::Cast; - /// use ethers_providers::{Provider, Http}; /// use ethers_core::types::{BlockId, BlockNumber}; + /// use ethers_providers::{Http, Provider}; /// use std::convert::TryFrom; /// /// # async fn foo() -> eyre::Result<()> { /// let provider = Provider::::try_from("http://localhost:8545")?; /// let cast = Cast::new(provider); /// - /// let block_number = cast.convert_block_number(Some(BlockId::Number(BlockNumber::from(5)))).await?; + /// let block_number = + /// cast.convert_block_number(Some(BlockId::Number(BlockNumber::from(5)))).await?; /// assert_eq!(block_number, Some(BlockNumber::from(5))); /// - /// let block_number = cast.convert_block_number(Some(BlockId::Hash("0x1234".parse().unwrap()))).await?; + /// let block_number = + /// cast.convert_block_number(Some(BlockId::Hash("0x1234".parse().unwrap()))).await?; /// assert_eq!(block_number, Some(BlockNumber::from(1234))); /// /// let block_number = cast.convert_block_number(None).await?; @@ -876,17 +873,16 @@ where /// /// ```no_run /// use cast::Cast; - /// use ethers_core::abi::Address; + /// use ethers_core::{abi::Address, types::Filter}; /// use ethers_providers::{Provider, Ws}; - /// use ethers_core::types::Filter; - /// use std::{str::FromStr, convert::TryFrom}; - /// use std::io; + /// use std::{io, str::FromStr}; /// /// # async fn foo() -> eyre::Result<()> { /// let provider = Provider::new(Ws::connect("wss://localhost:8545").await?); /// let cast = Cast::new(provider); /// - /// let filter = Filter::new().address(Address::from_str("0x00000000006c3852cbEf3e08E8dF289169EdE581")?); + /// let filter = + /// Filter::new().address(Address::from_str("0x00000000006c3852cbEf3e08E8dF289169EdE581")?); /// let mut output = io::stdout(); /// cast.subscribe(filter, &mut output, false).await?; /// # Ok(()) @@ -988,11 +984,12 @@ impl SimpleCast { /// # Example /// /// ``` - /// # use cast::SimpleCast; - /// # use ethers_core::types::{I256, U256}; - /// assert_eq!(SimpleCast::max_int("uint256")?, format!("{}", U256::MAX)); - /// assert_eq!(SimpleCast::max_int("int256")?, format!("{}", I256::MAX)); - /// assert_eq!(SimpleCast::max_int("int32")?, format!("{}", i32::MAX)); + /// use cast::SimpleCast; + /// use ethers_core::types::{I256, U256}; + /// + /// assert_eq!(SimpleCast::max_int("uint256")?, U256::MAX.to_string()); + /// assert_eq!(SimpleCast::max_int("int256")?, I256::MAX.to_string()); + /// assert_eq!(SimpleCast::max_int("int32")?, i32::MAX.to_string()); /// # Ok::<(), eyre::Report>(()) /// ``` pub fn max_int(s: &str) -> Result { @@ -1004,11 +1001,12 @@ impl SimpleCast { /// # Example /// /// ``` - /// # use cast::SimpleCast; - /// # use ethers_core::types::{I256, U256}; + /// use cast::SimpleCast; + /// use ethers_core::types::{I256, U256}; + /// /// assert_eq!(SimpleCast::min_int("uint256")?, "0"); - /// assert_eq!(SimpleCast::min_int("int256")?, format!("{}", I256::MIN)); - /// assert_eq!(SimpleCast::min_int("int32")?, format!("{}", i32::MIN)); + /// assert_eq!(SimpleCast::min_int("int256")?, I256::MIN.to_string()); + /// assert_eq!(SimpleCast::min_int("int32")?, i32::MIN.to_string()); /// # Ok::<(), eyre::Report>(()) /// ``` pub fn min_int(s: &str) -> Result { @@ -1050,13 +1048,10 @@ impl SimpleCast { /// ``` /// use cast::SimpleCast as Cast; /// - /// fn main() -> eyre::Result<()> { - /// assert_eq!(Cast::from_utf8("yo"), "0x796f"); - /// assert_eq!(Cast::from_utf8("Hello, World!"), "0x48656c6c6f2c20576f726c6421"); - /// assert_eq!(Cast::from_utf8("TurboDappTools"), "0x547572626f44617070546f6f6c73"); - /// - /// Ok(()) - /// } + /// assert_eq!(Cast::from_utf8("yo"), "0x796f"); + /// assert_eq!(Cast::from_utf8("Hello, World!"), "0x48656c6c6f2c20576f726c6421"); + /// assert_eq!(Cast::from_utf8("TurboDappTools"), "0x547572626f44617070546f6f6c73"); + /// # Ok::<_, eyre::Report>(()) /// ``` pub fn from_utf8(s: &str) -> String { hex::encode_prefixed(s) @@ -1069,13 +1064,10 @@ impl SimpleCast { /// ``` /// use cast::SimpleCast as Cast; /// - /// fn main() -> eyre::Result<()> { - /// assert_eq!(Cast::to_ascii("0x796f")?, "yo"); - /// assert_eq!(Cast::to_ascii("48656c6c6f2c20576f726c6421")?, "Hello, World!"); - /// assert_eq!(Cast::to_ascii("0x547572626f44617070546f6f6c73")?, "TurboDappTools"); - /// - /// Ok(()) - /// } + /// assert_eq!(Cast::to_ascii("0x796f")?, "yo"); + /// assert_eq!(Cast::to_ascii("48656c6c6f2c20576f726c6421")?, "Hello, World!"); + /// assert_eq!(Cast::to_ascii("0x547572626f44617070546f6f6c73")?, "TurboDappTools"); + /// # Ok::<_, eyre::Report>(()) /// ``` pub fn to_ascii(hex: &str) -> Result { let bytes = hex::decode(hex)?; @@ -1090,14 +1082,11 @@ impl SimpleCast { /// use cast::SimpleCast as Cast; /// use ethers_core::types::U256; /// - /// fn main() -> eyre::Result<()> { - /// assert_eq!(Cast::from_fixed_point("10", "0")?, "10"); - /// assert_eq!(Cast::from_fixed_point("1.0", "1")?, "10"); - /// assert_eq!(Cast::from_fixed_point("0.10", "2")?, "10"); - /// assert_eq!(Cast::from_fixed_point("0.010", "3")?, "10"); - /// - /// Ok(()) - /// } + /// assert_eq!(Cast::from_fixed_point("10", "0")?, "10"); + /// assert_eq!(Cast::from_fixed_point("1.0", "1")?, "10"); + /// assert_eq!(Cast::from_fixed_point("0.10", "2")?, "10"); + /// assert_eq!(Cast::from_fixed_point("0.010", "3")?, "10"); + /// # Ok::<_, eyre::Report>(()) /// ``` pub fn from_fixed_point(value: &str, decimals: &str) -> Result { // first try u32 as Units assumes a string can only be "ether", "gwei"... and not a number @@ -1117,19 +1106,16 @@ impl SimpleCast { /// use cast::SimpleCast as Cast; /// use ethers_core::types::U256; /// - /// fn main() -> eyre::Result<()> { - /// assert_eq!(Cast::to_fixed_point("10", "0")?, "10."); - /// assert_eq!(Cast::to_fixed_point("10", "1")?, "1.0"); - /// assert_eq!(Cast::to_fixed_point("10", "2")?, "0.10"); - /// assert_eq!(Cast::to_fixed_point("10", "3")?, "0.010"); - /// - /// assert_eq!(Cast::to_fixed_point("-10", "0")?, "-10."); - /// assert_eq!(Cast::to_fixed_point("-10", "1")?, "-1.0"); - /// assert_eq!(Cast::to_fixed_point("-10", "2")?, "-0.10"); - /// assert_eq!(Cast::to_fixed_point("-10", "3")?, "-0.010"); + /// assert_eq!(Cast::to_fixed_point("10", "0")?, "10."); + /// assert_eq!(Cast::to_fixed_point("10", "1")?, "1.0"); + /// assert_eq!(Cast::to_fixed_point("10", "2")?, "0.10"); + /// assert_eq!(Cast::to_fixed_point("10", "3")?, "0.010"); /// - /// Ok(()) - /// } + /// assert_eq!(Cast::to_fixed_point("-10", "0")?, "-10."); + /// assert_eq!(Cast::to_fixed_point("-10", "1")?, "-1.0"); + /// assert_eq!(Cast::to_fixed_point("-10", "2")?, "-0.10"); + /// assert_eq!(Cast::to_fixed_point("-10", "3")?, "-0.010"); + /// # Ok::<_, eyre::Report>(()) /// ``` pub fn to_fixed_point(value: &str, decimals: &str) -> Result { let (sign, mut value, value_len) = { @@ -1161,12 +1147,9 @@ impl SimpleCast { /// ``` /// use cast::SimpleCast as Cast; /// - /// fn main() -> eyre::Result<()> { - /// assert_eq!(Cast::concat_hex(["0x00", "0x01"]), "0x0001"); - /// assert_eq!(Cast::concat_hex(["1", "2"]), "0x12"); - /// - /// Ok(()) - /// } + /// assert_eq!(Cast::concat_hex(["0x00", "0x01"]), "0x0001"); + /// assert_eq!(Cast::concat_hex(["1", "2"]), "0x12"); + /// # Ok::<_, eyre::Report>(()) /// ``` pub fn concat_hex>(values: impl IntoIterator) -> String { let mut out = String::new(); @@ -1184,16 +1167,21 @@ impl SimpleCast { /// ``` /// use cast::SimpleCast as Cast; /// - /// fn main() -> eyre::Result<()> { - /// assert_eq!(Cast::to_uint256("100")?, "0x0000000000000000000000000000000000000000000000000000000000000064"); - /// assert_eq!(Cast::to_uint256("192038293923")?, "0x0000000000000000000000000000000000000000000000000000002cb65fd1a3"); - /// assert_eq!( - /// Cast::to_uint256("115792089237316195423570985008687907853269984665640564039457584007913129639935")?, - /// "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" - /// ); - /// - /// Ok(()) - /// } + /// assert_eq!( + /// Cast::to_uint256("100")?, + /// "0x0000000000000000000000000000000000000000000000000000000000000064" + /// ); + /// assert_eq!( + /// Cast::to_uint256("192038293923")?, + /// "0x0000000000000000000000000000000000000000000000000000002cb65fd1a3" + /// ); + /// assert_eq!( + /// Cast::to_uint256( + /// "115792089237316195423570985008687907853269984665640564039457584007913129639935" + /// )?, + /// "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + /// ); + /// # Ok::<_, eyre::Report>(()) /// ``` pub fn to_uint256(value: &str) -> Result { let n = NumberWithBase::parse_uint(value, None)?; @@ -1207,23 +1195,39 @@ impl SimpleCast { /// ``` /// use cast::SimpleCast as Cast; /// - /// fn main() -> eyre::Result<()> { - /// assert_eq!(Cast::to_int256("0")?, "0x0000000000000000000000000000000000000000000000000000000000000000"); - /// assert_eq!(Cast::to_int256("100")?, "0x0000000000000000000000000000000000000000000000000000000000000064"); - /// assert_eq!(Cast::to_int256("-100")?, "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9c"); - /// assert_eq!(Cast::to_int256("192038293923")?, "0x0000000000000000000000000000000000000000000000000000002cb65fd1a3"); - /// assert_eq!(Cast::to_int256("-192038293923")?, "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffd349a02e5d"); - /// assert_eq!( - /// Cast::to_int256("57896044618658097711785492504343953926634992332820282019728792003956564819967")?, - /// "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" - /// ); - /// assert_eq!( - /// Cast::to_int256("-57896044618658097711785492504343953926634992332820282019728792003956564819968")?, - /// "0x8000000000000000000000000000000000000000000000000000000000000000" - /// ); - /// - /// Ok(()) - /// } + /// assert_eq!( + /// Cast::to_int256("0")?, + /// "0x0000000000000000000000000000000000000000000000000000000000000000" + /// ); + /// assert_eq!( + /// Cast::to_int256("100")?, + /// "0x0000000000000000000000000000000000000000000000000000000000000064" + /// ); + /// assert_eq!( + /// Cast::to_int256("-100")?, + /// "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9c" + /// ); + /// assert_eq!( + /// Cast::to_int256("192038293923")?, + /// "0x0000000000000000000000000000000000000000000000000000002cb65fd1a3" + /// ); + /// assert_eq!( + /// Cast::to_int256("-192038293923")?, + /// "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffd349a02e5d" + /// ); + /// assert_eq!( + /// Cast::to_int256( + /// "57896044618658097711785492504343953926634992332820282019728792003956564819967" + /// )?, + /// "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + /// ); + /// assert_eq!( + /// Cast::to_int256( + /// "-57896044618658097711785492504343953926634992332820282019728792003956564819968" + /// )?, + /// "0x8000000000000000000000000000000000000000000000000000000000000000" + /// ); + /// # Ok::<_, eyre::Report>(()) /// ``` pub fn to_int256(value: &str) -> Result { let n = NumberWithBase::parse_int(value, None)?; @@ -1237,14 +1241,11 @@ impl SimpleCast { /// ``` /// use cast::SimpleCast as Cast; /// - /// fn main() -> eyre::Result<()> { - /// assert_eq!(Cast::to_unit("1 wei", "wei")?, "1"); - /// assert_eq!(Cast::to_unit("1", "wei")?, "1"); - /// assert_eq!(Cast::to_unit("1ether", "wei")?, "1000000000000000000"); - /// assert_eq!(Cast::to_unit("100 gwei", "gwei")?, "100"); - /// - /// Ok(()) - /// } + /// assert_eq!(Cast::to_unit("1 wei", "wei")?, "1"); + /// assert_eq!(Cast::to_unit("1", "wei")?, "1"); + /// assert_eq!(Cast::to_unit("1ether", "wei")?, "1000000000000000000"); + /// assert_eq!(Cast::to_unit("100 gwei", "gwei")?, "100"); + /// # Ok::<_, eyre::Report>(()) /// ``` pub fn to_unit(value: &str, unit: &str) -> Result { let value = DynSolType::coerce_str(&DynSolType::Uint(256), value)? @@ -1285,15 +1286,12 @@ impl SimpleCast { /// ``` /// use cast::SimpleCast as Cast; /// - /// fn main() -> eyre::Result<()> { - /// assert_eq!(Cast::from_wei("1", "gwei")?, "0.000000001"); - /// assert_eq!(Cast::from_wei("12340000005", "gwei")?, "12.340000005"); - /// assert_eq!(Cast::from_wei("10", "ether")?, "0.000000000000000010"); - /// assert_eq!(Cast::from_wei("100", "eth")?, "0.000000000000000100"); - /// assert_eq!(Cast::from_wei("17", "")?, "0.000000000000000017"); - /// - /// Ok(()) - /// } + /// assert_eq!(Cast::from_wei("1", "gwei")?, "0.000000001"); + /// assert_eq!(Cast::from_wei("12340000005", "gwei")?, "12.340000005"); + /// assert_eq!(Cast::from_wei("10", "ether")?, "0.000000000000000010"); + /// assert_eq!(Cast::from_wei("100", "eth")?, "0.000000000000000100"); + /// assert_eq!(Cast::from_wei("17", "")?, "0.000000000000000017"); + /// # Ok::<_, eyre::Report>(()) /// ``` pub fn from_wei(value: &str, unit: &str) -> Result { let value = NumberWithBase::parse_int(value, None)?.number(); @@ -1311,14 +1309,11 @@ impl SimpleCast { /// ``` /// use cast::SimpleCast as Cast; /// - /// fn main() -> eyre::Result<()> { - /// assert_eq!(Cast::to_wei("1", "")?, "1000000000000000000"); - /// assert_eq!(Cast::to_wei("100", "gwei")?, "100000000000"); - /// assert_eq!(Cast::to_wei("100", "eth")?, "100000000000000000000"); - /// assert_eq!(Cast::to_wei("1000", "ether")?, "1000000000000000000000"); - /// - /// Ok(()) - /// } + /// assert_eq!(Cast::to_wei("1", "")?, "1000000000000000000"); + /// assert_eq!(Cast::to_wei("100", "gwei")?, "100000000000"); + /// assert_eq!(Cast::to_wei("100", "eth")?, "100000000000000000000"); + /// assert_eq!(Cast::to_wei("1000", "ether")?, "1000000000000000000000"); + /// # Ok::<_, eyre::Report>(()) /// ``` pub fn to_wei(value: &str, unit: &str) -> Result { let wei = match unit { @@ -1335,14 +1330,12 @@ impl SimpleCast { /// ``` /// use cast::SimpleCast as Cast; /// - /// fn main() -> eyre::Result<()> { - /// assert_eq!(Cast::from_rlp("0xc0".to_string()).unwrap(), "[]"); - /// assert_eq!(Cast::from_rlp("0x0f".to_string()).unwrap(), "\"0x0f\""); - /// assert_eq!(Cast::from_rlp("0x33".to_string()).unwrap(), "\"0x33\""); - /// assert_eq!(Cast::from_rlp("0xc161".to_string()).unwrap(), "[\"0x61\"]"); - /// assert_eq!(Cast::from_rlp("0xc26162".to_string()).unwrap(), "[\"0x61\",\"0x62\"]"); - /// Ok(()) - /// } + /// assert_eq!(Cast::from_rlp("0xc0").unwrap(), "[]"); + /// assert_eq!(Cast::from_rlp("0x0f").unwrap(), "\"0x0f\""); + /// assert_eq!(Cast::from_rlp("0x33").unwrap(), "\"0x33\""); + /// assert_eq!(Cast::from_rlp("0xc161").unwrap(), "[\"0x61\"]"); + /// assert_eq!(Cast::from_rlp("0xc26162").unwrap(), "[\"0x61\",\"0x62\"]"); + /// # Ok::<_, eyre::Report>(()) /// ``` pub fn from_rlp(value: impl AsRef) -> Result { let bytes = hex::decode(value.as_ref()).wrap_err("Could not decode hex")?; @@ -1357,13 +1350,11 @@ impl SimpleCast { /// ``` /// use cast::SimpleCast as Cast; /// - /// fn main() -> eyre::Result<()> { - /// assert_eq!(Cast::to_rlp("[]").unwrap(),"0xc0".to_string()); - /// assert_eq!(Cast::to_rlp("0x22").unwrap(),"0x22".to_string()); - /// assert_eq!(Cast::to_rlp("[\"0x61\"]",).unwrap(), "0xc161".to_string()); - /// assert_eq!(Cast::to_rlp( "[\"0xf1\",\"f2\"]").unwrap(), "0xc481f181f2".to_string()); - /// Ok(()) - /// } + /// assert_eq!(Cast::to_rlp("[]").unwrap(), "0xc0".to_string()); + /// assert_eq!(Cast::to_rlp("0x22").unwrap(), "0x22".to_string()); + /// assert_eq!(Cast::to_rlp("[\"0x61\"]",).unwrap(), "0xc161".to_string()); + /// assert_eq!(Cast::to_rlp("[\"0xf1\",\"f2\"]").unwrap(), "0xc481f181f2".to_string()); + /// # Ok::<_, eyre::Report>(()) /// ``` pub fn to_rlp(value: &str) -> Result { let val = serde_json::from_str(value) @@ -1380,27 +1371,34 @@ impl SimpleCast { /// use cast::SimpleCast as Cast; /// use ethers_core::types::{I256, U256}; /// - /// fn main() -> eyre::Result<()> { - /// assert_eq!(Cast::to_base("100", Some("10".to_string()), "16")?, "0x64"); - /// assert_eq!(Cast::to_base("100", Some("10".to_string()), "oct")?, "0o144"); - /// assert_eq!(Cast::to_base("100", Some("10".to_string()), "binary")?, "0b1100100"); - /// - /// assert_eq!(Cast::to_base("0xffffffffffffffff", None, "10")?, u64::MAX.to_string()); - /// assert_eq!(Cast::to_base("0xffffffffffffffffffffffffffffffff", None, "dec")?, u128::MAX.to_string()); - /// // U256::MAX overflows as internally it is being parsed as I256 - /// assert_eq!(Cast::to_base("0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", None, "decimal")?, I256::MAX.to_string()); - /// - /// Ok(()) - /// } - /// ``` - pub fn to_base(value: &str, base_in: Option, base_out: &str) -> Result { + /// assert_eq!(Cast::to_base("100", Some("10"), "16")?, "0x64"); + /// assert_eq!(Cast::to_base("100", Some("10"), "oct")?, "0o144"); + /// assert_eq!(Cast::to_base("100", Some("10"), "binary")?, "0b1100100"); + /// + /// assert_eq!(Cast::to_base("0xffffffffffffffff", None, "10")?, u64::MAX.to_string()); + /// assert_eq!( + /// Cast::to_base("0xffffffffffffffffffffffffffffffff", None, "dec")?, + /// u128::MAX.to_string() + /// ); + /// // U256::MAX overflows as internally it is being parsed as I256 + /// assert_eq!( + /// Cast::to_base( + /// "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + /// None, + /// "decimal" + /// )?, + /// I256::MAX.to_string() + /// ); + /// # Ok::<_, eyre::Report>(()) + /// ``` + pub fn to_base(value: &str, base_in: Option<&str>, base_out: &str) -> Result { let base_in = Base::unwrap_or_detect(base_in, value)?; let base_out: Base = base_out.parse()?; if base_in == base_out { return Ok(value.to_string()) } - let mut n = NumberWithBase::parse_int(value, Some(base_in.to_string()))?; + let mut n = NumberWithBase::parse_int(value, Some(&base_in.to_string()))?; n.set_base(base_out); // Use Debug fmt @@ -1414,7 +1412,6 @@ impl SimpleCast { /// ``` /// use cast::SimpleCast as Cast; /// - /// # fn main() -> eyre::Result<()> { /// let bytes = Cast::to_bytes32("1234")?; /// assert_eq!(bytes, "0x1234000000000000000000000000000000000000000000000000000000000000"); /// @@ -1423,9 +1420,7 @@ impl SimpleCast { /// /// let err = Cast::to_bytes32("0x123400000000000000000000000000000000000000000000000000000000000011").unwrap_err(); /// assert_eq!(err.to_string(), "string >32 bytes"); - /// - /// # Ok(()) - /// # } + /// # Ok::<_, eyre::Report>(()) pub fn to_bytes32(s: &str) -> Result { let s = strip_0x(s); if s.len() > 64 { @@ -1485,7 +1480,6 @@ impl SimpleCast { /// use cast::SimpleCast as Cast; /// use hex; /// - /// fn main() -> eyre::Result<()> { /// // Passing `input = false` will decode the data as the output type. /// // The input data types and the full function sig are ignored, i.e. /// // you could also pass `balanceOf()(uint256)` and it'd still work. @@ -1513,10 +1507,7 @@ impl SimpleCast { /// decoded, /// vec!["0x8dbd1b711dc621e1404633da156fcc779e1c6f3e", "0xd9f3c9cc99548bf3b44a43e0a2d07399eb918adc", "42", "1", ""] /// ); - /// - /// - /// # Ok(()) - /// } + /// # Ok::<_, eyre::Report>(()) /// ``` pub fn abi_decode(sig: &str, calldata: &str, input: bool) -> Result> { foundry_common::abi::abi_decode_calldata(sig, calldata, input, false) @@ -1530,16 +1521,14 @@ impl SimpleCast { /// /// ``` /// use cast::SimpleCast as Cast; - /// use hex; /// - /// fn main() -> eyre::Result<()> { - /// // Passing `input = false` will decode the data as the output type. - /// // The input data types and the full function sig are ignored, i.e. - /// // you could also pass `balanceOf()(uint256)` and it'd still work. - /// let data = "0x0000000000000000000000000000000000000000000000000000000000000001"; - /// let sig = "balanceOf(address, uint256)(uint256)"; - /// let decoded = Cast::calldata_decode(sig, data, false)?[0].as_uint().unwrap().0.to_string(); - /// assert_eq!(decoded, "1"); + /// // Passing `input = false` will decode the data as the output type. + /// // The input data types and the full function sig are ignored, i.e. + /// // you could also pass `balanceOf()(uint256)` and it'd still work. + /// let data = "0x0000000000000000000000000000000000000000000000000000000000000001"; + /// let sig = "balanceOf(address, uint256)(uint256)"; + /// let decoded = Cast::calldata_decode(sig, data, false)?[0].as_uint().unwrap().0.to_string(); + /// assert_eq!(decoded, "1"); /// /// // Passing `input = true` will decode the data with the input function signature. /// let data = "0xf242432a0000000000000000000000008dbd1b711dc621e1404633da156fcc779e1c6f3e000000000000000000000000d9f3c9cc99548bf3b44a43e0a2d07399eb918adc000000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000"; @@ -1558,10 +1547,7 @@ impl SimpleCast { /// decoded, /// vec!["0x8dbd1b711dc621e1404633da156fcc779e1c6f3e", "0xd9f3c9cc99548bf3b44a43e0a2d07399eb918adc", "42", "1", ""] /// ); - /// - /// - /// # Ok(()) - /// } + /// # Ok::<_, eyre::Report>(()) /// ``` pub fn calldata_decode(sig: &str, calldata: &str, input: bool) -> Result> { foundry_common::abi::abi_decode_calldata(sig, calldata, input, true) @@ -1573,19 +1559,17 @@ impl SimpleCast { /// # Example /// /// ``` - /// # use cast::SimpleCast as Cast; + /// use cast::SimpleCast as Cast; /// - /// # fn main() -> eyre::Result<()> { - /// assert_eq!( - /// "0x0000000000000000000000000000000000000000000000000000000000000001", - /// Cast::abi_encode("f(uint a)", &["1"]).unwrap().as_str() - /// ); - /// assert_eq!( - /// "0x0000000000000000000000000000000000000000000000000000000000000001", - /// Cast::abi_encode("constructor(uint a)", &["1"]).unwrap().as_str() - /// ); - /// # Ok(()) - /// # } + /// assert_eq!( + /// "0x0000000000000000000000000000000000000000000000000000000000000001", + /// Cast::abi_encode("f(uint a)", &["1"]).unwrap().as_str() + /// ); + /// assert_eq!( + /// "0x0000000000000000000000000000000000000000000000000000000000000001", + /// Cast::abi_encode("constructor(uint a)", &["1"]).unwrap().as_str() + /// ); + /// # Ok::<_, eyre::Report>(()) /// ``` pub fn abi_encode(sig: &str, args: &[impl AsRef]) -> Result { let func = match Function::parse(sig) { @@ -1607,15 +1591,13 @@ impl SimpleCast { /// # Example /// /// ``` - /// # use cast::SimpleCast as Cast; + /// use cast::SimpleCast as Cast; /// - /// # fn main() -> eyre::Result<()> { - /// assert_eq!( - /// "0x693c61390000000000000000000000000000000000000000000000000000000000000001", - /// Cast::calldata_encode("f(uint a)", &["1"]).unwrap().as_str() - /// ); - /// # Ok(()) - /// # } + /// assert_eq!( + /// "0x693c61390000000000000000000000000000000000000000000000000000000000000001", + /// Cast::calldata_encode("f(uint a)", &["1"]).unwrap().as_str() + /// ); + /// # Ok::<_, eyre::Report>(()) /// ``` pub fn calldata_encode(sig: impl AsRef, args: &[impl AsRef]) -> Result { let func = Function::parse(sig.as_ref())?; @@ -1627,14 +1609,11 @@ impl SimpleCast { /// Etherscan. It returns a vector of [`InterfaceSource`] structs that contain the source of the /// interface and their name. /// ```no_run - /// use cast::SimpleCast as Cast; - /// use cast::AbiPath; + /// use cast::{AbiPath, SimpleCast as Cast}; /// # async fn foo() -> eyre::Result<()> { - /// let path = AbiPath::Local { - /// path: "utils/testdata/interfaceTestABI.json".to_owned(), - /// name: None, - /// }; - /// let interfaces= Cast::generate_interface(path).await?; + /// let path = + /// AbiPath::Local { path: "utils/testdata/interfaceTestABI.json".to_owned(), name: None }; + /// let interfaces = Cast::generate_interface(path).await?; /// println!("interface {} {{\n {}\n}}", interfaces[0].name, interfaces[0].source); /// # Ok(()) /// # } @@ -1702,12 +1681,15 @@ impl SimpleCast { /// ``` /// # use cast::SimpleCast as Cast; /// - /// # fn main() -> eyre::Result<()> { - /// - /// assert_eq!(Cast::index("address", "0xD0074F4E6490ae3f888d1d4f7E3E43326bD3f0f5" ,"2").unwrap().as_str(),"0x9525a448a9000053a4d151336329d6563b7e80b24f8e628e95527f218e8ab5fb"); - /// assert_eq!(Cast::index("uint256","42" ,"6").unwrap().as_str(),"0xfc808b0f31a1e6b9cf25ff6289feae9b51017b392cc8e25620a94a38dcdafcc1"); - /// # Ok(()) - /// # } + /// assert_eq!( + /// Cast::index("address", "0xD0074F4E6490ae3f888d1d4f7E3E43326bD3f0f5", "2").unwrap().as_str(), + /// "0x9525a448a9000053a4d151336329d6563b7e80b24f8e628e95527f218e8ab5fb" + /// ); + /// assert_eq!( + /// Cast::index("uint256", "42", "6").unwrap().as_str(), + /// "0xfc808b0f31a1e6b9cf25ff6289feae9b51017b392cc8e25620a94a38dcdafcc1" + /// ); + /// # Ok::<_, eyre::Report>(()) /// ``` pub fn index(from_type: &str, from_value: &str, slot_number: &str) -> Result { let sig = format!("x({from_type},uint256)"); @@ -1725,14 +1707,23 @@ impl SimpleCast { /// ``` /// use cast::SimpleCast as Cast; /// - /// fn main() -> eyre::Result<()> { - /// assert_eq!(Cast::namehash("")?, "0x0000000000000000000000000000000000000000000000000000000000000000"); - /// assert_eq!(Cast::namehash("eth")?, "0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae"); - /// assert_eq!(Cast::namehash("foo.eth")?, "0xde9b09fd7c5f901e23a3f19fecc54828e9c848539801e86591bd9801b019f84f"); - /// assert_eq!(Cast::namehash("sub.foo.eth")?, "0x500d86f9e663479e5aaa6e99276e55fc139c597211ee47d17e1e92da16a83402"); - /// - /// Ok(()) - /// } + /// assert_eq!( + /// Cast::namehash("")?, + /// "0x0000000000000000000000000000000000000000000000000000000000000000" + /// ); + /// assert_eq!( + /// Cast::namehash("eth")?, + /// "0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae" + /// ); + /// assert_eq!( + /// Cast::namehash("foo.eth")?, + /// "0xde9b09fd7c5f901e23a3f19fecc54828e9c848539801e86591bd9801b019f84f" + /// ); + /// assert_eq!( + /// Cast::namehash("sub.foo.eth")?, + /// "0x500d86f9e663479e5aaa6e99276e55fc139c597211ee47d17e1e92da16a83402" + /// ); + /// # Ok::<_, eyre::Report>(()) /// ``` pub fn namehash(ens: &str) -> Result { let mut node = vec![0u8; 32]; @@ -1761,14 +1752,23 @@ impl SimpleCast { /// ``` /// use cast::SimpleCast as Cast; /// - /// fn main() -> eyre::Result<()> { - /// assert_eq!(Cast::keccak("foo")?, "0x41b1a0649752af1b28b3dc29a1556eee781e4a4c3a1f7f53f90fa834de098c4d"); - /// assert_eq!(Cast::keccak("123abc")?, "0xb1f1c74a1ba56f07a892ea1110a39349d40f66ca01d245e704621033cb7046a4"); - /// assert_eq!(Cast::keccak("0x12")?, "0x5fa2358263196dbbf23d1ca7a509451f7a2f64c15837bfbb81298b1e3e24e4fa"); - /// assert_eq!(Cast::keccak("12")?, "0x7f8b6b088b6d74c2852fc86c796dca07b44eed6fb3daf5e6b59f7c364db14528"); - /// - /// Ok(()) - /// } + /// assert_eq!( + /// Cast::keccak("foo")?, + /// "0x41b1a0649752af1b28b3dc29a1556eee781e4a4c3a1f7f53f90fa834de098c4d" + /// ); + /// assert_eq!( + /// Cast::keccak("123abc")?, + /// "0xb1f1c74a1ba56f07a892ea1110a39349d40f66ca01d245e704621033cb7046a4" + /// ); + /// assert_eq!( + /// Cast::keccak("0x12")?, + /// "0x5fa2358263196dbbf23d1ca7a509451f7a2f64c15837bfbb81298b1e3e24e4fa" + /// ); + /// assert_eq!( + /// Cast::keccak("12")?, + /// "0x7f8b6b088b6d74c2852fc86c796dca07b44eed6fb3daf5e6b59f7c364db14528" + /// ); + /// # Ok::<_, eyre::Report>(()) /// ``` pub fn keccak(data: &str) -> Result { let hash = match data.as_bytes() { @@ -1788,18 +1788,15 @@ impl SimpleCast { /// ``` /// use cast::SimpleCast as Cast; /// - /// fn main() -> eyre::Result<()> { - /// assert_eq!(Cast::left_shift("16", "10", Some("10".to_string()), "hex")?, "0x4000"); - /// assert_eq!(Cast::left_shift("255", "16", Some("dec".to_string()), "hex")?, "0xff0000"); - /// assert_eq!(Cast::left_shift("0xff", "16", None, "hex")?, "0xff0000"); - /// - /// Ok(()) - /// } + /// assert_eq!(Cast::left_shift("16", "10", Some("10"), "hex")?, "0x4000"); + /// assert_eq!(Cast::left_shift("255", "16", Some("dec"), "hex")?, "0xff0000"); + /// assert_eq!(Cast::left_shift("0xff", "16", None, "hex")?, "0xff0000"); + /// # Ok::<_, eyre::Report>(()) /// ``` pub fn left_shift( value: &str, bits: &str, - base_in: Option, + base_in: Option<&str>, base_out: &str, ) -> Result { let base_out: Base = base_out.parse()?; @@ -1818,18 +1815,15 @@ impl SimpleCast { /// ``` /// use cast::SimpleCast as Cast; /// - /// fn main() -> eyre::Result<()> { - /// assert_eq!(Cast::right_shift("0x4000", "10", None, "dec")?, "16"); - /// assert_eq!(Cast::right_shift("16711680", "16", Some("10".to_string()), "hex")?, "0xff"); - /// assert_eq!(Cast::right_shift("0xff0000", "16", None, "hex")?, "0xff"); - /// - /// Ok(()) - /// } + /// assert_eq!(Cast::right_shift("0x4000", "10", None, "dec")?, "16"); + /// assert_eq!(Cast::right_shift("16711680", "16", Some("10"), "hex")?, "0xff"); + /// assert_eq!(Cast::right_shift("0xff0000", "16", None, "hex")?, "0xff"); + /// # Ok::<(), eyre::Report>(()) /// ``` pub fn right_shift( value: &str, bits: &str, - base_in: Option, + base_in: Option<&str>, base_out: &str, ) -> Result { let base_out: Base = base_out.parse()?; @@ -1850,13 +1844,20 @@ impl SimpleCast { /// # use ethers_core::types::Chain; /// /// # async fn foo() -> eyre::Result<()> { - /// assert_eq!( - /// "/* + /// assert_eq!( + /// "/* /// - Bytecode Verification performed was compared on second iteration - /// This file is part of the DAO.....", - /// Cast::etherscan_source(Chain::Mainnet, "0xBB9bc244D798123fDe783fCc1C72d3Bb8C189413".to_string(), "".to_string()).await.unwrap().as_str() - /// ); - /// # Ok(()) + /// Cast::etherscan_source( + /// Chain::Mainnet, + /// "0xBB9bc244D798123fDe783fCc1C72d3Bb8C189413".to_string(), + /// "".to_string() + /// ) + /// .await + /// .unwrap() + /// .as_str() + /// ); + /// # Ok(()) /// # } /// ``` pub async fn etherscan_source( @@ -1880,8 +1881,14 @@ impl SimpleCast { /// # use std::path::PathBuf; /// /// # async fn expand() -> eyre::Result<()> { - /// Cast::expand_etherscan_source_to_directory(Chain::Mainnet, "0xBB9bc244D798123fDe783fCc1C72d3Bb8C189413".to_string(), "".to_string(), PathBuf::from("output_dir")).await?; - /// # Ok(()) + /// Cast::expand_etherscan_source_to_directory( + /// Chain::Mainnet, + /// "0xBB9bc244D798123fDe783fCc1C72d3Bb8C189413".to_string(), + /// "".to_string(), + /// PathBuf::from("output_dir"), + /// ) + /// .await?; + /// # Ok(()) /// # } /// ``` pub async fn expand_etherscan_source_to_directory( @@ -1923,23 +1930,19 @@ impl SimpleCast { /// ``` /// use cast::SimpleCast as Cast; /// - /// fn main() -> eyre::Result<()> { - /// assert_eq!(Cast::get_selector("foo(address,uint256)", None)?.0, String::from("0xbd0d639f")); - /// - /// Ok(()) - /// } + /// assert_eq!(Cast::get_selector("foo(address,uint256)", 0)?.0, String::from("0xbd0d639f")); + /// # Ok::<(), eyre::Error>(()) /// ``` - pub fn get_selector(signature: &str, optimize: Option) -> Result<(String, String)> { - let optimize = optimize.unwrap_or(0); + pub fn get_selector(signature: &str, optimize: usize) -> Result<(String, String)> { if optimize > 4 { - eyre::bail!("Number of leading zeroes must not be greater than 4"); + eyre::bail!("number of leading zeroes must not be greater than 4"); } if optimize == 0 { let selector = Function::parse(signature)?.selector(); return Ok((selector.to_string(), String::from(signature))) } let Some((name, params)) = signature.split_once('(') else { - eyre::bail!("Invalid signature"); + eyre::bail!("invalid function signature"); }; let num_threads = std::thread::available_parallelism().map_or(1, |n| n.get()); @@ -1980,12 +1983,9 @@ impl SimpleCast { /// ``` /// use cast::SimpleCast as Cast; /// - /// fn main() -> eyre::Result<()> { /// let tx = "0x02f8f582a86a82058d8459682f008508351050808303fd84948e42f2f4101563bf679975178e880fd87d3efd4e80b884659ac74b00000000000000000000000080f0c1c49891dcfdd40b6e0f960f84e6042bcb6f000000000000000000000000b97ef9ef8734c71904d8002f8b6bc66dd9c48a6e00000000000000000000000000000000000000000000000000000000007ff4e20000000000000000000000000000000000000000000000000000000000000064c001a05d429597befe2835396206781b199122f2e8297327ed4a05483339e7a8b2022aa04c23a7f70fb29dda1b4ee342fb10a625e9b8ddc6a603fb4e170d4f6f37700cb8"; /// let (tx, sig) = Cast::decode_raw_transaction(&tx)?; - /// - /// Ok(()) - /// } + /// # Ok::<(), eyre::Report>(()) pub fn decode_raw_transaction(tx: &str) -> Result<(TypedTransaction, Signature)> { let tx_hex = hex::decode(strip_0x(tx))?; let tx_rlp = rlp::Rlp::new(tx_hex.as_slice()); @@ -2004,15 +2004,12 @@ mod tests { #[test] fn simple_selector() { - assert_eq!("0xc2985578", Cast::get_selector("foo()", None).unwrap().0.as_str()) + assert_eq!("0xc2985578", Cast::get_selector("foo()", 0).unwrap().0.as_str()) } #[test] fn selector_with_arg() { - assert_eq!( - "0xbd0d639f", - Cast::get_selector("foo(address,uint256)", None).unwrap().0.as_str() - ) + assert_eq!("0xbd0d639f", Cast::get_selector("foo(address,uint256)", 0).unwrap().0.as_str()) } #[test] diff --git a/crates/cast/src/tx.rs b/crates/cast/src/tx.rs index 2b376edff422..65b1b7e08701 100644 --- a/crates/cast/src/tx.rs +++ b/crates/cast/src/tx.rs @@ -26,17 +26,18 @@ pub type TxBuilderPeekOutput<'a> = (&'a TypedTransaction, &'a Option); /// Transaction builder /// ``` -/// async fn foo() -> eyre::Result<()> { -/// use ethers_core::types::Chain; -/// use alloy_primitives::U256; -/// use cast::TxBuilder; -/// let provider = ethers_providers::test_provider::MAINNET.provider(); -/// let mut builder = TxBuilder::new(&provider, "a.eth", Some("b.eth"), Chain::Mainnet, false).await?; -/// builder -/// .gas(Some(U256::from(1))); -/// let (tx, _) = builder.build(); -/// Ok(()) -/// } +/// # async fn foo() -> eyre::Result<()> { +/// use alloy_primitives::U256; +/// use cast::TxBuilder; +/// use ethers_core::types::Chain; +/// +/// let provider = ethers_providers::test_provider::MAINNET.provider(); +/// let mut builder = +/// TxBuilder::new(&provider, "a.eth", Some("b.eth"), Chain::Mainnet, false).await?; +/// builder.gas(Some(U256::from(1))); +/// let (tx, _) = builder.build(); +/// # Ok(()) +/// # } /// ``` impl<'a, M: Middleware> TxBuilder<'a, M> { /// Create a new TxBuilder diff --git a/crates/cheatcodes/src/impls/evm/fork.rs b/crates/cheatcodes/src/impls/evm/fork.rs index c4d7c410062a..de722e7722bd 100644 --- a/crates/cheatcodes/src/impls/evm/fork.rs +++ b/crates/cheatcodes/src/impls/evm/fork.rs @@ -222,7 +222,7 @@ impl Cheatcode for rpcCall { let Self { method, params } = self; let url = ccx.data.db.active_fork_url().ok_or_else(|| fmt_err!("no active fork URL found"))?; - let provider = ProviderBuilder::new(url).build()?; + let provider = ProviderBuilder::new(&url).build()?; let params_json: serde_json::Value = serde_json::from_str(params)?; let result = RuntimeOrHandle::new() @@ -250,7 +250,7 @@ impl Cheatcode for eth_getLogsCall { let url = ccx.data.db.active_fork_url().ok_or_else(|| fmt_err!("no active fork URL found"))?; - let provider = ProviderBuilder::new(url).build()?; + let provider = ProviderBuilder::new(&url).build()?; let mut filter = Filter::new().address(addr.to_ethers()).from_block(from_block).to_block(to_block); for (i, topic) in topics.iter().enumerate() { diff --git a/crates/common/src/abi.rs b/crates/common/src/abi.rs index c7917f761bc3..955fa80ad99b 100644 --- a/crates/common/src/abi.rs +++ b/crates/common/src/abi.rs @@ -1,26 +1,24 @@ -//! ABI related helper functions +//! ABI related helper functions. + use alloy_dyn_abi::{DynSolType, DynSolValue, FunctionExt, JsonAbiExt}; use alloy_json_abi::{AbiItem, Event, Function}; -use alloy_primitives::{hex, Address, Log, U256}; +use alloy_primitives::{hex, Address, Log}; use ethers_core::types::Chain; use eyre::{ContextCompat, Result}; use foundry_block_explorers::{contract::ContractMetadata, errors::EtherscanError, Client}; use std::{future::Future, pin::Pin}; -use yansi::Paint; - -use crate::calc::to_exponential_notation; /// Given a function and a vector of string arguments, it proceeds to convert the args to alloy /// [DynSolValue]s and then ABI encode them. -pub fn encode_function_args(func: &Function, args: &[impl AsRef]) -> Result> { - let params: Result> = func - .inputs - .iter() - .zip(args) - .map(|(input, arg)| (input.selector_type().clone(), arg.as_ref())) - .map(|(ty, arg)| coerce_value(&ty, arg)) - .collect(); - Ok(func.abi_encode_input(params?.as_slice())?) +pub fn encode_function_args(func: &Function, args: I) -> Result> +where + I: IntoIterator, + S: AsRef, +{ + let params = std::iter::zip(&func.inputs, args) + .map(|(input, arg)| coerce_value(&input.selector_type(), arg.as_ref())) + .collect::>>()?; + func.abi_encode_input(params.as_slice()).map_err(Into::into) } /// Decodes the calldata of the function @@ -32,16 +30,18 @@ pub fn abi_decode_calldata( ) -> Result> { let func = Function::parse(sig)?; let calldata = hex::decode(calldata)?; + + let mut calldata = calldata.as_slice(); + // If function selector is prefixed in "calldata", remove it (first 4 bytes) + if input && fn_selector && calldata.len() >= 4 { + calldata = &calldata[4..]; + } + let res = if input { - // If function selector is prefixed in "calldata", remove it (first 4 bytes) - if fn_selector { - func.abi_decode_input(&calldata[4..], false)? - } else { - func.abi_decode_input(&calldata, false)? - } + func.abi_decode_input(calldata, false) } else { - func.abi_decode_output(&calldata, false)? - }; + func.abi_decode_output(calldata, false) + }?; // in case the decoding worked but nothing was decoded if res.is_empty() { @@ -51,95 +51,6 @@ pub fn abi_decode_calldata( Ok(res) } -/// Parses string input as Token against the expected ParamType -pub fn parse_tokens<'a, I: IntoIterator>( - params: I, -) -> Result> { - let mut tokens = Vec::new(); - - for (param, value) in params.into_iter() { - let token = DynSolType::coerce_str(param, value)?; - tokens.push(token); - } - Ok(tokens) -} - -/// Pretty print a slice of tokens. -pub fn format_tokens(tokens: &[DynSolValue]) -> impl Iterator + '_ { - tokens.iter().map(format_token) -} - -/// Gets pretty print strings for tokens -pub fn format_token(param: &DynSolValue) -> String { - match param { - DynSolValue::Address(addr) => addr.to_checksum(None), - DynSolValue::FixedBytes(bytes, _) => hex::encode_prefixed(bytes), - DynSolValue::Bytes(bytes) => hex::encode_prefixed(bytes), - DynSolValue::Int(num, _) => format!("{}", num), - DynSolValue::Uint(num, _) => format_uint_with_exponential_notation_hint(*num), - DynSolValue::Bool(b) => format!("{b}"), - DynSolValue::String(s) => s.to_string(), - DynSolValue::FixedArray(tokens) => { - let string = tokens.iter().map(format_token).collect::>().join(", "); - format!("[{string}]") - } - DynSolValue::Array(tokens) => { - let string = tokens.iter().map(format_token).collect::>().join(", "); - format!("[{string}]") - } - DynSolValue::Tuple(tokens) => { - let string = tokens.iter().map(format_token).collect::>().join(", "); - format!("({string})") - } - DynSolValue::CustomStruct { name: _, prop_names: _, tuple } => { - let string = tuple.iter().map(format_token).collect::>().join(", "); - format!("({string})") - } - DynSolValue::Function(f) => { - format!("{}", f.to_address_and_selector().1) - } - } -} - -/// Gets pretty print strings for tokens, without adding -/// exponential notation hints for large numbers (e.g. [1e7] for 10000000) -pub fn format_token_raw(param: &DynSolValue) -> String { - match param { - DynSolValue::Uint(num, _) => format!("{}", num), - DynSolValue::FixedArray(tokens) | DynSolValue::Array(tokens) => { - let string = tokens.iter().map(format_token_raw).collect::>().join(", "); - format!("[{string}]") - } - DynSolValue::Tuple(tokens) => { - let string = tokens.iter().map(format_token_raw).collect::>().join(", "); - format!("({string})") - } - _ => format_token(param), - } -} - -/// Formats a U256 number to string, adding an exponential notation _hint_ if it -/// is larger than `10_000`, with a precision of `4` figures, and trimming the -/// trailing zeros. -/// -/// Examples: -/// -/// ```text -/// 0 -> "0" -/// 1234 -> "1234" -/// 1234567890 -> "1234567890 [1.234e9]" -/// 1000000000000000000 -> "1000000000000000000 [1e18]" -/// 10000000000000000000000 -> "10000000000000000000000 [1e22]" -/// ``` -pub fn format_uint_with_exponential_notation_hint(num: U256) -> String { - if num.lt(&U256::from(10_000)) { - return num.to_string() - } - - let exp = to_exponential_notation(num, 4, true); - format!("{} {}", num, Paint::default(format!("[{}]", exp)).dimmed()) -} - /// Helper trait for converting types to Functions. Helpful for allowing the `call` /// function on the EVM to be generic over `String`, `&str` and `Function`. pub trait IntoFunction { @@ -281,11 +192,9 @@ fn coerce_value(ty: &str, arg: &str) -> Result { #[cfg(test)] mod tests { - use std::str::FromStr; - use super::*; use alloy_dyn_abi::EventExt; - use alloy_primitives::B256; + use alloy_primitives::{B256, U256}; #[test] fn test_get_func() { @@ -308,19 +217,6 @@ mod tests { assert_eq!(func.outputs[0].ty, "bytes4"); } - #[test] - fn parse_hex_uint_tokens() { - let param = DynSolType::Uint(256); - - let tokens = parse_tokens(std::iter::once((¶m, "100"))).unwrap(); - assert_eq!(tokens, vec![DynSolValue::Uint(U256::from(100), 256)]); - - let val: U256 = U256::from(100u64); - let hex_val = format!("0x{val:x}"); - let tokens = parse_tokens(std::iter::once((¶m, hex_val.as_str()))).unwrap(); - assert_eq!(tokens, vec![DynSolValue::Uint(U256::from(100), 256)]); - } - #[test] fn test_indexed_only_address() { let event = get_event("event Ev(address,uint256,address)").unwrap(); @@ -365,23 +261,4 @@ mod tests { assert_eq!(parsed.indexed[1], DynSolValue::Uint(U256::from_be_bytes([3; 32]), 256)); assert_eq!(parsed.indexed[2], DynSolValue::Address(Address::from_word(param2))); } - - #[test] - fn test_format_token_addr() { - // copied from testcases in https://github.com/ethereum/EIPs/blob/master/EIPS/eip-55.md - let eip55 = "0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed"; - assert_eq!( - format_token(&DynSolValue::Address(Address::from_str(&eip55.to_lowercase()).unwrap())), - eip55.to_string() - ); - - // copied from testcases in https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1191.md - let eip1191 = "0xFb6916095cA1Df60bb79ce92cE3EA74c37c5d359"; - assert_ne!( - format_token(&DynSolValue::Address( - Address::from_str(&eip1191.to_lowercase()).unwrap() - )), - eip1191.to_string() - ); - } } diff --git a/crates/common/src/calc.rs b/crates/common/src/calc.rs index 848c4c612952..2383e346f7d7 100644 --- a/crates/common/src/calc.rs +++ b/crates/common/src/calc.rs @@ -44,7 +44,7 @@ pub fn median_sorted(values: &[U256]) -> U256 { /// 10000000 -> 1e7 /// ``` #[inline] -pub fn to_exponential_notation(value: U256, precision: usize, trim_end_zeros: bool) -> String { +pub fn to_exp_notation(value: U256, precision: usize, trim_end_zeros: bool) -> String { let stringified = value.to_string(); let exponent = stringified.len() - 1; let mut mantissa = stringified.chars().take(precision).collect::(); @@ -61,7 +61,7 @@ pub fn to_exponential_notation(value: U256, precision: usize, trim_end_zeros: bo mantissa.insert(1, '.'); } - format!("{}e{}", mantissa, exponent) + format!("{mantissa}e{exponent}") } #[cfg(test)] @@ -119,18 +119,18 @@ mod tests { fn test_format_to_exponential_notation() { let value = 1234124124u64; - let formatted = to_exponential_notation(U256::from(value), 4, false); + let formatted = to_exp_notation(U256::from(value), 4, false); assert_eq!(formatted, "1.234e9"); - let formatted = to_exponential_notation(U256::from(value), 3, true); + let formatted = to_exp_notation(U256::from(value), 3, true); assert_eq!(formatted, "1.23e9"); let value = 10000000u64; - let formatted = to_exponential_notation(U256::from(value), 4, false); + let formatted = to_exp_notation(U256::from(value), 4, false); assert_eq!(formatted, "1.000e7"); - let formatted = to_exponential_notation(U256::from(value), 3, true); + let formatted = to_exp_notation(U256::from(value), 3, true); assert_eq!(formatted, "1e7"); } } diff --git a/crates/common/src/compile.rs b/crates/common/src/compile.rs index a990035244d3..83ab7bc1ab44 100644 --- a/crates/common/src/compile.rs +++ b/crates/common/src/compile.rs @@ -82,7 +82,8 @@ impl ProjectCompiler { /// use foundry_common::compile::ProjectCompiler; /// let config = foundry_config::Config::load(); /// ProjectCompiler::default() - /// .compile_with(&config.project().unwrap(), |prj| Ok(prj.compile()?)).unwrap(); + /// .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) -> Result diff --git a/crates/common/src/fmt.rs b/crates/common/src/fmt.rs index 67eac0e6f49f..ca7bc272f4ad 100644 --- a/crates/common/src/fmt.rs +++ b/crates/common/src/fmt.rs @@ -1,9 +1,164 @@ //! Helpers for formatting ethereum types -use crate::TransactionReceiptWithRevertReason; +use crate::{calc::to_exp_notation, TransactionReceiptWithRevertReason}; +use alloy_dyn_abi::{DynSolType, DynSolValue}; +use alloy_primitives::{hex, U256}; +use eyre::Result; +use std::fmt::{self, Display}; +use yansi::Paint; pub use foundry_macros::fmt::*; +/// [`DynSolValue`] formatter. +struct DynValueFormatter { + raw: bool, +} + +impl DynValueFormatter { + /// Recursively formats a [`DynSolValue`]. + fn value(&self, value: &DynSolValue, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match value { + DynSolValue::Address(inner) => Display::fmt(inner, f), + DynSolValue::Function(inner) => Display::fmt(inner, f), + DynSolValue::Bytes(inner) => f.write_str(&hex::encode_prefixed(inner)), + DynSolValue::FixedBytes(inner, _) => f.write_str(&hex::encode_prefixed(inner)), + DynSolValue::Uint(inner, _) => { + if self.raw { + write!(f, "{inner}") + } else { + f.write_str(&format_uint_exp(*inner)) + } + } + DynSolValue::Int(inner, _) => write!(f, "{inner}"), + DynSolValue::Array(values) | DynSolValue::FixedArray(values) => { + f.write_str("[")?; + self.list(values, f)?; + f.write_str("]") + } + DynSolValue::Tuple(values) => self.tuple(values, f), + DynSolValue::String(inner) => f.write_str(inner), + DynSolValue::Bool(inner) => Display::fmt(inner, f), + DynSolValue::CustomStruct { name, prop_names, tuple } => { + if self.raw { + return self.tuple(tuple, f); + } + + f.write_str(name)?; + f.write_str(" { ")?; + + for (i, (prop_name, value)) in std::iter::zip(prop_names, tuple).enumerate() { + if i > 0 { + f.write_str(", ")?; + } + f.write_str(prop_name)?; + f.write_str(": ")?; + self.value(value, f)?; + } + + f.write_str(" }") + } + } + } + + /// Recursively formats a comma-separated list of [`DynSolValue`]s. + fn list(&self, values: &[DynSolValue], f: &mut fmt::Formatter<'_>) -> fmt::Result { + for (i, value) in values.iter().enumerate() { + if i > 0 { + f.write_str(", ")?; + } + self.value(value, f)?; + } + Ok(()) + } + + /// Formats the given values as a tuple. + fn tuple(&self, values: &[DynSolValue], f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("(")?; + self.list(values, f)?; + f.write_str(")") + } +} + +/// Wrapper that implements [`Display`] for a [`DynSolValue`]. +struct DynValueDisplay<'a> { + /// The value to display. + value: &'a DynSolValue, + /// The formatter. + formatter: DynValueFormatter, +} + +impl<'a> DynValueDisplay<'a> { + /// Creates a new [`Display`] wrapper for the given value. + #[inline] + fn new(value: &'a DynSolValue, raw: bool) -> Self { + Self { value, formatter: DynValueFormatter { raw } } + } +} + +impl fmt::Display for DynValueDisplay<'_> { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.formatter.value(self.value, f) + } +} + +/// Parses string input as Token against the expected ParamType +pub fn parse_tokens<'a, I: IntoIterator>( + params: I, +) -> Result> { + let mut tokens = Vec::new(); + for (param, value) in params { + let token = DynSolType::coerce_str(param, value)?; + tokens.push(token); + } + Ok(tokens) +} + +/// Pretty-prints a slice of tokens using [`format_token`]. +pub fn format_tokens(tokens: &[DynSolValue]) -> impl Iterator + '_ { + tokens.iter().map(format_token) +} + +/// Pretty-prints the given value into a string suitable for user output. +pub fn format_token(value: &DynSolValue) -> String { + DynValueDisplay::new(value, false).to_string() +} + +/// Pretty-prints the given value into a string suitable for re-parsing as values later. +/// +/// This means: +/// - integers are not formatted with exponential notation hints +/// - structs are formatted as tuples, losing the struct and property names +pub fn format_token_raw(value: &DynSolValue) -> String { + DynValueDisplay::new(value, true).to_string() +} + +/// Formats a U256 number to string, adding an exponential notation _hint_ if it +/// is larger than `10_000`, with a precision of `4` figures, and trimming the +/// trailing zeros. +/// +/// # Examples +/// +/// ``` +/// use alloy_primitives::U256; +/// use foundry_common::fmt::format_uint_exp as f; +/// +/// yansi::Paint::disable(); +/// assert_eq!(f(U256::from(0)), "0"); +/// assert_eq!(f(U256::from(1234)), "1234"); +/// assert_eq!(f(U256::from(1234567890)), "1234567890 [1.234e9]"); +/// assert_eq!(f(U256::from(1000000000000000000_u128)), "1000000000000000000 [1e18]"); +/// assert_eq!(f(U256::from(10000000000000000000000_u128)), "10000000000000000000000 [1e22]"); +/// ``` +pub fn format_uint_exp(num: U256) -> String { + if num < U256::from(10_000) { + return num.to_string() + } + + let exp = to_exp_notation(num, 4, true); + format!("{} {}", num, Paint::default(format!("[{exp}]")).dimmed()) +} + impl UIfmt for TransactionReceiptWithRevertReason { fn pretty(&self) -> String { if let Some(revert_reason) = &self.revert_reason { @@ -48,3 +203,41 @@ pub fn get_pretty_tx_receipt_attr( _ => None, } } + +#[cfg(test)] +mod tests { + use super::*; + use alloy_primitives::address; + + #[test] + fn parse_hex_uint() { + let ty = DynSolType::Uint(256); + + let values = parse_tokens(std::iter::once((&ty, "100"))).unwrap(); + assert_eq!(values, [DynSolValue::Uint(U256::from(100), 256)]); + + let val: U256 = U256::from(100u64); + let hex_val = format!("0x{val:x}"); + let values = parse_tokens(std::iter::once((&ty, hex_val.as_str()))).unwrap(); + assert_eq!(values, [DynSolValue::Uint(U256::from(100), 256)]); + } + + #[test] + fn format_addr() { + // copied from testcases in https://github.com/ethereum/EIPs/blob/master/EIPS/eip-55.md + assert_eq!( + format_token(&DynSolValue::Address(address!( + "5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed" + ))), + "0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed", + ); + + // copied from testcases in https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1191.md + assert_ne!( + format_token(&DynSolValue::Address(address!( + "Fb6916095cA1Df60bb79ce92cE3EA74c37c5d359" + ))), + "0xFb6916095cA1Df60bb79ce92cE3EA74c37c5d359" + ); + } +} diff --git a/crates/common/src/provider.rs b/crates/common/src/provider.rs index 7695260d9b4e..79bae27c98c8 100644 --- a/crates/common/src/provider.rs +++ b/crates/common/src/provider.rs @@ -4,11 +4,9 @@ use crate::{runtime_client::RuntimeClient, ALCHEMY_FREE_TIER_CUPS, REQUEST_TIMEO use ethers_core::types::{Chain, U256}; use ethers_middleware::gas_oracle::{GasCategory, GasOracle, Polygon}; use ethers_providers::{is_local_endpoint, Middleware, Provider, DEFAULT_LOCAL_POLL_INTERVAL}; -use eyre::WrapErr; -use reqwest::{IntoUrl, Url}; +use eyre::{Result, WrapErr}; +use reqwest::Url; use std::{ - borrow::Cow, - env, path::{Path, PathBuf}, time::Duration, }; @@ -20,35 +18,40 @@ pub type RetryProvider = Provider; /// Helper type alias for a rpc url pub type RpcUrl = String; -/// Same as `try_get_http_provider` +/// Constructs a provider with a 100 millisecond interval poll if it's a localhost URL (most likely +/// an anvil or other dev node) and with the default, or 7 second otherwise. +/// +/// See [`try_get_http_provider`] for more details. /// /// # Panics /// -/// If invalid URL +/// Panics if the URL is invalid. /// -/// # Example +/// # Examples /// /// ``` /// use foundry_common::get_http_provider; -/// # fn f() { -/// let retry_provider = get_http_provider("http://localhost:8545"); -/// # } +/// +/// let retry_provider = get_http_provider("http://localhost:8545"); /// ``` -pub fn get_http_provider(builder: impl Into) -> RetryProvider { +#[inline] +#[track_caller] +pub fn get_http_provider(builder: impl AsRef) -> RetryProvider { try_get_http_provider(builder).unwrap() } -/// Gives out a provider with a `100ms` interval poll if it's a localhost URL (most likely an anvil -/// or other dev node) and with the default, `7s` if otherwise. -pub fn try_get_http_provider(builder: impl Into) -> eyre::Result { - builder.into().build() +/// Constructs a provider with a 100 millisecond interval poll if it's a localhost URL (most likely +/// an anvil or other dev node) and with the default, or 7 second otherwise. +#[inline] +pub fn try_get_http_provider(builder: impl AsRef) -> Result { + ProviderBuilder::new(builder.as_ref()).build() } /// Helper type to construct a `RetryProvider` #[derive(Debug)] pub struct ProviderBuilder { // Note: this is a result, so we can easily chain builder calls - url: eyre::Result, + url: Result, chain: Chain, max_retry: u32, timeout_retry: u32, @@ -64,12 +67,16 @@ pub struct ProviderBuilder { impl ProviderBuilder { /// Creates a new builder instance - pub fn new(url: impl IntoUrl) -> Self { - let url_str = url.as_str(); + pub fn new(url_str: &str) -> Self { + // a copy is needed for the next lines to work + let mut url_str = url_str; + + // invalid url: non-prefixed URL scheme is not allowed, so we prepend the default http + // prefix + let storage; if url_str.starts_with("localhost:") { - // invalid url: non-prefixed URL scheme is not allowed, so we prepend the default http - // prefix - return Self::new(format!("http://{url_str}")) + storage = format!("http://{url_str}"); + url_str = storage.as_str(); } let url = Url::parse(url_str) @@ -78,20 +85,14 @@ impl ProviderBuilder { let path = Path::new(url_str); if let Ok(path) = resolve_path(path) { - Url::parse( - format!( - "file://{path_str}", - path_str = path.to_str().expect("Should be valid string") - ) - .as_str(), - ) + Url::parse(&format!("file://{}", path.display())) } else { Err(err) } } _ => Err(err), }) - .wrap_err(format!("Invalid provider url: {url_str}")); + .wrap_err_with(|| format!("invalid provider URL: {url_str:?}")); Self { url, @@ -175,8 +176,8 @@ impl ProviderBuilder { } /// Same as [`Self:build()`] but also retrieves the `chainId` in order to derive an appropriate - /// interval - pub async fn connect(self) -> eyre::Result { + /// interval. + pub async fn connect(self) -> Result { let mut provider = self.build()?; if let Some(blocktime) = provider.get_chainid().await.ok().and_then(|id| { Chain::try_from(id).ok().and_then(|chain| chain.average_blocktime_hint()) @@ -186,8 +187,8 @@ impl ProviderBuilder { Ok(provider) } - /// Constructs the `RetryProvider` taking all configs into account - pub fn build(self) -> eyre::Result { + /// Constructs the `RetryProvider` taking all configs into account. + pub fn build(self) -> Result { let ProviderBuilder { url, chain, @@ -200,8 +201,10 @@ impl ProviderBuilder { } = self; let url = url?; + let is_local = is_local_endpoint(url.as_str()); + let mut provider = Provider::new(RuntimeClient::new( - url.clone(), + url, max_retry, timeout_retry, initial_backoff, @@ -210,38 +213,13 @@ impl ProviderBuilder { jwt, )); - let is_local = is_local_endpoint(url.as_str()); - if is_local { provider = provider.interval(DEFAULT_LOCAL_POLL_INTERVAL); } else if let Some(blocktime) = chain.average_blocktime_hint() { provider = provider.interval(blocktime / 2); } - Ok(provider) - } -} - -impl<'a> From<&'a str> for ProviderBuilder { - fn from(url: &'a str) -> Self { - Self::new(url) - } -} - -impl<'a> From<&'a String> for ProviderBuilder { - fn from(url: &'a String) -> Self { - url.as_str().into() - } -} - -impl From for ProviderBuilder { - fn from(url: String) -> Self { - url.as_str().into() - } -} -impl<'a> From> for ProviderBuilder { - fn from(url: Cow<'a, str>) -> Self { - url.as_ref().into() + Ok(provider) } } @@ -254,7 +232,7 @@ impl<'a> From> for ProviderBuilder { pub async fn estimate_eip1559_fees( provider: &M, chain: Option, -) -> eyre::Result<(U256, U256)> +) -> Result<(U256, U256)> where M::Error: 'static, { @@ -282,21 +260,18 @@ fn resolve_path(path: &Path) -> Result { if path.is_absolute() { Ok(path.to_path_buf()) } else { - Ok(env::current_dir() - .map(|current_dir| current_dir.join(path)) - .expect("Current directory should exist")) + std::env::current_dir().map(|d| d.join(path)).map_err(drop) } } #[cfg(windows)] fn resolve_path(path: &Path) -> Result { - let path_str = path.to_str().expect("Path should be a valid string"); - - if path_str.starts_with(r"\\.\pipe\") { - Ok(PathBuf::from(path_str)) - } else { - Err(()) + if let Some(s) = path.to_str() { + if s.starts_with(r"\\.\pipe\") { + return Ok(path.to_path_buf()); + } } + Err(()) } #[cfg(test)] diff --git a/crates/common/src/selectors.rs b/crates/common/src/selectors.rs index a1220b6b6a80..42cb03c87444 100644 --- a/crates/common/src/selectors.rs +++ b/crates/common/src/selectors.rs @@ -241,12 +241,17 @@ impl SignEthClient { /// Pretty print calldata and if available, fetch possible function signatures /// /// ```no_run - /// /// use foundry_common::selectors::SignEthClient; /// /// # async fn foo() -> eyre::Result<()> { - /// let pretty_data = SignEthClient::new()?.pretty_calldata("0x70a08231000000000000000000000000d0074f4e6490ae3f888d1d4f7e3e43326bd3f0f5".to_string(), false).await?; - /// println!("{}",pretty_data); + /// let pretty_data = SignEthClient::new()? + /// .pretty_calldata( + /// "0x70a08231000000000000000000000000d0074f4e6490ae3f888d1d4f7e3e43326bd3f0f5" + /// .to_string(), + /// false, + /// ) + /// .await?; + /// println!("{}", pretty_data); /// # Ok(()) /// # } /// ``` @@ -388,12 +393,15 @@ pub async fn decode_event_topic(topic: &str) -> eyre::Result> { /// Pretty print calldata and if available, fetch possible function signatures /// /// ```no_run -/// /// use foundry_common::selectors::pretty_calldata; /// /// # async fn foo() -> eyre::Result<()> { -/// let pretty_data = pretty_calldata("0x70a08231000000000000000000000000d0074f4e6490ae3f888d1d4f7e3e43326bd3f0f5".to_string(), false).await?; -/// println!("{}",pretty_data); +/// let pretty_data = pretty_calldata( +/// "0x70a08231000000000000000000000000d0074f4e6490ae3f888d1d4f7e3e43326bd3f0f5".to_string(), +/// false, +/// ) +/// .await?; +/// println!("{}", pretty_data); /// # Ok(()) /// # } /// ``` diff --git a/crates/common/src/units.rs b/crates/common/src/units.rs index 937c95498853..3a85ba3e04b1 100644 --- a/crates/common/src/units.rs +++ b/crates/common/src/units.rs @@ -1,7 +1,7 @@ //! Unit conversion utilities. use alloy_primitives::{Address, ParseSignedError, I256, U256}; -use std::{convert::TryFrom, fmt, str::FromStr}; +use std::{fmt, str::FromStr}; use thiserror::Error; /// I256 overflows for numbers wider than 77 units. diff --git a/crates/config/src/inline/conf_parser.rs b/crates/config/src/inline/conf_parser.rs index 7402ce6de0e0..1b8de84d1224 100644 --- a/crates/config/src/inline/conf_parser.rs +++ b/crates/config/src/inline/conf_parser.rs @@ -82,25 +82,21 @@ where Ok(()) } - /// Given a list of `config_lines, returns all available pairs (key, value) - /// matching the current config key + /// Given a list of config lines, returns all available pairs (key, value) matching the current + /// config key. /// - /// i.e. Given the `invariant` config key and a vector of config lines - /// ```rust - /// let _config_lines = vec![ - /// "forge-config: default.invariant.runs = 500", - /// "forge-config: default.invariant.depth = 500", - /// "forge-config: ci.invariant.depth = 500", - /// "forge-config: ci.fuzz.runs = 10" - /// ]; - /// ``` - /// would return the whole set of `invariant` configs. - /// ```rust - /// let _result = vec![ - /// ("runs", "500"), - /// ("depth", "500"), - /// ("depth", "500"), - /// ]; + /// # Examples + /// + /// ```ignore + /// assert_eq!( + /// get_config_overrides(&[ + /// "forge-config: default.invariant.runs = 500", + /// "forge-config: default.invariant.depth = 500", + /// "forge-config: ci.invariant.depth = 500", + /// "forge-config: ci.fuzz.runs = 10", + /// ]), + /// [("runs", "500"), ("depth", "500"), ("depth", "500")] + /// ); /// ``` fn get_config_overrides(config_lines: &[String]) -> Vec<(String, String)> { let mut result: Vec<(String, String)> = vec![]; diff --git a/crates/config/src/lib.rs b/crates/config/src/lib.rs index 04598261086c..8515f6df2f4e 100644 --- a/crates/config/src/lib.rs +++ b/crates/config/src/lib.rs @@ -374,13 +374,10 @@ pub struct Config { /// PRIVATE: This structure may grow, As such, constructing this structure should /// _always_ be done using a public constructor or update syntax: /// - /// ```rust + /// ```ignore /// use foundry_config::Config; /// - /// let config = Config { - /// src: "other".into(), - /// ..Default::default() - /// }; + /// let config = Config { src: "other".into(), ..Default::default() }; /// ``` #[doc(hidden)] #[serde(skip)] @@ -448,13 +445,12 @@ impl Config { /// # Example /// /// ```no_run + /// use figment::providers::{Env, Format, Toml}; /// use foundry_config::Config; - /// use figment::providers::{Toml, Format, Env}; /// /// // Use foundry's default `Figment`, but allow values from `other.toml` /// // to supersede its values. - /// let figment = Config::figment() - /// .merge(Toml::file("other.toml").nested()); + /// let figment = Config::figment().merge(Toml::file("other.toml").nested()); /// /// let config = Config::from_provider(figment); /// ``` @@ -469,13 +465,12 @@ impl Config { /// # Example /// /// ```rust + /// use figment::providers::{Env, Format, Toml}; /// use foundry_config::Config; - /// use figment::providers::{Toml, Format, Env}; /// /// // Use foundry's default `Figment`, but allow values from `other.toml` /// // to supersede its values. - /// let figment = Config::figment() - /// .merge(Toml::file("other.toml").nested()); + /// let figment = Config::figment().merge(Toml::file("other.toml").nested()); /// /// let config = Config::try_from(figment); /// ``` @@ -777,11 +772,10 @@ impl Config { /// # Example /// /// ``` - /// /// use foundry_config::Config; /// # fn t() { - /// let config = Config::with_root("./"); - /// let rpc_jwt = config.get_rpc_jwt_secret().unwrap().unwrap(); + /// let config = Config::with_root("./"); + /// let rpc_jwt = config.get_rpc_jwt_secret().unwrap().unwrap(); /// # } /// ``` pub fn get_rpc_jwt_secret(&self) -> Result>, UnresolvedEnvVarError> { @@ -797,11 +791,10 @@ impl Config { /// # Example /// /// ``` - /// /// use foundry_config::Config; /// # fn t() { - /// let config = Config::with_root("./"); - /// let rpc_url = config.get_rpc_url().unwrap().unwrap(); + /// let config = Config::with_root("./"); + /// let rpc_url = config.get_rpc_url().unwrap().unwrap(); /// # } /// ``` pub fn get_rpc_url(&self) -> Option, UnresolvedEnvVarError>> { @@ -822,11 +815,10 @@ impl Config { /// # Example /// /// ``` - /// /// use foundry_config::Config; /// # fn t() { - /// let config = Config::with_root("./"); - /// let rpc_url = config.get_rpc_url_with_alias("mainnet").unwrap().unwrap(); + /// let config = Config::with_root("./"); + /// let rpc_url = config.get_rpc_url_with_alias("mainnet").unwrap().unwrap(); /// # } /// ``` pub fn get_rpc_url_with_alias( @@ -842,11 +834,10 @@ impl Config { /// # Example /// /// ``` - /// /// use foundry_config::Config; /// # fn t() { - /// let config = Config::with_root("./"); - /// let rpc_url = config.get_rpc_url_or("http://localhost:8545").unwrap(); + /// let config = Config::with_root("./"); + /// let rpc_url = config.get_rpc_url_or("http://localhost:8545").unwrap(); /// # } /// ``` pub fn get_rpc_url_or<'a>( @@ -865,11 +856,10 @@ impl Config { /// # Example /// /// ``` - /// /// use foundry_config::Config; /// # fn t() { - /// let config = Config::with_root("./"); - /// let rpc_url = config.get_rpc_url_or_localhost_http().unwrap(); + /// let config = Config::with_root("./"); + /// let rpc_url = config.get_rpc_url_or_localhost_http().unwrap(); /// # } /// ``` pub fn get_rpc_url_or_localhost_http(&self) -> Result, UnresolvedEnvVarError> { @@ -886,12 +876,11 @@ impl Config { /// # Example /// /// ``` - /// /// use foundry_config::Config; /// # fn t() { - /// let config = Config::with_root("./"); - /// let etherscan_config = config.get_etherscan_config().unwrap().unwrap(); - /// let client = etherscan_config.into_client().unwrap(); + /// let config = Config::with_root("./"); + /// let etherscan_config = config.get_etherscan_config().unwrap().unwrap(); + /// let client = etherscan_config.into_client().unwrap(); /// # } /// ``` pub fn get_etherscan_config( @@ -2453,7 +2442,7 @@ impl ProviderExt for P {} /// # Example /// /// ```rust -/// use foundry_config::{Config, BasicConfig}; +/// use foundry_config::{BasicConfig, Config}; /// use serde::Deserialize; /// /// let my_config = Config::figment().extract::(); diff --git a/crates/config/src/macros.rs b/crates/config/src/macros.rs index eaf7ae7a5295..4bd501354f11 100644 --- a/crates/config/src/macros.rs +++ b/crates/config/src/macros.rs @@ -121,10 +121,11 @@ macro_rules! impl_figment_convert { /// Merge several nested `Provider` together with the type itself /// /// ```rust +/// use foundry_config::{ +/// figment::{value::*, *}, +/// impl_figment_convert, merge_impl_figment_convert, Config, +/// }; /// use std::path::PathBuf; -/// use foundry_config::{Config, merge_impl_figment_convert, impl_figment_convert}; -/// use foundry_config::figment::*; -/// use foundry_config::figment::value::*; /// /// #[derive(Default)] /// struct MyArgs { @@ -137,7 +138,7 @@ macro_rules! impl_figment_convert { /// } /// /// fn data(&self) -> Result, Error> { -/// todo!() +/// todo!() /// } /// } /// @@ -146,7 +147,7 @@ macro_rules! impl_figment_convert { /// #[derive(Default)] /// struct OuterArgs { /// value: u64, -/// inner: MyArgs +/// inner: MyArgs, /// } /// /// impl Provider for OuterArgs { @@ -155,7 +156,7 @@ macro_rules! impl_figment_convert { /// } /// /// fn data(&self) -> Result, Error> { -/// todo!() +/// todo!() /// } /// } /// diff --git a/crates/evm/core/src/decode.rs b/crates/evm/core/src/decode.rs index 7e3af7a217ae..1d941d94e359 100644 --- a/crates/evm/core/src/decode.rs +++ b/crates/evm/core/src/decode.rs @@ -7,7 +7,7 @@ use alloy_primitives::{B256, U256}; use alloy_sol_types::{sol_data::String as SolString, SolType}; use ethers::{abi::RawLog, contract::EthLogDecode, types::Log}; use foundry_abi::console::ConsoleEvents::{self, *}; -use foundry_common::{abi::format_token, SELECTOR_LEN}; +use foundry_common::{fmt::format_token, SELECTOR_LEN}; use foundry_utils::error::{ERROR_PREFIX, REVERT_PREFIX}; use itertools::Itertools; use once_cell::sync::Lazy; @@ -205,7 +205,7 @@ pub fn decode_revert( { let inputs = decoded .iter() - .map(foundry_common::abi::format_token) + .map(foundry_common::fmt::format_token) .collect::>() .join(", "); return Ok(format!("{}({inputs})", abi_error.name)) diff --git a/crates/evm/fuzz/src/lib.rs b/crates/evm/fuzz/src/lib.rs index ae95e16b8e89..b4bb0eb2106e 100644 --- a/crates/evm/fuzz/src/lib.rs +++ b/crates/evm/fuzz/src/lib.rs @@ -92,7 +92,7 @@ impl BaseCounterExample { impl fmt::Display for BaseCounterExample { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let args = foundry_common::abi::format_tokens(&self.args).collect::>().join(", "); + let args = foundry_common::fmt::format_tokens(&self.args).collect::>().join(", "); if let Some(sender) = self.sender { write!(f, "sender={sender} addr=")? diff --git a/crates/evm/traces/src/utils.rs b/crates/evm/traces/src/utils.rs index d5361491d0b5..c046fe5d6c16 100644 --- a/crates/evm/traces/src/utils.rs +++ b/crates/evm/traces/src/utils.rs @@ -3,7 +3,7 @@ use alloy_dyn_abi::{DynSolType, DynSolValue, JsonAbiExt}; use alloy_json_abi::{Function, JsonAbi as Abi}; use alloy_primitives::Address; -use foundry_common::{abi::format_token, SELECTOR_LEN}; +use foundry_common::{fmt::format_token, SELECTOR_LEN}; use foundry_evm_core::decode; use std::collections::HashMap; diff --git a/crates/forge/bin/cmd/create.rs b/crates/forge/bin/cmd/create.rs index 56c9886bfccd..a418b9c7d93c 100644 --- a/crates/forge/bin/cmd/create.rs +++ b/crates/forge/bin/cmd/create.rs @@ -17,7 +17,7 @@ use foundry_cli::{ opts::{CoreBuildArgs, EthereumOpts, EtherscanOpts, TransactionOpts}, utils::{self, read_constructor_args_file, remove_contract, LoadConfig}, }; -use foundry_common::{abi::parse_tokens, compile, estimate_eip1559_fees}; +use foundry_common::{compile, estimate_eip1559_fees, fmt::parse_tokens}; use foundry_compilers::{artifacts::BytecodeObject, info::ContractInfo, utils::canonicalized}; use foundry_utils::types::{ToAlloy, ToEthers}; use serde_json::json; diff --git a/crates/forge/bin/cmd/script/mod.rs b/crates/forge/bin/cmd/script/mod.rs index 48ec70fdcf41..e6f960ee8dce 100644 --- a/crates/forge/bin/cmd/script/mod.rs +++ b/crates/forge/bin/cmd/script/mod.rs @@ -27,10 +27,11 @@ use forge::{ }; use foundry_cli::opts::MultiWallet; use foundry_common::{ - abi::{encode_function_args, format_token}, + abi::encode_function_args, contracts::get_contract_name, errors::UnlinkedByteCode, evm::{Breakpoints, EvmArgs}, + fmt::format_token, shell, ContractsByArtifact, RpcUrl, CONTRACT_MAX_SIZE, SELECTOR_LEN, }; use foundry_compilers::{ diff --git a/crates/forge/bin/cmd/script/transaction.rs b/crates/forge/bin/cmd/script/transaction.rs index 100d8c349ba5..93002e1aec9b 100644 --- a/crates/forge/bin/cmd/script/transaction.rs +++ b/crates/forge/bin/cmd/script/transaction.rs @@ -4,7 +4,7 @@ use alloy_json_abi::Function; use alloy_primitives::{Address, B256}; use ethers::{prelude::NameOrAddress, types::transaction::eip2718::TypedTransaction}; use eyre::{ContextCompat, Result, WrapErr}; -use foundry_common::{abi::format_token_raw, RpcUrl, SELECTOR_LEN}; +use foundry_common::{fmt::format_token_raw, RpcUrl, SELECTOR_LEN}; use foundry_evm::{constants::DEFAULT_CREATE2_DEPLOYER, traces::CallTraceDecoder, utils::CallKind}; use foundry_utils::types::{ToAlloy, ToEthers}; use serde::{Deserialize, Serialize}; diff --git a/crates/forge/bin/cmd/verify/etherscan/mod.rs b/crates/forge/bin/cmd/verify/etherscan/mod.rs index 295bcc457090..57fdfeb9ab8b 100644 --- a/crates/forge/bin/cmd/verify/etherscan/mod.rs +++ b/crates/forge/bin/cmd/verify/etherscan/mod.rs @@ -421,7 +421,7 @@ impl EtherscanVerificationProvider { }; let encoded_args = encode_function_args( &func, - &read_constructor_args_file(constructor_args_path.to_path_buf())?, + read_constructor_args_file(constructor_args_path.to_path_buf())?, )?; let encoded_args = hex::encode(encoded_args); return Ok(Some(encoded_args[8..].into())) diff --git a/crates/macros/Cargo.toml b/crates/macros/Cargo.toml index 4d6354558fa2..de56c69b6b82 100644 --- a/crates/macros/Cargo.toml +++ b/crates/macros/Cargo.toml @@ -15,6 +15,3 @@ foundry-macros-impl = { path = "impl" } ethers-core.workspace = true serde.workspace = true serde_json.workspace = true - -alloy-primitives.workspace = true -alloy-dyn-abi.workspace = true diff --git a/crates/macros/src/fmt/mod.rs b/crates/macros/src/fmt/mod.rs index dada2b94e6a3..d6723bd897e7 100644 --- a/crates/macros/src/fmt/mod.rs +++ b/crates/macros/src/fmt/mod.rs @@ -3,8 +3,5 @@ mod ui; pub use ui::*; -mod token; -pub use token::*; - mod console_fmt; pub use console_fmt::{console_format, ConsoleFmt, FormatSpec}; diff --git a/crates/macros/src/fmt/token.rs b/crates/macros/src/fmt/token.rs deleted file mode 100644 index 9853ec7ed9d2..000000000000 --- a/crates/macros/src/fmt/token.rs +++ /dev/null @@ -1,54 +0,0 @@ -//! Formatting helpers for [`DynSolValue`]s. - -use alloy_dyn_abi::DynSolValue; -use alloy_primitives::hex; -use std::{fmt, fmt::Write}; - -/// Wrapper that pretty formats a [DynSolValue] -pub struct TokenDisplay<'a>(pub &'a DynSolValue); - -impl fmt::Display for TokenDisplay<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt_token(f, self.0) - } -} - -/// Recursively formats an ABI token. -fn fmt_token(f: &mut fmt::Formatter, item: &DynSolValue) -> fmt::Result { - match item { - DynSolValue::Address(inner) => { - write!(f, "{}", inner.to_checksum(None)) - } - // add 0x - DynSolValue::Bytes(inner) => f.write_str(&hex::encode_prefixed(inner)), - DynSolValue::FixedBytes(inner, _) => f.write_str(&hex::encode_prefixed(inner)), - // print as decimal - DynSolValue::Uint(inner, _) => write!(f, "{inner}"), - DynSolValue::Int(inner, _) => write!(f, "{}", *inner), - DynSolValue::Array(tokens) | DynSolValue::FixedArray(tokens) => { - f.write_char('[')?; - let mut tokens = tokens.iter().peekable(); - while let Some(token) = tokens.next() { - fmt_token(f, token)?; - if tokens.peek().is_some() { - f.write_char(',')? - } - } - f.write_char(']') - } - DynSolValue::Tuple(tokens) => { - f.write_char('(')?; - let mut tokens = tokens.iter().peekable(); - while let Some(token) = tokens.next() { - fmt_token(f, token)?; - if tokens.peek().is_some() { - f.write_char(',')? - } - } - f.write_char(')') - } - DynSolValue::String(inner) => write!(f, "{:?}", inner), - DynSolValue::Bool(inner) => write!(f, "{}", inner), - _ => write!(f, "{item:?}"), - } -} diff --git a/crates/macros/src/lib.rs b/crates/macros/src/lib.rs index 79c552b5cc0a..c193cb5d70be 100644 --- a/crates/macros/src/lib.rs +++ b/crates/macros/src/lib.rs @@ -7,7 +7,7 @@ extern crate self as foundry_macros; pub mod fmt; -pub use fmt::{console_format, ConsoleFmt, FormatSpec, TokenDisplay, UIfmt}; +pub use fmt::{console_format, ConsoleFmt, FormatSpec, UIfmt}; #[doc(inline)] pub use foundry_macros_impl::{Cheatcode, ConsoleFmt}; diff --git a/rustfmt.toml b/rustfmt.toml index 3b4a88a3cd6f..7fabf2c1de8f 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -7,6 +7,8 @@ binop_separator = "Back" trailing_comma = "Vertical" trailing_semicolon = false use_field_init_shorthand = true +format_code_in_doc_comments = true +doc_comment_code_block_width = 100 # Ignore automatically-generated code. ignore = ["crates/abi/src/bindings"]