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