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