Skip to main content

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