cast/
args.rs

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