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