Skip to main content

cast/
opts.rs

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/// A Swiss Army knife for interacting with Ethereum applications from the command line.
42#[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    /// Include the global arguments.
52    #[command(flatten)]
53    pub global: GlobalArgs,
54
55    #[command(subcommand)]
56    pub cmd: CastSubcommand,
57}
58
59#[derive(Subcommand)]
60pub enum CastSubcommand {
61    /// Prints the maximum value of the given integer type.
62    #[command(visible_aliases = &["--max-int", "maxi"])]
63    MaxInt {
64        /// The integer type to get the maximum value of.
65        #[arg(default_value = "int256")]
66        r#type: String,
67    },
68
69    /// Prints the minimum value of the given integer type.
70    #[command(visible_aliases = &["--min-int", "mini"])]
71    MinInt {
72        /// The integer type to get the minimum value of.
73        #[arg(default_value = "int256")]
74        r#type: String,
75    },
76
77    /// Prints the maximum value of the given integer type.
78    #[command(visible_aliases = &["--max-uint", "maxu"])]
79    MaxUint {
80        /// The unsigned integer type to get the maximum value of.
81        #[arg(default_value = "uint256")]
82        r#type: String,
83    },
84
85    /// Prints the zero address.
86    #[command(visible_aliases = &["--address-zero", "az"])]
87    AddressZero,
88
89    /// Prints the zero hash.
90    #[command(visible_aliases = &["--hash-zero", "hz"])]
91    HashZero,
92
93    /// Convert UTF8 text to hex.
94    #[command(
95        visible_aliases = &[
96        "--from-ascii",
97        "--from-utf8",
98        "from-ascii",
99        "fu",
100        "fa"]
101    )]
102    FromUtf8 {
103        /// The text to convert.
104        text: Option<String>,
105    },
106
107    /// Concatenate hex strings.
108    #[command(visible_aliases = &["--concat-hex", "ch"])]
109    ConcatHex {
110        /// The data to concatenate.
111        data: Vec<String>,
112    },
113
114    /// Convert binary data into hex data.
115    #[command(visible_aliases = &["--from-bin", "from-binx", "fb"])]
116    FromBin,
117
118    /// Normalize the input to lowercase, 0x-prefixed hex.
119    ///
120    /// The input can be:
121    /// - mixed case hex with or without 0x prefix
122    /// - 0x prefixed hex, concatenated with a ':'
123    /// - an absolute path to file
124    /// - @tag, where the tag is defined in an environment variable
125    #[command(visible_aliases = &["--to-hexdata", "thd", "2hd"])]
126    ToHexdata {
127        /// The input to normalize.
128        input: Option<String>,
129    },
130
131    /// Convert an address to a checksummed format (EIP-55).
132    #[command(
133        visible_aliases = &["--to-checksum-address",
134        "--to-checksum",
135        "to-checksum",
136        "ta",
137        "2a"]
138    )]
139    ToCheckSumAddress {
140        /// The address to convert.
141        address: Option<Address>,
142        /// EIP-155 chain ID to encode the address using EIP-1191.
143        chain_id: Option<u64>,
144    },
145
146    /// Convert hex data to an ASCII string.
147    #[command(visible_aliases = &["--to-ascii", "tas", "2as"])]
148    ToAscii {
149        /// The hex data to convert.
150        hexdata: Option<String>,
151    },
152
153    /// Convert hex data to a utf-8 string.
154    #[command(visible_aliases = &["--to-utf8", "tu8", "2u8"])]
155    ToUtf8 {
156        /// The hex data to convert.
157        hexdata: Option<String>,
158    },
159
160    /// Convert a fixed point number into an integer.
161    #[command(visible_aliases = &["--from-fix", "ff"])]
162    FromFixedPoint {
163        /// The number of decimals to use.
164        decimals: Option<String>,
165
166        /// The value to convert.
167        #[arg(allow_hyphen_values = true)]
168        value: Option<String>,
169    },
170
171    /// Right-pads hex data to 32 bytes.
172    #[command(visible_aliases = &["--to-bytes32", "tb", "2b"])]
173    ToBytes32 {
174        /// The hex data to convert.
175        bytes: Option<String>,
176    },
177
178    /// Pads hex data to a specified length.
179    #[command(visible_aliases = &["pd"])]
180    Pad {
181        /// The hex data to pad.
182        data: Option<String>,
183
184        /// Right-pad the data (instead of left-pad).
185        #[arg(long)]
186        right: bool,
187
188        /// Left-pad the data (default).
189        #[arg(long, conflicts_with = "right")]
190        left: bool,
191
192        /// Target length in bytes (default: 32).
193        #[arg(long, default_value = "32")]
194        len: usize,
195    },
196
197    /// Convert an integer into a fixed point number.
198    #[command(visible_aliases = &["--to-fix", "tf", "2f"])]
199    ToFixedPoint {
200        /// The number of decimals to use.
201        decimals: Option<String>,
202
203        /// The value to convert.
204        #[arg(allow_hyphen_values = true)]
205        value: Option<String>,
206    },
207
208    /// Convert a number to a hex-encoded uint256.
209    #[command(name = "to-uint256", visible_aliases = &["--to-uint256", "tu", "2u"])]
210    ToUint256 {
211        /// The value to convert.
212        value: Option<String>,
213    },
214
215    /// Convert a number to a hex-encoded int256.
216    #[command(name = "to-int256", visible_aliases = &["--to-int256", "ti", "2i"])]
217    ToInt256 {
218        /// The value to convert.
219        value: Option<String>,
220    },
221
222    /// Perform a left shifting operation
223    #[command(name = "shl")]
224    LeftShift {
225        /// The value to shift.
226        value: String,
227
228        /// The number of bits to shift.
229        bits: String,
230
231        /// The input base.
232        #[arg(long)]
233        base_in: Option<String>,
234
235        /// The output base.
236        #[arg(long, default_value = "16")]
237        base_out: String,
238    },
239
240    /// Perform a right shifting operation
241    #[command(name = "shr")]
242    RightShift {
243        /// The value to shift.
244        value: String,
245
246        /// The number of bits to shift.
247        bits: String,
248
249        /// The input base,
250        #[arg(long)]
251        base_in: Option<String>,
252
253        /// The output base,
254        #[arg(long, default_value = "16")]
255        base_out: String,
256    },
257
258    /// Convert an ETH amount into another unit (ether, gwei or wei).
259    ///
260    /// Examples:
261    /// - 1ether wei
262    /// - "1 ether" wei
263    /// - 1ether
264    /// - 1 gwei
265    /// - 1gwei ether
266    #[command(visible_aliases = &["--to-unit", "tun", "2un"])]
267    ToUnit {
268        /// The value to convert.
269        value: Option<String>,
270
271        /// The unit to convert to (ether, gwei, wei).
272        #[arg(default_value = "wei")]
273        unit: String,
274    },
275
276    /// Convert a number from decimal to smallest unit with arbitrary decimals.
277    ///
278    /// Examples:
279    /// - 1.0 6    (for USDC, result: 1000000)
280    /// - 2.5 12   (for 12 decimals token, result: 2500000000000)
281    /// - 1.23 3   (for 3 decimals token, result: 1230)
282    #[command(visible_aliases = &["--parse-units", "pun"])]
283    ParseUnits {
284        /// The value to convert.
285        value: Option<String>,
286
287        /// The unit to convert to.
288        #[arg(default_value = "18")]
289        unit: u8,
290    },
291
292    /// Format a number from smallest unit to decimal with arbitrary decimals.
293    ///
294    /// Examples:
295    /// - 1000000 6       (for USDC, result: 1.0)
296    /// - 2500000000000 12 (for 12 decimals, result: 2.5)
297    /// - 1230 3          (for 3 decimals, result: 1.23)
298    #[command(visible_aliases = &["--format-units", "fun"])]
299    FormatUnits {
300        /// The value to format.
301        value: Option<String>,
302
303        /// The unit to format to.
304        #[arg(default_value = "18")]
305        unit: u8,
306    },
307
308    /// Convert an ETH amount to wei.
309    ///
310    /// Consider using --to-unit.
311    #[command(visible_aliases = &["--to-wei", "tw", "2w"])]
312    ToWei {
313        /// The value to convert.
314        #[arg(allow_hyphen_values = true)]
315        value: Option<String>,
316
317        /// The unit to convert from (ether, gwei, wei).
318        #[arg(default_value = "eth")]
319        unit: String,
320    },
321
322    /// Convert wei into an ETH amount.
323    ///
324    /// Consider using --to-unit.
325    #[command(visible_aliases = &["--from-wei", "fw"])]
326    FromWei {
327        /// The value to convert.
328        #[arg(allow_hyphen_values = true)]
329        value: Option<String>,
330
331        /// The unit to convert from (ether, gwei, wei).
332        #[arg(default_value = "eth")]
333        unit: String,
334    },
335
336    /// RLP encodes hex data, or an array of hex data.
337    ///
338    /// Accepts a hex-encoded string, or an array of hex-encoded strings.
339    /// Can be arbitrarily recursive.
340    ///
341    /// Examples:
342    /// - `cast to-rlp "[]"` -> `0xc0`
343    /// - `cast to-rlp "0x22"` -> `0x22`
344    /// - `cast to-rlp "[\"0x61\"]"` -> `0xc161`
345    /// - `cast to-rlp "[\"0xf1\", \"f2\"]"` -> `0xc481f181f2`
346    #[command(visible_aliases = &["--to-rlp"])]
347    ToRlp {
348        /// The value to convert.
349        ///
350        /// This is a hex-encoded string, or an array of hex-encoded strings.
351        /// Can be arbitrarily recursive.
352        value: Option<String>,
353    },
354
355    /// Decodes RLP hex-encoded data.
356    #[command(visible_aliases = &["--from-rlp"])]
357    FromRlp {
358        /// The RLP hex-encoded data.
359        value: Option<String>,
360
361        /// Decode the RLP data as int
362        #[arg(long, alias = "int")]
363        as_int: bool,
364    },
365
366    /// Converts a number of one base to another
367    #[command(visible_aliases = &["--to-hex", "th", "2h"])]
368    ToHex(ToBaseArgs),
369
370    /// Converts a number of one base to decimal
371    #[command(visible_aliases = &["--to-dec", "td", "2d"])]
372    ToDec(ToBaseArgs),
373
374    /// Converts a number of one base to another
375    #[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        /// The output base.
387        #[arg(value_name = "BASE")]
388        base_out: Option<String>,
389    },
390    /// Create an access list for a transaction.
391    #[command(visible_aliases = &["ac", "acl"])]
392    AccessList(AccessListArgs),
393    /// Get logs by signature or topic.
394    #[command(visible_alias = "l")]
395    Logs(LogsArgs),
396    /// Get information about a block.
397    #[command(visible_alias = "bl")]
398    Block {
399        /// The block height to query at.
400        ///
401        /// Can also be the tags earliest, finalized, safe, latest, or pending.
402        block: Option<BlockId>,
403
404        /// If specified, only get the given field of the block.
405        #[arg(short, long = "field", aliases = ["fields"], num_args = 0.., action = ArgAction::Append, value_delimiter = ',')]
406        fields: Vec<String>,
407
408        /// Print the raw RLP encoded block header.
409        #[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        /// Specify the Network for correct encoding.
419        #[arg(long, short, num_args = 1, value_name = "NETWORK")]
420        network: Option<NetworkVariant>,
421    },
422
423    /// Get the latest block number.
424    #[command(visible_alias = "bn")]
425    BlockNumber {
426        /// The hash or tag to query. If not specified, the latest number is returned.
427        block: Option<BlockId>,
428        #[command(flatten)]
429        rpc: RpcOpts,
430    },
431
432    /// Perform a call on an account without publishing a transaction.
433    #[command(visible_alias = "c")]
434    Call(CallArgs),
435
436    /// ABI-encode a function with arguments.
437    #[command(name = "calldata", visible_alias = "cd")]
438    CalldataEncode {
439        /// The function signature in the format `<name>(<in-types>)(<out-types>)`
440        sig: String,
441
442        /// The arguments to encode.
443        #[arg(allow_hyphen_values = true)]
444        args: Vec<String>,
445
446        // Path to file containing arguments to encode.
447        #[arg(long, value_name = "PATH")]
448        file: Option<PathBuf>,
449    },
450
451    /// Get the symbolic name of the current chain.
452    Chain {
453        #[command(flatten)]
454        rpc: RpcOpts,
455    },
456
457    /// Get the Ethereum chain ID.
458    #[command(visible_aliases = &["ci", "cid"])]
459    ChainId {
460        #[command(flatten)]
461        rpc: RpcOpts,
462    },
463
464    /// Get the current client version.
465    #[command(visible_alias = "cl")]
466    Client {
467        #[command(flatten)]
468        rpc: RpcOpts,
469    },
470
471    /// Compute the contract address from a given nonce and deployer address.
472    #[command(visible_alias = "ca")]
473    ComputeAddress {
474        /// The deployer address.
475        address: Option<Address>,
476
477        /// The nonce of the deployer address.
478        #[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        /// The salt for CREATE2 address computation.
487        #[arg(long, conflicts_with = "nonce")]
488        salt: Option<B256>,
489
490        /// The init code for CREATE2 address computation.
491        #[arg(
492            long,
493            requires = "salt",
494            conflicts_with = "init_code_hash",
495            conflicts_with = "nonce"
496        )]
497        init_code: Option<String>,
498
499        /// The init code hash for CREATE2 address computation.
500        #[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    /// Disassembles a hex-encoded bytecode into a human-readable representation.
508    #[command(visible_alias = "da")]
509    Disassemble {
510        /// The hex-encoded bytecode.
511        bytecode: Option<String>,
512    },
513
514    /// Build and sign a transaction.
515    #[command(name = "mktx", visible_alias = "m")]
516    MakeTx(MakeTxArgs),
517
518    /// Classify a raw transaction as Tempo T5 payment/general lane.
519    Classify {
520        /// The raw signed transaction.
521        raw_tx: Option<String>,
522    },
523
524    /// Calculate the ENS namehash of a name.
525    #[command(visible_aliases = &["na", "nh"])]
526    Namehash { name: Option<String> },
527
528    /// Get information about a transaction.
529    #[command(visible_alias = "t")]
530    Tx {
531        /// The transaction hash.
532        tx_hash: Option<String>,
533
534        /// The sender of the transaction.
535        #[arg(long, value_parser = NameOrAddress::from_str)]
536        from: Option<NameOrAddress>,
537
538        /// Nonce of the transaction.
539        #[arg(long)]
540        nonce: Option<u64>,
541
542        /// If specified, only get the given field of the transaction. If "raw", the RLP encoded
543        /// transaction will be printed.
544        field: Option<String>,
545
546        /// Print the raw RLP encoded transaction.
547        #[arg(long, conflicts_with = "field")]
548        raw: bool,
549
550        /// Classify the transaction as Tempo T5 payment/general lane.
551        #[arg(long, conflicts_with_all = ["field", "raw", "to_request"])]
552        lane: bool,
553
554        #[command(flatten)]
555        rpc: RpcOpts,
556
557        /// If specified, the transaction will be converted to a TransactionRequest JSON format.
558        #[arg(long)]
559        to_request: bool,
560
561        /// Specify the Network for correct encoding.
562        #[arg(long, short, num_args = 1, value_name = "NETWORK")]
563        network: Option<NetworkVariant>,
564    },
565
566    /// Get the transaction receipt for a transaction.
567    #[command(visible_alias = "re")]
568    Receipt {
569        /// The transaction hash.
570        tx_hash: String,
571
572        /// If specified, only get the given field of the transaction.
573        field: Option<String>,
574
575        /// The number of confirmations until the receipt is fetched
576        #[arg(long, default_value = "1")]
577        confirmations: u64,
578
579        /// Exit immediately if the transaction was not found.
580        #[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    /// Sign and publish a transaction.
588    #[command(name = "send", visible_alias = "s")]
589    SendTx(SendTxArgs),
590
591    /// Build and sign a batch transaction (Tempo).
592    #[command(name = "batch-mktx", visible_alias = "bm")]
593    BatchMakeTx(BatchMakeTxArgs),
594
595    /// Sign and publish a batch transaction (Tempo).
596    #[command(name = "batch-send", visible_alias = "bs")]
597    BatchSend(BatchSendArgs),
598
599    /// Publish a raw transaction to the network.
600    #[command(name = "publish", visible_alias = "p")]
601    PublishTx {
602        /// The raw transaction
603        raw_tx: String,
604
605        /// Only print the transaction hash and exit immediately.
606        #[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    /// Estimate the gas cost of a transaction.
614    #[command(visible_alias = "e")]
615    Estimate(EstimateArgs),
616
617    /// Decode ABI-encoded input data.
618    ///
619    /// Similar to `abi-decode --input`, but function selector MUST be prefixed in `calldata`
620    /// string
621    #[command(visible_aliases = &["calldata-decode", "--calldata-decode", "cdd"])]
622    DecodeCalldata {
623        /// The function signature in the format `<name>(<in-types>)(<out-types>)`.
624        sig: String,
625
626        /// The ABI-encoded calldata.
627        #[arg(required_unless_present = "file", index = 2)]
628        calldata: Option<String>,
629
630        /// Load ABI-encoded calldata from a file instead.
631        #[arg(long = "file", short = 'f', conflicts_with = "calldata")]
632        file: Option<PathBuf>,
633    },
634
635    /// Decode ABI-encoded string.
636    ///
637    /// Similar to `calldata-decode --input`, but the function argument is a `string`
638    #[command(visible_aliases = &["string-decode", "--string-decode", "sd"])]
639    DecodeString {
640        /// The ABI-encoded string.
641        data: String,
642    },
643
644    /// Decode event data.
645    #[command(visible_aliases = &["event-decode", "--event-decode", "ed"])]
646    DecodeEvent {
647        /// The event signature. If none provided then tries to decode from local cache or <https://api.openchain.xyz>.
648        #[arg(long, visible_alias = "event-sig")]
649        sig: Option<String>,
650        /// The event data to decode.
651        data: String,
652    },
653
654    /// Decode custom error data.
655    #[command(visible_aliases = &["error-decode", "--error-decode", "erd"])]
656    DecodeError {
657        /// The error signature. If none provided then tries to decode from local cache or <https://api.openchain.xyz>.
658        #[arg(long, visible_alias = "error-sig")]
659        sig: Option<String>,
660        /// The error data to decode.
661        data: String,
662    },
663
664    /// Decode ABI-encoded input or output data.
665    ///
666    /// Defaults to decoding output data. To decode input data pass --input.
667    ///
668    /// When passing `--input`, function selector must NOT be prefixed in `calldata` string
669    #[command(name = "decode-abi", visible_aliases = &["abi-decode", "--abi-decode", "ad"])]
670    DecodeAbi {
671        /// The function signature in the format `<name>(<in-types>)(<out-types>)`.
672        sig: String,
673
674        /// The ABI-encoded calldata.
675        calldata: String,
676
677        /// Whether to decode the input or output data.
678        #[arg(long, short, help_heading = "Decode input data instead of output data")]
679        input: bool,
680    },
681
682    /// ABI encode the given function argument, excluding the selector.
683    #[command(visible_alias = "ae")]
684    AbiEncode {
685        /// The function signature.
686        sig: String,
687
688        /// Whether to use packed encoding.
689        #[arg(long)]
690        packed: bool,
691
692        /// The arguments of the function.
693        #[arg(allow_hyphen_values = true)]
694        args: Vec<String>,
695    },
696
697    /// ABI encode an event and its arguments to generate topics and data.
698    #[command(visible_alias = "aee")]
699    AbiEncodeEvent {
700        /// The event signature.
701        sig: String,
702
703        /// The arguments of the event.
704        #[arg(allow_hyphen_values = true)]
705        args: Vec<String>,
706    },
707
708    /// Compute the storage slot for an entry in a mapping.
709    #[command(visible_alias = "in")]
710    Index {
711        /// The mapping key type.
712        key_type: String,
713
714        /// The mapping key.
715        key: String,
716
717        /// The storage slot of the mapping.
718        slot_number: String,
719    },
720
721    /// Compute storage slots as specified by `ERC-7201: Namespaced Storage Layout`.
722    #[command(name = "index-erc7201", alias = "index-erc-7201", visible_aliases = &["index7201", "in7201"])]
723    IndexErc7201 {
724        /// The arbitrary identifier.
725        id: Option<String>,
726        /// The formula ID. Currently the only supported formula is `erc7201`.
727        #[arg(long, default_value = "erc7201")]
728        formula_id: String,
729    },
730
731    /// Fetch the EIP-1967 implementation for a contract
732    /// Can read from the implementation slot or the beacon slot.
733    #[command(visible_alias = "impl")]
734    Implementation {
735        /// The block height to query at.
736        ///
737        /// Can also be the tags earliest, finalized, safe, latest, or pending.
738        #[arg(long, short = 'B')]
739        block: Option<BlockId>,
740
741        /// Fetch the implementation from the beacon slot.
742        ///
743        /// If not specified, the implementation slot is used.
744        #[arg(long)]
745        beacon: bool,
746
747        /// The address for which the implementation will be fetched.
748        #[arg(value_parser = NameOrAddress::from_str)]
749        who: NameOrAddress,
750
751        #[command(flatten)]
752        rpc: RpcOpts,
753    },
754
755    /// Fetch the EIP-1967 admin account
756    #[command(visible_alias = "adm")]
757    Admin {
758        /// The block height to query at.
759        ///
760        /// Can also be the tags earliest, finalized, safe, latest, or pending.
761        #[arg(long, short = 'B')]
762        block: Option<BlockId>,
763
764        /// The address from which the admin account will be fetched.
765        #[arg(value_parser = NameOrAddress::from_str)]
766        who: NameOrAddress,
767
768        #[command(flatten)]
769        rpc: RpcOpts,
770    },
771
772    /// Get the function signatures for the given selector from <https://openchain.xyz>.
773    #[command(name = "4byte", visible_aliases = &["4", "4b"])]
774    FourByte {
775        /// The function selector.
776        selector: Option<Selector>,
777    },
778
779    /// Decode ABI-encoded calldata using <https://openchain.xyz>.
780    #[command(name = "4byte-calldata", aliases = &["4byte-decode", "4d", "4bd"], visible_aliases = &["4c", "4bc"])]
781    FourByteCalldata {
782        /// The ABI-encoded calldata.
783        calldata: Option<String>,
784    },
785
786    /// Get the event signature for a given topic 0 from <https://openchain.xyz>.
787    #[command(name = "4byte-event", visible_aliases = &["4e", "4be", "topic0-event", "t0e"])]
788    FourByteEvent {
789        /// Topic 0
790        #[arg(value_name = "TOPIC_0")]
791        topic: Option<B256>,
792    },
793
794    /// Upload the given signatures to <https://openchain.xyz>.
795    ///
796    /// Example inputs:
797    /// - "transfer(address,uint256)"
798    /// - "function transfer(address,uint256)"
799    /// - "function transfer(address,uint256)" "event Transfer(address,address,uint256)"
800    /// - "./out/Contract.sol/Contract.json"
801    #[command(visible_aliases = &["ups"])]
802    UploadSignature {
803        /// The signatures to upload.
804        ///
805        /// Prefix with 'function', 'event', or 'error'. Defaults to function if no prefix given.
806        /// Can also take paths to contract artifact JSON.
807        signatures: Vec<String>,
808    },
809
810    /// Pretty print calldata.
811    ///
812    /// Tries to decode the calldata using <https://openchain.xyz> unless --offline is passed.
813    #[command(visible_alias = "pc")]
814    PrettyCalldata {
815        /// The calldata.
816        calldata: Option<String>,
817
818        /// Skip the <https://openchain.xyz> lookup.
819        #[arg(long, short)]
820        offline: bool,
821    },
822
823    /// Get the timestamp of a block.
824    #[command(visible_alias = "a")]
825    Age {
826        /// The block height to query at.
827        ///
828        /// Can also be the tags earliest, finalized, safe, latest, or pending.
829        block: Option<BlockId>,
830
831        #[command(flatten)]
832        rpc: RpcOpts,
833    },
834
835    /// Get the balance of an account in wei.
836    #[command(visible_alias = "b")]
837    Balance {
838        /// The block height to query at.
839        ///
840        /// Can also be the tags earliest, finalized, safe, latest, or pending.
841        #[arg(long, short = 'B')]
842        block: Option<BlockId>,
843
844        /// The account to query.
845        #[arg(value_parser = NameOrAddress::from_str)]
846        who: NameOrAddress,
847
848        /// Format the balance in ether.
849        #[arg(long, short)]
850        ether: bool,
851
852        #[command(flatten)]
853        rpc: RpcOpts,
854
855        /// erc20 address to query, with the method `balanceOf(address) return (uint256)`, alias
856        /// with '--erc721'
857        #[arg(long, alias = "erc721")]
858        erc20: Option<Address>,
859    },
860
861    /// Get the basefee of a block.
862    #[command(visible_aliases = &["ba", "fee", "basefee"])]
863    BaseFee {
864        /// The block height to query at.
865        ///
866        /// Can also be the tags earliest, finalized, safe, latest, or pending.
867        block: Option<BlockId>,
868
869        #[command(flatten)]
870        rpc: RpcOpts,
871    },
872
873    /// Get the runtime bytecode of a contract.
874    #[command(visible_alias = "co")]
875    Code {
876        /// The block height to query at.
877        ///
878        /// Can also be the tags earliest, finalized, safe, latest, or pending.
879        #[arg(long, short = 'B')]
880        block: Option<BlockId>,
881
882        /// The contract address.
883        #[arg(value_parser = NameOrAddress::from_str)]
884        who: NameOrAddress,
885
886        /// Disassemble bytecodes.
887        #[arg(long, short)]
888        disassemble: bool,
889
890        #[command(flatten)]
891        rpc: RpcOpts,
892    },
893
894    /// Get the runtime bytecode size of a contract.
895    #[command(visible_alias = "cs")]
896    Codesize {
897        /// The block height to query at.
898        ///
899        /// Can also be the tags earliest, finalized, safe, latest, or pending.
900        #[arg(long, short = 'B')]
901        block: Option<BlockId>,
902
903        /// The contract address.
904        #[arg(value_parser = NameOrAddress::from_str)]
905        who: NameOrAddress,
906
907        #[command(flatten)]
908        rpc: RpcOpts,
909    },
910
911    /// Get the current gas price.
912    #[command(visible_alias = "g")]
913    GasPrice {
914        #[command(flatten)]
915        rpc: RpcOpts,
916    },
917
918    /// Generate event signatures from event string.
919    #[command(visible_alias = "se")]
920    SigEvent {
921        /// The event string.
922        event_string: Option<String>,
923    },
924
925    /// Hash arbitrary data using Keccak-256.
926    #[command(visible_aliases = &["k", "keccak256"])]
927    Keccak {
928        /// The data to hash.
929        data: Option<String>,
930    },
931
932    /// Hash a message according to EIP-191.
933    #[command(visible_aliases = &["--hash-message", "hm"])]
934    HashMessage {
935        /// The message to hash.
936        message: Option<String>,
937    },
938
939    /// Perform an ENS lookup.
940    #[command(visible_alias = "rn")]
941    ResolveName {
942        /// The name to lookup.
943        who: Option<String>,
944
945        /// Perform a reverse lookup to verify that the name is correct.
946        #[arg(long)]
947        verify: bool,
948
949        #[command(flatten)]
950        rpc: RpcOpts,
951    },
952
953    /// Perform an ENS reverse lookup.
954    #[command(visible_alias = "la")]
955    LookupAddress {
956        /// The account to perform the lookup for.
957        who: Option<Address>,
958
959        /// Perform a normal lookup to verify that the address is correct.
960        #[arg(long)]
961        verify: bool,
962
963        #[command(flatten)]
964        rpc: RpcOpts,
965    },
966
967    /// Get the raw value of a contract's storage slot.
968    #[command(visible_alias = "st")]
969    Storage(StorageArgs),
970
971    /// Generate a storage proof for a given storage slot.
972    #[command(visible_alias = "pr")]
973    Proof {
974        /// The contract address.
975        #[arg(value_parser = NameOrAddress::from_str)]
976        address: NameOrAddress,
977
978        /// The storage slot numbers (hex or decimal).
979        #[arg(value_parser = parse_slot)]
980        slots: Vec<B256>,
981
982        /// The block height to query at.
983        ///
984        /// Can also be the tags earliest, finalized, safe, latest, or pending.
985        #[arg(long, short = 'B')]
986        block: Option<BlockId>,
987
988        #[command(flatten)]
989        rpc: RpcOpts,
990    },
991
992    /// Get the nonce for an account.
993    #[command(visible_alias = "n")]
994    Nonce {
995        /// The block height to query at.
996        ///
997        /// Can also be the tags earliest, finalized, safe, latest, or pending.
998        #[arg(long, short = 'B')]
999        block: Option<BlockId>,
1000
1001        /// The address to get the nonce for.
1002        #[arg(value_parser = NameOrAddress::from_str)]
1003        who: NameOrAddress,
1004
1005        #[command(flatten)]
1006        rpc: RpcOpts,
1007    },
1008
1009    /// Get the codehash for an account.
1010    #[command()]
1011    Codehash {
1012        /// The block height to query at.
1013        ///
1014        /// Can also be the tags earliest, finalized, safe, latest, or pending.
1015        #[arg(long, short = 'B')]
1016        block: Option<BlockId>,
1017
1018        /// The address to get the codehash for.
1019        #[arg(value_parser = NameOrAddress::from_str)]
1020        who: NameOrAddress,
1021
1022        /// The storage slot numbers (hex or decimal).
1023        #[arg(value_parser = parse_slot)]
1024        slots: Vec<B256>,
1025
1026        #[command(flatten)]
1027        rpc: RpcOpts,
1028    },
1029
1030    /// Get the storage root for an account.
1031    #[command(visible_alias = "sr")]
1032    StorageRoot {
1033        /// The block height to query at.
1034        ///
1035        /// Can also be the tags earliest, finalized, safe, latest, or pending.
1036        #[arg(long, short = 'B')]
1037        block: Option<BlockId>,
1038
1039        /// The address to get the storage root for.
1040        #[arg(value_parser = NameOrAddress::from_str)]
1041        who: NameOrAddress,
1042
1043        /// The storage slot numbers (hex or decimal).
1044        #[arg(value_parser = parse_slot)]
1045        slots: Vec<B256>,
1046
1047        #[command(flatten)]
1048        rpc: RpcOpts,
1049    },
1050
1051    /// Compute a Tempo TIP-20 channel reserve channel ID.
1052    #[command(name = "channel-id")]
1053    ChannelId {
1054        /// Channel payer address.
1055        #[arg(value_parser = NameOrAddress::from_str)]
1056        payer: NameOrAddress,
1057
1058        /// Channel payee address.
1059        #[arg(value_parser = NameOrAddress::from_str)]
1060        payee: NameOrAddress,
1061
1062        /// TIP-20 token address locked by the channel.
1063        #[arg(value_parser = NameOrAddress::from_str)]
1064        token: NameOrAddress,
1065
1066        /// User-supplied channel salt.
1067        salt: B256,
1068
1069        /// Optional relayer allowed to submit settlements for the payee.
1070        #[arg(long, value_parser = NameOrAddress::from_str)]
1071        operator: Option<NameOrAddress>,
1072
1073        /// Optional voucher signer. Defaults to the zero address, meaning the payer signs.
1074        #[arg(long, value_parser = NameOrAddress::from_str)]
1075        authorized_signer: Option<NameOrAddress>,
1076
1077        /// Transaction-derived expiring nonce hash from ChannelOpened.
1078        #[arg(long, default_value_t = B256::ZERO)]
1079        expiring_nonce_hash: B256,
1080
1081        /// Channel reserve precompile address.
1082        #[arg(long, value_parser = NameOrAddress::from_str)]
1083        reserve: Option<NameOrAddress>,
1084
1085        /// The block height to query at.
1086        ///
1087        /// Can also be the tags earliest, finalized, safe, latest, or pending.
1088        #[arg(long, short = 'B')]
1089        block: Option<BlockId>,
1090
1091        #[command(flatten)]
1092        rpc: RpcOpts,
1093    },
1094
1095    /// Get the source code of a contract from a block explorer.
1096    #[command(visible_aliases = &["et", "src"])]
1097    Source {
1098        /// The contract's address.
1099        address: String,
1100
1101        /// Whether to flatten the source code.
1102        #[arg(long, short)]
1103        flatten: bool,
1104
1105        /// The output directory/file to expand source tree into.
1106        #[arg(short, value_hint = ValueHint::DirPath, alias = "path")]
1107        directory: Option<PathBuf>,
1108
1109        #[command(flatten)]
1110        etherscan: EtherscanOpts,
1111
1112        /// Alternative explorer API URL to use that adheres to the Etherscan API. If not provided,
1113        /// defaults to Etherscan.
1114        #[arg(long, env = "EXPLORER_API_URL")]
1115        explorer_api_url: Option<String>,
1116
1117        /// Alternative explorer browser URL.
1118        #[arg(long, env = "EXPLORER_URL")]
1119        explorer_url: Option<String>,
1120    },
1121
1122    /// Wallet management utilities.
1123    #[command(visible_alias = "w")]
1124    Wallet {
1125        #[command(subcommand)]
1126        command: WalletSubcommands,
1127    },
1128
1129    /// Download a contract creation code from Etherscan and RPC.
1130    #[command(visible_alias = "cc")]
1131    CreationCode(CreationCodeArgs),
1132
1133    /// Generate an artifact file, that can be used to deploy a contract locally.
1134    #[command(visible_alias = "ar")]
1135    Artifact(ArtifactArgs),
1136
1137    /// Display constructor arguments used for the contract initialization.
1138    #[command(visible_alias = "cra")]
1139    ConstructorArgs(ConstructorArgsArgs),
1140
1141    /// Generate a Solidity interface from a given ABI.
1142    ///
1143    /// Currently does not support ABI encoder v2.
1144    #[command(visible_alias = "i")]
1145    Interface(InterfaceArgs),
1146
1147    /// Generate a rust binding from a given ABI.
1148    #[command(visible_alias = "bi")]
1149    Bind(BindArgs),
1150
1151    /// Convert Beacon payload to execution payload.
1152    #[command(visible_alias = "b2e")]
1153    B2EPayload(B2EPayloadArgs),
1154
1155    /// Get the selector for a function.
1156    #[command(visible_alias = "si")]
1157    Sig {
1158        /// The function signature, e.g. transfer(address,uint256).
1159        sig: Option<String>,
1160
1161        /// Optimize signature to contain provided amount of leading zeroes in selector.
1162        #[arg(conflicts_with = "json")]
1163        optimize: Option<usize>,
1164    },
1165
1166    /// Generate a deterministic contract address using CREATE2.
1167    #[command(visible_alias = "c2")]
1168    Create2(Create2Args),
1169
1170    /// Get the block number closest to the provided timestamp.
1171    #[command(visible_alias = "f")]
1172    FindBlock(FindBlockArgs),
1173
1174    /// Generate shell completions script.
1175    #[command(visible_alias = "com")]
1176    Completions {
1177        #[arg(value_enum)]
1178        shell: foundry_cli::clap::Shell,
1179    },
1180
1181    /// Runs a published transaction in a local environment and prints the trace.
1182    #[command(visible_alias = "r")]
1183    Run(RunArgs),
1184
1185    /// Perform a raw JSON-RPC request.
1186    #[command(visible_alias = "rp")]
1187    Rpc(RpcArgs),
1188
1189    /// Formats a string into bytes32 encoding.
1190    #[command(name = "format-bytes32-string", visible_aliases = &["--format-bytes32-string"])]
1191    FormatBytes32String {
1192        /// The string to format.
1193        string: Option<String>,
1194    },
1195
1196    /// Parses a string from bytes32 encoding.
1197    #[command(name = "parse-bytes32-string", visible_aliases = &["--parse-bytes32-string"])]
1198    ParseBytes32String {
1199        /// The string to parse.
1200        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    /// Decodes a raw signed EIP 2718 typed transaction
1210    #[command(visible_aliases = &["dt", "decode-tx"])]
1211    DecodeTransaction {
1212        /// Encoded transaction
1213        tx: Option<String>,
1214
1215        /// Specify the Network for correct encoding.
1216        #[arg(long, short, num_args = 1, value_name = "NETWORK")]
1217        network: Option<NetworkVariant>,
1218    },
1219
1220    /// Recovery an EIP-7702 authority from a Authorization JSON string.
1221    #[command(visible_aliases = &["decode-auth"])]
1222    RecoverAuthority { auth: String },
1223
1224    /// Extracts function selectors and arguments from bytecode
1225    #[command(visible_alias = "sel")]
1226    Selectors {
1227        /// The hex-encoded bytecode.
1228        bytecode: Option<String>,
1229
1230        /// Resolve the function signatures for the extracted selectors using <https://openchain.xyz>
1231        #[arg(long, short)]
1232        resolve: bool,
1233    },
1234
1235    /// Inspect the TxPool of a node.
1236    #[command(visible_alias = "tp")]
1237    TxPool {
1238        #[command(subcommand)]
1239        command: TxPoolSubcommands,
1240    },
1241    /// Estimates the data availability size of a given opstack block.
1242    #[cfg(feature = "optimism")]
1243    #[command(name = "da-estimate")]
1244    DAEstimate(DAEstimateArgs),
1245
1246    /// ERC20 token operations.
1247    #[command(visible_alias = "erc20")]
1248    Erc20Token {
1249        #[command(subcommand)]
1250        command: Erc20Subcommand,
1251    },
1252
1253    /// TIP-20 token operations (Tempo).
1254    #[command(visible_alias = "tip20")]
1255    Tip20Token {
1256        #[command(subcommand)]
1257        command: Tip20Subcommand,
1258    },
1259
1260    /// Tempo keychain (access key) management.
1261    #[command(visible_alias = "kc")]
1262    Keychain {
1263        #[command(subcommand)]
1264        command: KeychainSubcommand,
1265    },
1266
1267    /// Tempo key authorization RLP helpers.
1268    #[command(name = "key-auth")]
1269    KeyAuth {
1270        #[command(subcommand)]
1271        command: KeyAuthSubcommand,
1272    },
1273
1274    /// Tempo wallet integration (login, etc.).
1275    Tempo {
1276        #[command(subcommand)]
1277        command: TempoSubcommand,
1278    },
1279
1280    /// TIP-1022 virtual address registry operations (Tempo).
1281    #[command(visible_alias = "vaddr")]
1282    VirtualAddress {
1283        #[command(subcommand)]
1284        command: VaddrSubcommand,
1285    },
1286
1287    #[command(name = "trace")]
1288    Trace(TraceArgs),
1289}
1290
1291/// CLI arguments for `cast --to-base`.
1292#[derive(Debug, Parser)]
1293pub struct ToBaseArgs {
1294    /// The value to convert.
1295    #[arg(allow_hyphen_values = true)]
1296    pub value: Option<String>,
1297
1298    /// The input base.
1299    #[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    // <https://github.com/foundry-rs/book/issues/1019>
1383    #[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}