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