cast/lib.rs
1//! Cast is a Swiss Army knife for interacting with Ethereum applications from the command line.
2
3#![cfg_attr(not(test), warn(unused_crate_dependencies))]
4#![cfg_attr(docsrs, feature(doc_cfg))]
5
6#[macro_use]
7extern crate foundry_common;
8#[macro_use]
9extern crate tracing;
10
11use alloy_consensus::{
12 BlockHeader,
13 transaction::{Recovered, SignerRecoverable},
14};
15use alloy_dyn_abi::{DynSolType, DynSolValue, FunctionExt};
16use alloy_eips::Encodable2718;
17use alloy_ens::NameOrAddress;
18use alloy_json_abi::Function;
19use alloy_network::{AnyNetwork, BlockResponse, Network, TransactionBuilder};
20use alloy_primitives::{
21 Address, B256, I256, Keccak256, LogData, Selector, TxHash, U64, U256, hex,
22 utils::{ParseUnits, Unit, keccak256},
23};
24use alloy_provider::{PendingTransactionBuilder, Provider, network::eip2718::Decodable2718};
25use alloy_rlp::{Decodable, Encodable};
26use alloy_rpc_types::{
27 BlockId, BlockNumberOrTag, BlockOverrides, Filter, FilterBlockOption, Log, state::StateOverride,
28};
29use base::{Base, NumberWithBase, ToBase};
30use chrono::DateTime;
31use eyre::{Context, ContextCompat, OptionExt, Result};
32use foundry_block_explorers::Client;
33use foundry_common::{
34 abi::{coerce_value, encode_function_args, encode_function_args_packed, get_event, get_func},
35 compile::etherscan_project,
36 flatten,
37 fmt::*,
38 fs, shell,
39};
40use foundry_config::Chain;
41use foundry_evm::core::bytecode::InstIter;
42use futures::{FutureExt, StreamExt, future::Either};
43#[cfg(feature = "optimism")]
44use op_alloy_consensus as _;
45
46use rayon::prelude::*;
47use serde::Serialize;
48use std::{
49 borrow::Cow,
50 fmt::Write,
51 io,
52 marker::PhantomData,
53 path::PathBuf,
54 str::FromStr,
55 sync::atomic::{AtomicBool, Ordering},
56};
57use tokio::signal::ctrl_c;
58
59pub use foundry_evm::*;
60
61pub mod args;
62pub mod cmd;
63pub mod opts;
64pub mod tempo;
65
66pub mod base;
67pub mod call_spec;
68pub(crate) mod debug;
69pub mod errors;
70mod rlp_converter;
71pub mod tx;
72
73use rlp_converter::Item;
74
75// TODO: CastContract with common contract initializers? Same for CastProviders?
76
77pub struct Cast<P, N = AnyNetwork> {
78 provider: P,
79 _phantom: PhantomData<N>,
80}
81
82impl<P: Provider<N> + Clone + Unpin, N: Network> Cast<P, N> {
83 /// Creates a new Cast instance from the provided client
84 ///
85 /// # Example
86 ///
87 /// ```
88 /// use alloy_provider::{ProviderBuilder, RootProvider, network::AnyNetwork};
89 /// use cast::Cast;
90 ///
91 /// # async fn foo() -> eyre::Result<()> {
92 /// let provider =
93 /// ProviderBuilder::<_, _, AnyNetwork>::default().connect("http://localhost:8545").await?;
94 /// let cast = Cast::new(provider);
95 /// # Ok(())
96 /// # }
97 /// ```
98 pub const fn new(provider: P) -> Self {
99 Self { provider, _phantom: PhantomData }
100 }
101
102 /// Makes a read-only call to the specified address
103 ///
104 /// # Example
105 ///
106 /// ```
107 /// use alloy_primitives::{Address, U256, Bytes};
108 /// use alloy_rpc_types::{TransactionRequest, BlockOverrides, state::{StateOverride, AccountOverride}};
109 /// use alloy_serde::WithOtherFields;
110 /// use cast::Cast;
111 /// use alloy_provider::{RootProvider, ProviderBuilder, network::AnyNetwork};
112 /// use std::{str::FromStr, collections::HashMap};
113 /// use alloy_rpc_types::state::StateOverridesBuilder;
114 /// use alloy_sol_types::{sol, SolCall};
115 ///
116 /// sol!(
117 /// function greeting(uint256 i) public returns (string);
118 /// );
119 ///
120 /// # async fn foo() -> eyre::Result<()> {
121 /// let alloy_provider = ProviderBuilder::<_,_, AnyNetwork>::default().connect("http://localhost:8545").await?;;
122 /// let to = Address::from_str("0xB3C95ff08316fb2F2e3E52Ee82F8e7b605Aa1304")?;
123 /// let greeting = greetingCall { i: U256::from(5) }.abi_encode();
124 /// let bytes = Bytes::from_iter(greeting.iter());
125 /// let tx = TransactionRequest::default().to(to).input(bytes.into());
126 /// let tx = WithOtherFields::new(tx);
127 ///
128 /// // Create state overrides
129 /// let mut state_override = StateOverride::default();
130 /// let mut account_override = AccountOverride::default();
131 /// account_override.balance = Some(U256::from(1000));
132 /// state_override.insert(to, account_override);
133 /// let state_override_object = StateOverridesBuilder::default().build();
134 /// let block_override_object = BlockOverrides::default();
135 ///
136 /// let cast = Cast::new(alloy_provider);
137 /// let data = cast.call(&tx, None, None, Some(state_override_object), Some(block_override_object)).await?;
138 /// println!("{}", data);
139 /// # Ok(())
140 /// # }
141 /// ```
142 pub async fn call(
143 &self,
144 req: &N::TransactionRequest,
145 func: Option<&Function>,
146 block: Option<BlockId>,
147 state_override: Option<StateOverride>,
148 block_override: Option<BlockOverrides>,
149 ) -> Result<String> {
150 let mut call = self
151 .provider
152 .call(req.clone())
153 .block(block.unwrap_or_default())
154 .with_block_overrides_opt(block_override);
155 if let Some(state_override) = state_override {
156 call = call.overrides(state_override)
157 }
158
159 let res = call.await?;
160 let decoded = if let Some(func) = func {
161 // decode args into tokens
162 match func.abi_decode_output(res.as_ref()) {
163 Ok(decoded) => decoded,
164 Err(err) => {
165 // ensure the address is a contract
166 if res.is_empty() {
167 // check that the recipient is a contract that can be called
168 if let Some(addr) = req.to() {
169 if let Ok(code) = self
170 .provider
171 .get_code_at(addr)
172 .block_id(block.unwrap_or_default())
173 .await
174 && code.is_empty()
175 {
176 eyre::bail!("contract {addr:?} does not have any code")
177 }
178 } else if req.to().is_none() {
179 eyre::bail!("tx req is a contract deployment");
180 } else {
181 eyre::bail!("recipient is None");
182 }
183 }
184 return Err(err).wrap_err(
185 "could not decode output; did you specify the wrong function return data type?"
186 );
187 }
188 }
189 } else {
190 vec![]
191 };
192
193 // handle case when return type is not specified
194 Ok(if decoded.is_empty() {
195 res.to_string()
196 } else if shell::is_json() {
197 let tokens = decoded
198 .into_iter()
199 .map(|value| serialize_value_as_json(value, None))
200 .collect::<eyre::Result<Vec<_>>>()?;
201 serde_json::to_string_pretty(&tokens).unwrap()
202 } else {
203 // seth compatible user-friendly return type conversions
204 decoded.iter().map(format_token).collect::<Vec<_>>().join("\n")
205 })
206 }
207
208 /// Generates an access list for the specified transaction
209 ///
210 /// # Example
211 ///
212 /// ```
213 /// use cast::{Cast};
214 /// use alloy_primitives::{Address, U256, Bytes};
215 /// use alloy_rpc_types::{TransactionRequest};
216 /// use alloy_serde::WithOtherFields;
217 /// use alloy_provider::{RootProvider, ProviderBuilder, network::AnyNetwork};
218 /// use std::str::FromStr;
219 /// use alloy_sol_types::{sol, SolCall};
220 ///
221 /// sol!(
222 /// function greeting(uint256 i) public returns (string);
223 /// );
224 ///
225 /// # async fn foo() -> eyre::Result<()> {
226 /// let provider = ProviderBuilder::<_,_, AnyNetwork>::default().connect("http://localhost:8545").await?;;
227 /// let to = Address::from_str("0xB3C95ff08316fb2F2e3E52Ee82F8e7b605Aa1304")?;
228 /// let greeting = greetingCall { i: U256::from(5) }.abi_encode();
229 /// let bytes = Bytes::from_iter(greeting.iter());
230 /// let tx = TransactionRequest::default().to(to).input(bytes.into());
231 /// let tx = WithOtherFields::new(tx);
232 /// let cast = Cast::new(&provider);
233 /// let access_list = cast.access_list(&tx, None).await?;
234 /// println!("{}", access_list);
235 /// # Ok(())
236 /// # }
237 /// ```
238 pub async fn access_list(
239 &self,
240 req: &N::TransactionRequest,
241 block: Option<BlockId>,
242 ) -> Result<String> {
243 let access_list =
244 self.provider.create_access_list(req).block_id(block.unwrap_or_default()).await?;
245 let res = if shell::is_json() {
246 serde_json::to_string(&access_list)?
247 } else {
248 let mut s =
249 vec![format!("gas used: {}", access_list.gas_used), "access list:".to_string()];
250 for al in access_list.access_list.0 {
251 s.push(format!("- address: {}", al.address.to_checksum(None)));
252 if !al.storage_keys.is_empty() {
253 s.push(" keys:".to_string());
254 for key in al.storage_keys {
255 s.push(format!(" {key:?}"));
256 }
257 }
258 }
259 s.join("\n")
260 };
261
262 Ok(res)
263 }
264
265 pub async fn balance(&self, who: Address, block: Option<BlockId>) -> Result<U256> {
266 Ok(self.provider.get_balance(who).block_id(block.unwrap_or_default()).await?)
267 }
268
269 /// Publishes a raw transaction to the network
270 ///
271 /// # Example
272 ///
273 /// ```
274 /// use alloy_provider::{ProviderBuilder, RootProvider, network::AnyNetwork};
275 /// use cast::Cast;
276 ///
277 /// # async fn foo() -> eyre::Result<()> {
278 /// let provider =
279 /// ProviderBuilder::<_, _, AnyNetwork>::default().connect("http://localhost:8545").await?;
280 /// let cast = Cast::new(provider);
281 /// let res = cast.publish("0x1234".to_string()).await?;
282 /// println!("{:?}", res);
283 /// # Ok(())
284 /// # }
285 /// ```
286 pub async fn publish(&self, raw_tx: String) -> Result<PendingTransactionBuilder<N>> {
287 let tx = hex::decode(strip_0x(&raw_tx))?;
288 let res = self.provider.send_raw_transaction(&tx).await?;
289
290 Ok(res)
291 }
292
293 pub async fn chain_id(&self) -> Result<u64> {
294 Ok(self.provider.get_chain_id().await?)
295 }
296
297 pub async fn block_number(&self) -> Result<u64> {
298 Ok(self.provider.get_block_number().await?)
299 }
300
301 pub async fn gas_price(&self) -> Result<u128> {
302 Ok(self.provider.get_gas_price().await?)
303 }
304
305 /// # Example
306 ///
307 /// ```
308 /// use alloy_primitives::Address;
309 /// use alloy_provider::{ProviderBuilder, RootProvider, network::AnyNetwork};
310 /// use cast::Cast;
311 /// use std::str::FromStr;
312 ///
313 /// # async fn foo() -> eyre::Result<()> {
314 /// let provider =
315 /// ProviderBuilder::<_, _, AnyNetwork>::default().connect("http://localhost:8545").await?;
316 /// let cast = Cast::new(provider);
317 /// let addr = Address::from_str("0x7eD52863829AB99354F3a0503A622e82AcD5F7d3")?;
318 /// let nonce = cast.nonce(addr, None).await?;
319 /// println!("{}", nonce);
320 /// # Ok(())
321 /// # }
322 /// ```
323 pub async fn nonce(&self, who: Address, block: Option<BlockId>) -> Result<u64> {
324 Ok(self.provider.get_transaction_count(who).block_id(block.unwrap_or_default()).await?)
325 }
326
327 /// #Example
328 ///
329 /// ```
330 /// use alloy_primitives::{Address, FixedBytes};
331 /// use alloy_provider::{network::AnyNetwork, ProviderBuilder, RootProvider};
332 /// use cast::Cast;
333 /// use std::str::FromStr;
334 ///
335 /// # async fn foo() -> eyre::Result<()> {
336 /// let provider =
337 /// ProviderBuilder::<_, _, AnyNetwork>::default().connect("http://localhost:8545").await?;
338 /// let cast = Cast::new(provider);
339 /// let addr = Address::from_str("0x7eD52863829AB99354F3a0503A622e82AcD5F7d3")?;
340 /// let slots = vec![FixedBytes::from_str("0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")?];
341 /// let codehash = cast.codehash(addr, slots, None).await?;
342 /// println!("{}", codehash);
343 /// # Ok(())
344 /// # }
345 pub async fn codehash(
346 &self,
347 who: Address,
348 slots: Vec<B256>,
349 block: Option<BlockId>,
350 ) -> Result<String> {
351 Ok(self
352 .provider
353 .get_proof(who, slots)
354 .block_id(block.unwrap_or_default())
355 .await?
356 .code_hash
357 .to_string())
358 }
359
360 /// #Example
361 ///
362 /// ```
363 /// use alloy_primitives::{Address, FixedBytes};
364 /// use alloy_provider::{network::AnyNetwork, ProviderBuilder, RootProvider};
365 /// use cast::Cast;
366 /// use std::str::FromStr;
367 ///
368 /// # async fn foo() -> eyre::Result<()> {
369 /// let provider =
370 /// ProviderBuilder::<_, _, AnyNetwork>::default().connect("http://localhost:8545").await?;
371 /// let cast = Cast::new(provider);
372 /// let addr = Address::from_str("0x7eD52863829AB99354F3a0503A622e82AcD5F7d3")?;
373 /// let slots = vec![FixedBytes::from_str("0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")?];
374 /// let storage_root = cast.storage_root(addr, slots, None).await?;
375 /// println!("{}", storage_root);
376 /// # Ok(())
377 /// # }
378 pub async fn storage_root(
379 &self,
380 who: Address,
381 slots: Vec<B256>,
382 block: Option<BlockId>,
383 ) -> Result<String> {
384 Ok(self
385 .provider
386 .get_proof(who, slots)
387 .block_id(block.unwrap_or_default())
388 .await?
389 .storage_hash
390 .to_string())
391 }
392
393 /// # Example
394 ///
395 /// ```
396 /// use alloy_primitives::Address;
397 /// use alloy_provider::{ProviderBuilder, RootProvider, network::AnyNetwork};
398 /// use cast::Cast;
399 /// use std::str::FromStr;
400 ///
401 /// # async fn foo() -> eyre::Result<()> {
402 /// let provider =
403 /// ProviderBuilder::<_, _, AnyNetwork>::default().connect("http://localhost:8545").await?;
404 /// let cast = Cast::new(provider);
405 /// let addr = Address::from_str("0x7eD52863829AB99354F3a0503A622e82AcD5F7d3")?;
406 /// let implementation = cast.implementation(addr, false, None).await?;
407 /// println!("{}", implementation);
408 /// # Ok(())
409 /// # }
410 /// ```
411 pub async fn implementation(
412 &self,
413 who: Address,
414 is_beacon: bool,
415 block: Option<BlockId>,
416 ) -> Result<String> {
417 let slot = match is_beacon {
418 true => {
419 // Use the beacon slot : bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)
420 B256::from_str(
421 "0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50",
422 )?
423 }
424 false => {
425 // Use the implementation slot :
426 // bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1)
427 B256::from_str(
428 "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc",
429 )?
430 }
431 };
432
433 let value = self
434 .provider
435 .get_storage_at(who, slot.into())
436 .block_id(block.unwrap_or_default())
437 .await?;
438 let addr = Address::from_word(value.into());
439 Ok(format!("{addr:?}"))
440 }
441
442 /// # Example
443 ///
444 /// ```
445 /// use alloy_primitives::Address;
446 /// use alloy_provider::{ProviderBuilder, RootProvider, network::AnyNetwork};
447 /// use cast::Cast;
448 /// use std::str::FromStr;
449 ///
450 /// # async fn foo() -> eyre::Result<()> {
451 /// let provider =
452 /// ProviderBuilder::<_, _, AnyNetwork>::default().connect("http://localhost:8545").await?;
453 /// let cast = Cast::new(provider);
454 /// let addr = Address::from_str("0x7eD52863829AB99354F3a0503A622e82AcD5F7d3")?;
455 /// let admin = cast.admin(addr, None).await?;
456 /// println!("{}", admin);
457 /// # Ok(())
458 /// # }
459 /// ```
460 pub async fn admin(&self, who: Address, block: Option<BlockId>) -> Result<String> {
461 let slot =
462 B256::from_str("0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103")?;
463 let value = self
464 .provider
465 .get_storage_at(who, slot.into())
466 .block_id(block.unwrap_or_default())
467 .await?;
468 let addr = Address::from_word(value.into());
469 Ok(format!("{addr:?}"))
470 }
471
472 /// # Example
473 ///
474 /// ```
475 /// use alloy_primitives::{Address, U256};
476 /// use alloy_provider::{ProviderBuilder, RootProvider, network::AnyNetwork};
477 /// use cast::Cast;
478 /// use std::str::FromStr;
479 ///
480 /// # async fn foo() -> eyre::Result<()> {
481 /// let provider =
482 /// ProviderBuilder::<_, _, AnyNetwork>::default().connect("http://localhost:8545").await?;
483 /// let cast = Cast::new(provider);
484 /// let addr = Address::from_str("7eD52863829AB99354F3a0503A622e82AcD5F7d3")?;
485 /// let computed_address = cast.compute_address(addr, None).await?;
486 /// println!("Computed address for address {addr}: {computed_address}");
487 /// # Ok(())
488 /// # }
489 /// ```
490 pub async fn compute_address(&self, address: Address, nonce: Option<u64>) -> Result<Address> {
491 let unpacked = if let Some(n) = nonce { n } else { self.nonce(address, None).await? };
492 Ok(address.create(unpacked))
493 }
494
495 /// # Example
496 ///
497 /// ```
498 /// use alloy_primitives::Address;
499 /// use alloy_provider::{ProviderBuilder, RootProvider, network::AnyNetwork};
500 /// use cast::Cast;
501 /// use std::str::FromStr;
502 ///
503 /// # async fn foo() -> eyre::Result<()> {
504 /// let provider =
505 /// ProviderBuilder::<_, _, AnyNetwork>::default().connect("http://localhost:8545").await?;
506 /// let cast = Cast::new(provider);
507 /// let addr = Address::from_str("0x00000000219ab540356cbb839cbe05303d7705fa")?;
508 /// let code = cast.code(addr, None, false).await?;
509 /// println!("{}", code);
510 /// # Ok(())
511 /// # }
512 /// ```
513 pub async fn code(
514 &self,
515 who: Address,
516 block: Option<BlockId>,
517 disassemble: bool,
518 ) -> Result<String> {
519 if disassemble {
520 let code =
521 self.provider.get_code_at(who).block_id(block.unwrap_or_default()).await?.to_vec();
522 SimpleCast::disassemble(&code)
523 } else {
524 Ok(format!(
525 "{}",
526 self.provider.get_code_at(who).block_id(block.unwrap_or_default()).await?
527 ))
528 }
529 }
530
531 /// Example
532 ///
533 /// ```
534 /// use alloy_primitives::Address;
535 /// use alloy_provider::{ProviderBuilder, RootProvider, network::AnyNetwork};
536 /// use cast::Cast;
537 /// use std::str::FromStr;
538 ///
539 /// # async fn foo() -> eyre::Result<()> {
540 /// let provider =
541 /// ProviderBuilder::<_, _, AnyNetwork>::default().connect("http://localhost:8545").await?;
542 /// let cast = Cast::new(provider);
543 /// let addr = Address::from_str("0x00000000219ab540356cbb839cbe05303d7705fa")?;
544 /// let codesize = cast.codesize(addr, None).await?;
545 /// println!("{}", codesize);
546 /// # Ok(())
547 /// # }
548 /// ```
549 pub async fn codesize(&self, who: Address, block: Option<BlockId>) -> Result<String> {
550 let code =
551 self.provider.get_code_at(who).block_id(block.unwrap_or_default()).await?.to_vec();
552 Ok(code.len().to_string())
553 }
554
555 /// Perform a raw JSON-RPC request
556 ///
557 /// # Example
558 ///
559 /// ```
560 /// use alloy_provider::{ProviderBuilder, RootProvider, network::AnyNetwork};
561 /// use cast::Cast;
562 ///
563 /// # async fn foo() -> eyre::Result<()> {
564 /// let provider =
565 /// ProviderBuilder::<_, _, AnyNetwork>::default().connect("http://localhost:8545").await?;
566 /// let cast = Cast::new(provider);
567 /// let result = cast
568 /// .rpc("eth_getBalance", &["0xc94770007dda54cF92009BFF0dE90c06F603a09f", "latest"])
569 /// .await?;
570 /// println!("{}", result);
571 /// # Ok(())
572 /// # }
573 /// ```
574 pub async fn rpc<V>(&self, method: &str, params: V) -> Result<String>
575 where
576 V: alloy_json_rpc::RpcSend,
577 {
578 let res = self
579 .provider
580 .raw_request::<V, serde_json::Value>(Cow::Owned(method.to_string()), params)
581 .await?;
582 Ok(serde_json::to_string(&res)?)
583 }
584
585 /// Returns the slot
586 ///
587 /// # Example
588 ///
589 /// ```
590 /// use alloy_primitives::{Address, B256};
591 /// use alloy_provider::{ProviderBuilder, RootProvider, network::AnyNetwork};
592 /// use cast::Cast;
593 /// use std::str::FromStr;
594 ///
595 /// # async fn foo() -> eyre::Result<()> {
596 /// let provider =
597 /// ProviderBuilder::<_, _, AnyNetwork>::default().connect("http://localhost:8545").await?;
598 /// let cast = Cast::new(provider);
599 /// let addr = Address::from_str("0x00000000006c3852cbEf3e08E8dF289169EdE581")?;
600 /// let slot = B256::ZERO;
601 /// let storage = cast.storage(addr, slot, None).await?;
602 /// println!("{}", storage);
603 /// # Ok(())
604 /// # }
605 /// ```
606 pub async fn storage(
607 &self,
608 from: Address,
609 slot: B256,
610 block: Option<BlockId>,
611 ) -> Result<String> {
612 Ok(format!(
613 "{:?}",
614 B256::from(
615 self.provider
616 .get_storage_at(from, slot.into())
617 .block_id(block.unwrap_or_default())
618 .await?
619 )
620 ))
621 }
622
623 pub async fn filter_logs(&self, filter: Filter) -> Result<String> {
624 let logs = self.provider.get_logs(&filter).await?;
625 Self::format_logs(logs)
626 }
627
628 /// Retrieves logs using chunked requests to handle large block ranges.
629 ///
630 /// Automatically divides large block ranges into smaller chunks to avoid provider limits
631 /// and processes them with controlled concurrency to prevent rate limiting.
632 pub async fn filter_logs_chunked(&self, filter: Filter, chunk_size: u64) -> Result<String> {
633 let logs = self.get_logs_chunked(&filter, chunk_size).await?;
634 Self::format_logs(logs)
635 }
636
637 fn format_logs(logs: Vec<Log>) -> Result<String> {
638 let res = if shell::is_json() {
639 serde_json::to_string(&logs)?
640 } else {
641 let mut s = vec![];
642 for log in logs {
643 let pretty = log
644 .pretty()
645 .replacen('\n', "- ", 1) // Remove empty first line
646 .replace('\n', "\n "); // Indent
647 s.push(pretty);
648 }
649 s.join("\n")
650 };
651 Ok(res)
652 }
653
654 fn extract_block_range(filter: &Filter) -> (Option<u64>, Option<u64>) {
655 let FilterBlockOption::Range { from_block, to_block } = &filter.block_option else {
656 return (None, None);
657 };
658
659 (from_block.and_then(|b| b.as_number()), to_block.and_then(|b| b.as_number()))
660 }
661
662 /// Retrieves logs with automatic chunking fallback.
663 ///
664 /// First tries to fetch logs for the entire range. If that fails,
665 /// falls back to concurrent chunked requests with rate limiting.
666 async fn get_logs_chunked(&self, filter: &Filter, chunk_size: u64) -> Result<Vec<Log>>
667 where
668 P: Clone + Unpin,
669 {
670 // Try the full range first
671 if let Ok(logs) = self.provider.get_logs(filter).await {
672 return Ok(logs);
673 }
674
675 // Fallback: use concurrent chunked approach
676 self.get_logs_chunked_concurrent(filter, chunk_size).await
677 }
678
679 /// Retrieves logs using concurrent chunked requests with rate limiting.
680 ///
681 /// Divides the block range into chunks and processes them with a maximum of
682 /// 5 concurrent requests. Falls back to single-block queries if chunks fail.
683 async fn get_logs_chunked_concurrent(
684 &self,
685 filter: &Filter,
686 chunk_size: u64,
687 ) -> Result<Vec<Log>>
688 where
689 P: Clone + Unpin,
690 {
691 let (from_block, to_block) = Self::extract_block_range(filter);
692 let (Some(from), Some(to)) = (from_block, to_block) else {
693 return self.provider.get_logs(filter).await.map_err(Into::into);
694 };
695
696 if from >= to {
697 return Ok(vec![]);
698 }
699
700 // Create chunk ranges using iterator
701 let chunk_ranges: Vec<(u64, u64)> = (from..to)
702 .step_by(chunk_size as usize)
703 .map(|chunk_start| (chunk_start, (chunk_start + chunk_size).min(to)))
704 .collect();
705
706 // Process chunks with controlled concurrency using buffered stream
707 let mut all_results: Vec<(u64, Vec<Log>)> = futures::stream::iter(chunk_ranges)
708 .map(|(start_block, chunk_end)| {
709 let chunk_filter = filter.clone().from_block(start_block).to_block(chunk_end - 1);
710 let provider = self.provider.clone();
711
712 async move {
713 // Try direct chunk request with simplified fallback
714 match provider.get_logs(&chunk_filter).await {
715 Ok(logs) => (start_block, logs),
716 Err(_) => {
717 // Simple fallback: try individual blocks in this chunk
718 let mut fallback_logs = Vec::new();
719 for single_block in start_block..chunk_end {
720 let single_filter = chunk_filter
721 .clone()
722 .from_block(single_block)
723 .to_block(single_block);
724 if let Ok(logs) = provider.get_logs(&single_filter).await {
725 fallback_logs.extend(logs);
726 }
727 }
728 (start_block, fallback_logs)
729 }
730 }
731 }
732 })
733 .buffered(5) // Limit to 5 concurrent requests to avoid rate limits
734 .collect()
735 .await;
736
737 // Sort once at the end by block number and flatten
738 all_results.sort_by_key(|(block_num, _)| *block_num);
739
740 let mut all_logs = Vec::new();
741 for (_, logs) in all_results {
742 all_logs.extend(logs);
743 }
744
745 Ok(all_logs)
746 }
747
748 /// Converts a block identifier into a block number.
749 ///
750 /// If the block identifier is a block number, then this function returns the block number. If
751 /// the block identifier is a block hash, then this function returns the block number of
752 /// that block hash. If the block identifier is `None`, then this function returns `None`.
753 ///
754 /// # Example
755 ///
756 /// ```
757 /// use alloy_primitives::fixed_bytes;
758 /// use alloy_provider::{ProviderBuilder, RootProvider, network::AnyNetwork};
759 /// use alloy_rpc_types::{BlockId, BlockNumberOrTag};
760 /// use cast::Cast;
761 /// use std::{convert::TryFrom, str::FromStr};
762 ///
763 /// # async fn foo() -> eyre::Result<()> {
764 /// let provider =
765 /// ProviderBuilder::<_, _, AnyNetwork>::default().connect("http://localhost:8545").await?;
766 /// let cast = Cast::new(provider);
767 ///
768 /// let block_number = cast.convert_block_number(Some(BlockId::number(5))).await?;
769 /// assert_eq!(block_number, Some(BlockNumberOrTag::Number(5)));
770 ///
771 /// let block_number = cast
772 /// .convert_block_number(Some(BlockId::hash(fixed_bytes!(
773 /// "0000000000000000000000000000000000000000000000000000000000001234"
774 /// ))))
775 /// .await?;
776 /// assert_eq!(block_number, Some(BlockNumberOrTag::Number(4660)));
777 ///
778 /// let block_number = cast.convert_block_number(None).await?;
779 /// assert_eq!(block_number, None);
780 /// # Ok(())
781 /// # }
782 /// ```
783 pub async fn convert_block_number(
784 &self,
785 block: Option<BlockId>,
786 ) -> Result<Option<BlockNumberOrTag>, eyre::Error> {
787 match block {
788 Some(block) => match block {
789 BlockId::Number(block_number) => Ok(Some(block_number)),
790 BlockId::Hash(hash) => {
791 let block = self.provider.get_block_by_hash(hash.block_hash).await?;
792 Ok(block.map(|block| block.header().number()).map(BlockNumberOrTag::from))
793 }
794 },
795 None => Ok(None),
796 }
797 }
798
799 /// Sets up a subscription to the given filter and writes the logs to the given output.
800 ///
801 /// # Example
802 ///
803 /// ```
804 /// use alloy_primitives::Address;
805 /// use alloy_provider::{ProviderBuilder, RootProvider, network::AnyNetwork};
806 /// use alloy_rpc_types::Filter;
807 /// use alloy_transport::BoxTransport;
808 /// use cast::Cast;
809 /// use std::{io, str::FromStr};
810 ///
811 /// # async fn foo() -> eyre::Result<()> {
812 /// let provider =
813 /// ProviderBuilder::<_, _, AnyNetwork>::default().connect("wss://localhost:8545").await?;
814 /// let cast = Cast::new(provider);
815 ///
816 /// let filter =
817 /// Filter::new().address(Address::from_str("0x00000000006c3852cbEf3e08E8dF289169EdE581")?);
818 /// let mut output = io::stdout();
819 /// cast.subscribe(filter, &mut output).await?;
820 /// # Ok(())
821 /// # }
822 /// ```
823 pub async fn subscribe(&self, filter: Filter, output: &mut dyn io::Write) -> Result<()> {
824 // Initialize the subscription stream for logs
825 let mut subscription = self.provider.subscribe_logs(&filter).await?.into_stream();
826
827 // Check if a to_block is specified, if so, subscribe to blocks
828 let mut block_subscription = if filter.get_to_block().is_some() {
829 Some(self.provider.subscribe_blocks().await?.into_stream())
830 } else {
831 None
832 };
833
834 let format_json = shell::is_json();
835 let to_block_number = filter.get_to_block();
836
837 // If output should be JSON, start with an opening bracket
838 if format_json {
839 write!(output, "[")?;
840 }
841
842 let mut first = true;
843
844 loop {
845 tokio::select! {
846 // If block subscription is present, listen to it to avoid blocking indefinitely past the desired to_block
847 block = if let Some(bs) = &mut block_subscription {
848 Either::Left(bs.next().fuse())
849 } else {
850 Either::Right(futures::future::pending())
851 } => {
852 if let (Some(block), Some(to_block)) = (block, to_block_number)
853 && block.number() > to_block {
854 break;
855 }
856 },
857 // Process incoming log
858 log = subscription.next() => {
859 if format_json {
860 if !first {
861 write!(output, ",")?;
862 }
863 first = false;
864 let log_str = serde_json::to_string(&log).unwrap();
865 write!(output, "{log_str}")?;
866 } else {
867 let log_str = log.pretty()
868 .replacen('\n', "- ", 1) // Remove empty first line
869 .replace('\n', "\n "); // Indent
870 writeln!(output, "{log_str}")?;
871 }
872 },
873 // Break on cancel signal, to allow for closing JSON bracket
874 _ = ctrl_c() => {
875 break;
876 },
877 else => break,
878 }
879 }
880
881 // If output was JSON, end with a closing bracket
882 if format_json {
883 write!(output, "]")?;
884 }
885
886 Ok(())
887 }
888}
889
890impl<P: Provider<N>, N: Network> Cast<P, N>
891where
892 N::HeaderResponse: UIfmtHeaderExt,
893 N::BlockResponse: UIfmt,
894{
895 /// # Example
896 ///
897 /// ```
898 /// use alloy_provider::{ProviderBuilder, RootProvider, network::AnyNetwork};
899 /// use cast::Cast;
900 ///
901 /// # async fn foo() -> eyre::Result<()> {
902 /// let provider =
903 /// ProviderBuilder::<_, _, AnyNetwork>::default().connect("http://localhost:8545").await?;
904 /// let cast = Cast::new(provider);
905 /// let block = cast.block(5, true, vec![]).await?;
906 /// println!("{}", block);
907 /// # Ok(())
908 /// # }
909 /// ```
910 pub async fn block<B: Into<BlockId>>(
911 &self,
912 block: B,
913 full: bool,
914 fields: Vec<String>,
915 ) -> Result<String> {
916 let block = block.into();
917 if fields.contains(&"transactions".into()) && !full {
918 eyre::bail!("use --full to view transactions")
919 }
920
921 let block = self
922 .provider
923 .get_block(block)
924 .kind(full.into())
925 .await?
926 .ok_or_else(|| eyre::eyre!("block {:?} not found", block))?;
927
928 Ok(if !fields.is_empty() {
929 let mut result = String::new();
930 for field in fields {
931 result.push_str(
932 &get_pretty_block_attr::<N>(&block, &field)
933 .unwrap_or_else(|| format!("{field} is not a valid block field")),
934 );
935
936 result.push('\n');
937 }
938 result.trim_end().to_string()
939 } else if shell::is_json() {
940 serde_json::to_value(&block).unwrap().to_string()
941 } else {
942 block.pretty()
943 })
944 }
945
946 async fn block_field_as_num<B: Into<BlockId>>(&self, block: B, field: String) -> Result<U256> {
947 Self::block(
948 self,
949 block.into(),
950 false,
951 // Select only select field
952 vec![field],
953 )
954 .await?
955 .parse()
956 .map_err(Into::into)
957 }
958
959 pub async fn base_fee<B: Into<BlockId>>(&self, block: B) -> Result<U256> {
960 Self::block_field_as_num(self, block, String::from("baseFeePerGas")).await
961 }
962
963 pub async fn age<B: Into<BlockId>>(&self, block: B) -> Result<String> {
964 let timestamp_str =
965 Self::block_field_as_num(self, block, String::from("timestamp")).await?.to_string();
966 let datetime = DateTime::from_timestamp(timestamp_str.parse::<i64>().unwrap(), 0).unwrap();
967 Ok(datetime.format("%a %b %e %H:%M:%S %Y").to_string())
968 }
969
970 pub async fn timestamp<B: Into<BlockId>>(&self, block: B) -> Result<U256> {
971 Self::block_field_as_num(self, block, "timestamp".to_string()).await
972 }
973
974 pub async fn chain(&self) -> Result<&str> {
975 let genesis_hash = Self::block(
976 self,
977 0,
978 false,
979 // Select only block hash
980 vec![String::from("hash")],
981 )
982 .await?;
983
984 Ok(match &genesis_hash[..] {
985 "0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3" => {
986 match &(Self::block(self, 1920000, false, vec![String::from("hash")]).await?)[..] {
987 "0x94365e3a8c0b35089c1d1195081fe7489b528a84b22199c916180db8b28ade7f" => {
988 "etclive"
989 }
990 _ => "ethlive",
991 }
992 }
993 "0xa3c565fc15c7478862d50ccd6561e3c06b24cc509bf388941c25ea985ce32cb9" => "kovan",
994 "0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d" => "ropsten",
995 "0x7ca38a1916c42007829c55e69d3e9a73265554b586a499015373241b8a3fa48b" => {
996 "optimism-mainnet"
997 }
998 "0xc1fc15cd51159b1f1e5cbc4b82e85c1447ddfa33c52cf1d98d14fba0d6354be1" => {
999 "optimism-goerli"
1000 }
1001 "0x02adc9b449ff5f2467b8c674ece7ff9b21319d76c4ad62a67a70d552655927e5" => {
1002 "optimism-kovan"
1003 }
1004 "0x521982bd54239dc71269eefb58601762cc15cfb2978e0becb46af7962ed6bfaa" => "fraxtal",
1005 "0x910f5c4084b63fd860d0c2f9a04615115a5a991254700b39ba072290dbd77489" => {
1006 "fraxtal-testnet"
1007 }
1008 "0x7ee576b35482195fc49205cec9af72ce14f003b9ae69f6ba0faef4514be8b442" => {
1009 "arbitrum-mainnet"
1010 }
1011 "0x0cd786a2425d16f152c658316c423e6ce1181e15c3295826d7c9904cba9ce303" => "morden",
1012 "0x6341fd3daf94b748c72ced5a5b26028f2474f5f00d824504e4fa37a75767e177" => "rinkeby",
1013 "0xbf7e331f7f7c1dd2e05159666b3bf8bc7a8a3a9eb1d518969eab529dd9b88c1a" => "goerli",
1014 "0x14c2283285a88fe5fce9bf5c573ab03d6616695d717b12a127188bcacfc743c4" => "kotti",
1015 "0xa9c28ce2141b56c474f1dc504bee9b01eb1bd7d1a507580d5519d4437a97de1b" => "polygon-pos",
1016 "0x7202b2b53c5a0836e773e319d18922cc756dd67432f9a1f65352b61f4406c697" => {
1017 "polygon-pos-amoy-testnet"
1018 }
1019 "0x81005434635456a16f74ff7023fbe0bf423abbc8a8deb093ffff455c0ad3b741" => "polygon-zkevm",
1020 "0x676c1a76a6c5855a32bdf7c61977a0d1510088a4eeac1330466453b3d08b60b9" => {
1021 "polygon-zkevm-cardona-testnet"
1022 }
1023 "0x4f1dd23188aab3a76b463e4af801b52b1248ef073c648cbdc4c9333d3da79756" => "gnosis",
1024 "0xada44fd8d2ecab8b08f256af07ad3e777f17fb434f8f8e678b312f576212ba9a" => "chiado",
1025 "0x6d3c66c5357ec91d5c43af47e234a939b22557cbb552dc45bebbceeed90fbe34" => "bsctest",
1026 "0x0d21840abff46b96c84b2ac9e10e4f5cdaeb5693cb665db62a2f3b02d2d57b5b" => "bsc",
1027 "0x31ced5b9beb7f8782b014660da0cb18cc409f121f408186886e1ca3e8eeca96b" => {
1028 match &(Self::block(self, 1, false, vec![String::from("hash")]).await?)[..] {
1029 "0x738639479dc82d199365626f90caa82f7eafcfe9ed354b456fb3d294597ceb53" => {
1030 "avalanche-fuji"
1031 }
1032 _ => "avalanche",
1033 }
1034 }
1035 "0x23a2658170ba70d014ba0d0d2709f8fbfe2fa660cd868c5f282f991eecbe38ee" => "ink",
1036 "0xe5fd5cf0be56af58ad5751b401410d6b7a09d830fa459789746a3d0dd1c79834" => "ink-sepolia",
1037 _ => "unknown",
1038 })
1039 }
1040}
1041
1042impl<P: Provider<N>, N: Network> Cast<P, N>
1043where
1044 N::Header: Encodable,
1045{
1046 /// # Example
1047 ///
1048 /// ```
1049 /// use alloy_provider::{ProviderBuilder, RootProvider, network::Ethereum};
1050 /// use cast::Cast;
1051 ///
1052 /// # async fn foo() -> eyre::Result<()> {
1053 /// let provider =
1054 /// ProviderBuilder::<_, _, Ethereum>::default().connect("http://localhost:8545").await?;
1055 /// let cast = Cast::new(provider);
1056 /// let block = cast.block_raw(5, true).await?;
1057 /// println!("{}", block);
1058 /// # Ok(())
1059 /// # }
1060 /// ```
1061 pub async fn block_raw<B: Into<BlockId>>(&self, block: B, full: bool) -> Result<String> {
1062 let block_id = block.into();
1063
1064 let block = self
1065 .provider
1066 .get_block(block_id)
1067 .kind(full.into())
1068 .await?
1069 .ok_or_else(|| eyre::eyre!("block {:?} not found", block_id))?;
1070
1071 let encoded = alloy_rlp::encode(block.header().as_ref());
1072
1073 Ok(format!("0x{}", hex::encode(encoded)))
1074 }
1075}
1076
1077impl<P: Provider<N>, N: Network> Cast<P, N>
1078where
1079 N::TxEnvelope: Serialize + UIfmtSignatureExt,
1080 N::TransactionResponse: UIfmt,
1081{
1082 /// # Example
1083 ///
1084 /// ```
1085 /// use alloy_provider::{ProviderBuilder, RootProvider, network::AnyNetwork};
1086 /// use cast::Cast;
1087 ///
1088 /// # async fn foo() -> eyre::Result<()> {
1089 /// let provider =
1090 /// ProviderBuilder::<_, _, AnyNetwork>::default().connect("http://localhost:8545").await?;
1091 /// let cast = Cast::new(provider);
1092 /// let tx_hash = "0xf8d1713ea15a81482958fb7ddf884baee8d3bcc478c5f2f604e008dc788ee4fc";
1093 /// let tx = cast.transaction(Some(tx_hash.to_string()), None, None, None, false, false).await?;
1094 /// println!("{}", tx);
1095 /// # Ok(())
1096 /// # }
1097 /// ```
1098 pub async fn transaction(
1099 &self,
1100 tx_hash: Option<String>,
1101 from: Option<NameOrAddress>,
1102 nonce: Option<u64>,
1103 field: Option<String>,
1104 raw: bool,
1105 to_request: bool,
1106 ) -> Result<String> {
1107 let tx = if let Some(tx_hash) = tx_hash {
1108 let tx_hash = TxHash::from_str(&tx_hash).wrap_err("invalid tx hash")?;
1109 self.provider
1110 .get_transaction_by_hash(tx_hash)
1111 .await?
1112 .ok_or_else(|| eyre::eyre!("tx not found: {:?}", tx_hash))?
1113 } else if let Some(from) = from {
1114 // If nonce is not provided, uses 0.
1115 let nonce = U64::from(nonce.unwrap_or_default());
1116 let from = from.resolve(self.provider.root()).await?;
1117
1118 self.provider
1119 .raw_request::<_, Option<N::TransactionResponse>>(
1120 "eth_getTransactionBySenderAndNonce".into(),
1121 (from, nonce),
1122 )
1123 .await?
1124 .ok_or_else(|| {
1125 eyre::eyre!("tx not found for sender {from} and nonce {:?}", nonce.to::<u64>())
1126 })?
1127 } else {
1128 eyre::bail!("tx hash or from address is required")
1129 };
1130
1131 Ok(if raw {
1132 let encoded = tx.as_ref().encoded_2718();
1133 format!("0x{}", hex::encode(encoded))
1134 } else if let Some(ref field) = field {
1135 get_pretty_tx_attr::<N>(&tx, field.as_str())
1136 .ok_or_else(|| eyre::eyre!("invalid tx field: {}", field.clone()))?
1137 } else if shell::is_json() {
1138 // to_value first to sort json object keys
1139 serde_json::to_value(&tx)?.to_string()
1140 } else if to_request {
1141 serde_json::to_string_pretty(&Into::<N::TransactionRequest>::into(tx))?
1142 } else {
1143 tx.pretty()
1144 })
1145 }
1146}
1147
1148pub struct SimpleCast;
1149
1150impl SimpleCast {
1151 /// Returns the maximum value of the given integer type
1152 ///
1153 /// # Example
1154 ///
1155 /// ```
1156 /// use alloy_primitives::{I256, U256};
1157 /// use cast::SimpleCast;
1158 ///
1159 /// assert_eq!(SimpleCast::max_int("uint256")?, U256::MAX.to_string());
1160 /// assert_eq!(SimpleCast::max_int("int256")?, I256::MAX.to_string());
1161 /// assert_eq!(SimpleCast::max_int("int32")?, i32::MAX.to_string());
1162 /// # Ok::<(), eyre::Report>(())
1163 /// ```
1164 pub fn max_int(s: &str) -> Result<String> {
1165 Self::max_min_int::<true>(s)
1166 }
1167
1168 /// Returns the maximum value of the given integer type
1169 ///
1170 /// # Example
1171 ///
1172 /// ```
1173 /// use alloy_primitives::{I256, U256};
1174 /// use cast::SimpleCast;
1175 ///
1176 /// assert_eq!(SimpleCast::min_int("uint256")?, "0");
1177 /// assert_eq!(SimpleCast::min_int("int256")?, I256::MIN.to_string());
1178 /// assert_eq!(SimpleCast::min_int("int32")?, i32::MIN.to_string());
1179 /// # Ok::<(), eyre::Report>(())
1180 /// ```
1181 pub fn min_int(s: &str) -> Result<String> {
1182 Self::max_min_int::<false>(s)
1183 }
1184
1185 fn max_min_int<const MAX: bool>(s: &str) -> Result<String> {
1186 let ty = DynSolType::parse(s).wrap_err("Invalid type, expected `(u)int<bit size>`")?;
1187 match ty {
1188 DynSolType::Int(n) => {
1189 let mask = U256::from(1).wrapping_shl(n - 1);
1190 let max = (U256::MAX & mask).saturating_sub(U256::from(1));
1191 if MAX {
1192 Ok(max.to_string())
1193 } else {
1194 let min = I256::from_raw(max).wrapping_neg() + I256::MINUS_ONE;
1195 Ok(min.to_string())
1196 }
1197 }
1198 DynSolType::Uint(n) => {
1199 if MAX {
1200 let mut max = U256::MAX;
1201 if n < 256 {
1202 max &= U256::from(1).wrapping_shl(n).wrapping_sub(U256::from(1));
1203 }
1204 Ok(max.to_string())
1205 } else {
1206 Ok("0".to_string())
1207 }
1208 }
1209 _ => Err(eyre::eyre!("Type is not int/uint: {s}")),
1210 }
1211 }
1212
1213 /// Converts UTF-8 text input to hex
1214 ///
1215 /// # Example
1216 ///
1217 /// ```
1218 /// use cast::SimpleCast as Cast;
1219 ///
1220 /// assert_eq!(Cast::from_utf8("yo"), "0x796f");
1221 /// assert_eq!(Cast::from_utf8("Hello, World!"), "0x48656c6c6f2c20576f726c6421");
1222 /// assert_eq!(Cast::from_utf8("TurboDappTools"), "0x547572626f44617070546f6f6c73");
1223 /// # Ok::<_, eyre::Report>(())
1224 /// ```
1225 pub fn from_utf8(s: &str) -> String {
1226 hex::encode_prefixed(s)
1227 }
1228
1229 /// Converts hex input to UTF-8 text
1230 ///
1231 /// # Example
1232 ///
1233 /// ```
1234 /// use cast::SimpleCast as Cast;
1235 ///
1236 /// assert_eq!(Cast::to_utf8("0x796f")?, "yo");
1237 /// assert_eq!(Cast::to_utf8("0x48656c6c6f2c20576f726c6421")?, "Hello, World!");
1238 /// assert_eq!(Cast::to_utf8("0x547572626f44617070546f6f6c73")?, "TurboDappTools");
1239 /// assert_eq!(Cast::to_utf8("0xe4bda0e5a5bd")?, "ä½ å¥½");
1240 /// # Ok::<_, eyre::Report>(())
1241 /// ```
1242 pub fn to_utf8(s: &str) -> Result<String> {
1243 let bytes = hex::decode(s)?;
1244 Ok(String::from_utf8_lossy(bytes.as_ref()).to_string())
1245 }
1246
1247 /// Converts hex data into text data
1248 ///
1249 /// # Example
1250 ///
1251 /// ```
1252 /// use cast::SimpleCast as Cast;
1253 ///
1254 /// assert_eq!(Cast::to_ascii("0x796f")?, "yo");
1255 /// assert_eq!(Cast::to_ascii("48656c6c6f2c20576f726c6421")?, "Hello, World!");
1256 /// assert_eq!(Cast::to_ascii("0x547572626f44617070546f6f6c73")?, "TurboDappTools");
1257 /// # Ok::<_, eyre::Report>(())
1258 /// ```
1259 pub fn to_ascii(hex: &str) -> Result<String> {
1260 let bytes = hex::decode(hex)?;
1261 if !bytes.iter().all(u8::is_ascii) {
1262 return Err(eyre::eyre!("Invalid ASCII bytes"));
1263 }
1264 Ok(String::from_utf8(bytes).unwrap())
1265 }
1266
1267 /// Converts fixed point number into specified number of decimals
1268 /// ```
1269 /// use alloy_primitives::U256;
1270 /// use cast::SimpleCast as Cast;
1271 ///
1272 /// assert_eq!(Cast::from_fixed_point("10", "0")?, "10");
1273 /// assert_eq!(Cast::from_fixed_point("1.0", "1")?, "10");
1274 /// assert_eq!(Cast::from_fixed_point("0.10", "2")?, "10");
1275 /// assert_eq!(Cast::from_fixed_point("0.010", "3")?, "10");
1276 /// # Ok::<_, eyre::Report>(())
1277 /// ```
1278 pub fn from_fixed_point(value: &str, decimals: &str) -> Result<String> {
1279 let units: Unit = Unit::from_str(decimals)?;
1280 let n = ParseUnits::parse_units(value, units)?;
1281 Ok(n.to_string())
1282 }
1283
1284 /// Converts integers with specified decimals into fixed point numbers
1285 ///
1286 /// # Example
1287 ///
1288 /// ```
1289 /// use alloy_primitives::U256;
1290 /// use cast::SimpleCast as Cast;
1291 ///
1292 /// assert_eq!(Cast::to_fixed_point("10", "0")?, "10.");
1293 /// assert_eq!(Cast::to_fixed_point("10", "1")?, "1.0");
1294 /// assert_eq!(Cast::to_fixed_point("10", "2")?, "0.10");
1295 /// assert_eq!(Cast::to_fixed_point("10", "3")?, "0.010");
1296 ///
1297 /// assert_eq!(Cast::to_fixed_point("-10", "0")?, "-10.");
1298 /// assert_eq!(Cast::to_fixed_point("-10", "1")?, "-1.0");
1299 /// assert_eq!(Cast::to_fixed_point("-10", "2")?, "-0.10");
1300 /// assert_eq!(Cast::to_fixed_point("-10", "3")?, "-0.010");
1301 /// # Ok::<_, eyre::Report>(())
1302 /// ```
1303 pub fn to_fixed_point(value: &str, decimals: &str) -> Result<String> {
1304 let (sign, mut value, value_len) = {
1305 let number = NumberWithBase::parse_int(value, None)?;
1306 let sign = if number.is_nonnegative() { "" } else { "-" };
1307 let value = format!("{number:#}");
1308 let value_stripped = value.strip_prefix('-').unwrap_or(&value).to_string();
1309 let value_len = value_stripped.len();
1310 (sign, value_stripped, value_len)
1311 };
1312 let decimals = NumberWithBase::parse_uint(decimals, None)?.number().to::<usize>();
1313
1314 let value = if decimals >= value_len {
1315 // Add "0." and pad with 0s
1316 format!("0.{value:0>decimals$}")
1317 } else {
1318 // Insert decimal at -idx (i.e 1 => decimal idx = -1)
1319 value.insert(value_len - decimals, '.');
1320 value
1321 };
1322
1323 Ok(format!("{sign}{value}"))
1324 }
1325
1326 /// Concatencates hex strings
1327 ///
1328 /// # Example
1329 ///
1330 /// ```
1331 /// use cast::SimpleCast as Cast;
1332 ///
1333 /// assert_eq!(Cast::concat_hex(["0x00", "0x01"]), "0x0001");
1334 /// assert_eq!(Cast::concat_hex(["1", "2"]), "0x12");
1335 /// # Ok::<_, eyre::Report>(())
1336 /// ```
1337 pub fn concat_hex<T: AsRef<str>>(values: impl IntoIterator<Item = T>) -> String {
1338 let mut out = String::new();
1339 for s in values {
1340 let s = s.as_ref();
1341 out.push_str(strip_0x(s))
1342 }
1343 format!("0x{out}")
1344 }
1345
1346 /// Converts a number into uint256 hex string with 0x prefix
1347 ///
1348 /// # Example
1349 ///
1350 /// ```
1351 /// use cast::SimpleCast as Cast;
1352 ///
1353 /// assert_eq!(
1354 /// Cast::to_uint256("100")?,
1355 /// "0x0000000000000000000000000000000000000000000000000000000000000064"
1356 /// );
1357 /// assert_eq!(
1358 /// Cast::to_uint256("192038293923")?,
1359 /// "0x0000000000000000000000000000000000000000000000000000002cb65fd1a3"
1360 /// );
1361 /// assert_eq!(
1362 /// Cast::to_uint256(
1363 /// "115792089237316195423570985008687907853269984665640564039457584007913129639935"
1364 /// )?,
1365 /// "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
1366 /// );
1367 /// # Ok::<_, eyre::Report>(())
1368 /// ```
1369 pub fn to_uint256(value: &str) -> Result<String> {
1370 let n = NumberWithBase::parse_uint(value, None)?;
1371 Ok(format!("{n:#066x}"))
1372 }
1373
1374 /// Converts a number into int256 hex string with 0x prefix
1375 ///
1376 /// # Example
1377 ///
1378 /// ```
1379 /// use cast::SimpleCast as Cast;
1380 ///
1381 /// assert_eq!(
1382 /// Cast::to_int256("0")?,
1383 /// "0x0000000000000000000000000000000000000000000000000000000000000000"
1384 /// );
1385 /// assert_eq!(
1386 /// Cast::to_int256("100")?,
1387 /// "0x0000000000000000000000000000000000000000000000000000000000000064"
1388 /// );
1389 /// assert_eq!(
1390 /// Cast::to_int256("-100")?,
1391 /// "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9c"
1392 /// );
1393 /// assert_eq!(
1394 /// Cast::to_int256("192038293923")?,
1395 /// "0x0000000000000000000000000000000000000000000000000000002cb65fd1a3"
1396 /// );
1397 /// assert_eq!(
1398 /// Cast::to_int256("-192038293923")?,
1399 /// "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffd349a02e5d"
1400 /// );
1401 /// assert_eq!(
1402 /// Cast::to_int256(
1403 /// "57896044618658097711785492504343953926634992332820282019728792003956564819967"
1404 /// )?,
1405 /// "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
1406 /// );
1407 /// assert_eq!(
1408 /// Cast::to_int256(
1409 /// "-57896044618658097711785492504343953926634992332820282019728792003956564819968"
1410 /// )?,
1411 /// "0x8000000000000000000000000000000000000000000000000000000000000000"
1412 /// );
1413 /// # Ok::<_, eyre::Report>(())
1414 /// ```
1415 pub fn to_int256(value: &str) -> Result<String> {
1416 let n = NumberWithBase::parse_int(value, None)?;
1417 Ok(format!("{n:#066x}"))
1418 }
1419
1420 /// Converts an eth amount into a specified unit
1421 ///
1422 /// # Example
1423 ///
1424 /// ```
1425 /// use cast::SimpleCast as Cast;
1426 ///
1427 /// assert_eq!(Cast::to_unit("1 wei", "wei")?, "1");
1428 /// assert_eq!(Cast::to_unit("1", "wei")?, "1");
1429 /// assert_eq!(Cast::to_unit("1ether", "wei")?, "1000000000000000000");
1430 /// # Ok::<_, eyre::Report>(())
1431 /// ```
1432 pub fn to_unit(value: &str, unit: &str) -> Result<String> {
1433 let value = DynSolType::coerce_str(&DynSolType::Uint(256), value)?
1434 .as_uint()
1435 .wrap_err("Could not convert to uint")?
1436 .0;
1437 let unit = unit.parse().wrap_err("could not parse units")?;
1438 Ok(Self::format_unit_as_string(value, unit))
1439 }
1440
1441 /// Convert a number into a uint with arbitrary decimals.
1442 ///
1443 /// # Example
1444 ///
1445 /// ```
1446 /// use cast::SimpleCast as Cast;
1447 ///
1448 /// # fn main() -> eyre::Result<()> {
1449 /// assert_eq!(Cast::parse_units("1.0", 6)?, "1000000"); // USDC (6 decimals)
1450 /// assert_eq!(Cast::parse_units("2.5", 6)?, "2500000");
1451 /// assert_eq!(Cast::parse_units("1.0", 12)?, "1000000000000"); // 12 decimals
1452 /// assert_eq!(Cast::parse_units("1.23", 3)?, "1230"); // 3 decimals
1453 ///
1454 /// # Ok(())
1455 /// # }
1456 /// ```
1457 pub fn parse_units(value: &str, unit: u8) -> Result<String> {
1458 let unit = Unit::new(unit).ok_or_else(|| eyre::eyre!("invalid unit"))?;
1459
1460 Ok(ParseUnits::parse_units(value, unit)?.to_string())
1461 }
1462
1463 /// Format a number from smallest unit to decimal with arbitrary decimals.
1464 ///
1465 /// # Example
1466 ///
1467 /// ```
1468 /// use cast::SimpleCast as Cast;
1469 ///
1470 /// # fn main() -> eyre::Result<()> {
1471 /// assert_eq!(Cast::format_units("1000000", 6)?, "1"); // USDC (6 decimals)
1472 /// assert_eq!(Cast::format_units("2500000", 6)?, "2.500000");
1473 /// assert_eq!(Cast::format_units("1000000000000", 12)?, "1"); // 12 decimals
1474 /// assert_eq!(Cast::format_units("1230", 3)?, "1.230"); // 3 decimals
1475 ///
1476 /// # Ok(())
1477 /// # }
1478 /// ```
1479 pub fn format_units(value: &str, unit: u8) -> Result<String> {
1480 let value = NumberWithBase::parse_int(value, None)?.number();
1481 let unit = Unit::new(unit).ok_or_else(|| eyre::eyre!("invalid unit"))?;
1482 Ok(Self::format_unit_as_string(value, unit))
1483 }
1484
1485 // Helper function to format units as a string
1486 fn format_unit_as_string(value: U256, unit: Unit) -> String {
1487 let mut formatted = ParseUnits::U256(value).format_units(unit);
1488 // Trim empty fractional part.
1489 if let Some(dot) = formatted.find('.') {
1490 let fractional = &formatted[dot + 1..];
1491 if fractional.chars().all(|c: char| c == '0') {
1492 formatted = formatted[..dot].to_string();
1493 }
1494 }
1495 formatted
1496 }
1497
1498 /// Converts wei into an eth amount
1499 ///
1500 /// # Example
1501 ///
1502 /// ```
1503 /// use cast::SimpleCast as Cast;
1504 ///
1505 /// assert_eq!(Cast::from_wei("1", "gwei")?, "0.000000001");
1506 /// assert_eq!(Cast::from_wei("12340000005", "gwei")?, "12.340000005");
1507 /// assert_eq!(Cast::from_wei("10", "ether")?, "0.000000000000000010");
1508 /// assert_eq!(Cast::from_wei("100", "eth")?, "0.000000000000000100");
1509 /// assert_eq!(Cast::from_wei("17", "ether")?, "0.000000000000000017");
1510 /// # Ok::<_, eyre::Report>(())
1511 /// ```
1512 pub fn from_wei(value: &str, unit: &str) -> Result<String> {
1513 let value = NumberWithBase::parse_int(value, None)?.number();
1514 Ok(ParseUnits::U256(value).format_units(unit.parse()?))
1515 }
1516
1517 /// Converts an eth amount into wei
1518 ///
1519 /// # Example
1520 ///
1521 /// ```
1522 /// use cast::SimpleCast as Cast;
1523 ///
1524 /// assert_eq!(Cast::to_wei("100", "gwei")?, "100000000000");
1525 /// assert_eq!(Cast::to_wei("100", "eth")?, "100000000000000000000");
1526 /// assert_eq!(Cast::to_wei("1000", "ether")?, "1000000000000000000000");
1527 /// # Ok::<_, eyre::Report>(())
1528 /// ```
1529 pub fn to_wei(value: &str, unit: &str) -> Result<String> {
1530 let unit = unit.parse().wrap_err("could not parse units")?;
1531 Ok(ParseUnits::parse_units(value, unit)?.to_string())
1532 }
1533
1534 // Decodes RLP encoded data with validation for canonical integer representation
1535 ///
1536 /// # Examples
1537 /// ```
1538 /// use cast::SimpleCast as Cast;
1539 ///
1540 /// assert_eq!(Cast::from_rlp("0xc0", false).unwrap(), "[]");
1541 /// assert_eq!(Cast::from_rlp("0x0f", false).unwrap(), "\"0x0f\"");
1542 /// assert_eq!(Cast::from_rlp("0x33", false).unwrap(), "\"0x33\"");
1543 /// assert_eq!(Cast::from_rlp("0xc161", false).unwrap(), "[\"0x61\"]");
1544 /// assert_eq!(Cast::from_rlp("820002", true).is_err(), true);
1545 /// assert_eq!(Cast::from_rlp("820002", false).unwrap(), "\"0x0002\"");
1546 /// assert_eq!(Cast::from_rlp("00", true).is_err(), true);
1547 /// assert_eq!(Cast::from_rlp("00", false).unwrap(), "\"0x00\"");
1548 /// # Ok::<_, eyre::Report>(())
1549 /// ```
1550 pub fn from_rlp(value: impl AsRef<str>, as_int: bool) -> Result<String> {
1551 let bytes = hex::decode(value.as_ref()).wrap_err("Could not decode hex")?;
1552
1553 if as_int {
1554 return Ok(U256::decode(&mut &bytes[..])?.to_string());
1555 }
1556
1557 let item = Item::decode(&mut &bytes[..]).wrap_err("Could not decode rlp")?;
1558
1559 Ok(item.to_string())
1560 }
1561
1562 /// Encodes hex data or list of hex data to hexadecimal rlp
1563 ///
1564 /// # Example
1565 ///
1566 /// ```
1567 /// use cast::SimpleCast as Cast;
1568 ///
1569 /// assert_eq!(Cast::to_rlp("[]").unwrap(), "0xc0".to_string());
1570 /// assert_eq!(Cast::to_rlp("0x22").unwrap(), "0x22".to_string());
1571 /// assert_eq!(Cast::to_rlp("[\"0x61\"]",).unwrap(), "0xc161".to_string());
1572 /// assert_eq!(Cast::to_rlp("[\"0xf1\", \"f2\"]").unwrap(), "0xc481f181f2".to_string());
1573 /// # Ok::<_, eyre::Report>(())
1574 /// ```
1575 pub fn to_rlp(value: &str) -> Result<String> {
1576 let val = serde_json::from_str(value)
1577 .unwrap_or_else(|_| serde_json::Value::String(value.to_string()));
1578 let item = Item::value_to_item(&val)?;
1579 Ok(format!("0x{}", hex::encode(alloy_rlp::encode(item))))
1580 }
1581
1582 /// Converts a number of one base to another
1583 ///
1584 /// # Example
1585 ///
1586 /// ```
1587 /// use alloy_primitives::I256;
1588 /// use cast::SimpleCast as Cast;
1589 ///
1590 /// assert_eq!(Cast::to_base("100", Some("10"), "16")?, "0x64");
1591 /// assert_eq!(Cast::to_base("100", Some("10"), "oct")?, "0o144");
1592 /// assert_eq!(Cast::to_base("100", Some("10"), "binary")?, "0b1100100");
1593 ///
1594 /// assert_eq!(Cast::to_base("0xffffffffffffffff", None, "10")?, u64::MAX.to_string());
1595 /// assert_eq!(
1596 /// Cast::to_base("0xffffffffffffffffffffffffffffffff", None, "dec")?,
1597 /// u128::MAX.to_string()
1598 /// );
1599 /// // U256::MAX overflows as internally it is being parsed as I256
1600 /// assert_eq!(
1601 /// Cast::to_base(
1602 /// "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
1603 /// None,
1604 /// "decimal"
1605 /// )?,
1606 /// I256::MAX.to_string()
1607 /// );
1608 /// # Ok::<_, eyre::Report>(())
1609 /// ```
1610 pub fn to_base(value: &str, base_in: Option<&str>, base_out: &str) -> Result<String> {
1611 let base_in = Base::unwrap_or_detect(base_in, value)?;
1612 let base_out: Base = base_out.parse()?;
1613 if base_in == base_out {
1614 return Ok(value.to_string());
1615 }
1616
1617 let mut n = NumberWithBase::parse_int(value, Some(&base_in.to_string()))?;
1618 n.set_base(base_out);
1619
1620 // Use Debug fmt
1621 Ok(format!("{n:#?}"))
1622 }
1623
1624 /// Converts hexdata into bytes32 value
1625 ///
1626 /// # Example
1627 ///
1628 /// ```
1629 /// use cast::SimpleCast as Cast;
1630 ///
1631 /// let bytes = Cast::to_bytes32("1234")?;
1632 /// assert_eq!(bytes, "0x1234000000000000000000000000000000000000000000000000000000000000");
1633 ///
1634 /// let bytes = Cast::to_bytes32("0x1234")?;
1635 /// assert_eq!(bytes, "0x1234000000000000000000000000000000000000000000000000000000000000");
1636 ///
1637 /// let err = Cast::to_bytes32("0x123400000000000000000000000000000000000000000000000000000000000011").unwrap_err();
1638 /// assert_eq!(err.to_string(), "string >32 bytes");
1639 /// # Ok::<_, eyre::Report>(())
1640 pub fn to_bytes32(s: &str) -> Result<String> {
1641 let s = strip_0x(s);
1642 if s.len() > 64 {
1643 eyre::bail!("string >32 bytes");
1644 }
1645
1646 let padded = format!("{s:0<64}");
1647 Ok(padded.parse::<B256>()?.to_string())
1648 }
1649
1650 /// Encodes string into bytes32 value
1651 pub fn format_bytes32_string(s: &str) -> Result<String> {
1652 let str_bytes: &[u8] = s.as_bytes();
1653 eyre::ensure!(str_bytes.len() <= 32, "bytes32 strings must not exceed 32 bytes in length");
1654
1655 let mut bytes32: [u8; 32] = [0u8; 32];
1656 bytes32[..str_bytes.len()].copy_from_slice(str_bytes);
1657 Ok(hex::encode_prefixed(bytes32))
1658 }
1659
1660 /// Pads hex data to a specified length
1661 ///
1662 /// # Example
1663 ///
1664 /// ```
1665 /// use cast::SimpleCast as Cast;
1666 ///
1667 /// let padded = Cast::pad("abcd", true, 20)?;
1668 /// assert_eq!(padded, "0xabcd000000000000000000000000000000000000");
1669 ///
1670 /// let padded = Cast::pad("abcd", false, 20)?;
1671 /// assert_eq!(padded, "0x000000000000000000000000000000000000abcd");
1672 ///
1673 /// let padded = Cast::pad("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", true, 32)?;
1674 /// assert_eq!(padded, "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2000000000000000000000000");
1675 ///
1676 /// let padded = Cast::pad("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", false, 32)?;
1677 /// assert_eq!(padded, "0x000000000000000000000000C02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2");
1678 ///
1679 /// let err = Cast::pad("1234", false, 1).unwrap_err();
1680 /// assert_eq!(err.to_string(), "input length exceeds target length");
1681 ///
1682 /// let err = Cast::pad("foobar", false, 32).unwrap_err();
1683 /// assert_eq!(err.to_string(), "input is not a valid hex");
1684 ///
1685 /// # Ok::<_, eyre::Report>(())
1686 /// ```
1687 pub fn pad(s: &str, right: bool, len: usize) -> Result<String> {
1688 let s = strip_0x(s);
1689 let hex_len = len * 2;
1690
1691 // Validate input
1692 if s.len() > hex_len {
1693 eyre::bail!("input length exceeds target length");
1694 }
1695 if !s.chars().all(|c| c.is_ascii_hexdigit()) {
1696 eyre::bail!("input is not a valid hex");
1697 }
1698
1699 Ok(if right { format!("0x{s:0<hex_len$}") } else { format!("0x{s:0>hex_len$}") })
1700 }
1701
1702 /// Decodes string from bytes32 value
1703 pub fn parse_bytes32_string(s: &str) -> Result<String> {
1704 let bytes = hex::decode(s)?;
1705 eyre::ensure!(bytes.len() == 32, "expected 32 byte hex-string");
1706 let len = bytes.iter().take_while(|x| **x != 0).count();
1707 Ok(std::str::from_utf8(&bytes[..len])?.into())
1708 }
1709
1710 /// Decodes checksummed address from bytes32 value
1711 pub fn parse_bytes32_address(s: &str) -> Result<String> {
1712 let s = strip_0x(s);
1713 if s.len() != 64 {
1714 eyre::bail!("expected 64 byte hex-string, got {s}");
1715 }
1716
1717 let s = if let Some(stripped) = s.strip_prefix("000000000000000000000000") {
1718 stripped
1719 } else {
1720 return Err(eyre::eyre!("Not convertible to address, there are non-zero bytes"));
1721 };
1722
1723 let lowercase_address_string = format!("0x{s}");
1724 let lowercase_address = Address::from_str(&lowercase_address_string)?;
1725
1726 Ok(lowercase_address.to_checksum(None))
1727 }
1728
1729 /// Decodes abi-encoded hex input or output
1730 ///
1731 /// When `input=true`, `calldata` string MUST not be prefixed with function selector
1732 ///
1733 /// # Example
1734 ///
1735 /// ```
1736 /// use cast::SimpleCast as Cast;
1737 /// use alloy_primitives::hex;
1738 ///
1739 /// // Passing `input = false` will decode the data as the output type.
1740 /// // The input data types and the full function sig are ignored, i.e.
1741 /// // you could also pass `balanceOf()(uint256)` and it'd still work.
1742 /// let data = "0x0000000000000000000000000000000000000000000000000000000000000001";
1743 /// let sig = "balanceOf(address, uint256)(uint256)";
1744 /// let decoded = Cast::abi_decode(sig, data, false)?[0].as_uint().unwrap().0.to_string();
1745 /// assert_eq!(decoded, "1");
1746 ///
1747 /// // Passing `input = true` will decode the data with the input function signature.
1748 /// // We exclude the "prefixed" function selector from the data field (the first 4 bytes).
1749 /// let data = "0x0000000000000000000000008dbd1b711dc621e1404633da156fcc779e1c6f3e000000000000000000000000d9f3c9cc99548bf3b44a43e0a2d07399eb918adc000000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000";
1750 /// let sig = "safeTransferFrom(address, address, uint256, uint256, bytes)";
1751 /// let decoded = Cast::abi_decode(sig, data, true)?;
1752 /// let decoded = [
1753 /// decoded[0].as_address().unwrap().to_string().to_lowercase(),
1754 /// decoded[1].as_address().unwrap().to_string().to_lowercase(),
1755 /// decoded[2].as_uint().unwrap().0.to_string(),
1756 /// decoded[3].as_uint().unwrap().0.to_string(),
1757 /// hex::encode(decoded[4].as_bytes().unwrap())
1758 /// ]
1759 /// .into_iter()
1760 /// .collect::<Vec<_>>();
1761 ///
1762 /// assert_eq!(
1763 /// decoded,
1764 /// vec!["0x8dbd1b711dc621e1404633da156fcc779e1c6f3e", "0xd9f3c9cc99548bf3b44a43e0a2d07399eb918adc", "42", "1", ""]
1765 /// );
1766 /// # Ok::<_, eyre::Report>(())
1767 /// ```
1768 pub fn abi_decode(sig: &str, calldata: &str, input: bool) -> Result<Vec<DynSolValue>> {
1769 foundry_common::abi::abi_decode_calldata(sig, calldata, input, false)
1770 }
1771
1772 /// Decodes calldata-encoded hex input or output
1773 ///
1774 /// Similar to `abi_decode`, but `calldata` string MUST be prefixed with function selector
1775 ///
1776 /// # Example
1777 ///
1778 /// ```
1779 /// use cast::SimpleCast as Cast;
1780 /// use alloy_primitives::hex;
1781 ///
1782 /// // Passing `input = false` will decode the data as the output type.
1783 /// // The input data types and the full function sig are ignored, i.e.
1784 /// // you could also pass `balanceOf()(uint256)` and it'd still work.
1785 /// let data = "0x0000000000000000000000000000000000000000000000000000000000000001";
1786 /// let sig = "balanceOf(address, uint256)(uint256)";
1787 /// let decoded = Cast::calldata_decode(sig, data, false)?[0].as_uint().unwrap().0.to_string();
1788 /// assert_eq!(decoded, "1");
1789 ///
1790 /// // Passing `input = true` will decode the data with the input function signature.
1791 /// let data = "0xf242432a0000000000000000000000008dbd1b711dc621e1404633da156fcc779e1c6f3e000000000000000000000000d9f3c9cc99548bf3b44a43e0a2d07399eb918adc000000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000";
1792 /// let sig = "safeTransferFrom(address, address, uint256, uint256, bytes)";
1793 /// let decoded = Cast::calldata_decode(sig, data, true)?;
1794 /// let decoded = [
1795 /// decoded[0].as_address().unwrap().to_string().to_lowercase(),
1796 /// decoded[1].as_address().unwrap().to_string().to_lowercase(),
1797 /// decoded[2].as_uint().unwrap().0.to_string(),
1798 /// decoded[3].as_uint().unwrap().0.to_string(),
1799 /// hex::encode(decoded[4].as_bytes().unwrap()),
1800 /// ]
1801 /// .into_iter()
1802 /// .collect::<Vec<_>>();
1803 /// assert_eq!(
1804 /// decoded,
1805 /// vec!["0x8dbd1b711dc621e1404633da156fcc779e1c6f3e", "0xd9f3c9cc99548bf3b44a43e0a2d07399eb918adc", "42", "1", ""]
1806 /// );
1807 /// # Ok::<_, eyre::Report>(())
1808 /// ```
1809 pub fn calldata_decode(sig: &str, calldata: &str, input: bool) -> Result<Vec<DynSolValue>> {
1810 foundry_common::abi::abi_decode_calldata(sig, calldata, input, true)
1811 }
1812
1813 /// Performs ABI encoding based off of the function signature. Does not include
1814 /// the function selector in the result.
1815 ///
1816 /// # Example
1817 ///
1818 /// ```
1819 /// use cast::SimpleCast as Cast;
1820 ///
1821 /// assert_eq!(
1822 /// "0x0000000000000000000000000000000000000000000000000000000000000001",
1823 /// Cast::abi_encode("f(uint a)", &["1"]).unwrap().as_str()
1824 /// );
1825 /// assert_eq!(
1826 /// "0x0000000000000000000000000000000000000000000000000000000000000001",
1827 /// Cast::abi_encode("constructor(uint a)", &["1"]).unwrap().as_str()
1828 /// );
1829 /// # Ok::<_, eyre::Report>(())
1830 /// ```
1831 pub fn abi_encode(sig: &str, args: &[impl AsRef<str>]) -> Result<String> {
1832 let func = get_func(sig)?;
1833 match encode_function_args(&func, args) {
1834 Ok(res) => Ok(hex::encode_prefixed(&res[4..])),
1835 Err(e) => eyre::bail!("Could not ABI encode the function and arguments: {e}"),
1836 }
1837 }
1838
1839 /// Performs packed ABI encoding based off of the function signature or tuple.
1840 ///
1841 /// # Examplez
1842 ///
1843 /// ```
1844 /// use cast::SimpleCast as Cast;
1845 ///
1846 /// assert_eq!(
1847 /// "0x0000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000000012c00000000000000c8",
1848 /// Cast::abi_encode_packed("(uint128[] a, uint64 b)", &["[100, 300]", "200"]).unwrap().as_str()
1849 /// );
1850 ///
1851 /// assert_eq!(
1852 /// "0x8dbd1b711dc621e1404633da156fcc779e1c6f3e68656c6c6f20776f726c64",
1853 /// Cast::abi_encode_packed("foo(address a, string b)", &["0x8dbd1b711dc621e1404633da156fcc779e1c6f3e", "hello world"]).unwrap().as_str()
1854 /// );
1855 /// # Ok::<_, eyre::Report>(())
1856 /// ```
1857 pub fn abi_encode_packed(sig: &str, args: &[impl AsRef<str>]) -> Result<String> {
1858 // If the signature is a tuple, we need to prefix it to make it a function
1859 let sig =
1860 if sig.trim_start().starts_with('(') { format!("foo{sig}") } else { sig.to_string() };
1861
1862 let func = get_func(sig.as_str())?;
1863 let encoded = match encode_function_args_packed(&func, args) {
1864 Ok(res) => hex::encode(res),
1865 Err(e) => eyre::bail!("Could not ABI encode the function and arguments: {e}"),
1866 };
1867 Ok(format!("0x{encoded}"))
1868 }
1869
1870 /// Performs ABI encoding of an event to produce the topics and data.
1871 ///
1872 /// # Example
1873 ///
1874 /// ```
1875 /// use alloy_primitives::hex;
1876 /// use cast::SimpleCast as Cast;
1877 ///
1878 /// let log_data = Cast::abi_encode_event(
1879 /// "Transfer(address indexed from, address indexed to, uint256 value)",
1880 /// &[
1881 /// "0x1234567890123456789012345678901234567890",
1882 /// "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
1883 /// "1000",
1884 /// ],
1885 /// )
1886 /// .unwrap();
1887 ///
1888 /// // topic0 is the event selector
1889 /// assert_eq!(log_data.topics().len(), 3);
1890 /// assert_eq!(
1891 /// log_data.topics()[0].to_string(),
1892 /// "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
1893 /// );
1894 /// assert_eq!(
1895 /// log_data.topics()[1].to_string(),
1896 /// "0x0000000000000000000000001234567890123456789012345678901234567890"
1897 /// );
1898 /// assert_eq!(
1899 /// log_data.topics()[2].to_string(),
1900 /// "0x000000000000000000000000abcdefabcdefabcdefabcdefabcdefabcdefabcd"
1901 /// );
1902 /// assert_eq!(
1903 /// hex::encode_prefixed(log_data.data),
1904 /// "0x00000000000000000000000000000000000000000000000000000000000003e8"
1905 /// );
1906 /// # Ok::<_, eyre::Report>(())
1907 /// ```
1908 pub fn abi_encode_event(sig: &str, args: &[impl AsRef<str>]) -> Result<LogData> {
1909 let event = get_event(sig)?;
1910 let tokens = std::iter::zip(&event.inputs, args)
1911 .map(|(input, arg)| coerce_value(&input.ty, arg.as_ref()))
1912 .collect::<Result<Vec<_>>>()?;
1913
1914 let mut topics = vec![event.selector()];
1915 let mut data_tokens: Vec<u8> = Vec::new();
1916
1917 for (input, token) in event.inputs.iter().zip(tokens) {
1918 if input.indexed {
1919 let ty = DynSolType::parse(&input.ty)?;
1920 if matches!(
1921 ty,
1922 DynSolType::String
1923 | DynSolType::Bytes
1924 | DynSolType::Array(_)
1925 | DynSolType::Tuple(_)
1926 ) {
1927 // For dynamic types, hash the encoded value
1928 let encoded = token.abi_encode();
1929 let hash = keccak256(encoded);
1930 topics.push(hash);
1931 } else {
1932 // For fixed-size types, encode directly to 32 bytes
1933 let mut encoded = [0u8; 32];
1934 let token_encoded = token.abi_encode();
1935 if token_encoded.len() <= 32 {
1936 let start = 32 - token_encoded.len();
1937 encoded[start..].copy_from_slice(&token_encoded);
1938 }
1939 topics.push(B256::from(encoded));
1940 }
1941 } else {
1942 // Non-indexed parameters go into data
1943 data_tokens.extend_from_slice(&token.abi_encode());
1944 }
1945 }
1946
1947 Ok(LogData::new_unchecked(topics, data_tokens.into()))
1948 }
1949
1950 /// Performs ABI encoding to produce the hexadecimal calldata with the given arguments.
1951 ///
1952 /// # Example
1953 ///
1954 /// ```
1955 /// use cast::SimpleCast as Cast;
1956 ///
1957 /// assert_eq!(
1958 /// "0xb3de648b0000000000000000000000000000000000000000000000000000000000000001",
1959 /// Cast::calldata_encode("f(uint256 a)", &["1"]).unwrap().as_str()
1960 /// );
1961 /// # Ok::<_, eyre::Report>(())
1962 /// ```
1963 pub fn calldata_encode(sig: impl AsRef<str>, args: &[impl AsRef<str>]) -> Result<String> {
1964 let func = get_func(sig.as_ref())?;
1965 let calldata = encode_function_args(&func, args)?;
1966 Ok(hex::encode_prefixed(calldata))
1967 }
1968
1969 /// Returns the slot number for a given mapping key and slot.
1970 ///
1971 /// Given `mapping(k => v) m`, for a key `k` the slot number of its associated `v` is
1972 /// `keccak256(concat(h(k), p))`, where `h` is the padding function for `k`'s type, and `p`
1973 /// is slot number of the mapping `m`.
1974 ///
1975 /// See [the Solidity documentation](https://docs.soliditylang.org/en/latest/internals/layout_in_storage.html#mappings-and-dynamic-arrays)
1976 /// for more details.
1977 ///
1978 /// # Example
1979 ///
1980 /// ```
1981 /// # use cast::SimpleCast as Cast;
1982 ///
1983 /// // Value types.
1984 /// assert_eq!(
1985 /// Cast::index("address", "0xD0074F4E6490ae3f888d1d4f7E3E43326bD3f0f5", "2").unwrap().as_str(),
1986 /// "0x9525a448a9000053a4d151336329d6563b7e80b24f8e628e95527f218e8ab5fb"
1987 /// );
1988 /// assert_eq!(
1989 /// Cast::index("uint256", "42", "6").unwrap().as_str(),
1990 /// "0xfc808b0f31a1e6b9cf25ff6289feae9b51017b392cc8e25620a94a38dcdafcc1"
1991 /// );
1992 ///
1993 /// // Strings and byte arrays.
1994 /// assert_eq!(
1995 /// Cast::index("string", "hello", "1").unwrap().as_str(),
1996 /// "0x8404bb4d805e9ca2bd5dd5c43a107e935c8ec393caa7851b353b3192cd5379ae"
1997 /// );
1998 /// # Ok::<_, eyre::Report>(())
1999 /// ```
2000 pub fn index(key_type: &str, key: &str, slot_number: &str) -> Result<String> {
2001 let mut hasher = Keccak256::new();
2002
2003 let k_ty = DynSolType::parse(key_type).wrap_err("Could not parse type")?;
2004 let k = k_ty.coerce_str(key).wrap_err("Could not parse value")?;
2005 match k_ty {
2006 // For value types, `h` pads the value to 32 bytes in the same way as when storing the
2007 // value in memory.
2008 DynSolType::Bool
2009 | DynSolType::Int(_)
2010 | DynSolType::Uint(_)
2011 | DynSolType::FixedBytes(_)
2012 | DynSolType::Address
2013 | DynSolType::Function => hasher.update(k.as_word().unwrap()),
2014
2015 // For strings and byte arrays, `h(k)` is just the unpadded data.
2016 DynSolType::String | DynSolType::Bytes => hasher.update(k.as_packed_seq().unwrap()),
2017
2018 DynSolType::Array(..)
2019 | DynSolType::FixedArray(..)
2020 | DynSolType::Tuple(..)
2021 | DynSolType::CustomStruct { .. } => {
2022 eyre::bail!("Type `{k_ty}` is not supported as a mapping key")
2023 }
2024 }
2025
2026 let p = DynSolType::Uint(256)
2027 .coerce_str(slot_number)
2028 .wrap_err("Could not parse slot number")?;
2029 let p = p.as_word().unwrap();
2030 hasher.update(p);
2031
2032 let location = hasher.finalize();
2033 Ok(location.to_string())
2034 }
2035
2036 /// Keccak-256 hashes arbitrary data
2037 ///
2038 /// # Example
2039 ///
2040 /// ```
2041 /// use cast::SimpleCast as Cast;
2042 ///
2043 /// assert_eq!(
2044 /// Cast::keccak("foo")?,
2045 /// "0x41b1a0649752af1b28b3dc29a1556eee781e4a4c3a1f7f53f90fa834de098c4d"
2046 /// );
2047 /// assert_eq!(
2048 /// Cast::keccak("123abc")?,
2049 /// "0xb1f1c74a1ba56f07a892ea1110a39349d40f66ca01d245e704621033cb7046a4"
2050 /// );
2051 /// assert_eq!(
2052 /// Cast::keccak("0x12")?,
2053 /// "0x5fa2358263196dbbf23d1ca7a509451f7a2f64c15837bfbb81298b1e3e24e4fa"
2054 /// );
2055 /// assert_eq!(
2056 /// Cast::keccak("12")?,
2057 /// "0x7f8b6b088b6d74c2852fc86c796dca07b44eed6fb3daf5e6b59f7c364db14528"
2058 /// );
2059 /// # Ok::<_, eyre::Report>(())
2060 /// ```
2061 pub fn keccak(data: &str) -> Result<String> {
2062 // Hex-decode if data starts with 0x.
2063 let hash = if data.starts_with("0x") {
2064 keccak256(hex::decode(data.trim_end())?)
2065 } else {
2066 keccak256(data)
2067 };
2068 Ok(hash.to_string())
2069 }
2070
2071 /// Performs the left shift operation (<<) on a number
2072 ///
2073 /// # Example
2074 ///
2075 /// ```
2076 /// use cast::SimpleCast as Cast;
2077 ///
2078 /// assert_eq!(Cast::left_shift("16", "10", Some("10"), "hex")?, "0x4000");
2079 /// assert_eq!(Cast::left_shift("255", "16", Some("dec"), "hex")?, "0xff0000");
2080 /// assert_eq!(Cast::left_shift("0xff", "16", None, "hex")?, "0xff0000");
2081 /// # Ok::<_, eyre::Report>(())
2082 /// ```
2083 pub fn left_shift(
2084 value: &str,
2085 bits: &str,
2086 base_in: Option<&str>,
2087 base_out: &str,
2088 ) -> Result<String> {
2089 let base_out: Base = base_out.parse()?;
2090 let value = NumberWithBase::parse_uint(value, base_in)?;
2091 let bits = NumberWithBase::parse_uint(bits, None)?;
2092
2093 let res = value.number() << bits.number();
2094
2095 Ok(res.to_base(base_out, true)?)
2096 }
2097
2098 /// Performs the right shift operation (>>) on a number
2099 ///
2100 /// # Example
2101 ///
2102 /// ```
2103 /// use cast::SimpleCast as Cast;
2104 ///
2105 /// assert_eq!(Cast::right_shift("0x4000", "10", None, "dec")?, "16");
2106 /// assert_eq!(Cast::right_shift("16711680", "16", Some("10"), "hex")?, "0xff");
2107 /// assert_eq!(Cast::right_shift("0xff0000", "16", None, "hex")?, "0xff");
2108 /// # Ok::<(), eyre::Report>(())
2109 /// ```
2110 pub fn right_shift(
2111 value: &str,
2112 bits: &str,
2113 base_in: Option<&str>,
2114 base_out: &str,
2115 ) -> Result<String> {
2116 let base_out: Base = base_out.parse()?;
2117 let value = NumberWithBase::parse_uint(value, base_in)?;
2118 let bits = NumberWithBase::parse_uint(bits, None)?;
2119
2120 let res = value.number().wrapping_shr(bits.number().saturating_to());
2121
2122 Ok(res.to_base(base_out, true)?)
2123 }
2124
2125 /// Fetches source code of verified contracts from etherscan.
2126 ///
2127 /// # Example
2128 ///
2129 /// ```
2130 /// # use cast::SimpleCast as Cast;
2131 /// # use foundry_config::NamedChain;
2132 /// # async fn foo() -> eyre::Result<()> {
2133 /// assert_eq!(
2134 /// "/*
2135 /// - Bytecode Verification performed was compared on second iteration -
2136 /// This file is part of the DAO.....",
2137 /// Cast::etherscan_source(
2138 /// NamedChain::Mainnet.into(),
2139 /// "0xBB9bc244D798123fDe783fCc1C72d3Bb8C189413".to_string(),
2140 /// Some("<etherscan_api_key>".to_string()),
2141 /// None,
2142 /// None
2143 /// )
2144 /// .await
2145 /// .unwrap()
2146 /// .as_str()
2147 /// );
2148 /// # Ok(())
2149 /// # }
2150 /// ```
2151 pub async fn etherscan_source(
2152 chain: Chain,
2153 contract_address: String,
2154 etherscan_api_key: Option<String>,
2155 explorer_api_url: Option<String>,
2156 explorer_url: Option<String>,
2157 ) -> Result<String> {
2158 let client = explorer_client(chain, etherscan_api_key, explorer_api_url, explorer_url)?;
2159 let metadata = client.contract_source_code(contract_address.parse()?).await?;
2160 Ok(metadata.source_code())
2161 }
2162
2163 /// Fetches the source code of verified contracts from etherscan and expands the resulting
2164 /// files to a directory for easy perusal.
2165 ///
2166 /// # Example
2167 ///
2168 /// ```
2169 /// # use cast::SimpleCast as Cast;
2170 /// # use foundry_config::NamedChain;
2171 /// # use std::path::PathBuf;
2172 /// # async fn expand() -> eyre::Result<()> {
2173 /// Cast::expand_etherscan_source_to_directory(
2174 /// NamedChain::Mainnet.into(),
2175 /// "0xBB9bc244D798123fDe783fCc1C72d3Bb8C189413".to_string(),
2176 /// Some("<etherscan_api_key>".to_string()),
2177 /// PathBuf::from("output_dir"),
2178 /// None,
2179 /// None,
2180 /// )
2181 /// .await?;
2182 /// # Ok(())
2183 /// # }
2184 /// ```
2185 pub async fn expand_etherscan_source_to_directory(
2186 chain: Chain,
2187 contract_address: String,
2188 etherscan_api_key: Option<String>,
2189 output_directory: PathBuf,
2190 explorer_api_url: Option<String>,
2191 explorer_url: Option<String>,
2192 ) -> eyre::Result<()> {
2193 let client = explorer_client(chain, etherscan_api_key, explorer_api_url, explorer_url)?;
2194 let meta = client.contract_source_code(contract_address.parse()?).await?;
2195 let source_tree = meta.source_tree();
2196 source_tree.write_to(&output_directory)?;
2197 Ok(())
2198 }
2199
2200 /// Fetches the source code of verified contracts from etherscan, flattens it and writes it to
2201 /// the given path or stdout.
2202 pub async fn etherscan_source_flatten(
2203 chain: Chain,
2204 contract_address: String,
2205 etherscan_api_key: Option<String>,
2206 output_path: Option<PathBuf>,
2207 explorer_api_url: Option<String>,
2208 explorer_url: Option<String>,
2209 ) -> Result<()> {
2210 let client = explorer_client(chain, etherscan_api_key, explorer_api_url, explorer_url)?;
2211 let metadata = client.contract_source_code(contract_address.parse()?).await?;
2212 let Some(metadata) = metadata.items.first() else {
2213 eyre::bail!("Empty contract source code")
2214 };
2215
2216 let tmp = tempfile::tempdir()?;
2217 let project = etherscan_project(metadata, tmp.path())?;
2218 let target_path = project.find_contract_path(&metadata.contract_name)?;
2219
2220 let flattened = flatten(project, &target_path)?;
2221
2222 if let Some(path) = output_path {
2223 fs::create_dir_all(path.parent().unwrap())?;
2224 fs::write(&path, flattened)?;
2225 sh_println!("Flattened file written at {}", path.display())?
2226 } else {
2227 sh_println!("{flattened}")?
2228 }
2229
2230 Ok(())
2231 }
2232
2233 /// Disassembles hex encoded bytecode into individual / human readable opcodes
2234 ///
2235 /// # Example
2236 ///
2237 /// ```
2238 /// use alloy_primitives::hex;
2239 /// use cast::SimpleCast as Cast;
2240 ///
2241 /// # async fn foo() -> eyre::Result<()> {
2242 /// let bytecode = "0x608060405260043610603f57600035";
2243 /// let opcodes = Cast::disassemble(&hex::decode(bytecode)?)?;
2244 /// println!("{}", opcodes);
2245 /// # Ok(())
2246 /// # }
2247 /// ```
2248 pub fn disassemble(code: &[u8]) -> Result<String> {
2249 let mut output = String::new();
2250 for (pc, inst) in InstIter::new(code).with_pc() {
2251 writeln!(output, "{pc:08x}: {inst}")?;
2252 }
2253 Ok(output)
2254 }
2255
2256 /// Gets the selector for a given function signature
2257 /// Optimizes if the `optimize` parameter is set to a number of leading zeroes
2258 ///
2259 /// # Example
2260 ///
2261 /// ```
2262 /// use cast::SimpleCast as Cast;
2263 ///
2264 /// assert_eq!(Cast::get_selector("foo(address,uint256)", 0)?.0, String::from("0xbd0d639f"));
2265 /// # Ok::<(), eyre::Error>(())
2266 /// ```
2267 pub fn get_selector(signature: &str, optimize: usize) -> Result<(String, String)> {
2268 if optimize > 4 {
2269 eyre::bail!("number of leading zeroes must not be greater than 4");
2270 }
2271 if optimize == 0 {
2272 let selector = get_func(signature)?.selector();
2273 return Ok((selector.to_string(), String::from(signature)));
2274 }
2275 let Some((name, params)) = signature.split_once('(') else {
2276 eyre::bail!("invalid function signature");
2277 };
2278
2279 let num_threads = rayon::current_num_threads();
2280 let found = AtomicBool::new(false);
2281
2282 let result: Option<(u32, String, String)> =
2283 (0..num_threads).into_par_iter().find_map_any(|i| {
2284 let nonce_start = i as u32;
2285 let nonce_step = num_threads as u32;
2286
2287 let mut nonce = nonce_start;
2288 while nonce < u32::MAX && !found.load(Ordering::Relaxed) {
2289 let input = format!("{name}{nonce}({params}");
2290 let hash = keccak256(input.as_bytes());
2291 let selector = &hash[..4];
2292
2293 if selector.iter().take_while(|&&byte| byte == 0).count() == optimize {
2294 found.store(true, Ordering::Relaxed);
2295 return Some((nonce, hex::encode_prefixed(selector), input));
2296 }
2297
2298 nonce += nonce_step;
2299 }
2300 None
2301 });
2302
2303 match result {
2304 Some((_nonce, selector, signature)) => Ok((selector, signature)),
2305 None => eyre::bail!("No selector found"),
2306 }
2307 }
2308
2309 /// Extracts function selectors, arguments and state mutability from bytecode
2310 ///
2311 /// # Example
2312 ///
2313 /// ```
2314 /// use alloy_primitives::fixed_bytes;
2315 /// use cast::SimpleCast as Cast;
2316 ///
2317 /// let bytecode = "6080604052348015600e575f80fd5b50600436106026575f3560e01c80632125b65b14602a575b5f80fd5b603a6035366004603c565b505050565b005b5f805f60608486031215604d575f80fd5b833563ffffffff81168114605f575f80fd5b925060208401356001600160a01b03811681146079575f80fd5b915060408401356001600160e01b03811681146093575f80fd5b80915050925092509256";
2318 /// let functions = Cast::extract_functions(bytecode)?;
2319 /// assert_eq!(functions, vec![(fixed_bytes!("0x2125b65b"), "uint32,address,uint224".to_string(), "pure")]);
2320 /// # Ok::<(), eyre::Report>(())
2321 /// ```
2322 pub fn extract_functions(bytecode: &str) -> Result<Vec<(Selector, String, &str)>> {
2323 let code = hex::decode(bytecode)?;
2324 let info = evmole::contract_info(
2325 evmole::ContractInfoArgs::new(&code)
2326 .with_selectors()
2327 .with_arguments()
2328 .with_state_mutability(),
2329 );
2330 Ok(info
2331 .functions
2332 .expect("functions extraction was requested")
2333 .into_iter()
2334 .map(|f| {
2335 (
2336 f.selector.into(),
2337 f.arguments
2338 .expect("arguments extraction was requested")
2339 .into_iter()
2340 .map(|t| t.sol_type_name().to_string())
2341 .collect::<Vec<String>>()
2342 .join(","),
2343 f.state_mutability
2344 .expect("state_mutability extraction was requested")
2345 .as_json_str(),
2346 )
2347 })
2348 .collect())
2349 }
2350
2351 /// Decodes a raw EIP2718 transaction payload
2352 /// Returns details about the typed transaction and ECSDA signature components
2353 ///
2354 /// # Example
2355 ///
2356 /// ```
2357 /// use alloy_network::Ethereum;
2358 /// use cast::SimpleCast as Cast;
2359 ///
2360 /// let tx = "0x02f8f582a86a82058d8459682f008508351050808303fd84948e42f2f4101563bf679975178e880fd87d3efd4e80b884659ac74b00000000000000000000000080f0c1c49891dcfdd40b6e0f960f84e6042bcb6f000000000000000000000000b97ef9ef8734c71904d8002f8b6bc66dd9c48a6e00000000000000000000000000000000000000000000000000000000007ff4e20000000000000000000000000000000000000000000000000000000000000064c001a05d429597befe2835396206781b199122f2e8297327ed4a05483339e7a8b2022aa04c23a7f70fb29dda1b4ee342fb10a625e9b8ddc6a603fb4e170d4f6f37700cb8";
2361 /// let tx_envelope = Cast::decode_raw_transaction::<Ethereum>(&tx)?;
2362 /// # Ok::<(), eyre::Report>(())
2363 pub fn decode_raw_transaction<N: Network<TxEnvelope: SignerRecoverable + Serialize>>(
2364 tx: &str,
2365 ) -> Result<String> {
2366 let tx_hex = hex::decode(tx)?;
2367 let tx: N::TxEnvelope = Decodable2718::decode_2718(&mut tx_hex.as_slice())?;
2368 if let Ok(signer) = tx.recover_signer() {
2369 Ok(serde_json::to_string_pretty(&Recovered::new_unchecked(tx, signer))?)
2370 } else {
2371 Ok(serde_json::to_string_pretty(&tx)?)
2372 }
2373 }
2374}
2375
2376pub(crate) fn strip_0x(s: &str) -> &str {
2377 s.strip_prefix("0x").unwrap_or(s)
2378}
2379
2380fn explorer_client(
2381 chain: Chain,
2382 api_key: Option<String>,
2383 api_url: Option<String>,
2384 explorer_url: Option<String>,
2385) -> Result<Client> {
2386 let mut builder = Client::builder();
2387
2388 let deduced = chain.etherscan_urls();
2389
2390 let explorer_url = explorer_url
2391 .or(deduced.map(|d| d.1.to_string()))
2392 .ok_or_eyre("Please provide the explorer browser URL using `--explorer-url`")?;
2393 builder = builder.with_url(explorer_url)?;
2394
2395 let api_url = api_url
2396 .or(deduced.map(|d| d.0.to_string()))
2397 .ok_or_eyre("Please provide the explorer API URL using `--explorer-api-url`")?;
2398 builder = builder.with_api_url(api_url)?;
2399
2400 if let Some(api_key) = api_key {
2401 builder = builder.with_api_key(api_key);
2402 }
2403
2404 builder.build().map_err(Into::into)
2405}
2406
2407#[cfg(test)]
2408mod tests {
2409 use super::{DynSolValue, SimpleCast as Cast, serialize_value_as_json};
2410 use alloy_primitives::hex;
2411
2412 #[test]
2413 fn simple_selector() {
2414 assert_eq!("0xc2985578", Cast::get_selector("foo()", 0).unwrap().0.as_str())
2415 }
2416
2417 #[test]
2418 fn selector_with_arg() {
2419 assert_eq!("0xbd0d639f", Cast::get_selector("foo(address,uint256)", 0).unwrap().0.as_str())
2420 }
2421
2422 #[test]
2423 fn calldata_uint() {
2424 assert_eq!(
2425 "0xb3de648b0000000000000000000000000000000000000000000000000000000000000001",
2426 Cast::calldata_encode("f(uint256 a)", &["1"]).unwrap().as_str()
2427 );
2428 }
2429
2430 // <https://github.com/foundry-rs/foundry/issues/2681>
2431 #[test]
2432 fn calldata_array() {
2433 assert_eq!(
2434 "0xcde2baba0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000",
2435 Cast::calldata_encode("propose(string[])", &["[\"\"]"]).unwrap().as_str()
2436 );
2437 }
2438
2439 #[test]
2440 fn calldata_bool() {
2441 assert_eq!(
2442 "0x6fae94120000000000000000000000000000000000000000000000000000000000000000",
2443 Cast::calldata_encode("bar(bool)", &["false"]).unwrap().as_str()
2444 );
2445 }
2446
2447 #[test]
2448 fn abi_decode() {
2449 let data = "0x0000000000000000000000000000000000000000000000000000000000000001";
2450 let sig = "balanceOf(address, uint256)(uint256)";
2451 assert_eq!(
2452 "1",
2453 Cast::abi_decode(sig, data, false).unwrap()[0].as_uint().unwrap().0.to_string()
2454 );
2455
2456 let data = "0x0000000000000000000000008dbd1b711dc621e1404633da156fcc779e1c6f3e000000000000000000000000d9f3c9cc99548bf3b44a43e0a2d07399eb918adc000000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000";
2457 let sig = "safeTransferFrom(address,address,uint256,uint256,bytes)";
2458 let decoded = Cast::abi_decode(sig, data, true).unwrap();
2459 let decoded = [
2460 decoded[0]
2461 .as_address()
2462 .unwrap()
2463 .to_string()
2464 .strip_prefix("0x")
2465 .unwrap()
2466 .to_owned()
2467 .to_lowercase(),
2468 decoded[1]
2469 .as_address()
2470 .unwrap()
2471 .to_string()
2472 .strip_prefix("0x")
2473 .unwrap()
2474 .to_owned()
2475 .to_lowercase(),
2476 decoded[2].as_uint().unwrap().0.to_string(),
2477 decoded[3].as_uint().unwrap().0.to_string(),
2478 hex::encode(decoded[4].as_bytes().unwrap()),
2479 ]
2480 .to_vec();
2481 assert_eq!(
2482 decoded,
2483 vec![
2484 "8dbd1b711dc621e1404633da156fcc779e1c6f3e",
2485 "d9f3c9cc99548bf3b44a43e0a2d07399eb918adc",
2486 "42",
2487 "1",
2488 ""
2489 ]
2490 );
2491 }
2492
2493 #[test]
2494 fn calldata_decode() {
2495 let data = "0x0000000000000000000000000000000000000000000000000000000000000001";
2496 let sig = "balanceOf(address, uint256)(uint256)";
2497 let decoded =
2498 Cast::calldata_decode(sig, data, false).unwrap()[0].as_uint().unwrap().0.to_string();
2499 assert_eq!(decoded, "1");
2500
2501 // Passing `input = true` will decode the data with the input function signature.
2502 // We exclude the "prefixed" function selector from the data field (the first 4 bytes).
2503 let data = "0xf242432a0000000000000000000000008dbd1b711dc621e1404633da156fcc779e1c6f3e000000000000000000000000d9f3c9cc99548bf3b44a43e0a2d07399eb918adc000000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000";
2504 let sig = "safeTransferFrom(address, address, uint256, uint256, bytes)";
2505 let decoded = Cast::calldata_decode(sig, data, true).unwrap();
2506 let decoded = [
2507 decoded[0].as_address().unwrap().to_string().to_lowercase(),
2508 decoded[1].as_address().unwrap().to_string().to_lowercase(),
2509 decoded[2].as_uint().unwrap().0.to_string(),
2510 decoded[3].as_uint().unwrap().0.to_string(),
2511 hex::encode(decoded[4].as_bytes().unwrap()),
2512 ]
2513 .into_iter()
2514 .collect::<Vec<_>>();
2515 assert_eq!(
2516 decoded,
2517 vec![
2518 "0x8dbd1b711dc621e1404633da156fcc779e1c6f3e",
2519 "0xd9f3c9cc99548bf3b44a43e0a2d07399eb918adc",
2520 "42",
2521 "1",
2522 ""
2523 ]
2524 );
2525 }
2526
2527 #[test]
2528 fn calldata_decode_nested_json() {
2529 let calldata = "0xdb5b0ed700000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000006772bf190000000000000000000000000000000000000000000000000000000000020716000000000000000000000000af9d27ffe4d51ed54ac8eec78f2785d7e11e5ab100000000000000000000000000000000000000000000000000000000000002c0000000000000000000000000000000000000000000000000000000000000000404366a6dc4b2f348a85e0066e46f0cc206fca6512e0ed7f17ca7afb88e9a4c27000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000093922dee6e380c28a50c008ab167b7800bb24c2026cd1b22f1c6fb884ceed7400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060f85e59ecad6c1a6be343a945abedb7d5b5bfad7817c4d8cc668da7d391faf700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000093dfbf04395fbec1f1aed4ad0f9d3ba880ff58a60485df5d33f8f5e0fb73188600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000aa334a426ea9e21d5f84eb2d4723ca56b92382b9260ab2b6769b7c23d437b6b512322a25cecc954127e60cf91ef056ac1da25f90b73be81c3ff1872fa48d10c7ef1ccb4087bbeedb54b1417a24abbb76f6cd57010a65bb03c7b6602b1eaf0e32c67c54168232d4edc0bfa1b815b2af2a2d0a5c109d675a4f2de684e51df9abb324ab1b19a81bac80f9ce3a45095f3df3a7cf69ef18fc08e94ac3cbc1c7effeacca68e3bfe5d81e26a659b5";
2530 let sig = "sequenceBatchesValidium((bytes32,bytes32,uint64,bytes32)[],uint64,uint64,address,bytes)";
2531 let decoded = Cast::calldata_decode(sig, calldata, true).unwrap();
2532 let json_value = serialize_value_as_json(DynSolValue::Array(decoded), None).unwrap();
2533 let expected = serde_json::json!([
2534 [
2535 [
2536 "0x04366a6dc4b2f348a85e0066e46f0cc206fca6512e0ed7f17ca7afb88e9a4c27",
2537 "0x0000000000000000000000000000000000000000000000000000000000000000",
2538 0,
2539 "0x0000000000000000000000000000000000000000000000000000000000000000"
2540 ],
2541 [
2542 "0x093922dee6e380c28a50c008ab167b7800bb24c2026cd1b22f1c6fb884ceed74",
2543 "0x0000000000000000000000000000000000000000000000000000000000000000",
2544 0,
2545 "0x0000000000000000000000000000000000000000000000000000000000000000"
2546 ],
2547 [
2548 "0x60f85e59ecad6c1a6be343a945abedb7d5b5bfad7817c4d8cc668da7d391faf7",
2549 "0x0000000000000000000000000000000000000000000000000000000000000000",
2550 0,
2551 "0x0000000000000000000000000000000000000000000000000000000000000000"
2552 ],
2553 [
2554 "0x93dfbf04395fbec1f1aed4ad0f9d3ba880ff58a60485df5d33f8f5e0fb731886",
2555 "0x0000000000000000000000000000000000000000000000000000000000000000",
2556 0,
2557 "0x0000000000000000000000000000000000000000000000000000000000000000"
2558 ]
2559 ],
2560 1735573273,
2561 132886,
2562 "0xAF9d27ffe4d51eD54AC8eEc78f2785D7E11E5ab1",
2563 "0x334a426ea9e21d5f84eb2d4723ca56b92382b9260ab2b6769b7c23d437b6b512322a25cecc954127e60cf91ef056ac1da25f90b73be81c3ff1872fa48d10c7ef1ccb4087bbeedb54b1417a24abbb76f6cd57010a65bb03c7b6602b1eaf0e32c67c54168232d4edc0bfa1b815b2af2a2d0a5c109d675a4f2de684e51df9abb324ab1b19a81bac80f9ce3a45095f3df3a7cf69ef18fc08e94ac3cbc1c7effeacca68e3bfe5d81e26a659b5"
2564 ]);
2565 assert_eq!(json_value, expected);
2566 }
2567
2568 #[test]
2569 fn concat_hex() {
2570 assert_eq!(Cast::concat_hex(["0x00", "0x01"]), "0x0001");
2571 assert_eq!(Cast::concat_hex(["1", "2"]), "0x12");
2572 }
2573
2574 #[test]
2575 fn from_rlp() {
2576 let rlp = "0xf8b1a02b5df5f0757397573e8ff34a8b987b21680357de1f6c8d10273aa528a851eaca8080a02838ac1d2d2721ba883169179b48480b2ba4f43d70fcf806956746bd9e83f90380a0e46fff283b0ab96a32a7cc375cecc3ed7b6303a43d64e0a12eceb0bc6bd8754980a01d818c1c414c665a9c9a0e0c0ef1ef87cacb380b8c1f6223cb2a68a4b2d023f5808080a0236e8f61ecde6abfebc6c529441f782f62469d8a2cc47b7aace2c136bd3b1ff08080808080";
2577 let item = Cast::from_rlp(rlp, false).unwrap();
2578 assert_eq!(
2579 item,
2580 r#"["0x2b5df5f0757397573e8ff34a8b987b21680357de1f6c8d10273aa528a851eaca","0x","0x","0x2838ac1d2d2721ba883169179b48480b2ba4f43d70fcf806956746bd9e83f903","0x","0xe46fff283b0ab96a32a7cc375cecc3ed7b6303a43d64e0a12eceb0bc6bd87549","0x","0x1d818c1c414c665a9c9a0e0c0ef1ef87cacb380b8c1f6223cb2a68a4b2d023f5","0x","0x","0x","0x236e8f61ecde6abfebc6c529441f782f62469d8a2cc47b7aace2c136bd3b1ff0","0x","0x","0x","0x","0x"]"#
2581 )
2582 }
2583
2584 #[test]
2585 fn disassemble_incomplete_sequence() {
2586 let incomplete = &hex!("60"); // PUSH1
2587 let disassembled = Cast::disassemble(incomplete).unwrap();
2588 assert_eq!(disassembled, "00000000: PUSH1\n");
2589
2590 let complete = &hex!("6000"); // PUSH1 0x00
2591 let disassembled = Cast::disassemble(complete).unwrap();
2592 assert_eq!(disassembled, "00000000: PUSH1 0x00\n");
2593
2594 let incomplete = &hex!("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); // PUSH32 with 31 bytes
2595 let disassembled = Cast::disassemble(incomplete).unwrap();
2596 assert_eq!(disassembled, "00000000: PUSH32\n");
2597
2598 let complete = &hex!("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); // PUSH32 with 32 bytes
2599 let disassembled = Cast::disassemble(complete).unwrap();
2600 assert_eq!(
2601 disassembled,
2602 "00000000: PUSH32 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\n"
2603 );
2604 }
2605}