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