1use crate::cmd::{
2 access_list::AccessListArgs, artifact::ArtifactArgs, bind::BindArgs, call::CallArgs,
3 constructor_args::ConstructorArgsArgs, create2::Create2Args, creation_code::CreationCodeArgs,
4 da_estimate::DAEstimateArgs, estimate::EstimateArgs, find_block::FindBlockArgs,
5 interface::InterfaceArgs, logs::LogsArgs, mktx::MakeTxArgs, rpc::RpcArgs, run::RunArgs,
6 send::SendTxArgs, storage::StorageArgs, txpool::TxPoolSubcommands, wallet::WalletSubcommands,
7};
8use alloy_ens::NameOrAddress;
9use alloy_primitives::{Address, B256, Selector, U256};
10use alloy_rpc_types::BlockId;
11use clap::{Parser, Subcommand, ValueHint};
12use eyre::Result;
13use foundry_cli::opts::{EtherscanOpts, GlobalArgs, RpcOpts};
14use foundry_common::version::{LONG_VERSION, SHORT_VERSION};
15use std::{path::PathBuf, str::FromStr};
16
17#[derive(Parser)]
19#[command(
20 name = "cast",
21 version = SHORT_VERSION,
22 long_version = LONG_VERSION,
23 after_help = "Find more information in the book: https://getfoundry.sh/cast/overview",
24 next_display_order = None,
25)]
26pub struct Cast {
27 #[command(flatten)]
29 pub global: GlobalArgs,
30
31 #[command(subcommand)]
32 pub cmd: CastSubcommand,
33}
34
35#[derive(Subcommand)]
36pub enum CastSubcommand {
37 #[command(visible_aliases = &["--max-int", "maxi"])]
39 MaxInt {
40 #[arg(default_value = "int256")]
42 r#type: String,
43 },
44
45 #[command(visible_aliases = &["--min-int", "mini"])]
47 MinInt {
48 #[arg(default_value = "int256")]
50 r#type: String,
51 },
52
53 #[command(visible_aliases = &["--max-uint", "maxu"])]
55 MaxUint {
56 #[arg(default_value = "uint256")]
58 r#type: String,
59 },
60
61 #[command(visible_aliases = &["--address-zero", "az"])]
63 AddressZero,
64
65 #[command(visible_aliases = &["--hash-zero", "hz"])]
67 HashZero,
68
69 #[command(
71 visible_aliases = &[
72 "--from-ascii",
73 "--from-utf8",
74 "from-ascii",
75 "fu",
76 "fa"]
77 )]
78 FromUtf8 {
79 text: Option<String>,
81 },
82
83 #[command(visible_aliases = &["--concat-hex", "ch"])]
85 ConcatHex {
86 data: Vec<String>,
88 },
89
90 #[command(visible_aliases = &["--from-bin", "from-binx", "fb"])]
92 FromBin,
93
94 #[command(visible_aliases = &["--to-hexdata", "thd", "2hd"])]
102 ToHexdata {
103 input: Option<String>,
105 },
106
107 #[command(
109 visible_aliases = &["--to-checksum-address",
110 "--to-checksum",
111 "to-checksum",
112 "ta",
113 "2a"]
114 )]
115 ToCheckSumAddress {
116 address: Option<Address>,
118 chain_id: Option<u64>,
120 },
121
122 #[command(visible_aliases = &["--to-ascii", "tas", "2as"])]
124 ToAscii {
125 hexdata: Option<String>,
127 },
128
129 #[command(visible_aliases = &["--to-utf8", "tu8", "2u8"])]
131 ToUtf8 {
132 hexdata: Option<String>,
134 },
135
136 #[command(visible_aliases = &["--from-fix", "ff"])]
138 FromFixedPoint {
139 decimals: Option<String>,
141
142 #[arg(allow_hyphen_values = true)]
144 value: Option<String>,
145 },
146
147 #[command(visible_aliases = &["--to-bytes32", "tb", "2b"])]
149 ToBytes32 {
150 bytes: Option<String>,
152 },
153
154 #[command(visible_aliases = &["pd"])]
156 Pad {
157 data: Option<String>,
159
160 #[arg(long)]
162 right: bool,
163
164 #[arg(long, conflicts_with = "right")]
166 left: bool,
167
168 #[arg(long, default_value = "32")]
170 len: usize,
171 },
172
173 #[command(visible_aliases = &["--to-fix", "tf", "2f"])]
175 ToFixedPoint {
176 decimals: Option<String>,
178
179 #[arg(allow_hyphen_values = true)]
181 value: Option<String>,
182 },
183
184 #[command(name = "to-uint256", visible_aliases = &["--to-uint256", "tu", "2u"])]
186 ToUint256 {
187 value: Option<String>,
189 },
190
191 #[command(name = "to-int256", visible_aliases = &["--to-int256", "ti", "2i"])]
193 ToInt256 {
194 value: Option<String>,
196 },
197
198 #[command(name = "shl")]
200 LeftShift {
201 value: String,
203
204 bits: String,
206
207 #[arg(long)]
209 base_in: Option<String>,
210
211 #[arg(long, default_value = "16")]
213 base_out: String,
214 },
215
216 #[command(name = "shr")]
218 RightShift {
219 value: String,
221
222 bits: String,
224
225 #[arg(long)]
227 base_in: Option<String>,
228
229 #[arg(long, default_value = "16")]
231 base_out: String,
232 },
233
234 #[command(visible_aliases = &["--to-unit", "tun", "2un"])]
243 ToUnit {
244 value: Option<String>,
246
247 #[arg(default_value = "wei")]
249 unit: String,
250 },
251
252 #[command(visible_aliases = &["--parse-units", "pun"])]
259 ParseUnits {
260 value: Option<String>,
262
263 #[arg(default_value = "18")]
265 unit: u8,
266 },
267
268 #[command(visible_aliases = &["--format-units", "fun"])]
275 FormatUnits {
276 value: Option<String>,
278
279 #[arg(default_value = "18")]
281 unit: u8,
282 },
283
284 #[command(visible_aliases = &["--to-wei", "tw", "2w"])]
288 ToWei {
289 #[arg(allow_hyphen_values = true)]
291 value: Option<String>,
292
293 #[arg(default_value = "eth")]
295 unit: String,
296 },
297
298 #[command(visible_aliases = &["--from-wei", "fw"])]
302 FromWei {
303 #[arg(allow_hyphen_values = true)]
305 value: Option<String>,
306
307 #[arg(default_value = "eth")]
309 unit: String,
310 },
311
312 #[command(visible_aliases = &["--to-rlp"])]
323 ToRlp {
324 value: Option<String>,
329 },
330
331 #[command(visible_aliases = &["--from-rlp"])]
333 FromRlp {
334 value: Option<String>,
336
337 #[arg(long, alias = "int")]
339 as_int: bool,
340 },
341
342 #[command(visible_aliases = &["--to-hex", "th", "2h"])]
344 ToHex(ToBaseArgs),
345
346 #[command(visible_aliases = &["--to-dec", "td", "2d"])]
348 ToDec(ToBaseArgs),
349
350 #[command(
352 visible_aliases = &["--to-base",
353 "--to-radix",
354 "to-radix",
355 "tr",
356 "2r"]
357 )]
358 ToBase {
359 #[command(flatten)]
360 base: ToBaseArgs,
361
362 #[arg(value_name = "BASE")]
364 base_out: Option<String>,
365 },
366 #[command(visible_aliases = &["ac", "acl"])]
368 AccessList(AccessListArgs),
369 #[command(visible_alias = "l")]
371 Logs(LogsArgs),
372 #[command(visible_alias = "bl")]
374 Block {
375 block: Option<BlockId>,
379
380 #[arg(long, short)]
382 field: Option<String>,
383
384 #[arg(long, conflicts_with = "field")]
386 raw: bool,
387
388 #[arg(long, env = "CAST_FULL_BLOCK")]
389 full: bool,
390
391 #[command(flatten)]
392 rpc: RpcOpts,
393 },
394
395 #[command(visible_alias = "bn")]
397 BlockNumber {
398 block: Option<BlockId>,
400 #[command(flatten)]
401 rpc: RpcOpts,
402 },
403
404 #[command(visible_alias = "c")]
406 Call(CallArgs),
407
408 #[command(name = "calldata", visible_alias = "cd")]
410 CalldataEncode {
411 sig: String,
413
414 #[arg(allow_hyphen_values = true)]
416 args: Vec<String>,
417
418 #[arg(long, value_name = "PATH")]
420 file: Option<PathBuf>,
421 },
422
423 Chain {
425 #[command(flatten)]
426 rpc: RpcOpts,
427 },
428
429 #[command(visible_aliases = &["ci", "cid"])]
431 ChainId {
432 #[command(flatten)]
433 rpc: RpcOpts,
434 },
435
436 #[command(visible_alias = "cl")]
438 Client {
439 #[command(flatten)]
440 rpc: RpcOpts,
441 },
442
443 #[command(visible_alias = "ca")]
445 ComputeAddress {
446 address: Option<Address>,
448
449 #[arg(
451 long,
452 conflicts_with = "salt",
453 conflicts_with = "init_code",
454 conflicts_with = "init_code_hash"
455 )]
456 nonce: Option<u64>,
457
458 #[arg(long, conflicts_with = "nonce")]
460 salt: Option<B256>,
461
462 #[arg(
464 long,
465 requires = "salt",
466 conflicts_with = "init_code_hash",
467 conflicts_with = "nonce"
468 )]
469 init_code: Option<String>,
470
471 #[arg(long, requires = "salt", conflicts_with = "init_code", conflicts_with = "nonce")]
473 init_code_hash: Option<B256>,
474
475 #[command(flatten)]
476 rpc: RpcOpts,
477 },
478
479 #[command(visible_alias = "da")]
481 Disassemble {
482 bytecode: Option<String>,
484 },
485
486 #[command(name = "mktx", visible_alias = "m")]
488 MakeTx(MakeTxArgs),
489
490 #[command(visible_aliases = &["na", "nh"])]
492 Namehash { name: Option<String> },
493
494 #[command(visible_alias = "t")]
496 Tx {
497 tx_hash: Option<String>,
499
500 #[arg(long, value_parser = NameOrAddress::from_str)]
502 from: Option<NameOrAddress>,
503
504 #[arg(long)]
506 nonce: Option<u64>,
507
508 field: Option<String>,
511
512 #[arg(long, conflicts_with = "field")]
514 raw: bool,
515
516 #[command(flatten)]
517 rpc: RpcOpts,
518
519 #[arg(long)]
521 to_request: bool,
522 },
523
524 #[command(visible_alias = "re")]
526 Receipt {
527 tx_hash: String,
529
530 field: Option<String>,
532
533 #[arg(long, default_value = "1")]
535 confirmations: u64,
536
537 #[arg(id = "async", long = "async", env = "CAST_ASYNC", alias = "cast-async")]
539 cast_async: bool,
540
541 #[command(flatten)]
542 rpc: RpcOpts,
543 },
544
545 #[command(name = "send", visible_alias = "s")]
547 SendTx(SendTxArgs),
548
549 #[command(name = "publish", visible_alias = "p")]
551 PublishTx {
552 raw_tx: String,
554
555 #[arg(id = "async", long = "async", env = "CAST_ASYNC", alias = "cast-async")]
557 cast_async: bool,
558
559 #[command(flatten)]
560 rpc: RpcOpts,
561 },
562
563 #[command(visible_alias = "e")]
565 Estimate(EstimateArgs),
566
567 #[command(visible_aliases = &["calldata-decode", "--calldata-decode", "cdd"])]
572 DecodeCalldata {
573 sig: String,
575
576 #[arg(required_unless_present = "file", index = 2)]
578 calldata: Option<String>,
579
580 #[arg(long = "file", short = 'f', conflicts_with = "calldata")]
582 file: Option<PathBuf>,
583 },
584
585 #[command(visible_aliases = &["string-decode", "--string-decode", "sd"])]
589 DecodeString {
590 data: String,
592 },
593
594 #[command(visible_aliases = &["event-decode", "--event-decode", "ed"])]
596 DecodeEvent {
597 #[arg(long, visible_alias = "event-sig")]
599 sig: Option<String>,
600 data: String,
602 },
603
604 #[command(visible_aliases = &["error-decode", "--error-decode", "erd"])]
606 DecodeError {
607 #[arg(long, visible_alias = "error-sig")]
609 sig: Option<String>,
610 data: String,
612 },
613
614 #[command(name = "decode-abi", visible_aliases = &["abi-decode", "--abi-decode", "ad"])]
620 DecodeAbi {
621 sig: String,
623
624 calldata: String,
626
627 #[arg(long, short, help_heading = "Decode input data instead of output data")]
629 input: bool,
630 },
631
632 #[command(visible_alias = "ae")]
634 AbiEncode {
635 sig: String,
637
638 #[arg(long)]
640 packed: bool,
641
642 #[arg(allow_hyphen_values = true)]
644 args: Vec<String>,
645 },
646
647 #[command(visible_alias = "aee")]
649 AbiEncodeEvent {
650 sig: String,
652
653 #[arg(allow_hyphen_values = true)]
655 args: Vec<String>,
656 },
657
658 #[command(visible_alias = "in")]
660 Index {
661 key_type: String,
663
664 key: String,
666
667 slot_number: String,
669 },
670
671 #[command(name = "index-erc7201", alias = "index-erc-7201", visible_aliases = &["index7201", "in7201"])]
673 IndexErc7201 {
674 id: Option<String>,
676 #[arg(long, default_value = "erc7201")]
678 formula_id: String,
679 },
680
681 #[command(visible_alias = "impl")]
684 Implementation {
685 #[arg(long, short = 'B')]
689 block: Option<BlockId>,
690
691 #[arg(long)]
695 beacon: bool,
696
697 #[arg(value_parser = NameOrAddress::from_str)]
699 who: NameOrAddress,
700
701 #[command(flatten)]
702 rpc: RpcOpts,
703 },
704
705 #[command(visible_alias = "adm")]
707 Admin {
708 #[arg(long, short = 'B')]
712 block: Option<BlockId>,
713
714 #[arg(value_parser = NameOrAddress::from_str)]
716 who: NameOrAddress,
717
718 #[command(flatten)]
719 rpc: RpcOpts,
720 },
721
722 #[command(name = "4byte", visible_aliases = &["4", "4b"])]
724 FourByte {
725 selector: Option<Selector>,
727 },
728
729 #[command(name = "4byte-calldata", aliases = &["4byte-decode", "4d", "4bd"], visible_aliases = &["4c", "4bc"])]
731 FourByteCalldata {
732 calldata: Option<String>,
734 },
735
736 #[command(name = "4byte-event", visible_aliases = &["4e", "4be", "topic0-event", "t0e"])]
738 FourByteEvent {
739 #[arg(value_name = "TOPIC_0")]
741 topic: Option<B256>,
742 },
743
744 #[command(visible_aliases = &["ups"])]
752 UploadSignature {
753 signatures: Vec<String>,
758 },
759
760 #[command(visible_alias = "pc")]
764 PrettyCalldata {
765 calldata: Option<String>,
767
768 #[arg(long, short)]
770 offline: bool,
771 },
772
773 #[command(visible_alias = "a")]
775 Age {
776 block: Option<BlockId>,
780
781 #[command(flatten)]
782 rpc: RpcOpts,
783 },
784
785 #[command(visible_alias = "b")]
787 Balance {
788 #[arg(long, short = 'B')]
792 block: Option<BlockId>,
793
794 #[arg(value_parser = NameOrAddress::from_str)]
796 who: NameOrAddress,
797
798 #[arg(long, short)]
800 ether: bool,
801
802 #[command(flatten)]
803 rpc: RpcOpts,
804
805 #[arg(long, alias = "erc721")]
808 erc20: Option<Address>,
809 },
810
811 #[command(visible_aliases = &["ba", "fee", "basefee"])]
813 BaseFee {
814 block: Option<BlockId>,
818
819 #[command(flatten)]
820 rpc: RpcOpts,
821 },
822
823 #[command(visible_alias = "co")]
825 Code {
826 #[arg(long, short = 'B')]
830 block: Option<BlockId>,
831
832 #[arg(value_parser = NameOrAddress::from_str)]
834 who: NameOrAddress,
835
836 #[arg(long, short)]
838 disassemble: bool,
839
840 #[command(flatten)]
841 rpc: RpcOpts,
842 },
843
844 #[command(visible_alias = "cs")]
846 Codesize {
847 #[arg(long, short = 'B')]
851 block: Option<BlockId>,
852
853 #[arg(value_parser = NameOrAddress::from_str)]
855 who: NameOrAddress,
856
857 #[command(flatten)]
858 rpc: RpcOpts,
859 },
860
861 #[command(visible_alias = "g")]
863 GasPrice {
864 #[command(flatten)]
865 rpc: RpcOpts,
866 },
867
868 #[command(visible_alias = "se")]
870 SigEvent {
871 event_string: Option<String>,
873 },
874
875 #[command(visible_aliases = &["k", "keccak256"])]
877 Keccak {
878 data: Option<String>,
880 },
881
882 #[command(visible_aliases = &["--hash-message", "hm"])]
884 HashMessage {
885 message: Option<String>,
887 },
888
889 #[command(visible_alias = "rn")]
891 ResolveName {
892 who: Option<String>,
894
895 #[arg(long)]
897 verify: bool,
898
899 #[command(flatten)]
900 rpc: RpcOpts,
901 },
902
903 #[command(visible_alias = "la")]
905 LookupAddress {
906 who: Option<Address>,
908
909 #[arg(long)]
911 verify: bool,
912
913 #[command(flatten)]
914 rpc: RpcOpts,
915 },
916
917 #[command(visible_alias = "st")]
919 Storage(StorageArgs),
920
921 #[command(visible_alias = "pr")]
923 Proof {
924 #[arg(value_parser = NameOrAddress::from_str)]
926 address: NameOrAddress,
927
928 #[arg(value_parser = parse_slot)]
930 slots: Vec<B256>,
931
932 #[arg(long, short = 'B')]
936 block: Option<BlockId>,
937
938 #[command(flatten)]
939 rpc: RpcOpts,
940 },
941
942 #[command(visible_alias = "n")]
944 Nonce {
945 #[arg(long, short = 'B')]
949 block: Option<BlockId>,
950
951 #[arg(value_parser = NameOrAddress::from_str)]
953 who: NameOrAddress,
954
955 #[command(flatten)]
956 rpc: RpcOpts,
957 },
958
959 #[command()]
961 Codehash {
962 #[arg(long, short = 'B')]
966 block: Option<BlockId>,
967
968 #[arg(value_parser = NameOrAddress::from_str)]
970 who: NameOrAddress,
971
972 #[arg(value_parser = parse_slot)]
974 slots: Vec<B256>,
975
976 #[command(flatten)]
977 rpc: RpcOpts,
978 },
979
980 #[command(visible_alias = "sr")]
982 StorageRoot {
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_aliases = &["et", "src"])]
1003 Source {
1004 address: String,
1006
1007 #[arg(long, short)]
1009 flatten: bool,
1010
1011 #[arg(short, value_hint = ValueHint::DirPath, alias = "path")]
1013 directory: Option<PathBuf>,
1014
1015 #[command(flatten)]
1016 etherscan: EtherscanOpts,
1017
1018 #[arg(long, env = "EXPLORER_API_URL")]
1021 explorer_api_url: Option<String>,
1022
1023 #[arg(long, env = "EXPLORER_URL")]
1025 explorer_url: Option<String>,
1026 },
1027
1028 #[command(visible_alias = "w")]
1030 Wallet {
1031 #[command(subcommand)]
1032 command: WalletSubcommands,
1033 },
1034
1035 #[command(visible_alias = "cc")]
1037 CreationCode(CreationCodeArgs),
1038
1039 #[command(visible_alias = "ar")]
1041 Artifact(ArtifactArgs),
1042
1043 #[command(visible_alias = "cra")]
1045 ConstructorArgs(ConstructorArgsArgs),
1046
1047 #[command(visible_alias = "i")]
1051 Interface(InterfaceArgs),
1052
1053 #[command(visible_alias = "bi")]
1055 Bind(BindArgs),
1056
1057 #[command(visible_alias = "si")]
1059 Sig {
1060 sig: Option<String>,
1062
1063 optimize: Option<usize>,
1065 },
1066
1067 #[command(visible_alias = "c2")]
1069 Create2(Create2Args),
1070
1071 #[command(visible_alias = "f")]
1073 FindBlock(FindBlockArgs),
1074
1075 #[command(visible_alias = "com")]
1077 Completions {
1078 #[arg(value_enum)]
1079 shell: foundry_common::clap::Shell,
1080 },
1081
1082 #[command(visible_alias = "fig")]
1084 GenerateFigSpec,
1085
1086 #[command(visible_alias = "r")]
1088 Run(RunArgs),
1089
1090 #[command(visible_alias = "rp")]
1092 Rpc(RpcArgs),
1093
1094 #[command(name = "format-bytes32-string", visible_aliases = &["--format-bytes32-string"])]
1096 FormatBytes32String {
1097 string: Option<String>,
1099 },
1100
1101 #[command(name = "parse-bytes32-string", visible_aliases = &["--parse-bytes32-string"])]
1103 ParseBytes32String {
1104 bytes: Option<String>,
1106 },
1107 #[command(name = "parse-bytes32-address", visible_aliases = &["--parse-bytes32-address"])]
1108 #[command(about = "Parses a checksummed address from bytes32 encoding.")]
1109 ParseBytes32Address {
1110 #[arg(value_name = "BYTES")]
1111 bytes: Option<String>,
1112 },
1113
1114 #[command(visible_aliases = &["dt", "decode-tx"])]
1116 DecodeTransaction { tx: Option<String> },
1117
1118 #[command(visible_aliases = &["decode-auth"])]
1120 RecoverAuthority { auth: String },
1121
1122 #[command(visible_alias = "sel")]
1124 Selectors {
1125 bytecode: Option<String>,
1127
1128 #[arg(long, short)]
1130 resolve: bool,
1131 },
1132
1133 #[command(visible_alias = "tp")]
1135 TxPool {
1136 #[command(subcommand)]
1137 command: TxPoolSubcommands,
1138 },
1139 #[command(name = "da-estimate")]
1141 DAEstimate(DAEstimateArgs),
1142}
1143
1144#[derive(Debug, Parser)]
1146pub struct ToBaseArgs {
1147 #[arg(allow_hyphen_values = true)]
1149 pub value: Option<String>,
1150
1151 #[arg(long, short = 'i')]
1153 pub base_in: Option<String>,
1154}
1155
1156pub fn parse_slot(s: &str) -> Result<B256> {
1157 let slot = U256::from_str(s).map_err(|e| eyre::eyre!("Could not parse slot number: {e}"))?;
1158 Ok(B256::from(slot))
1159}
1160
1161#[cfg(test)]
1162mod tests {
1163 use super::*;
1164 use crate::SimpleCast;
1165 use alloy_rpc_types::{BlockNumberOrTag, RpcBlockHash};
1166 use clap::CommandFactory;
1167
1168 #[test]
1169 fn verify_cli() {
1170 Cast::command().debug_assert();
1171 }
1172
1173 #[test]
1174 fn parse_proof_slot() {
1175 let args: Cast = Cast::parse_from([
1176 "foundry-cli",
1177 "proof",
1178 "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
1179 "0",
1180 "1",
1181 "0x0000000000000000000000000000000000000000000000000000000000000000",
1182 "0x1",
1183 "0x01",
1184 ]);
1185 match args.cmd {
1186 CastSubcommand::Proof { slots, .. } => {
1187 assert_eq!(
1188 slots,
1189 vec![
1190 B256::ZERO,
1191 U256::from(1).into(),
1192 B256::ZERO,
1193 U256::from(1).into(),
1194 U256::from(1).into()
1195 ]
1196 );
1197 }
1198 _ => unreachable!(),
1199 };
1200 }
1201
1202 #[test]
1203 fn parse_call_data() {
1204 let args: Cast = Cast::parse_from([
1205 "foundry-cli",
1206 "calldata",
1207 "f()",
1208 "5c9d55b78febcc2061715ba4f57ecf8ea2711f2c",
1209 "2",
1210 ]);
1211 match args.cmd {
1212 CastSubcommand::CalldataEncode { args, .. } => {
1213 assert_eq!(
1214 args,
1215 vec!["5c9d55b78febcc2061715ba4f57ecf8ea2711f2c".to_string(), "2".to_string()]
1216 )
1217 }
1218 _ => unreachable!(),
1219 };
1220 }
1221
1222 #[test]
1223 fn parse_call_data_with_file() {
1224 let args: Cast = Cast::parse_from(["foundry-cli", "calldata", "f()", "--file", "test.txt"]);
1225 match args.cmd {
1226 CastSubcommand::CalldataEncode { sig, file, args } => {
1227 assert_eq!(sig, "f()".to_string());
1228 assert_eq!(file, Some(PathBuf::from("test.txt")));
1229 assert!(args.is_empty());
1230 }
1231 _ => unreachable!(),
1232 };
1233 }
1234
1235 #[test]
1237 fn parse_signature() {
1238 let args: Cast = Cast::parse_from([
1239 "foundry-cli",
1240 "sig",
1241 "__$_$__$$$$$__$$_$$$_$$__$$___$$(address,address,uint256)",
1242 ]);
1243 match args.cmd {
1244 CastSubcommand::Sig { sig, .. } => {
1245 let sig = sig.unwrap();
1246 assert_eq!(
1247 sig,
1248 "__$_$__$$$$$__$$_$$$_$$__$$___$$(address,address,uint256)".to_string()
1249 );
1250
1251 let selector = SimpleCast::get_selector(&sig, 0).unwrap();
1252 assert_eq!(selector.0, "0x23b872dd".to_string());
1253 }
1254 _ => unreachable!(),
1255 };
1256 }
1257
1258 #[test]
1259 fn parse_block_ids() {
1260 struct TestCase {
1261 input: String,
1262 expect: BlockId,
1263 }
1264
1265 let test_cases = [
1266 TestCase {
1267 input: "0".to_string(),
1268 expect: BlockId::Number(BlockNumberOrTag::Number(0u64)),
1269 },
1270 TestCase {
1271 input: "0x56462c47c03df160f66819f0a79ea07def1569f8aac0fe91bb3a081159b61b4a"
1272 .to_string(),
1273 expect: BlockId::Hash(RpcBlockHash::from_hash(
1274 "0x56462c47c03df160f66819f0a79ea07def1569f8aac0fe91bb3a081159b61b4a"
1275 .parse()
1276 .unwrap(),
1277 None,
1278 )),
1279 },
1280 TestCase {
1281 input: "latest".to_string(),
1282 expect: BlockId::Number(BlockNumberOrTag::Latest),
1283 },
1284 TestCase {
1285 input: "earliest".to_string(),
1286 expect: BlockId::Number(BlockNumberOrTag::Earliest),
1287 },
1288 TestCase {
1289 input: "pending".to_string(),
1290 expect: BlockId::Number(BlockNumberOrTag::Pending),
1291 },
1292 TestCase { input: "safe".to_string(), expect: BlockId::Number(BlockNumberOrTag::Safe) },
1293 TestCase {
1294 input: "finalized".to_string(),
1295 expect: BlockId::Number(BlockNumberOrTag::Finalized),
1296 },
1297 ];
1298
1299 for test in test_cases {
1300 let result: BlockId = test.input.parse().unwrap();
1301 assert_eq!(result, test.expect);
1302 }
1303 }
1304}