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, Selector, B256, 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: http://book.getfoundry.sh/reference/cast/cast.html",
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 },
119
120 #[command(visible_aliases = &["--to-ascii", "tas", "2as"])]
122 ToAscii {
123 hexdata: Option<String>,
125 },
126
127 #[command(visible_aliases = &["--to-utf8", "tu8", "2u8"])]
129 ToUtf8 {
130 hexdata: Option<String>,
132 },
133
134 #[command(visible_aliases = &["--from-fix", "ff"])]
136 FromFixedPoint {
137 decimals: Option<String>,
139
140 #[arg(allow_hyphen_values = true)]
142 value: Option<String>,
143 },
144
145 #[command(visible_aliases = &["--to-bytes32", "tb", "2b"])]
147 ToBytes32 {
148 bytes: Option<String>,
150 },
151
152 #[command(visible_aliases = &["--to-fix", "tf", "2f"])]
154 ToFixedPoint {
155 decimals: Option<String>,
157
158 #[arg(allow_hyphen_values = true)]
160 value: Option<String>,
161 },
162
163 #[command(name = "to-uint256", visible_aliases = &["--to-uint256", "tu", "2u"])]
165 ToUint256 {
166 value: Option<String>,
168 },
169
170 #[command(name = "to-int256", visible_aliases = &["--to-int256", "ti", "2i"])]
172 ToInt256 {
173 value: Option<String>,
175 },
176
177 #[command(name = "shl")]
179 LeftShift {
180 value: String,
182
183 bits: String,
185
186 #[arg(long)]
188 base_in: Option<String>,
189
190 #[arg(long, default_value = "16")]
192 base_out: String,
193 },
194
195 #[command(name = "shr")]
197 RightShift {
198 value: String,
200
201 bits: String,
203
204 #[arg(long)]
206 base_in: Option<String>,
207
208 #[arg(long, default_value = "16")]
210 base_out: String,
211 },
212
213 #[command(visible_aliases = &["--to-unit", "tun", "2un"])]
222 ToUnit {
223 value: Option<String>,
225
226 #[arg(default_value = "wei")]
228 unit: String,
229 },
230
231 #[command(visible_aliases = &["--parse-units", "pun"])]
238 ParseUnits {
239 value: Option<String>,
241
242 #[arg(default_value = "18")]
244 unit: u8,
245 },
246
247 #[command(visible_aliases = &["--format-units", "fun"])]
254 FormatUnits {
255 value: Option<String>,
257
258 #[arg(default_value = "18")]
260 unit: u8,
261 },
262
263 #[command(visible_aliases = &["--to-wei", "tw", "2w"])]
267 ToWei {
268 #[arg(allow_hyphen_values = true)]
270 value: Option<String>,
271
272 #[arg(default_value = "eth")]
274 unit: String,
275 },
276
277 #[command(visible_aliases = &["--from-wei", "fw"])]
281 FromWei {
282 #[arg(allow_hyphen_values = true)]
284 value: Option<String>,
285
286 #[arg(default_value = "eth")]
288 unit: String,
289 },
290
291 #[command(visible_aliases = &["--to-rlp"])]
302 ToRlp {
303 value: Option<String>,
308 },
309
310 #[command(visible_aliases = &["--from-rlp"])]
312 FromRlp {
313 value: Option<String>,
315
316 #[arg(long, alias = "int")]
318 as_int: bool,
319 },
320
321 #[command(visible_aliases = &["--to-hex", "th", "2h"])]
323 ToHex(ToBaseArgs),
324
325 #[command(visible_aliases = &["--to-dec", "td", "2d"])]
327 ToDec(ToBaseArgs),
328
329 #[command(
331 visible_aliases = &["--to-base",
332 "--to-radix",
333 "to-radix",
334 "tr",
335 "2r"]
336 )]
337 ToBase {
338 #[command(flatten)]
339 base: ToBaseArgs,
340
341 #[arg(value_name = "BASE")]
343 base_out: Option<String>,
344 },
345 #[command(visible_aliases = &["ac", "acl"])]
347 AccessList(AccessListArgs),
348 #[command(visible_alias = "l")]
350 Logs(LogsArgs),
351 #[command(visible_alias = "bl")]
353 Block {
354 block: Option<BlockId>,
358
359 #[arg(long, short)]
361 field: Option<String>,
362
363 #[arg(long, env = "CAST_FULL_BLOCK")]
364 full: bool,
365
366 #[command(flatten)]
367 rpc: RpcOpts,
368 },
369
370 #[command(visible_alias = "bn")]
372 BlockNumber {
373 block: Option<BlockId>,
375 #[command(flatten)]
376 rpc: RpcOpts,
377 },
378
379 #[command(visible_alias = "c")]
381 Call(CallArgs),
382
383 #[command(name = "calldata", visible_alias = "cd")]
385 CalldataEncode {
386 sig: String,
388
389 #[arg(allow_hyphen_values = true)]
391 args: Vec<String>,
392
393 #[arg(long, value_name = "PATH")]
395 file: Option<PathBuf>,
396 },
397
398 Chain {
400 #[command(flatten)]
401 rpc: RpcOpts,
402 },
403
404 #[command(visible_aliases = &["ci", "cid"])]
406 ChainId {
407 #[command(flatten)]
408 rpc: RpcOpts,
409 },
410
411 #[command(visible_alias = "cl")]
413 Client {
414 #[command(flatten)]
415 rpc: RpcOpts,
416 },
417
418 #[command(visible_alias = "ca")]
420 ComputeAddress {
421 address: Option<Address>,
423
424 #[arg(
426 long,
427 conflicts_with = "salt",
428 conflicts_with = "init_code",
429 conflicts_with = "init_code_hash"
430 )]
431 nonce: Option<u64>,
432
433 #[arg(long, conflicts_with = "nonce")]
435 salt: Option<B256>,
436
437 #[arg(
439 long,
440 requires = "salt",
441 conflicts_with = "init_code_hash",
442 conflicts_with = "nonce"
443 )]
444 init_code: Option<String>,
445
446 #[arg(long, requires = "salt", conflicts_with = "init_code", conflicts_with = "nonce")]
448 init_code_hash: Option<B256>,
449
450 #[command(flatten)]
451 rpc: RpcOpts,
452 },
453
454 #[command(visible_alias = "da")]
456 Disassemble {
457 bytecode: Option<String>,
459 },
460
461 #[command(name = "mktx", visible_alias = "m")]
463 MakeTx(MakeTxArgs),
464
465 #[command(visible_aliases = &["na", "nh"])]
467 Namehash { name: Option<String> },
468
469 #[command(visible_alias = "t")]
471 Tx {
472 tx_hash: Option<String>,
474
475 #[arg(long, value_parser = NameOrAddress::from_str)]
477 from: Option<NameOrAddress>,
478
479 #[arg(long)]
481 nonce: Option<u64>,
482
483 field: Option<String>,
486
487 #[arg(long, conflicts_with = "field")]
489 raw: bool,
490
491 #[command(flatten)]
492 rpc: RpcOpts,
493 },
494
495 #[command(visible_alias = "re")]
497 Receipt {
498 tx_hash: String,
500
501 field: Option<String>,
503
504 #[arg(long, default_value = "1")]
506 confirmations: u64,
507
508 #[arg(id = "async", long = "async", env = "CAST_ASYNC", alias = "cast-async")]
510 cast_async: bool,
511
512 #[command(flatten)]
513 rpc: RpcOpts,
514 },
515
516 #[command(name = "send", visible_alias = "s")]
518 SendTx(SendTxArgs),
519
520 #[command(name = "publish", visible_alias = "p")]
522 PublishTx {
523 raw_tx: String,
525
526 #[arg(id = "async", long = "async", env = "CAST_ASYNC", alias = "cast-async")]
528 cast_async: bool,
529
530 #[command(flatten)]
531 rpc: RpcOpts,
532 },
533
534 #[command(visible_alias = "e")]
536 Estimate(EstimateArgs),
537
538 #[command(visible_aliases = &["calldata-decode", "--calldata-decode", "cdd"])]
543 DecodeCalldata {
544 sig: String,
546
547 calldata: String,
549 },
550
551 #[command(visible_aliases = &["string-decode", "--string-decode", "sd"])]
555 DecodeString {
556 data: String,
558 },
559
560 #[command(visible_aliases = &["event-decode", "--event-decode", "ed"])]
562 DecodeEvent {
563 #[arg(long, visible_alias = "event-sig")]
565 sig: Option<String>,
566 data: String,
568 },
569
570 #[command(visible_aliases = &["error-decode", "--error-decode", "erd"])]
572 DecodeError {
573 #[arg(long, visible_alias = "error-sig")]
575 sig: Option<String>,
576 data: String,
578 },
579
580 #[command(name = "decode-abi", visible_aliases = &["abi-decode", "--abi-decode", "ad"])]
586 DecodeAbi {
587 sig: String,
589
590 calldata: String,
592
593 #[arg(long, short, help_heading = "Decode input data instead of output data")]
595 input: bool,
596 },
597
598 #[command(visible_alias = "ae")]
600 AbiEncode {
601 sig: String,
603
604 #[arg(long)]
606 packed: bool,
607
608 #[arg(allow_hyphen_values = true)]
610 args: Vec<String>,
611 },
612
613 #[command(visible_alias = "in")]
615 Index {
616 key_type: String,
618
619 key: String,
621
622 slot_number: String,
624 },
625
626 #[command(name = "index-erc7201", alias = "index-erc-7201", visible_aliases = &["index7201", "in7201"])]
628 IndexErc7201 {
629 id: Option<String>,
631 #[arg(long, default_value = "erc7201")]
633 formula_id: String,
634 },
635
636 #[command(visible_alias = "impl")]
639 Implementation {
640 #[arg(long, short = 'B')]
644 block: Option<BlockId>,
645
646 #[arg(long)]
650 beacon: bool,
651
652 #[arg(value_parser = NameOrAddress::from_str)]
654 who: NameOrAddress,
655
656 #[command(flatten)]
657 rpc: RpcOpts,
658 },
659
660 #[command(visible_alias = "adm")]
662 Admin {
663 #[arg(long, short = 'B')]
667 block: Option<BlockId>,
668
669 #[arg(value_parser = NameOrAddress::from_str)]
671 who: NameOrAddress,
672
673 #[command(flatten)]
674 rpc: RpcOpts,
675 },
676
677 #[command(name = "4byte", visible_aliases = &["4", "4b"])]
679 FourByte {
680 selector: Option<Selector>,
682 },
683
684 #[command(name = "4byte-calldata", aliases = &["4byte-decode", "4d", "4bd"], visible_aliases = &["4c", "4bc"])]
686 FourByteCalldata {
687 calldata: Option<String>,
689 },
690
691 #[command(name = "4byte-event", visible_aliases = &["4e", "4be", "topic0-event", "t0e"])]
693 FourByteEvent {
694 #[arg(value_name = "TOPIC_0")]
696 topic: Option<B256>,
697 },
698
699 #[command(visible_aliases = &["ups"])]
707 UploadSignature {
708 signatures: Vec<String>,
713 },
714
715 #[command(visible_alias = "pc")]
719 PrettyCalldata {
720 calldata: Option<String>,
722
723 #[arg(long, short)]
725 offline: bool,
726 },
727
728 #[command(visible_alias = "a")]
730 Age {
731 block: Option<BlockId>,
735
736 #[command(flatten)]
737 rpc: RpcOpts,
738 },
739
740 #[command(visible_alias = "b")]
742 Balance {
743 #[arg(long, short = 'B')]
747 block: Option<BlockId>,
748
749 #[arg(value_parser = NameOrAddress::from_str)]
751 who: NameOrAddress,
752
753 #[arg(long, short)]
755 ether: bool,
756
757 #[command(flatten)]
758 rpc: RpcOpts,
759
760 #[arg(long, alias = "erc721")]
763 erc20: Option<Address>,
764 },
765
766 #[command(visible_aliases = &["ba", "fee", "basefee"])]
768 BaseFee {
769 block: Option<BlockId>,
773
774 #[command(flatten)]
775 rpc: RpcOpts,
776 },
777
778 #[command(visible_alias = "co")]
780 Code {
781 #[arg(long, short = 'B')]
785 block: Option<BlockId>,
786
787 #[arg(value_parser = NameOrAddress::from_str)]
789 who: NameOrAddress,
790
791 #[arg(long, short)]
793 disassemble: bool,
794
795 #[command(flatten)]
796 rpc: RpcOpts,
797 },
798
799 #[command(visible_alias = "cs")]
801 Codesize {
802 #[arg(long, short = 'B')]
806 block: Option<BlockId>,
807
808 #[arg(value_parser = NameOrAddress::from_str)]
810 who: NameOrAddress,
811
812 #[command(flatten)]
813 rpc: RpcOpts,
814 },
815
816 #[command(visible_alias = "g")]
818 GasPrice {
819 #[command(flatten)]
820 rpc: RpcOpts,
821 },
822
823 #[command(visible_alias = "se")]
825 SigEvent {
826 event_string: Option<String>,
828 },
829
830 #[command(visible_aliases = &["k", "keccak256"])]
832 Keccak {
833 data: Option<String>,
835 },
836
837 #[command(visible_aliases = &["--hash-message", "hm"])]
839 HashMessage {
840 message: Option<String>,
842 },
843
844 #[command(visible_alias = "rn")]
846 ResolveName {
847 who: Option<String>,
849
850 #[arg(long)]
852 verify: bool,
853
854 #[command(flatten)]
855 rpc: RpcOpts,
856 },
857
858 #[command(visible_alias = "la")]
860 LookupAddress {
861 who: Option<Address>,
863
864 #[arg(long)]
866 verify: bool,
867
868 #[command(flatten)]
869 rpc: RpcOpts,
870 },
871
872 #[command(visible_alias = "st")]
874 Storage(StorageArgs),
875
876 #[command(visible_alias = "pr")]
878 Proof {
879 #[arg(value_parser = NameOrAddress::from_str)]
881 address: NameOrAddress,
882
883 #[arg(value_parser = parse_slot)]
885 slots: Vec<B256>,
886
887 #[arg(long, short = 'B')]
891 block: Option<BlockId>,
892
893 #[command(flatten)]
894 rpc: RpcOpts,
895 },
896
897 #[command(visible_alias = "n")]
899 Nonce {
900 #[arg(long, short = 'B')]
904 block: Option<BlockId>,
905
906 #[arg(value_parser = NameOrAddress::from_str)]
908 who: NameOrAddress,
909
910 #[command(flatten)]
911 rpc: RpcOpts,
912 },
913
914 #[command()]
916 Codehash {
917 #[arg(long, short = 'B')]
921 block: Option<BlockId>,
922
923 #[arg(value_parser = NameOrAddress::from_str)]
925 who: NameOrAddress,
926
927 #[arg(value_parser = parse_slot)]
929 slots: Vec<B256>,
930
931 #[command(flatten)]
932 rpc: RpcOpts,
933 },
934
935 #[command(visible_alias = "sr")]
937 StorageRoot {
938 #[arg(long, short = 'B')]
942 block: Option<BlockId>,
943
944 #[arg(value_parser = NameOrAddress::from_str)]
946 who: NameOrAddress,
947
948 #[arg(value_parser = parse_slot)]
950 slots: Vec<B256>,
951
952 #[command(flatten)]
953 rpc: RpcOpts,
954 },
955
956 #[command(visible_aliases = &["et", "src"])]
958 Source {
959 address: String,
961
962 #[arg(long, short)]
964 flatten: bool,
965
966 #[arg(short, value_hint = ValueHint::DirPath, alias = "path")]
968 directory: Option<PathBuf>,
969
970 #[command(flatten)]
971 etherscan: EtherscanOpts,
972
973 #[arg(long, env = "EXPLORER_API_URL")]
976 explorer_api_url: Option<String>,
977
978 #[arg(long, env = "EXPLORER_URL")]
980 explorer_url: Option<String>,
981 },
982
983 #[command(visible_alias = "w")]
985 Wallet {
986 #[command(subcommand)]
987 command: WalletSubcommands,
988 },
989
990 #[command(visible_alias = "cc")]
992 CreationCode(CreationCodeArgs),
993
994 #[command(visible_alias = "ar")]
996 Artifact(ArtifactArgs),
997
998 #[command(visible_alias = "cra")]
1000 ConstructorArgs(ConstructorArgsArgs),
1001
1002 #[command(visible_alias = "i")]
1006 Interface(InterfaceArgs),
1007
1008 #[command(visible_alias = "bi")]
1010 Bind(BindArgs),
1011
1012 #[command(visible_alias = "si")]
1014 Sig {
1015 sig: Option<String>,
1017
1018 optimize: Option<usize>,
1020 },
1021
1022 #[command(visible_alias = "c2")]
1024 Create2(Create2Args),
1025
1026 #[command(visible_alias = "f")]
1028 FindBlock(FindBlockArgs),
1029
1030 #[command(visible_alias = "com")]
1032 Completions {
1033 #[arg(value_enum)]
1034 shell: clap_complete::Shell,
1035 },
1036
1037 #[command(visible_alias = "fig")]
1039 GenerateFigSpec,
1040
1041 #[command(visible_alias = "r")]
1043 Run(RunArgs),
1044
1045 #[command(visible_alias = "rp")]
1047 Rpc(RpcArgs),
1048
1049 #[command(name = "format-bytes32-string", visible_aliases = &["--format-bytes32-string"])]
1051 FormatBytes32String {
1052 string: Option<String>,
1054 },
1055
1056 #[command(name = "parse-bytes32-string", visible_aliases = &["--parse-bytes32-string"])]
1058 ParseBytes32String {
1059 bytes: Option<String>,
1061 },
1062 #[command(name = "parse-bytes32-address", visible_aliases = &["--parse-bytes32-address"])]
1063 #[command(about = "Parses a checksummed address from bytes32 encoding.")]
1064 ParseBytes32Address {
1065 #[arg(value_name = "BYTES")]
1066 bytes: Option<String>,
1067 },
1068
1069 #[command(visible_aliases = &["dt", "decode-tx"])]
1071 DecodeTransaction { tx: Option<String> },
1072
1073 #[command(visible_alias = "sel")]
1075 Selectors {
1076 bytecode: Option<String>,
1078
1079 #[arg(long, short)]
1081 resolve: bool,
1082 },
1083
1084 #[command(visible_alias = "tp")]
1086 TxPool {
1087 #[command(subcommand)]
1088 command: TxPoolSubcommands,
1089 },
1090 #[command(name = "da-estimate")]
1092 DAEstimate(DAEstimateArgs),
1093}
1094
1095#[derive(Debug, Parser)]
1097pub struct ToBaseArgs {
1098 #[arg(allow_hyphen_values = true)]
1100 pub value: Option<String>,
1101
1102 #[arg(long, short = 'i')]
1104 pub base_in: Option<String>,
1105}
1106
1107pub fn parse_slot(s: &str) -> Result<B256> {
1108 let slot = U256::from_str(s).map_err(|e| eyre::eyre!("Could not parse slot number: {e}"))?;
1109 Ok(B256::from(slot))
1110}
1111
1112#[cfg(test)]
1113mod tests {
1114 use super::*;
1115 use crate::SimpleCast;
1116 use alloy_rpc_types::{BlockNumberOrTag, RpcBlockHash};
1117 use clap::CommandFactory;
1118
1119 #[test]
1120 fn verify_cli() {
1121 Cast::command().debug_assert();
1122 }
1123
1124 #[test]
1125 fn parse_proof_slot() {
1126 let args: Cast = Cast::parse_from([
1127 "foundry-cli",
1128 "proof",
1129 "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
1130 "0",
1131 "1",
1132 "0x0000000000000000000000000000000000000000000000000000000000000000",
1133 "0x1",
1134 "0x01",
1135 ]);
1136 match args.cmd {
1137 CastSubcommand::Proof { slots, .. } => {
1138 assert_eq!(
1139 slots,
1140 vec![
1141 B256::ZERO,
1142 U256::from(1).into(),
1143 B256::ZERO,
1144 U256::from(1).into(),
1145 U256::from(1).into()
1146 ]
1147 );
1148 }
1149 _ => unreachable!(),
1150 };
1151 }
1152
1153 #[test]
1154 fn parse_call_data() {
1155 let args: Cast = Cast::parse_from([
1156 "foundry-cli",
1157 "calldata",
1158 "f()",
1159 "5c9d55b78febcc2061715ba4f57ecf8ea2711f2c",
1160 "2",
1161 ]);
1162 match args.cmd {
1163 CastSubcommand::CalldataEncode { args, .. } => {
1164 assert_eq!(
1165 args,
1166 vec!["5c9d55b78febcc2061715ba4f57ecf8ea2711f2c".to_string(), "2".to_string()]
1167 )
1168 }
1169 _ => unreachable!(),
1170 };
1171 }
1172
1173 #[test]
1174 fn parse_call_data_with_file() {
1175 let args: Cast = Cast::parse_from(["foundry-cli", "calldata", "f()", "--file", "test.txt"]);
1176 match args.cmd {
1177 CastSubcommand::CalldataEncode { sig, file, args } => {
1178 assert_eq!(sig, "f()".to_string());
1179 assert_eq!(file, Some(PathBuf::from("test.txt")));
1180 assert!(args.is_empty());
1181 }
1182 _ => unreachable!(),
1183 };
1184 }
1185
1186 #[test]
1188 fn parse_signature() {
1189 let args: Cast = Cast::parse_from([
1190 "foundry-cli",
1191 "sig",
1192 "__$_$__$$$$$__$$_$$$_$$__$$___$$(address,address,uint256)",
1193 ]);
1194 match args.cmd {
1195 CastSubcommand::Sig { sig, .. } => {
1196 let sig = sig.unwrap();
1197 assert_eq!(
1198 sig,
1199 "__$_$__$$$$$__$$_$$$_$$__$$___$$(address,address,uint256)".to_string()
1200 );
1201
1202 let selector = SimpleCast::get_selector(&sig, 0).unwrap();
1203 assert_eq!(selector.0, "0x23b872dd".to_string());
1204 }
1205 _ => unreachable!(),
1206 };
1207 }
1208
1209 #[test]
1210 fn parse_block_ids() {
1211 struct TestCase {
1212 input: String,
1213 expect: BlockId,
1214 }
1215
1216 let test_cases = [
1217 TestCase {
1218 input: "0".to_string(),
1219 expect: BlockId::Number(BlockNumberOrTag::Number(0u64)),
1220 },
1221 TestCase {
1222 input: "0x56462c47c03df160f66819f0a79ea07def1569f8aac0fe91bb3a081159b61b4a"
1223 .to_string(),
1224 expect: BlockId::Hash(RpcBlockHash::from_hash(
1225 "0x56462c47c03df160f66819f0a79ea07def1569f8aac0fe91bb3a081159b61b4a"
1226 .parse()
1227 .unwrap(),
1228 None,
1229 )),
1230 },
1231 TestCase {
1232 input: "latest".to_string(),
1233 expect: BlockId::Number(BlockNumberOrTag::Latest),
1234 },
1235 TestCase {
1236 input: "earliest".to_string(),
1237 expect: BlockId::Number(BlockNumberOrTag::Earliest),
1238 },
1239 TestCase {
1240 input: "pending".to_string(),
1241 expect: BlockId::Number(BlockNumberOrTag::Pending),
1242 },
1243 TestCase { input: "safe".to_string(), expect: BlockId::Number(BlockNumberOrTag::Safe) },
1244 TestCase {
1245 input: "finalized".to_string(),
1246 expect: BlockId::Number(BlockNumberOrTag::Finalized),
1247 },
1248 ];
1249
1250 for test in test_cases {
1251 let result: BlockId = test.input.parse().unwrap();
1252 assert_eq!(result, test.expect);
1253 }
1254 }
1255}