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