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