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