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