From 74fab99fc52148b520903a41264a57e32c5e4aba Mon Sep 17 00:00:00 2001 From: dipanshuhappy Date: Fri, 31 Oct 2025 01:28:42 +0530 Subject: [PATCH 01/12] feat(cast): added custom polling interval args --- crates/cast/src/cmd/send.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/crates/cast/src/cmd/send.rs b/crates/cast/src/cmd/send.rs index 5f17f93184c99..35a9e644b1aa6 100644 --- a/crates/cast/src/cmd/send.rs +++ b/crates/cast/src/cmd/send.rs @@ -15,7 +15,7 @@ use foundry_cli::{ utils, utils::LoadConfig, }; -use std::{path::PathBuf, str::FromStr}; +use std::{path::PathBuf, str::FromStr, time::Duration}; /// CLI arguments for `cast send`. #[derive(Debug, Parser)] @@ -41,6 +41,10 @@ pub struct SendTxArgs { #[arg(long, default_value = "1")] confirmations: u64, + /// Polling interval for transaction receipts (in seconds). + #[arg(long, env = "ETH_POLL_INTERVAL")] + poll_interval: Option, + #[command(subcommand)] command: Option, @@ -100,6 +104,7 @@ impl SendTxArgs { unlocked, path, timeout, + poll_interval, } = self; let blob_data = if let Some(path) = path { Some(std::fs::read(path)?) } else { None }; @@ -135,6 +140,9 @@ impl SendTxArgs { let config = eth.load_config()?; let provider = utils::get_provider(&config)?; + poll_interval + .map(|interval| provider.client().set_poll_interval(Duration::from_secs(interval))); + let builder = CastTxBuilder::new(&provider, tx, &config) .await? .with_to(to) @@ -204,7 +212,6 @@ async fn cast_send>( ) -> Result<()> { let cast = Cast::new(provider); let pending_tx = cast.send(tx).await?; - let tx_hash = pending_tx.inner().tx_hash(); if cast_async { From 3b03b3d69aa0ab3c03dd449930a36540af406dbf Mon Sep 17 00:00:00 2001 From: dipanshuhappy Date: Fri, 31 Oct 2025 01:39:26 +0530 Subject: [PATCH 02/12] feat(cast): added a custom alias for poll interval --- crates/cast/src/cmd/send.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/cast/src/cmd/send.rs b/crates/cast/src/cmd/send.rs index 35a9e644b1aa6..2bafaa56a374f 100644 --- a/crates/cast/src/cmd/send.rs +++ b/crates/cast/src/cmd/send.rs @@ -42,7 +42,7 @@ pub struct SendTxArgs { confirmations: u64, /// Polling interval for transaction receipts (in seconds). - #[arg(long, env = "ETH_POLL_INTERVAL")] + #[arg(long, alias = "poll-interval", env = "ETH_POLL_INTERVAL")] poll_interval: Option, #[command(subcommand)] From 6992ffb73bb51583792253bc6d40e290b3cc1dc4 Mon Sep 17 00:00:00 2001 From: dipanshuhappy Date: Fri, 31 Oct 2025 02:50:02 +0530 Subject: [PATCH 03/12] feat(cast): updated with clippy suggestion --- crates/cast/src/cmd/send.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/crates/cast/src/cmd/send.rs b/crates/cast/src/cmd/send.rs index 2bafaa56a374f..bf6b4c8db3bc5 100644 --- a/crates/cast/src/cmd/send.rs +++ b/crates/cast/src/cmd/send.rs @@ -140,8 +140,7 @@ impl SendTxArgs { let config = eth.load_config()?; let provider = utils::get_provider(&config)?; - poll_interval - .map(|interval| provider.client().set_poll_interval(Duration::from_secs(interval))); + if let Some(interval) = poll_interval { provider.client().set_poll_interval(Duration::from_secs(interval)) } let builder = CastTxBuilder::new(&provider, tx, &config) .await? From 8f41f4ce014a72aeadca8bd0d408bac97b3f9c72 Mon Sep 17 00:00:00 2001 From: dipanshuhappy Date: Mon, 3 Nov 2025 00:40:54 +0530 Subject: [PATCH 04/12] feat(cast): added multi fields to cast block --- crates/cast/src/args.rs | 7 +++---- crates/cast/src/lib.rs | 30 ++++++++++++++++++------------ crates/cast/src/opts.rs | 8 ++++---- crates/cast/tests/cli/main.rs | 35 ++++++++++++++++++++++------------- 4 files changed, 47 insertions(+), 33 deletions(-) diff --git a/crates/cast/src/args.rs b/crates/cast/src/args.rs index e13eed21c29f8..4538512f93c19 100644 --- a/crates/cast/src/args.rs +++ b/crates/cast/src/args.rs @@ -338,17 +338,16 @@ pub async fn run_command(args: CastArgs) -> Result<()> { Cast::new(provider).base_fee(block.unwrap_or(BlockId::Number(Latest))).await? )? } - CastSubcommand::Block { block, full, field, raw, rpc } => { + CastSubcommand::Block { block, full, fields, raw, rpc } => { let config = rpc.load_config()?; let provider = utils::get_provider(&config)?; - // Can use either --raw or specify raw as a field - let raw = raw || field.as_ref().is_some_and(|f| f == "raw"); + let raw = raw || fields.contains(&"raw".into()); sh_println!( "{}", Cast::new(provider) - .block(block.unwrap_or(BlockId::Number(Latest)), full, field, raw) + .block(block.unwrap_or(BlockId::Number(Latest)), full, fields, raw) .await? )? } diff --git a/crates/cast/src/lib.rs b/crates/cast/src/lib.rs index 4eff21fec1fd4..fee07f312dded 100644 --- a/crates/cast/src/lib.rs +++ b/crates/cast/src/lib.rs @@ -48,6 +48,7 @@ use std::{ time::Duration, }; use tokio::signal::ctrl_c; +use tracing::field::FieldSet; use foundry_common::abi::encode_function_args_packed; pub use foundry_evm::*; @@ -356,14 +357,11 @@ impl> Cast

