From 301e94de5e66dded70b671e3f1ecbb1f43a3cf89 Mon Sep 17 00:00:00 2001 From: Ayush Dubey <61616662+Ayushdubey86@users.noreply.github.com> Date: Sun, 27 Apr 2025 04:00:47 +0530 Subject: [PATCH 1/4] (cast mktx --raw-unsigned): support signing with provided v, r, s --- crates/cast/src/cmd/mktx.rs | 73 ++++++++++++++++++++++++++++++++++--- 1 file changed, 67 insertions(+), 6 deletions(-) diff --git a/crates/cast/src/cmd/mktx.rs b/crates/cast/src/cmd/mktx.rs index a17f52be8071b..148b1f0c5cfc8 100644 --- a/crates/cast/src/cmd/mktx.rs +++ b/crates/cast/src/cmd/mktx.rs @@ -1,6 +1,7 @@ use crate::tx::{self, CastTxBuilder}; use alloy_network::{eip2718::Encodable2718, EthereumWallet, TransactionBuilder}; -use alloy_primitives::hex; +use alloy_primitives::{hex, Address, Bytes, U256, U64}; +use alloy_rlp::{Decodable, RlpDecodable, RlpEncodable}; use alloy_signer::Signer; use clap::Parser; use eyre::{OptionExt, Result}; @@ -50,6 +51,25 @@ pub struct MakeTxArgs { /// Relaxes the wallet requirement. #[arg(long, requires = "from")] raw_unsigned: bool, + + #[arg(long, value_name = "V")] + v: Option, + + #[arg(long, value_name = "R")] + r: Option, + + #[arg(long, value_name = "S")] + s: Option, +} + +#[derive(Debug, Clone, PartialEq, Eq, RlpDecodable, RlpEncodable)] +pub struct UnsignedTransaction { + pub nonce: U256, + pub gas_price: U256, + pub gas_limit: U256, + pub to: Address, + pub value: U256, + pub data: Bytes, } #[derive(Debug, Parser)] @@ -70,7 +90,13 @@ pub enum MakeTxSubcommands { impl MakeTxArgs { pub async fn run(self) -> Result<()> { - let Self { to, mut sig, mut args, command, tx, path, eth, raw_unsigned } = self; + let Self { mut to, mut sig, mut args, command, tx, path, eth, raw_unsigned, v, r, s } = + self; + + if !raw_unsigned && to.is_none() && !args.is_empty() { + let to_str = args.remove(0); + to = Some(NameOrAddress::from_str(&to_str)?); + } let blob_data = if let Some(path) = path { Some(std::fs::read(path)?) } else { None }; @@ -100,15 +126,50 @@ impl MakeTxArgs { .with_blob_data(blob_data)?; if raw_unsigned { - // Build unsigned raw tx let from = eth.wallet.from.ok_or_eyre("missing `--from` address")?; - let raw_tx = tx_builder.build_unsigned_raw(from).await?; + let raw_unsigned_hex = tx_builder.build_unsigned_raw(from).await?; + + if let (Some(v), Some(r_hex), Some(s_hex)) = (v, r.as_ref(), s.as_ref()) { + let raw_unsigned_bytes = hex::decode(raw_unsigned_hex.trim_start_matches("0x"))?; + let mut buf = raw_unsigned_bytes.as_slice(); + let unsigned_tx: UnsignedTransaction = UnsignedTransaction::decode(&mut buf)?; + + let r_bytes = hex::decode(r_hex.trim_start_matches("0x"))?; + let s_bytes = hex::decode(s_hex.trim_start_matches("0x"))?; + + if r_bytes.len() != 32 || s_bytes.len() != 32 { + eyre::bail!("r and s must be 32 bytes each"); + } + + let r = U256::from_be_slice(&r_bytes); + let s = U256::from_be_slice(&s_bytes); + let v = U64::from(v); + + let mut out = Vec::new(); + let fields: &[&dyn alloy_rlp::Encodable] = &[ + &unsigned_tx.nonce, + &unsigned_tx.gas_price, + &unsigned_tx.gas_limit, + &unsigned_tx.to, + &unsigned_tx.value, + &unsigned_tx.data, + &v, + &r, + &s, + ]; + + alloy_rlp::encode_list::<&dyn alloy_rlp::Encodable, dyn alloy_rlp::Encodable>( + fields, &mut out, + ); + + sh_println!("0x{}", hex::encode(out))?; + } else { + sh_println!("{}", raw_unsigned_hex)?; + } - sh_println!("{raw_tx}")?; return Ok(()); } - // Retrieve the signer, and bail if it can't be constructed. let signer = eth.wallet.signer().await?; let from = signer.address(); From 7b500f6abb9fb576f28ea8052b549254aa86a8a0 Mon Sep 17 00:00:00 2001 From: Ayush Dubey <61616662+Ayushdubey86@users.noreply.github.com> Date: Sun, 27 Apr 2025 04:01:48 +0530 Subject: [PATCH 2/4] Update revert_handlers.rs --- crates/cheatcodes/src/test/revert_handlers.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/cheatcodes/src/test/revert_handlers.rs b/crates/cheatcodes/src/test/revert_handlers.rs index e8f713dcc7144..2dfd4b014fa6f 100644 --- a/crates/cheatcodes/src/test/revert_handlers.rs +++ b/crates/cheatcodes/src/test/revert_handlers.rs @@ -100,7 +100,7 @@ fn handle_revert( Ok(()) } else { let (actual, expected) = if let Some(contracts) = known_contracts { - let decoder = RevertDecoder::new().with_abis(contracts.iter().map(|(_, c)| &c.abi)); + let decoder = RevertDecoder::new().with_abis(contracts.values().map(|c| &c.abi)); ( &decoder.decode(actual_revert.as_slice(), Some(status)), &decoder.decode(expected_reason, Some(status)), From fd3ec0ee0cc6cf91b692ee1d3f5e3378bb00b330 Mon Sep 17 00:00:00 2001 From: Ayush Dubey <61616662+Ayushdubey86@users.noreply.github.com> Date: Sun, 27 Apr 2025 04:02:35 +0530 Subject: [PATCH 3/4] Update error.rs --- crates/evm/evm/src/executors/invariant/error.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/evm/evm/src/executors/invariant/error.rs b/crates/evm/evm/src/executors/invariant/error.rs index f5eef18ed7529..146cd86de465c 100644 --- a/crates/evm/evm/src/executors/invariant/error.rs +++ b/crates/evm/evm/src/executors/invariant/error.rs @@ -78,7 +78,7 @@ impl FailedInvariantCaseData { ) -> Self { // Collect abis of fuzzed and invariant contracts to decode custom error. let revert_reason = RevertDecoder::new() - .with_abis(targeted_contracts.targets.lock().iter().map(|(_, c)| &c.abi)) + .with_abis(targeted_contracts.targets.lock().iter().values(|c| &c.abi)) .with_abi(invariant_contract.abi) .decode(call_result.result.as_ref(), Some(call_result.exit_reason)); From e77a35fb795ae903362da3da2faf07bad311517c Mon Sep 17 00:00:00 2001 From: Ayush Dubey <61616662+Ayushdubey86@users.noreply.github.com> Date: Sun, 27 Apr 2025 04:16:26 +0530 Subject: [PATCH 4/4] Update error.rs --- crates/evm/evm/src/executors/invariant/error.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/evm/evm/src/executors/invariant/error.rs b/crates/evm/evm/src/executors/invariant/error.rs index 146cd86de465c..0ff4b4c52f962 100644 --- a/crates/evm/evm/src/executors/invariant/error.rs +++ b/crates/evm/evm/src/executors/invariant/error.rs @@ -78,7 +78,7 @@ impl FailedInvariantCaseData { ) -> Self { // Collect abis of fuzzed and invariant contracts to decode custom error. let revert_reason = RevertDecoder::new() - .with_abis(targeted_contracts.targets.lock().iter().values(|c| &c.abi)) + .with_abis(targeted_contracts.targets.lock().values().map(|c| &c.abi)) .with_abi(invariant_contract.abi) .decode(call_result.result.as_ref(), Some(call_result.exit_reason));