1#[cfg(feature = "optimism")]
2use crate::cmd::da_estimate::DAEstimateArgs;
3use crate::cmd::{
4 access_list::AccessListArgs, artifact::ArtifactArgs, b2e_payload::B2EPayloadArgs,
5 batch_mktx::BatchMakeTxArgs, batch_send::BatchSendArgs, bind::BindArgs, call::CallArgs,
6 constructor_args::ConstructorArgsArgs, create2::Create2Args, creation_code::CreationCodeArgs,
7 erc20::Erc20Subcommand, estimate::EstimateArgs, find_block::FindBlockArgs,
8 interface::InterfaceArgs, keychain::KeychainSubcommand, logs::LogsArgs, mktx::MakeTxArgs,
9 rpc::RpcArgs, run::RunArgs, send::SendTxArgs, storage::StorageArgs, tempo::TempoSubcommand,
10 tip20::Tip20Subcommand, trace::TraceArgs, txpool::TxPoolSubcommands, vaddr::VaddrSubcommand,
11 wallet::WalletSubcommands,
12};
13use alloy_ens::NameOrAddress;
14use alloy_primitives::{Address, B256, Selector, U256};
15use alloy_rpc_types::BlockId;
16use clap::{ArgAction, Parser, Subcommand, ValueHint};
17use eyre::Result;
18use foundry_cli::opts::{EtherscanOpts, GlobalArgs, RpcOpts};
19use foundry_common::version::{LONG_VERSION, SHORT_VERSION};
20use foundry_evm_networks::NetworkVariant;
21use std::{path::PathBuf, str::FromStr};
22#[derive(Parser)]
24#[command(
25 name = "cast",
26 version = SHORT_VERSION,
27 long_version = LONG_VERSION,
28 after_help = "Find more information in the book: https://getfoundry.sh/cast/overview",
29 next_display_order = None,
30)]
31pub struct Cast {
32 #[command(flatten)]
34 pub global: GlobalArgs,
35
36 #[command(subcommand)]
37 pub cmd: CastSubcommand,
38}
39
40#[derive(Subcommand)]
41pub enum CastSubcommand {
42 #[command(visible_aliases = &["--max-int", "maxi"])]
44 MaxInt {
45 #[arg(default_value = "int256")]
47 r#type: String,
48 },
49
50 #[command(visible_aliases = &["--min-int", "mini"])]
52 MinInt {
53 #[arg(default_value = "int256")]
55 r#type: String,
56 },
57
58 #[command(visible_aliases = &["--max-uint", "maxu"])]
60 MaxUint {
61 #[arg(default_value = "uint256")]
63 r#type: String,
64 },
65
66 #[command(visible_aliases = &["--address-zero", "az"])]
68 AddressZero,
69
70 #[command(visible_aliases = &["--hash-zero", "hz"])]
72 HashZero,
73
74 #[command(
76 visible_aliases = &[
77 "--from-ascii",
78 "--from-utf8",
79 "from-ascii",
80 "fu",
81 "fa"]
82 )]
83 FromUtf8 {
84 text: Option<String>,
86 },
87
88 #[command(visible_aliases = &["--concat-hex", "ch"])]
90 ConcatHex {
91 data: Vec<String>,
93 },
94
95 #[command(visible_aliases = &["--from-bin", "from-binx", "fb"])]
97 FromBin,
98
99 #[command(visible_aliases = &["--to-hexdata", "thd", "2hd"])]
107 ToHexdata {
108 input: Option<String>,
110 },
111
112 #[command(
114 visible_aliases = &["--to-checksum-address",
115 "--to-checksum",
116 "to-checksum",
117 "ta",
118 "2a"]
119 )]
120 ToCheckSumAddress {
121 address: Option<Address>,
123 chain_id: Option<u64>,
125 },
126
127 #[command(visible_aliases = &["--to-ascii", "tas", "2as"])]
129 ToAscii {
130 hexdata: Option<String>,
132 },
133
134 #[command(visible_aliases = &["--to-utf8", "tu8", "2u8"])]
136 ToUtf8 {
137 hexdata: Option<String>,
139 },
140
141 #[command(visible_aliases = &["--from-fix", "ff"])]
143 FromFixedPoint {
144 decimals: Option<String>,
146
147 #[arg(allow_hyphen_values = true)]
149 value: Option<String>,
150 },
151
152 #[command(visible_aliases = &["--to-bytes32", "tb", "2b"])]
154 ToBytes32 {
155 bytes: Option<String>,
157 },
158
159 #[command(visible_aliases = &["pd"])]
161 Pad {
162 data: Option<String>,
164
165 #[arg(long)]
167 right: bool,
168
169 #[arg(long, conflicts_with = "right")]
171 left: bool,
172
173 #[arg(long, default_value = "32")]
175 len: usize,
176 },
177
178 #[command(visible_aliases = &["--to-fix", "tf", "2f"])]
180 ToFixedPoint {
181 decimals: Option<String>,
183
184 #[arg(allow_hyphen_values = true)]
186 value: Option<String>,
187 },
188
189 #[command(name = "to-uint256", visible_aliases = &["--to-uint256", "tu", "2u"])]
191 ToUint256 {
192 value: Option<String>,
194 },
195
196 #[command(name = "to-int256", visible_aliases = &["--to-int256", "ti", "2i"])]
198 ToInt256 {
199 value: Option<String>,
201 },
202
203 #[command(name = "shl")]
205 LeftShift {
206 value: String,
208
209 bits: String,
211
212 #[arg(long)]
214 base_in: Option<String>,
215
216 #[arg(long, default_value = "16")]
218 base_out: String,
219 },
220
221 #[command(name = "shr")]
223 RightShift {
224 value: String,
226
227 bits: String,
229
230 #[arg(long)]
232 base_in: Option<String>,
233
234 #[arg(long, default_value = "16")]
236 base_out: String,
237 },
238
239 #[command(visible_aliases = &["--to-unit", "tun", "2un"])]
248 ToUnit {
249 value: Option<String>,
251
252 #[arg(default_value = "wei")]
254 unit: String,
255 },
256
257 #[command(visible_aliases = &["--parse-units", "pun"])]
264 ParseUnits {
265 value: Option<String>,
267
268 #[arg(default_value = "18")]
270 unit: u8,
271 },
272
273 #[command(visible_aliases = &["--format-units", "fun"])]
280 FormatUnits {
281 value: Option<String>,
283
284 #[arg(default_value = "18")]
286 unit: u8,
287 },
288
289 #[command(visible_aliases = &["--to-wei", "tw", "2w"])]
293 ToWei {
294 #[arg(allow_hyphen_values = true)]
296 value: Option<String>,
297
298 #[arg(default_value = "eth")]
300 unit: String,
301 },
302
303 #[command(visible_aliases = &["--from-wei", "fw"])]
307 FromWei {
308 #[arg(allow_hyphen_values = true)]
310 value: Option<String>,
311
312 #[arg(default_value = "eth")]
314 unit: String,
315 },
316
317 #[command(visible_aliases = &["--to-rlp"])]
328 ToRlp {
329 value: Option<String>,
334 },
335
336 #[command(visible_aliases = &["--from-rlp"])]
338 FromRlp {
339 value: Option<String>,
341
342 #[arg(long, alias = "int")]
344 as_int: bool,
345 },
346
347 #[command(visible_aliases = &["--to-hex", "th", "2h"])]
349 ToHex(ToBaseArgs),
350
351 #[command(visible_aliases = &["--to-dec", "td", "2d"])]
353 ToDec(ToBaseArgs),
354
355 #[command(
357 visible_aliases = &["--to-base",
358 "--to-radix",
359 "to-radix",
360 "tr",
361 "2r"]
362 )]
363 ToBase {
364 #[command(flatten)]
365 base: ToBaseArgs,
366
367 #[arg(value_name = "BASE")]
369 base_out: Option<String>,
370 },
371 #[command(visible_aliases = &["ac", "acl"])]
373 AccessList(AccessListArgs),
374 #[command(visible_alias = "l")]
376 Logs(LogsArgs),
377 #[command(visible_alias = "bl")]
379 Block {
380 block: Option<BlockId>,
384
385 #[arg(short, long = "field", aliases = ["fields"], num_args = 0.., action = ArgAction::Append, value_delimiter = ',')]
387 fields: Vec<String>,
388
389 #[arg(long, conflicts_with = "fields")]
391 raw: bool,
392
393 #[arg(long, env = "CAST_FULL_BLOCK")]
394 full: bool,
395
396 #[command(flatten)]
397 rpc: RpcOpts,
398
399 #[arg(long, short, num_args = 1, value_name = "NETWORK")]
401 network: Option<NetworkVariant>,
402 },
403
404 #[command(visible_alias = "bn")]
406 BlockNumber {
407 block: Option<BlockId>,
409 #[command(flatten)]
410 rpc: RpcOpts,
411 },
412
413 #[command(visible_alias = "c")]
415 Call(CallArgs),
416
417 #[command(name = "calldata", visible_alias = "cd")]
419 CalldataEncode {
420 sig: String,
422
423 #[arg(allow_hyphen_values = true)]
425 args: Vec<String>,
426
427 #[arg(long, value_name = "PATH")]
429 file: Option<PathBuf>,
430 },
431
432 Chain {
434 #[command(flatten)]
435 rpc: RpcOpts,
436 },
437
438 #[command(visible_aliases = &["ci", "cid"])]
440 ChainId {
441 #[command(flatten)]
442 rpc: RpcOpts,
443 },
444
445 #[command(visible_alias = "cl")]
447 Client {
448 #[command(flatten)]
449 rpc: RpcOpts,
450 },
451
452 #[command(visible_alias = "ca")]
454 ComputeAddress {
455 address: Option<Address>,
457
458 #[arg(
460 long,
461 conflicts_with = "salt",
462 conflicts_with = "init_code",
463 conflicts_with = "init_code_hash"
464 )]
465 nonce: Option<u64>,
466
467 #[arg(long, conflicts_with = "nonce")]
469 salt: Option<B256>,
470
471 #[arg(
473 long,
474 requires = "salt",
475 conflicts_with = "init_code_hash",
476 conflicts_with = "nonce"
477 )]
478 init_code: Option<String>,
479
480 #[arg(long, requires = "salt", conflicts_with = "init_code", conflicts_with = "nonce")]
482 init_code_hash: Option<B256>,
483
484 #[command(flatten)]
485 rpc: RpcOpts,
486 },
487
488 #[command(visible_alias = "da")]
490 Disassemble {
491 bytecode: Option<String>,
493 },
494
495 #[command(name = "mktx", visible_alias = "m")]
497 MakeTx(MakeTxArgs),
498
499 #[command(visible_aliases = &["na", "nh"])]
501 Namehash { name: Option<String> },
502
503 #[command(visible_alias = "t")]
505 Tx {
506 tx_hash: Option<String>,
508
509 #[arg(long, value_parser = NameOrAddress::from_str)]
511 from: Option<NameOrAddress>,
512
513 #[arg(long)]
515 nonce: Option<u64>,
516
517 field: Option<String>,
520
521 #[arg(long, conflicts_with = "field")]
523 raw: bool,
524
525 #[command(flatten)]
526 rpc: RpcOpts,
527
528 #[arg(long)]
530 to_request: bool,
531
532 #[arg(long, short, num_args = 1, value_name = "NETWORK")]
534 network: Option<NetworkVariant>,
535 },
536
537 #[command(visible_alias = "re")]
539 Receipt {
540 tx_hash: String,
542
543 field: Option<String>,
545
546 #[arg(long, default_value = "1")]
548 confirmations: u64,
549
550 #[arg(id = "async", long = "async", env = "CAST_ASYNC", alias = "cast-async")]
552 cast_async: bool,
553
554 #[command(flatten)]
555 rpc: RpcOpts,
556 },
557
558 #[command(name = "send", visible_alias = "s")]
560 SendTx(SendTxArgs),
561
562 #[command(name = "batch-mktx", visible_alias = "bm")]
564 BatchMakeTx(BatchMakeTxArgs),
565
566 #[command(name = "batch-send", visible_alias = "bs")]
568 BatchSend(BatchSendArgs),
569
570 #[command(name = "publish", visible_alias = "p")]
572 PublishTx {
573 raw_tx: String,
575
576 #[arg(id = "async", long = "async", env = "CAST_ASYNC", alias = "cast-async")]
578 cast_async: bool,
579
580 #[command(flatten)]
581 rpc: RpcOpts,
582 },
583
584 #[command(visible_alias = "e")]
586 Estimate(EstimateArgs),
587
588 #[command(visible_aliases = &["calldata-decode", "--calldata-decode", "cdd"])]
593 DecodeCalldata {
594 sig: String,
596
597 #[arg(required_unless_present = "file", index = 2)]
599 calldata: Option<String>,
600
601 #[arg(long = "file", short = 'f', conflicts_with = "calldata")]
603 file: Option<PathBuf>,
604 },
605
606 #[command(visible_aliases = &["string-decode", "--string-decode", "sd"])]
610 DecodeString {
611 data: String,
613 },
614
615 #[command(visible_aliases = &["event-decode", "--event-decode", "ed"])]
617 DecodeEvent {
618 #[arg(long, visible_alias = "event-sig")]
620 sig: Option<String>,
621 data: String,
623 },
624
625 #[command(visible_aliases = &["error-decode", "--error-decode", "erd"])]
627 DecodeError {
628 #[arg(long, visible_alias = "error-sig")]
630 sig: Option<String>,
631 data: String,
633 },
634
635 #[command(name = "decode-abi", visible_aliases = &["abi-decode", "--abi-decode", "ad"])]
641 DecodeAbi {
642 sig: String,
644
645 calldata: String,
647
648 #[arg(long, short, help_heading = "Decode input data instead of output data")]
650 input: bool,
651 },
652
653 #[command(visible_alias = "ae")]
655 AbiEncode {
656 sig: String,
658
659 #[arg(long)]
661 packed: bool,
662
663 #[arg(allow_hyphen_values = true)]
665 args: Vec<String>,
666 },
667
668 #[command(visible_alias = "aee")]
670 AbiEncodeEvent {
671 sig: String,
673
674 #[arg(allow_hyphen_values = true)]
676 args: Vec<String>,
677 },
678
679 #[command(visible_alias = "in")]
681 Index {
682 key_type: String,
684
685 key: String,
687
688 slot_number: String,
690 },
691
692 #[command(name = "index-erc7201", alias = "index-erc-7201", visible_aliases = &["index7201", "in7201"])]
694 IndexErc7201 {
695 id: Option<String>,
697 #[arg(long, default_value = "erc7201")]
699 formula_id: String,
700 },
701
702 #[command(visible_alias = "impl")]
705 Implementation {
706 #[arg(long, short = 'B')]
710 block: Option<BlockId>,
711
712 #[arg(long)]
716 beacon: bool,
717
718 #[arg(value_parser = NameOrAddress::from_str)]
720 who: NameOrAddress,
721
722 #[command(flatten)]
723 rpc: RpcOpts,
724 },
725
726 #[command(visible_alias = "adm")]
728 Admin {
729 #[arg(long, short = 'B')]
733 block: Option<BlockId>,
734
735 #[arg(value_parser = NameOrAddress::from_str)]
737 who: NameOrAddress,
738
739 #[command(flatten)]
740 rpc: RpcOpts,
741 },
742
743 #[command(name = "4byte", visible_aliases = &["4", "4b"])]
745 FourByte {
746 selector: Option<Selector>,
748 },
749
750 #[command(name = "4byte-calldata", aliases = &["4byte-decode", "4d", "4bd"], visible_aliases = &["4c", "4bc"])]
752 FourByteCalldata {
753 calldata: Option<String>,
755 },
756
757 #[command(name = "4byte-event", visible_aliases = &["4e", "4be", "topic0-event", "t0e"])]
759 FourByteEvent {
760 #[arg(value_name = "TOPIC_0")]
762 topic: Option<B256>,
763 },
764
765 #[command(visible_aliases = &["ups"])]
773 UploadSignature {
774 signatures: Vec<String>,
779 },
780
781 #[command(visible_alias = "pc")]
785 PrettyCalldata {
786 calldata: Option<String>,
788
789 #[arg(long, short)]
791 offline: bool,
792 },
793
794 #[command(visible_alias = "a")]
796 Age {
797 block: Option<BlockId>,
801
802 #[command(flatten)]
803 rpc: RpcOpts,
804 },
805
806 #[command(visible_alias = "b")]
808 Balance {
809 #[arg(long, short = 'B')]
813 block: Option<BlockId>,
814
815 #[arg(value_parser = NameOrAddress::from_str)]
817 who: NameOrAddress,
818
819 #[arg(long, short)]
821 ether: bool,
822
823 #[command(flatten)]
824 rpc: RpcOpts,
825
826 #[arg(long, alias = "erc721")]
829 erc20: Option<Address>,
830 },
831
832 #[command(visible_aliases = &["ba", "fee", "basefee"])]
834 BaseFee {
835 block: Option<BlockId>,
839
840 #[command(flatten)]
841 rpc: RpcOpts,
842 },
843
844 #[command(visible_alias = "co")]
846 Code {
847 #[arg(long, short = 'B')]
851 block: Option<BlockId>,
852
853 #[arg(value_parser = NameOrAddress::from_str)]
855 who: NameOrAddress,
856
857 #[arg(long, short)]
859 disassemble: bool,
860
861 #[command(flatten)]
862 rpc: RpcOpts,
863 },
864
865 #[command(visible_alias = "cs")]
867 Codesize {
868 #[arg(long, short = 'B')]
872 block: Option<BlockId>,
873
874 #[arg(value_parser = NameOrAddress::from_str)]
876 who: NameOrAddress,
877
878 #[command(flatten)]
879 rpc: RpcOpts,
880 },
881
882 #[command(visible_alias = "g")]
884 GasPrice {
885 #[command(flatten)]
886 rpc: RpcOpts,
887 },
888
889 #[command(visible_alias = "se")]
891 SigEvent {
892 event_string: Option<String>,
894 },
895
896 #[command(visible_aliases = &["k", "keccak256"])]
898 Keccak {
899 data: Option<String>,
901 },
902
903 #[command(visible_aliases = &["--hash-message", "hm"])]
905 HashMessage {
906 message: Option<String>,
908 },
909
910 #[command(visible_alias = "rn")]
912 ResolveName {
913 who: Option<String>,
915
916 #[arg(long)]
918 verify: bool,
919
920 #[command(flatten)]
921 rpc: RpcOpts,
922 },
923
924 #[command(visible_alias = "la")]
926 LookupAddress {
927 who: Option<Address>,
929
930 #[arg(long)]
932 verify: bool,
933
934 #[command(flatten)]
935 rpc: RpcOpts,
936 },
937
938 #[command(visible_alias = "st")]
940 Storage(StorageArgs),
941
942 #[command(visible_alias = "pr")]
944 Proof {
945 #[arg(value_parser = NameOrAddress::from_str)]
947 address: NameOrAddress,
948
949 #[arg(value_parser = parse_slot)]
951 slots: Vec<B256>,
952
953 #[arg(long, short = 'B')]
957 block: Option<BlockId>,
958
959 #[command(flatten)]
960 rpc: RpcOpts,
961 },
962
963 #[command(visible_alias = "n")]
965 Nonce {
966 #[arg(long, short = 'B')]
970 block: Option<BlockId>,
971
972 #[arg(value_parser = NameOrAddress::from_str)]
974 who: NameOrAddress,
975
976 #[command(flatten)]
977 rpc: RpcOpts,
978 },
979
980 #[command()]
982 Codehash {
983 #[arg(long, short = 'B')]
987 block: Option<BlockId>,
988
989 #[arg(value_parser = NameOrAddress::from_str)]
991 who: NameOrAddress,
992
993 #[arg(value_parser = parse_slot)]
995 slots: Vec<B256>,
996
997 #[command(flatten)]
998 rpc: RpcOpts,
999 },
1000
1001 #[command(visible_alias = "sr")]
1003 StorageRoot {
1004 #[arg(long, short = 'B')]
1008 block: Option<BlockId>,
1009
1010 #[arg(value_parser = NameOrAddress::from_str)]
1012 who: NameOrAddress,
1013
1014 #[arg(value_parser = parse_slot)]
1016 slots: Vec<B256>,
1017
1018 #[command(flatten)]
1019 rpc: RpcOpts,
1020 },
1021
1022 #[command(visible_aliases = &["et", "src"])]
1024 Source {
1025 address: String,
1027
1028 #[arg(long, short)]
1030 flatten: bool,
1031
1032 #[arg(short, value_hint = ValueHint::DirPath, alias = "path")]
1034 directory: Option<PathBuf>,
1035
1036 #[command(flatten)]
1037 etherscan: EtherscanOpts,
1038
1039 #[arg(long, env = "EXPLORER_API_URL")]
1042 explorer_api_url: Option<String>,
1043
1044 #[arg(long, env = "EXPLORER_URL")]
1046 explorer_url: Option<String>,
1047 },
1048
1049 #[command(visible_alias = "w")]
1051 Wallet {
1052 #[command(subcommand)]
1053 command: WalletSubcommands,
1054 },
1055
1056 #[command(visible_alias = "cc")]
1058 CreationCode(CreationCodeArgs),
1059
1060 #[command(visible_alias = "ar")]
1062 Artifact(ArtifactArgs),
1063
1064 #[command(visible_alias = "cra")]
1066 ConstructorArgs(ConstructorArgsArgs),
1067
1068 #[command(visible_alias = "i")]
1072 Interface(InterfaceArgs),
1073
1074 #[command(visible_alias = "bi")]
1076 Bind(BindArgs),
1077
1078 #[command(visible_alias = "b2e")]
1080 B2EPayload(B2EPayloadArgs),
1081
1082 #[command(visible_alias = "si")]
1084 Sig {
1085 sig: Option<String>,
1087
1088 optimize: Option<usize>,
1090 },
1091
1092 #[command(visible_alias = "c2")]
1094 Create2(Create2Args),
1095
1096 #[command(visible_alias = "f")]
1098 FindBlock(FindBlockArgs),
1099
1100 #[command(visible_alias = "com")]
1102 Completions {
1103 #[arg(value_enum)]
1104 shell: foundry_cli::clap::Shell,
1105 },
1106
1107 #[command(visible_alias = "r")]
1109 Run(RunArgs),
1110
1111 #[command(visible_alias = "rp")]
1113 Rpc(RpcArgs),
1114
1115 #[command(name = "format-bytes32-string", visible_aliases = &["--format-bytes32-string"])]
1117 FormatBytes32String {
1118 string: Option<String>,
1120 },
1121
1122 #[command(name = "parse-bytes32-string", visible_aliases = &["--parse-bytes32-string"])]
1124 ParseBytes32String {
1125 bytes: Option<String>,
1127 },
1128 #[command(name = "parse-bytes32-address", visible_aliases = &["--parse-bytes32-address"])]
1129 #[command(about = "Parses a checksummed address from bytes32 encoding.")]
1130 ParseBytes32Address {
1131 #[arg(value_name = "BYTES")]
1132 bytes: Option<String>,
1133 },
1134
1135 #[command(visible_aliases = &["dt", "decode-tx"])]
1137 DecodeTransaction {
1138 tx: Option<String>,
1140
1141 #[arg(long, short, num_args = 1, value_name = "NETWORK")]
1143 network: Option<NetworkVariant>,
1144 },
1145
1146 #[command(visible_aliases = &["decode-auth"])]
1148 RecoverAuthority { auth: String },
1149
1150 #[command(visible_alias = "sel")]
1152 Selectors {
1153 bytecode: Option<String>,
1155
1156 #[arg(long, short)]
1158 resolve: bool,
1159 },
1160
1161 #[command(visible_alias = "tp")]
1163 TxPool {
1164 #[command(subcommand)]
1165 command: TxPoolSubcommands,
1166 },
1167 #[cfg(feature = "optimism")]
1169 #[command(name = "da-estimate")]
1170 DAEstimate(DAEstimateArgs),
1171
1172 #[command(visible_alias = "erc20")]
1174 Erc20Token {
1175 #[command(subcommand)]
1176 command: Erc20Subcommand,
1177 },
1178
1179 #[command(visible_alias = "tip20")]
1181 Tip20Token {
1182 #[command(subcommand)]
1183 command: Tip20Subcommand,
1184 },
1185
1186 #[command(visible_alias = "kc")]
1188 Keychain {
1189 #[command(subcommand)]
1190 command: KeychainSubcommand,
1191 },
1192
1193 Tempo {
1195 #[command(subcommand)]
1196 command: TempoSubcommand,
1197 },
1198
1199 #[command(visible_alias = "vaddr")]
1201 VirtualAddress {
1202 #[command(subcommand)]
1203 command: VaddrSubcommand,
1204 },
1205
1206 #[command(name = "trace")]
1207 Trace(TraceArgs),
1208}
1209
1210#[derive(Debug, Parser)]
1212pub struct ToBaseArgs {
1213 #[arg(allow_hyphen_values = true)]
1215 pub value: Option<String>,
1216
1217 #[arg(long, short = 'i')]
1219 pub base_in: Option<String>,
1220}
1221
1222pub fn parse_slot(s: &str) -> Result<B256> {
1223 let slot = U256::from_str(s).map_err(|e| eyre::eyre!("Could not parse slot number: {e}"))?;
1224 Ok(B256::from(slot))
1225}
1226
1227#[cfg(test)]
1228mod tests {
1229 use super::*;
1230 use crate::SimpleCast;
1231 use alloy_rpc_types::{BlockNumberOrTag, RpcBlockHash};
1232 use clap::CommandFactory;
1233
1234 #[test]
1235 fn verify_cli() {
1236 Cast::command().debug_assert();
1237 }
1238
1239 #[test]
1240 fn parse_proof_slot() {
1241 let args: Cast = Cast::parse_from([
1242 "foundry-cli",
1243 "proof",
1244 "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
1245 "0",
1246 "1",
1247 "0x0000000000000000000000000000000000000000000000000000000000000000",
1248 "0x1",
1249 "0x01",
1250 ]);
1251 match args.cmd {
1252 CastSubcommand::Proof { slots, .. } => {
1253 assert_eq!(
1254 slots,
1255 vec![
1256 B256::ZERO,
1257 U256::from(1).into(),
1258 B256::ZERO,
1259 U256::from(1).into(),
1260 U256::from(1).into()
1261 ]
1262 );
1263 }
1264 _ => unreachable!(),
1265 };
1266 }
1267
1268 #[test]
1269 fn parse_call_data() {
1270 let args: Cast = Cast::parse_from([
1271 "foundry-cli",
1272 "calldata",
1273 "f()",
1274 "5c9d55b78febcc2061715ba4f57ecf8ea2711f2c",
1275 "2",
1276 ]);
1277 match args.cmd {
1278 CastSubcommand::CalldataEncode { args, .. } => {
1279 assert_eq!(
1280 args,
1281 vec!["5c9d55b78febcc2061715ba4f57ecf8ea2711f2c".to_string(), "2".to_string()]
1282 )
1283 }
1284 _ => unreachable!(),
1285 };
1286 }
1287
1288 #[test]
1289 fn parse_call_data_with_file() {
1290 let args: Cast = Cast::parse_from(["foundry-cli", "calldata", "f()", "--file", "test.txt"]);
1291 match args.cmd {
1292 CastSubcommand::CalldataEncode { sig, file, args } => {
1293 assert_eq!(sig, "f()".to_string());
1294 assert_eq!(file, Some(PathBuf::from("test.txt")));
1295 assert!(args.is_empty());
1296 }
1297 _ => unreachable!(),
1298 };
1299 }
1300
1301 #[test]
1303 fn parse_signature() {
1304 let args: Cast = Cast::parse_from([
1305 "foundry-cli",
1306 "sig",
1307 "__$_$__$$$$$__$$_$$$_$$__$$___$$(address,address,uint256)",
1308 ]);
1309 match args.cmd {
1310 CastSubcommand::Sig { sig, .. } => {
1311 let sig = sig.unwrap();
1312 assert_eq!(
1313 sig,
1314 "__$_$__$$$$$__$$_$$$_$$__$$___$$(address,address,uint256)".to_string()
1315 );
1316
1317 let selector = SimpleCast::get_selector(&sig, 0).unwrap();
1318 assert_eq!(selector.0, "0x23b872dd".to_string());
1319 }
1320 _ => unreachable!(),
1321 };
1322 }
1323
1324 #[test]
1325 fn parse_block_ids() {
1326 struct TestCase {
1327 input: String,
1328 expect: BlockId,
1329 }
1330
1331 let test_cases = [
1332 TestCase {
1333 input: "0".to_string(),
1334 expect: BlockId::Number(BlockNumberOrTag::Number(0u64)),
1335 },
1336 TestCase {
1337 input: "0x56462c47c03df160f66819f0a79ea07def1569f8aac0fe91bb3a081159b61b4a"
1338 .to_string(),
1339 expect: BlockId::Hash(RpcBlockHash::from_hash(
1340 "0x56462c47c03df160f66819f0a79ea07def1569f8aac0fe91bb3a081159b61b4a"
1341 .parse()
1342 .unwrap(),
1343 None,
1344 )),
1345 },
1346 TestCase {
1347 input: "latest".to_string(),
1348 expect: BlockId::Number(BlockNumberOrTag::Latest),
1349 },
1350 TestCase {
1351 input: "earliest".to_string(),
1352 expect: BlockId::Number(BlockNumberOrTag::Earliest),
1353 },
1354 TestCase {
1355 input: "pending".to_string(),
1356 expect: BlockId::Number(BlockNumberOrTag::Pending),
1357 },
1358 TestCase { input: "safe".to_string(), expect: BlockId::Number(BlockNumberOrTag::Safe) },
1359 TestCase {
1360 input: "finalized".to_string(),
1361 expect: BlockId::Number(BlockNumberOrTag::Finalized),
1362 },
1363 ];
1364
1365 for test in test_cases {
1366 let result: BlockId = test.input.parse().unwrap();
1367 assert_eq!(result, test.expect);
1368 }
1369 }
1370}