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