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