{ &self, block: B, full: bool, - field: Option, + fields: Vec, raw: bool, ) -> Result { let block = block.into(); - if let Some(ref field) = field - && field == "transactions" - && !full - { + if fields.contains(&"transactions".into()) && !full { eyre::bail!("use --full to view transactions") } @@ -377,9 +375,16 @@ impl> Cast

{ Ok(if raw { let header: Header = block.into_inner().header.inner.try_into_header()?; format!("0x{}", hex::encode(alloy_rlp::encode(&header))) - } else if let Some(ref field) = field { - get_pretty_block_attr(&block, field) - .unwrap_or_else(|| format!("{field} is not a valid block field")) + } else if fields.len() > 0 { + let mut result = String::new(); + for field in fields { + result.push_str( + &get_pretty_block_attr(&block, &field) + .unwrap_or_else(|| format!("{field} is not a valid block field")), + ); + result.push('\n'); + } + result } else if shell::is_json() { serde_json::to_value(&block).unwrap().to_string() } else { @@ -393,7 +398,7 @@ impl> Cast

{ block.into(), false, // Select only select field - Some(field), + vec![field], false, ) .await? @@ -422,14 +427,15 @@ impl> Cast

{ 0, false, // Select only block hash - Some(String::from("hash")), + vec![String::from("hash")], false, ) .await?; Ok(match &genesis_hash[..] { "0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3" => { - match &(Self::block(self, 1920000, false, Some("hash".to_string()), false).await?)[..] + match &(Self::block(self, 1920000, false, vec![String::from("hash")], false) + .await?)[..] { "0x94365e3a8c0b35089c1d1195081fe7489b528a84b22199c916180db8b28ade7f" => { "etclive" @@ -472,7 +478,7 @@ impl> Cast

{ "0x6d3c66c5357ec91d5c43af47e234a939b22557cbb552dc45bebbceeed90fbe34" => "bsctest", "0x0d21840abff46b96c84b2ac9e10e4f5cdaeb5693cb665db62a2f3b02d2d57b5b" => "bsc", "0x31ced5b9beb7f8782b014660da0cb18cc409f121f408186886e1ca3e8eeca96b" => { - match &(Self::block(self, 1, false, Some(String::from("hash")), false).await?)[..] { + match &(Self::block(self, 1, false, vec![String::from("hash")], false).await?)[..] { "0x738639479dc82d199365626f90caa82f7eafcfe9ed354b456fb3d294597ceb53" => { "avalanche-fuji" } diff --git a/crates/cast/src/opts.rs b/crates/cast/src/opts.rs index 95c14f3a0e0b3..45cdfe607b4f9 100644 --- a/crates/cast/src/opts.rs +++ b/crates/cast/src/opts.rs @@ -9,12 +9,12 @@ use crate::cmd::{ use alloy_ens::NameOrAddress; use alloy_primitives::{Address, B256, Selector, U256}; use alloy_rpc_types::BlockId; +use clap::ArgAction; use clap::{Parser, Subcommand, ValueHint}; use eyre::Result; use foundry_cli::opts::{EtherscanOpts, GlobalArgs, RpcOpts}; use foundry_common::version::{LONG_VERSION, SHORT_VERSION}; use std::{path::PathBuf, str::FromStr}; - /// A Swiss Army knife for interacting with Ethereum applications from the command line. #[derive(Parser)] #[command( @@ -379,11 +379,11 @@ pub enum CastSubcommand { block: Option, /// If specified, only get the given field of the block. - #[arg(long, short)] - field: Option, + #[arg(short, long,num_args = 1..,action = ArgAction::Append,value_delimiter = ',')] + fields: Vec, /// Print the raw RLP encoded block header. - #[arg(long, conflicts_with = "field")] + #[arg(long, conflicts_with = "fields")] raw: bool, #[arg(long, env = "CAST_FULL_BLOCK")] diff --git a/crates/cast/tests/cli/main.rs b/crates/cast/tests/cli/main.rs index 8c483be531a03..4949eedd89359 100644 --- a/crates/cast/tests/cli/main.rs +++ b/crates/cast/tests/cli/main.rs @@ -142,9 +142,18 @@ transactions: [ "#]]); // - cmd.cast_fuse().args(["block", "15007840", "-f", "hash", "--rpc-url", eth_rpc_url.as_str()]); + cmd.cast_fuse().args([ + "block", + "15007840", + "-f", + "hash,timestamp", + "--rpc-url", + eth_rpc_url.as_str(), + ]); cmd.assert_success().stdout_eq(str![[r#" 0x950091817a57e22b6c1f3b951a15f52d41ac89b299cc8f9c89bb6d185f80c415 +1655904485 + "#]]); }); @@ -1327,20 +1336,20 @@ casttest!(receipt_revert_reason, |_prj, cmd| { blockHash 0x2cfe65be49863676b6dbc04d58176a14f39b123f1e2f4fea0383a2d82c2c50d0 blockNumber 16239315 -contractAddress +contractAddress cumulativeGasUsed 10743428 effectiveGasPrice 10539984136 from 0x199D5ED7F45F4eE35960cF22EAde2076e95B253F gasUsed 21000 logs [] logsBloom 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -root +root status 1 (success) transactionHash 0x44f2aaa351460c074f2cb1e5a9e28cbc7d83f33e425101d2de14331c7b7ec31e transactionIndex 116 type 0 -blobGasPrice -blobGasUsed +blobGasPrice +blobGasUsed to 0x91da5bf3F8Eb72724E6f50Ec6C3D199C6355c59c "#]]); @@ -1360,20 +1369,20 @@ to 0x91da5bf3F8Eb72724E6f50Ec6C3D199C6355c59c blockHash 0x883f974b17ca7b28cb970798d1c80f4d4bb427473dc6d39b2a7fe24edc02902d blockNumber 14839405 -contractAddress +contractAddress cumulativeGasUsed 20273649 effectiveGasPrice 21491736378 from 0x3cF412d970474804623bb4e3a42dE13F9bCa5436 gasUsed 24952 logs [] logsBloom 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -root +root status 0 (failed) transactionHash 0x0e07d8b53ed3d91314c80e53cf25bcde02084939395845cbb625b029d568135c transactionIndex 173 type 2 -blobGasPrice -blobGasUsed +blobGasPrice +blobGasUsed to 0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45 revertReason [..]Transaction too old, data: "0x08c379a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000135472616e73616374696f6e20746f6f206f6c6400000000000000000000000000" @@ -1395,20 +1404,20 @@ casttest!(revert_reason_from, |_prj, cmd| { blockHash 0x32663d7730c9ea8e1de6d99854483e25fcc05bb56c91c0cc82f9f04944fbffc1 blockNumber 7823353 -contractAddress +contractAddress cumulativeGasUsed 7500797 effectiveGasPrice 14296851013 from 0x3583fF95f96b356d716881C871aF7Eb55ea34a93 gasUsed 25815 logs [] logsBloom 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -root +root status 0 (failed) transactionHash 0x10ee70cf9f5ced5c515e8d53bfab5ea9f5c72cd61b25fba455c8355ee286c4e4 transactionIndex 96 type 0 -blobGasPrice -blobGasUsed +blobGasPrice +blobGasUsed to 0x91b5d4111a4C038153b24e31F75ccdC47123595d revertReason Counter is too large, data: "0x08c379a000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000014436f756e74657220697320746f6f206c61726765000000000000000000000000" From d00864c95392d87e4275b6fa3ff583501bbc608a Mon Sep 17 00:00:00 2001 From: dipanshuhappy Date: Mon, 3 Nov 2025 16:27:30 +0530 Subject: [PATCH 05/12] feat(cast): num of args needed for fields in block set to 0 --- crates/cast/src/opts.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/cast/src/opts.rs b/crates/cast/src/opts.rs index 45cdfe607b4f9..f994ef32a2dbc 100644 --- a/crates/cast/src/opts.rs +++ b/crates/cast/src/opts.rs @@ -379,7 +379,7 @@ pub enum CastSubcommand { block: Option, /// If specified, only get the given field of the block. - #[arg(short, long,num_args = 1..,action = ArgAction::Append,value_delimiter = ',')] + #[arg(short, long,num_args = 0..,action = ArgAction::Append,value_delimiter = ',')] fields: Vec, /// Print the raw RLP encoded block header. From ccc98a92410498acc5515865b986736d61e6b453 Mon Sep 17 00:00:00 2001 From: dipanshuhappy Date: Mon, 3 Nov 2025 16:31:54 +0530 Subject: [PATCH 06/12] chore: updated with formatting --- crates/cast/src/lib.rs | 3 +-- crates/cast/src/opts.rs | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/crates/cast/src/lib.rs b/crates/cast/src/lib.rs index 5e35f0b5469a7..8d0448e6562ae 100644 --- a/crates/cast/src/lib.rs +++ b/crates/cast/src/lib.rs @@ -48,7 +48,6 @@ use std::{ time::Duration, }; use tokio::signal::ctrl_c; -use tracing::field::FieldSet; use foundry_common::abi::encode_function_args_packed; pub use foundry_evm::*; @@ -368,7 +367,7 @@ impl> Cast

{ Ok(if raw { let header: Header = block.into_inner().header.inner.try_into_header()?; format!("0x{}", hex::encode(alloy_rlp::encode(&header))) - } else if fields.len() > 0 { + } else if !fields.is_empty() { let mut result = String::new(); for field in fields { result.push_str( diff --git a/crates/cast/src/opts.rs b/crates/cast/src/opts.rs index f994ef32a2dbc..2c3deb3c0bd95 100644 --- a/crates/cast/src/opts.rs +++ b/crates/cast/src/opts.rs @@ -9,8 +9,7 @@ use crate::cmd::{ use alloy_ens::NameOrAddress; use alloy_primitives::{Address, B256, Selector, U256}; use alloy_rpc_types::BlockId; -use clap::ArgAction; -use clap::{Parser, Subcommand, ValueHint}; +use clap::{ArgAction, Parser, Subcommand, ValueHint}; use eyre::Result; use foundry_cli::opts::{EtherscanOpts, GlobalArgs, RpcOpts}; use foundry_common::version::{LONG_VERSION, SHORT_VERSION}; From b34c60f6cd2de1a59728c08728475cf864c3c906 Mon Sep 17 00:00:00 2001 From: dipanshuhappy Date: Mon, 3 Nov 2025 16:47:00 +0530 Subject: [PATCH 07/12] feat(cast): added long field to cast block --- crates/cast/src/opts.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/cast/src/opts.rs b/crates/cast/src/opts.rs index 2c3deb3c0bd95..b52d38c4c73c8 100644 --- a/crates/cast/src/opts.rs +++ b/crates/cast/src/opts.rs @@ -378,7 +378,7 @@ pub enum CastSubcommand { block: Option, /// If specified, only get the given field of the block. - #[arg(short, long,num_args = 0..,action = ArgAction::Append,value_delimiter = ',')] + #[arg(short, long = "field", aliases = ["fields"], num_args = 0.., action = ArgAction::Append, value_delimiter = ',')] fields: Vec, /// Print the raw RLP encoded block header. From de99dcd512835513384486450b419f7a73cbc95f Mon Sep 17 00:00:00 2001 From: dipanshuhappy Date: Mon, 3 Nov 2025 18:11:08 +0530 Subject: [PATCH 08/12] doc(cast): updated docs to match change in fields --- crates/cast/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/cast/src/lib.rs b/crates/cast/src/lib.rs index 8d0448e6562ae..9ec2bb01ca6e9 100644 --- a/crates/cast/src/lib.rs +++ b/crates/cast/src/lib.rs @@ -340,7 +340,7 @@ impl> Cast

{ /// let provider = /// ProviderBuilder::<_, _, AnyNetwork>::default().connect("http://localhost:8545").await?; /// let cast = Cast::new(provider); - /// let block = cast.block(5, true, None, false).await?; + /// let block = cast.block(5, true, vec![], false).await?; /// println!("{}", block); /// # Ok(()) /// # } From e41c2f2ffbf219a6812c392e67dfac3e204e7b1c Mon Sep 17 00:00:00 2001 From: dipanshuhappy Date: Tue, 11 Nov 2025 11:39:11 +0530 Subject: [PATCH 09/12] test(cast): Remove trailing whitespace from block output --- crates/cast/src/lib.rs | 3 ++- crates/cast/tests/cli/main.rs | 45 +++++++++++++++-------------------- 2 files changed, 21 insertions(+), 27 deletions(-) diff --git a/crates/cast/src/lib.rs b/crates/cast/src/lib.rs index 9ec2bb01ca6e9..6fb4b41eb8a44 100644 --- a/crates/cast/src/lib.rs +++ b/crates/cast/src/lib.rs @@ -374,9 +374,10 @@ impl> Cast

{ &get_pretty_block_attr(&block, &field) .unwrap_or_else(|| format!("{field} is not a valid block field")), ); + result.push('\n'); } - result + result.trim_end().to_string() } else if shell::is_json() { serde_json::to_value(&block).unwrap().to_string() } else { diff --git a/crates/cast/tests/cli/main.rs b/crates/cast/tests/cli/main.rs index 4949eedd89359..7fd1aa2f1c7fd 100644 --- a/crates/cast/tests/cli/main.rs +++ b/crates/cast/tests/cli/main.rs @@ -154,7 +154,6 @@ transactions: [ 0x950091817a57e22b6c1f3b951a15f52d41ac89b299cc8f9c89bb6d185f80c415 1655904485 - "#]]); }); @@ -1321,6 +1320,7 @@ casttest!(to_base, |_prj, cmd| { }); // tests that revert reason is only present if transaction has reverted. + casttest!(receipt_revert_reason, |_prj, cmd| { let rpc = next_http_archive_rpc_url(); @@ -1332,27 +1332,25 @@ casttest!(receipt_revert_reason, |_prj, cmd| { rpc.as_str(), ]) .assert_success() - .stdout_eq(str![[r#" - + .stdout_eq(format!(r#" blockHash 0x2cfe65be49863676b6dbc04d58176a14f39b123f1e2f4fea0383a2d82c2c50d0 blockNumber 16239315 -contractAddress +contractAddress {} cumulativeGasUsed 10743428 effectiveGasPrice 10539984136 from 0x199D5ED7F45F4eE35960cF22EAde2076e95B253F gasUsed 21000 logs [] logsBloom 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -root +root {} status 1 (success) transactionHash 0x44f2aaa351460c074f2cb1e5a9e28cbc7d83f33e425101d2de14331c7b7ec31e transactionIndex 116 type 0 -blobGasPrice -blobGasUsed +blobGasPrice {} +blobGasUsed {} to 0x91da5bf3F8Eb72724E6f50Ec6C3D199C6355c59c - -"#]]); +"#,"", "", "", "")); let rpc = next_http_archive_rpc_url(); @@ -1365,30 +1363,27 @@ to 0x91da5bf3F8Eb72724E6f50Ec6C3D199C6355c59c rpc.as_str(), ]) .assert_success() - .stdout_eq(str![[r#" - + .stdout_eq(format!(r#" blockHash 0x883f974b17ca7b28cb970798d1c80f4d4bb427473dc6d39b2a7fe24edc02902d blockNumber 14839405 -contractAddress +contractAddress {} cumulativeGasUsed 20273649 effectiveGasPrice 21491736378 from 0x3cF412d970474804623bb4e3a42dE13F9bCa5436 gasUsed 24952 logs [] logsBloom 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -root +root {} status 0 (failed) transactionHash 0x0e07d8b53ed3d91314c80e53cf25bcde02084939395845cbb625b029d568135c transactionIndex 173 type 2 -blobGasPrice -blobGasUsed +blobGasPrice {} +blobGasUsed {} to 0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45 revertReason [..]Transaction too old, data: "0x08c379a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000135472616e73616374696f6e20746f6f206f6c6400000000000000000000000000" - -"#]]); +"#,"","","","")); }); - // tests that the revert reason is loaded using the correct `from` address. casttest!(revert_reason_from, |_prj, cmd| { let rpc = next_rpc_endpoint(NamedChain::Sepolia); @@ -1400,28 +1395,26 @@ casttest!(revert_reason_from, |_prj, cmd| { rpc.as_str(), ]) .assert_success() - .stdout_eq(str![[r#" - + .stdout_eq(format!(r#" blockHash 0x32663d7730c9ea8e1de6d99854483e25fcc05bb56c91c0cc82f9f04944fbffc1 blockNumber 7823353 -contractAddress +contractAddress {} cumulativeGasUsed 7500797 effectiveGasPrice 14296851013 from 0x3583fF95f96b356d716881C871aF7Eb55ea34a93 gasUsed 25815 logs [] logsBloom 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -root +root {} status 0 (failed) transactionHash 0x10ee70cf9f5ced5c515e8d53bfab5ea9f5c72cd61b25fba455c8355ee286c4e4 transactionIndex 96 type 0 -blobGasPrice -blobGasUsed +blobGasPrice {} +blobGasUsed {} to 0x91b5d4111a4C038153b24e31F75ccdC47123595d revertReason Counter is too large, data: "0x08c379a000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000014436f756e74657220697320746f6f206c61726765000000000000000000000000" - -"#]]); +"#, "", "", "", "")); }); // tests that `cast --parse-bytes32-address` command is working correctly. From c84a3ecefe94f53c63789bceefc2a53cf8e8830d Mon Sep 17 00:00:00 2001 From: dipanshuhappy Date: Sat, 22 Nov 2025 19:53:18 +0530 Subject: [PATCH 10/12] feat(cast): added convert.rs sub command file with appropriate enums and handlers --- crates/cast/src/cmd/convert.rs | 435 +++++++++++++++++++++++++++++++++ 1 file changed, 435 insertions(+) create mode 100644 crates/cast/src/cmd/convert.rs diff --git a/crates/cast/src/cmd/convert.rs b/crates/cast/src/cmd/convert.rs new file mode 100644 index 0000000000000..8b54a29e1b115 --- /dev/null +++ b/crates/cast/src/cmd/convert.rs @@ -0,0 +1,435 @@ +use crate::SimpleCast; +use alloy_primitives::{Address, hex}; +use clap::Parser; +use eyre::Result; +use foundry_common::{sh_println, stdin}; +use std::{env, fs}; + +/// CLI arguments for `cast --to-base`. +#[derive(Debug, Parser)] +pub struct ToBaseArgs { + /// The value to convert. + #[arg(allow_hyphen_values = true)] + pub value: Option, + + /// The input base. + #[arg(long, short = 'i')] + pub base_in: Option, +} +#[derive(Debug, Parser)] +pub enum ConvertSubCommand { + /// Convert wei into an ETH amount. + /// + /// Consider using --to-unit. + #[command(visible_aliases = &["--from-wei", "fw"])] + FromWei { + /// The value to convert. + #[arg(allow_hyphen_values = true)] + value: Option, + + /// The unit to convert from (ether, gwei, wei). + #[arg(default_value = "eth")] + unit: String, + }, + /// Convert an ETH amount to wei. + /// + /// Consider using --to-unit. + #[command(visible_aliases = &["--to-wei", "tw", "2w"])] + ToWei { + /// The value to convert. + #[arg(allow_hyphen_values = true)] + value: Option, + + /// The unit to convert from (ether, gwei, wei). + #[arg(default_value = "eth")] + unit: String, + }, + /// Convert an ETH amount into another unit (ether, gwei or wei). + /// + /// Examples: + /// - 1ether wei + /// - "1 ether" wei + /// - 1ether + /// - 1 gwei + /// - 1gwei ether + #[command(visible_aliases = &["--to-unit", "tun", "2un"])] + ToUnit { + /// The value to convert. + value: Option, + + /// The unit to convert to (ether, gwei, wei). + #[arg(default_value = "wei")] + unit: String, + }, + /// Convert an integer into a fixed point number. + #[command(visible_aliases = &["--to-fix", "tf", "2f"])] + ToFixedPoint { + /// The number of decimals to use. + decimals: Option, + + /// The value to convert. + #[arg(allow_hyphen_values = true)] + value: Option, + }, + /// Convert a fixed point number into an integer. + #[command(visible_aliases = &["--from-fix", "ff"])] + FromFixedPoint { + /// The number of decimals to use. + decimals: Option, + + /// The value to convert. + #[arg(allow_hyphen_values = true)] + value: Option, + }, + /// Format a number from smallest unit to decimal with arbitrary decimals. + /// + /// Examples: + /// - 1000000 6 (for USDC, result: 1.0) + /// - 2500000000000 12 (for 12 decimals, result: 2.5) + /// - 1230 3 (for 3 decimals, result: 1.23) + #[command(visible_aliases = &["--format-units", "fun"])] + FormatUnits { + /// The value to format. + value: Option, + + /// The unit to format to. + #[arg(default_value = "18")] + unit: u8, + }, + /// Convert a number from decimal to smallest unit with arbitrary decimals. + /// + /// Examples: + /// - 1.0 6 (for USDC, result: 1000000) + /// - 2.5 12 (for 12 decimals token, result: 2500000000000) + /// - 1.23 3 (for 3 decimals token, result: 1230) + #[command(visible_aliases = &["--parse-units", "pun"])] + ParseUnits { + /// The value to convert. + value: Option, + + /// The unit to convert to. + #[arg(default_value = "18")] + unit: u8, + }, + /// Converts a number of one base to another + #[command(visible_aliases = &["--to-hex", "th", "2h"])] + ToHex(ToBaseArgs), + + /// Converts a number of one base to decimal + #[command(visible_aliases = &["--to-dec", "td", "2d"])] + ToDec(ToBaseArgs), + /// Converts a number of one base to another + #[command( + visible_aliases = &["--to-base", + "--to-radix", + "to-radix", + "tr", + "2r"] + )] + ToBase { + #[command(flatten)] + base: ToBaseArgs, + + /// The output base. + #[arg(value_name = "BASE")] + base_out: Option, + }, + /// Convert a number to a hex-encoded int256. + #[command(name = "to-int256", visible_aliases = &["--to-int256", "ti", "2i"])] + ToInt256 { + /// The value to convert. + value: Option, + }, + /// Convert a number to a hex-encoded uint256. + #[command(name = "to-uint256", visible_aliases = &["--to-uint256", "tu", "2u"])] + ToUint256 { + /// The value to convert. + value: Option, + }, + + // New commands copied from opts.rs + /// Convert UTF-8 text to hex. + #[command( + visible_aliases = &[ + "--from-ascii", + "--from-utf8", + "from-ascii", + "fu", + "fa"] + )] + FromUtf8 { + /// The text to convert. + text: Option, + }, + + /// Convert hex data to a utf-8 string. + #[command(visible_aliases = &["--to-utf8", "tu8", "2u8"])] + ToUtf8 { + /// The hex data to convert. + hexdata: Option, + }, + + /// Convert hex data to an ASCII string. + #[command(visible_aliases = &["--to-ascii", "tas", "2as"])] + ToAscii { + /// The hex data to convert. + hexdata: Option, + }, + + /// Convert binary data into hex data. + #[command(visible_aliases = &["--from-bin", "from-binx", "fb"])] + FromBin, + + /// Right-pads hex data to 32 bytes. + #[command(visible_aliases = &["--to-bytes32", "tb", "2b"])] + ToBytes32 { + /// The hex data to convert. + bytes: Option, + }, + + /// Normalize the input to lowercase, 0x-prefixed hex. + /// + /// The input can be: + /// - mixed case hex with or without 0x prefix + /// - 0x prefixed hex, concatenated with a ':' + /// - an absolute path to file + /// - @tag, where the tag is defined in an environment variable + #[command(visible_aliases = &["--to-hexdata", "thd", "2hd"])] + ToHexdata { + /// The input to normalize. + input: Option, + }, + + /// Formats a string into bytes32 encoding. + #[command(name = "format-bytes32-string", visible_aliases = &["--format-bytes32-string"])] + FormatBytes32String { + /// The string to format. + string: Option, + }, + + /// Parses a string from bytes32 encoding. + #[command(name = "parse-bytes32-string", visible_aliases = &["--parse-bytes32-string"])] + ParseBytes32String { + /// The string to parse. + bytes: Option, + }, + + /// Parses a checksummed address from bytes32 encoding. + #[command(name = "parse-bytes32-address", visible_aliases = &["--parse-bytes32-address"])] + ParseBytes32Address { + #[arg(value_name = "BYTES")] + bytes: Option, + }, + + /// Convert an address to a checksummed format (EIP-55). + #[command( + visible_aliases = &["--to-checksum-address", + "--to-checksum", + "to-checksum", + "ta", + "2a"] + )] + ToCheckSumAddress { + /// The address to convert. + address: Option

, + /// EIP-155 chain ID to encode the address using EIP-1191. + chain_id: Option, + }, + + /// Concatenate hex strings. + #[command(visible_aliases = &["--concat-hex", "ch"])] + ConcatHex { + /// The data to concatenate. + data: Vec, + }, + + /// Pads hex data to a specified length. + #[command(visible_aliases = &["pd"])] + Pad { + /// The hex data to pad. + data: Option, + + /// Right-pad the data (instead of left-pad). + #[arg(long)] + right: bool, + + /// Left-pad the data (default). + #[arg(long, conflicts_with = "right")] + left: bool, + + /// Target length in bytes (default: 32). + #[arg(long, default_value = "32")] + len: usize, + }, + + /// RLP encode the given JSON data. + /// + /// Example: cast to-rlp "[\"0x61\"]" -> `0xc161` + /// - `cast to-rlp "[\"0x61\"]"` -> `0xc161` + /// - `cast to-rlp "[\"0xf1\", \"f2\"]"` -> `0xc481f181f2` + #[command(visible_aliases = &["--to-rlp"])] + ToRlp { + /// The value to convert. + /// + /// This is a hex-encoded string, or an array of hex-encoded strings. + /// Can be arbitrarily recursive. + value: Option, + }, + + /// Decodes RLP hex-encoded data. + #[command(visible_aliases = &["--from-rlp"])] + FromRlp { + /// The RLP hex-encoded data. + value: Option, + + /// Decode the RLP data as int + #[arg(long, alias = "int")] + as_int: bool, + }, +} + +impl ConvertSubCommand { + pub async fn run(self) -> Result<()> { + match self { + // Wei/Ether unit conversions + Self::FromWei { value, unit } => { + let value = stdin::unwrap_line(value)?; + sh_println!("{}", SimpleCast::from_wei(&value, &unit)?)?; + } + Self::ToWei { value, unit } => { + let value = stdin::unwrap_line(value)?; + sh_println!("{}", SimpleCast::to_wei(&value, &unit)?)?; + } + Self::ToUnit { value, unit } => { + let value = stdin::unwrap_line(value)?; + sh_println!("{}", SimpleCast::to_unit(&value, &unit)?)?; + } + + // Fixed point conversions + Self::ToFixedPoint { value, decimals } => { + let (value, decimals) = stdin::unwrap2(value, decimals)?; + sh_println!("{}", SimpleCast::to_fixed_point(&value, &decimals)?)?; + } + Self::FromFixedPoint { value, decimals } => { + let (value, decimals) = stdin::unwrap2(value, decimals)?; + sh_println!("{}", SimpleCast::from_fixed_point(&value, &decimals)?)?; + } + + // Unit parsing and formatting + Self::FormatUnits { value, unit } => { + let value = stdin::unwrap_line(value)?; + sh_println!("{}", SimpleCast::format_units(&value, unit)?)?; + } + Self::ParseUnits { value, unit } => { + let value = stdin::unwrap_line(value)?; + sh_println!("{}", SimpleCast::parse_units(&value, unit)?)?; + } + + // Base conversions + Self::ToHex(ToBaseArgs { value, base_in }) => { + let value = stdin::unwrap_line(value)?; + sh_println!("{}", SimpleCast::to_base(&value, base_in.as_deref(), "hex")?)?; + } + Self::ToDec(ToBaseArgs { value, base_in }) => { + let value = stdin::unwrap_line(value)?; + sh_println!("{}", SimpleCast::to_base(&value, base_in.as_deref(), "dec")?)?; + } + Self::ToBase { base: ToBaseArgs { value, base_in }, base_out } => { + let (value, base_out) = stdin::unwrap2(value, base_out)?; + sh_println!("{}", SimpleCast::to_base(&value, base_in.as_deref(), &base_out)?)?; + } + + // Integer conversions + Self::ToInt256 { value } => { + let value = stdin::unwrap_line(value)?; + sh_println!("{}", SimpleCast::to_int256(&value)?)?; + } + Self::ToUint256 { value } => { + let value = stdin::unwrap_line(value)?; + sh_println!("{}", SimpleCast::to_uint256(&value)?)?; + } + + // String/Hex conversions + Self::FromUtf8 { text } => { + let value = stdin::unwrap(text, false)?; + sh_println!("{}", SimpleCast::from_utf8(&value))?; + } + Self::ToUtf8 { hexdata } => { + let value = stdin::unwrap(hexdata, false)?; + sh_println!("{}", SimpleCast::to_utf8(&value)?)?; + } + Self::ToAscii { hexdata } => { + let value = stdin::unwrap(hexdata, false)?; + sh_println!("{}", SimpleCast::to_ascii(value.trim())?)?; + } + + // Binary conversion + Self::FromBin => { + let hex = stdin::read_bytes(false)?; + sh_println!("{}", hex::encode_prefixed(hex))?; + } + + // Bytes32 conversions + Self::ToBytes32 { bytes } => { + let value = stdin::unwrap_line(bytes)?; + sh_println!("{}", SimpleCast::to_bytes32(&value)?)?; + } + + // Hex data normalization + Self::ToHexdata { input } => { + let value = stdin::unwrap_line(input)?; + let output = match value { + s if s.starts_with('@') => hex::encode(env::var(&s[1..])?), + s if s.starts_with('/') => hex::encode(fs::read(s)?), + s => s.split(':').map(|s| s.trim_start_matches("0x").to_lowercase()).collect(), + }; + sh_println!("0x{output}")?; + } + + // Bytes32 string operations + Self::FormatBytes32String { string } => { + let value = stdin::unwrap_line(string)?; + sh_println!("{}", SimpleCast::format_bytes32_string(&value)?)?; + } + Self::ParseBytes32String { bytes } => { + let value = stdin::unwrap_line(bytes)?; + sh_println!("{}", SimpleCast::parse_bytes32_string(&value)?)?; + } + Self::ParseBytes32Address { bytes } => { + let value = stdin::unwrap_line(bytes)?; + sh_println!("{}", SimpleCast::parse_bytes32_address(&value)?)?; + } + + // Address checksum + Self::ToCheckSumAddress { address, chain_id } => { + let value = stdin::unwrap_line(address)?; + sh_println!("{}", value.to_checksum(chain_id))?; + } + + // Hex operations + Self::ConcatHex { data } => { + if data.is_empty() { + let s = stdin::read(true)?; + sh_println!("{}", SimpleCast::concat_hex(s.split_whitespace()))?; + } else { + sh_println!("{}", SimpleCast::concat_hex(data))?; + } + } + Self::Pad { data, right, left: _, len } => { + let value = stdin::unwrap_line(data)?; + sh_println!("{}", SimpleCast::pad(&value, right, len)?)?; + } + + // RLP operations + Self::ToRlp { value } => { + let value = stdin::unwrap_line(value)?; + sh_println!("{}", SimpleCast::to_rlp(&value)?)?; + } + Self::FromRlp { value, as_int } => { + let value = stdin::unwrap_line(value)?; + sh_println!("{}", SimpleCast::from_rlp(value, as_int)?)?; + } + } + Ok(()) + } +} From 38dcf3d503f36679f94dcb0e2ee3f04b3f5ccd70 Mon Sep 17 00:00:00 2001 From: dipanshuhappy Date: Sat, 22 Nov 2025 19:53:40 +0530 Subject: [PATCH 11/12] feat(cast): changed existing covert cli tooling --- crates/cast/src/args.rs | 121 +-------------- crates/cast/src/cmd/mod.rs | 1 + crates/cast/src/opts.rs | 298 ++----------------------------------- 3 files changed, 17 insertions(+), 403 deletions(-) diff --git a/crates/cast/src/args.rs b/crates/cast/src/args.rs index 4538512f93c19..4ca715f4f3e0c 100644 --- a/crates/cast/src/args.rs +++ b/crates/cast/src/args.rs @@ -1,7 +1,7 @@ use crate::{ Cast, SimpleCast, cmd::erc20::IERC20, - opts::{Cast as CastArgs, CastSubcommand, ToBaseArgs}, + opts::{Cast as CastArgs, CastSubcommand}, traces::identifier::SignaturesIdentifier, }; use alloy_consensus::transaction::{Recovered, SignerRecoverable}; @@ -64,122 +64,6 @@ pub async fn run_command(args: CastArgs) -> Result<()> { CastSubcommand::HashZero => { sh_println!("{:?}", B256::ZERO)?; } - - // Conversions & transformations - CastSubcommand::FromUtf8 { text } => { - let value = stdin::unwrap(text, false)?; - sh_println!("{}", SimpleCast::from_utf8(&value))? - } - CastSubcommand::ToAscii { hexdata } => { - let value = stdin::unwrap(hexdata, false)?; - sh_println!("{}", SimpleCast::to_ascii(value.trim())?)? - } - CastSubcommand::ToUtf8 { hexdata } => { - let value = stdin::unwrap(hexdata, false)?; - sh_println!("{}", SimpleCast::to_utf8(&value)?)? - } - CastSubcommand::FromFixedPoint { value, decimals } => { - let (value, decimals) = stdin::unwrap2(value, decimals)?; - sh_println!("{}", SimpleCast::from_fixed_point(&value, &decimals)?)? - } - CastSubcommand::ToFixedPoint { value, decimals } => { - let (value, decimals) = stdin::unwrap2(value, decimals)?; - sh_println!("{}", SimpleCast::to_fixed_point(&value, &decimals)?)? - } - CastSubcommand::ConcatHex { data } => { - if data.is_empty() { - let s = stdin::read(true)?; - sh_println!("{}", SimpleCast::concat_hex(s.split_whitespace()))? - } else { - sh_println!("{}", SimpleCast::concat_hex(data))? - } - } - CastSubcommand::FromBin => { - let hex = stdin::read_bytes(false)?; - sh_println!("{}", hex::encode_prefixed(hex))? - } - CastSubcommand::ToHexdata { input } => { - let value = stdin::unwrap_line(input)?; - let output = match value { - s if s.starts_with('@') => hex::encode(std::env::var(&s[1..])?), - s if s.starts_with('/') => hex::encode(fs::read(s)?), - s => s.split(':').map(|s| s.trim_start_matches("0x").to_lowercase()).collect(), - }; - sh_println!("0x{output}")? - } - CastSubcommand::ToCheckSumAddress { address, chain_id } => { - let value = stdin::unwrap_line(address)?; - sh_println!("{}", value.to_checksum(chain_id))? - } - CastSubcommand::ToUint256 { value } => { - let value = stdin::unwrap_line(value)?; - sh_println!("{}", SimpleCast::to_uint256(&value)?)? - } - CastSubcommand::ToInt256 { value } => { - let value = stdin::unwrap_line(value)?; - sh_println!("{}", SimpleCast::to_int256(&value)?)? - } - CastSubcommand::ToUnit { value, unit } => { - let value = stdin::unwrap_line(value)?; - sh_println!("{}", SimpleCast::to_unit(&value, &unit)?)? - } - CastSubcommand::ParseUnits { value, unit } => { - let value = stdin::unwrap_line(value)?; - sh_println!("{}", SimpleCast::parse_units(&value, unit)?)?; - } - CastSubcommand::FormatUnits { value, unit } => { - let value = stdin::unwrap_line(value)?; - sh_println!("{}", SimpleCast::format_units(&value, unit)?)?; - } - CastSubcommand::FromWei { value, unit } => { - let value = stdin::unwrap_line(value)?; - sh_println!("{}", SimpleCast::from_wei(&value, &unit)?)? - } - CastSubcommand::ToWei { value, unit } => { - let value = stdin::unwrap_line(value)?; - sh_println!("{}", SimpleCast::to_wei(&value, &unit)?)? - } - CastSubcommand::FromRlp { value, as_int } => { - let value = stdin::unwrap_line(value)?; - sh_println!("{}", SimpleCast::from_rlp(value, as_int)?)? - } - CastSubcommand::ToRlp { value } => { - let value = stdin::unwrap_line(value)?; - sh_println!("{}", SimpleCast::to_rlp(&value)?)? - } - CastSubcommand::ToHex(ToBaseArgs { value, base_in }) => { - let value = stdin::unwrap_line(value)?; - sh_println!("{}", SimpleCast::to_base(&value, base_in.as_deref(), "hex")?)? - } - CastSubcommand::ToDec(ToBaseArgs { value, base_in }) => { - let value = stdin::unwrap_line(value)?; - sh_println!("{}", SimpleCast::to_base(&value, base_in.as_deref(), "dec")?)? - } - CastSubcommand::ToBase { base: ToBaseArgs { value, base_in }, base_out } => { - let (value, base_out) = stdin::unwrap2(value, base_out)?; - sh_println!("{}", SimpleCast::to_base(&value, base_in.as_deref(), &base_out)?)? - } - CastSubcommand::ToBytes32 { bytes } => { - let value = stdin::unwrap_line(bytes)?; - sh_println!("{}", SimpleCast::to_bytes32(&value)?)? - } - CastSubcommand::Pad { data, right, left: _, len } => { - let value = stdin::unwrap_line(data)?; - sh_println!("{}", SimpleCast::pad(&value, right, len)?)? - } - CastSubcommand::FormatBytes32String { string } => { - let value = stdin::unwrap_line(string)?; - sh_println!("{}", SimpleCast::format_bytes32_string(&value)?)? - } - CastSubcommand::ParseBytes32String { bytes } => { - let value = stdin::unwrap_line(bytes)?; - sh_println!("{}", SimpleCast::parse_bytes32_string(&value)?)? - } - CastSubcommand::ParseBytes32Address { bytes } => { - let value = stdin::unwrap_line(bytes)?; - sh_println!("{}", SimpleCast::parse_bytes32_address(&value)?)? - } - // ABI encoding & decoding CastSubcommand::DecodeAbi { sig, calldata, input } => { let tokens = SimpleCast::abi_decode(&sig, &calldata, input)?; @@ -756,6 +640,9 @@ pub async fn run_command(args: CastArgs) -> Result<()> { CastSubcommand::DAEstimate(cmd) => { cmd.run().await?; } + CastSubcommand::Convert { command } => { + command.run().await?; + } }; /// Prints slice of tokens using [`format_tokens`] or [`serialize_value_as_json`] depending diff --git a/crates/cast/src/cmd/mod.rs b/crates/cast/src/cmd/mod.rs index 782a34071cf71..174e8857250d8 100644 --- a/crates/cast/src/cmd/mod.rs +++ b/crates/cast/src/cmd/mod.rs @@ -11,6 +11,7 @@ pub mod b2e_payload; pub mod bind; pub mod call; pub mod constructor_args; +pub mod convert; pub mod create2; pub mod creation_code; pub mod da_estimate; diff --git a/crates/cast/src/opts.rs b/crates/cast/src/opts.rs index b52d38c4c73c8..9374531e42e3e 100644 --- a/crates/cast/src/opts.rs +++ b/crates/cast/src/opts.rs @@ -1,10 +1,11 @@ use crate::cmd::{ access_list::AccessListArgs, artifact::ArtifactArgs, b2e_payload::B2EPayloadArgs, - bind::BindArgs, call::CallArgs, constructor_args::ConstructorArgsArgs, create2::Create2Args, - creation_code::CreationCodeArgs, da_estimate::DAEstimateArgs, erc20::Erc20Subcommand, - estimate::EstimateArgs, find_block::FindBlockArgs, interface::InterfaceArgs, logs::LogsArgs, - mktx::MakeTxArgs, rpc::RpcArgs, run::RunArgs, send::SendTxArgs, storage::StorageArgs, - txpool::TxPoolSubcommands, wallet::WalletSubcommands, + bind::BindArgs, call::CallArgs, constructor_args::ConstructorArgsArgs, + convert::ConvertSubCommand, create2::Create2Args, creation_code::CreationCodeArgs, + da_estimate::DAEstimateArgs, erc20::Erc20Subcommand, estimate::EstimateArgs, + find_block::FindBlockArgs, interface::InterfaceArgs, logs::LogsArgs, mktx::MakeTxArgs, + rpc::RpcArgs, run::RunArgs, send::SendTxArgs, storage::StorageArgs, txpool::TxPoolSubcommands, + wallet::WalletSubcommands, }; use alloy_ens::NameOrAddress; use alloy_primitives::{Address, B256, Selector, U256}; @@ -66,135 +67,6 @@ pub enum CastSubcommand { #[command(visible_aliases = &["--hash-zero", "hz"])] HashZero, - /// Convert UTF8 text to hex. - #[command( - visible_aliases = &[ - "--from-ascii", - "--from-utf8", - "from-ascii", - "fu", - "fa"] - )] - FromUtf8 { - /// The text to convert. - text: Option, - }, - - /// Concatenate hex strings. - #[command(visible_aliases = &["--concat-hex", "ch"])] - ConcatHex { - /// The data to concatenate. - data: Vec, - }, - - /// Convert binary data into hex data. - #[command(visible_aliases = &["--from-bin", "from-binx", "fb"])] - FromBin, - - /// Normalize the input to lowercase, 0x-prefixed hex. - /// - /// The input can be: - /// - mixed case hex with or without 0x prefix - /// - 0x prefixed hex, concatenated with a ':' - /// - an absolute path to file - /// - @tag, where the tag is defined in an environment variable - #[command(visible_aliases = &["--to-hexdata", "thd", "2hd"])] - ToHexdata { - /// The input to normalize. - input: Option, - }, - - /// Convert an address to a checksummed format (EIP-55). - #[command( - visible_aliases = &["--to-checksum-address", - "--to-checksum", - "to-checksum", - "ta", - "2a"] - )] - ToCheckSumAddress { - /// The address to convert. - address: Option
, - /// EIP-155 chain ID to encode the address using EIP-1191. - chain_id: Option, - }, - - /// Convert hex data to an ASCII string. - #[command(visible_aliases = &["--to-ascii", "tas", "2as"])] - ToAscii { - /// The hex data to convert. - hexdata: Option, - }, - - /// Convert hex data to a utf-8 string. - #[command(visible_aliases = &["--to-utf8", "tu8", "2u8"])] - ToUtf8 { - /// The hex data to convert. - hexdata: Option, - }, - - /// Convert a fixed point number into an integer. - #[command(visible_aliases = &["--from-fix", "ff"])] - FromFixedPoint { - /// The number of decimals to use. - decimals: Option, - - /// The value to convert. - #[arg(allow_hyphen_values = true)] - value: Option, - }, - - /// Right-pads hex data to 32 bytes. - #[command(visible_aliases = &["--to-bytes32", "tb", "2b"])] - ToBytes32 { - /// The hex data to convert. - bytes: Option, - }, - - /// Pads hex data to a specified length. - #[command(visible_aliases = &["pd"])] - Pad { - /// The hex data to pad. - data: Option, - - /// Right-pad the data (instead of left-pad). - #[arg(long)] - right: bool, - - /// Left-pad the data (default). - #[arg(long, conflicts_with = "right")] - left: bool, - - /// Target length in bytes (default: 32). - #[arg(long, default_value = "32")] - len: usize, - }, - - /// Convert an integer into a fixed point number. - #[command(visible_aliases = &["--to-fix", "tf", "2f"])] - ToFixedPoint { - /// The number of decimals to use. - decimals: Option, - - /// The value to convert. - #[arg(allow_hyphen_values = true)] - value: Option, - }, - - /// Convert a number to a hex-encoded uint256. - #[command(name = "to-uint256", visible_aliases = &["--to-uint256", "tu", "2u"])] - ToUint256 { - /// The value to convert. - value: Option, - }, - - /// Convert a number to a hex-encoded int256. - #[command(name = "to-int256", visible_aliases = &["--to-int256", "ti", "2i"])] - ToInt256 { - /// The value to convert. - value: Option, - }, - /// Perform a left shifting operation #[command(name = "shl")] LeftShift { @@ -231,138 +103,6 @@ pub enum CastSubcommand { base_out: String, }, - /// Convert an ETH amount into another unit (ether, gwei or wei). - /// - /// Examples: - /// - 1ether wei - /// - "1 ether" wei - /// - 1ether - /// - 1 gwei - /// - 1gwei ether - #[command(visible_aliases = &["--to-unit", "tun", "2un"])] - ToUnit { - /// The value to convert. - value: Option, - - /// The unit to convert to (ether, gwei, wei). - #[arg(default_value = "wei")] - unit: String, - }, - - /// Convert a number from decimal to smallest unit with arbitrary decimals. - /// - /// Examples: - /// - 1.0 6 (for USDC, result: 1000000) - /// - 2.5 12 (for 12 decimals token, result: 2500000000000) - /// - 1.23 3 (for 3 decimals token, result: 1230) - #[command(visible_aliases = &["--parse-units", "pun"])] - ParseUnits { - /// The value to convert. - value: Option, - - /// The unit to convert to. - #[arg(default_value = "18")] - unit: u8, - }, - - /// Format a number from smallest unit to decimal with arbitrary decimals. - /// - /// Examples: - /// - 1000000 6 (for USDC, result: 1.0) - /// - 2500000000000 12 (for 12 decimals, result: 2.5) - /// - 1230 3 (for 3 decimals, result: 1.23) - #[command(visible_aliases = &["--format-units", "fun"])] - FormatUnits { - /// The value to format. - value: Option, - - /// The unit to format to. - #[arg(default_value = "18")] - unit: u8, - }, - - /// Convert an ETH amount to wei. - /// - /// Consider using --to-unit. - #[command(visible_aliases = &["--to-wei", "tw", "2w"])] - ToWei { - /// The value to convert. - #[arg(allow_hyphen_values = true)] - value: Option, - - /// The unit to convert from (ether, gwei, wei). - #[arg(default_value = "eth")] - unit: String, - }, - - /// Convert wei into an ETH amount. - /// - /// Consider using --to-unit. - #[command(visible_aliases = &["--from-wei", "fw"])] - FromWei { - /// The value to convert. - #[arg(allow_hyphen_values = true)] - value: Option, - - /// The unit to convert from (ether, gwei, wei). - #[arg(default_value = "eth")] - unit: String, - }, - - /// RLP encodes hex data, or an array of hex data. - /// - /// Accepts a hex-encoded string, or an array of hex-encoded strings. - /// Can be arbitrarily recursive. - /// - /// Examples: - /// - `cast to-rlp "[]"` -> `0xc0` - /// - `cast to-rlp "0x22"` -> `0x22` - /// - `cast to-rlp "[\"0x61\"]"` -> `0xc161` - /// - `cast to-rlp "[\"0xf1\", \"f2\"]"` -> `0xc481f181f2` - #[command(visible_aliases = &["--to-rlp"])] - ToRlp { - /// The value to convert. - /// - /// This is a hex-encoded string, or an array of hex-encoded strings. - /// Can be arbitrarily recursive. - value: Option, - }, - - /// Decodes RLP hex-encoded data. - #[command(visible_aliases = &["--from-rlp"])] - FromRlp { - /// The RLP hex-encoded data. - value: Option, - - /// Decode the RLP data as int - #[arg(long, alias = "int")] - as_int: bool, - }, - - /// Converts a number of one base to another - #[command(visible_aliases = &["--to-hex", "th", "2h"])] - ToHex(ToBaseArgs), - - /// Converts a number of one base to decimal - #[command(visible_aliases = &["--to-dec", "td", "2d"])] - ToDec(ToBaseArgs), - - /// Converts a number of one base to another - #[command( - visible_aliases = &["--to-base", - "--to-radix", - "to-radix", - "tr", - "2r"] - )] - ToBase { - #[command(flatten)] - base: ToBaseArgs, - - /// The output base. - #[arg(value_name = "BASE")] - base_out: Option, - }, /// Create an access list for a transaction. #[command(visible_aliases = &["ac", "acl"])] AccessList(AccessListArgs), @@ -1091,26 +831,6 @@ pub enum CastSubcommand { #[command(visible_alias = "rp")] Rpc(RpcArgs), - /// Formats a string into bytes32 encoding. - #[command(name = "format-bytes32-string", visible_aliases = &["--format-bytes32-string"])] - FormatBytes32String { - /// The string to format. - string: Option, - }, - - /// Parses a string from bytes32 encoding. - #[command(name = "parse-bytes32-string", visible_aliases = &["--parse-bytes32-string"])] - ParseBytes32String { - /// The string to parse. - bytes: Option, - }, - #[command(name = "parse-bytes32-address", visible_aliases = &["--parse-bytes32-address"])] - #[command(about = "Parses a checksummed address from bytes32 encoding.")] - ParseBytes32Address { - #[arg(value_name = "BYTES")] - bytes: Option, - }, - /// Decodes a raw signed EIP 2718 typed transaction #[command(visible_aliases = &["dt", "decode-tx"])] DecodeTransaction { tx: Option }, @@ -1146,6 +866,12 @@ pub enum CastSubcommand { #[command(subcommand)] command: Erc20Subcommand, }, + /// Convert operations. + #[command(visible_alias = "convert")] + Convert { + #[command(subcommand)] + command: ConvertSubCommand, + }, } /// CLI arguments for `cast --to-base`. From 5362d4c12105ad190d63981146a9ee7b2da1b53c Mon Sep 17 00:00:00 2001 From: dipanshuhappy Date: Sat, 29 Nov 2025 15:05:26 +0530 Subject: [PATCH 12/12] feat(cast): updatd test cases --- crates/cast/src/opts.rs | 2 +- crates/cast/tests/cli/main.rs | 41 ++++++++++++++++++++--------------- 2 files changed, 24 insertions(+), 19 deletions(-) diff --git a/crates/cast/src/opts.rs b/crates/cast/src/opts.rs index 9374531e42e3e..fab0b5a4b9caa 100644 --- a/crates/cast/src/opts.rs +++ b/crates/cast/src/opts.rs @@ -867,7 +867,7 @@ pub enum CastSubcommand { command: Erc20Subcommand, }, /// Convert operations. - #[command(visible_alias = "convert")] + #[command(name = "convert")] Convert { #[command(subcommand)] command: ConvertSubCommand, diff --git a/crates/cast/tests/cli/main.rs b/crates/cast/tests/cli/main.rs index d76b6f51592f9..1e9daeb50b925 100644 --- a/crates/cast/tests/cli/main.rs +++ b/crates/cast/tests/cli/main.rs @@ -1187,18 +1187,20 @@ casttest!(estimate_contract_deploy_gas, |_prj, cmd| { // tests that the `cast to-rlp` and `cast from-rlp` commands work correctly casttest!(rlp, |_prj, cmd| { - cmd.args(["--to-rlp", "[\"0xaa\", [[\"bb\"]], \"0xcc\"]"]).assert_success().stdout_eq(str![[ - r#" + cmd.args(["convert", "--to-rlp", "[\"0xaa\", [[\"bb\"]], \"0xcc\"]"]) + .assert_success() + .stdout_eq(str![[r#" 0xc881aac3c281bb81cc -"# - ]]); +"#]]); cmd.cast_fuse(); - cmd.args(["--from-rlp", "0xcbc58455556666c0c0c2c1c0"]).assert_success().stdout_eq(str![[r#" + cmd.args(["convert", "--from-rlp", "0xcbc58455556666c0c0c2c1c0"]).assert_success().stdout_eq( + str![[r#" [["0x55556666"],[],[],[[[]]]] -"#]]); +"#]], + ); }); // test that `cast impl` works correctly for both the implementation slot and the beacon slot @@ -1389,11 +1391,11 @@ casttest!(to_base, |_prj, cmd| { for subcmd in ["--to-base", "--to-hex", "--to-dec"] { if subcmd == "--to-base" { for base in ["bin", "oct", "dec", "hex"] { - cmd.cast_fuse().args([subcmd, value, base]); + cmd.cast_fuse().args(["convert", subcmd, value, base]); assert!(!cmd.assert_success().get_output().stdout_lossy().trim().is_empty()); } } else { - cmd.cast_fuse().args([subcmd, value]); + cmd.cast_fuse().args(["convert", subcmd, value]); assert!(!cmd.assert_success().get_output().stdout_lossy().trim().is_empty()); } } @@ -1501,6 +1503,7 @@ revertReason Counter is too large, data: "0x08c379a000000000000000000000 // tests that `cast --parse-bytes32-address` command is working correctly. casttest!(parse_bytes32_address, |_prj, cmd| { cmd.args([ + "convert", "--parse-bytes32-address", "0x000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa96045", ]) @@ -2699,20 +2702,22 @@ casttest!(hash_message, |_prj, cmd| { }); casttest!(parse_units, |_prj, cmd| { - cmd.args(["parse-units", "1.5", "6"]).assert_success().stdout_eq(str![[r#" + cmd.args(["convert", "parse-units", "1.5", "6"]).assert_success().stdout_eq(str![[r#" 1500000 "#]]); - cmd.cast_fuse().args(["pun", "1.23", "18"]).assert_success().stdout_eq(str![[r#" + cmd.cast_fuse().args(["convert", "pun", "1.23", "18"]).assert_success().stdout_eq(str![[r#" 1230000000000000000 "#]]); - cmd.cast_fuse().args(["--parse-units", "1.23", "3"]).assert_success().stdout_eq(str![[r#" + cmd.cast_fuse().args(["convert", "--parse-units", "1.23", "3"]).assert_success().stdout_eq( + str![[r#" 1230 -"#]]); +"#]], + ); }); casttest!(string_decode, |_prj, cmd| { @@ -2723,19 +2728,19 @@ casttest!(string_decode, |_prj, cmd| { }); casttest!(format_units, |_prj, cmd| { - cmd.args(["format-units", "1000000", "6"]).assert_success().stdout_eq(str![[r#" + cmd.args(["convert", "format-units", "1000000", "6"]).assert_success().stdout_eq(str![[r#" 1 "#]]); - cmd.cast_fuse().args(["--format-units", "2500000", "6"]).assert_success().stdout_eq(str![[ - r#" + cmd.cast_fuse().args(["convert", "--format-units", "2500000", "6"]).assert_success().stdout_eq( + str![[r#" 2.500000 -"# - ]]); +"#]], + ); - cmd.cast_fuse().args(["fun", "1230", "3"]).assert_success().stdout_eq(str![[r#" + cmd.cast_fuse().args(["convert", "fun", "1230", "3"]).assert_success().stdout_eq(str![[r#" 1.230 "#]]);