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