Skip to main content

cast/
args.rs

1use crate::{
2    Cast, SimpleCast,
3    cmd::erc20::IERC20,
4    opts::{Cast as CastArgs, CastSubcommand, ToBaseArgs},
5    traces::identifier::SignaturesIdentifier,
6    tx::CastTxSender,
7};
8use alloy_dyn_abi::{DynSolValue, ErrorExt, EventExt};
9use alloy_eips::eip7702::SignedAuthorization;
10use alloy_ens::{ProviderEnsExt, namehash};
11use alloy_network::Ethereum;
12use alloy_primitives::{Address, B256, eip191_hash_message, hex, keccak256};
13use alloy_provider::Provider;
14use alloy_rpc_types::{BlockId, BlockNumberOrTag::Latest};
15use clap::{CommandFactory, Parser};
16use clap_complete::generate;
17use eyre::Result;
18use foundry_cli::{
19    opts::NetworkVariant,
20    utils::{self, LoadConfig},
21};
22use foundry_common::{
23    abi::{get_error, get_event},
24    fmt::{format_tokens, format_uint_exp, serialize_value_as_json},
25    fs,
26    provider::ProviderBuilder,
27    selectors::{
28        ParsedSignatures, SelectorImportData, SelectorKind, decode_calldata, decode_event_topic,
29        decode_function_selector, decode_selectors, import_selectors, parse_signatures,
30        pretty_calldata,
31    },
32    shell, stdin,
33};
34use op_alloy_network::Optimism;
35use std::time::Instant;
36use tempo_alloy::TempoNetwork;
37
38/// Run the `cast` command-line interface.
39pub fn run() -> Result<()> {
40    setup()?;
41
42    foundry_cli::opts::GlobalArgs::check_markdown_help::<CastArgs>();
43
44    let args = CastArgs::parse();
45    args.global.init()?;
46    args.global.tokio_runtime().block_on(run_command(args))
47}
48
49/// Setup the global logger and other utilities.
50pub fn setup() -> Result<()> {
51    utils::common_setup();
52    utils::subscriber();
53
54    Ok(())
55}
56
57/// Run the subcommand.
58pub async fn run_command(args: CastArgs) -> Result<()> {
59    match args.cmd {
60        // Constants
61        CastSubcommand::MaxInt { r#type } => {
62            sh_println!("{}", SimpleCast::max_int(&r#type)?)?;
63        }
64        CastSubcommand::MinInt { r#type } => {
65            sh_println!("{}", SimpleCast::min_int(&r#type)?)?;
66        }
67        CastSubcommand::MaxUint { r#type } => {
68            sh_println!("{}", SimpleCast::max_int(&r#type)?)?;
69        }
70        CastSubcommand::AddressZero => {
71            sh_println!("{:?}", Address::ZERO)?;
72        }
73        CastSubcommand::HashZero => {
74            sh_println!("{:?}", B256::ZERO)?;
75        }
76
77        // Conversions & transformations
78        CastSubcommand::FromUtf8 { text } => {
79            let value = stdin::unwrap(text, false)?;
80            sh_println!("{}", SimpleCast::from_utf8(&value))?
81        }
82        CastSubcommand::ToAscii { hexdata } => {
83            let value = stdin::unwrap(hexdata, false)?;
84            sh_println!("{}", SimpleCast::to_ascii(value.trim())?)?
85        }
86        CastSubcommand::ToUtf8 { hexdata } => {
87            let value = stdin::unwrap(hexdata, false)?;
88            sh_println!("{}", SimpleCast::to_utf8(&value)?)?
89        }
90        CastSubcommand::FromFixedPoint { value, decimals } => {
91            let (value, decimals) = stdin::unwrap2(value, decimals)?;
92            sh_println!("{}", SimpleCast::from_fixed_point(&value, &decimals)?)?
93        }
94        CastSubcommand::ToFixedPoint { value, decimals } => {
95            let (value, decimals) = stdin::unwrap2(value, decimals)?;
96            sh_println!("{}", SimpleCast::to_fixed_point(&value, &decimals)?)?
97        }
98        CastSubcommand::ConcatHex { data } => {
99            if data.is_empty() {
100                let s = stdin::read(true)?;
101                sh_println!("{}", SimpleCast::concat_hex(s.split_whitespace()))?
102            } else {
103                sh_println!("{}", SimpleCast::concat_hex(data))?
104            }
105        }
106        CastSubcommand::FromBin => {
107            let hex = stdin::read_bytes(false)?;
108            sh_println!("{}", hex::encode_prefixed(hex))?
109        }
110        CastSubcommand::ToHexdata { input } => {
111            let value = stdin::unwrap_line(input)?;
112            let output = match value {
113                s if s.starts_with('@') => hex::encode(std::env::var(&s[1..])?),
114                s if s.starts_with('/') => hex::encode(fs::read(s)?),
115                s => s.split(':').map(|s| s.trim_start_matches("0x").to_lowercase()).collect(),
116            };
117            sh_println!("0x{output}")?
118        }
119        CastSubcommand::ToCheckSumAddress { address, chain_id } => {
120            let value = stdin::unwrap_line(address)?;
121            sh_println!("{}", value.to_checksum(chain_id))?
122        }
123        CastSubcommand::ToUint256 { value } => {
124            let value = stdin::unwrap_line(value)?;
125            sh_println!("{}", SimpleCast::to_uint256(&value)?)?
126        }
127        CastSubcommand::ToInt256 { value } => {
128            let value = stdin::unwrap_line(value)?;
129            sh_println!("{}", SimpleCast::to_int256(&value)?)?
130        }
131        CastSubcommand::ToUnit { value, unit } => {
132            let value = stdin::unwrap_line(value)?;
133            sh_println!("{}", SimpleCast::to_unit(&value, &unit)?)?
134        }
135        CastSubcommand::ParseUnits { value, unit } => {
136            let value = stdin::unwrap_line(value)?;
137            sh_println!("{}", SimpleCast::parse_units(&value, unit)?)?;
138        }
139        CastSubcommand::FormatUnits { value, unit } => {
140            let value = stdin::unwrap_line(value)?;
141            sh_println!("{}", SimpleCast::format_units(&value, unit)?)?;
142        }
143        CastSubcommand::FromWei { value, unit } => {
144            let value = stdin::unwrap_line(value)?;
145            sh_println!("{}", SimpleCast::from_wei(&value, &unit)?)?
146        }
147        CastSubcommand::ToWei { value, unit } => {
148            let value = stdin::unwrap_line(value)?;
149            sh_println!("{}", SimpleCast::to_wei(&value, &unit)?)?
150        }
151        CastSubcommand::FromRlp { value, as_int } => {
152            let value = stdin::unwrap_line(value)?;
153            sh_println!("{}", SimpleCast::from_rlp(value, as_int)?)?
154        }
155        CastSubcommand::ToRlp { value } => {
156            let value = stdin::unwrap_line(value)?;
157            sh_println!("{}", SimpleCast::to_rlp(&value)?)?
158        }
159        CastSubcommand::ToHex(ToBaseArgs { value, base_in }) => {
160            let value = stdin::unwrap_line(value)?;
161            sh_println!("{}", SimpleCast::to_base(&value, base_in.as_deref(), "hex")?)?
162        }
163        CastSubcommand::ToDec(ToBaseArgs { value, base_in }) => {
164            let value = stdin::unwrap_line(value)?;
165            sh_println!("{}", SimpleCast::to_base(&value, base_in.as_deref(), "dec")?)?
166        }
167        CastSubcommand::ToBase { base: ToBaseArgs { value, base_in }, base_out } => {
168            let (value, base_out) = stdin::unwrap2(value, base_out)?;
169            sh_println!("{}", SimpleCast::to_base(&value, base_in.as_deref(), &base_out)?)?
170        }
171        CastSubcommand::ToBytes32 { bytes } => {
172            let value = stdin::unwrap_line(bytes)?;
173            sh_println!("{}", SimpleCast::to_bytes32(&value)?)?
174        }
175        CastSubcommand::Pad { data, right, left: _, len } => {
176            let value = stdin::unwrap_line(data)?;
177            sh_println!("{}", SimpleCast::pad(&value, right, len)?)?
178        }
179        CastSubcommand::FormatBytes32String { string } => {
180            let value = stdin::unwrap_line(string)?;
181            sh_println!("{}", SimpleCast::format_bytes32_string(&value)?)?
182        }
183        CastSubcommand::ParseBytes32String { bytes } => {
184            let value = stdin::unwrap_line(bytes)?;
185            sh_println!("{}", SimpleCast::parse_bytes32_string(&value)?)?
186        }
187        CastSubcommand::ParseBytes32Address { bytes } => {
188            let value = stdin::unwrap_line(bytes)?;
189            sh_println!("{}", SimpleCast::parse_bytes32_address(&value)?)?
190        }
191
192        // ABI encoding & decoding
193        CastSubcommand::DecodeAbi { sig, calldata, input } => {
194            let tokens = SimpleCast::abi_decode(&sig, &calldata, input)?;
195            print_tokens(&tokens);
196        }
197        CastSubcommand::AbiEncode { sig, packed, args } => {
198            if packed {
199                sh_println!("{}", SimpleCast::abi_encode_packed(&sig, &args)?)?
200            } else {
201                sh_println!("{}", SimpleCast::abi_encode(&sig, &args)?)?
202            }
203        }
204        CastSubcommand::AbiEncodeEvent { sig, args } => {
205            let log_data = SimpleCast::abi_encode_event(&sig, &args)?;
206            for (i, topic) in log_data.topics().iter().enumerate() {
207                sh_println!("[topic{}]: {}", i, topic)?;
208            }
209            if !log_data.data.is_empty() {
210                sh_println!("[data]: {}", hex::encode_prefixed(log_data.data))?;
211            }
212        }
213        CastSubcommand::DecodeCalldata { sig, calldata, file } => {
214            let raw_hex = if let Some(file_path) = file {
215                let contents = fs::read_to_string(&file_path)?;
216                contents.trim().to_string()
217            } else {
218                calldata.unwrap()
219            };
220
221            let tokens = SimpleCast::calldata_decode(&sig, &raw_hex, true)?;
222            print_tokens(&tokens);
223        }
224        CastSubcommand::CalldataEncode { sig, args, file } => {
225            let final_args = if let Some(file_path) = file {
226                let contents = fs::read_to_string(file_path)?;
227                contents
228                    .lines()
229                    .map(str::trim)
230                    .filter(|line| !line.is_empty())
231                    .map(String::from)
232                    .collect()
233            } else {
234                args
235            };
236            sh_println!("{}", SimpleCast::calldata_encode(sig, &final_args)?)?;
237        }
238        CastSubcommand::DecodeString { data } => {
239            let tokens = SimpleCast::calldata_decode("Any(string)", &data, true)?;
240            print_tokens(&tokens);
241        }
242        CastSubcommand::DecodeEvent { sig, data } => {
243            let decoded_event = if let Some(event_sig) = sig {
244                let event = get_event(event_sig.as_str())?;
245                event.decode_log_parts(core::iter::once(event.selector()), &hex::decode(data)?)?
246            } else {
247                let data = crate::strip_0x(&data);
248                let selector = data.get(..64).unwrap_or_default();
249                let selector = selector.parse()?;
250                let identified_event =
251                    SignaturesIdentifier::new(false)?.identify_event(selector).await;
252                if let Some(event) = identified_event {
253                    let _ = sh_println!("{}", event.signature());
254                    let data = data.get(64..).unwrap_or_default();
255                    get_event(event.signature().as_str())?
256                        .decode_log_parts(core::iter::once(selector), &hex::decode(data)?)?
257                } else {
258                    eyre::bail!("No matching event signature found for selector `{selector}`")
259                }
260            };
261            print_tokens(&decoded_event.body);
262        }
263        CastSubcommand::DecodeError { sig, data } => {
264            let error = if let Some(err_sig) = sig {
265                get_error(err_sig.as_str())?
266            } else {
267                let data = crate::strip_0x(&data);
268                let selector = data.get(..8).unwrap_or_default();
269                let identified_error =
270                    SignaturesIdentifier::new(false)?.identify_error(selector.parse()?).await;
271                if let Some(error) = identified_error {
272                    let _ = sh_println!("{}", error.signature());
273                    error
274                } else {
275                    eyre::bail!("No matching error signature found for selector `{selector}`")
276                }
277            };
278            let decoded_error = error.decode_error(&hex::decode(data)?)?;
279            print_tokens(&decoded_error.body);
280        }
281        CastSubcommand::Interface(cmd) => cmd.run().await?,
282        CastSubcommand::CreationCode(cmd) => cmd.run().await?,
283        CastSubcommand::ConstructorArgs(cmd) => cmd.run().await?,
284        CastSubcommand::Artifact(cmd) => cmd.run().await?,
285        CastSubcommand::Bind(cmd) => cmd.run().await?,
286        CastSubcommand::B2EPayload(cmd) => cmd.run().await?,
287        CastSubcommand::PrettyCalldata { calldata, offline } => {
288            let calldata = stdin::unwrap_line(calldata)?;
289            sh_println!("{}", pretty_calldata(&calldata, offline).await?)?;
290        }
291        CastSubcommand::Sig { sig, optimize } => {
292            let sig = stdin::unwrap_line(sig)?;
293            match optimize {
294                Some(opt) => {
295                    sh_println!("Starting to optimize signature...")?;
296                    let start_time = Instant::now();
297                    let (selector, signature) = SimpleCast::get_selector(&sig, opt)?;
298                    sh_println!("Successfully generated in {:?}", start_time.elapsed())?;
299                    sh_println!("Selector: {selector}")?;
300                    sh_println!("Optimized signature: {signature}")?;
301                }
302                None => sh_println!("{}", SimpleCast::get_selector(&sig, 0)?.0)?,
303            }
304        }
305
306        // Blockchain & RPC queries
307        CastSubcommand::AccessList(cmd) => cmd.run().await?,
308        CastSubcommand::Age { block, rpc } => {
309            let config = rpc.load_config()?;
310            let provider = utils::get_provider(&config)?;
311            sh_println!(
312                "{} UTC",
313                Cast::new(provider).age(block.unwrap_or(BlockId::Number(Latest))).await?
314            )?
315        }
316        CastSubcommand::Balance { block, who, ether, rpc, erc20 } => {
317            let config = rpc.load_config()?;
318            let provider = utils::get_provider(&config)?;
319            let account_addr = who.resolve(&provider).await?;
320
321            match erc20 {
322                Some(token) => {
323                    let balance = IERC20::new(token, &provider)
324                        .balanceOf(account_addr)
325                        .block(block.unwrap_or_default())
326                        .call()
327                        .await?;
328
329                    sh_warn!("--erc20 flag is deprecated, use `cast erc20 balance` instead")?;
330                    sh_println!("{}", format_uint_exp(balance))?
331                }
332                None => {
333                    let value = Cast::new(&provider).balance(account_addr, block).await?;
334                    if ether {
335                        sh_println!("{}", SimpleCast::from_wei(&value.to_string(), "eth")?)?
336                    } else {
337                        sh_println!("{value}")?
338                    }
339                }
340            }
341        }
342        CastSubcommand::BaseFee { block, rpc } => {
343            let config = rpc.load_config()?;
344            let provider = utils::get_provider(&config)?;
345            sh_println!(
346                "{}",
347                Cast::new(provider).base_fee(block.unwrap_or(BlockId::Number(Latest))).await?
348            )?
349        }
350        CastSubcommand::Block { block, full, fields, raw, rpc, network } => {
351            let config = rpc.load_config()?;
352            // Can use either --raw or specify raw as a field
353            let output = if raw || fields.contains(&"raw".into()) {
354                match network {
355                    Some(NetworkVariant::Optimism) => {
356                        let provider =
357                            ProviderBuilder::<Optimism>::from_config(&config)?.build()?;
358
359                        Cast::new(&provider)
360                            .block_raw(block.unwrap_or(BlockId::Number(Latest)), full)
361                            .await?
362                    }
363                    Some(NetworkVariant::Tempo) => {
364                        let provider =
365                            ProviderBuilder::<TempoNetwork>::from_config(&config)?.build()?;
366                        Cast::new(&provider)
367                            .block_raw(block.unwrap_or(BlockId::Number(Latest)), full)
368                            .await?
369                    }
370                    // Ethereum (default) or no --raw flag
371                    _ => {
372                        let provider =
373                            ProviderBuilder::<Ethereum>::from_config(&config)?.build()?;
374                        Cast::new(&provider)
375                            .block_raw(block.unwrap_or(BlockId::Number(Latest)), full)
376                            .await?
377                    }
378                }
379            } else {
380                let provider = utils::get_provider(&config)?;
381                Cast::new(provider)
382                    .block(block.unwrap_or(BlockId::Number(Latest)), full, fields)
383                    .await?
384            };
385            sh_println!("{}", output)?
386        }
387        CastSubcommand::BlockNumber { rpc, block } => {
388            let config = rpc.load_config()?;
389            let provider = utils::get_provider(&config)?;
390            let number = match block {
391                Some(id) => {
392                    provider
393                        .get_block(id)
394                        .await?
395                        .ok_or_else(|| eyre::eyre!("block {id:?} not found"))?
396                        .header
397                        .number
398                }
399                None => Cast::new(provider).block_number().await?,
400            };
401            sh_println!("{number}")?
402        }
403        CastSubcommand::Chain { rpc } => {
404            let config = rpc.load_config()?;
405            let provider = utils::get_provider(&config)?;
406            sh_println!("{}", Cast::new(provider).chain().await?)?
407        }
408        CastSubcommand::ChainId { rpc } => {
409            let config = rpc.load_config()?;
410            let provider = utils::get_provider(&config)?;
411            sh_println!("{}", Cast::new(provider).chain_id().await?)?
412        }
413        CastSubcommand::Client { rpc } => {
414            let config = rpc.load_config()?;
415            let provider = utils::get_provider(&config)?;
416            sh_println!("{}", provider.get_client_version().await?)?
417        }
418        CastSubcommand::Code { block, who, disassemble, rpc } => {
419            let config = rpc.load_config()?;
420            let provider = utils::get_provider(&config)?;
421            let who = who.resolve(&provider).await?;
422            sh_println!("{}", Cast::new(provider).code(who, block, disassemble).await?)?
423        }
424        CastSubcommand::Codesize { block, who, rpc } => {
425            let config = rpc.load_config()?;
426            let provider = utils::get_provider(&config)?;
427            let who = who.resolve(&provider).await?;
428            sh_println!("{}", Cast::new(provider).codesize(who, block).await?)?
429        }
430        CastSubcommand::ComputeAddress { address, nonce, salt, init_code, init_code_hash, rpc } => {
431            let address = stdin::unwrap_line(address)?;
432            let computed = {
433                // For CREATE2, init_code_hash is needed to compute the address
434                if let Some(init_code_hash) = init_code_hash {
435                    address.create2(salt.unwrap_or(B256::ZERO), init_code_hash)
436                } else if let Some(init_code) = init_code {
437                    address.create2(salt.unwrap_or(B256::ZERO), keccak256(hex::decode(init_code)?))
438                } else {
439                    // For CREATE, rpc is needed to compute the address
440                    let config = rpc.load_config()?;
441                    let provider = utils::get_provider(&config)?;
442                    Cast::new(provider).compute_address(address, nonce).await?
443                }
444            };
445            sh_println!("Computed Address: {}", computed.to_checksum(None))?
446        }
447        CastSubcommand::Disassemble { bytecode } => {
448            let bytecode = stdin::unwrap_line(bytecode)?;
449            sh_println!("{}", SimpleCast::disassemble(&hex::decode(bytecode)?)?)?
450        }
451        CastSubcommand::Selectors { bytecode, resolve } => {
452            let bytecode = stdin::unwrap_line(bytecode)?;
453            let functions = SimpleCast::extract_functions(&bytecode)?;
454            let max_args_len = functions.iter().map(|r| r.1.len()).max().unwrap_or(0);
455            let max_mutability_len = functions.iter().map(|r| r.2.len()).max().unwrap_or(0);
456
457            let resolve_results = if resolve {
458                let selectors = functions
459                    .iter()
460                    .map(|&(selector, ..)| SelectorKind::Function(selector))
461                    .collect::<Vec<_>>();
462                let ds = decode_selectors(&selectors).await?;
463                ds.into_iter().map(|v| v.join("|")).collect()
464            } else {
465                vec![]
466            };
467            for (pos, (selector, arguments, state_mutability)) in functions.into_iter().enumerate()
468            {
469                if resolve {
470                    let resolved = &resolve_results[pos];
471                    sh_println!(
472                        "{selector}\t{arguments:max_args_len$}\t{state_mutability:max_mutability_len$}\t{resolved}"
473                    )?
474                } else {
475                    sh_println!("{selector}\t{arguments:max_args_len$}\t{state_mutability}")?
476                }
477            }
478        }
479        CastSubcommand::FindBlock(cmd) => cmd.run().await?,
480        CastSubcommand::GasPrice { rpc } => {
481            let config = rpc.load_config()?;
482            let provider = utils::get_provider(&config)?;
483            sh_println!("{}", Cast::new(provider).gas_price().await?)?;
484        }
485        CastSubcommand::Index { key_type, key, slot_number } => {
486            sh_println!("{}", SimpleCast::index(&key_type, &key, &slot_number)?)?;
487        }
488        CastSubcommand::IndexErc7201 { id, formula_id } => {
489            eyre::ensure!(formula_id == "erc7201", "unsupported formula ID: {formula_id}");
490            let id = stdin::unwrap_line(id)?;
491            sh_println!("{}", foundry_common::erc7201(&id))?;
492        }
493        CastSubcommand::Implementation { block, beacon, who, rpc } => {
494            let config = rpc.load_config()?;
495            let provider = utils::get_provider(&config)?;
496            let who = who.resolve(&provider).await?;
497            sh_println!("{}", Cast::new(provider).implementation(who, beacon, block).await?)?;
498        }
499        CastSubcommand::Admin { block, who, rpc } => {
500            let config = rpc.load_config()?;
501            let provider = utils::get_provider(&config)?;
502            let who = who.resolve(&provider).await?;
503            sh_println!("{}", Cast::new(provider).admin(who, block).await?)?;
504        }
505        CastSubcommand::Nonce { block, who, rpc } => {
506            let config = rpc.load_config()?;
507            let provider = utils::get_provider(&config)?;
508            let who = who.resolve(&provider).await?;
509            sh_println!("{}", Cast::new(provider).nonce(who, block).await?)?;
510        }
511        CastSubcommand::Codehash { block, who, slots, rpc } => {
512            let config = rpc.load_config()?;
513            let provider = utils::get_provider(&config)?;
514            let who = who.resolve(&provider).await?;
515            sh_println!("{}", Cast::new(provider).codehash(who, slots, block).await?)?;
516        }
517        CastSubcommand::StorageRoot { block, who, slots, rpc } => {
518            let config = rpc.load_config()?;
519            let provider = utils::get_provider(&config)?;
520            let who = who.resolve(&provider).await?;
521            sh_println!("{}", Cast::new(provider).storage_root(who, slots, block).await?)?;
522        }
523        CastSubcommand::Proof { address, slots, rpc, block } => {
524            let config = rpc.load_config()?;
525            let provider = utils::get_provider(&config)?;
526            let address = address.resolve(&provider).await?;
527            let value = provider
528                .get_proof(address, slots.into_iter().collect())
529                .block_id(block.unwrap_or_default())
530                .await?;
531            sh_println!("{}", serde_json::to_string(&value)?)?;
532        }
533        CastSubcommand::Rpc(cmd) => cmd.run().await?,
534        CastSubcommand::Storage(cmd) => cmd.run().await?,
535
536        // Calls & transactions
537        CastSubcommand::Call(cmd) => cmd.run().await?,
538        CastSubcommand::Estimate(cmd) => cmd.run().await?,
539        CastSubcommand::MakeTx(cmd) => cmd.run().await?,
540        CastSubcommand::PublishTx { raw_tx, cast_async, rpc } => {
541            let config = rpc.load_config()?;
542            let provider = utils::get_provider(&config)?;
543            let cast = Cast::new(&provider);
544            let pending_tx = cast.publish(raw_tx).await?;
545            let tx_hash = pending_tx.inner().tx_hash();
546
547            if cast_async {
548                sh_println!("{tx_hash:#x}")?;
549            } else {
550                let receipt = pending_tx.get_receipt().await?;
551                sh_println!("{}", serde_json::json!(receipt))?;
552            }
553        }
554        CastSubcommand::Receipt { tx_hash, field, cast_async, confirmations, rpc } => {
555            let config = rpc.load_config()?;
556            let provider = utils::get_provider(&config)?;
557            sh_println!(
558                "{}",
559                CastTxSender::new(provider)
560                    .receipt(tx_hash, field, confirmations, None, cast_async)
561                    .await?
562            )?
563        }
564        CastSubcommand::Run(cmd) => cmd.run().await?,
565        CastSubcommand::SendTx(cmd) => cmd.run().await?,
566        CastSubcommand::BatchMakeTx(cmd) => cmd.run().await?,
567        CastSubcommand::BatchSend(cmd) => cmd.run().await?,
568        CastSubcommand::Tx { tx_hash, from, nonce, field, raw, rpc, to_request, network } => {
569            let config = rpc.load_config()?;
570            // Can use either --raw or specify raw as a field
571            let is_raw = raw || field.as_ref().is_some_and(|f| f == "raw");
572            let output = match network {
573                Some(NetworkVariant::Optimism) => {
574                    let provider = ProviderBuilder::<Optimism>::from_config(&config)?.build()?;
575
576                    Cast::new(&provider)
577                        .transaction(tx_hash, from, nonce, field, is_raw, to_request)
578                        .await?
579                }
580                Some(NetworkVariant::Tempo) => {
581                    let provider =
582                        ProviderBuilder::<TempoNetwork>::from_config(&config)?.build()?;
583                    Cast::new(&provider)
584                        .transaction(tx_hash, from, nonce, field, is_raw, to_request)
585                        .await?
586                }
587                // Ethereum (default) or no --raw flag
588                _ => {
589                    let provider = utils::get_provider(&config)?;
590                    Cast::new(&provider)
591                        .transaction(tx_hash, from, nonce, field, is_raw, to_request)
592                        .await?
593                }
594            };
595            sh_println!("{}", output)?
596        }
597
598        // 4Byte
599        CastSubcommand::FourByte { selector } => {
600            let selector = stdin::unwrap_line(selector)?;
601            let sigs = decode_function_selector(selector).await?;
602            if sigs.is_empty() {
603                eyre::bail!("No matching function signatures found for selector `{selector}`");
604            }
605            for sig in sigs {
606                sh_println!("{sig}")?
607            }
608        }
609
610        CastSubcommand::FourByteCalldata { calldata } => {
611            let calldata = stdin::unwrap_line(calldata)?;
612
613            if calldata.len() == 10 {
614                let sigs = decode_function_selector(calldata.parse()?).await?;
615                if sigs.is_empty() {
616                    eyre::bail!("No matching function signatures found for calldata `{calldata}`");
617                }
618                for sig in sigs {
619                    sh_println!("{sig}")?
620                }
621                return Ok(());
622            }
623
624            let sigs = decode_calldata(&calldata).await?;
625            sigs.iter().enumerate().for_each(|(i, sig)| {
626                let _ = sh_println!("{}) \"{sig}\"", i + 1);
627            });
628
629            let sig = match sigs.len() {
630                0 => eyre::bail!("No signatures found"),
631                1 => sigs.first().unwrap(),
632                _ => {
633                    let i: usize = prompt!("Select a function signature by number: ")?;
634                    sigs.get(i - 1).ok_or_else(|| eyre::eyre!("Invalid signature index"))?
635                }
636            };
637
638            let tokens = SimpleCast::calldata_decode(sig, &calldata, true)?;
639            print_tokens(&tokens);
640        }
641
642        CastSubcommand::FourByteEvent { topic } => {
643            let topic = stdin::unwrap_line(topic)?;
644            let sigs = decode_event_topic(topic).await?;
645            if sigs.is_empty() {
646                eyre::bail!("No matching event signatures found for topic `{topic}`");
647            }
648            for sig in sigs {
649                sh_println!("{sig}")?
650            }
651        }
652        CastSubcommand::UploadSignature { signatures } => {
653            let signatures = stdin::unwrap_vec(signatures)?;
654            let ParsedSignatures { signatures, abis } = parse_signatures(signatures);
655            if !abis.is_empty() {
656                import_selectors(SelectorImportData::Abi(abis)).await?.describe();
657            }
658            if !signatures.is_empty() {
659                import_selectors(SelectorImportData::Raw(signatures)).await?.describe();
660            }
661        }
662
663        // ENS
664        CastSubcommand::Namehash { name } => {
665            let name = stdin::unwrap_line(name)?;
666            sh_println!("{}", namehash(&name))?
667        }
668        CastSubcommand::LookupAddress { who, rpc, verify } => {
669            let config = rpc.load_config()?;
670            let provider = utils::get_provider(&config)?;
671
672            let who = stdin::unwrap_line(who)?;
673            let name = provider.lookup_address(&who).await?;
674            if verify {
675                let address = provider.resolve_name(&name).await?;
676                eyre::ensure!(
677                    address == who,
678                    "Reverse lookup verification failed: got `{address}`, expected `{who}`"
679                );
680            }
681            sh_println!("{name}")?
682        }
683        CastSubcommand::ResolveName { who, rpc, verify } => {
684            let config = rpc.load_config()?;
685            let provider = utils::get_provider(&config)?;
686
687            let who = stdin::unwrap_line(who)?;
688            let address = provider.resolve_name(&who).await?;
689            if verify {
690                let name = provider.lookup_address(&address).await?;
691                eyre::ensure!(
692                    name == who,
693                    "Forward lookup verification failed: got `{name}`, expected `{who}`"
694                );
695            }
696            sh_println!("{address}")?
697        }
698
699        // Misc
700        CastSubcommand::Keccak { data } => {
701            let bytes = match data {
702                Some(data) => data.into_bytes(),
703                None => stdin::read_bytes(false)?,
704            };
705            match String::from_utf8(bytes) {
706                Ok(s) => {
707                    let s = SimpleCast::keccak(&s)?;
708                    sh_println!("{s}")?
709                }
710                Err(e) => {
711                    let hash = keccak256(e.as_bytes());
712                    let s = hex::encode(hash);
713                    sh_println!("0x{s}")?
714                }
715            };
716        }
717        CastSubcommand::HashMessage { message } => {
718            let message = stdin::unwrap(message, false)?;
719            sh_println!("{}", eip191_hash_message(message))?
720        }
721        CastSubcommand::SigEvent { event_string } => {
722            let event_string = stdin::unwrap_line(event_string)?;
723            let parsed_event = get_event(&event_string)?;
724            sh_println!("{:?}", parsed_event.selector())?
725        }
726        CastSubcommand::LeftShift { value, bits, base_in, base_out } => sh_println!(
727            "{}",
728            SimpleCast::left_shift(&value, &bits, base_in.as_deref(), &base_out)?
729        )?,
730        CastSubcommand::RightShift { value, bits, base_in, base_out } => sh_println!(
731            "{}",
732            SimpleCast::right_shift(&value, &bits, base_in.as_deref(), &base_out)?
733        )?,
734        CastSubcommand::Source {
735            address,
736            directory,
737            explorer_api_url,
738            explorer_url,
739            etherscan,
740            flatten,
741        } => {
742            let config = etherscan.load_config()?;
743            let chain = config.chain.unwrap_or_default();
744            let api_key = config.get_etherscan_api_key(Some(chain));
745            match (directory, flatten) {
746                (Some(dir), false) => {
747                    SimpleCast::expand_etherscan_source_to_directory(
748                        chain,
749                        address,
750                        api_key,
751                        dir,
752                        explorer_api_url,
753                        explorer_url,
754                    )
755                    .await?
756                }
757                (None, false) => sh_println!(
758                    "{}",
759                    SimpleCast::etherscan_source(
760                        chain,
761                        address,
762                        api_key,
763                        explorer_api_url,
764                        explorer_url
765                    )
766                    .await?
767                )?,
768                (dir, true) => {
769                    SimpleCast::etherscan_source_flatten(
770                        chain,
771                        address,
772                        api_key,
773                        dir,
774                        explorer_api_url,
775                        explorer_url,
776                    )
777                    .await?;
778                }
779            }
780        }
781        CastSubcommand::Create2(cmd) => {
782            cmd.run()?;
783        }
784        CastSubcommand::Wallet { command } => command.run().await?,
785        CastSubcommand::Completions { shell } => {
786            generate(shell, &mut CastArgs::command(), "cast", &mut std::io::stdout())
787        }
788        CastSubcommand::Logs(cmd) => cmd.run().await?,
789        CastSubcommand::DecodeTransaction { tx, network } => {
790            let tx = stdin::unwrap_line(tx)?;
791            let decoded_tx = match network {
792                Some(NetworkVariant::Optimism) => {
793                    SimpleCast::decode_raw_transaction::<Optimism>(&tx)?
794                }
795                Some(NetworkVariant::Tempo) => {
796                    SimpleCast::decode_raw_transaction::<TempoNetwork>(&tx)?
797                }
798                _ => SimpleCast::decode_raw_transaction::<Ethereum>(&tx)?,
799            };
800            sh_println!("{}", serde_json::to_string_pretty(&decoded_tx)?)?;
801        }
802        CastSubcommand::RecoverAuthority { auth } => {
803            let auth: SignedAuthorization = serde_json::from_str(&auth)?;
804            sh_println!("{}", auth.recover_authority()?)?;
805        }
806        CastSubcommand::TxPool { command } => command.run().await?,
807        CastSubcommand::Erc20Token { command } => command.run().await?,
808        CastSubcommand::Tip20Token { command } => command.run().await?,
809        CastSubcommand::Keychain { command } => command.run().await?,
810        CastSubcommand::DAEstimate(cmd) => {
811            cmd.run().await?;
812        }
813        CastSubcommand::Trace(cmd) => cmd.run().await?,
814    };
815
816    /// Prints slice of tokens using [`format_tokens`] or [`serialize_value_as_json`] depending
817    /// whether the shell is in JSON mode.
818    ///
819    /// This is included here to avoid a cyclic dependency between `fmt` and `common`.
820    fn print_tokens(tokens: &[DynSolValue]) {
821        if shell::is_json() {
822            let tokens: Vec<serde_json::Value> = tokens
823                .iter()
824                .cloned()
825                .map(|t| serialize_value_as_json(t, None))
826                .collect::<Result<Vec<_>>>()
827                .unwrap();
828            let _ = sh_println!("{}", serde_json::to_string_pretty(&tokens).unwrap());
829        } else {
830            let tokens = format_tokens(tokens);
831            tokens.for_each(|t| {
832                let _ = sh_println!("{t}");
833            });
834        }
835    }
836
837    Ok(())
838}