cast/
args.rs

1use crate::{
2    opts::{Cast as CastArgs, CastSubcommand, ToBaseArgs},
3    traces::identifier::SignaturesIdentifier,
4    Cast, SimpleCast,
5};
6use alloy_consensus::transaction::Recovered;
7use alloy_dyn_abi::{DynSolValue, ErrorExt, EventExt};
8use alloy_primitives::{eip191_hash_message, hex, keccak256, Address, B256};
9use alloy_provider::Provider;
10use alloy_rpc_types::{BlockId, BlockNumberOrTag::Latest};
11use clap::{CommandFactory, Parser};
12use clap_complete::generate;
13use eyre::Result;
14use foundry_cli::{handler, utils, utils::LoadConfig};
15use foundry_common::{
16    abi::{get_error, get_event},
17    ens::{namehash, ProviderEnsExt},
18    fmt::{format_tokens, format_tokens_raw, format_uint_exp},
19    fs,
20    selectors::{
21        decode_calldata, decode_event_topic, decode_function_selector, decode_selectors,
22        import_selectors, parse_signatures, pretty_calldata, ParsedSignatures, SelectorImportData,
23        SelectorType,
24    },
25    shell, stdin,
26};
27use foundry_config::Config;
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
37    run_command(args)
38}
39
40/// Setup the global logger and other utilities.
41pub fn setup() -> Result<()> {
42    handler::install();
43    utils::load_dotenv();
44    utils::subscriber();
45    utils::enable_paint();
46
47    Ok(())
48}
49
50/// Run the subcommand.
51#[tokio::main]
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 } => {
114            let value = stdin::unwrap_line(address)?;
115            sh_println!("{}", value.to_checksum(None))?
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::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::DecodeCalldata { sig, calldata } => {
195            let tokens = SimpleCast::calldata_decode(&sig, &calldata, true)?;
196            print_tokens(&tokens);
197        }
198        CastSubcommand::CalldataEncode { sig, args } => {
199            sh_println!("{}", SimpleCast::calldata_encode(sig, &args)?)?;
200        }
201        CastSubcommand::DecodeString { data } => {
202            let tokens = SimpleCast::calldata_decode("Any(string)", &data, true)?;
203            print_tokens(&tokens);
204        }
205        CastSubcommand::DecodeEvent { sig, data } => {
206            let decoded_event = if let Some(event_sig) = sig {
207                get_event(event_sig.as_str())?.decode_log_parts(None, &hex::decode(data)?, false)?
208            } else {
209                let data = data.strip_prefix("0x").unwrap_or(data.as_str());
210                let selector = data.get(..64).unwrap_or_default();
211                let identified_event =
212                    SignaturesIdentifier::new(Config::foundry_cache_dir(), false)?
213                        .write()
214                        .await
215                        .identify_event(&hex::decode(selector)?)
216                        .await;
217                if let Some(event) = identified_event {
218                    let _ = sh_println!("{}", event.signature());
219                    let data = data.get(64..).unwrap_or_default();
220                    get_event(event.signature().as_str())?.decode_log_parts(
221                        None,
222                        &hex::decode(data)?,
223                        false,
224                    )?
225                } else {
226                    eyre::bail!("No matching event signature found for selector `{selector}`")
227                }
228            };
229            print_tokens(&decoded_event.body);
230        }
231        CastSubcommand::DecodeError { sig, data } => {
232            let error = if let Some(err_sig) = sig {
233                get_error(err_sig.as_str())?
234            } else {
235                let data = data.strip_prefix("0x").unwrap_or(data.as_str());
236                let selector = data.get(..8).unwrap_or_default();
237                let identified_error =
238                    SignaturesIdentifier::new(Config::foundry_cache_dir(), false)?
239                        .write()
240                        .await
241                        .identify_error(&hex::decode(selector)?)
242                        .await;
243                if let Some(error) = identified_error {
244                    let _ = sh_println!("{}", error.signature());
245                    error
246                } else {
247                    eyre::bail!("No matching error signature found for selector `{selector}`")
248                }
249            };
250            let decoded_error = error.decode_error(&hex::decode(data)?)?;
251            print_tokens(&decoded_error.body);
252        }
253        CastSubcommand::Interface(cmd) => cmd.run().await?,
254        CastSubcommand::CreationCode(cmd) => cmd.run().await?,
255        CastSubcommand::ConstructorArgs(cmd) => cmd.run().await?,
256        CastSubcommand::Artifact(cmd) => cmd.run().await?,
257        CastSubcommand::Bind(cmd) => cmd.run().await?,
258        CastSubcommand::PrettyCalldata { calldata, offline } => {
259            let calldata = stdin::unwrap_line(calldata)?;
260            sh_println!("{}", pretty_calldata(&calldata, offline).await?)?;
261        }
262        CastSubcommand::Sig { sig, optimize } => {
263            let sig = stdin::unwrap_line(sig)?;
264            match optimize {
265                Some(opt) => {
266                    sh_println!("Starting to optimize signature...")?;
267                    let start_time = Instant::now();
268                    let (selector, signature) = SimpleCast::get_selector(&sig, opt)?;
269                    sh_println!("Successfully generated in {:?}", start_time.elapsed())?;
270                    sh_println!("Selector: {selector}")?;
271                    sh_println!("Optimized signature: {signature}")?;
272                }
273                None => sh_println!("{}", SimpleCast::get_selector(&sig, 0)?.0)?,
274            }
275        }
276
277        // Blockchain & RPC queries
278        CastSubcommand::AccessList(cmd) => cmd.run().await?,
279        CastSubcommand::Age { block, rpc } => {
280            let config = rpc.load_config()?;
281            let provider = utils::get_provider(&config)?;
282            sh_println!(
283                "{} UTC",
284                Cast::new(provider).age(block.unwrap_or(BlockId::Number(Latest))).await?
285            )?
286        }
287        CastSubcommand::Balance { block, who, ether, rpc, erc20 } => {
288            let config = rpc.load_config()?;
289            let provider = utils::get_provider(&config)?;
290            let account_addr = who.resolve(&provider).await?;
291
292            match erc20 {
293                Some(token) => {
294                    let balance =
295                        Cast::new(&provider).erc20_balance(token, account_addr, block).await?;
296                    sh_println!("{}", format_uint_exp(balance))?
297                }
298                None => {
299                    let value = Cast::new(&provider).balance(account_addr, block).await?;
300                    if ether {
301                        sh_println!("{}", SimpleCast::from_wei(&value.to_string(), "eth")?)?
302                    } else {
303                        sh_println!("{value}")?
304                    }
305                }
306            }
307        }
308        CastSubcommand::BaseFee { block, rpc } => {
309            let config = rpc.load_config()?;
310            let provider = utils::get_provider(&config)?;
311            sh_println!(
312                "{}",
313                Cast::new(provider).base_fee(block.unwrap_or(BlockId::Number(Latest))).await?
314            )?
315        }
316        CastSubcommand::Block { block, full, field, rpc } => {
317            let config = rpc.load_config()?;
318            let provider = utils::get_provider(&config)?;
319            sh_println!(
320                "{}",
321                Cast::new(provider)
322                    .block(block.unwrap_or(BlockId::Number(Latest)), full, field)
323                    .await?
324            )?
325        }
326        CastSubcommand::BlockNumber { rpc, block } => {
327            let config = rpc.load_config()?;
328            let provider = utils::get_provider(&config)?;
329            let number = match block {
330                Some(id) => {
331                    provider
332                        .get_block(id)
333                        .await?
334                        .ok_or_else(|| eyre::eyre!("block {id:?} not found"))?
335                        .header
336                        .number
337                }
338                None => Cast::new(provider).block_number().await?,
339            };
340            sh_println!("{number}")?
341        }
342        CastSubcommand::Chain { rpc } => {
343            let config = rpc.load_config()?;
344            let provider = utils::get_provider(&config)?;
345            sh_println!("{}", Cast::new(provider).chain().await?)?
346        }
347        CastSubcommand::ChainId { rpc } => {
348            let config = rpc.load_config()?;
349            let provider = utils::get_provider(&config)?;
350            sh_println!("{}", Cast::new(provider).chain_id().await?)?
351        }
352        CastSubcommand::Client { rpc } => {
353            let config = rpc.load_config()?;
354            let provider = utils::get_provider(&config)?;
355            sh_println!("{}", provider.get_client_version().await?)?
356        }
357        CastSubcommand::Code { block, who, disassemble, rpc } => {
358            let config = rpc.load_config()?;
359            let provider = utils::get_provider(&config)?;
360            let who = who.resolve(&provider).await?;
361            sh_println!("{}", Cast::new(provider).code(who, block, disassemble).await?)?
362        }
363        CastSubcommand::Codesize { block, who, rpc } => {
364            let config = rpc.load_config()?;
365            let provider = utils::get_provider(&config)?;
366            let who = who.resolve(&provider).await?;
367            sh_println!("{}", Cast::new(provider).codesize(who, block).await?)?
368        }
369        CastSubcommand::ComputeAddress { address, nonce, rpc } => {
370            let config = rpc.load_config()?;
371            let provider = utils::get_provider(&config)?;
372
373            let address = stdin::unwrap_line(address)?;
374            let computed = Cast::new(provider).compute_address(address, nonce).await?;
375            sh_println!("Computed Address: {}", computed.to_checksum(None))?
376        }
377        CastSubcommand::Disassemble { bytecode } => {
378            let bytecode = stdin::unwrap_line(bytecode)?;
379            sh_println!("{}", SimpleCast::disassemble(&hex::decode(bytecode)?)?)?
380        }
381        CastSubcommand::Selectors { bytecode, resolve } => {
382            let bytecode = stdin::unwrap_line(bytecode)?;
383            let functions = SimpleCast::extract_functions(&bytecode)?;
384            let max_args_len = functions.iter().map(|r| r.1.len()).max().unwrap_or(0);
385            let max_mutability_len = functions.iter().map(|r| r.2.len()).max().unwrap_or(0);
386
387            let resolve_results = if resolve {
388                let selectors_it = functions.iter().map(|r| &r.0);
389                let ds = decode_selectors(SelectorType::Function, selectors_it).await?;
390                ds.into_iter().map(|v| v.unwrap_or_default().join("|")).collect()
391            } else {
392                vec![]
393            };
394            for (pos, (selector, arguments, state_mutability)) in functions.into_iter().enumerate()
395            {
396                if resolve {
397                    let resolved = &resolve_results[pos];
398                    sh_println!("{selector}\t{arguments:max_args_len$}\t{state_mutability:max_mutability_len$}\t{resolved}")?
399                } else {
400                    sh_println!("{selector}\t{arguments:max_args_len$}\t{state_mutability}")?
401                }
402            }
403        }
404        CastSubcommand::FindBlock(cmd) => cmd.run().await?,
405        CastSubcommand::GasPrice { rpc } => {
406            let config = rpc.load_config()?;
407            let provider = utils::get_provider(&config)?;
408            sh_println!("{}", Cast::new(provider).gas_price().await?)?;
409        }
410        CastSubcommand::Index { key_type, key, slot_number } => {
411            sh_println!("{}", SimpleCast::index(&key_type, &key, &slot_number)?)?;
412        }
413        CastSubcommand::IndexErc7201 { id, formula_id } => {
414            eyre::ensure!(formula_id == "erc7201", "unsupported formula ID: {formula_id}");
415            let id = stdin::unwrap_line(id)?;
416            sh_println!("{}", foundry_common::erc7201(&id))?;
417        }
418        CastSubcommand::Implementation { block, beacon, who, rpc } => {
419            let config = rpc.load_config()?;
420            let provider = utils::get_provider(&config)?;
421            let who = who.resolve(&provider).await?;
422            sh_println!("{}", Cast::new(provider).implementation(who, beacon, block).await?)?;
423        }
424        CastSubcommand::Admin { block, who, rpc } => {
425            let config = rpc.load_config()?;
426            let provider = utils::get_provider(&config)?;
427            let who = who.resolve(&provider).await?;
428            sh_println!("{}", Cast::new(provider).admin(who, block).await?)?;
429        }
430        CastSubcommand::Nonce { block, who, rpc } => {
431            let config = rpc.load_config()?;
432            let provider = utils::get_provider(&config)?;
433            let who = who.resolve(&provider).await?;
434            sh_println!("{}", Cast::new(provider).nonce(who, block).await?)?;
435        }
436        CastSubcommand::Codehash { block, who, slots, rpc } => {
437            let config = rpc.load_config()?;
438            let provider = utils::get_provider(&config)?;
439            let who = who.resolve(&provider).await?;
440            sh_println!("{}", Cast::new(provider).codehash(who, slots, block).await?)?;
441        }
442        CastSubcommand::StorageRoot { block, who, slots, rpc } => {
443            let config = rpc.load_config()?;
444            let provider = utils::get_provider(&config)?;
445            let who = who.resolve(&provider).await?;
446            sh_println!("{}", Cast::new(provider).storage_root(who, slots, block).await?)?;
447        }
448        CastSubcommand::Proof { address, slots, rpc, block } => {
449            let config = rpc.load_config()?;
450            let provider = utils::get_provider(&config)?;
451            let address = address.resolve(&provider).await?;
452            let value = provider
453                .get_proof(address, slots.into_iter().collect())
454                .block_id(block.unwrap_or_default())
455                .await?;
456            sh_println!("{}", serde_json::to_string(&value)?)?;
457        }
458        CastSubcommand::Rpc(cmd) => cmd.run().await?,
459        CastSubcommand::Storage(cmd) => cmd.run().await?,
460
461        // Calls & transactions
462        CastSubcommand::Call(cmd) => cmd.run().await?,
463        CastSubcommand::Estimate(cmd) => cmd.run().await?,
464        CastSubcommand::MakeTx(cmd) => cmd.run().await?,
465        CastSubcommand::PublishTx { raw_tx, cast_async, rpc } => {
466            let config = rpc.load_config()?;
467            let provider = utils::get_provider(&config)?;
468            let cast = Cast::new(&provider);
469            let pending_tx = cast.publish(raw_tx).await?;
470            let tx_hash = pending_tx.inner().tx_hash();
471
472            if cast_async {
473                sh_println!("{tx_hash:#x}")?;
474            } else {
475                let receipt = pending_tx.get_receipt().await?;
476                sh_println!("{}", serde_json::json!(receipt))?;
477            }
478        }
479        CastSubcommand::Receipt { tx_hash, field, cast_async, confirmations, rpc } => {
480            let config = rpc.load_config()?;
481            let provider = utils::get_provider(&config)?;
482            sh_println!(
483                "{}",
484                Cast::new(provider)
485                    .receipt(tx_hash, field, confirmations, None, cast_async)
486                    .await?
487            )?
488        }
489        CastSubcommand::Run(cmd) => cmd.run().await?,
490        CastSubcommand::SendTx(cmd) => cmd.run().await?,
491        CastSubcommand::Tx { tx_hash, field, raw, rpc } => {
492            let config = rpc.load_config()?;
493            let provider = utils::get_provider(&config)?;
494
495            // Can use either --raw or specify raw as a field
496            let raw = raw || field.as_ref().is_some_and(|f| f == "raw");
497
498            sh_println!("{}", Cast::new(&provider).transaction(tx_hash, field, raw).await?)?
499        }
500
501        // 4Byte
502        CastSubcommand::FourByte { selector } => {
503            let selector = stdin::unwrap_line(selector)?;
504            let sigs = decode_function_selector(&selector).await?;
505            if sigs.is_empty() {
506                eyre::bail!("No matching function signatures found for selector `{selector}`");
507            }
508            for sig in sigs {
509                sh_println!("{sig}")?
510            }
511        }
512
513        CastSubcommand::FourByteCalldata { calldata } => {
514            let calldata = stdin::unwrap_line(calldata)?;
515
516            if calldata.len() == 10 {
517                let sigs = decode_function_selector(&calldata).await?;
518                if sigs.is_empty() {
519                    eyre::bail!("No matching function signatures found for calldata `{calldata}`");
520                }
521                for sig in sigs {
522                    sh_println!("{sig}")?
523                }
524                return Ok(());
525            }
526
527            let sigs = decode_calldata(&calldata).await?;
528            sigs.iter().enumerate().for_each(|(i, sig)| {
529                let _ = sh_println!("{}) \"{sig}\"", i + 1);
530            });
531
532            let sig = match sigs.len() {
533                0 => eyre::bail!("No signatures found"),
534                1 => sigs.first().unwrap(),
535                _ => {
536                    let i: usize = prompt!("Select a function signature by number: ")?;
537                    sigs.get(i - 1).ok_or_else(|| eyre::eyre!("Invalid signature index"))?
538                }
539            };
540
541            let tokens = SimpleCast::calldata_decode(sig, &calldata, true)?;
542            print_tokens(&tokens);
543        }
544
545        CastSubcommand::FourByteEvent { topic } => {
546            let topic = stdin::unwrap_line(topic)?;
547            let sigs = decode_event_topic(&topic).await?;
548            if sigs.is_empty() {
549                eyre::bail!("No matching event signatures found for topic `{topic}`");
550            }
551            for sig in sigs {
552                sh_println!("{sig}")?
553            }
554        }
555        CastSubcommand::UploadSignature { signatures } => {
556            let signatures = stdin::unwrap_vec(signatures)?;
557            let ParsedSignatures { signatures, abis } = parse_signatures(signatures);
558            if !abis.is_empty() {
559                import_selectors(SelectorImportData::Abi(abis)).await?.describe();
560            }
561            if !signatures.is_empty() {
562                import_selectors(SelectorImportData::Raw(signatures)).await?.describe();
563            }
564        }
565
566        // ENS
567        CastSubcommand::Namehash { name } => {
568            let name = stdin::unwrap_line(name)?;
569            sh_println!("{}", namehash(&name))?
570        }
571        CastSubcommand::LookupAddress { who, rpc, verify } => {
572            let config = rpc.load_config()?;
573            let provider = utils::get_provider(&config)?;
574
575            let who = stdin::unwrap_line(who)?;
576            let name = provider.lookup_address(&who).await?;
577            if verify {
578                let address = provider.resolve_name(&name).await?;
579                eyre::ensure!(
580                    address == who,
581                    "Reverse lookup verification failed: got `{address}`, expected `{who}`"
582                );
583            }
584            sh_println!("{name}")?
585        }
586        CastSubcommand::ResolveName { who, rpc, verify } => {
587            let config = rpc.load_config()?;
588            let provider = utils::get_provider(&config)?;
589
590            let who = stdin::unwrap_line(who)?;
591            let address = provider.resolve_name(&who).await?;
592            if verify {
593                let name = provider.lookup_address(&address).await?;
594                eyre::ensure!(
595                    name == who,
596                    "Forward lookup verification failed: got `{name}`, expected `{who}`"
597                );
598            }
599            sh_println!("{address}")?
600        }
601
602        // Misc
603        CastSubcommand::Keccak { data } => {
604            let bytes = match data {
605                Some(data) => data.into_bytes(),
606                None => stdin::read_bytes(false)?,
607            };
608            match String::from_utf8(bytes) {
609                Ok(s) => {
610                    let s = SimpleCast::keccak(&s)?;
611                    sh_println!("{s}")?
612                }
613                Err(e) => {
614                    let hash = keccak256(e.as_bytes());
615                    let s = hex::encode(hash);
616                    sh_println!("0x{s}")?
617                }
618            };
619        }
620        CastSubcommand::HashMessage { message } => {
621            let message = stdin::unwrap_line(message)?;
622            sh_println!("{}", eip191_hash_message(message))?
623        }
624        CastSubcommand::SigEvent { event_string } => {
625            let event_string = stdin::unwrap_line(event_string)?;
626            let parsed_event = get_event(&event_string)?;
627            sh_println!("{:?}", parsed_event.selector())?
628        }
629        CastSubcommand::LeftShift { value, bits, base_in, base_out } => sh_println!(
630            "{}",
631            SimpleCast::left_shift(&value, &bits, base_in.as_deref(), &base_out)?
632        )?,
633        CastSubcommand::RightShift { value, bits, base_in, base_out } => sh_println!(
634            "{}",
635            SimpleCast::right_shift(&value, &bits, base_in.as_deref(), &base_out)?
636        )?,
637        CastSubcommand::Source {
638            address,
639            directory,
640            explorer_api_url,
641            explorer_url,
642            etherscan,
643            flatten,
644        } => {
645            let config = etherscan.load_config()?;
646            let chain = config.chain.unwrap_or_default();
647            let api_key = config.get_etherscan_api_key(Some(chain));
648            match (directory, flatten) {
649                (Some(dir), false) => {
650                    SimpleCast::expand_etherscan_source_to_directory(
651                        chain,
652                        address,
653                        api_key,
654                        dir,
655                        explorer_api_url,
656                        explorer_url,
657                    )
658                    .await?
659                }
660                (None, false) => sh_println!(
661                    "{}",
662                    SimpleCast::etherscan_source(
663                        chain,
664                        address,
665                        api_key,
666                        explorer_api_url,
667                        explorer_url
668                    )
669                    .await?
670                )?,
671                (dir, true) => {
672                    SimpleCast::etherscan_source_flatten(
673                        chain,
674                        address,
675                        api_key,
676                        dir,
677                        explorer_api_url,
678                        explorer_url,
679                    )
680                    .await?;
681                }
682            }
683        }
684        CastSubcommand::Create2(cmd) => {
685            cmd.run()?;
686        }
687        CastSubcommand::Wallet { command } => command.run().await?,
688        CastSubcommand::Completions { shell } => {
689            generate(shell, &mut CastArgs::command(), "cast", &mut std::io::stdout())
690        }
691        CastSubcommand::GenerateFigSpec => clap_complete::generate(
692            clap_complete_fig::Fig,
693            &mut CastArgs::command(),
694            "cast",
695            &mut std::io::stdout(),
696        ),
697        CastSubcommand::Logs(cmd) => cmd.run().await?,
698        CastSubcommand::DecodeTransaction { tx } => {
699            let tx = stdin::unwrap_line(tx)?;
700            let tx = SimpleCast::decode_raw_transaction(&tx)?;
701
702            if let Ok(signer) = tx.recover_signer() {
703                let recovered = Recovered::new_unchecked(tx, signer);
704                sh_println!("{}", serde_json::to_string_pretty(&recovered)?)?;
705            } else {
706                sh_println!("{}", serde_json::to_string_pretty(&tx)?)?;
707            }
708        }
709        CastSubcommand::DecodeEof { eof } => {
710            let eof = stdin::unwrap_line(eof)?;
711            sh_println!("{}", SimpleCast::decode_eof(&eof)?)?
712        }
713        CastSubcommand::TxPool { command } => command.run().await?,
714    };
715
716    /// Prints slice of tokens using [`format_tokens`] or [`format_tokens_raw`] depending whether
717    /// the shell is in JSON mode.
718    ///
719    /// This is included here to avoid a cyclic dependency between `fmt` and `common`.
720    fn print_tokens(tokens: &[DynSolValue]) {
721        if shell::is_json() {
722            let tokens: Vec<String> = format_tokens_raw(tokens).collect();
723            let _ = sh_println!("{}", serde_json::to_string_pretty(&tokens).unwrap());
724        } else {
725            let tokens = format_tokens(tokens);
726            tokens.for_each(|t| {
727                let _ = sh_println!("{t}");
728            });
729        }
730    }
731
732    Ok(())
733}