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 constructor_args::ConstructorArgsArgs,
12 create2::Create2Args,
13 creation_code::CreationCodeArgs,
14 erc20::Erc20Subcommand,
15 estimate::EstimateArgs,
16 find_block::FindBlockArgs,
17 interface::InterfaceArgs,
18 keychain::{KeyAuthSubcommand, KeychainSubcommand},
19 logs::LogsArgs,
20 mktx::MakeTxArgs,
21 rpc::RpcArgs,
22 run::RunArgs,
23 send::SendTxArgs,
24 storage::StorageArgs,
25 tempo::TempoSubcommand,
26 tip20::Tip20Subcommand,
27 trace::TraceArgs,
28 txpool::TxPoolSubcommands,
29 vaddr::VaddrSubcommand,
30 wallet::WalletSubcommands,
31};
32use alloy_ens::NameOrAddress;
33use alloy_primitives::{Address, B256, Selector, U256};
34use alloy_rpc_types::BlockId;
35use clap::{ArgAction, Parser, Subcommand, ValueHint};
36use eyre::Result;
37use foundry_cli::opts::{EtherscanOpts, GlobalArgs, RpcOpts};
38use foundry_common::version::{LONG_VERSION, SHORT_VERSION};
39use foundry_evm_networks::NetworkVariant;
40use std::{path::PathBuf, str::FromStr};
41#[derive(Parser)]
43#[command(
44 name = "cast",
45 version = SHORT_VERSION,
46 long_version = LONG_VERSION,
47 after_help = "Find more information in the book: https://getfoundry.sh/cast/overview",
48 next_display_order = None,
49)]
50pub struct Cast {
51 #[command(flatten)]
53 pub global: GlobalArgs,
54
55 #[command(subcommand)]
56 pub cmd: CastSubcommand,
57}
58
59#[derive(Subcommand)]
60pub enum CastSubcommand {
61 #[command(visible_aliases = &["--max-int", "maxi"])]
63 MaxInt {
64 #[arg(default_value = "int256")]
66 r#type: String,
67 },
68
69 #[command(visible_aliases = &["--min-int", "mini"])]
71 MinInt {
72 #[arg(default_value = "int256")]
74 r#type: String,
75 },
76
77 #[command(visible_aliases = &["--max-uint", "maxu"])]
79 MaxUint {
80 #[arg(default_value = "uint256")]
82 r#type: String,
83 },
84
85 #[command(visible_aliases = &["--address-zero", "az"])]
87 AddressZero,
88
89 #[command(visible_aliases = &["--hash-zero", "hz"])]
91 HashZero,
92
93 #[command(
95 visible_aliases = &[
96 "--from-ascii",
97 "--from-utf8",
98 "from-ascii",
99 "fu",
100 "fa"]
101 )]
102 FromUtf8 {
103 text: Option<String>,
105 },
106
107 #[command(visible_aliases = &["--concat-hex", "ch"])]
109 ConcatHex {
110 data: Vec<String>,
112 },
113
114 #[command(visible_aliases = &["--from-bin", "from-binx", "fb"])]
116 FromBin,
117
118 #[command(visible_aliases = &["--to-hexdata", "thd", "2hd"])]
126 ToHexdata {
127 input: Option<String>,
129 },
130
131 #[command(
133 visible_aliases = &["--to-checksum-address",
134 "--to-checksum",
135 "to-checksum",
136 "ta",
137 "2a"]
138 )]
139 ToCheckSumAddress {
140 address: Option<Address>,
142 chain_id: Option<u64>,
144 },
145
146 #[command(visible_aliases = &["--to-ascii", "tas", "2as"])]
148 ToAscii {
149 hexdata: Option<String>,
151 },
152
153 #[command(visible_aliases = &["--to-utf8", "tu8", "2u8"])]
155 ToUtf8 {
156 hexdata: Option<String>,
158 },
159
160 #[command(visible_aliases = &["--from-fix", "ff"])]
162 FromFixedPoint {
163 decimals: Option<String>,
165
166 #[arg(allow_hyphen_values = true)]
168 value: Option<String>,
169 },
170
171 #[command(visible_aliases = &["--to-bytes32", "tb", "2b"])]
173 ToBytes32 {
174 bytes: Option<String>,
176 },
177
178 #[command(visible_aliases = &["pd"])]
180 Pad {
181 data: Option<String>,
183
184 #[arg(long)]
186 right: bool,
187
188 #[arg(long, conflicts_with = "right")]
190 left: bool,
191
192 #[arg(long, default_value = "32")]
194 len: usize,
195 },
196
197 #[command(visible_aliases = &["--to-fix", "tf", "2f"])]
199 ToFixedPoint {
200 decimals: Option<String>,
202
203 #[arg(allow_hyphen_values = true)]
205 value: Option<String>,
206 },
207
208 #[command(name = "to-uint256", visible_aliases = &["--to-uint256", "tu", "2u"])]
210 ToUint256 {
211 value: Option<String>,
213 },
214
215 #[command(name = "to-int256", visible_aliases = &["--to-int256", "ti", "2i"])]
217 ToInt256 {
218 value: Option<String>,
220 },
221
222 #[command(name = "shl")]
224 LeftShift {
225 value: String,
227
228 bits: String,
230
231 #[arg(long)]
233 base_in: Option<String>,
234
235 #[arg(long, default_value = "16")]
237 base_out: String,
238 },
239
240 #[command(name = "shr")]
242 RightShift {
243 value: String,
245
246 bits: String,
248
249 #[arg(long)]
251 base_in: Option<String>,
252
253 #[arg(long, default_value = "16")]
255 base_out: String,
256 },
257
258 #[command(visible_aliases = &["--to-unit", "tun", "2un"])]
267 ToUnit {
268 value: Option<String>,
270
271 #[arg(default_value = "wei")]
273 unit: String,
274 },
275
276 #[command(visible_aliases = &["--parse-units", "pun"])]
283 ParseUnits {
284 value: Option<String>,
286
287 #[arg(default_value = "18")]
289 unit: u8,
290 },
291
292 #[command(visible_aliases = &["--format-units", "fun"])]
299 FormatUnits {
300 value: Option<String>,
302
303 #[arg(default_value = "18")]
305 unit: u8,
306 },
307
308 #[command(visible_aliases = &["--to-wei", "tw", "2w"])]
312 ToWei {
313 #[arg(allow_hyphen_values = true)]
315 value: Option<String>,
316
317 #[arg(default_value = "eth")]
319 unit: String,
320 },
321
322 #[command(visible_aliases = &["--from-wei", "fw"])]
326 FromWei {
327 #[arg(allow_hyphen_values = true)]
329 value: Option<String>,
330
331 #[arg(default_value = "eth")]
333 unit: String,
334 },
335
336 #[command(visible_aliases = &["--to-rlp"])]
347 ToRlp {
348 value: Option<String>,
353 },
354
355 #[command(visible_aliases = &["--from-rlp"])]
357 FromRlp {
358 value: Option<String>,
360
361 #[arg(long, alias = "int")]
363 as_int: bool,
364 },
365
366 #[command(visible_aliases = &["--to-hex", "th", "2h"])]
368 ToHex(ToBaseArgs),
369
370 #[command(visible_aliases = &["--to-dec", "td", "2d"])]
372 ToDec(ToBaseArgs),
373
374 #[command(
376 visible_aliases = &["--to-base",
377 "--to-radix",
378 "to-radix",
379 "tr",
380 "2r"]
381 )]
382 ToBase {
383 #[command(flatten)]
384 base: ToBaseArgs,
385
386 #[arg(value_name = "BASE")]
388 base_out: Option<String>,
389 },
390 #[command(visible_aliases = &["ac", "acl"])]
392 AccessList(AccessListArgs),
393 #[command(visible_alias = "l")]
395 Logs(LogsArgs),
396 #[command(visible_alias = "bl")]
398 Block {
399 block: Option<BlockId>,
403
404 #[arg(short, long = "field", aliases = ["fields"], num_args = 0.., action = ArgAction::Append, value_delimiter = ',')]
406 fields: Vec<String>,
407
408 #[arg(long, conflicts_with = "fields")]
410 raw: bool,
411
412 #[arg(long, env = "CAST_FULL_BLOCK")]
413 full: bool,
414
415 #[command(flatten)]
416 rpc: RpcOpts,
417
418 #[arg(long, short, num_args = 1, value_name = "NETWORK")]
420 network: Option<NetworkVariant>,
421 },
422
423 #[command(visible_alias = "bn")]
425 BlockNumber {
426 block: Option<BlockId>,
428 #[command(flatten)]
429 rpc: RpcOpts,
430 },
431
432 #[command(visible_alias = "c")]
434 Call(CallArgs),
435
436 #[command(name = "calldata", visible_alias = "cd")]
438 CalldataEncode {
439 sig: String,
441
442 #[arg(allow_hyphen_values = true)]
444 args: Vec<String>,
445
446 #[arg(long, value_name = "PATH")]
448 file: Option<PathBuf>,
449 },
450
451 Chain {
453 #[command(flatten)]
454 rpc: RpcOpts,
455 },
456
457 #[command(visible_aliases = &["ci", "cid"])]
459 ChainId {
460 #[command(flatten)]
461 rpc: RpcOpts,
462 },
463
464 #[command(visible_alias = "cl")]
466 Client {
467 #[command(flatten)]
468 rpc: RpcOpts,
469 },
470
471 #[command(visible_alias = "ca")]
473 ComputeAddress {
474 address: Option<Address>,
476
477 #[arg(
479 long,
480 conflicts_with = "salt",
481 conflicts_with = "init_code",
482 conflicts_with = "init_code_hash"
483 )]
484 nonce: Option<u64>,
485
486 #[arg(long, conflicts_with = "nonce")]
488 salt: Option<B256>,
489
490 #[arg(
492 long,
493 requires = "salt",
494 conflicts_with = "init_code_hash",
495 conflicts_with = "nonce"
496 )]
497 init_code: Option<String>,
498
499 #[arg(long, requires = "salt", conflicts_with = "init_code", conflicts_with = "nonce")]
501 init_code_hash: Option<B256>,
502
503 #[command(flatten)]
504 rpc: RpcOpts,
505 },
506
507 #[command(visible_alias = "da")]
509 Disassemble {
510 bytecode: Option<String>,
512 },
513
514 #[command(name = "mktx", visible_alias = "m")]
516 MakeTx(MakeTxArgs),
517
518 Classify {
520 raw_tx: Option<String>,
522 },
523
524 #[command(visible_aliases = &["na", "nh"])]
526 Namehash { name: Option<String> },
527
528 #[command(visible_alias = "t")]
530 Tx {
531 tx_hash: Option<String>,
533
534 #[arg(long, value_parser = NameOrAddress::from_str)]
536 from: Option<NameOrAddress>,
537
538 #[arg(long)]
540 nonce: Option<u64>,
541
542 field: Option<String>,
545
546 #[arg(long, conflicts_with = "field")]
548 raw: bool,
549
550 #[arg(long, conflicts_with_all = ["field", "raw", "to_request"])]
552 lane: bool,
553
554 #[command(flatten)]
555 rpc: RpcOpts,
556
557 #[arg(long)]
559 to_request: bool,
560
561 #[arg(long, short, num_args = 1, value_name = "NETWORK")]
563 network: Option<NetworkVariant>,
564 },
565
566 #[command(visible_alias = "re")]
568 Receipt {
569 tx_hash: String,
571
572 field: Option<String>,
574
575 #[arg(long, default_value = "1")]
577 confirmations: u64,
578
579 #[arg(id = "async", long = "async", env = "CAST_ASYNC", alias = "cast-async")]
581 cast_async: bool,
582
583 #[command(flatten)]
584 rpc: RpcOpts,
585 },
586
587 #[command(name = "send", visible_alias = "s")]
589 SendTx(SendTxArgs),
590
591 #[command(name = "batch-mktx", visible_alias = "bm")]
593 BatchMakeTx(BatchMakeTxArgs),
594
595 #[command(name = "batch-send", visible_alias = "bs")]
597 BatchSend(BatchSendArgs),
598
599 #[command(name = "publish", visible_alias = "p")]
601 PublishTx {
602 raw_tx: String,
604
605 #[arg(id = "async", long = "async", env = "CAST_ASYNC", alias = "cast-async")]
607 cast_async: bool,
608
609 #[command(flatten)]
610 rpc: RpcOpts,
611 },
612
613 #[command(visible_alias = "e")]
615 Estimate(EstimateArgs),
616
617 #[command(visible_aliases = &["calldata-decode", "--calldata-decode", "cdd"])]
622 DecodeCalldata {
623 sig: String,
625
626 #[arg(required_unless_present = "file", index = 2)]
628 calldata: Option<String>,
629
630 #[arg(long = "file", short = 'f', conflicts_with = "calldata")]
632 file: Option<PathBuf>,
633 },
634
635 #[command(visible_aliases = &["string-decode", "--string-decode", "sd"])]
639 DecodeString {
640 data: String,
642 },
643
644 #[command(visible_aliases = &["event-decode", "--event-decode", "ed"])]
646 DecodeEvent {
647 #[arg(long, visible_alias = "event-sig")]
649 sig: Option<String>,
650 data: String,
652 },
653
654 #[command(visible_aliases = &["error-decode", "--error-decode", "erd"])]
656 DecodeError {
657 #[arg(long, visible_alias = "error-sig")]
659 sig: Option<String>,
660 data: String,
662 },
663
664 #[command(name = "decode-abi", visible_aliases = &["abi-decode", "--abi-decode", "ad"])]
670 DecodeAbi {
671 sig: String,
673
674 calldata: String,
676
677 #[arg(long, short, help_heading = "Decode input data instead of output data")]
679 input: bool,
680 },
681
682 #[command(visible_alias = "ae")]
684 AbiEncode {
685 sig: String,
687
688 #[arg(long)]
690 packed: bool,
691
692 #[arg(allow_hyphen_values = true)]
694 args: Vec<String>,
695 },
696
697 #[command(visible_alias = "aee")]
699 AbiEncodeEvent {
700 sig: String,
702
703 #[arg(allow_hyphen_values = true)]
705 args: Vec<String>,
706 },
707
708 #[command(visible_alias = "in")]
710 Index {
711 key_type: String,
713
714 key: String,
716
717 slot_number: String,
719 },
720
721 #[command(name = "index-erc7201", alias = "index-erc-7201", visible_aliases = &["index7201", "in7201"])]
723 IndexErc7201 {
724 id: Option<String>,
726 #[arg(long, default_value = "erc7201")]
728 formula_id: String,
729 },
730
731 #[command(visible_alias = "impl")]
734 Implementation {
735 #[arg(long, short = 'B')]
739 block: Option<BlockId>,
740
741 #[arg(long)]
745 beacon: bool,
746
747 #[arg(value_parser = NameOrAddress::from_str)]
749 who: NameOrAddress,
750
751 #[command(flatten)]
752 rpc: RpcOpts,
753 },
754
755 #[command(visible_alias = "adm")]
757 Admin {
758 #[arg(long, short = 'B')]
762 block: Option<BlockId>,
763
764 #[arg(value_parser = NameOrAddress::from_str)]
766 who: NameOrAddress,
767
768 #[command(flatten)]
769 rpc: RpcOpts,
770 },
771
772 #[command(name = "4byte", visible_aliases = &["4", "4b"])]
774 FourByte {
775 selector: Option<Selector>,
777 },
778
779 #[command(name = "4byte-calldata", aliases = &["4byte-decode", "4d", "4bd"], visible_aliases = &["4c", "4bc"])]
781 FourByteCalldata {
782 calldata: Option<String>,
784 },
785
786 #[command(name = "4byte-event", visible_aliases = &["4e", "4be", "topic0-event", "t0e"])]
788 FourByteEvent {
789 #[arg(value_name = "TOPIC_0")]
791 topic: Option<B256>,
792 },
793
794 #[command(visible_aliases = &["ups"])]
802 UploadSignature {
803 signatures: Vec<String>,
808 },
809
810 #[command(visible_alias = "pc")]
814 PrettyCalldata {
815 calldata: Option<String>,
817
818 #[arg(long, short)]
820 offline: bool,
821 },
822
823 #[command(visible_alias = "a")]
825 Age {
826 block: Option<BlockId>,
830
831 #[command(flatten)]
832 rpc: RpcOpts,
833 },
834
835 #[command(visible_alias = "b")]
837 Balance {
838 #[arg(long, short = 'B')]
842 block: Option<BlockId>,
843
844 #[arg(value_parser = NameOrAddress::from_str)]
846 who: NameOrAddress,
847
848 #[arg(long, short)]
850 ether: bool,
851
852 #[command(flatten)]
853 rpc: RpcOpts,
854
855 #[arg(long, alias = "erc721")]
858 erc20: Option<Address>,
859 },
860
861 #[command(visible_aliases = &["ba", "fee", "basefee"])]
863 BaseFee {
864 block: Option<BlockId>,
868
869 #[command(flatten)]
870 rpc: RpcOpts,
871 },
872
873 #[command(visible_alias = "co")]
875 Code {
876 #[arg(long, short = 'B')]
880 block: Option<BlockId>,
881
882 #[arg(value_parser = NameOrAddress::from_str)]
884 who: NameOrAddress,
885
886 #[arg(long, short)]
888 disassemble: bool,
889
890 #[command(flatten)]
891 rpc: RpcOpts,
892 },
893
894 #[command(visible_alias = "cs")]
896 Codesize {
897 #[arg(long, short = 'B')]
901 block: Option<BlockId>,
902
903 #[arg(value_parser = NameOrAddress::from_str)]
905 who: NameOrAddress,
906
907 #[command(flatten)]
908 rpc: RpcOpts,
909 },
910
911 #[command(visible_alias = "g")]
913 GasPrice {
914 #[command(flatten)]
915 rpc: RpcOpts,
916 },
917
918 #[command(visible_alias = "se")]
920 SigEvent {
921 event_string: Option<String>,
923 },
924
925 #[command(visible_aliases = &["k", "keccak256"])]
927 Keccak {
928 data: Option<String>,
930 },
931
932 #[command(visible_aliases = &["--hash-message", "hm"])]
934 HashMessage {
935 message: Option<String>,
937 },
938
939 #[command(visible_alias = "rn")]
941 ResolveName {
942 who: Option<String>,
944
945 #[arg(long)]
947 verify: bool,
948
949 #[command(flatten)]
950 rpc: RpcOpts,
951 },
952
953 #[command(visible_alias = "la")]
955 LookupAddress {
956 who: Option<Address>,
958
959 #[arg(long)]
961 verify: bool,
962
963 #[command(flatten)]
964 rpc: RpcOpts,
965 },
966
967 #[command(visible_alias = "st")]
969 Storage(StorageArgs),
970
971 #[command(visible_alias = "pr")]
973 Proof {
974 #[arg(value_parser = NameOrAddress::from_str)]
976 address: NameOrAddress,
977
978 #[arg(value_parser = parse_slot)]
980 slots: Vec<B256>,
981
982 #[arg(long, short = 'B')]
986 block: Option<BlockId>,
987
988 #[command(flatten)]
989 rpc: RpcOpts,
990 },
991
992 #[command(visible_alias = "n")]
994 Nonce {
995 #[arg(long, short = 'B')]
999 block: Option<BlockId>,
1000
1001 #[arg(value_parser = NameOrAddress::from_str)]
1003 who: NameOrAddress,
1004
1005 #[command(flatten)]
1006 rpc: RpcOpts,
1007 },
1008
1009 #[command()]
1011 Codehash {
1012 #[arg(long, short = 'B')]
1016 block: Option<BlockId>,
1017
1018 #[arg(value_parser = NameOrAddress::from_str)]
1020 who: NameOrAddress,
1021
1022 #[arg(value_parser = parse_slot)]
1024 slots: Vec<B256>,
1025
1026 #[command(flatten)]
1027 rpc: RpcOpts,
1028 },
1029
1030 #[command(visible_alias = "sr")]
1032 StorageRoot {
1033 #[arg(long, short = 'B')]
1037 block: Option<BlockId>,
1038
1039 #[arg(value_parser = NameOrAddress::from_str)]
1041 who: NameOrAddress,
1042
1043 #[arg(value_parser = parse_slot)]
1045 slots: Vec<B256>,
1046
1047 #[command(flatten)]
1048 rpc: RpcOpts,
1049 },
1050
1051 #[command(name = "channel-id")]
1053 ChannelId {
1054 #[arg(value_parser = NameOrAddress::from_str)]
1056 payer: NameOrAddress,
1057
1058 #[arg(value_parser = NameOrAddress::from_str)]
1060 payee: NameOrAddress,
1061
1062 #[arg(value_parser = NameOrAddress::from_str)]
1064 token: NameOrAddress,
1065
1066 salt: B256,
1068
1069 #[arg(long, value_parser = NameOrAddress::from_str)]
1071 operator: Option<NameOrAddress>,
1072
1073 #[arg(long, value_parser = NameOrAddress::from_str)]
1075 authorized_signer: Option<NameOrAddress>,
1076
1077 #[arg(long, default_value_t = B256::ZERO)]
1079 expiring_nonce_hash: B256,
1080
1081 #[arg(long, value_parser = NameOrAddress::from_str)]
1083 reserve: Option<NameOrAddress>,
1084
1085 #[arg(long, short = 'B')]
1089 block: Option<BlockId>,
1090
1091 #[command(flatten)]
1092 rpc: RpcOpts,
1093 },
1094
1095 #[command(visible_aliases = &["et", "src"])]
1097 Source {
1098 address: String,
1100
1101 #[arg(long, short)]
1103 flatten: bool,
1104
1105 #[arg(short, value_hint = ValueHint::DirPath, alias = "path")]
1107 directory: Option<PathBuf>,
1108
1109 #[command(flatten)]
1110 etherscan: EtherscanOpts,
1111
1112 #[arg(long, env = "EXPLORER_API_URL")]
1115 explorer_api_url: Option<String>,
1116
1117 #[arg(long, env = "EXPLORER_URL")]
1119 explorer_url: Option<String>,
1120 },
1121
1122 #[command(visible_alias = "w")]
1124 Wallet {
1125 #[command(subcommand)]
1126 command: WalletSubcommands,
1127 },
1128
1129 #[command(visible_alias = "cc")]
1131 CreationCode(CreationCodeArgs),
1132
1133 #[command(visible_alias = "ar")]
1135 Artifact(ArtifactArgs),
1136
1137 #[command(visible_alias = "cra")]
1139 ConstructorArgs(ConstructorArgsArgs),
1140
1141 #[command(visible_alias = "i")]
1145 Interface(InterfaceArgs),
1146
1147 #[command(visible_alias = "bi")]
1149 Bind(BindArgs),
1150
1151 #[command(visible_alias = "b2e")]
1153 B2EPayload(B2EPayloadArgs),
1154
1155 #[command(visible_alias = "si")]
1157 Sig {
1158 sig: Option<String>,
1160
1161 #[arg(conflicts_with = "json")]
1163 optimize: Option<usize>,
1164 },
1165
1166 #[command(visible_alias = "c2")]
1168 Create2(Create2Args),
1169
1170 #[command(visible_alias = "f")]
1172 FindBlock(FindBlockArgs),
1173
1174 #[command(visible_alias = "com")]
1176 Completions {
1177 #[arg(value_enum)]
1178 shell: foundry_cli::clap::Shell,
1179 },
1180
1181 #[command(visible_alias = "r")]
1183 Run(RunArgs),
1184
1185 #[command(visible_alias = "rp")]
1187 Rpc(RpcArgs),
1188
1189 #[command(name = "format-bytes32-string", visible_aliases = &["--format-bytes32-string"])]
1191 FormatBytes32String {
1192 string: Option<String>,
1194 },
1195
1196 #[command(name = "parse-bytes32-string", visible_aliases = &["--parse-bytes32-string"])]
1198 ParseBytes32String {
1199 bytes: Option<String>,
1201 },
1202 #[command(name = "parse-bytes32-address", visible_aliases = &["--parse-bytes32-address"])]
1203 #[command(about = "Parses a checksummed address from bytes32 encoding.")]
1204 ParseBytes32Address {
1205 #[arg(value_name = "BYTES")]
1206 bytes: Option<String>,
1207 },
1208
1209 #[command(visible_aliases = &["dt", "decode-tx"])]
1211 DecodeTransaction {
1212 tx: Option<String>,
1214
1215 #[arg(long, short, num_args = 1, value_name = "NETWORK")]
1217 network: Option<NetworkVariant>,
1218 },
1219
1220 #[command(visible_aliases = &["decode-auth"])]
1222 RecoverAuthority { auth: String },
1223
1224 #[command(visible_alias = "sel")]
1226 Selectors {
1227 bytecode: Option<String>,
1229
1230 #[arg(long, short)]
1232 resolve: bool,
1233 },
1234
1235 #[command(visible_alias = "tp")]
1237 TxPool {
1238 #[command(subcommand)]
1239 command: TxPoolSubcommands,
1240 },
1241 #[cfg(feature = "optimism")]
1243 #[command(name = "da-estimate")]
1244 DAEstimate(DAEstimateArgs),
1245
1246 #[command(visible_alias = "erc20")]
1248 Erc20Token {
1249 #[command(subcommand)]
1250 command: Erc20Subcommand,
1251 },
1252
1253 #[command(visible_alias = "tip20")]
1255 Tip20Token {
1256 #[command(subcommand)]
1257 command: Tip20Subcommand,
1258 },
1259
1260 #[command(visible_alias = "kc")]
1262 Keychain {
1263 #[command(subcommand)]
1264 command: KeychainSubcommand,
1265 },
1266
1267 #[command(name = "key-auth")]
1269 KeyAuth {
1270 #[command(subcommand)]
1271 command: KeyAuthSubcommand,
1272 },
1273
1274 Tempo {
1276 #[command(subcommand)]
1277 command: TempoSubcommand,
1278 },
1279
1280 #[command(visible_alias = "vaddr")]
1282 VirtualAddress {
1283 #[command(subcommand)]
1284 command: VaddrSubcommand,
1285 },
1286
1287 #[command(name = "trace")]
1288 Trace(TraceArgs),
1289}
1290
1291#[derive(Debug, Parser)]
1293pub struct ToBaseArgs {
1294 #[arg(allow_hyphen_values = true)]
1296 pub value: Option<String>,
1297
1298 #[arg(long, short = 'i')]
1300 pub base_in: Option<String>,
1301}
1302
1303pub fn parse_slot(s: &str) -> Result<B256> {
1304 let slot = U256::from_str(s).map_err(|e| eyre::eyre!("Could not parse slot number: {e}"))?;
1305 Ok(B256::from(slot))
1306}
1307
1308#[cfg(test)]
1309mod tests {
1310 use super::*;
1311 use crate::SimpleCast;
1312 use alloy_rpc_types::{BlockNumberOrTag, RpcBlockHash};
1313 use clap::CommandFactory;
1314
1315 #[test]
1316 fn verify_cli() {
1317 Cast::command().debug_assert();
1318 }
1319
1320 #[test]
1321 fn parse_proof_slot() {
1322 let args: Cast = Cast::parse_from([
1323 "foundry-cli",
1324 "proof",
1325 "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
1326 "0",
1327 "1",
1328 "0x0000000000000000000000000000000000000000000000000000000000000000",
1329 "0x1",
1330 "0x01",
1331 ]);
1332 match args.cmd {
1333 CastSubcommand::Proof { slots, .. } => {
1334 assert_eq!(
1335 slots,
1336 vec![
1337 B256::ZERO,
1338 U256::from(1).into(),
1339 B256::ZERO,
1340 U256::from(1).into(),
1341 U256::from(1).into()
1342 ]
1343 );
1344 }
1345 _ => unreachable!(),
1346 };
1347 }
1348
1349 #[test]
1350 fn parse_call_data() {
1351 let args: Cast = Cast::parse_from([
1352 "foundry-cli",
1353 "calldata",
1354 "f()",
1355 "5c9d55b78febcc2061715ba4f57ecf8ea2711f2c",
1356 "2",
1357 ]);
1358 match args.cmd {
1359 CastSubcommand::CalldataEncode { args, .. } => {
1360 assert_eq!(
1361 args,
1362 vec!["5c9d55b78febcc2061715ba4f57ecf8ea2711f2c".to_string(), "2".to_string()]
1363 )
1364 }
1365 _ => unreachable!(),
1366 };
1367 }
1368
1369 #[test]
1370 fn parse_call_data_with_file() {
1371 let args: Cast = Cast::parse_from(["foundry-cli", "calldata", "f()", "--file", "test.txt"]);
1372 match args.cmd {
1373 CastSubcommand::CalldataEncode { sig, file, args } => {
1374 assert_eq!(sig, "f()".to_string());
1375 assert_eq!(file, Some(PathBuf::from("test.txt")));
1376 assert!(args.is_empty());
1377 }
1378 _ => unreachable!(),
1379 };
1380 }
1381
1382 #[test]
1384 fn parse_signature() {
1385 let args: Cast = Cast::parse_from([
1386 "foundry-cli",
1387 "sig",
1388 "__$_$__$$$$$__$$_$$$_$$__$$___$$(address,address,uint256)",
1389 ]);
1390 match args.cmd {
1391 CastSubcommand::Sig { sig, .. } => {
1392 let sig = sig.unwrap();
1393 assert_eq!(
1394 sig,
1395 "__$_$__$$$$$__$$_$$$_$$__$$___$$(address,address,uint256)".to_string()
1396 );
1397
1398 let selector = SimpleCast::get_selector(&sig, 0).unwrap();
1399 assert_eq!(selector.0, "0x23b872dd".to_string());
1400 }
1401 _ => unreachable!(),
1402 };
1403 }
1404
1405 #[test]
1406 fn parse_block_ids() {
1407 struct TestCase {
1408 input: String,
1409 expect: BlockId,
1410 }
1411
1412 let test_cases = [
1413 TestCase {
1414 input: "0".to_string(),
1415 expect: BlockId::Number(BlockNumberOrTag::Number(0u64)),
1416 },
1417 TestCase {
1418 input: "0x56462c47c03df160f66819f0a79ea07def1569f8aac0fe91bb3a081159b61b4a"
1419 .to_string(),
1420 expect: BlockId::Hash(RpcBlockHash::from_hash(
1421 "0x56462c47c03df160f66819f0a79ea07def1569f8aac0fe91bb3a081159b61b4a"
1422 .parse()
1423 .unwrap(),
1424 None,
1425 )),
1426 },
1427 TestCase {
1428 input: "latest".to_string(),
1429 expect: BlockId::Number(BlockNumberOrTag::Latest),
1430 },
1431 TestCase {
1432 input: "earliest".to_string(),
1433 expect: BlockId::Number(BlockNumberOrTag::Earliest),
1434 },
1435 TestCase {
1436 input: "pending".to_string(),
1437 expect: BlockId::Number(BlockNumberOrTag::Pending),
1438 },
1439 TestCase { input: "safe".to_string(), expect: BlockId::Number(BlockNumberOrTag::Safe) },
1440 TestCase {
1441 input: "finalized".to_string(),
1442 expect: BlockId::Number(BlockNumberOrTag::Finalized),
1443 },
1444 ];
1445
1446 for test in test_cases {
1447 let result: BlockId = test.input.parse().unwrap();
1448 assert_eq!(result, test.expect);
1449 }
1450 }
1451}