1use crate::cmd::{
2 access_list::AccessListArgs, artifact::ArtifactArgs, bind::BindArgs, call::CallArgs,
3 constructor_args::ConstructorArgsArgs, create2::Create2Args, creation_code::CreationCodeArgs,
4 da_estimate::DAEstimateArgs, estimate::EstimateArgs, find_block::FindBlockArgs,
5 interface::InterfaceArgs, logs::LogsArgs, mktx::MakeTxArgs, rpc::RpcArgs, run::RunArgs,
6 send::SendTxArgs, storage::StorageArgs, txpool::TxPoolSubcommands, wallet::WalletSubcommands,
7};
8use alloy_ens::NameOrAddress;
9use alloy_primitives::{Address, B256, Selector, U256};
10use alloy_rpc_types::BlockId;
11use clap::{Parser, Subcommand, ValueHint};
12use eyre::Result;
13use foundry_cli::opts::{EtherscanOpts, GlobalArgs, RpcOpts};
14use foundry_common::version::{LONG_VERSION, SHORT_VERSION};
15use std::{path::PathBuf, str::FromStr};
16
17#[derive(Parser)]
19#[command(
20 name = "cast",
21 version = SHORT_VERSION,
22 long_version = LONG_VERSION,
23 after_help = "Find more information in the book: https://getfoundry.sh/cast/overview",
24 next_display_order = None,
25)]
26pub struct Cast {
27 #[command(flatten)]
29 pub global: GlobalArgs,
30
31 #[command(subcommand)]
32 pub cmd: CastSubcommand,
33}
34
35#[derive(Subcommand)]
36pub enum CastSubcommand {
37 #[command(visible_aliases = &["--max-int", "maxi"])]
39 MaxInt {
40 #[arg(default_value = "int256")]
42 r#type: String,
43 },
44
45 #[command(visible_aliases = &["--min-int", "mini"])]
47 MinInt {
48 #[arg(default_value = "int256")]
50 r#type: String,
51 },
52
53 #[command(visible_aliases = &["--max-uint", "maxu"])]
55 MaxUint {
56 #[arg(default_value = "uint256")]
58 r#type: String,
59 },
60
61 #[command(visible_aliases = &["--address-zero", "az"])]
63 AddressZero,
64
65 #[command(visible_aliases = &["--hash-zero", "hz"])]
67 HashZero,
68
69 #[command(
71 visible_aliases = &[
72 "--from-ascii",
73 "--from-utf8",
74 "from-ascii",
75 "fu",
76 "fa"]
77 )]
78 FromUtf8 {
79 text: Option<String>,
81 },
82
83 #[command(visible_aliases = &["--concat-hex", "ch"])]
85 ConcatHex {
86 data: Vec<String>,
88 },
89
90 #[command(visible_aliases = &["--from-bin", "from-binx", "fb"])]
92 FromBin,
93
94 #[command(visible_aliases = &["--to-hexdata", "thd", "2hd"])]
102 ToHexdata {
103 input: Option<String>,
105 },
106
107 #[command(
109 visible_aliases = &["--to-checksum-address",
110 "--to-checksum",
111 "to-checksum",
112 "ta",
113 "2a"]
114 )]
115 ToCheckSumAddress {
116 address: Option<Address>,
118 chain_id: Option<u64>,
120 },
121
122 #[command(visible_aliases = &["--to-ascii", "tas", "2as"])]
124 ToAscii {
125 hexdata: Option<String>,
127 },
128
129 #[command(visible_aliases = &["--to-utf8", "tu8", "2u8"])]
131 ToUtf8 {
132 hexdata: Option<String>,
134 },
135
136 #[command(visible_aliases = &["--from-fix", "ff"])]
138 FromFixedPoint {
139 decimals: Option<String>,
141
142 #[arg(allow_hyphen_values = true)]
144 value: Option<String>,
145 },
146
147 #[command(visible_aliases = &["--to-bytes32", "tb", "2b"])]
149 ToBytes32 {
150 bytes: Option<String>,
152 },
153
154 #[command(visible_aliases = &["--to-fix", "tf", "2f"])]
156 ToFixedPoint {
157 decimals: Option<String>,
159
160 #[arg(allow_hyphen_values = true)]
162 value: Option<String>,
163 },
164
165 #[command(name = "to-uint256", visible_aliases = &["--to-uint256", "tu", "2u"])]
167 ToUint256 {
168 value: Option<String>,
170 },
171
172 #[command(name = "to-int256", visible_aliases = &["--to-int256", "ti", "2i"])]
174 ToInt256 {
175 value: Option<String>,
177 },
178
179 #[command(name = "shl")]
181 LeftShift {
182 value: String,
184
185 bits: String,
187
188 #[arg(long)]
190 base_in: Option<String>,
191
192 #[arg(long, default_value = "16")]
194 base_out: String,
195 },
196
197 #[command(name = "shr")]
199 RightShift {
200 value: String,
202
203 bits: String,
205
206 #[arg(long)]
208 base_in: Option<String>,
209
210 #[arg(long, default_value = "16")]
212 base_out: String,
213 },
214
215 #[command(visible_aliases = &["--to-unit", "tun", "2un"])]
224 ToUnit {
225 value: Option<String>,
227
228 #[arg(default_value = "wei")]
230 unit: String,
231 },
232
233 #[command(visible_aliases = &["--parse-units", "pun"])]
240 ParseUnits {
241 value: Option<String>,
243
244 #[arg(default_value = "18")]
246 unit: u8,
247 },
248
249 #[command(visible_aliases = &["--format-units", "fun"])]
256 FormatUnits {
257 value: Option<String>,
259
260 #[arg(default_value = "18")]
262 unit: u8,
263 },
264
265 #[command(visible_aliases = &["--to-wei", "tw", "2w"])]
269 ToWei {
270 #[arg(allow_hyphen_values = true)]
272 value: Option<String>,
273
274 #[arg(default_value = "eth")]
276 unit: String,
277 },
278
279 #[command(visible_aliases = &["--from-wei", "fw"])]
283 FromWei {
284 #[arg(allow_hyphen_values = true)]
286 value: Option<String>,
287
288 #[arg(default_value = "eth")]
290 unit: String,
291 },
292
293 #[command(visible_aliases = &["--to-rlp"])]
304 ToRlp {
305 value: Option<String>,
310 },
311
312 #[command(visible_aliases = &["--from-rlp"])]
314 FromRlp {
315 value: Option<String>,
317
318 #[arg(long, alias = "int")]
320 as_int: bool,
321 },
322
323 #[command(visible_aliases = &["--to-hex", "th", "2h"])]
325 ToHex(ToBaseArgs),
326
327 #[command(visible_aliases = &["--to-dec", "td", "2d"])]
329 ToDec(ToBaseArgs),
330
331 #[command(
333 visible_aliases = &["--to-base",
334 "--to-radix",
335 "to-radix",
336 "tr",
337 "2r"]
338 )]
339 ToBase {
340 #[command(flatten)]
341 base: ToBaseArgs,
342
343 #[arg(value_name = "BASE")]
345 base_out: Option<String>,
346 },
347 #[command(visible_aliases = &["ac", "acl"])]
349 AccessList(AccessListArgs),
350 #[command(visible_alias = "l")]
352 Logs(LogsArgs),
353 #[command(visible_alias = "bl")]
355 Block {
356 block: Option<BlockId>,
360
361 #[arg(long, short)]
363 field: Option<String>,
364
365 #[arg(long, conflicts_with = "field")]
367 raw: bool,
368
369 #[arg(long, env = "CAST_FULL_BLOCK")]
370 full: bool,
371
372 #[command(flatten)]
373 rpc: RpcOpts,
374 },
375
376 #[command(visible_alias = "bn")]
378 BlockNumber {
379 block: Option<BlockId>,
381 #[command(flatten)]
382 rpc: RpcOpts,
383 },
384
385 #[command(visible_alias = "c")]
387 Call(CallArgs),
388
389 #[command(name = "calldata", visible_alias = "cd")]
391 CalldataEncode {
392 sig: String,
394
395 #[arg(allow_hyphen_values = true)]
397 args: Vec<String>,
398
399 #[arg(long, value_name = "PATH")]
401 file: Option<PathBuf>,
402 },
403
404 Chain {
406 #[command(flatten)]
407 rpc: RpcOpts,
408 },
409
410 #[command(visible_aliases = &["ci", "cid"])]
412 ChainId {
413 #[command(flatten)]
414 rpc: RpcOpts,
415 },
416
417 #[command(visible_alias = "cl")]
419 Client {
420 #[command(flatten)]
421 rpc: RpcOpts,
422 },
423
424 #[command(visible_alias = "ca")]
426 ComputeAddress {
427 address: Option<Address>,
429
430 #[arg(
432 long,
433 conflicts_with = "salt",
434 conflicts_with = "init_code",
435 conflicts_with = "init_code_hash"
436 )]
437 nonce: Option<u64>,
438
439 #[arg(long, conflicts_with = "nonce")]
441 salt: Option<B256>,
442
443 #[arg(
445 long,
446 requires = "salt",
447 conflicts_with = "init_code_hash",
448 conflicts_with = "nonce"
449 )]
450 init_code: Option<String>,
451
452 #[arg(long, requires = "salt", conflicts_with = "init_code", conflicts_with = "nonce")]
454 init_code_hash: Option<B256>,
455
456 #[command(flatten)]
457 rpc: RpcOpts,
458 },
459
460 #[command(visible_alias = "da")]
462 Disassemble {
463 bytecode: Option<String>,
465 },
466
467 #[command(name = "mktx", visible_alias = "m")]
469 MakeTx(MakeTxArgs),
470
471 #[command(visible_aliases = &["na", "nh"])]
473 Namehash { name: Option<String> },
474
475 #[command(visible_alias = "t")]
477 Tx {
478 tx_hash: Option<String>,
480
481 #[arg(long, value_parser = NameOrAddress::from_str)]
483 from: Option<NameOrAddress>,
484
485 #[arg(long)]
487 nonce: Option<u64>,
488
489 field: Option<String>,
492
493 #[arg(long, conflicts_with = "field")]
495 raw: bool,
496
497 #[command(flatten)]
498 rpc: RpcOpts,
499 },
500
501 #[command(visible_alias = "re")]
503 Receipt {
504 tx_hash: String,
506
507 field: Option<String>,
509
510 #[arg(long, default_value = "1")]
512 confirmations: u64,
513
514 #[arg(id = "async", long = "async", env = "CAST_ASYNC", alias = "cast-async")]
516 cast_async: bool,
517
518 #[command(flatten)]
519 rpc: RpcOpts,
520 },
521
522 #[command(name = "send", visible_alias = "s")]
524 SendTx(SendTxArgs),
525
526 #[command(name = "publish", visible_alias = "p")]
528 PublishTx {
529 raw_tx: String,
531
532 #[arg(id = "async", long = "async", env = "CAST_ASYNC", alias = "cast-async")]
534 cast_async: bool,
535
536 #[command(flatten)]
537 rpc: RpcOpts,
538 },
539
540 #[command(visible_alias = "e")]
542 Estimate(EstimateArgs),
543
544 #[command(visible_aliases = &["calldata-decode", "--calldata-decode", "cdd"])]
549 DecodeCalldata {
550 sig: String,
552
553 calldata: String,
555 },
556
557 #[command(visible_aliases = &["string-decode", "--string-decode", "sd"])]
561 DecodeString {
562 data: String,
564 },
565
566 #[command(visible_aliases = &["event-decode", "--event-decode", "ed"])]
568 DecodeEvent {
569 #[arg(long, visible_alias = "event-sig")]
571 sig: Option<String>,
572 data: String,
574 },
575
576 #[command(visible_aliases = &["error-decode", "--error-decode", "erd"])]
578 DecodeError {
579 #[arg(long, visible_alias = "error-sig")]
581 sig: Option<String>,
582 data: String,
584 },
585
586 #[command(name = "decode-abi", visible_aliases = &["abi-decode", "--abi-decode", "ad"])]
592 DecodeAbi {
593 sig: String,
595
596 calldata: String,
598
599 #[arg(long, short, help_heading = "Decode input data instead of output data")]
601 input: bool,
602 },
603
604 #[command(visible_alias = "ae")]
606 AbiEncode {
607 sig: String,
609
610 #[arg(long)]
612 packed: bool,
613
614 #[arg(allow_hyphen_values = true)]
616 args: Vec<String>,
617 },
618
619 #[command(visible_alias = "in")]
621 Index {
622 key_type: String,
624
625 key: String,
627
628 slot_number: String,
630 },
631
632 #[command(name = "index-erc7201", alias = "index-erc-7201", visible_aliases = &["index7201", "in7201"])]
634 IndexErc7201 {
635 id: Option<String>,
637 #[arg(long, default_value = "erc7201")]
639 formula_id: String,
640 },
641
642 #[command(visible_alias = "impl")]
645 Implementation {
646 #[arg(long, short = 'B')]
650 block: Option<BlockId>,
651
652 #[arg(long)]
656 beacon: bool,
657
658 #[arg(value_parser = NameOrAddress::from_str)]
660 who: NameOrAddress,
661
662 #[command(flatten)]
663 rpc: RpcOpts,
664 },
665
666 #[command(visible_alias = "adm")]
668 Admin {
669 #[arg(long, short = 'B')]
673 block: Option<BlockId>,
674
675 #[arg(value_parser = NameOrAddress::from_str)]
677 who: NameOrAddress,
678
679 #[command(flatten)]
680 rpc: RpcOpts,
681 },
682
683 #[command(name = "4byte", visible_aliases = &["4", "4b"])]
685 FourByte {
686 selector: Option<Selector>,
688 },
689
690 #[command(name = "4byte-calldata", aliases = &["4byte-decode", "4d", "4bd"], visible_aliases = &["4c", "4bc"])]
692 FourByteCalldata {
693 calldata: Option<String>,
695 },
696
697 #[command(name = "4byte-event", visible_aliases = &["4e", "4be", "topic0-event", "t0e"])]
699 FourByteEvent {
700 #[arg(value_name = "TOPIC_0")]
702 topic: Option<B256>,
703 },
704
705 #[command(visible_aliases = &["ups"])]
713 UploadSignature {
714 signatures: Vec<String>,
719 },
720
721 #[command(visible_alias = "pc")]
725 PrettyCalldata {
726 calldata: Option<String>,
728
729 #[arg(long, short)]
731 offline: bool,
732 },
733
734 #[command(visible_alias = "a")]
736 Age {
737 block: Option<BlockId>,
741
742 #[command(flatten)]
743 rpc: RpcOpts,
744 },
745
746 #[command(visible_alias = "b")]
748 Balance {
749 #[arg(long, short = 'B')]
753 block: Option<BlockId>,
754
755 #[arg(value_parser = NameOrAddress::from_str)]
757 who: NameOrAddress,
758
759 #[arg(long, short)]
761 ether: bool,
762
763 #[command(flatten)]
764 rpc: RpcOpts,
765
766 #[arg(long, alias = "erc721")]
769 erc20: Option<Address>,
770 },
771
772 #[command(visible_aliases = &["ba", "fee", "basefee"])]
774 BaseFee {
775 block: Option<BlockId>,
779
780 #[command(flatten)]
781 rpc: RpcOpts,
782 },
783
784 #[command(visible_alias = "co")]
786 Code {
787 #[arg(long, short = 'B')]
791 block: Option<BlockId>,
792
793 #[arg(value_parser = NameOrAddress::from_str)]
795 who: NameOrAddress,
796
797 #[arg(long, short)]
799 disassemble: bool,
800
801 #[command(flatten)]
802 rpc: RpcOpts,
803 },
804
805 #[command(visible_alias = "cs")]
807 Codesize {
808 #[arg(long, short = 'B')]
812 block: Option<BlockId>,
813
814 #[arg(value_parser = NameOrAddress::from_str)]
816 who: NameOrAddress,
817
818 #[command(flatten)]
819 rpc: RpcOpts,
820 },
821
822 #[command(visible_alias = "g")]
824 GasPrice {
825 #[command(flatten)]
826 rpc: RpcOpts,
827 },
828
829 #[command(visible_alias = "se")]
831 SigEvent {
832 event_string: Option<String>,
834 },
835
836 #[command(visible_aliases = &["k", "keccak256"])]
838 Keccak {
839 data: Option<String>,
841 },
842
843 #[command(visible_aliases = &["--hash-message", "hm"])]
845 HashMessage {
846 message: Option<String>,
848 },
849
850 #[command(visible_alias = "rn")]
852 ResolveName {
853 who: Option<String>,
855
856 #[arg(long)]
858 verify: bool,
859
860 #[command(flatten)]
861 rpc: RpcOpts,
862 },
863
864 #[command(visible_alias = "la")]
866 LookupAddress {
867 who: Option<Address>,
869
870 #[arg(long)]
872 verify: bool,
873
874 #[command(flatten)]
875 rpc: RpcOpts,
876 },
877
878 #[command(visible_alias = "st")]
880 Storage(StorageArgs),
881
882 #[command(visible_alias = "pr")]
884 Proof {
885 #[arg(value_parser = NameOrAddress::from_str)]
887 address: NameOrAddress,
888
889 #[arg(value_parser = parse_slot)]
891 slots: Vec<B256>,
892
893 #[arg(long, short = 'B')]
897 block: Option<BlockId>,
898
899 #[command(flatten)]
900 rpc: RpcOpts,
901 },
902
903 #[command(visible_alias = "n")]
905 Nonce {
906 #[arg(long, short = 'B')]
910 block: Option<BlockId>,
911
912 #[arg(value_parser = NameOrAddress::from_str)]
914 who: NameOrAddress,
915
916 #[command(flatten)]
917 rpc: RpcOpts,
918 },
919
920 #[command()]
922 Codehash {
923 #[arg(long, short = 'B')]
927 block: Option<BlockId>,
928
929 #[arg(value_parser = NameOrAddress::from_str)]
931 who: NameOrAddress,
932
933 #[arg(value_parser = parse_slot)]
935 slots: Vec<B256>,
936
937 #[command(flatten)]
938 rpc: RpcOpts,
939 },
940
941 #[command(visible_alias = "sr")]
943 StorageRoot {
944 #[arg(long, short = 'B')]
948 block: Option<BlockId>,
949
950 #[arg(value_parser = NameOrAddress::from_str)]
952 who: NameOrAddress,
953
954 #[arg(value_parser = parse_slot)]
956 slots: Vec<B256>,
957
958 #[command(flatten)]
959 rpc: RpcOpts,
960 },
961
962 #[command(visible_aliases = &["et", "src"])]
964 Source {
965 address: String,
967
968 #[arg(long, short)]
970 flatten: bool,
971
972 #[arg(short, value_hint = ValueHint::DirPath, alias = "path")]
974 directory: Option<PathBuf>,
975
976 #[command(flatten)]
977 etherscan: EtherscanOpts,
978
979 #[arg(long, env = "EXPLORER_API_URL")]
982 explorer_api_url: Option<String>,
983
984 #[arg(long, env = "EXPLORER_URL")]
986 explorer_url: Option<String>,
987 },
988
989 #[command(visible_alias = "w")]
991 Wallet {
992 #[command(subcommand)]
993 command: WalletSubcommands,
994 },
995
996 #[command(visible_alias = "cc")]
998 CreationCode(CreationCodeArgs),
999
1000 #[command(visible_alias = "ar")]
1002 Artifact(ArtifactArgs),
1003
1004 #[command(visible_alias = "cra")]
1006 ConstructorArgs(ConstructorArgsArgs),
1007
1008 #[command(visible_alias = "i")]
1012 Interface(InterfaceArgs),
1013
1014 #[command(visible_alias = "bi")]
1016 Bind(BindArgs),
1017
1018 #[command(visible_alias = "si")]
1020 Sig {
1021 sig: Option<String>,
1023
1024 optimize: Option<usize>,
1026 },
1027
1028 #[command(visible_alias = "c2")]
1030 Create2(Create2Args),
1031
1032 #[command(visible_alias = "f")]
1034 FindBlock(FindBlockArgs),
1035
1036 #[command(visible_alias = "com")]
1038 Completions {
1039 #[arg(value_enum)]
1040 shell: clap_complete::Shell,
1041 },
1042
1043 #[command(visible_alias = "fig")]
1045 GenerateFigSpec,
1046
1047 #[command(visible_alias = "r")]
1049 Run(RunArgs),
1050
1051 #[command(visible_alias = "rp")]
1053 Rpc(RpcArgs),
1054
1055 #[command(name = "format-bytes32-string", visible_aliases = &["--format-bytes32-string"])]
1057 FormatBytes32String {
1058 string: Option<String>,
1060 },
1061
1062 #[command(name = "parse-bytes32-string", visible_aliases = &["--parse-bytes32-string"])]
1064 ParseBytes32String {
1065 bytes: Option<String>,
1067 },
1068 #[command(name = "parse-bytes32-address", visible_aliases = &["--parse-bytes32-address"])]
1069 #[command(about = "Parses a checksummed address from bytes32 encoding.")]
1070 ParseBytes32Address {
1071 #[arg(value_name = "BYTES")]
1072 bytes: Option<String>,
1073 },
1074
1075 #[command(visible_aliases = &["dt", "decode-tx"])]
1077 DecodeTransaction { tx: Option<String> },
1078
1079 #[command(visible_aliases = &["decode-auth"])]
1081 RecoverAuthority { auth: String },
1082
1083 #[command(visible_alias = "sel")]
1085 Selectors {
1086 bytecode: Option<String>,
1088
1089 #[arg(long, short)]
1091 resolve: bool,
1092 },
1093
1094 #[command(visible_alias = "tp")]
1096 TxPool {
1097 #[command(subcommand)]
1098 command: TxPoolSubcommands,
1099 },
1100 #[command(name = "da-estimate")]
1102 DAEstimate(DAEstimateArgs),
1103}
1104
1105#[derive(Debug, Parser)]
1107pub struct ToBaseArgs {
1108 #[arg(allow_hyphen_values = true)]
1110 pub value: Option<String>,
1111
1112 #[arg(long, short = 'i')]
1114 pub base_in: Option<String>,
1115}
1116
1117pub fn parse_slot(s: &str) -> Result<B256> {
1118 let slot = U256::from_str(s).map_err(|e| eyre::eyre!("Could not parse slot number: {e}"))?;
1119 Ok(B256::from(slot))
1120}
1121
1122#[cfg(test)]
1123mod tests {
1124 use super::*;
1125 use crate::SimpleCast;
1126 use alloy_rpc_types::{BlockNumberOrTag, RpcBlockHash};
1127 use clap::CommandFactory;
1128
1129 #[test]
1130 fn verify_cli() {
1131 Cast::command().debug_assert();
1132 }
1133
1134 #[test]
1135 fn parse_proof_slot() {
1136 let args: Cast = Cast::parse_from([
1137 "foundry-cli",
1138 "proof",
1139 "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
1140 "0",
1141 "1",
1142 "0x0000000000000000000000000000000000000000000000000000000000000000",
1143 "0x1",
1144 "0x01",
1145 ]);
1146 match args.cmd {
1147 CastSubcommand::Proof { slots, .. } => {
1148 assert_eq!(
1149 slots,
1150 vec![
1151 B256::ZERO,
1152 U256::from(1).into(),
1153 B256::ZERO,
1154 U256::from(1).into(),
1155 U256::from(1).into()
1156 ]
1157 );
1158 }
1159 _ => unreachable!(),
1160 };
1161 }
1162
1163 #[test]
1164 fn parse_call_data() {
1165 let args: Cast = Cast::parse_from([
1166 "foundry-cli",
1167 "calldata",
1168 "f()",
1169 "5c9d55b78febcc2061715ba4f57ecf8ea2711f2c",
1170 "2",
1171 ]);
1172 match args.cmd {
1173 CastSubcommand::CalldataEncode { args, .. } => {
1174 assert_eq!(
1175 args,
1176 vec!["5c9d55b78febcc2061715ba4f57ecf8ea2711f2c".to_string(), "2".to_string()]
1177 )
1178 }
1179 _ => unreachable!(),
1180 };
1181 }
1182
1183 #[test]
1184 fn parse_call_data_with_file() {
1185 let args: Cast = Cast::parse_from(["foundry-cli", "calldata", "f()", "--file", "test.txt"]);
1186 match args.cmd {
1187 CastSubcommand::CalldataEncode { sig, file, args } => {
1188 assert_eq!(sig, "f()".to_string());
1189 assert_eq!(file, Some(PathBuf::from("test.txt")));
1190 assert!(args.is_empty());
1191 }
1192 _ => unreachable!(),
1193 };
1194 }
1195
1196 #[test]
1198 fn parse_signature() {
1199 let args: Cast = Cast::parse_from([
1200 "foundry-cli",
1201 "sig",
1202 "__$_$__$$$$$__$$_$$$_$$__$$___$$(address,address,uint256)",
1203 ]);
1204 match args.cmd {
1205 CastSubcommand::Sig { sig, .. } => {
1206 let sig = sig.unwrap();
1207 assert_eq!(
1208 sig,
1209 "__$_$__$$$$$__$$_$$$_$$__$$___$$(address,address,uint256)".to_string()
1210 );
1211
1212 let selector = SimpleCast::get_selector(&sig, 0).unwrap();
1213 assert_eq!(selector.0, "0x23b872dd".to_string());
1214 }
1215 _ => unreachable!(),
1216 };
1217 }
1218
1219 #[test]
1220 fn parse_block_ids() {
1221 struct TestCase {
1222 input: String,
1223 expect: BlockId,
1224 }
1225
1226 let test_cases = [
1227 TestCase {
1228 input: "0".to_string(),
1229 expect: BlockId::Number(BlockNumberOrTag::Number(0u64)),
1230 },
1231 TestCase {
1232 input: "0x56462c47c03df160f66819f0a79ea07def1569f8aac0fe91bb3a081159b61b4a"
1233 .to_string(),
1234 expect: BlockId::Hash(RpcBlockHash::from_hash(
1235 "0x56462c47c03df160f66819f0a79ea07def1569f8aac0fe91bb3a081159b61b4a"
1236 .parse()
1237 .unwrap(),
1238 None,
1239 )),
1240 },
1241 TestCase {
1242 input: "latest".to_string(),
1243 expect: BlockId::Number(BlockNumberOrTag::Latest),
1244 },
1245 TestCase {
1246 input: "earliest".to_string(),
1247 expect: BlockId::Number(BlockNumberOrTag::Earliest),
1248 },
1249 TestCase {
1250 input: "pending".to_string(),
1251 expect: BlockId::Number(BlockNumberOrTag::Pending),
1252 },
1253 TestCase { input: "safe".to_string(), expect: BlockId::Number(BlockNumberOrTag::Safe) },
1254 TestCase {
1255 input: "finalized".to_string(),
1256 expect: BlockId::Number(BlockNumberOrTag::Finalized),
1257 },
1258 ];
1259
1260 for test in test_cases {
1261 let result: BlockId = test.input.parse().unwrap();
1262 assert_eq!(result, test.expect);
1263 }
1264 }
1265}