1use crate::cmd::{
2 access_list::AccessListArgs, artifact::ArtifactArgs, b2e_payload::B2EPayloadArgs,
3 batch_mktx::BatchMakeTxArgs, batch_send::BatchSendArgs, bind::BindArgs, call::CallArgs,
4 constructor_args::ConstructorArgsArgs, create2::Create2Args, creation_code::CreationCodeArgs,
5 da_estimate::DAEstimateArgs, erc20::Erc20Subcommand, estimate::EstimateArgs,
6 find_block::FindBlockArgs, interface::InterfaceArgs, keychain::KeychainSubcommand,
7 logs::LogsArgs, mktx::MakeTxArgs, rpc::RpcArgs, run::RunArgs, send::SendTxArgs,
8 storage::StorageArgs, tip20::Tip20Subcommand, trace::TraceArgs, txpool::TxPoolSubcommands,
9 wallet::WalletSubcommands,
10};
11use alloy_ens::NameOrAddress;
12use alloy_primitives::{Address, B256, Selector, U256};
13use alloy_rpc_types::BlockId;
14use clap::{ArgAction, Parser, Subcommand, ValueHint};
15use eyre::Result;
16use foundry_cli::opts::{EtherscanOpts, GlobalArgs, NetworkVariant, RpcOpts};
17use foundry_common::version::{LONG_VERSION, SHORT_VERSION};
18use std::{path::PathBuf, str::FromStr};
19#[derive(Parser)]
21#[command(
22 name = "cast",
23 version = SHORT_VERSION,
24 long_version = LONG_VERSION,
25 after_help = "Find more information in the book: https://getfoundry.sh/cast/overview",
26 next_display_order = None,
27)]
28pub struct Cast {
29 #[command(flatten)]
31 pub global: GlobalArgs,
32
33 #[command(subcommand)]
34 pub cmd: CastSubcommand,
35}
36
37#[derive(Subcommand)]
38pub enum CastSubcommand {
39 #[command(visible_aliases = &["--max-int", "maxi"])]
41 MaxInt {
42 #[arg(default_value = "int256")]
44 r#type: String,
45 },
46
47 #[command(visible_aliases = &["--min-int", "mini"])]
49 MinInt {
50 #[arg(default_value = "int256")]
52 r#type: String,
53 },
54
55 #[command(visible_aliases = &["--max-uint", "maxu"])]
57 MaxUint {
58 #[arg(default_value = "uint256")]
60 r#type: String,
61 },
62
63 #[command(visible_aliases = &["--address-zero", "az"])]
65 AddressZero,
66
67 #[command(visible_aliases = &["--hash-zero", "hz"])]
69 HashZero,
70
71 #[command(
73 visible_aliases = &[
74 "--from-ascii",
75 "--from-utf8",
76 "from-ascii",
77 "fu",
78 "fa"]
79 )]
80 FromUtf8 {
81 text: Option<String>,
83 },
84
85 #[command(visible_aliases = &["--concat-hex", "ch"])]
87 ConcatHex {
88 data: Vec<String>,
90 },
91
92 #[command(visible_aliases = &["--from-bin", "from-binx", "fb"])]
94 FromBin,
95
96 #[command(visible_aliases = &["--to-hexdata", "thd", "2hd"])]
104 ToHexdata {
105 input: Option<String>,
107 },
108
109 #[command(
111 visible_aliases = &["--to-checksum-address",
112 "--to-checksum",
113 "to-checksum",
114 "ta",
115 "2a"]
116 )]
117 ToCheckSumAddress {
118 address: Option<Address>,
120 chain_id: Option<u64>,
122 },
123
124 #[command(visible_aliases = &["--to-ascii", "tas", "2as"])]
126 ToAscii {
127 hexdata: Option<String>,
129 },
130
131 #[command(visible_aliases = &["--to-utf8", "tu8", "2u8"])]
133 ToUtf8 {
134 hexdata: Option<String>,
136 },
137
138 #[command(visible_aliases = &["--from-fix", "ff"])]
140 FromFixedPoint {
141 decimals: Option<String>,
143
144 #[arg(allow_hyphen_values = true)]
146 value: Option<String>,
147 },
148
149 #[command(visible_aliases = &["--to-bytes32", "tb", "2b"])]
151 ToBytes32 {
152 bytes: Option<String>,
154 },
155
156 #[command(visible_aliases = &["pd"])]
158 Pad {
159 data: Option<String>,
161
162 #[arg(long)]
164 right: bool,
165
166 #[arg(long, conflicts_with = "right")]
168 left: bool,
169
170 #[arg(long, default_value = "32")]
172 len: usize,
173 },
174
175 #[command(visible_aliases = &["--to-fix", "tf", "2f"])]
177 ToFixedPoint {
178 decimals: Option<String>,
180
181 #[arg(allow_hyphen_values = true)]
183 value: Option<String>,
184 },
185
186 #[command(name = "to-uint256", visible_aliases = &["--to-uint256", "tu", "2u"])]
188 ToUint256 {
189 value: Option<String>,
191 },
192
193 #[command(name = "to-int256", visible_aliases = &["--to-int256", "ti", "2i"])]
195 ToInt256 {
196 value: Option<String>,
198 },
199
200 #[command(name = "shl")]
202 LeftShift {
203 value: String,
205
206 bits: String,
208
209 #[arg(long)]
211 base_in: Option<String>,
212
213 #[arg(long, default_value = "16")]
215 base_out: String,
216 },
217
218 #[command(name = "shr")]
220 RightShift {
221 value: String,
223
224 bits: String,
226
227 #[arg(long)]
229 base_in: Option<String>,
230
231 #[arg(long, default_value = "16")]
233 base_out: String,
234 },
235
236 #[command(visible_aliases = &["--to-unit", "tun", "2un"])]
245 ToUnit {
246 value: Option<String>,
248
249 #[arg(default_value = "wei")]
251 unit: String,
252 },
253
254 #[command(visible_aliases = &["--parse-units", "pun"])]
261 ParseUnits {
262 value: Option<String>,
264
265 #[arg(default_value = "18")]
267 unit: u8,
268 },
269
270 #[command(visible_aliases = &["--format-units", "fun"])]
277 FormatUnits {
278 value: Option<String>,
280
281 #[arg(default_value = "18")]
283 unit: u8,
284 },
285
286 #[command(visible_aliases = &["--to-wei", "tw", "2w"])]
290 ToWei {
291 #[arg(allow_hyphen_values = true)]
293 value: Option<String>,
294
295 #[arg(default_value = "eth")]
297 unit: String,
298 },
299
300 #[command(visible_aliases = &["--from-wei", "fw"])]
304 FromWei {
305 #[arg(allow_hyphen_values = true)]
307 value: Option<String>,
308
309 #[arg(default_value = "eth")]
311 unit: String,
312 },
313
314 #[command(visible_aliases = &["--to-rlp"])]
325 ToRlp {
326 value: Option<String>,
331 },
332
333 #[command(visible_aliases = &["--from-rlp"])]
335 FromRlp {
336 value: Option<String>,
338
339 #[arg(long, alias = "int")]
341 as_int: bool,
342 },
343
344 #[command(visible_aliases = &["--to-hex", "th", "2h"])]
346 ToHex(ToBaseArgs),
347
348 #[command(visible_aliases = &["--to-dec", "td", "2d"])]
350 ToDec(ToBaseArgs),
351
352 #[command(
354 visible_aliases = &["--to-base",
355 "--to-radix",
356 "to-radix",
357 "tr",
358 "2r"]
359 )]
360 ToBase {
361 #[command(flatten)]
362 base: ToBaseArgs,
363
364 #[arg(value_name = "BASE")]
366 base_out: Option<String>,
367 },
368 #[command(visible_aliases = &["ac", "acl"])]
370 AccessList(AccessListArgs),
371 #[command(visible_alias = "l")]
373 Logs(LogsArgs),
374 #[command(visible_alias = "bl")]
376 Block {
377 block: Option<BlockId>,
381
382 #[arg(short, long = "field", aliases = ["fields"], num_args = 0.., action = ArgAction::Append, value_delimiter = ',')]
384 fields: Vec<String>,
385
386 #[arg(long, conflicts_with = "fields")]
388 raw: bool,
389
390 #[arg(long, env = "CAST_FULL_BLOCK")]
391 full: bool,
392
393 #[command(flatten)]
394 rpc: RpcOpts,
395
396 #[arg(long, short, num_args = 1, value_name = "NETWORK")]
398 network: Option<NetworkVariant>,
399 },
400
401 #[command(visible_alias = "bn")]
403 BlockNumber {
404 block: Option<BlockId>,
406 #[command(flatten)]
407 rpc: RpcOpts,
408 },
409
410 #[command(visible_alias = "c")]
412 Call(CallArgs),
413
414 #[command(name = "calldata", visible_alias = "cd")]
416 CalldataEncode {
417 sig: String,
419
420 #[arg(allow_hyphen_values = true)]
422 args: Vec<String>,
423
424 #[arg(long, value_name = "PATH")]
426 file: Option<PathBuf>,
427 },
428
429 Chain {
431 #[command(flatten)]
432 rpc: RpcOpts,
433 },
434
435 #[command(visible_aliases = &["ci", "cid"])]
437 ChainId {
438 #[command(flatten)]
439 rpc: RpcOpts,
440 },
441
442 #[command(visible_alias = "cl")]
444 Client {
445 #[command(flatten)]
446 rpc: RpcOpts,
447 },
448
449 #[command(visible_alias = "ca")]
451 ComputeAddress {
452 address: Option<Address>,
454
455 #[arg(
457 long,
458 conflicts_with = "salt",
459 conflicts_with = "init_code",
460 conflicts_with = "init_code_hash"
461 )]
462 nonce: Option<u64>,
463
464 #[arg(long, conflicts_with = "nonce")]
466 salt: Option<B256>,
467
468 #[arg(
470 long,
471 requires = "salt",
472 conflicts_with = "init_code_hash",
473 conflicts_with = "nonce"
474 )]
475 init_code: Option<String>,
476
477 #[arg(long, requires = "salt", conflicts_with = "init_code", conflicts_with = "nonce")]
479 init_code_hash: Option<B256>,
480
481 #[command(flatten)]
482 rpc: RpcOpts,
483 },
484
485 #[command(visible_alias = "da")]
487 Disassemble {
488 bytecode: Option<String>,
490 },
491
492 #[command(name = "mktx", visible_alias = "m")]
494 MakeTx(MakeTxArgs),
495
496 #[command(visible_aliases = &["na", "nh"])]
498 Namehash { name: Option<String> },
499
500 #[command(visible_alias = "t")]
502 Tx {
503 tx_hash: Option<String>,
505
506 #[arg(long, value_parser = NameOrAddress::from_str)]
508 from: Option<NameOrAddress>,
509
510 #[arg(long)]
512 nonce: Option<u64>,
513
514 field: Option<String>,
517
518 #[arg(long, conflicts_with = "field")]
520 raw: bool,
521
522 #[command(flatten)]
523 rpc: RpcOpts,
524
525 #[arg(long)]
527 to_request: bool,
528
529 #[arg(long, short, num_args = 1, value_name = "NETWORK")]
531 network: Option<NetworkVariant>,
532 },
533
534 #[command(visible_alias = "re")]
536 Receipt {
537 tx_hash: String,
539
540 field: Option<String>,
542
543 #[arg(long, default_value = "1")]
545 confirmations: u64,
546
547 #[arg(id = "async", long = "async", env = "CAST_ASYNC", alias = "cast-async")]
549 cast_async: bool,
550
551 #[command(flatten)]
552 rpc: RpcOpts,
553 },
554
555 #[command(name = "send", visible_alias = "s")]
557 SendTx(SendTxArgs),
558
559 #[command(name = "batch-mktx", visible_alias = "bm")]
561 BatchMakeTx(BatchMakeTxArgs),
562
563 #[command(name = "batch-send", visible_alias = "bs")]
565 BatchSend(BatchSendArgs),
566
567 #[command(name = "publish", visible_alias = "p")]
569 PublishTx {
570 raw_tx: String,
572
573 #[arg(id = "async", long = "async", env = "CAST_ASYNC", alias = "cast-async")]
575 cast_async: bool,
576
577 #[command(flatten)]
578 rpc: RpcOpts,
579 },
580
581 #[command(visible_alias = "e")]
583 Estimate(EstimateArgs),
584
585 #[command(visible_aliases = &["calldata-decode", "--calldata-decode", "cdd"])]
590 DecodeCalldata {
591 sig: String,
593
594 #[arg(required_unless_present = "file", index = 2)]
596 calldata: Option<String>,
597
598 #[arg(long = "file", short = 'f', conflicts_with = "calldata")]
600 file: Option<PathBuf>,
601 },
602
603 #[command(visible_aliases = &["string-decode", "--string-decode", "sd"])]
607 DecodeString {
608 data: String,
610 },
611
612 #[command(visible_aliases = &["event-decode", "--event-decode", "ed"])]
614 DecodeEvent {
615 #[arg(long, visible_alias = "event-sig")]
617 sig: Option<String>,
618 data: String,
620 },
621
622 #[command(visible_aliases = &["error-decode", "--error-decode", "erd"])]
624 DecodeError {
625 #[arg(long, visible_alias = "error-sig")]
627 sig: Option<String>,
628 data: String,
630 },
631
632 #[command(name = "decode-abi", visible_aliases = &["abi-decode", "--abi-decode", "ad"])]
638 DecodeAbi {
639 sig: String,
641
642 calldata: String,
644
645 #[arg(long, short, help_heading = "Decode input data instead of output data")]
647 input: bool,
648 },
649
650 #[command(visible_alias = "ae")]
652 AbiEncode {
653 sig: String,
655
656 #[arg(long)]
658 packed: bool,
659
660 #[arg(allow_hyphen_values = true)]
662 args: Vec<String>,
663 },
664
665 #[command(visible_alias = "aee")]
667 AbiEncodeEvent {
668 sig: String,
670
671 #[arg(allow_hyphen_values = true)]
673 args: Vec<String>,
674 },
675
676 #[command(visible_alias = "in")]
678 Index {
679 key_type: String,
681
682 key: String,
684
685 slot_number: String,
687 },
688
689 #[command(name = "index-erc7201", alias = "index-erc-7201", visible_aliases = &["index7201", "in7201"])]
691 IndexErc7201 {
692 id: Option<String>,
694 #[arg(long, default_value = "erc7201")]
696 formula_id: String,
697 },
698
699 #[command(visible_alias = "impl")]
702 Implementation {
703 #[arg(long, short = 'B')]
707 block: Option<BlockId>,
708
709 #[arg(long)]
713 beacon: bool,
714
715 #[arg(value_parser = NameOrAddress::from_str)]
717 who: NameOrAddress,
718
719 #[command(flatten)]
720 rpc: RpcOpts,
721 },
722
723 #[command(visible_alias = "adm")]
725 Admin {
726 #[arg(long, short = 'B')]
730 block: Option<BlockId>,
731
732 #[arg(value_parser = NameOrAddress::from_str)]
734 who: NameOrAddress,
735
736 #[command(flatten)]
737 rpc: RpcOpts,
738 },
739
740 #[command(name = "4byte", visible_aliases = &["4", "4b"])]
742 FourByte {
743 selector: Option<Selector>,
745 },
746
747 #[command(name = "4byte-calldata", aliases = &["4byte-decode", "4d", "4bd"], visible_aliases = &["4c", "4bc"])]
749 FourByteCalldata {
750 calldata: Option<String>,
752 },
753
754 #[command(name = "4byte-event", visible_aliases = &["4e", "4be", "topic0-event", "t0e"])]
756 FourByteEvent {
757 #[arg(value_name = "TOPIC_0")]
759 topic: Option<B256>,
760 },
761
762 #[command(visible_aliases = &["ups"])]
770 UploadSignature {
771 signatures: Vec<String>,
776 },
777
778 #[command(visible_alias = "pc")]
782 PrettyCalldata {
783 calldata: Option<String>,
785
786 #[arg(long, short)]
788 offline: bool,
789 },
790
791 #[command(visible_alias = "a")]
793 Age {
794 block: Option<BlockId>,
798
799 #[command(flatten)]
800 rpc: RpcOpts,
801 },
802
803 #[command(visible_alias = "b")]
805 Balance {
806 #[arg(long, short = 'B')]
810 block: Option<BlockId>,
811
812 #[arg(value_parser = NameOrAddress::from_str)]
814 who: NameOrAddress,
815
816 #[arg(long, short)]
818 ether: bool,
819
820 #[command(flatten)]
821 rpc: RpcOpts,
822
823 #[arg(long, alias = "erc721")]
826 erc20: Option<Address>,
827 },
828
829 #[command(visible_aliases = &["ba", "fee", "basefee"])]
831 BaseFee {
832 block: Option<BlockId>,
836
837 #[command(flatten)]
838 rpc: RpcOpts,
839 },
840
841 #[command(visible_alias = "co")]
843 Code {
844 #[arg(long, short = 'B')]
848 block: Option<BlockId>,
849
850 #[arg(value_parser = NameOrAddress::from_str)]
852 who: NameOrAddress,
853
854 #[arg(long, short)]
856 disassemble: bool,
857
858 #[command(flatten)]
859 rpc: RpcOpts,
860 },
861
862 #[command(visible_alias = "cs")]
864 Codesize {
865 #[arg(long, short = 'B')]
869 block: Option<BlockId>,
870
871 #[arg(value_parser = NameOrAddress::from_str)]
873 who: NameOrAddress,
874
875 #[command(flatten)]
876 rpc: RpcOpts,
877 },
878
879 #[command(visible_alias = "g")]
881 GasPrice {
882 #[command(flatten)]
883 rpc: RpcOpts,
884 },
885
886 #[command(visible_alias = "se")]
888 SigEvent {
889 event_string: Option<String>,
891 },
892
893 #[command(visible_aliases = &["k", "keccak256"])]
895 Keccak {
896 data: Option<String>,
898 },
899
900 #[command(visible_aliases = &["--hash-message", "hm"])]
902 HashMessage {
903 message: Option<String>,
905 },
906
907 #[command(visible_alias = "rn")]
909 ResolveName {
910 who: Option<String>,
912
913 #[arg(long)]
915 verify: bool,
916
917 #[command(flatten)]
918 rpc: RpcOpts,
919 },
920
921 #[command(visible_alias = "la")]
923 LookupAddress {
924 who: Option<Address>,
926
927 #[arg(long)]
929 verify: bool,
930
931 #[command(flatten)]
932 rpc: RpcOpts,
933 },
934
935 #[command(visible_alias = "st")]
937 Storage(StorageArgs),
938
939 #[command(visible_alias = "pr")]
941 Proof {
942 #[arg(value_parser = NameOrAddress::from_str)]
944 address: NameOrAddress,
945
946 #[arg(value_parser = parse_slot)]
948 slots: Vec<B256>,
949
950 #[arg(long, short = 'B')]
954 block: Option<BlockId>,
955
956 #[command(flatten)]
957 rpc: RpcOpts,
958 },
959
960 #[command(visible_alias = "n")]
962 Nonce {
963 #[arg(long, short = 'B')]
967 block: Option<BlockId>,
968
969 #[arg(value_parser = NameOrAddress::from_str)]
971 who: NameOrAddress,
972
973 #[command(flatten)]
974 rpc: RpcOpts,
975 },
976
977 #[command()]
979 Codehash {
980 #[arg(long, short = 'B')]
984 block: Option<BlockId>,
985
986 #[arg(value_parser = NameOrAddress::from_str)]
988 who: NameOrAddress,
989
990 #[arg(value_parser = parse_slot)]
992 slots: Vec<B256>,
993
994 #[command(flatten)]
995 rpc: RpcOpts,
996 },
997
998 #[command(visible_alias = "sr")]
1000 StorageRoot {
1001 #[arg(long, short = 'B')]
1005 block: Option<BlockId>,
1006
1007 #[arg(value_parser = NameOrAddress::from_str)]
1009 who: NameOrAddress,
1010
1011 #[arg(value_parser = parse_slot)]
1013 slots: Vec<B256>,
1014
1015 #[command(flatten)]
1016 rpc: RpcOpts,
1017 },
1018
1019 #[command(visible_aliases = &["et", "src"])]
1021 Source {
1022 address: String,
1024
1025 #[arg(long, short)]
1027 flatten: bool,
1028
1029 #[arg(short, value_hint = ValueHint::DirPath, alias = "path")]
1031 directory: Option<PathBuf>,
1032
1033 #[command(flatten)]
1034 etherscan: EtherscanOpts,
1035
1036 #[arg(long, env = "EXPLORER_API_URL")]
1039 explorer_api_url: Option<String>,
1040
1041 #[arg(long, env = "EXPLORER_URL")]
1043 explorer_url: Option<String>,
1044 },
1045
1046 #[command(visible_alias = "w")]
1048 Wallet {
1049 #[command(subcommand)]
1050 command: WalletSubcommands,
1051 },
1052
1053 #[command(visible_alias = "cc")]
1055 CreationCode(CreationCodeArgs),
1056
1057 #[command(visible_alias = "ar")]
1059 Artifact(ArtifactArgs),
1060
1061 #[command(visible_alias = "cra")]
1063 ConstructorArgs(ConstructorArgsArgs),
1064
1065 #[command(visible_alias = "i")]
1069 Interface(InterfaceArgs),
1070
1071 #[command(visible_alias = "bi")]
1073 Bind(BindArgs),
1074
1075 #[command(visible_alias = "b2e")]
1077 B2EPayload(B2EPayloadArgs),
1078
1079 #[command(visible_alias = "si")]
1081 Sig {
1082 sig: Option<String>,
1084
1085 optimize: Option<usize>,
1087 },
1088
1089 #[command(visible_alias = "c2")]
1091 Create2(Create2Args),
1092
1093 #[command(visible_alias = "f")]
1095 FindBlock(FindBlockArgs),
1096
1097 #[command(visible_alias = "com")]
1099 Completions {
1100 #[arg(value_enum)]
1101 shell: foundry_cli::clap::Shell,
1102 },
1103
1104 #[command(visible_alias = "r")]
1106 Run(RunArgs),
1107
1108 #[command(visible_alias = "rp")]
1110 Rpc(RpcArgs),
1111
1112 #[command(name = "format-bytes32-string", visible_aliases = &["--format-bytes32-string"])]
1114 FormatBytes32String {
1115 string: Option<String>,
1117 },
1118
1119 #[command(name = "parse-bytes32-string", visible_aliases = &["--parse-bytes32-string"])]
1121 ParseBytes32String {
1122 bytes: Option<String>,
1124 },
1125 #[command(name = "parse-bytes32-address", visible_aliases = &["--parse-bytes32-address"])]
1126 #[command(about = "Parses a checksummed address from bytes32 encoding.")]
1127 ParseBytes32Address {
1128 #[arg(value_name = "BYTES")]
1129 bytes: Option<String>,
1130 },
1131
1132 #[command(visible_aliases = &["dt", "decode-tx"])]
1134 DecodeTransaction {
1135 tx: Option<String>,
1137
1138 #[arg(long, short, num_args = 1, value_name = "NETWORK")]
1140 network: Option<NetworkVariant>,
1141 },
1142
1143 #[command(visible_aliases = &["decode-auth"])]
1145 RecoverAuthority { auth: String },
1146
1147 #[command(visible_alias = "sel")]
1149 Selectors {
1150 bytecode: Option<String>,
1152
1153 #[arg(long, short)]
1155 resolve: bool,
1156 },
1157
1158 #[command(visible_alias = "tp")]
1160 TxPool {
1161 #[command(subcommand)]
1162 command: TxPoolSubcommands,
1163 },
1164 #[command(name = "da-estimate")]
1166 DAEstimate(DAEstimateArgs),
1167
1168 #[command(visible_alias = "erc20")]
1170 Erc20Token {
1171 #[command(subcommand)]
1172 command: Erc20Subcommand,
1173 },
1174
1175 #[command(visible_alias = "tip20")]
1177 Tip20Token {
1178 #[command(subcommand)]
1179 command: Tip20Subcommand,
1180 },
1181
1182 #[command(visible_alias = "kc")]
1184 Keychain {
1185 #[command(subcommand)]
1186 command: KeychainSubcommand,
1187 },
1188 #[command(name = "trace")]
1189 Trace(TraceArgs),
1190}
1191
1192#[derive(Debug, Parser)]
1194pub struct ToBaseArgs {
1195 #[arg(allow_hyphen_values = true)]
1197 pub value: Option<String>,
1198
1199 #[arg(long, short = 'i')]
1201 pub base_in: Option<String>,
1202}
1203
1204pub fn parse_slot(s: &str) -> Result<B256> {
1205 let slot = U256::from_str(s).map_err(|e| eyre::eyre!("Could not parse slot number: {e}"))?;
1206 Ok(B256::from(slot))
1207}
1208
1209#[cfg(test)]
1210mod tests {
1211 use super::*;
1212 use crate::SimpleCast;
1213 use alloy_rpc_types::{BlockNumberOrTag, RpcBlockHash};
1214 use clap::CommandFactory;
1215
1216 #[test]
1217 fn verify_cli() {
1218 Cast::command().debug_assert();
1219 }
1220
1221 #[test]
1222 fn parse_proof_slot() {
1223 let args: Cast = Cast::parse_from([
1224 "foundry-cli",
1225 "proof",
1226 "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
1227 "0",
1228 "1",
1229 "0x0000000000000000000000000000000000000000000000000000000000000000",
1230 "0x1",
1231 "0x01",
1232 ]);
1233 match args.cmd {
1234 CastSubcommand::Proof { slots, .. } => {
1235 assert_eq!(
1236 slots,
1237 vec![
1238 B256::ZERO,
1239 U256::from(1).into(),
1240 B256::ZERO,
1241 U256::from(1).into(),
1242 U256::from(1).into()
1243 ]
1244 );
1245 }
1246 _ => unreachable!(),
1247 };
1248 }
1249
1250 #[test]
1251 fn parse_call_data() {
1252 let args: Cast = Cast::parse_from([
1253 "foundry-cli",
1254 "calldata",
1255 "f()",
1256 "5c9d55b78febcc2061715ba4f57ecf8ea2711f2c",
1257 "2",
1258 ]);
1259 match args.cmd {
1260 CastSubcommand::CalldataEncode { args, .. } => {
1261 assert_eq!(
1262 args,
1263 vec!["5c9d55b78febcc2061715ba4f57ecf8ea2711f2c".to_string(), "2".to_string()]
1264 )
1265 }
1266 _ => unreachable!(),
1267 };
1268 }
1269
1270 #[test]
1271 fn parse_call_data_with_file() {
1272 let args: Cast = Cast::parse_from(["foundry-cli", "calldata", "f()", "--file", "test.txt"]);
1273 match args.cmd {
1274 CastSubcommand::CalldataEncode { sig, file, args } => {
1275 assert_eq!(sig, "f()".to_string());
1276 assert_eq!(file, Some(PathBuf::from("test.txt")));
1277 assert!(args.is_empty());
1278 }
1279 _ => unreachable!(),
1280 };
1281 }
1282
1283 #[test]
1285 fn parse_signature() {
1286 let args: Cast = Cast::parse_from([
1287 "foundry-cli",
1288 "sig",
1289 "__$_$__$$$$$__$$_$$$_$$__$$___$$(address,address,uint256)",
1290 ]);
1291 match args.cmd {
1292 CastSubcommand::Sig { sig, .. } => {
1293 let sig = sig.unwrap();
1294 assert_eq!(
1295 sig,
1296 "__$_$__$$$$$__$$_$$$_$$__$$___$$(address,address,uint256)".to_string()
1297 );
1298
1299 let selector = SimpleCast::get_selector(&sig, 0).unwrap();
1300 assert_eq!(selector.0, "0x23b872dd".to_string());
1301 }
1302 _ => unreachable!(),
1303 };
1304 }
1305
1306 #[test]
1307 fn parse_block_ids() {
1308 struct TestCase {
1309 input: String,
1310 expect: BlockId,
1311 }
1312
1313 let test_cases = [
1314 TestCase {
1315 input: "0".to_string(),
1316 expect: BlockId::Number(BlockNumberOrTag::Number(0u64)),
1317 },
1318 TestCase {
1319 input: "0x56462c47c03df160f66819f0a79ea07def1569f8aac0fe91bb3a081159b61b4a"
1320 .to_string(),
1321 expect: BlockId::Hash(RpcBlockHash::from_hash(
1322 "0x56462c47c03df160f66819f0a79ea07def1569f8aac0fe91bb3a081159b61b4a"
1323 .parse()
1324 .unwrap(),
1325 None,
1326 )),
1327 },
1328 TestCase {
1329 input: "latest".to_string(),
1330 expect: BlockId::Number(BlockNumberOrTag::Latest),
1331 },
1332 TestCase {
1333 input: "earliest".to_string(),
1334 expect: BlockId::Number(BlockNumberOrTag::Earliest),
1335 },
1336 TestCase {
1337 input: "pending".to_string(),
1338 expect: BlockId::Number(BlockNumberOrTag::Pending),
1339 },
1340 TestCase { input: "safe".to_string(), expect: BlockId::Number(BlockNumberOrTag::Safe) },
1341 TestCase {
1342 input: "finalized".to_string(),
1343 expect: BlockId::Number(BlockNumberOrTag::Finalized),
1344 },
1345 ];
1346
1347 for test in test_cases {
1348 let result: BlockId = test.input.parse().unwrap();
1349 assert_eq!(result, test.expect);
1350 }
1351 }
1352}