1#[cfg(feature = "optimism")]
2use crate::cmd::da_estimate::DAEstimateArgs;
3use crate::cmd::{
4 access_list::AccessListArgs,
5 artifact::ArtifactArgs,
6 b2e_payload::B2EPayloadArgs,
7 batch_mktx::BatchMakeTxArgs,
8 batch_send::BatchSendArgs,
9 bind::BindArgs,
10 call::CallArgs,
11 call_overrides::CallOverrideOpts,
12 constructor_args::ConstructorArgsArgs,
13 create2::Create2Args,
14 creation_code::CreationCodeArgs,
15 erc20::Erc20Subcommand,
16 estimate::EstimateArgs,
17 find_block::FindBlockArgs,
18 interface::InterfaceArgs,
19 keychain::{KeyAuthorizationSubcommand, KeychainSubcommand},
20 logs::LogsArgs,
21 mktx::MakeTxArgs,
22 receive_policy::ReceivePolicySubcommand,
23 rpc::RpcArgs,
24 run::RunArgs,
25 send::SendTxArgs,
26 storage::StorageArgs,
27 storage_credits::StorageCreditsSubcommand,
28 tempo::TempoSubcommand,
29 tip20::Tip20Subcommand,
30 tip403::Tip403Subcommand,
31 trace::TraceArgs,
32 txpool::TxPoolSubcommands,
33 vaddr::VaddrSubcommand,
34 wallet::WalletSubcommands,
35};
36use alloy_ens::NameOrAddress;
37use alloy_primitives::{Address, B256, Selector, U256};
38use alloy_rpc_types::BlockId;
39use clap::{ArgAction, Parser, Subcommand, ValueHint};
40use eyre::Result;
41use foundry_cli::opts::{EtherscanOpts, GlobalArgs, RpcOpts};
42use foundry_common::version::{LONG_VERSION, SHORT_VERSION};
43use foundry_evm_networks::NetworkVariant;
44use std::{path::PathBuf, str::FromStr};
45#[derive(Parser)]
47#[command(
48 name = "cast",
49 version = SHORT_VERSION,
50 long_version = LONG_VERSION,
51 after_help = "Find more information in the book: https://getfoundry.sh/cast/overview",
52 next_display_order = None,
53)]
54pub struct Cast {
55 #[command(flatten)]
57 pub global: GlobalArgs,
58
59 #[command(subcommand)]
60 pub cmd: CastSubcommand,
61}
62
63#[derive(Subcommand)]
64pub enum CastSubcommand {
65 #[command(visible_aliases = &["--max-int", "maxi"])]
67 MaxInt {
68 #[arg(default_value = "int256")]
70 r#type: String,
71 },
72
73 #[command(visible_aliases = &["--min-int", "mini"])]
75 MinInt {
76 #[arg(default_value = "int256")]
78 r#type: String,
79 },
80
81 #[command(visible_aliases = &["--max-uint", "maxu"])]
83 MaxUint {
84 #[arg(default_value = "uint256")]
86 r#type: String,
87 },
88
89 #[command(visible_aliases = &["--address-zero", "az"])]
91 AddressZero,
92
93 #[command(visible_aliases = &["--hash-zero", "hz"])]
95 HashZero,
96
97 #[command(
99 visible_aliases = &[
100 "--from-ascii",
101 "--from-utf8",
102 "from-ascii",
103 "fu",
104 "fa"]
105 )]
106 FromUtf8 {
107 text: Option<String>,
109 },
110
111 #[command(visible_aliases = &["--concat-hex", "ch"])]
113 ConcatHex {
114 data: Vec<String>,
116 },
117
118 #[command(visible_aliases = &["--from-bin", "from-binx", "fb"])]
120 FromBin,
121
122 #[command(visible_aliases = &["--to-hexdata", "thd", "2hd"])]
130 ToHexdata {
131 input: Option<String>,
133 },
134
135 #[command(
137 visible_aliases = &["--to-checksum-address",
138 "--to-checksum",
139 "to-checksum",
140 "ta",
141 "2a"]
142 )]
143 ToCheckSumAddress {
144 address: Option<Address>,
146 chain_id: Option<u64>,
148 },
149
150 #[command(visible_aliases = &["--to-ascii", "tas", "2as"])]
152 ToAscii {
153 hexdata: Option<String>,
155 },
156
157 #[command(visible_aliases = &["--to-utf8", "tu8", "2u8"])]
159 ToUtf8 {
160 hexdata: Option<String>,
162 },
163
164 #[command(visible_aliases = &["--from-fix", "ff"])]
166 FromFixedPoint {
167 decimals: Option<String>,
169
170 #[arg(allow_hyphen_values = true)]
172 value: Option<String>,
173 },
174
175 #[command(visible_aliases = &["--to-bytes32", "tb", "2b"])]
177 ToBytes32 {
178 bytes: Option<String>,
180 },
181
182 #[command(visible_aliases = &["pd"])]
184 Pad {
185 data: Option<String>,
187
188 #[arg(long)]
190 right: bool,
191
192 #[arg(long, conflicts_with = "right")]
194 left: bool,
195
196 #[arg(long, default_value = "32")]
198 len: usize,
199 },
200
201 #[command(visible_aliases = &["--to-fix", "tf", "2f"])]
203 ToFixedPoint {
204 decimals: Option<String>,
206
207 #[arg(allow_hyphen_values = true)]
209 value: Option<String>,
210 },
211
212 #[command(name = "to-uint256", visible_aliases = &["--to-uint256", "tu", "2u"])]
214 ToUint256 {
215 value: Option<String>,
217 },
218
219 #[command(name = "to-int256", visible_aliases = &["--to-int256", "ti", "2i"])]
221 ToInt256 {
222 value: Option<String>,
224 },
225
226 #[command(name = "shl")]
228 LeftShift {
229 value: String,
231
232 bits: String,
234
235 #[arg(long)]
237 base_in: Option<String>,
238
239 #[arg(long, default_value = "16")]
241 base_out: String,
242 },
243
244 #[command(name = "shr")]
246 RightShift {
247 value: String,
249
250 bits: String,
252
253 #[arg(long)]
255 base_in: Option<String>,
256
257 #[arg(long, default_value = "16")]
259 base_out: String,
260 },
261
262 #[command(visible_aliases = &["--to-unit", "tun", "2un"])]
271 ToUnit {
272 value: Option<String>,
274
275 #[arg(default_value = "wei")]
277 unit: String,
278 },
279
280 #[command(visible_aliases = &["--parse-units", "pun"])]
287 ParseUnits {
288 value: Option<String>,
290
291 #[arg(default_value = "18")]
293 unit: u8,
294 },
295
296 #[command(visible_aliases = &["--format-units", "fun"])]
303 FormatUnits {
304 value: Option<String>,
306
307 #[arg(default_value = "18")]
309 unit: u8,
310 },
311
312 #[command(visible_aliases = &["--to-wei", "tw", "2w"])]
316 ToWei {
317 #[arg(allow_hyphen_values = true)]
319 value: Option<String>,
320
321 #[arg(default_value = "eth")]
323 unit: String,
324 },
325
326 #[command(visible_aliases = &["--from-wei", "fw"])]
330 FromWei {
331 #[arg(allow_hyphen_values = true)]
333 value: Option<String>,
334
335 #[arg(default_value = "eth")]
337 unit: String,
338 },
339
340 #[command(visible_aliases = &["--to-rlp"])]
351 ToRlp {
352 value: Option<String>,
357 },
358
359 #[command(visible_aliases = &["--from-rlp"])]
361 FromRlp {
362 value: Option<String>,
364
365 #[arg(long, alias = "int")]
367 as_int: bool,
368 },
369
370 #[command(visible_aliases = &["--to-hex", "th", "2h"])]
372 ToHex(ToBaseArgs),
373
374 #[command(visible_aliases = &["--to-dec", "td", "2d"])]
376 ToDec(ToBaseArgs),
377
378 #[command(
380 visible_aliases = &["--to-base",
381 "--to-radix",
382 "to-radix",
383 "tr",
384 "2r"]
385 )]
386 ToBase {
387 #[command(flatten)]
388 base: ToBaseArgs,
389
390 #[arg(value_name = "BASE")]
392 base_out: Option<String>,
393 },
394 #[command(visible_aliases = &["ac", "acl"])]
396 AccessList(AccessListArgs),
397 #[command(visible_alias = "l")]
399 Logs(LogsArgs),
400 #[command(visible_alias = "bl")]
402 Block {
403 block: Option<BlockId>,
407
408 #[arg(short, long = "field", aliases = ["fields"], num_args = 0.., action = ArgAction::Append, value_delimiter = ',')]
410 fields: Vec<String>,
411
412 #[arg(long, conflicts_with = "fields")]
414 raw: bool,
415
416 #[arg(long, env = "CAST_FULL_BLOCK")]
417 full: bool,
418
419 #[command(flatten)]
420 rpc: RpcOpts,
421
422 #[arg(long, short, num_args = 1, value_name = "NETWORK")]
424 network: Option<NetworkVariant>,
425 },
426
427 #[command(visible_alias = "bn")]
429 BlockNumber {
430 block: Option<BlockId>,
432 #[command(flatten)]
433 rpc: RpcOpts,
434 },
435
436 #[command(visible_alias = "c")]
438 Call(CallArgs),
439
440 #[command(name = "calldata", visible_alias = "cd")]
442 CalldataEncode {
443 sig: String,
445
446 #[arg(allow_hyphen_values = true)]
448 args: Vec<String>,
449
450 #[arg(long, value_name = "PATH")]
452 file: Option<PathBuf>,
453 },
454
455 Chain {
457 #[command(flatten)]
458 rpc: RpcOpts,
459 },
460
461 #[command(visible_aliases = &["ci", "cid"])]
463 ChainId {
464 #[command(flatten)]
465 rpc: RpcOpts,
466 },
467
468 #[command(visible_alias = "cl")]
470 Client {
471 #[command(flatten)]
472 rpc: RpcOpts,
473 },
474
475 #[command(visible_alias = "ca")]
477 ComputeAddress {
478 address: Option<Address>,
480
481 #[arg(
483 long,
484 conflicts_with = "salt",
485 conflicts_with = "init_code",
486 conflicts_with = "init_code_hash"
487 )]
488 nonce: Option<u64>,
489
490 #[arg(long, conflicts_with = "nonce")]
492 salt: Option<B256>,
493
494 #[arg(
496 long,
497 requires = "salt",
498 conflicts_with = "init_code_hash",
499 conflicts_with = "nonce"
500 )]
501 init_code: Option<String>,
502
503 #[arg(long, requires = "salt", conflicts_with = "init_code", conflicts_with = "nonce")]
505 init_code_hash: Option<B256>,
506
507 #[command(flatten)]
508 rpc: RpcOpts,
509 },
510
511 #[command(visible_alias = "da")]
513 Disassemble {
514 bytecode: Option<String>,
516 },
517
518 #[command(name = "mktx", visible_alias = "m")]
520 MakeTx(MakeTxArgs),
521
522 Classify {
524 raw_tx: Option<String>,
526 },
527
528 #[command(visible_aliases = &["na", "nh"])]
530 Namehash { name: Option<String> },
531
532 #[command(visible_alias = "t")]
534 Tx {
535 tx_hash: Option<String>,
537
538 #[arg(long, value_parser = NameOrAddress::from_str)]
540 from: Option<NameOrAddress>,
541
542 #[arg(long)]
544 nonce: Option<u64>,
545
546 field: Option<String>,
549
550 #[arg(long, conflicts_with = "field")]
552 raw: bool,
553
554 #[arg(long, conflicts_with_all = ["field", "raw", "to_request"])]
556 lane: bool,
557
558 #[command(flatten)]
559 rpc: RpcOpts,
560
561 #[arg(long)]
563 to_request: bool,
564
565 #[arg(long, short, num_args = 1, value_name = "NETWORK")]
567 network: Option<NetworkVariant>,
568 },
569
570 #[command(visible_alias = "re")]
572 Receipt {
573 tx_hash: String,
575
576 field: Option<String>,
578
579 #[arg(long, default_value = "1")]
581 confirmations: u64,
582
583 #[arg(id = "async", long = "async", env = "CAST_ASYNC", alias = "cast-async")]
585 cast_async: bool,
586
587 #[command(flatten)]
588 rpc: RpcOpts,
589 },
590
591 #[command(name = "send", visible_alias = "s")]
593 SendTx(SendTxArgs),
594
595 #[command(name = "batch-mktx", visible_alias = "bm")]
597 BatchMakeTx(BatchMakeTxArgs),
598
599 #[command(name = "batch-send", visible_alias = "bs")]
601 BatchSend(BatchSendArgs),
602
603 #[command(name = "publish", visible_alias = "p")]
605 PublishTx {
606 raw_tx: String,
608
609 #[arg(id = "async", long = "async", env = "CAST_ASYNC", alias = "cast-async")]
611 cast_async: bool,
612
613 #[command(flatten)]
614 rpc: RpcOpts,
615 },
616
617 #[command(visible_alias = "e")]
619 Estimate(EstimateArgs),
620
621 #[command(visible_aliases = &["calldata-decode", "--calldata-decode", "cdd"])]
626 DecodeCalldata {
627 sig: String,
629
630 #[arg(required_unless_present = "file", index = 2)]
632 calldata: Option<String>,
633
634 #[arg(long = "file", short = 'f', conflicts_with = "calldata")]
636 file: Option<PathBuf>,
637 },
638
639 #[command(visible_aliases = &["string-decode", "--string-decode", "sd"])]
643 DecodeString {
644 data: String,
646 },
647
648 #[command(visible_aliases = &["event-decode", "--event-decode", "ed"])]
650 DecodeEvent {
651 #[arg(long, visible_alias = "event-sig")]
653 sig: Option<String>,
654 data: String,
656 },
657
658 #[command(visible_aliases = &["error-decode", "--error-decode", "erd"])]
660 DecodeError {
661 #[arg(long, visible_alias = "error-sig")]
663 sig: Option<String>,
664 data: String,
666 },
667
668 #[command(name = "decode-abi", visible_aliases = &["abi-decode", "--abi-decode", "ad"])]
674 DecodeAbi {
675 sig: String,
677
678 calldata: String,
680
681 #[arg(long, short, help_heading = "Decode input data instead of output data")]
683 input: bool,
684 },
685
686 #[command(visible_alias = "ae")]
688 AbiEncode {
689 sig: String,
691
692 #[arg(long)]
694 packed: bool,
695
696 #[arg(allow_hyphen_values = true)]
698 args: Vec<String>,
699 },
700
701 #[command(visible_alias = "aee")]
703 AbiEncodeEvent {
704 sig: String,
706
707 #[arg(allow_hyphen_values = true)]
709 args: Vec<String>,
710 },
711
712 #[command(visible_alias = "in")]
714 Index {
715 key_type: String,
717
718 key: String,
720
721 slot_number: String,
723 },
724
725 #[command(name = "index-erc7201", alias = "index-erc-7201", visible_aliases = &["index7201", "in7201"])]
727 IndexErc7201 {
728 id: Option<String>,
730 #[arg(long, default_value = "erc7201")]
732 formula_id: String,
733 },
734
735 #[command(visible_alias = "impl")]
738 Implementation {
739 #[arg(long, short = 'B')]
743 block: Option<BlockId>,
744
745 #[arg(long)]
749 beacon: bool,
750
751 #[arg(value_parser = NameOrAddress::from_str)]
753 who: NameOrAddress,
754
755 #[command(flatten)]
756 rpc: RpcOpts,
757 },
758
759 #[command(visible_alias = "adm")]
761 Admin {
762 #[arg(long, short = 'B')]
766 block: Option<BlockId>,
767
768 #[arg(value_parser = NameOrAddress::from_str)]
770 who: NameOrAddress,
771
772 #[command(flatten)]
773 rpc: RpcOpts,
774 },
775
776 #[command(name = "4byte", visible_aliases = &["4", "4b"])]
778 FourByte {
779 selector: Option<Selector>,
781 },
782
783 #[command(name = "4byte-calldata", aliases = &["4byte-decode", "4d", "4bd"], visible_aliases = &["4c", "4bc"])]
785 FourByteCalldata {
786 calldata: Option<String>,
788 },
789
790 #[command(name = "4byte-event", visible_aliases = &["4e", "4be", "topic0-event", "t0e"])]
792 FourByteEvent {
793 #[arg(value_name = "TOPIC_0")]
795 topic: Option<B256>,
796 },
797
798 #[command(visible_aliases = &["ups"])]
806 UploadSignature {
807 signatures: Vec<String>,
812 },
813
814 #[command(visible_alias = "pc")]
818 PrettyCalldata {
819 calldata: Option<String>,
821
822 #[arg(long, short)]
824 offline: bool,
825 },
826
827 #[command(visible_alias = "a")]
829 Age {
830 block: Option<BlockId>,
834
835 #[command(flatten)]
836 rpc: RpcOpts,
837 },
838
839 #[command(visible_alias = "b")]
841 Balance {
842 #[arg(long, short = 'B')]
846 block: Option<BlockId>,
847
848 #[arg(value_parser = NameOrAddress::from_str)]
850 who: NameOrAddress,
851
852 #[arg(long, short)]
854 ether: bool,
855
856 #[command(flatten)]
857 rpc: RpcOpts,
858
859 #[arg(long, alias = "erc721")]
862 erc20: Option<Address>,
863
864 #[command(flatten)]
865 overrides: CallOverrideOpts,
866 },
867
868 #[command(visible_aliases = &["ba", "fee", "basefee"])]
870 BaseFee {
871 block: Option<BlockId>,
875
876 #[command(flatten)]
877 rpc: RpcOpts,
878 },
879
880 #[command(visible_alias = "co")]
882 Code {
883 #[arg(long, short = 'B')]
887 block: Option<BlockId>,
888
889 #[arg(value_parser = NameOrAddress::from_str)]
891 who: NameOrAddress,
892
893 #[arg(long, short)]
895 disassemble: bool,
896
897 #[command(flatten)]
898 rpc: RpcOpts,
899 },
900
901 #[command(visible_alias = "cs")]
903 Codesize {
904 #[arg(long, short = 'B')]
908 block: Option<BlockId>,
909
910 #[arg(value_parser = NameOrAddress::from_str)]
912 who: NameOrAddress,
913
914 #[command(flatten)]
915 rpc: RpcOpts,
916 },
917
918 #[command(visible_alias = "g")]
920 GasPrice {
921 #[command(flatten)]
922 rpc: RpcOpts,
923 },
924
925 #[command(visible_alias = "se")]
927 SigEvent {
928 event_string: Option<String>,
930 },
931
932 #[command(visible_aliases = &["k", "keccak256"])]
934 Keccak {
935 data: Option<String>,
937 },
938
939 #[command(visible_aliases = &["--hash-message", "hm"])]
941 HashMessage {
942 message: Option<String>,
944 },
945
946 #[command(visible_alias = "rn")]
948 ResolveName {
949 who: Option<String>,
951
952 #[arg(long)]
954 verify: bool,
955
956 #[command(flatten)]
957 rpc: RpcOpts,
958 },
959
960 #[command(visible_alias = "la")]
962 LookupAddress {
963 who: Option<Address>,
965
966 #[arg(long)]
968 verify: bool,
969
970 #[command(flatten)]
971 rpc: RpcOpts,
972 },
973
974 #[command(visible_alias = "st")]
976 Storage(StorageArgs),
977
978 #[command(visible_alias = "pr")]
980 Proof {
981 #[arg(value_parser = NameOrAddress::from_str)]
983 address: NameOrAddress,
984
985 #[arg(value_parser = parse_slot)]
987 slots: Vec<B256>,
988
989 #[arg(long, short = 'B')]
993 block: Option<BlockId>,
994
995 #[command(flatten)]
996 rpc: RpcOpts,
997 },
998
999 #[command(visible_alias = "n")]
1001 Nonce {
1002 #[arg(long, short = 'B')]
1006 block: Option<BlockId>,
1007
1008 #[arg(value_parser = NameOrAddress::from_str)]
1010 who: NameOrAddress,
1011
1012 #[command(flatten)]
1013 rpc: RpcOpts,
1014 },
1015
1016 #[command()]
1018 Codehash {
1019 #[arg(long, short = 'B')]
1023 block: Option<BlockId>,
1024
1025 #[arg(value_parser = NameOrAddress::from_str)]
1027 who: NameOrAddress,
1028
1029 #[arg(value_parser = parse_slot)]
1031 slots: Vec<B256>,
1032
1033 #[command(flatten)]
1034 rpc: RpcOpts,
1035 },
1036
1037 #[command(visible_alias = "sr")]
1039 StorageRoot {
1040 #[arg(long, short = 'B')]
1044 block: Option<BlockId>,
1045
1046 #[arg(value_parser = NameOrAddress::from_str)]
1048 who: NameOrAddress,
1049
1050 #[arg(value_parser = parse_slot)]
1052 slots: Vec<B256>,
1053
1054 #[command(flatten)]
1055 rpc: RpcOpts,
1056 },
1057
1058 #[command(name = "channel-id")]
1060 ChannelId {
1061 #[arg(value_parser = NameOrAddress::from_str)]
1063 payer: NameOrAddress,
1064
1065 #[arg(value_parser = NameOrAddress::from_str)]
1067 payee: NameOrAddress,
1068
1069 #[arg(value_parser = NameOrAddress::from_str)]
1071 token: NameOrAddress,
1072
1073 salt: B256,
1075
1076 #[arg(long, value_parser = NameOrAddress::from_str)]
1078 operator: Option<NameOrAddress>,
1079
1080 #[arg(long, value_parser = NameOrAddress::from_str)]
1082 authorized_signer: Option<NameOrAddress>,
1083
1084 #[arg(long, default_value_t = B256::ZERO)]
1086 expiring_nonce_hash: B256,
1087
1088 #[arg(long, value_parser = NameOrAddress::from_str)]
1090 reserve: Option<NameOrAddress>,
1091
1092 #[arg(long, short = 'B')]
1096 block: Option<BlockId>,
1097
1098 #[command(flatten)]
1099 rpc: RpcOpts,
1100 },
1101
1102 #[command(visible_aliases = &["et", "src"])]
1104 Source {
1105 address: String,
1107
1108 #[arg(long, short)]
1110 flatten: bool,
1111
1112 #[arg(short, value_hint = ValueHint::DirPath, alias = "path")]
1114 directory: Option<PathBuf>,
1115
1116 #[command(flatten)]
1117 etherscan: EtherscanOpts,
1118
1119 #[arg(long, env = "EXPLORER_API_URL")]
1122 explorer_api_url: Option<String>,
1123
1124 #[arg(long, env = "EXPLORER_URL")]
1126 explorer_url: Option<String>,
1127 },
1128
1129 #[command(visible_alias = "w")]
1131 Wallet {
1132 #[command(subcommand)]
1133 command: WalletSubcommands,
1134 },
1135
1136 #[command(visible_alias = "cc")]
1138 CreationCode(CreationCodeArgs),
1139
1140 #[command(visible_alias = "ar")]
1142 Artifact(ArtifactArgs),
1143
1144 #[command(visible_alias = "cra")]
1146 ConstructorArgs(ConstructorArgsArgs),
1147
1148 #[command(visible_alias = "i")]
1152 Interface(InterfaceArgs),
1153
1154 #[command(visible_alias = "bi")]
1156 Bind(BindArgs),
1157
1158 #[command(visible_alias = "b2e")]
1160 B2EPayload(B2EPayloadArgs),
1161
1162 #[command(visible_alias = "si")]
1164 Sig {
1165 sig: Option<String>,
1167
1168 #[arg(conflicts_with = "json")]
1170 optimize: Option<usize>,
1171 },
1172
1173 #[command(visible_alias = "c2")]
1175 Create2(Create2Args),
1176
1177 #[command(visible_alias = "f")]
1179 FindBlock(FindBlockArgs),
1180
1181 #[command(visible_alias = "com")]
1183 Completions {
1184 #[arg(value_enum)]
1185 shell: foundry_cli::clap::Shell,
1186 },
1187
1188 #[command(visible_alias = "r")]
1190 Run(RunArgs),
1191
1192 #[command(visible_alias = "rp")]
1194 Rpc(RpcArgs),
1195
1196 #[command(name = "format-bytes32-string", visible_aliases = &["--format-bytes32-string"])]
1198 FormatBytes32String {
1199 string: Option<String>,
1201 },
1202
1203 #[command(name = "parse-bytes32-string", visible_aliases = &["--parse-bytes32-string"])]
1205 ParseBytes32String {
1206 bytes: Option<String>,
1208 },
1209 #[command(name = "parse-bytes32-address", visible_aliases = &["--parse-bytes32-address"])]
1210 #[command(about = "Parses a checksummed address from bytes32 encoding.")]
1211 ParseBytes32Address {
1212 #[arg(value_name = "BYTES")]
1213 bytes: Option<String>,
1214 },
1215
1216 #[command(visible_aliases = &["dt", "decode-tx"])]
1218 DecodeTransaction {
1219 tx: Option<String>,
1221
1222 #[arg(long, short, num_args = 1, value_name = "NETWORK")]
1227 network: Option<NetworkVariant>,
1228 },
1229
1230 #[command(visible_aliases = &["decode-auth"])]
1232 RecoverAuthority { auth: String },
1233
1234 #[command(visible_alias = "sel")]
1236 Selectors {
1237 bytecode: Option<String>,
1239
1240 #[arg(long, short)]
1242 resolve: bool,
1243 },
1244
1245 #[command(visible_alias = "tp")]
1247 TxPool {
1248 #[command(subcommand)]
1249 command: TxPoolSubcommands,
1250 },
1251 #[cfg(feature = "optimism")]
1253 #[command(name = "da-estimate")]
1254 DAEstimate(DAEstimateArgs),
1255
1256 #[command(visible_alias = "erc20")]
1258 Erc20Token {
1259 #[command(subcommand)]
1260 command: Erc20Subcommand,
1261 },
1262
1263 #[command(visible_alias = "tip20")]
1265 Tip20Token {
1266 #[command(subcommand)]
1267 command: Tip20Subcommand,
1268 },
1269
1270 #[command(name = "receive-policy")]
1272 ReceivePolicy {
1273 #[command(subcommand)]
1274 command: ReceivePolicySubcommand,
1275 },
1276
1277 #[command(name = "tip403")]
1279 Tip403 {
1280 #[command(subcommand)]
1281 command: Tip403Subcommand,
1282 },
1283
1284 #[command(name = "storage-credits", visible_alias = "sc")]
1286 StorageCredits {
1287 #[command(subcommand)]
1288 command: StorageCreditsSubcommand,
1289 },
1290
1291 #[command(visible_alias = "kc")]
1293 Keychain {
1294 #[command(subcommand)]
1295 command: KeychainSubcommand,
1296 },
1297
1298 #[command(name = "key-authorization", visible_alias = "key-auth")]
1300 KeyAuthorization {
1301 #[command(subcommand)]
1302 command: KeyAuthorizationSubcommand,
1303 },
1304
1305 Tempo {
1307 #[command(subcommand)]
1308 command: TempoSubcommand,
1309 },
1310
1311 #[command(visible_alias = "vaddr")]
1313 VirtualAddress {
1314 #[command(subcommand)]
1315 command: VaddrSubcommand,
1316 },
1317
1318 #[command(name = "trace")]
1319 Trace(TraceArgs),
1320}
1321
1322#[derive(Debug, Parser)]
1324pub struct ToBaseArgs {
1325 #[arg(allow_hyphen_values = true)]
1327 pub value: Option<String>,
1328
1329 #[arg(long, short = 'i')]
1331 pub base_in: Option<String>,
1332}
1333
1334pub fn parse_slot(s: &str) -> Result<B256> {
1335 let slot = U256::from_str(s).map_err(|e| eyre::eyre!("Could not parse slot number: {e}"))?;
1336 Ok(B256::from(slot))
1337}
1338
1339#[cfg(test)]
1340mod tests {
1341 use super::*;
1342 use crate::SimpleCast;
1343 use alloy_rpc_types::{BlockNumberOrTag, RpcBlockHash};
1344 use clap::CommandFactory;
1345
1346 #[test]
1347 fn verify_cli() {
1348 Cast::command().debug_assert();
1349 }
1350
1351 #[test]
1352 fn parse_proof_slot() {
1353 let args: Cast = Cast::parse_from([
1354 "foundry-cli",
1355 "proof",
1356 "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
1357 "0",
1358 "1",
1359 "0x0000000000000000000000000000000000000000000000000000000000000000",
1360 "0x1",
1361 "0x01",
1362 ]);
1363 match args.cmd {
1364 CastSubcommand::Proof { slots, .. } => {
1365 assert_eq!(
1366 slots,
1367 vec![
1368 B256::ZERO,
1369 U256::from(1).into(),
1370 B256::ZERO,
1371 U256::from(1).into(),
1372 U256::from(1).into()
1373 ]
1374 );
1375 }
1376 _ => unreachable!(),
1377 };
1378 }
1379
1380 #[test]
1381 fn parse_call_data() {
1382 let args: Cast = Cast::parse_from([
1383 "foundry-cli",
1384 "calldata",
1385 "f()",
1386 "5c9d55b78febcc2061715ba4f57ecf8ea2711f2c",
1387 "2",
1388 ]);
1389 match args.cmd {
1390 CastSubcommand::CalldataEncode { args, .. } => {
1391 assert_eq!(
1392 args,
1393 vec!["5c9d55b78febcc2061715ba4f57ecf8ea2711f2c".to_string(), "2".to_string()]
1394 )
1395 }
1396 _ => unreachable!(),
1397 };
1398 }
1399
1400 #[test]
1401 fn parse_call_data_with_file() {
1402 let args: Cast = Cast::parse_from(["foundry-cli", "calldata", "f()", "--file", "test.txt"]);
1403 match args.cmd {
1404 CastSubcommand::CalldataEncode { sig, file, args } => {
1405 assert_eq!(sig, "f()".to_string());
1406 assert_eq!(file, Some(PathBuf::from("test.txt")));
1407 assert!(args.is_empty());
1408 }
1409 _ => unreachable!(),
1410 };
1411 }
1412
1413 #[test]
1415 fn parse_signature() {
1416 let args: Cast = Cast::parse_from([
1417 "foundry-cli",
1418 "sig",
1419 "__$_$__$$$$$__$$_$$$_$$__$$___$$(address,address,uint256)",
1420 ]);
1421 match args.cmd {
1422 CastSubcommand::Sig { sig, .. } => {
1423 let sig = sig.unwrap();
1424 assert_eq!(
1425 sig,
1426 "__$_$__$$$$$__$$_$$$_$$__$$___$$(address,address,uint256)".to_string()
1427 );
1428
1429 let selector = SimpleCast::get_selector(&sig, 0).unwrap();
1430 assert_eq!(selector.0, "0x23b872dd".to_string());
1431 }
1432 _ => unreachable!(),
1433 };
1434 }
1435
1436 #[test]
1437 fn parse_block_ids() {
1438 struct TestCase {
1439 input: String,
1440 expect: BlockId,
1441 }
1442
1443 let test_cases = [
1444 TestCase {
1445 input: "0".to_string(),
1446 expect: BlockId::Number(BlockNumberOrTag::Number(0u64)),
1447 },
1448 TestCase {
1449 input: "0x56462c47c03df160f66819f0a79ea07def1569f8aac0fe91bb3a081159b61b4a"
1450 .to_string(),
1451 expect: BlockId::Hash(RpcBlockHash::from_hash(
1452 "0x56462c47c03df160f66819f0a79ea07def1569f8aac0fe91bb3a081159b61b4a"
1453 .parse()
1454 .unwrap(),
1455 None,
1456 )),
1457 },
1458 TestCase {
1459 input: "latest".to_string(),
1460 expect: BlockId::Number(BlockNumberOrTag::Latest),
1461 },
1462 TestCase {
1463 input: "earliest".to_string(),
1464 expect: BlockId::Number(BlockNumberOrTag::Earliest),
1465 },
1466 TestCase {
1467 input: "pending".to_string(),
1468 expect: BlockId::Number(BlockNumberOrTag::Pending),
1469 },
1470 TestCase { input: "safe".to_string(), expect: BlockId::Number(BlockNumberOrTag::Safe) },
1471 TestCase {
1472 input: "finalized".to_string(),
1473 expect: BlockId::Number(BlockNumberOrTag::Finalized),
1474 },
1475 ];
1476
1477 for test in test_cases {
1478 let result: BlockId = test.input.parse().unwrap();
1479 assert_eq!(result, test.expect);
1480 }
1481 }
1482}