1use crate::cmd::{
2 access_list::AccessListArgs, artifact::ArtifactArgs, b2e_payload::B2EPayloadArgs,
3 bind::BindArgs, call::CallArgs, constructor_args::ConstructorArgsArgs, create2::Create2Args,
4 creation_code::CreationCodeArgs, da_estimate::DAEstimateArgs, estimate::EstimateArgs,
5 find_block::FindBlockArgs, interface::InterfaceArgs, logs::LogsArgs, mktx::MakeTxArgs,
6 rpc::RpcArgs, run::RunArgs, send::SendTxArgs, storage::StorageArgs, txpool::TxPoolSubcommands,
7 wallet::WalletSubcommands,
8};
9use alloy_ens::NameOrAddress;
10use alloy_primitives::{Address, B256, Selector, U256};
11use alloy_rpc_types::BlockId;
12use clap::{Parser, Subcommand, ValueHint};
13use eyre::Result;
14use foundry_cli::opts::{EtherscanOpts, GlobalArgs, RpcOpts};
15use foundry_common::version::{LONG_VERSION, SHORT_VERSION};
16use std::{path::PathBuf, str::FromStr};
17
18#[derive(Parser)]
20#[command(
21 name = "cast",
22 version = SHORT_VERSION,
23 long_version = LONG_VERSION,
24 after_help = "Find more information in the book: https://getfoundry.sh/cast/overview",
25 next_display_order = None,
26)]
27pub struct Cast {
28 #[command(flatten)]
30 pub global: GlobalArgs,
31
32 #[command(subcommand)]
33 pub cmd: CastSubcommand,
34}
35
36#[derive(Subcommand)]
37pub enum CastSubcommand {
38 #[command(visible_aliases = &["--max-int", "maxi"])]
40 MaxInt {
41 #[arg(default_value = "int256")]
43 r#type: String,
44 },
45
46 #[command(visible_aliases = &["--min-int", "mini"])]
48 MinInt {
49 #[arg(default_value = "int256")]
51 r#type: String,
52 },
53
54 #[command(visible_aliases = &["--max-uint", "maxu"])]
56 MaxUint {
57 #[arg(default_value = "uint256")]
59 r#type: String,
60 },
61
62 #[command(visible_aliases = &["--address-zero", "az"])]
64 AddressZero,
65
66 #[command(visible_aliases = &["--hash-zero", "hz"])]
68 HashZero,
69
70 #[command(
72 visible_aliases = &[
73 "--from-ascii",
74 "--from-utf8",
75 "from-ascii",
76 "fu",
77 "fa"]
78 )]
79 FromUtf8 {
80 text: Option<String>,
82 },
83
84 #[command(visible_aliases = &["--concat-hex", "ch"])]
86 ConcatHex {
87 data: Vec<String>,
89 },
90
91 #[command(visible_aliases = &["--from-bin", "from-binx", "fb"])]
93 FromBin,
94
95 #[command(visible_aliases = &["--to-hexdata", "thd", "2hd"])]
103 ToHexdata {
104 input: Option<String>,
106 },
107
108 #[command(
110 visible_aliases = &["--to-checksum-address",
111 "--to-checksum",
112 "to-checksum",
113 "ta",
114 "2a"]
115 )]
116 ToCheckSumAddress {
117 address: Option<Address>,
119 chain_id: Option<u64>,
121 },
122
123 #[command(visible_aliases = &["--to-ascii", "tas", "2as"])]
125 ToAscii {
126 hexdata: Option<String>,
128 },
129
130 #[command(visible_aliases = &["--to-utf8", "tu8", "2u8"])]
132 ToUtf8 {
133 hexdata: Option<String>,
135 },
136
137 #[command(visible_aliases = &["--from-fix", "ff"])]
139 FromFixedPoint {
140 decimals: Option<String>,
142
143 #[arg(allow_hyphen_values = true)]
145 value: Option<String>,
146 },
147
148 #[command(visible_aliases = &["--to-bytes32", "tb", "2b"])]
150 ToBytes32 {
151 bytes: Option<String>,
153 },
154
155 #[command(visible_aliases = &["pd"])]
157 Pad {
158 data: Option<String>,
160
161 #[arg(long)]
163 right: bool,
164
165 #[arg(long, conflicts_with = "right")]
167 left: bool,
168
169 #[arg(long, default_value = "32")]
171 len: usize,
172 },
173
174 #[command(visible_aliases = &["--to-fix", "tf", "2f"])]
176 ToFixedPoint {
177 decimals: Option<String>,
179
180 #[arg(allow_hyphen_values = true)]
182 value: Option<String>,
183 },
184
185 #[command(name = "to-uint256", visible_aliases = &["--to-uint256", "tu", "2u"])]
187 ToUint256 {
188 value: Option<String>,
190 },
191
192 #[command(name = "to-int256", visible_aliases = &["--to-int256", "ti", "2i"])]
194 ToInt256 {
195 value: Option<String>,
197 },
198
199 #[command(name = "shl")]
201 LeftShift {
202 value: String,
204
205 bits: String,
207
208 #[arg(long)]
210 base_in: Option<String>,
211
212 #[arg(long, default_value = "16")]
214 base_out: String,
215 },
216
217 #[command(name = "shr")]
219 RightShift {
220 value: String,
222
223 bits: String,
225
226 #[arg(long)]
228 base_in: Option<String>,
229
230 #[arg(long, default_value = "16")]
232 base_out: String,
233 },
234
235 #[command(visible_aliases = &["--to-unit", "tun", "2un"])]
244 ToUnit {
245 value: Option<String>,
247
248 #[arg(default_value = "wei")]
250 unit: String,
251 },
252
253 #[command(visible_aliases = &["--parse-units", "pun"])]
260 ParseUnits {
261 value: Option<String>,
263
264 #[arg(default_value = "18")]
266 unit: u8,
267 },
268
269 #[command(visible_aliases = &["--format-units", "fun"])]
276 FormatUnits {
277 value: Option<String>,
279
280 #[arg(default_value = "18")]
282 unit: u8,
283 },
284
285 #[command(visible_aliases = &["--to-wei", "tw", "2w"])]
289 ToWei {
290 #[arg(allow_hyphen_values = true)]
292 value: Option<String>,
293
294 #[arg(default_value = "eth")]
296 unit: String,
297 },
298
299 #[command(visible_aliases = &["--from-wei", "fw"])]
303 FromWei {
304 #[arg(allow_hyphen_values = true)]
306 value: Option<String>,
307
308 #[arg(default_value = "eth")]
310 unit: String,
311 },
312
313 #[command(visible_aliases = &["--to-rlp"])]
324 ToRlp {
325 value: Option<String>,
330 },
331
332 #[command(visible_aliases = &["--from-rlp"])]
334 FromRlp {
335 value: Option<String>,
337
338 #[arg(long, alias = "int")]
340 as_int: bool,
341 },
342
343 #[command(visible_aliases = &["--to-hex", "th", "2h"])]
345 ToHex(ToBaseArgs),
346
347 #[command(visible_aliases = &["--to-dec", "td", "2d"])]
349 ToDec(ToBaseArgs),
350
351 #[command(
353 visible_aliases = &["--to-base",
354 "--to-radix",
355 "to-radix",
356 "tr",
357 "2r"]
358 )]
359 ToBase {
360 #[command(flatten)]
361 base: ToBaseArgs,
362
363 #[arg(value_name = "BASE")]
365 base_out: Option<String>,
366 },
367 #[command(visible_aliases = &["ac", "acl"])]
369 AccessList(AccessListArgs),
370 #[command(visible_alias = "l")]
372 Logs(LogsArgs),
373 #[command(visible_alias = "bl")]
375 Block {
376 block: Option<BlockId>,
380
381 #[arg(long, short)]
383 field: Option<String>,
384
385 #[arg(long, conflicts_with = "field")]
387 raw: bool,
388
389 #[arg(long, env = "CAST_FULL_BLOCK")]
390 full: bool,
391
392 #[command(flatten)]
393 rpc: RpcOpts,
394 },
395
396 #[command(visible_alias = "bn")]
398 BlockNumber {
399 block: Option<BlockId>,
401 #[command(flatten)]
402 rpc: RpcOpts,
403 },
404
405 #[command(visible_alias = "c")]
407 Call(CallArgs),
408
409 #[command(name = "calldata", visible_alias = "cd")]
411 CalldataEncode {
412 sig: String,
414
415 #[arg(allow_hyphen_values = true)]
417 args: Vec<String>,
418
419 #[arg(long, value_name = "PATH")]
421 file: Option<PathBuf>,
422 },
423
424 Chain {
426 #[command(flatten)]
427 rpc: RpcOpts,
428 },
429
430 #[command(visible_aliases = &["ci", "cid"])]
432 ChainId {
433 #[command(flatten)]
434 rpc: RpcOpts,
435 },
436
437 #[command(visible_alias = "cl")]
439 Client {
440 #[command(flatten)]
441 rpc: RpcOpts,
442 },
443
444 #[command(visible_alias = "ca")]
446 ComputeAddress {
447 address: Option<Address>,
449
450 #[arg(
452 long,
453 conflicts_with = "salt",
454 conflicts_with = "init_code",
455 conflicts_with = "init_code_hash"
456 )]
457 nonce: Option<u64>,
458
459 #[arg(long, conflicts_with = "nonce")]
461 salt: Option<B256>,
462
463 #[arg(
465 long,
466 requires = "salt",
467 conflicts_with = "init_code_hash",
468 conflicts_with = "nonce"
469 )]
470 init_code: Option<String>,
471
472 #[arg(long, requires = "salt", conflicts_with = "init_code", conflicts_with = "nonce")]
474 init_code_hash: Option<B256>,
475
476 #[command(flatten)]
477 rpc: RpcOpts,
478 },
479
480 #[command(visible_alias = "da")]
482 Disassemble {
483 bytecode: Option<String>,
485 },
486
487 #[command(name = "mktx", visible_alias = "m")]
489 MakeTx(MakeTxArgs),
490
491 #[command(visible_aliases = &["na", "nh"])]
493 Namehash { name: Option<String> },
494
495 #[command(visible_alias = "t")]
497 Tx {
498 tx_hash: Option<String>,
500
501 #[arg(long, value_parser = NameOrAddress::from_str)]
503 from: Option<NameOrAddress>,
504
505 #[arg(long)]
507 nonce: Option<u64>,
508
509 field: Option<String>,
512
513 #[arg(long, conflicts_with = "field")]
515 raw: bool,
516
517 #[command(flatten)]
518 rpc: RpcOpts,
519
520 #[arg(long)]
522 to_request: bool,
523 },
524
525 #[command(visible_alias = "re")]
527 Receipt {
528 tx_hash: String,
530
531 field: Option<String>,
533
534 #[arg(long, default_value = "1")]
536 confirmations: u64,
537
538 #[arg(id = "async", long = "async", env = "CAST_ASYNC", alias = "cast-async")]
540 cast_async: bool,
541
542 #[command(flatten)]
543 rpc: RpcOpts,
544 },
545
546 #[command(name = "send", visible_alias = "s")]
548 SendTx(SendTxArgs),
549
550 #[command(name = "publish", visible_alias = "p")]
552 PublishTx {
553 raw_tx: String,
555
556 #[arg(id = "async", long = "async", env = "CAST_ASYNC", alias = "cast-async")]
558 cast_async: bool,
559
560 #[command(flatten)]
561 rpc: RpcOpts,
562 },
563
564 #[command(visible_alias = "e")]
566 Estimate(EstimateArgs),
567
568 #[command(visible_aliases = &["calldata-decode", "--calldata-decode", "cdd"])]
573 DecodeCalldata {
574 sig: String,
576
577 #[arg(required_unless_present = "file", index = 2)]
579 calldata: Option<String>,
580
581 #[arg(long = "file", short = 'f', conflicts_with = "calldata")]
583 file: Option<PathBuf>,
584 },
585
586 #[command(visible_aliases = &["string-decode", "--string-decode", "sd"])]
590 DecodeString {
591 data: String,
593 },
594
595 #[command(visible_aliases = &["event-decode", "--event-decode", "ed"])]
597 DecodeEvent {
598 #[arg(long, visible_alias = "event-sig")]
600 sig: Option<String>,
601 data: String,
603 },
604
605 #[command(visible_aliases = &["error-decode", "--error-decode", "erd"])]
607 DecodeError {
608 #[arg(long, visible_alias = "error-sig")]
610 sig: Option<String>,
611 data: String,
613 },
614
615 #[command(name = "decode-abi", visible_aliases = &["abi-decode", "--abi-decode", "ad"])]
621 DecodeAbi {
622 sig: String,
624
625 calldata: String,
627
628 #[arg(long, short, help_heading = "Decode input data instead of output data")]
630 input: bool,
631 },
632
633 #[command(visible_alias = "ae")]
635 AbiEncode {
636 sig: String,
638
639 #[arg(long)]
641 packed: bool,
642
643 #[arg(allow_hyphen_values = true)]
645 args: Vec<String>,
646 },
647
648 #[command(visible_alias = "aee")]
650 AbiEncodeEvent {
651 sig: String,
653
654 #[arg(allow_hyphen_values = true)]
656 args: Vec<String>,
657 },
658
659 #[command(visible_alias = "in")]
661 Index {
662 key_type: String,
664
665 key: String,
667
668 slot_number: String,
670 },
671
672 #[command(name = "index-erc7201", alias = "index-erc-7201", visible_aliases = &["index7201", "in7201"])]
674 IndexErc7201 {
675 id: Option<String>,
677 #[arg(long, default_value = "erc7201")]
679 formula_id: String,
680 },
681
682 #[command(visible_alias = "impl")]
685 Implementation {
686 #[arg(long, short = 'B')]
690 block: Option<BlockId>,
691
692 #[arg(long)]
696 beacon: bool,
697
698 #[arg(value_parser = NameOrAddress::from_str)]
700 who: NameOrAddress,
701
702 #[command(flatten)]
703 rpc: RpcOpts,
704 },
705
706 #[command(visible_alias = "adm")]
708 Admin {
709 #[arg(long, short = 'B')]
713 block: Option<BlockId>,
714
715 #[arg(value_parser = NameOrAddress::from_str)]
717 who: NameOrAddress,
718
719 #[command(flatten)]
720 rpc: RpcOpts,
721 },
722
723 #[command(name = "4byte", visible_aliases = &["4", "4b"])]
725 FourByte {
726 selector: Option<Selector>,
728 },
729
730 #[command(name = "4byte-calldata", aliases = &["4byte-decode", "4d", "4bd"], visible_aliases = &["4c", "4bc"])]
732 FourByteCalldata {
733 calldata: Option<String>,
735 },
736
737 #[command(name = "4byte-event", visible_aliases = &["4e", "4be", "topic0-event", "t0e"])]
739 FourByteEvent {
740 #[arg(value_name = "TOPIC_0")]
742 topic: Option<B256>,
743 },
744
745 #[command(visible_aliases = &["ups"])]
753 UploadSignature {
754 signatures: Vec<String>,
759 },
760
761 #[command(visible_alias = "pc")]
765 PrettyCalldata {
766 calldata: Option<String>,
768
769 #[arg(long, short)]
771 offline: bool,
772 },
773
774 #[command(visible_alias = "a")]
776 Age {
777 block: Option<BlockId>,
781
782 #[command(flatten)]
783 rpc: RpcOpts,
784 },
785
786 #[command(visible_alias = "b")]
788 Balance {
789 #[arg(long, short = 'B')]
793 block: Option<BlockId>,
794
795 #[arg(value_parser = NameOrAddress::from_str)]
797 who: NameOrAddress,
798
799 #[arg(long, short)]
801 ether: bool,
802
803 #[command(flatten)]
804 rpc: RpcOpts,
805
806 #[arg(long, alias = "erc721")]
809 erc20: Option<Address>,
810 },
811
812 #[command(visible_aliases = &["ba", "fee", "basefee"])]
814 BaseFee {
815 block: Option<BlockId>,
819
820 #[command(flatten)]
821 rpc: RpcOpts,
822 },
823
824 #[command(visible_alias = "co")]
826 Code {
827 #[arg(long, short = 'B')]
831 block: Option<BlockId>,
832
833 #[arg(value_parser = NameOrAddress::from_str)]
835 who: NameOrAddress,
836
837 #[arg(long, short)]
839 disassemble: bool,
840
841 #[command(flatten)]
842 rpc: RpcOpts,
843 },
844
845 #[command(visible_alias = "cs")]
847 Codesize {
848 #[arg(long, short = 'B')]
852 block: Option<BlockId>,
853
854 #[arg(value_parser = NameOrAddress::from_str)]
856 who: NameOrAddress,
857
858 #[command(flatten)]
859 rpc: RpcOpts,
860 },
861
862 #[command(visible_alias = "g")]
864 GasPrice {
865 #[command(flatten)]
866 rpc: RpcOpts,
867 },
868
869 #[command(visible_alias = "se")]
871 SigEvent {
872 event_string: Option<String>,
874 },
875
876 #[command(visible_aliases = &["k", "keccak256"])]
878 Keccak {
879 data: Option<String>,
881 },
882
883 #[command(visible_aliases = &["--hash-message", "hm"])]
885 HashMessage {
886 message: Option<String>,
888 },
889
890 #[command(visible_alias = "rn")]
892 ResolveName {
893 who: Option<String>,
895
896 #[arg(long)]
898 verify: bool,
899
900 #[command(flatten)]
901 rpc: RpcOpts,
902 },
903
904 #[command(visible_alias = "la")]
906 LookupAddress {
907 who: Option<Address>,
909
910 #[arg(long)]
912 verify: bool,
913
914 #[command(flatten)]
915 rpc: RpcOpts,
916 },
917
918 #[command(visible_alias = "st")]
920 Storage(StorageArgs),
921
922 #[command(visible_alias = "pr")]
924 Proof {
925 #[arg(value_parser = NameOrAddress::from_str)]
927 address: NameOrAddress,
928
929 #[arg(value_parser = parse_slot)]
931 slots: Vec<B256>,
932
933 #[arg(long, short = 'B')]
937 block: Option<BlockId>,
938
939 #[command(flatten)]
940 rpc: RpcOpts,
941 },
942
943 #[command(visible_alias = "n")]
945 Nonce {
946 #[arg(long, short = 'B')]
950 block: Option<BlockId>,
951
952 #[arg(value_parser = NameOrAddress::from_str)]
954 who: NameOrAddress,
955
956 #[command(flatten)]
957 rpc: RpcOpts,
958 },
959
960 #[command()]
962 Codehash {
963 #[arg(long, short = 'B')]
967 block: Option<BlockId>,
968
969 #[arg(value_parser = NameOrAddress::from_str)]
971 who: NameOrAddress,
972
973 #[arg(value_parser = parse_slot)]
975 slots: Vec<B256>,
976
977 #[command(flatten)]
978 rpc: RpcOpts,
979 },
980
981 #[command(visible_alias = "sr")]
983 StorageRoot {
984 #[arg(long, short = 'B')]
988 block: Option<BlockId>,
989
990 #[arg(value_parser = NameOrAddress::from_str)]
992 who: NameOrAddress,
993
994 #[arg(value_parser = parse_slot)]
996 slots: Vec<B256>,
997
998 #[command(flatten)]
999 rpc: RpcOpts,
1000 },
1001
1002 #[command(visible_aliases = &["et", "src"])]
1004 Source {
1005 address: String,
1007
1008 #[arg(long, short)]
1010 flatten: bool,
1011
1012 #[arg(short, value_hint = ValueHint::DirPath, alias = "path")]
1014 directory: Option<PathBuf>,
1015
1016 #[command(flatten)]
1017 etherscan: EtherscanOpts,
1018
1019 #[arg(long, env = "EXPLORER_API_URL")]
1022 explorer_api_url: Option<String>,
1023
1024 #[arg(long, env = "EXPLORER_URL")]
1026 explorer_url: Option<String>,
1027 },
1028
1029 #[command(visible_alias = "w")]
1031 Wallet {
1032 #[command(subcommand)]
1033 command: WalletSubcommands,
1034 },
1035
1036 #[command(visible_alias = "cc")]
1038 CreationCode(CreationCodeArgs),
1039
1040 #[command(visible_alias = "ar")]
1042 Artifact(ArtifactArgs),
1043
1044 #[command(visible_alias = "cra")]
1046 ConstructorArgs(ConstructorArgsArgs),
1047
1048 #[command(visible_alias = "i")]
1052 Interface(InterfaceArgs),
1053
1054 #[command(visible_alias = "bi")]
1056 Bind(BindArgs),
1057
1058 #[command(visible_alias = "b2e")]
1060 B2EPayload(B2EPayloadArgs),
1061
1062 #[command(visible_alias = "si")]
1064 Sig {
1065 sig: Option<String>,
1067
1068 optimize: Option<usize>,
1070 },
1071
1072 #[command(visible_alias = "c2")]
1074 Create2(Create2Args),
1075
1076 #[command(visible_alias = "f")]
1078 FindBlock(FindBlockArgs),
1079
1080 #[command(visible_alias = "com")]
1082 Completions {
1083 #[arg(value_enum)]
1084 shell: foundry_cli::clap::Shell,
1085 },
1086
1087 #[command(visible_alias = "r")]
1089 Run(RunArgs),
1090
1091 #[command(visible_alias = "rp")]
1093 Rpc(RpcArgs),
1094
1095 #[command(name = "format-bytes32-string", visible_aliases = &["--format-bytes32-string"])]
1097 FormatBytes32String {
1098 string: Option<String>,
1100 },
1101
1102 #[command(name = "parse-bytes32-string", visible_aliases = &["--parse-bytes32-string"])]
1104 ParseBytes32String {
1105 bytes: Option<String>,
1107 },
1108 #[command(name = "parse-bytes32-address", visible_aliases = &["--parse-bytes32-address"])]
1109 #[command(about = "Parses a checksummed address from bytes32 encoding.")]
1110 ParseBytes32Address {
1111 #[arg(value_name = "BYTES")]
1112 bytes: Option<String>,
1113 },
1114
1115 #[command(visible_aliases = &["dt", "decode-tx"])]
1117 DecodeTransaction { tx: Option<String> },
1118
1119 #[command(visible_aliases = &["decode-auth"])]
1121 RecoverAuthority { auth: String },
1122
1123 #[command(visible_alias = "sel")]
1125 Selectors {
1126 bytecode: Option<String>,
1128
1129 #[arg(long, short)]
1131 resolve: bool,
1132 },
1133
1134 #[command(visible_alias = "tp")]
1136 TxPool {
1137 #[command(subcommand)]
1138 command: TxPoolSubcommands,
1139 },
1140 #[command(name = "da-estimate")]
1142 DAEstimate(DAEstimateArgs),
1143}
1144
1145#[derive(Debug, Parser)]
1147pub struct ToBaseArgs {
1148 #[arg(allow_hyphen_values = true)]
1150 pub value: Option<String>,
1151
1152 #[arg(long, short = 'i')]
1154 pub base_in: Option<String>,
1155}
1156
1157pub fn parse_slot(s: &str) -> Result<B256> {
1158 let slot = U256::from_str(s).map_err(|e| eyre::eyre!("Could not parse slot number: {e}"))?;
1159 Ok(B256::from(slot))
1160}
1161
1162#[cfg(test)]
1163mod tests {
1164 use super::*;
1165 use crate::SimpleCast;
1166 use alloy_rpc_types::{BlockNumberOrTag, RpcBlockHash};
1167 use clap::CommandFactory;
1168
1169 #[test]
1170 fn verify_cli() {
1171 Cast::command().debug_assert();
1172 }
1173
1174 #[test]
1175 fn parse_proof_slot() {
1176 let args: Cast = Cast::parse_from([
1177 "foundry-cli",
1178 "proof",
1179 "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
1180 "0",
1181 "1",
1182 "0x0000000000000000000000000000000000000000000000000000000000000000",
1183 "0x1",
1184 "0x01",
1185 ]);
1186 match args.cmd {
1187 CastSubcommand::Proof { slots, .. } => {
1188 assert_eq!(
1189 slots,
1190 vec![
1191 B256::ZERO,
1192 U256::from(1).into(),
1193 B256::ZERO,
1194 U256::from(1).into(),
1195 U256::from(1).into()
1196 ]
1197 );
1198 }
1199 _ => unreachable!(),
1200 };
1201 }
1202
1203 #[test]
1204 fn parse_call_data() {
1205 let args: Cast = Cast::parse_from([
1206 "foundry-cli",
1207 "calldata",
1208 "f()",
1209 "5c9d55b78febcc2061715ba4f57ecf8ea2711f2c",
1210 "2",
1211 ]);
1212 match args.cmd {
1213 CastSubcommand::CalldataEncode { args, .. } => {
1214 assert_eq!(
1215 args,
1216 vec!["5c9d55b78febcc2061715ba4f57ecf8ea2711f2c".to_string(), "2".to_string()]
1217 )
1218 }
1219 _ => unreachable!(),
1220 };
1221 }
1222
1223 #[test]
1224 fn parse_call_data_with_file() {
1225 let args: Cast = Cast::parse_from(["foundry-cli", "calldata", "f()", "--file", "test.txt"]);
1226 match args.cmd {
1227 CastSubcommand::CalldataEncode { sig, file, args } => {
1228 assert_eq!(sig, "f()".to_string());
1229 assert_eq!(file, Some(PathBuf::from("test.txt")));
1230 assert!(args.is_empty());
1231 }
1232 _ => unreachable!(),
1233 };
1234 }
1235
1236 #[test]
1238 fn parse_signature() {
1239 let args: Cast = Cast::parse_from([
1240 "foundry-cli",
1241 "sig",
1242 "__$_$__$$$$$__$$_$$$_$$__$$___$$(address,address,uint256)",
1243 ]);
1244 match args.cmd {
1245 CastSubcommand::Sig { sig, .. } => {
1246 let sig = sig.unwrap();
1247 assert_eq!(
1248 sig,
1249 "__$_$__$$$$$__$$_$$$_$$__$$___$$(address,address,uint256)".to_string()
1250 );
1251
1252 let selector = SimpleCast::get_selector(&sig, 0).unwrap();
1253 assert_eq!(selector.0, "0x23b872dd".to_string());
1254 }
1255 _ => unreachable!(),
1256 };
1257 }
1258
1259 #[test]
1260 fn parse_block_ids() {
1261 struct TestCase {
1262 input: String,
1263 expect: BlockId,
1264 }
1265
1266 let test_cases = [
1267 TestCase {
1268 input: "0".to_string(),
1269 expect: BlockId::Number(BlockNumberOrTag::Number(0u64)),
1270 },
1271 TestCase {
1272 input: "0x56462c47c03df160f66819f0a79ea07def1569f8aac0fe91bb3a081159b61b4a"
1273 .to_string(),
1274 expect: BlockId::Hash(RpcBlockHash::from_hash(
1275 "0x56462c47c03df160f66819f0a79ea07def1569f8aac0fe91bb3a081159b61b4a"
1276 .parse()
1277 .unwrap(),
1278 None,
1279 )),
1280 },
1281 TestCase {
1282 input: "latest".to_string(),
1283 expect: BlockId::Number(BlockNumberOrTag::Latest),
1284 },
1285 TestCase {
1286 input: "earliest".to_string(),
1287 expect: BlockId::Number(BlockNumberOrTag::Earliest),
1288 },
1289 TestCase {
1290 input: "pending".to_string(),
1291 expect: BlockId::Number(BlockNumberOrTag::Pending),
1292 },
1293 TestCase { input: "safe".to_string(), expect: BlockId::Number(BlockNumberOrTag::Safe) },
1294 TestCase {
1295 input: "finalized".to_string(),
1296 expect: BlockId::Number(BlockNumberOrTag::Finalized),
1297 },
1298 ];
1299
1300 for test in test_cases {
1301 let result: BlockId = test.input.parse().unwrap();
1302 assert_eq!(result, test.expect);
1303 }
1304 }
1305}