From c7c7d848b6676ad863d07ee76f888c8ea409c970 Mon Sep 17 00:00:00 2001 From: Derek Cofausper <256792747+decofe@users.noreply.github.com> Date: Fri, 10 Apr 2026 14:01:58 +0200 Subject: [PATCH 01/12] clippy: warn on `if_then_some_else_none` (autofix) (#14235) clippy: warn on if_then_some_else_none Co-authored-by: zerosnacks <95942363+zerosnacks@users.noreply.github.com> --- Cargo.toml | 1 + crates/anvil/src/eth/api.rs | 2 +- crates/anvil/src/eth/backend/executor.rs | 8 +++----- crates/anvil/src/eth/backend/mem/mod.rs | 23 ++++++++--------------- crates/anvil/src/eth/fees.rs | 2 +- crates/anvil/src/eth/pool/transactions.rs | 6 +----- crates/cast/src/cmd/interface.rs | 2 +- crates/cast/src/cmd/wallet/mod.rs | 2 +- crates/cheatcodes/src/fs.rs | 2 +- crates/cheatcodes/src/inspector.rs | 2 +- crates/common/src/contracts.rs | 2 +- crates/config/src/fs_permissions.rs | 2 +- crates/config/src/providers/warnings.rs | 12 ++++-------- crates/doc/src/builder.rs | 2 +- crates/doc/src/document.rs | 8 +------- crates/doc/src/parser/comment.rs | 6 +----- crates/evm/core/src/buffer.rs | 17 +++++------------ crates/evm/evm/src/executors/fuzz/mod.rs | 2 +- crates/evm/evm/src/inspectors/stack.rs | 10 +++------- crates/evm/traces/src/decoder/mod.rs | 12 ++---------- crates/fmt/src/lib.rs | 2 +- crates/fmt/src/state/common.rs | 7 ++++--- crates/fmt/src/state/mod.rs | 6 +----- crates/fmt/src/state/sol.rs | 2 +- crates/forge/src/cmd/bind.rs | 2 +- crates/forge/src/cmd/compiler.rs | 12 +++--------- crates/forge/src/cmd/create.rs | 2 +- crates/forge/src/cmd/selectors.rs | 2 +- crates/forge/src/cmd/test/mod.rs | 11 +++-------- crates/lint/src/sol/gas/keccak.rs | 2 +- crates/lint/src/sol/mod.rs | 4 ++-- crates/script/src/verify.rs | 2 +- 32 files changed, 59 insertions(+), 118 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 73efb0b87a05a..37be5c76afc19 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -51,6 +51,7 @@ dbg_macro = "warn" empty_line_after_doc_comments = "warn" empty_line_after_outer_attr = "warn" explicit_iter_loop = "warn" +if_then_some_else_none = "warn" implicit_clone = "warn" imprecise_flops = "warn" iter_on_empty_collections = "warn" diff --git a/crates/anvil/src/eth/api.rs b/crates/anvil/src/eth/api.rs index af27b01dca34e..831e0f97c9913 100644 --- a/crates/anvil/src/eth/api.rs +++ b/crates/anvil/src/eth/api.rs @@ -418,7 +418,7 @@ impl EthApi { } }) .unwrap_or_default(), - network: if self.backend.is_tempo() { Some("tempo".to_string()) } else { None }, + network: self.backend.is_tempo().then(|| "tempo".to_string()), }) } diff --git a/crates/anvil/src/eth/backend/executor.rs b/crates/anvil/src/eth/backend/executor.rs index 70d3599a765f1..3df14f6ea86f3 100644 --- a/crates/anvil/src/eth/backend/executor.rs +++ b/crates/anvil/src/eth/backend/executor.rs @@ -436,13 +436,11 @@ where trace!(target: "backend", ?exit_reason, ?gas_used, "[{:?}] executed with out={:?}", pool_tx.hash(), out); trace!(target: "backend::executor", "transacted [{:?}], result: {:?} gas {}", pool_tx.hash(), exit_reason, gas_used); - let contract_address = if pending.transaction.to().is_none() { + let contract_address = pending.transaction.to().is_none().then(|| { let addr = sender.create(nonce); trace!(target: "backend", "Contract creation tx: computed address {:?}", addr); - Some(addr) - } else { - None - }; + addr + }); // TODO: replace `TransactionInfo` with alloy receipt/transaction types let transaction_index = tx_info.len() as u64; diff --git a/crates/anvil/src/eth/backend/mem/mod.rs b/crates/anvil/src/eth/backend/mem/mod.rs index fe8b4c37ea125..133cfd61f2bf7 100644 --- a/crates/anvil/src/eth/backend/mem/mod.rs +++ b/crates/anvil/src/eth/backend/mem/mod.rs @@ -1434,7 +1434,7 @@ impl Backend { let mut inspector = self.build_inspector(); // Extract Tempo-specific fields before `build_call_env` consumes `other`. - let tempo_overrides = if self.is_tempo() { + let tempo_overrides = self.is_tempo().then(|| { let fee_token = request.other.get_deserialized::
("feeToken").and_then(|r| r.ok()); let nonce_key = request @@ -1444,10 +1444,8 @@ impl Backend { .unwrap_or_default(); let valid_before = request.other.get_deserialized::("validBefore").and_then(|r| r.ok()); - Some((fee_token, nonce_key, valid_before)) - } else { - None - }; + (fee_token, nonce_key, valid_before) + }); let (evm_env, tx_env) = self.build_call_env(request, fee_details, block_env); @@ -2173,7 +2171,7 @@ impl Backend { } // Clear all storage and reinitialize with genesis - let base_fee = if self.fees.is_eip1559() { Some(self.fees.base_fee()) } else { None }; + let base_fee = self.fees.is_eip1559().then(|| self.fees.base_fee()); *self.blockchain.storage.write() = BlockchainStorage::new( &self.evm_env.read(), base_fee, @@ -2503,8 +2501,7 @@ where let mix_hash = evm_env.block_env.prevrandao; let beneficiary = evm_env.block_env.beneficiary; let timestamp = evm_env.block_env.timestamp; - let base_fee = - if spec_id >= SpecId::LONDON { Some(evm_env.block_env.basefee) } else { None }; + let base_fee = (spec_id >= SpecId::LONDON).then_some(evm_env.block_env.basefee); let excess_blob_gas = if is_cancun { evm_env.block_env.blob_excess_gas() } else { None }; @@ -2746,8 +2743,7 @@ where let mix_hash = evm_env.block_env.prevrandao; let beneficiary = evm_env.block_env.beneficiary; let timestamp = evm_env.block_env.timestamp; - let base_fee = - if spec_id >= SpecId::LONDON { Some(evm_env.block_env.basefee) } else { None }; + let base_fee = (spec_id >= SpecId::LONDON).then_some(evm_env.block_env.basefee); let excess_blob_gas = if is_cancun { evm_env.block_env.blob_excess_gas() } else { None }; let inspector_tx_config = self.inspector_tx_config(); @@ -3718,11 +3714,8 @@ impl> Backend { let best_number = self.blockchain.storage.read().best_number; let blocks = self.blockchain.storage.read().serialized_blocks(); let transactions = self.blockchain.storage.read().serialized_transactions(); - let historical_states = if preserve_historical_states { - Some(self.states.write().serialized_states()) - } else { - None - }; + let historical_states = + preserve_historical_states.then(|| self.states.write().serialized_states()); let state = self.db.read().await.dump_state( at, diff --git a/crates/anvil/src/eth/fees.rs b/crates/anvil/src/eth/fees.rs index c6a8660e02425..b7bef577d7fe6 100644 --- a/crates/anvil/src/eth/fees.rs +++ b/crates/anvil/src/eth/fees.rs @@ -120,7 +120,7 @@ impl FeeManager { } pub fn excess_blob_gas_and_price(&self) -> Option { - if self.is_eip4844() { Some(*self.blob_excess_gas_and_price.read()) } else { None } + self.is_eip4844().then(|| *self.blob_excess_gas_and_price.read()) } pub fn base_fee_per_blob_gas(&self) -> u128 { diff --git a/crates/anvil/src/eth/pool/transactions.rs b/crates/anvil/src/eth/pool/transactions.rs index 98c16fed375c9..049b3f217469f 100644 --- a/crates/anvil/src/eth/pool/transactions.rs +++ b/crates/anvil/src/eth/pool/transactions.rs @@ -515,11 +515,7 @@ impl ReadyTransactions { if let Some(idx) = tx2.unlocks.iter().position(|i| i == &hash) { tx2.unlocks.swap_remove(idx); } - if tx2.unlocks.is_empty() { - Some(tx2.transaction.transaction.provides.clone()) - } else { - None - } + tx2.unlocks.is_empty().then(|| tx2.transaction.transaction.provides.clone()) }; // find previous transactions diff --git a/crates/cast/src/cmd/interface.rs b/crates/cast/src/cmd/interface.rs index 634fc96d83c31..2e2051822dafc 100644 --- a/crates/cast/src/cmd/interface.rs +++ b/crates/cast/src/cmd/interface.rs @@ -80,7 +80,7 @@ impl InterfaceArgs { }; // Build config for to_sol conversion. - let config = if flatten { Some(ToSolConfig::new().one_contract(true)) } else { None }; + let config = flatten.then(|| ToSolConfig::new().one_contract(true)); // Retrieve interfaces from the array of ABIs. let interfaces = get_interfaces(abis, config)?; diff --git a/crates/cast/src/cmd/wallet/mod.rs b/crates/cast/src/cmd/wallet/mod.rs index 9381454f9b57b..8e0dd8dd3ed8c 100644 --- a/crates/cast/src/cmd/wallet/mod.rs +++ b/crates/cast/src/cmd/wallet/mod.rs @@ -313,7 +313,7 @@ impl WalletSubcommands { Self::New { path, account_name, unsafe_password, number, password, force } => { let mut rng = thread_rng(); - let mut json_values = if shell::is_json() { Some(vec![]) } else { None }; + let mut json_values = shell::is_json().then(std::vec::Vec::new); let path = if let Some(path) = path { match dunce::canonicalize(&path) { diff --git a/crates/cheatcodes/src/fs.rs b/crates/cheatcodes/src/fs.rs index 9f175c94d2f30..3f8bd91b0e8d9 100644 --- a/crates/cheatcodes/src/fs.rs +++ b/crates/cheatcodes/src/fs.rs @@ -549,7 +549,7 @@ fn get_artifact_code( // Try filtering by profile as well filtered.retain(|(id, _)| id.profile == running.profile); - if filtered.len() == 1 { Some(filtered[0]) } else { None } + (filtered.len() == 1).then(|| filtered[0]) }) .ok_or_else(|| fmt_err!("multiple matching artifacts found")), ) diff --git a/crates/cheatcodes/src/inspector.rs b/crates/cheatcodes/src/inspector.rs index 58d7c924622e9..cf6f0ebb6ece3 100644 --- a/crates/cheatcodes/src/inspector.rs +++ b/crates/cheatcodes/src/inspector.rs @@ -1548,7 +1548,7 @@ impl Inspector> for Cheatcode }, }; - if count != expected.count { Some((expected, count)) } else { None } + (count != expected.count).then_some((expected, count)) }) .collect::>(); diff --git a/crates/common/src/contracts.rs b/crates/common/src/contracts.rs index 06b2c29945417..c611d0723457e 100644 --- a/crates/common/src/contracts.rs +++ b/crates/common/src/contracts.rs @@ -628,7 +628,7 @@ pub fn find_matching_contract_artifact( // same but `id.path` is different. let artifact = possible_targets .iter() - .find_map(|(id, artifact)| if id.profile == "default" { Some(*artifact) } else { None }) + .find_map(|(id, artifact)| (id.profile == "default").then_some(*artifact)) .unwrap_or(target_artifact); Ok(artifact.clone()) diff --git a/crates/config/src/fs_permissions.rs b/crates/config/src/fs_permissions.rs index f8fba0c97a10e..bedd0c8cd3f04 100644 --- a/crates/config/src/fs_permissions.rs +++ b/crates/config/src/fs_permissions.rs @@ -90,7 +90,7 @@ impl FsPermissions { } } - if max_path_len > 0 { Some(highest_permission) } else { None } + (max_path_len > 0).then_some(highest_permission) } /// Updates all `allowed_paths` and joins ([`Path::join`]) the `root` with all entries diff --git a/crates/config/src/providers/warnings.rs b/crates/config/src/providers/warnings.rs index 9113fcd76fffa..930066b29cf73 100644 --- a/crates/config/src/providers/warnings.rs +++ b/crates/config/src/providers/warnings.rs @@ -89,14 +89,10 @@ impl WarningsProvider

