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