Skip to main content

cast/
lib.rs

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