{ // Add warning for deprecated keys. let deprecated_key_warning = |key| { DEPRECATIONS.iter().find_map(|(deprecated_key, new_value)| { - if key == *deprecated_key { - Some(Warning::DeprecatedKey { - old: deprecated_key.to_string(), - new: new_value.to_string(), - }) - } else { - None - } + (key == *deprecated_key).then(|| Warning::DeprecatedKey { + old: deprecated_key.to_string(), + new: new_value.to_string(), + }) }) }; let profiles = data diff --git a/crates/doc/src/builder.rs b/crates/doc/src/builder.rs index 30b0f9cd81179..aeffe590a1d12 100644 --- a/crates/doc/src/builder.rs +++ b/crates/doc/src/builder.rs @@ -393,7 +393,7 @@ impl DocBuilder { Some(self.config.book.clone()) } else { let book_path = self.config.book.join("book.toml"); - if book_path.is_file() { Some(book_path) } else { None } + book_path.is_file().then_some(book_path) } }; diff --git a/crates/doc/src/document.rs b/crates/doc/src/document.rs index cabc230e13b14..a41e0070ba3b5 100644 --- a/crates/doc/src/document.rs +++ b/crates/doc/src/document.rs @@ -101,13 +101,7 @@ impl DocumentContent { pub(crate) fn get_mut(&mut self, index: usize) -> Option<&mut ParseItem> { match self { Self::Empty => None, - Self::Single(item) => { - if index == 0 { - Some(item) - } else { - None - } - } + Self::Single(item) => (index == 0).then_some(item), Self::Constants(items) => items.get_mut(index), Self::OverloadedFunctions(items) => items.get_mut(index), } diff --git a/crates/doc/src/parser/comment.rs b/crates/doc/src/parser/comment.rs index 431bf70df88f5..1238b5f1a0a0f 100644 --- a/crates/doc/src/parser/comment.rs +++ b/crates/doc/src/parser/comment.rs @@ -86,11 +86,7 @@ impl Comment { /// Returns [None] if the word doesn't match. /// Useful for [CommentTag::Param] and [CommentTag::Return] comments. pub fn match_first_word(&self, expected: &str) -> Option<&str> { - self.split_first_word().and_then( - |(word, rest)| { - if word == expected { Some(rest) } else { None } - }, - ) + self.split_first_word().and_then(|(word, rest)| (word == expected).then_some(rest)) } /// Check if this comment is a custom tag. diff --git a/crates/evm/core/src/buffer.rs b/crates/evm/core/src/buffer.rs index e600708f43173..dc1947f4a6f05 100644 --- a/crates/evm/core/src/buffer.rs +++ b/crates/evm/core/src/buffer.rs @@ -83,17 +83,12 @@ pub fn get_buffer_accesses(op: u8, stack: &[U256]) -> Option { -2 => Some(1), -1 => Some(32), 0 => None, - 1.. => { - if (stack_index as usize) <= stack_len { - Some(stack[stack_len - stack_index as usize].saturating_to()) - } else { - None - } - } + 1.. => ((stack_index as usize) <= stack_len) + .then(|| stack[stack_len - stack_index as usize].saturating_to()), _ => panic!("invalid stack index"), }; - if buffer_access.0.is_some() || buffer_access.1.is_some() { + (buffer_access.0.is_some() || buffer_access.1.is_some()).then(|| { let (read, write) = buffer_access; let read_access = read.and_then(|b| { let (buffer, offset, len) = b; @@ -103,8 +98,6 @@ pub fn get_buffer_accesses(op: u8, stack: &[U256]) -> Option { let (offset, len) = b; Some(BufferAccess { offset: get_size(offset)?, len: get_size(len)? }) }); - Some(BufferAccesses { read: read_access, write: write_access }) - } else { - None - } + BufferAccesses { read: read_access, write: write_access } + }) } diff --git a/crates/evm/evm/src/executors/fuzz/mod.rs b/crates/evm/evm/src/executors/fuzz/mod.rs index 2b620eb65cd46..8ac18ffc3b812 100644 --- a/crates/evm/evm/src/executors/fuzz/mod.rs +++ b/crates/evm/evm/src/executors/fuzz/mod.rs @@ -437,7 +437,7 @@ impl FuzzedExecutor { self.config.corpus.clone(), strategy.boxed(), // Master worker replays the persisted corpus using the executor - if worker_id == 0 { Some(&self.executor_f) } else { None }, + (worker_id == 0).then_some(&self.executor_f), Some(func), None, // fuzzed_contracts for invariant tests )?; diff --git a/crates/evm/evm/src/inspectors/stack.rs b/crates/evm/evm/src/inspectors/stack.rs index 374dfca8febec..d4d9559acd1c9 100644 --- a/crates/evm/evm/src/inspectors/stack.rs +++ b/crates/evm/evm/src/inspectors/stack.rs @@ -459,13 +459,9 @@ impl CheatcodesExecutor for InspectorStackInner { fn set_in_inner_context(&mut self, enabled: bool, original_origin: Option

) { self.in_inner_context = enabled; - self.inner_context_data = if enabled { - Some(InnerContextData { - original_origin: original_origin.expect("origin required when enabling inner ctx"), - }) - } else { - None - }; + self.inner_context_data = enabled.then(|| InnerContextData { + original_origin: original_origin.expect("origin required when enabling inner ctx"), + }); } } diff --git a/crates/evm/traces/src/decoder/mod.rs b/crates/evm/traces/src/decoder/mod.rs index bf53210aebbb4..9ea9413817563 100644 --- a/crates/evm/traces/src/decoder/mod.rs +++ b/crates/evm/traces/src/decoder/mod.rs @@ -598,20 +598,12 @@ impl CallTraceDecoder { "broadcast" | "startBroadcast" => { // Redact private key if defined // broadcast(uint256) / startBroadcast(uint256) - if !func.inputs.is_empty() && func.inputs[0].ty == "uint256" { - Some(vec!["".to_string()]) - } else { - None - } + (!func.inputs.is_empty() && func.inputs[0].ty == "uint256").then(|| vec!["".to_string()]) } "getNonce" => { // Redact private key if defined // getNonce(Wallet) - if !func.inputs.is_empty() && func.inputs[0].ty == "tuple" { - Some(vec!["".to_string()]) - } else { - None - } + (!func.inputs.is_empty() && func.inputs[0].ty == "tuple").then(|| vec!["".to_string()]) } "sign" | "signP256" => { let mut decoded = func.abi_decode_input(&data[SELECTOR_LEN..]).ok()?; diff --git a/crates/fmt/src/lib.rs b/crates/fmt/src/lib.rs index c73e4c9553c18..db314074d23f0 100644 --- a/crates/fmt/src/lib.rs +++ b/crates/fmt/src/lib.rs @@ -234,7 +234,7 @@ pub fn format_ast<'ast>( gcx.sess.source_map(), true, config.wrap_comments, - if matches!(config.style, IndentStyle::Tab) { Some(config.tab_width) } else { None }, + matches!(config.style, IndentStyle::Tab).then(|| config.tab_width), ); let ast = source.ast.as_ref()?; let inline_config = parse_inline_config(gcx.sess, &comments, ast); diff --git a/crates/fmt/src/state/common.rs b/crates/fmt/src/state/common.rs index e3e37c5169329..481cda6d26806 100644 --- a/crates/fmt/src/state/common.rs +++ b/crates/fmt/src/state/common.rs @@ -601,9 +601,10 @@ impl<'ast> State<'_, 'ast> { let enabled = !self.inline_config.is_disabled(Span::new(block_lo, block_lo + BytePos(1))) && !self.handle_span(self.cursor.span(block_lo), true); - match self.peek_comment().and_then(|cmnt| { - if cmnt.span.hi() < block_lo { Some((cmnt.span, cmnt.style)) } else { None } - }) { + match self + .peek_comment() + .and_then(|cmnt| (cmnt.span.hi() < block_lo).then_some((cmnt.span, cmnt.style))) + { Some((span, style)) => { if enabled { // Inline config is not disabled and span not handled diff --git a/crates/fmt/src/state/mod.rs b/crates/fmt/src/state/mod.rs index e98eac6f4e5c1..ec8f2e69103b8 100644 --- a/crates/fmt/src/state/mod.rs +++ b/crates/fmt/src/state/mod.rs @@ -201,11 +201,7 @@ impl<'sess> State<'sess, '_> { Self { s: pp::Printer::new( config.line_length, - if matches!(config.style, IndentStyle::Tab) { - Some(config.tab_width) - } else { - None - }, + matches!(config.style, IndentStyle::Tab).then(|| config.tab_width), ), ind: config.tab_width as isize, sm, diff --git a/crates/fmt/src/state/sol.rs b/crates/fmt/src/state/sol.rs index f46455b2a6b5d..7138d3689074a 100644 --- a/crates/fmt/src/state/sol.rs +++ b/crates/fmt/src/state/sol.rs @@ -93,7 +93,7 @@ impl<'ast> State<'_, 'ast> { let cmnts = self .comments .iter() - .filter_map(|c| if c.pos() < span.lo() { Some(c.style) } else { None }) + .filter_map(|c| (c.pos() < span.lo()).then_some(c.style)) .collect::>(); if let Some(first) = cmnts.first() diff --git a/crates/forge/src/cmd/bind.rs b/crates/forge/src/cmd/bind.rs index 9ef8edc88f5d7..39108e01dd272 100644 --- a/crates/forge/src/cmd/bind.rs +++ b/crates/forge/src/cmd/bind.rs @@ -202,7 +202,7 @@ impl BindArgs { .get_json_files(artifacts)? .filter_map(|(name, path)| { trace!(?path, "parsing SolMacroGen from file"); - if dup.insert(name.clone()) { Some(SolMacroGen::new(path, name)) } else { None } + dup.insert(name.clone()).then(|| SolMacroGen::new(path, name)) }) .collect::>(); diff --git a/crates/forge/src/cmd/compiler.rs b/crates/forge/src/cmd/compiler.rs index 39d38b8b249ba..29c2e30cbb0c5 100644 --- a/crates/forge/src/cmd/compiler.rs +++ b/crates/forge/src/cmd/compiler.rs @@ -92,15 +92,9 @@ impl ResolveArgs { }) .collect(); - let evm_version = if shell::verbosity() > 1 { - let evm = EvmVersion::default() - .normalize_version_solc(version) - .unwrap_or_default(); - - Some(evm) - } else { - None - }; + let evm_version = (shell::verbosity() > 1).then(|| { + EvmVersion::default().normalize_version_solc(version).unwrap_or_default() + }); ResolvedCompiler { version: version.clone(), evm_version, paths } }) diff --git a/crates/forge/src/cmd/create.rs b/crates/forge/src/cmd/create.rs index a6337a266c9a8..64b4769beae46 100644 --- a/crates/forge/src/cmd/create.rs +++ b/crates/forge/src/cmd/create.rs @@ -504,7 +504,7 @@ impl CreateArgs { sh_println!("Starting contract verification...")?; let num_of_optimizations = if let Some(optimizer) = self.build.compiler.optimize { - if optimizer { Some(self.build.compiler.optimizer_runs.unwrap_or(200)) } else { None } + optimizer.then(|| self.build.compiler.optimizer_runs.unwrap_or(200)) } else { self.build.compiler.optimizer_runs }; diff --git a/crates/forge/src/cmd/selectors.rs b/crates/forge/src/cmd/selectors.rs index a0c319fe9c947..14f7e29dcde79 100644 --- a/crates/forge/src/cmd/selectors.rs +++ b/crates/forge/src/cmd/selectors.rs @@ -214,7 +214,7 @@ impl SelectorsSubcommands { .filter_map(|(k1, v1)| { second_method_map .iter() - .find_map(|(k2, v2)| if **v2 == *v1 { Some((k2, v2)) } else { None }) + .find_map(|(k2, v2)| (**v2 == *v1).then_some((k2, v2))) .map(|(k2, v2)| (v2, k1, k2)) }) .collect(); diff --git a/crates/forge/src/cmd/test/mod.rs b/crates/forge/src/cmd/test/mod.rs index c0a2da8cd528b..937b90162b08b 100644 --- a/crates/forge/src/cmd/test/mod.rs +++ b/crates/forge/src/cmd/test/mod.rs @@ -827,14 +827,9 @@ impl TestArgs { .iter() .filter_map(|(k, v)| { previous_snapshots.get(k).and_then(|previous_snapshot| { - if previous_snapshot != v { - Some(( - k.clone(), - (previous_snapshot.clone(), v.clone()), - )) - } else { - None - } + (previous_snapshot != v).then(|| { + (k.clone(), (previous_snapshot.clone(), v.clone())) + }) }) }) .collect(); diff --git a/crates/lint/src/sol/gas/keccak.rs b/crates/lint/src/sol/gas/keccak.rs index cb942510bbb49..b6a18f292a91b 100644 --- a/crates/lint/src/sol/gas/keccak.rs +++ b/crates/lint/src/sol/gas/keccak.rs @@ -91,7 +91,7 @@ fn extract_keccak256_arg<'hir>(expr: &'hir hir::Expr<'hir>) -> Option<&'hir hir: return None; }; - if is_keccak && args.len() == 1 { Some(&args[0]) } else { None } + (is_keccak && args.len() == 1).then(|| &args[0]) } // -- HELPER FUNCTIONS AND STRUCTS ---------------------------------------------------------------- diff --git a/crates/lint/src/sol/mod.rs b/crates/lint/src/sol/mod.rs index f9afac2b00443..8cac42a0dcf2d 100644 --- a/crates/lint/src/sol/mod.rs +++ b/crates/lint/src/sol/mod.rs @@ -147,7 +147,7 @@ impl<'a> SolidityLinter<'a> { .fold((Vec::new(), Vec::new()), |(mut passes, mut ids), (pass, lints)| { let included_ids: Vec<_> = lints .iter() - .filter_map(|lint| if self.include_lint(*lint) { Some(lint.id) } else { None }) + .filter_map(|lint| self.include_lint(*lint).then_some(lint.id)) .collect(); if !included_ids.is_empty() { @@ -198,7 +198,7 @@ impl<'a> SolidityLinter<'a> { .fold((Vec::new(), Vec::new()), |(mut passes, mut ids), (pass, lints)| { let included_ids: Vec<_> = lints .iter() - .filter_map(|lint| if self.include_lint(*lint) { Some(lint.id) } else { None }) + .filter_map(|lint| self.include_lint(*lint).then_some(lint.id)) .collect(); if !included_ids.is_empty() { diff --git a/crates/script/src/verify.rs b/crates/script/src/verify.rs index 0a2b171b379ba..4b5ec467bc240 100644 --- a/crates/script/src/verify.rs +++ b/crates/script/src/verify.rs @@ -78,7 +78,7 @@ impl VerifyBundle { cache_path: Some(project.paths.cache.clone()), lib_paths: project.paths.libraries.clone(), hardhat: config.profile == Config::HARDHAT_PROFILE, - config_path: if config_path.exists() { Some(config_path) } else { None }, + config_path: config_path.exists().then_some(config_path), }; let via_ir = config.via_ir; From 15bcd5e1b84f0cd1d19071d8328f2d24172269cb Mon Sep 17 00:00:00 2001 From: Derek Cofausper <256792747+decofe@users.noreply.github.com> Date: Fri, 10 Apr 2026 14:07:05 +0200 Subject: [PATCH 02/12] clippy: warn on `explicit_into_iter_loop` (autofix) (#14236) clippy: warn on explicit_into_iter_loop Co-authored-by: zerosnacks <95942363+zerosnacks@users.noreply.github.com> --- Cargo.toml | 1 + crates/anvil/src/eth/backend/db.rs | 4 ++-- crates/chisel/src/executor.rs | 2 +- crates/config/src/error.rs | 2 +- crates/config/src/etherscan.rs | 2 +- crates/evm/core/src/backend/mod.rs | 2 +- crates/forge/src/cmd/snapshot.rs | 2 +- crates/script-sequence/src/reader.rs | 2 +- 8 files changed, 9 insertions(+), 8 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 37be5c76afc19..ef1a8427a35d6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -50,6 +50,7 @@ collection_is_never_read = "warn" dbg_macro = "warn" empty_line_after_doc_comments = "warn" empty_line_after_outer_attr = "warn" +explicit_into_iter_loop = "warn" explicit_iter_loop = "warn" if_then_some_else_none = "warn" implicit_clone = "warn" diff --git a/crates/anvil/src/eth/backend/db.rs b/crates/anvil/src/eth/backend/db.rs index b27ee942c87bb..de9ad434252f3 100644 --- a/crates/anvil/src/eth/backend/db.rs +++ b/crates/anvil/src/eth/backend/db.rs @@ -226,7 +226,7 @@ pub trait Db: /// Deserialize and add all chain data to the backend storage fn load_state(&mut self, state: SerializableState) -> DatabaseResult { - for (addr, account) in state.accounts.into_iter() { + for (addr, account) in state.accounts { let old_account_nonce = DatabaseRef::basic_ref(self, addr) .ok() .and_then(|acc| acc.map(|acc| acc.nonce)) @@ -250,7 +250,7 @@ pub trait Db: }, ); - for (k, v) in account.storage.into_iter() { + for (k, v) in account.storage { self.set_storage_at(addr, k, v)?; } } diff --git a/crates/chisel/src/executor.rs b/crates/chisel/src/executor.rs index f5deb369ff963..96acfef54a1de 100644 --- a/crates/chisel/src/executor.rs +++ b/crates/chisel/src/executor.rs @@ -1607,7 +1607,7 @@ mod tests { T: AsRef + std::fmt::Display + 'a, I: IntoIterator + 'a, { - for (input, expected) in input.into_iter() { + for (input, expected) in input { let input = input.as_ref(); let ty = get_type_ethabi(s, input, true); assert_eq!(ty.as_ref(), Some(expected), "\n{input}"); diff --git a/crates/config/src/error.rs b/crates/config/src/error.rs index 4f9eddc5e3ad6..00a2f24910090 100644 --- a/crates/config/src/error.rs +++ b/crates/config/src/error.rs @@ -22,7 +22,7 @@ impl fmt::Display for ExtractConfigError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let mut unique_errors = Vec::with_capacity(self.error.count()); let mut unique = HashSet::with_capacity(self.error.count()); - for err in self.error.clone().into_iter() { + for err in self.error.clone() { let err = if err .metadata .as_ref() diff --git a/crates/config/src/etherscan.rs b/crates/config/src/etherscan.rs index 25772a8171303..4eca1582e2793 100644 --- a/crates/config/src/etherscan.rs +++ b/crates/config/src/etherscan.rs @@ -135,7 +135,7 @@ impl ResolvedEtherscanConfigs { self, chain: Chain, ) -> Option> { - for (_, config) in self.configs.into_iter() { + for (_, config) in self.configs { match config { Ok(c) if c.chain == Some(chain) => return Some(Ok(c)), Err(e) => return Some(Err(e)), diff --git a/crates/evm/core/src/backend/mod.rs b/crates/evm/core/src/backend/mod.rs index e7c1345792aa3..fcb5006d62e51 100644 --- a/crates/evm/core/src/backend/mod.rs +++ b/crates/evm/core/src/backend/mod.rs @@ -2006,7 +2006,7 @@ pub(crate) fn merge_account_data, ) { - for addr in accounts.into_iter() { + for addr in accounts { merge_db_account_data(addr, active, &mut target_fork.db); merge_journaled_state_data(addr, active_journaled_state, &mut target_fork.journaled_state); } diff --git a/crates/forge/src/cmd/snapshot.rs b/crates/forge/src/cmd/snapshot.rs index 1a37bd02aa4eb..de3e5c0c0e9b0 100644 --- a/crates/forge/src/cmd/snapshot.rs +++ b/crates/forge/src/cmd/snapshot.rs @@ -418,7 +418,7 @@ fn diff( let mut diffs = Vec::with_capacity(tests.len()); let mut new_tests = Vec::new(); - for test in tests.into_iter() { + for test in tests { if let Some(target_gas_used) = snaps.get(&(test.contract_name().to_string(), test.signature.clone())).cloned() { diff --git a/crates/script-sequence/src/reader.rs b/crates/script-sequence/src/reader.rs index 839ab77664202..4be6b42e4a35d 100644 --- a/crates/script-sequence/src/reader.rs +++ b/crates/script-sequence/src/reader.rs @@ -62,7 +62,7 @@ impl BroadcastReader { { // 1. Recursively read all .json files in the broadcast directory let mut broadcasts = vec![]; - for entry in walkdir::WalkDir::new(&self.broadcast_path).into_iter() { + for entry in walkdir::WalkDir::new(&self.broadcast_path) { let entry = entry?; let path = entry.path(); From 29c5f5e0376c0518adffdbaaa07858fb8c47058a Mon Sep 17 00:00:00 2001 From: Derek Cofausper <256792747+decofe@users.noreply.github.com> Date: Fri, 10 Apr 2026 14:15:53 +0200 Subject: [PATCH 03/12] chore(clippy): remove `literal_string_with_formatting_args` allow, no longer required (#14238) chore: remove literal_string_with_formatting_args allow The upstream clippy bug (rust-lang/rust-clippy#13885) was fixed in rust-lang/rust-clippy#13953 (merged Feb 2025). The workaround is no longer needed. Co-authored-by: zerosnacks <95942363+zerosnacks@users.noreply.github.com> --- Cargo.toml | 2 -- 1 file changed, 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ef1a8427a35d6..95898cd5bd310 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -94,8 +94,6 @@ significant_drop_tightening = "allow" too_long_first_doc_paragraph = "allow" # Specific allows. -# until is fixed -literal_string_with_formatting_args = "allow" result_large_err = "allow" [workspace.lints.rust] From 93b01f16084abf27bd6b83556bdeae3c20c56892 Mon Sep 17 00:00:00 2001 From: Derek Cofausper <256792747+decofe@users.noreply.github.com> Date: Fri, 10 Apr 2026 14:31:15 +0200 Subject: [PATCH 04/12] clippy: warn on `single_char_pattern` (autofix) (#14237) clippy: warn on single_char_pattern Co-authored-by: zerosnacks <95942363+zerosnacks@users.noreply.github.com> --- Cargo.toml | 1 + crates/anvil/src/lib.rs | 2 +- crates/common/src/comments/inline_config.rs | 2 +- crates/common/src/comments/mod.rs | 2 +- crates/common/src/contracts.rs | 2 +- crates/fmt/src/pp/convenience.rs | 2 +- crates/forge/src/cmd/test/mod.rs | 2 +- crates/forge/tests/cli/lint.rs | 2 +- crates/lint/src/sol/info/screaming_snake_case.rs | 4 ++-- crates/test-utils/src/ui_runner.rs | 2 +- 10 files changed, 11 insertions(+), 10 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 95898cd5bd310..0abd37f3bccdd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -68,6 +68,7 @@ nonstandard_macro_braces = "warn" path_buf_push_overwrite = "warn" read_zero_byte_vec = "warn" redundant_clone = "warn" +single_char_pattern = "warn" redundant_else = "warn" string_lit_chars_any = "warn" suboptimal_flops = "warn" diff --git a/crates/anvil/src/lib.rs b/crates/anvil/src/lib.rs index 6b2345aa3685f..c17a79bd71d20 100644 --- a/crates/anvil/src/lib.rs +++ b/crates/anvil/src/lib.rs @@ -465,7 +465,7 @@ pub fn init_tracing() -> LoggingManager { let manager = LoggingManager::default(); let _ = if let Ok(rust_log_val) = std::env::var("RUST_LOG") - && !rust_log_val.contains("=") + && !rust_log_val.contains('=') { // Mutate the given filter to include `node` logs if it is not already present. // This prevents the unexpected behaviour of not seeing any node logs if a RUST_LOG diff --git a/crates/common/src/comments/inline_config.rs b/crates/common/src/comments/inline_config.rs index 16ffd6993bfef..6244647adae26 100644 --- a/crates/common/src/comments/inline_config.rs +++ b/crates/common/src/comments/inline_config.rs @@ -46,7 +46,7 @@ impl InlineConfigItem> { vec!["all".to_string()] } else { match relevant.split_once(')') { - Some((id_str, _)) => id_str.split(",").map(|s| s.trim().to_string()).collect(), + Some((id_str, _)) => id_str.split(',').map(|s| s.trim().to_string()).collect(), None => return Err(InvalidInlineConfigItem::Syntax(s.into())), } }; diff --git a/crates/common/src/comments/mod.rs b/crates/common/src/comments/mod.rs index a3e4a8f3ec743..8f934f1311d44 100644 --- a/crates/common/src/comments/mod.rs +++ b/crates/common/src/comments/mod.rs @@ -380,7 +380,7 @@ fn format_doc_block_comment(line: &str, tab_width: Option) -> String { return (" *").to_string(); } - if let Some((_, rest_of_line)) = line.split_once("*") { + if let Some((_, rest_of_line)) = line.split_once('*') { if rest_of_line.is_empty() { (" *").to_string() } else if let Some(tab_width) = tab_width { diff --git a/crates/common/src/contracts.rs b/crates/common/src/contracts.rs index c611d0723457e..8238836491762 100644 --- a/crates/common/src/contracts.rs +++ b/crates/common/src/contracts.rs @@ -616,7 +616,7 @@ pub fn find_matching_contract_artifact( // If all artifact_ids in `possible_targets` have the same name (without ".", indicates // additional compiler profiles), it means that there are multiple contracts in the // same file. - if !target_id.name.contains(".") + if !target_id.name.contains('.') && possible_targets.iter().any(|(id, _)| id.name != target_id.name) { eyre::bail!( diff --git a/crates/fmt/src/pp/convenience.rs b/crates/fmt/src/pp/convenience.rs index 65e66d5d42097..bf025ae31c99c 100644 --- a/crates/fmt/src/pp/convenience.rs +++ b/crates/fmt/src/pp/convenience.rs @@ -76,7 +76,7 @@ impl Printer { return true; } - self.out.ends_with(" ") + self.out.ends_with(' ') } pub fn is_beginning_of_line(&self) -> bool { diff --git a/crates/forge/src/cmd/test/mod.rs b/crates/forge/src/cmd/test/mod.rs index 937b90162b08b..5560b5ebbd096 100644 --- a/crates/forge/src/cmd/test/mod.rs +++ b/crates/forge/src/cmd/test/mod.rs @@ -1046,7 +1046,7 @@ fn persist_run_failures(config: &Config, outcome: &TestOutcome) { let mut failures = outcome.failures().peekable(); while let Some((test_name, _)) = failures.next() { if test_name.is_any_test() - && let Some(test_match) = test_name.split("(").next() + && let Some(test_match) = test_name.split('(').next() { filter.push_str(test_match); if failures.peek().is_some() { diff --git a/crates/forge/tests/cli/lint.rs b/crates/forge/tests/cli/lint.rs index 05e6288d96f0e..fd69907be2f09 100644 --- a/crates/forge/tests/cli/lint.rs +++ b/crates/forge/tests/cli/lint.rs @@ -1155,7 +1155,7 @@ async fn ensure_lint_rule_docs() { let mut missing_lints = Vec::new(); for lint in REGISTERED_LINTS { let selector = lint.id().to_lowercase(); - let selector_with_space = selector.replace("-", " "); + let selector_with_space = selector.replace('-', " "); if !content.to_lowercase().contains(&selector) && !content.to_lowercase().contains(&selector_with_space) { diff --git a/crates/lint/src/sol/info/screaming_snake_case.rs b/crates/lint/src/sol/info/screaming_snake_case.rs index a0d56c5a3cf34..ff3d5982b2fb3 100644 --- a/crates/lint/src/sol/info/screaming_snake_case.rs +++ b/crates/lint/src/sol/info/screaming_snake_case.rs @@ -56,9 +56,9 @@ pub fn check_screaming_snake_case(s: &str) -> Option { // Handle leading/trailing underscores like `heck` does let expected = format!( "{prefix}{name}{suffix}", - prefix = if s.starts_with("_") { "_" } else { "" }, + prefix = if s.starts_with('_') { "_" } else { "" }, name = heck::AsShoutySnakeCase(s), - suffix = if s.ends_with("_") { "_" } else { "" } + suffix = if s.ends_with('_') { "_" } else { "" } ); if s == expected { None } else { Some(expected) } } diff --git a/crates/test-utils/src/ui_runner.rs b/crates/test-utils/src/ui_runner.rs index 8ae0af75fd458..c23d4b5ae08c9 100644 --- a/crates/test-utils/src/ui_runner.rs +++ b/crates/test-utils/src/ui_runner.rs @@ -116,7 +116,7 @@ fn config<'a>( } let stdout_filters: &[(&str, &str)] = - &[(&env!("CARGO_PKG_VERSION").replace(".", r"\."), "VERSION")]; + &[(&env!("CARGO_PKG_VERSION").replace('.', r"\."), "VERSION")]; for &(pattern, replacement) in stdout_filters { config.stdout_filter(pattern, replacement); } From dbe36758af369a46d748d52ce4c8c183473e9a76 Mon Sep 17 00:00:00 2001 From: Mablr <59505383+mablr@users.noreply.github.com> Date: Fri, 10 Apr 2026 15:24:46 +0200 Subject: [PATCH 05/12] fix(script): Tempo direct signer + gas calc logic (#14242) --- crates/cli/src/utils/cmd.rs | 7 ++++++- crates/script/src/broadcast.rs | 11 +++++++++-- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/crates/cli/src/utils/cmd.rs b/crates/cli/src/utils/cmd.rs index eb4cf477d39f9..f88346949d1b6 100644 --- a/crates/cli/src/utils/cmd.rs +++ b/crates/cli/src/utils/cmd.rs @@ -112,7 +112,12 @@ pub fn init_progress(len: u64, label: &str) -> indicatif::ProgressBar { /// True if the network calculates gas costs differently. pub fn has_different_gas_calc(chain_id: u64) -> bool { - if let Some(chain) = Chain::from(chain_id).named() { + let chain = Chain::from(chain_id); + // Is either Tempo | TempoModerato | TempoTestnet | TempoDevnet + if chain.is_tempo() || chain.id() == 31318 { + return true; + } + if let Some(chain) = chain.named() { return chain.is_arbitrum() || chain.is_elastic() || matches!( diff --git a/crates/script/src/broadcast.rs b/crates/script/src/broadcast.rs index 2fd7ab6537a39..f7b1d56a2880f 100644 --- a/crates/script/src/broadcast.rs +++ b/crates/script/src/broadcast.rs @@ -345,14 +345,18 @@ impl BundledState { .chain(self.browser_wallet.as_ref().map(|b| b.address())) .collect(); - // For addresses without an explicit signer, try Tempo access key lookup. + // For addresses without an explicit signer, try Tempo keys.toml fallback. let mut access_keys: AddressHashMap<(WalletSigner, TempoAccessKeyConfig)> = AddressHashMap::default(); + let mut direct_signers: AddressHashMap = AddressHashMap::default(); let mut missing_addresses = Vec::new(); for addr in &required_addresses { if !signers.contains(addr) { match lookup_signer(*addr) { + Ok(TempoLookup::Direct(signer)) => { + direct_signers.insert(*addr, signer); + } Ok(TempoLookup::Keychain(signer, config)) => { access_keys.insert(*addr, (signer, *config)); } @@ -372,8 +376,11 @@ impl BundledState { } let signers = self.script_wallets.into_multi_wallet().into_signers()?; - let eth_wallets = + let mut eth_wallets: AddressHashMap = signers.into_iter().map(|(addr, signer)| (addr, signer.into())).collect(); + for (addr, signer) in direct_signers { + eth_wallets.insert(addr, signer.into()); + } SendTransactionsKind::Raw { eth_wallets, browser: self.browser_wallet, access_keys } }; From b572ee29856950862f6603fcd9c0db55af8d02b8 Mon Sep 17 00:00:00 2001 From: Derek Cofausper <256792747+decofe@users.noreply.github.com> Date: Fri, 10 Apr 2026 15:28:52 +0200 Subject: [PATCH 06/12] clippy: warn on `unnested_or_patterns` (autofix) (#14239) clippy: warn on unnested_or_patterns Co-authored-by: zerosnacks <95942363+zerosnacks@users.noreply.github.com> --- Cargo.toml | 1 + crates/chisel/src/executor.rs | 20 +++++++++----------- crates/fmt/src/state/mod.rs | 4 ++-- crates/forge/src/cmd/inspect.rs | 3 +-- crates/lint/src/sol/med/unsafe_typecast.rs | 3 +-- crates/script/src/runner.rs | 8 +++++--- 6 files changed, 19 insertions(+), 20 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 0abd37f3bccdd..2ad5e5d49d321 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -76,6 +76,7 @@ suspicious_operation_groupings = "warn" transmute_undefined_repr = "warn" uninhabited_references = "warn" uninlined_format_args = "warn" +unnested_or_patterns = "warn" unused_rounding = "warn" use_self = "warn" while_float = "warn" diff --git a/crates/chisel/src/executor.rs b/crates/chisel/src/executor.rs index 96acfef54a1de..e13c0062b6aa1 100644 --- a/crates/chisel/src/executor.rs +++ b/crates/chisel/src/executor.rs @@ -549,9 +549,8 @@ impl Type { pt::Expression::Multiply(_, lhs, rhs) | pt::Expression::Divide(_, lhs, rhs) => { match (Self::ethabi(lhs, None), Self::ethabi(rhs, None)) { - (Some(DynSolType::Int(_)), Some(DynSolType::Int(_))) | - (Some(DynSolType::Int(_)), Some(DynSolType::Uint(_))) | - (Some(DynSolType::Uint(_)), Some(DynSolType::Int(_))) => { + (Some(DynSolType::Int(_) | DynSolType::Uint(_)), Some(DynSolType::Int(_))) | +(Some(DynSolType::Int(_)), Some(DynSolType::Uint(_))) => { Some(Self::Builtin(DynSolType::Int(256))) } _ => { @@ -822,7 +821,7 @@ impl Type { custom_type: &mut Vec, contract_name: Option, ) -> Result> { - if let Some("this") | Some("super") = custom_type.last().map(String::as_str) { + if let Some("this" | "super") = custom_type.last().map(String::as_str) { custom_type.pop(); } if custom_type.is_empty() { @@ -1081,12 +1080,12 @@ impl Type { match self { Self::Array(inner) | Self::FixedArray(inner, _) | Self::ArrayIndex(inner, _) => { match inner.try_as_ethabi(intermediate) { - Some(DynSolType::Array(inner)) | Some(DynSolType::FixedArray(inner, _)) => { + Some(DynSolType::Array(inner) | DynSolType::FixedArray(inner, _)) => { Some(*inner) } - Some(DynSolType::Bytes) - | Some(DynSolType::String) - | Some(DynSolType::FixedBytes(_)) => Some(DynSolType::FixedBytes(1)), + Some(DynSolType::Bytes | DynSolType::String | DynSolType::FixedBytes(_)) => { + Some(DynSolType::FixedBytes(1)) + } ty => ty, } } @@ -1113,8 +1112,7 @@ impl Type { self, Self::Array(_) | Self::FixedArray(_, _) - | Self::Builtin(DynSolType::Array(_)) - | Self::Builtin(DynSolType::FixedArray(_, _)) + | Self::Builtin(DynSolType::Array(_) | DynSolType::FixedArray(_, _)) ) } @@ -1143,7 +1141,7 @@ fn func_members(func: &pt::FunctionDefinition, custom_type: &[String]) -> Option _ => None, }); match vis { - Some(pt::Visibility::External(_)) | Some(pt::Visibility::Public(_)) => { + Some(pt::Visibility::External(_) | pt::Visibility::Public(_)) => { match custom_type.first().unwrap().as_str() { "address" => Some(DynSolType::Address), "selector" => Some(DynSolType::FixedBytes(4)), diff --git a/crates/fmt/src/state/mod.rs b/crates/fmt/src/state/mod.rs index ec8f2e69103b8..0d9caa65593bc 100644 --- a/crates/fmt/src/state/mod.rs +++ b/crates/fmt/src/state/mod.rs @@ -436,8 +436,8 @@ impl State<'_, '_> { // - ends with ',' a line break or a space are required. // - ends with ';' a line break is required. prev_needs_space = match line.chars().next_back() { - Some('[') | Some('(') | Some('{') => self.config.bracket_spacing, - Some(',') | Some(';') => true, + Some('[' | '(' | '{') => self.config.bracket_spacing, + Some(',' | ';') => true, _ => false, }; } diff --git a/crates/forge/src/cmd/inspect.rs b/crates/forge/src/cmd/inspect.rs index 139fd17b0cb96..9242221cce1b9 100644 --- a/crates/forge/src/cmd/inspect.rs +++ b/crates/forge/src/cmd/inspect.rs @@ -679,8 +679,7 @@ impl PartialEq for ContractArtifactField { type Eos = EvmOutputSelection; matches!( (self, other), - (Self::Abi | Self::Events, Cos::Abi) - | (Self::Errors, Cos::Abi) + (Self::Abi | Self::Events | Self::Errors, Cos::Abi) | (Self::Bytecode, Cos::Evm(Eos::ByteCode(_))) | (Self::DeployedBytecode, Cos::Evm(Eos::DeployedByteCode(_))) | (Self::Assembly | Self::AssemblyOptimized, Cos::Evm(Eos::Assembly)) diff --git a/crates/lint/src/sol/med/unsafe_typecast.rs b/crates/lint/src/sol/med/unsafe_typecast.rs index 7ef4d44ea03e3..92aadf36149f7 100644 --- a/crates/lint/src/sol/med/unsafe_typecast.rs +++ b/crates/lint/src/sol/med/unsafe_typecast.rs @@ -159,8 +159,7 @@ fn is_unsafe_elementary_typecast( } // Dynamic bytes to fixed bytes (potential truncation) - (ElementaryType::Bytes, ElementaryType::FixedBytes(_)) - | (ElementaryType::String, ElementaryType::FixedBytes(_)) => true, + (ElementaryType::Bytes | ElementaryType::String, ElementaryType::FixedBytes(_)) => true, // Address to smaller uint (truncation) - address is 160 bits (ElementaryType::Address(_), ElementaryType::UInt(target_size)) => target_size.bits() < 160, diff --git a/crates/script/src/runner.rs b/crates/script/src/runner.rs index f07b4b7a3168d..6900bc00d823e 100644 --- a/crates/script/src/runner.rs +++ b/crates/script/src/runner.rs @@ -395,9 +395,11 @@ impl ScriptRunner { self.executor.tx_env_mut().set_gas_limit(mid_gas_limit); let res = self.executor.call_raw(from, to, calldata.0.clone().into(), value)?; match res.exit_reason { - Some(InstructionResult::Revert) - | Some(InstructionResult::OutOfGas) - | Some(InstructionResult::OutOfFunds) => { + Some( + InstructionResult::Revert + | InstructionResult::OutOfGas + | InstructionResult::OutOfFunds, + ) => { lowest_gas_limit = mid_gas_limit; } _ => { From 9a79d44fa2d34848baf53f001b24f1ccfc6ba6bb Mon Sep 17 00:00:00 2001 From: Derek Cofausper <256792747+decofe@users.noreply.github.com> Date: Fri, 10 Apr 2026 15:29:38 +0200 Subject: [PATCH 07/12] clippy: warn on `enum_glob_use` (clippy) (#14240) clippy: warn on enum_glob_use Co-authored-by: zerosnacks <95942363+zerosnacks@users.noreply.github.com> --- Cargo.toml | 1 + crates/chisel/src/dispatcher.rs | 2 +- crates/chisel/src/solidity_helper.rs | 9 ++++++--- crates/evm/core/src/utils.rs | 2 +- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 2ad5e5d49d321..2ab678475bd7d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -50,6 +50,7 @@ collection_is_never_read = "warn" dbg_macro = "warn" empty_line_after_doc_comments = "warn" empty_line_after_outer_attr = "warn" +enum_glob_use = "warn" explicit_into_iter_loop = "warn" explicit_iter_loop = "warn" if_then_some_else_none = "warn" diff --git a/crates/chisel/src/dispatcher.rs b/crates/chisel/src/dispatcher.rs index 411c599aad22b..ec23182c0de65 100644 --- a/crates/chisel/src/dispatcher.rs +++ b/crates/chisel/src/dispatcher.rs @@ -512,7 +512,7 @@ fn preprocess(input: &str) -> (bool, Cow<'_, str>) { let mut only_trivia = true; let mut new_input = Cow::Borrowed(input); for (pos, token) in solar::parse::Cursor::new(input).with_position() { - use RawTokenKind::*; + use RawTokenKind::{BlockComment, LineComment, Literal, Whitespace}; if matches!(token.kind, Whitespace | LineComment { .. } | BlockComment { .. }) { continue; diff --git a/crates/chisel/src/solidity_helper.rs b/crates/chisel/src/solidity_helper.rs index 1002b5533f116..c3212f8e89962 100644 --- a/crates/chisel/src/solidity_helper.rs +++ b/crates/chisel/src/solidity_helper.rs @@ -147,8 +147,8 @@ impl SolidityHelper { /// Validate that a source snippet is closed (i.e., all braces and parenthesis are matched). fn validate_closed(&self, input: &str) -> ValidationResult { - use RawLiteralKind::*; - use RawTokenKind::*; + use RawLiteralKind::Str; + use RawTokenKind::{BlockComment, CloseDelim, Literal, OpenDelim}; let mut stack = vec![]; for token in Cursor::new(input) { match token.kind { @@ -282,7 +282,10 @@ impl Helper for SolidityHelper {} fn token_style(token: &Token) -> Style { use solar::parse::{ interface::kw::*, - token::{TokenKind::*, TokenLitKind::*}, + token::{ + TokenKind::{Arrow, Comment, FatArrow, Ident, Literal}, + TokenLitKind::{HexStr, Str, UnicodeStr}, + }, }; match token.kind { diff --git a/crates/evm/core/src/utils.rs b/crates/evm/core/src/utils.rs index 0f6b75022f00a..b0de5e9fae6ba 100644 --- a/crates/evm/core/src/utils.rs +++ b/crates/evm/core/src/utils.rs @@ -49,7 +49,7 @@ pub fn apply_chain_and_block_specific_env_changes< block: &N::BlockResponse, configs: NetworkConfigs, ) { - use NamedChain::*; + use NamedChain::{BinanceSmartChain, BinanceSmartChainTestnet, Mainnet}; if let Ok(chain) = NamedChain::try_from(evm_env.cfg_env.chain_id) { let block_number = block.header().number(); From 0b792f1a89aa5266f41e7288a5dad5b5bf54c2d8 Mon Sep 17 00:00:00 2001 From: Derek Cofausper <256792747+decofe@users.noreply.github.com> Date: Fri, 10 Apr 2026 15:29:56 +0200 Subject: [PATCH 08/12] clippy: warn on `from_iter_instead_of_collect` (autofix) (#14241) clippy: warn on from_iter_instead_of_collect Co-authored-by: zerosnacks <95942363+zerosnacks@users.noreply.github.com> --- Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.toml b/Cargo.toml index 2ab678475bd7d..706c133ee5774 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -53,6 +53,7 @@ empty_line_after_outer_attr = "warn" enum_glob_use = "warn" explicit_into_iter_loop = "warn" explicit_iter_loop = "warn" +from_iter_instead_of_collect = "warn" if_then_some_else_none = "warn" implicit_clone = "warn" imprecise_flops = "warn" From f2b3fa2b75a5925033265caf1c3ab5e5d8b5380e Mon Sep 17 00:00:00 2001 From: Derek Cofausper <256792747+decofe@users.noreply.github.com> Date: Fri, 10 Apr 2026 15:32:30 +0200 Subject: [PATCH 09/12] clippy: warn on `if_not_else` (autofix) (#14092) * clippy: warn on if_not_else Co-Authored-By: zerosnacks <95942363+zerosnacks@users.noreply.github.com> * refactor: use contains_key + remove instead of if-let remove Simpler branch flip that preserves the original structure. Co-Authored-By: zerosnacks <95942363+zerosnacks@users.noreply.github.com> * fix: resolve new if_not_else and redundant_else findings after merge Co-Authored-By: zerosnacks <95942363+zerosnacks@users.noreply.github.com> * fix: flip if_not_else in keychain authorize Co-Authored-By: zerosnacks <95942363+zerosnacks@users.noreply.github.com> * fix: use multi-line format for blob_hashes if-else Co-Authored-By: zerosnacks <95942363+zerosnacks@users.noreply.github.com> * fix: rustfmt prefers single-line if-else here Co-Authored-By: zerosnacks <95942363+zerosnacks@users.noreply.github.com> --------- Co-authored-by: zerosnacks <95942363+zerosnacks@users.noreply.github.com> --- Cargo.toml | 1 + benches/src/lib.rs | 6 ++-- crates/anvil/src/eth/backend/mem/mod.rs | 6 +--- crates/anvil/src/lib.rs | 6 ++-- crates/cast/src/args.rs | 6 ++-- crates/cast/src/cmd/keychain.rs | 34 +++++++++--------- crates/cheatcodes/src/json.rs | 2 +- crates/cheatcodes/src/test/assert.rs | 6 ++-- crates/cheatcodes/src/test/expect.rs | 6 ++-- crates/cheatcodes/src/test/revert_handlers.rs | 8 ++--- crates/cheatcodes/src/utils.rs | 5 ++- crates/common/fmt/src/console.rs | 24 ++++++------- crates/common/fmt/src/ui.rs | 6 ++-- crates/common/src/comments/mod.rs | 6 ++-- crates/common/src/compile.rs | 6 ++-- crates/config/src/filter.rs | 6 ++-- crates/config/src/lib.rs | 9 ++--- crates/debugger/src/tui/draw.rs | 6 ++-- crates/doc/src/solang_ext/ast_eq.rs | 6 ++-- crates/evm/evm/src/executors/corpus.rs | 6 ++-- crates/evm/fuzz/src/invariant/mod.rs | 6 ++-- crates/evm/fuzz/src/strategies/invariants.rs | 6 ++-- crates/evm/traces/src/decoder/mod.rs | 6 ++-- .../evm/traces/src/identifier/signatures.rs | 2 +- crates/fmt/src/state/common.rs | 12 +++---- crates/fmt/src/state/sol.rs | 34 +++++++++--------- crates/fmt/src/state/yul.rs | 6 ++-- crates/forge/src/cmd/bind.rs | 16 ++++----- crates/forge/src/cmd/bind_json.rs | 8 ++--- crates/forge/src/cmd/create.rs | 16 ++++----- crates/forge/src/cmd/inspect.rs | 6 ++-- crates/forge/src/runner.rs | 6 ++-- crates/script/src/build.rs | 36 +++++++++---------- crates/script/src/execute.rs | 12 +++---- crates/script/src/receipts.rs | 2 +- crates/script/src/runner.rs | 8 ++--- crates/script/src/simulate.rs | 20 +++++------ crates/sol-macro-gen/src/sol_macro_gen.rs | 12 +++---- crates/verify/src/etherscan/flatten.rs | 6 ++-- crates/verify/src/etherscan/mod.rs | 6 ++-- crates/verify/src/utils.rs | 14 ++++---- crates/wallets/src/utils.rs | 6 ++-- crates/wallets/src/wallet_multi/mod.rs | 6 ++-- 43 files changed, 205 insertions(+), 208 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 706c133ee5774..0e6adda2ecb52 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -56,6 +56,7 @@ explicit_iter_loop = "warn" from_iter_instead_of_collect = "warn" if_then_some_else_none = "warn" implicit_clone = "warn" +if_not_else = "warn" imprecise_flops = "warn" iter_on_empty_collections = "warn" iter_with_drain = "warn" diff --git a/benches/src/lib.rs b/benches/src/lib.rs index b4b3de2c3ddf3..ca429168c2095 100644 --- a/benches/src/lib.rs +++ b/benches/src/lib.rs @@ -175,13 +175,13 @@ impl BenchmarkProject { .status() .wrap_err("Failed to run npm install")?; - if !status.success() { + if status.success() { + sh_println!(" ✅ npm install completed successfully"); + } else { sh_println!( " ⚠️ Warning: npm install failed with exit code: {:?}", status.code() ); - } else { - sh_println!(" ✅ npm install completed successfully"); } } Ok(()) diff --git a/crates/anvil/src/eth/backend/mem/mod.rs b/crates/anvil/src/eth/backend/mem/mod.rs index 133cfd61f2bf7..4c972d2548752 100644 --- a/crates/anvil/src/eth/backend/mem/mod.rs +++ b/crates/anvil/src/eth/backend/mem/mod.rs @@ -1384,11 +1384,7 @@ impl Backend { gas_priority_fee: max_priority_fee_per_gas, max_fee_per_blob_gas: max_fee_per_blob_gas .or_else(|| { - if !blob_hashes.is_empty() { - evm_env.block_env.blob_gasprice() - } else { - Some(0) - } + if blob_hashes.is_empty() { Some(0) } else { evm_env.block_env.blob_gasprice() } }) .unwrap_or_default(), kind: match to { diff --git a/crates/anvil/src/lib.rs b/crates/anvil/src/lib.rs index c17a79bd71d20..1b95e956510cc 100644 --- a/crates/anvil/src/lib.rs +++ b/crates/anvil/src/lib.rs @@ -470,10 +470,10 @@ pub fn init_tracing() -> LoggingManager { // Mutate the given filter to include `node` logs if it is not already present. // This prevents the unexpected behaviour of not seeing any node logs if a RUST_LOG // is already present that doesn't set it. - let rust_log_val = if !rust_log_val.contains("node") { - format!("{rust_log_val},node=info") - } else { + let rust_log_val = if rust_log_val.contains("node") { rust_log_val + } else { + format!("{rust_log_val},node=info") }; let env_filter: EnvFilter = diff --git a/crates/cast/src/args.rs b/crates/cast/src/args.rs index c4ffcdf810d8d..7dfcbed400c3c 100644 --- a/crates/cast/src/args.rs +++ b/crates/cast/src/args.rs @@ -195,10 +195,10 @@ pub async fn run_command(args: CastArgs) -> Result<()> { print_tokens(&tokens); } CastSubcommand::AbiEncode { sig, packed, args } => { - if !packed { - sh_println!("{}", SimpleCast::abi_encode(&sig, &args)?)? - } else { + if packed { sh_println!("{}", SimpleCast::abi_encode_packed(&sig, &args)?)? + } else { + sh_println!("{}", SimpleCast::abi_encode(&sig, &args)?)? } } CastSubcommand::AbiEncodeEvent { sig, args } => { diff --git a/crates/cast/src/cmd/keychain.rs b/crates/cast/src/cmd/keychain.rs index c6a9646a6b2ab..f4541f3a0ed03 100644 --- a/crates/cast/src/cmd/keychain.rs +++ b/crates/cast/src/cmd/keychain.rs @@ -546,7 +546,9 @@ async fn run_check(wallet_address: Address, key_address: Address, rpc: RpcOpts) // Expiry: show human-readable date and whether it's expired. let expiry_str = format_expiry(info.expiry); - if info.expiry != u64::MAX { + if info.expiry == u64::MAX { + sh_println!("Expiry: {}", expiry_str)?; + } else { let now = std::time::SystemTime::now() .duration_since(std::time::UNIX_EPOCH) .unwrap_or_default() @@ -556,8 +558,6 @@ async fn run_check(wallet_address: Address, key_address: Address, rpc: RpcOpts) } else { sh_println!("Expiry: {}", expiry_str)?; } - } else { - sh_println!("Expiry: {}", expiry_str)?; } sh_println!("Spending Limits: {}", if info.enforceLimits { "enforced" } else { "none" })?; @@ -579,7 +579,17 @@ async fn run_authorize( ) -> Result<()> { let enforce = enforce_limits || !limits.is_empty(); - let calldata = if !allowed_calls.is_empty() { + let calldata = if allowed_calls.is_empty() { + // Use the legacy authorizeKey when no scopes are needed. + IAccountKeychain::authorizeKeyCall { + keyId: key_address, + signatureType: key_type, + expiry, + enforceLimits: enforce, + limits, + } + .abi_encode() + } else { // Use the T3+ authorizeKey overload with KeyRestrictions when scopes are provided. let sig_type_u8 = match key_type { SignatureType::Secp256k1 => 0u8, @@ -603,16 +613,6 @@ async fn run_authorize( config: restrictions, } .abi_encode() - } else { - // Use the legacy authorizeKey when no scopes are needed. - IAccountKeychain::authorizeKeyCall { - keyId: key_address, - signatureType: key_type, - expiry, - enforceLimits: enforce, - limits, - } - .abi_encode() }; send_keychain_tx(calldata, tx_opts, &send_tx).await @@ -783,10 +783,10 @@ fn print_key_entry(entry: &tempo::KeyEntry) -> Result<()> { if let Some(key_address) = entry.key_address { sh_println!("Key Address: {key_address}")?; - if key_address != entry.wallet_address { - sh_println!("Mode: keychain (access key)")?; - } else { + if key_address == entry.wallet_address { sh_println!("Mode: direct (EOA)")?; + } else { + sh_println!("Mode: keychain (access key)")?; } } else { sh_println!("Key Address: (not set)")?; diff --git a/crates/cheatcodes/src/json.rs b/crates/cheatcodes/src/json.rs index 24cfa5474a5ba..9af337e223eea 100644 --- a/crates/cheatcodes/src/json.rs +++ b/crates/cheatcodes/src/json.rs @@ -503,7 +503,7 @@ fn encode(values: Vec) -> Vec { /// Canonicalize a json path key to always start from the root of the document. /// Read more about json path syntax: pub(super) fn canonicalize_json_path(path: &str) -> Cow<'_, str> { - if !path.starts_with('$') { format!("${path}").into() } else { path.into() } + if path.starts_with('$') { path.into() } else { format!("${path}").into() } } /// Converts a JSON [`Value`] to a [`DynSolValue`] by trying to guess encoded type. For safer diff --git a/crates/cheatcodes/src/test/assert.rs b/crates/cheatcodes/src/test/assert.rs index db0399d78b0ec..7b5744c1abaa0 100644 --- a/crates/cheatcodes/src/test/assert.rs +++ b/crates/cheatcodes/src/test/assert.rs @@ -467,10 +467,10 @@ fn assert_eq<'a, T: PartialEq>(left: &'a T, right: &'a T) -> ComparisonResult<'a } fn assert_not_eq<'a, T: PartialEq>(left: &'a T, right: &'a T) -> ComparisonResult<'a, T> { - if left != right { - Ok(()) - } else { + if left == right { Err(ComparisonAssertionError { kind: AssertionKind::Ne, left, right }) + } else { + Ok(()) } } diff --git a/crates/cheatcodes/src/test/expect.rs b/crates/cheatcodes/src/test/expect.rs index 851500e938c06..325b836f3adc0 100644 --- a/crates/cheatcodes/src/test/expect.rs +++ b/crates/cheatcodes/src/test/expect.rs @@ -1244,10 +1244,10 @@ pub(crate) fn get_emit_mismatch_message( { let (expected_name, expected_value) = &expected_params[param_idx]; let (_actual_name, actual_value) = &actual_params[param_idx]; - let param_name = if !expected_name.is_empty() { - expected_name - } else { + let param_name = if expected_name.is_empty() { &format!("param{param_idx}") + } else { + expected_name }; return format!( "{param_name}: expected={expected_value}, got={actual_value}", diff --git a/crates/cheatcodes/src/test/revert_handlers.rs b/crates/cheatcodes/src/test/revert_handlers.rs index 3b0610ebf07a4..6ba333f63f402 100644 --- a/crates/cheatcodes/src/test/revert_handlers.rs +++ b/crates/cheatcodes/src/test/revert_handlers.rs @@ -198,7 +198,10 @@ pub(crate) fn handle_expect_revert( // If we expect no reverts with a specific reason/reverter, but got a revert, // we need to check if it matches our criteria - if !matches!(status, return_ok!()) { + if matches!(status, return_ok!()) { + // No revert occurred, which is what we expected + Ok(success_return()) + } else { // We got a revert, but we expected 0 reverts // We need to check if this revert matches our expected criteria @@ -266,9 +269,6 @@ pub(crate) fn handle_expect_revert( } } } - } else { - // No revert occurred, which is what we expected - Ok(success_return()) } } else { ensure!(!matches!(status, return_ok!()), "next call did not revert as expected"); diff --git a/crates/cheatcodes/src/utils.rs b/crates/cheatcodes/src/utils.rs index 90e93f63999ad..fcaf6e9c6c3bb 100644 --- a/crates/cheatcodes/src/utils.rs +++ b/crates/cheatcodes/src/utils.rs @@ -225,11 +225,10 @@ impl Cheatcode for resumeTracingCall { impl Cheatcode for interceptInitcodeCall { fn apply(&self, state: &mut Cheatcodes) -> Result { let Self {} = self; - if !state.intercept_next_create_call { - state.intercept_next_create_call = true; - } else { + if state.intercept_next_create_call { bail!("vm.interceptInitcode() has already been called") } + state.intercept_next_create_call = true; Ok(Default::default()) } } diff --git a/crates/common/fmt/src/console.rs b/crates/common/fmt/src/console.rs index 43c2a4621528b..d751ddba245ba 100644 --- a/crates/common/fmt/src/console.rs +++ b/crates/common/fmt/src/console.rs @@ -222,10 +222,10 @@ impl ConsoleFmt for U256 { let integer = amount / exp10; let decimal = (amount % exp10).to_string(); let decimal = format!("{decimal:0>log$}").trim_end_matches('0').to_string(); - if !decimal.is_empty() { - format!("{integer}.{decimal}e{log}") - } else { + if decimal.is_empty() { format!("{integer}e{log}") + } else { + format!("{integer}.{decimal}e{log}") } } FormatSpec::Exponential(Some(precision)) => { @@ -234,10 +234,10 @@ impl ConsoleFmt for U256 { let integer = amount / exp10; let decimal = (amount % exp10).to_string(); let decimal = format!("{decimal:0>precision$}").trim_end_matches('0').to_string(); - if !decimal.is_empty() { - format!("{integer}.{decimal}") - } else { + if decimal.is_empty() { format!("{integer}") + } else { + format!("{integer}.{decimal}") } } } @@ -266,10 +266,10 @@ impl ConsoleFmt for I256 { let integer = (amount / exp10).twos_complement(); let decimal = (amount % exp10).twos_complement().to_string(); let decimal = format!("{decimal:0>log$}").trim_end_matches('0').to_string(); - if !decimal.is_empty() { - format!("{sign}{integer}.{decimal}e{log}") - } else { + if decimal.is_empty() { format!("{sign}{integer}e{log}") + } else { + format!("{sign}{integer}.{decimal}e{log}") } } FormatSpec::Exponential(Some(precision)) => { @@ -279,10 +279,10 @@ impl ConsoleFmt for I256 { let integer = (amount / exp10).twos_complement(); let decimal = (amount % exp10).twos_complement().to_string(); let decimal = format!("{decimal:0>precision$}").trim_end_matches('0').to_string(); - if !decimal.is_empty() { - format!("{sign}{integer}.{decimal}") - } else { + if decimal.is_empty() { format!("{sign}{integer}") + } else { + format!("{sign}{integer}.{decimal}") } } } diff --git a/crates/common/fmt/src/ui.rs b/crates/common/fmt/src/ui.rs index 12948f896421c..3ab26593766e3 100644 --- a/crates/common/fmt/src/ui.rs +++ b/crates/common/fmt/src/ui.rs @@ -59,7 +59,9 @@ impl UIfmt for Option { impl UIfmt for [T] { fn pretty(&self) -> String { - if !self.is_empty() { + if self.is_empty() { + "[]".to_string() + } else { let mut s = String::with_capacity(self.len() * 64); s.push_str("[\n"); for item in self { @@ -71,8 +73,6 @@ impl UIfmt for [T] { } s.push(']'); s - } else { - "[]".to_string() } } } diff --git a/crates/common/src/comments/mod.rs b/crates/common/src/comments/mod.rs index 8f934f1311d44..e7477e18fd1b8 100644 --- a/crates/common/src/comments/mod.rs +++ b/crates/common/src/comments/mod.rs @@ -317,9 +317,7 @@ impl<'ast> CommentGatherer<'ast> { res.push(line); continue; } - if !pos.is_last { - res.push(format_doc_block_comment(&line, self.tab_width)); - } else { + if pos.is_last { // Ensure last line of a doc comment only has the `*/` decorator if let Some((first, _)) = line.split_once("*/") && !first.trim().is_empty() @@ -327,6 +325,8 @@ impl<'ast> CommentGatherer<'ast> { res.push(format_doc_block_comment(first.trim_end(), self.tab_width)); } res.push(" */".to_string()); + } else { + res.push(format_doc_block_comment(&line, self.tab_width)); } } res diff --git a/crates/common/src/compile.rs b/crates/common/src/compile.rs index 5078fc10f7f41..c080f82f8bcf6 100644 --- a/crates/common/src/compile.rs +++ b/crates/common/src/compile.rs @@ -163,10 +163,10 @@ impl ProjectCompiler { let files = std::mem::take(&mut self.files); let preprocess = self.dynamic_test_linking; self.compile_with(|| { - let sources = if !files.is_empty() { - Source::read_all(files)? - } else { + let sources = if files.is_empty() { project.paths.read_input_files()? + } else { + Source::read_all(files)? }; let mut compiler = diff --git a/crates/config/src/filter.rs b/crates/config/src/filter.rs index 97b2ef48d7509..0707e17a4fd68 100644 --- a/crates/config/src/filter.rs +++ b/crates/config/src/filter.rs @@ -138,11 +138,11 @@ impl FileFilter for SkipBuildFilters { /// Only returns a match if _no_ exclusion filter matches fn is_match(&self, file: &Path) -> bool { self.matchers.iter().all(|matcher| { - if !matcher.is_match_exclude(file) { - false - } else { + if matcher.is_match_exclude(file) { file.strip_prefix(&self.project_root) .map_or(true, |stripped| matcher.is_match_exclude(stripped)) + } else { + false } }) } diff --git a/crates/config/src/lib.rs b/crates/config/src/lib.rs index 92156f39a0aa8..8bb8de586332a 100644 --- a/crates/config/src/lib.rs +++ b/crates/config/src/lib.rs @@ -1150,7 +1150,8 @@ impl Config { paths: &ProjectPathsConfig, ) -> Result>, SolcError> { - let mut map = BTreeMap::new(); + let mut map: BTreeMap> = + BTreeMap::new(); if self.compilation_restrictions.is_empty() { return Ok(BTreeMap::new()); } @@ -1170,9 +1171,7 @@ impl Config { }) { let res: RestrictionsWithVersion<_> = res.clone().try_into().map_err(SolcError::msg)?; - if !map.contains_key(source) { - map.insert(source.clone(), res); - } else { + if map.contains_key(source) { let value = map.remove(source.as_path()).unwrap(); if let Some(merged) = value.clone().merge(res) { map.insert(source.clone(), merged); @@ -1187,6 +1186,8 @@ impl Config { ); map.insert(source.clone(), value); } + } else { + map.insert(source.clone(), res); } } } diff --git a/crates/debugger/src/tui/draw.rs b/crates/debugger/src/tui/draw.rs index daf2d01d1da84..5b6dceac4c890 100644 --- a/crates/debugger/src/tui/draw.rs +++ b/crates/debugger/src/tui/draw.rs @@ -290,11 +290,11 @@ impl TUIContext<'_> { lines.push(u_num, line, u_text); } - let first = if !last_has_nl { + let first = if last_has_nl { + 0 + } else { lines.push_raw(h_num, &[Span::raw(last), Span::styled(actual[0], h_text)]); 1 - } else { - 0 }; // Skip the first line if it has already been handled above. diff --git a/crates/doc/src/solang_ext/ast_eq.rs b/crates/doc/src/solang_ext/ast_eq.rs index e19d3469ce829..1252ac4eb32bf 100644 --- a/crates/doc/src/solang_ext/ast_eq.rs +++ b/crates/doc/src/solang_ext/ast_eq.rs @@ -100,10 +100,10 @@ where T: AstEq, { fn ast_eq(&self, other: &Self) -> bool { - if self.len() != other.len() { - false - } else { + if self.len() == other.len() { self.iter().zip(other.iter()).all(|(left, right)| left.ast_eq(right)) + } else { + false } } } diff --git a/crates/evm/evm/src/executors/corpus.rs b/crates/evm/evm/src/executors/corpus.rs index 9e70c42e7aafb..d667267ab3b1a 100644 --- a/crates/evm/evm/src/executors/corpus.rs +++ b/crates/evm/evm/src/executors/corpus.rs @@ -707,15 +707,15 @@ impl WorkerCorpus { self.evict_oldest_corpus()?; - let tx = if !self.in_memory_corpus.is_empty() { + let tx = if self.in_memory_corpus.is_empty() { + self.new_tx(test_runner)? + } else { let corpus = &self.in_memory_corpus [test_runner.rng().random_range(0..self.in_memory_corpus.len())]; self.current_mutated = Some(corpus.uuid); let mut tx = corpus.tx_seq.first().unwrap().clone(); self.abi_mutate(&mut tx, function, test_runner, fuzz_state)?; tx - } else { - self.new_tx(test_runner)? }; Ok(tx.call_details.calldata) diff --git a/crates/evm/fuzz/src/invariant/mod.rs b/crates/evm/fuzz/src/invariant/mod.rs index 9c47a37680254..70cd97b8f4fbd 100644 --- a/crates/evm/fuzz/src/invariant/mod.rs +++ b/crates/evm/fuzz/src/invariant/mod.rs @@ -225,15 +225,15 @@ impl TargetedContract { /// Returns specified targeted functions if any, else mutable abi functions that are not /// marked as excluded. pub fn abi_fuzzed_functions(&self) -> impl Iterator { - if !self.targeted_functions.is_empty() { - Either::Left(self.targeted_functions.iter()) - } else { + if self.targeted_functions.is_empty() { Either::Right(self.abi.functions().filter(|&func| { !matches!( func.state_mutability, alloy_json_abi::StateMutability::Pure | alloy_json_abi::StateMutability::View ) && !self.excluded_functions.contains(func) })) + } else { + Either::Left(self.targeted_functions.iter()) } } diff --git a/crates/evm/fuzz/src/strategies/invariants.rs b/crates/evm/fuzz/src/strategies/invariants.rs index 0f7ba181be7ac..8ff473d4ebc93 100644 --- a/crates/evm/fuzz/src/strategies/invariants.rs +++ b/crates/evm/fuzz/src/strategies/invariants.rs @@ -119,9 +119,7 @@ fn select_random_sender( senders: Rc, dictionary_weight: u32, ) -> impl Strategy + use<> { - if !senders.targeted.is_empty() { - any::().prop_map(move |index| *index.get(&senders.targeted)).boxed() - } else { + if senders.targeted.is_empty() { assert!(dictionary_weight <= 100, "dictionary_weight must be <= 100"); proptest::prop_oneof![ 100 - dictionary_weight => fuzz_param(&alloy_dyn_abi::DynSolType::Address), @@ -142,6 +140,8 @@ fn select_random_sender( addr }) .boxed() + } else { + any::().prop_map(move |index| *index.get(&senders.targeted)).boxed() } } diff --git a/crates/evm/traces/src/decoder/mod.rs b/crates/evm/traces/src/decoder/mod.rs index 9ea9413817563..98cfc5a1131d0 100644 --- a/crates/evm/traces/src/decoder/mod.rs +++ b/crates/evm/traces/src/decoder/mod.rs @@ -482,7 +482,9 @@ impl CallTraceDecoder { && !contract_selectors.contains(&selector) && (!cdata.is_empty() || !self.receive_contracts.contains(&trace.address)) { - let return_data = if !trace.success { + let return_data = if trace.success { + None + } else { let revert_msg = self.revert_decoder.decode(&trace.output, trace.status); if trace.output.is_empty() || revert_msg.contains("EvmError: Revert") { @@ -493,8 +495,6 @@ impl CallTraceDecoder { } else { Some(revert_msg) } - } else { - None }; return if let Some(func) = functions.first() { diff --git a/crates/evm/traces/src/identifier/signatures.rs b/crates/evm/traces/src/identifier/signatures.rs index ef557a10683ea..3481620fa7c75 100644 --- a/crates/evm/traces/src/identifier/signatures.rs +++ b/crates/evm/traces/src/identifier/signatures.rs @@ -181,7 +181,7 @@ impl SignaturesIdentifier { /// - `cache_dir` is the cache directory to store the signatures. /// - `offline` disables the OpenChain client. pub fn new_with(cache_dir: Option<&Path>, offline: bool) -> Result { - let client = if !offline { Some(OpenChainClient::new()?) } else { None }; + let client = if offline { None } else { Some(OpenChainClient::new()?) }; let (cache, cache_path) = if let Some(cache_dir) = cache_dir { let path = cache_dir.join("signatures"); let cache = SignaturesCache::load(&path); diff --git a/crates/fmt/src/state/common.rs b/crates/fmt/src/state/common.rs index 481cda6d26806..c5f2d46eccdd4 100644 --- a/crates/fmt/src/state/common.rs +++ b/crates/fmt/src/state/common.rs @@ -37,12 +37,12 @@ impl<'ast> State<'_, 'ast> { let quote_pos = span.lo() + kind.prefix().len() as u32; self.print_str_lit(kind, quote_pos, symbol.as_str()); } - if !pos.is_last { + if pos.is_last { + self.neverbreak(); + } else { if !self.print_trailing_comment(span.hi(), None) { self.space_if_not_bol(); } - } else { - self.neverbreak(); } } self.end(); @@ -93,10 +93,10 @@ impl<'ast> State<'_, 'ast> { let config = self.config.number_underscore; let is_dec = !["0x", "0b", "0o"].iter().any(|prefix| source.starts_with(prefix)); - let (val, exp) = if !is_dec { - (source, "") - } else { + let (val, exp) = if is_dec { source.split_once(['e', 'E']).unwrap_or((source, "")) + } else { + (source, "") }; let (val, fract) = val.split_once('.').unwrap_or((val, "")); diff --git a/crates/fmt/src/state/sol.rs b/crates/fmt/src/state/sol.rs index 7138d3689074a..7d58540bd6bd8 100644 --- a/crates/fmt/src/state/sol.rs +++ b/crates/fmt/src/state/sol.rs @@ -364,7 +364,16 @@ impl<'ast> State<'_, 'ast> { self.print_word("{"); self.end(); - if !body.is_empty() { + if body.is_empty() { + if self.print_comments(span.hi(), CommentConfig::skip_ws()).is_some() { + // Adjust the offset of the trailing break from comment printing + // so the closing brace is not indented + self.s.offset(-self.ind); + } else if self.config.bracket_spacing { + self.nbsp(); + }; + self.end(); + } else { // update block depth self.block_depth += 1; @@ -405,15 +414,6 @@ impl<'ast> State<'_, 'ast> { // restore block depth self.block_depth -= 1; - } else { - if self.print_comments(span.hi(), CommentConfig::skip_ws()).is_some() { - // Adjust the offset of the trailing break from comment printing - // so the closing brace is not indented - self.s.offset(-self.ind); - } else if self.config.bracket_spacing { - self.nbsp(); - }; - self.end(); } self.print_word("}"); @@ -1714,11 +1714,11 @@ impl<'ast> State<'_, 'ast> { self.call_stack.push(CallContext::chained(callee_size, chain_has_indent)); } - if !chain_has_indent { + if chain_has_indent { + self.s.ibox(self.ind); + } else { self.skip_index_break = true; self.cbox(0); - } else { - self.s.ibox(self.ind); } } @@ -2190,7 +2190,9 @@ impl<'ast> State<'_, 'ast> { self.nbsp(); } - if !args.is_empty() { + if args.is_empty() { + self.end(); + } else { self.print_word("returns "); self.print_word("("); self.zerobreak(); @@ -2206,8 +2208,6 @@ impl<'ast> State<'_, 'ast> { ); self.print_word(")"); self.nbsp(); - } else { - self.end(); } if block.is_empty() { self.print_block(block, *try_span); @@ -2750,7 +2750,7 @@ impl<'ast> AttributeCommentMapper<'ast> { let before_limit = self.attributes[a].span.lo(); let inner_limit = self.attributes[a].span.hi(); let after_limit = - if !is_last { self.attributes[a + 1].span.lo() } else { self.limit_pos }; + if is_last { self.limit_pos } else { self.attributes[a + 1].span.lo() }; let mut c = 0; while c < self.comments.len() { diff --git a/crates/fmt/src/state/yul.rs b/crates/fmt/src/state/yul.rs index 0f973624bf9ec..b67fdd5a26263 100644 --- a/crates/fmt/src/state/yul.rs +++ b/crates/fmt/src/state/yul.rs @@ -253,7 +253,9 @@ impl<'ast> State<'_, 'ast> { |s, stmt| { s.print_yul_stmt(stmt); s.print_comments(stmt.span.hi(), CommentConfig::default()); - if i != n_args { + if i == n_args { + s.print_trailing_comment(stmt.span.hi(), Some(span.hi())); + } else { let next_span = block[i + 1].span; s.print_trailing_comment(stmt.span.hi(), Some(next_span.lo())); if !s.is_bol_or_only_ind() && !s.inline_config.is_disabled(stmt.span) { @@ -270,8 +272,6 @@ impl<'ast> State<'_, 'ast> { } } i += 1; - } else { - s.print_trailing_comment(stmt.span.hi(), Some(span.hi())); } }, |b| b.span, diff --git a/crates/forge/src/cmd/bind.rs b/crates/forge/src/cmd/bind.rs index 39108e01dd272..e356dde7a2ead 100644 --- a/crates/forge/src/cmd/bind.rs +++ b/crates/forge/src/cmd/bind.rs @@ -235,7 +235,14 @@ impl BindArgs { let mut solmacrogen = self.get_solmacrogen(artifacts)?; sh_println!("Generating bindings for {} contracts", solmacrogen.instances.len())?; - if !self.module { + if self.module { + trace!(single_file = self.single_file, "generating module"); + solmacrogen.write_to_module( + bindings_root, + self.single_file, + !self.skip_extra_derives, + )?; + } else { trace!(single_file = self.single_file, "generating crate"); solmacrogen.write_to_crate( &self.crate_name, @@ -248,13 +255,6 @@ impl BindArgs { self.alloy_rev.clone(), !self.skip_extra_derives, )?; - } else { - trace!(single_file = self.single_file, "generating module"); - solmacrogen.write_to_module( - bindings_root, - self.single_file, - !self.skip_extra_derives, - )?; } Ok(()) diff --git a/crates/forge/src/cmd/bind_json.rs b/crates/forge/src/cmd/bind_json.rs index f29ba6f131409..303e8511dec14 100644 --- a/crates/forge/src/cmd/bind_json.rs +++ b/crates/forge/src/cmd/bind_json.rs @@ -157,13 +157,13 @@ impl BindJsonArgs { let mut target_files = HashSet::new(); for (path, source) in &input.input.sources { - if !include.is_empty() { - if !include.iter().any(|matcher| matcher.is_match(path)) { + if include.is_empty() { + // Exclude library files by default + if project.paths.has_library_ancestor(path) { continue; } } else { - // Exclude library files by default - if project.paths.has_library_ancestor(path) { + if !include.iter().any(|matcher| matcher.is_match(path)) { continue; } } diff --git a/crates/forge/src/cmd/create.rs b/crates/forge/src/cmd/create.rs index 64b4769beae46..943a10b5eb8cb 100644 --- a/crates/forge/src/cmd/create.rs +++ b/crates/forge/src/cmd/create.rs @@ -426,7 +426,14 @@ impl CreateArgs { } if dry_run { - if !shell::is_json() { + if shell::is_json() { + let output = json!({ + "contract": self.contract.name, + "transaction": &deployer.tx, + "abi":&abi + }); + sh_println!("{}", serde_json::to_string_pretty(&output)?)?; + } else { sh_warn!("Dry run enabled, not broadcasting transaction\n")?; sh_println!("Contract: {}", self.contract.name)?; @@ -439,13 +446,6 @@ impl CreateArgs { sh_warn!( "To broadcast this transaction, add --broadcast to the previous command. See forge create --help for more." )?; - } else { - let output = json!({ - "contract": self.contract.name, - "transaction": &deployer.tx, - "abi":&abi - }); - sh_println!("{}", serde_json::to_string_pretty(&output)?)?; } return Ok(()); diff --git a/crates/forge/src/cmd/inspect.rs b/crates/forge/src/cmd/inspect.rs index 9242221cce1b9..f5c8e559394b3 100644 --- a/crates/forge/src/cmd/inspect.rs +++ b/crates/forge/src/cmd/inspect.rs @@ -251,15 +251,15 @@ fn print_abi(abi: &JsonAbi, should_wrap: bool) -> Result<()> { for func in abi.functions.values().flatten() { let selector = func.selector().to_string(); let state_mut = func.state_mutability.as_json_str(); - let func_sig = if !func.outputs.is_empty() { + let func_sig = if func.outputs.is_empty() { + format!("{}({}) {state_mut}", func.name, get_ty_sig(&func.inputs)) + } else { format!( "{}({}) {state_mut} returns ({})", func.name, get_ty_sig(&func.inputs), get_ty_sig(&func.outputs) ) - } else { - format!("{}({}) {state_mut}", func.name, get_ty_sig(&func.inputs)) }; table.add_row(["function", &func_sig, &selector]); } diff --git a/crates/forge/src/runner.rs b/crates/forge/src/runner.rs index 94b003944d441..2f426581c2916 100644 --- a/crates/forge/src/runner.rs +++ b/crates/forge/src/runner.rs @@ -359,10 +359,10 @@ impl<'a, FEN: FoundryEvmNetwork> ContractRunner<'a, FEN> { if setup.reason.is_some() { // The setup failed, so we return a single test result for `setUp` - let fail_msg = if !setup.deployment_failure { - "setUp()".to_string() - } else { + let fail_msg = if setup.deployment_failure { "constructor()".to_string() + } else { + "setUp()".to_string() }; return SuiteResult::new( start.elapsed(), diff --git a/crates/script/src/build.rs b/crates/script/src/build.rs index bf8cfcddf6f64..aebdfd91d6099 100644 --- a/crates/script/src/build.rs +++ b/crates/script/src/build.rs @@ -292,7 +292,15 @@ impl CompiledState { }; let (args, build_data, script_wallets, browser_wallet, script_config) = - if !self.args.unlocked { + if self.args.unlocked { + ( + self.args, + self.build_data, + self.script_wallets, + self.browser_wallet, + self.script_config, + ) + } else { let mut froms = sequence.sequences().iter().flat_map(|s| { s.transactions .iter() @@ -305,7 +313,15 @@ impl CompiledState { .signers() .map_err(|e| eyre::eyre!("Failed to get available signers: {}", e))?; - if !froms.all(|from| available_signers.contains(&from)) { + if froms.all(|from| available_signers.contains(&from)) { + ( + self.args, + self.build_data, + self.script_wallets, + self.browser_wallet, + self.script_config, + ) + } else { // IF we are missing required signers, execute script as we might need to // collect private keys from the execution. let executed = self.link().await?.prepare_execution().await?.execute().await?; @@ -316,23 +332,7 @@ impl CompiledState { executed.browser_wallet, executed.script_config, ) - } else { - ( - self.args, - self.build_data, - self.script_wallets, - self.browser_wallet, - self.script_config, - ) } - } else { - ( - self.args, - self.build_data, - self.script_wallets, - self.browser_wallet, - self.script_config, - ) }; // Collect libraries from sequence and link contracts with them. diff --git a/crates/script/src/execute.rs b/crates/script/src/execute.rs index 1da825accded9..ea99ad27576d2 100644 --- a/crates/script/src/execute.rs +++ b/crates/script/src/execute.rs @@ -379,10 +379,10 @@ impl ExecutedState { ty: "unknown".to_string(), }); - let label = if !output.name.is_empty() { - output.name.clone() - } else { + let label = if output.name.is_empty() { index.to_string() + } else { + output.name.clone() }; returns.insert( @@ -477,10 +477,10 @@ impl PreSimulationState { ty: "unknown".to_string(), }); - let label = if !output.name.is_empty() { - output.name.clone() - } else { + let label = if output.name.is_empty() { index.to_string() + } else { + output.name.clone() }; sh_println!( "{label}: {internal_type} {value}", diff --git a/crates/script/src/receipts.rs b/crates/script/src/receipts.rs index dc6f8755d042b..c066a026e0a0f 100644 --- a/crates/script/src/receipts.rs +++ b/crates/script/src/receipts.rs @@ -27,7 +27,7 @@ pub enum TxStatus { impl From for TxStatus { fn from(receipt: R) -> Self { - if !receipt.status() { Self::Revert(receipt) } else { Self::Success(receipt) } + if receipt.status() { Self::Success(receipt) } else { Self::Revert(receipt) } } } diff --git a/crates/script/src/runner.rs b/crates/script/src/runner.rs index 6900bc00d823e..46764de687ed3 100644 --- a/crates/script/src/runner.rs +++ b/crates/script/src/runner.rs @@ -177,10 +177,7 @@ impl ScriptRunner { traces.extend(constructor_traces.map(|traces| (TraceKind::Deployment, traces))); // Optionally call the `setUp` function - let (success, gas_used, labeled_addresses, transactions) = if !setup { - self.executor.backend_mut().set_test_contract(address); - (true, 0, Default::default(), Some(library_transactions)) - } else { + let (success, gas_used, labeled_addresses, transactions) = if setup { match self.executor.setup(Some(self.evm_opts.sender), address, None) { Ok(RawCallResult { reverted, @@ -221,6 +218,9 @@ impl ScriptRunner { } Err(e) => return Err(e.into()), } + } else { + self.executor.backend_mut().set_test_contract(address); + (true, 0, Default::default(), Some(library_transactions)) }; Ok(( diff --git a/crates/script/src/simulate.rs b/crates/script/src/simulate.rs index 2d942670af066..5c5155aa1678b 100644 --- a/crates/script/src/simulate.rs +++ b/crates/script/src/simulate.rs @@ -240,7 +240,7 @@ impl PreSimulationState { if !shell::is_json() { let n = rpcs.len(); - let s = if n != 1 { "s" } else { "" }; + let s = if n == 1 { "" } else { "s" }; sh_println!("\n## Setting up {n} EVM{s}.")?; } @@ -384,15 +384,7 @@ impl FilledTransactionsState { .unwrap_or_else(|_| "[Could not calculate]".to_string()); let estimated_amount = estimated_amount_raw.trim_end_matches('0'); - if !shell::is_json() { - sh_println!("\n==========================")?; - sh_println!("\nChain {}", provider_info.chain)?; - - sh_println!("\nEstimated gas price: {} gwei", estimated_gas_price)?; - sh_println!("\nEstimated total gas used for script: {total_gas}")?; - sh_println!("\nEstimated amount required: {estimated_amount} {token_symbol}")?; - sh_println!("\n==========================")?; - } else { + if shell::is_json() { sh_println!( "{}", serde_json::json!({ @@ -403,6 +395,14 @@ impl FilledTransactionsState { "token_symbol": token_symbol, }) )?; + } else { + sh_println!("\n==========================")?; + sh_println!("\nChain {}", provider_info.chain)?; + + sh_println!("\nEstimated gas price: {} gwei", estimated_gas_price)?; + sh_println!("\nEstimated total gas used for script: {total_gas}")?; + sh_println!("\nEstimated amount required: {estimated_amount} {token_symbol}")?; + sh_println!("\n==========================")?; } } } diff --git a/crates/sol-macro-gen/src/sol_macro_gen.rs b/crates/sol-macro-gen/src/sol_macro_gen.rs index 6d98a26d79cb3..ca96e6218f5e7 100644 --- a/crates/sol-macro-gen/src/sol_macro_gen.rs +++ b/crates/sol-macro-gen/src/sol_macro_gen.rs @@ -238,7 +238,12 @@ edition = "2021" for instance in &self.instances { let name = instance.name.to_snake_case(); - if !single_file { + if single_file { + // Single File + let mut contents = String::new(); + write!(contents, "{}\n\n", instance.expansion.as_ref().unwrap())?; + write!(mod_contents, "{contents}")?; + } else { // Module write_mod_name(&mut mod_contents, &name)?; let mut contents = String::new(); @@ -249,11 +254,6 @@ edition = "2021" let contents = prettyplease::unparse(&file); fs::write(bindings_path.join(format!("{name}.rs")), contents) .wrap_err("Failed to write file")?; - } else { - // Single File - let mut contents = String::new(); - write!(contents, "{}\n\n", instance.expansion.as_ref().unwrap())?; - write!(mod_contents, "{contents}")?; } } diff --git a/crates/verify/src/etherscan/flatten.rs b/crates/verify/src/etherscan/flatten.rs index e603540a4c336..731779714776f 100644 --- a/crates/verify/src/etherscan/flatten.rs +++ b/crates/verify/src/etherscan/flatten.rs @@ -111,9 +111,9 @@ Diagnostics: {diags}", /// sanitized variant of the specific version so that it can be installed. This is merely /// intended to ensure the flattened code can be compiled without errors. fn strip_build_meta(version: Version) -> Version { - if version.build != BuildMetadata::EMPTY { - Version::new(version.major, version.minor, version.patch) - } else { + if version.build == BuildMetadata::EMPTY { version + } else { + Version::new(version.major, version.minor, version.patch) } } diff --git a/crates/verify/src/etherscan/mod.rs b/crates/verify/src/etherscan/mod.rs index bc074a3fe4c2f..7f0afd972c5bf 100644 --- a/crates/verify/src/etherscan/mod.rs +++ b/crates/verify/src/etherscan/mod.rs @@ -281,11 +281,11 @@ impl EtherscanVerificationProvider { builder = if let Some(api_url) = api_url { // we don't want any trailing slashes because this can cause cloudflare issues: let api_url = api_url.trim_end_matches('/'); - let base_url = if !is_etherscan { + let base_url = if is_etherscan { + base_url.unwrap_or(api_url) + } else { // If verifier is not Etherscan then set base url as api url without /api suffix. api_url.strip_suffix("/api").unwrap_or(api_url) - } else { - base_url.unwrap_or(api_url) }; builder.with_api_url(api_url)?.with_url(base_url)? } else { diff --git a/crates/verify/src/utils.rs b/crates/verify/src/utils.rs index a02dadf563922..585359dac451f 100644 --- a/crates/verify/src/utils.rs +++ b/crates/verify/src/utils.rs @@ -107,15 +107,15 @@ pub fn print_result( config: &Config, ) { if let Some(res) = res { - if !shell::is_json() { + if shell::is_json() { + let json_res = JsonResult { bytecode_type, match_type: Some(res), message: None }; + json_results.push(json_res); + } else { let _ = sh_println!( "{} with status {}", format!("{bytecode_type:?} code matched").green().bold(), res.green().bold() ); - } else { - let json_res = JsonResult { bytecode_type, match_type: Some(res), message: None }; - json_results.push(json_res); } } else if !shell::is_json() { let _ = sh_err!( @@ -397,10 +397,10 @@ pub fn is_host_only(url: &Url) -> bool { /// assert_ne!(version.build, BuildMetadata::EMPTY); /// ``` pub async fn ensure_solc_build_metadata(version: Version) -> Result { - if version.build != BuildMetadata::EMPTY { - Ok(version) - } else { + if version.build == BuildMetadata::EMPTY { Ok(lookup_compiler_version(&version).await?) + } else { + Ok(version) } } diff --git a/crates/wallets/src/utils.rs b/crates/wallets/src/utils.rs index f5282496ed0ca..6849125e3f084 100644 --- a/crates/wallets/src/utils.rs +++ b/crates/wallets/src/utils.rs @@ -124,9 +124,7 @@ pub fn create_keystore_signer( (Some(password), _) => Ok(Some(password.to_string())), (_, Some(password_file)) => { let password_file = Path::new(password_file); - if !password_file.is_file() { - Err(eyre::eyre!("Keystore password file `{password_file:?}` does not exist")) - } else { + if password_file.is_file() { Ok(Some( fs::read_to_string(password_file) .wrap_err_with(|| { @@ -135,6 +133,8 @@ pub fn create_keystore_signer( .trim_end() .to_string(), )) + } else { + Err(eyre::eyre!("Keystore password file `{password_file:?}` does not exist")) } } (None, None) => Ok(None), diff --git a/crates/wallets/src/wallet_multi/mod.rs b/crates/wallets/src/wallet_multi/mod.rs index 3ad8e9edbc70d..a6d85581e19f0 100644 --- a/crates/wallets/src/wallet_multi/mod.rs +++ b/crates/wallets/src/wallet_multi/mod.rs @@ -292,14 +292,14 @@ impl MultiWalletOpts { pks.push(pk); } } - if !pks.is_empty() { + if pks.is_empty() { + Ok(None) + } else { let wallets = pks .into_iter() .map(|pk| utils::create_private_key_signer(pk)) .collect::>>()?; Ok(Some(wallets)) - } else { - Ok(None) } } From de5b1600d91dfee87c3f7661fec816f80b207a85 Mon Sep 17 00:00:00 2001 From: Mablr <59505383+mablr@users.noreply.github.com> Date: Fri, 10 Apr 2026 16:45:06 +0200 Subject: [PATCH 10/12] fix(cli): restore short flag for `--rpc-url` (#14246) * fix(cli): restore short flag for `--rpc-url` * fix: requirements * fix: short flag collision * fix: restore long * fix: help message --- crates/cast/tests/cli/main.rs | 2 +- crates/cli/src/opts/evm.rs | 6 +++--- crates/cli/src/opts/rpc_common.rs | 6 +++--- crates/forge/src/cmd/coverage.rs | 1 - crates/forge/tests/cli/script.rs | 2 +- 5 files changed, 8 insertions(+), 9 deletions(-) diff --git a/crates/cast/tests/cli/main.rs b/crates/cast/tests/cli/main.rs index a1f949e186b8f..5b44e0a89e4a9 100644 --- a/crates/cast/tests/cli/main.rs +++ b/crates/cast/tests/cli/main.rs @@ -3977,7 +3977,7 @@ Error: Failed to estimate gas: server returned an error response: error code 3: // casttest!(estimate_base_da, |_prj, cmd| { - cmd.args(["da-estimate", "30558838", "--rpc-url", "https://mainnet.base.org/"]) + cmd.args(["da-estimate", "30558838", "-r", "https://mainnet.base.org/"]) .assert_success() .stdout_eq(str![[r#" Estimated data availability size for block 30558838 with 225 transactions: 52916546100 diff --git a/crates/cli/src/opts/evm.rs b/crates/cli/src/opts/evm.rs index bd43b0e014030..d83efb1e8e974 100644 --- a/crates/cli/src/opts/evm.rs +++ b/crates/cli/src/opts/evm.rs @@ -48,21 +48,21 @@ pub struct EvmArgs { /// Fetch state from a specific block number over a remote endpoint. /// /// See --rpc-url. - #[arg(long, requires = "url", value_name = "BLOCK")] + #[arg(long, requires = "rpc_url", value_name = "BLOCK")] #[serde(skip_serializing_if = "Option::is_none")] pub fork_block_number: Option, /// Number of retries. /// /// See --rpc-url. - #[arg(long, requires = "url", value_name = "RETRIES")] + #[arg(long, requires = "rpc_url", value_name = "RETRIES")] #[serde(skip_serializing_if = "Option::is_none")] pub fork_retries: Option, /// Initial retry backoff on encountering errors. /// /// See --rpc-url. - #[arg(long, requires = "url", value_name = "BACKOFF")] + #[arg(long, requires = "rpc_url", value_name = "BACKOFF")] #[serde(skip_serializing_if = "Option::is_none")] pub fork_retry_backoff: Option, diff --git a/crates/cli/src/opts/rpc_common.rs b/crates/cli/src/opts/rpc_common.rs index 48ef35c28d25b..05b98582fa88f 100644 --- a/crates/cli/src/opts/rpc_common.rs +++ b/crates/cli/src/opts/rpc_common.rs @@ -20,9 +20,9 @@ use std::borrow::Cow; #[derive(Clone, Debug, Default, Serialize, Parser)] pub struct RpcCommonOpts { /// The RPC endpoint. - #[arg(long = "rpc-url", visible_alias = "fork-url", env = "ETH_RPC_URL")] + #[arg(short, long, visible_alias = "fork-url", env = "ETH_RPC_URL")] #[serde(rename = "eth_rpc_url", skip_serializing_if = "Option::is_none")] - pub url: Option, + pub rpc_url: Option, /// Allow insecure RPC connections (accept invalid HTTPS certificates). /// @@ -80,7 +80,7 @@ impl figment::Provider for RpcCommonOpts { impl RpcCommonOpts { /// Returns the RPC endpoint URL, resolving from CLI args or config. pub fn url<'a>(&'a self, config: Option<&'a Config>) -> Result>> { - let url = match (self.url.as_deref(), config) { + let url = match (self.rpc_url.as_deref(), config) { (Some(url), _) => Some(Cow::Borrowed(url)), (None, Some(config)) => config.get_rpc_url().transpose()?, (None, None) => None, diff --git a/crates/forge/src/cmd/coverage.rs b/crates/forge/src/cmd/coverage.rs index e5ed66215b0bd..8f8cbe9ef20fd 100644 --- a/crates/forge/src/cmd/coverage.rs +++ b/crates/forge/src/cmd/coverage.rs @@ -55,7 +55,6 @@ pub struct CoverageArgs { /// If not specified, the report will be stored in the root of the project. #[arg( long, - short, value_hint = ValueHint::FilePath, value_name = "PATH" )] diff --git a/crates/forge/tests/cli/script.rs b/crates/forge/tests/cli/script.rs index d66b8468cfaf5..24539f585e46a 100644 --- a/crates/forge/tests/cli/script.rs +++ b/crates/forge/tests/cli/script.rs @@ -3201,7 +3201,7 @@ contract CounterScript is Script { error: the following required arguments were not provided: --broadcast -Usage: [..] script --broadcast --verify --rpc-url [ARGS]... +Usage: [..] script --broadcast --verify --rpc-url [ARGS]... For more information, try '--help'. From 709116ee59447f812b5d427090475608f6410163 Mon Sep 17 00:00:00 2001 From: Mablr <59505383+mablr@users.noreply.github.com> Date: Fri, 10 Apr 2026 18:27:10 +0200 Subject: [PATCH 11/12] fix(cast): `batch-send` handling by clearing `to`/`value` fields (#14250) --- crates/cast/src/cmd/batch_send.rs | 8 +++----- crates/cast/src/tx.rs | 5 +++++ crates/common/src/transactions/builder.rs | 15 +++++++++++++++ 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/crates/cast/src/cmd/batch_send.rs b/crates/cast/src/cmd/batch_send.rs index 4f88913d929da..c381e5f7a1e2a 100644 --- a/crates/cast/src/cmd/batch_send.rs +++ b/crates/cast/src/cmd/batch_send.rs @@ -9,8 +9,8 @@ use crate::{ cmd::send::cast_send, tx::{self, CastTxBuilder, CastTxSender, SendTxOpts}, }; -use alloy_network::{EthereumWallet, TransactionBuilder}; -use alloy_primitives::{Bytes, U256}; +use alloy_network::EthereumWallet; +use alloy_primitives::Bytes; use alloy_provider::{Provider, ProviderBuilder as AlloyProviderBuilder}; use alloy_signer::Signer; use clap::Parser; @@ -119,9 +119,7 @@ impl BatchSendArgs { let builder = builder.with_to(first_call_to.map(Into::into)).await?; // Use empty sig/args since we're using calls directly - let mut builder = builder.with_code_sig_and_args(None, None, vec![]).await?; - builder.tx.clear_kind(); - builder.tx.set_value(U256::ZERO); + let builder = builder.with_code_sig_and_args(None, None, vec![]).await?; let timeout = send_tx.timeout.unwrap_or(config.transaction_timeout); diff --git a/crates/cast/src/tx.rs b/crates/cast/src/tx.rs index 42c6fe843e921..a4e6edcc1310c 100644 --- a/crates/cast/src/tx.rs +++ b/crates/cast/src/tx.rs @@ -484,6 +484,11 @@ where let sender = sender.into(); self.prepare(&sender); + // For batch transactions with calls, clear `to` and `value` so the node correctly + // identifies this as an AA batch transaction. The `calls` field determines the actual + // targets. If `to` is set, `build_aa()` would add a spurious extra call. + self.tx.clear_batch_to(); + // resolve let tx_nonce = self.resolve_nonce(sender.address(), fill).await?; self.resolve_auth(&sender, tx_nonce).await?; diff --git a/crates/common/src/transactions/builder.rs b/crates/common/src/transactions/builder.rs index 935c30f20bfe9..b022db33eadaa 100644 --- a/crates/common/src/transactions/builder.rs +++ b/crates/common/src/transactions/builder.rs @@ -249,6 +249,14 @@ pub trait FoundryTransactionBuilder: TransactionBuilder { /// No-op for non-Tempo networks. fn convert_create_to_call(&mut self) {} + /// Clears the `to` and `value` fields for batch transactions that use `calls`. + /// + /// In Tempo AA batch transactions, targets are specified in the `calls` field, not in `to`. + /// If `to` is set, `build_aa()` would add a spurious extra call. Must be called after + /// `prepare()` sets `kind`/`to` but before gas estimation. + /// No-op for non-Tempo networks. + fn clear_batch_to(&mut self) {} + /// Signs the transaction using an access key (keychain mode). /// /// If `key_authorization` is provided and the key is not yet provisioned on-chain, @@ -440,6 +448,13 @@ impl FoundryTransactionBuilder for ::Tran } } + fn clear_batch_to(&mut self) { + if !self.calls.is_empty() { + self.inner.to = None; + self.inner.value = None; + } + } + fn sign_with_access_key( mut self, provider: &impl Provider, From 985e26efb484f62574178e56d3328dbdf61259e6 Mon Sep 17 00:00:00 2001 From: stevencartavia <112043913+stevencartavia@users.noreply.github.com> Date: Fri, 10 Apr 2026 14:20:27 -0600 Subject: [PATCH 12/12] chore(cast): remove redundant batch-mktx clearing (#14252) --- crates/cast/src/cmd/batch_mktx.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/crates/cast/src/cmd/batch_mktx.rs b/crates/cast/src/cmd/batch_mktx.rs index ec8725ae8c1ab..e2793f7de7571 100644 --- a/crates/cast/src/cmd/batch_mktx.rs +++ b/crates/cast/src/cmd/batch_mktx.rs @@ -10,7 +10,7 @@ use crate::{ use alloy_consensus::SignableTransaction; use alloy_eips::eip2718::Encodable2718; use alloy_network::{EthereumWallet, TransactionBuilder}; -use alloy_primitives::{Address, Bytes, U256}; +use alloy_primitives::{Address, Bytes}; use alloy_provider::Provider; use alloy_signer::Signer; use clap::Parser; @@ -115,9 +115,7 @@ impl BatchMakeTxArgs { // Set dummy "to" from first call let first_call_to = call_specs.first().map(|s| s.to); let builder = builder.with_to(first_call_to.map(Into::into)).await?; - let mut tx_builder = builder.with_code_sig_and_args(None, None, vec![]).await?; - tx_builder.tx.clear_kind(); - tx_builder.tx.set_value(U256::ZERO); + let tx_builder = builder.with_code_sig_and_args(None, None, vec![]).await?; if raw_unsigned { if eth.wallet.from.is_none() && !has_nonce {