cast/cmd/
estimate.rs

1use crate::tx::{CastTxBuilder, SenderKind};
2use alloy_primitives::U256;
3use alloy_provider::Provider;
4use alloy_rpc_types::BlockId;
5use clap::Parser;
6use eyre::Result;
7use foundry_cli::{
8    opts::{EthereumOpts, TransactionOpts},
9    utils::{self, parse_ether_value, LoadConfig},
10};
11use foundry_common::ens::NameOrAddress;
12use std::str::FromStr;
13
14/// CLI arguments for `cast estimate`.
15#[derive(Debug, Parser)]
16pub struct EstimateArgs {
17    /// The destination of the transaction.
18    #[arg(value_parser = NameOrAddress::from_str)]
19    to: Option<NameOrAddress>,
20
21    /// The signature of the function to call.
22    sig: Option<String>,
23
24    /// The arguments of the function to call.
25    args: Vec<String>,
26
27    /// The block height to query at.
28    ///
29    /// Can also be the tags earliest, finalized, safe, latest, or pending.
30    #[arg(long, short = 'B')]
31    block: Option<BlockId>,
32
33    #[command(subcommand)]
34    command: Option<EstimateSubcommands>,
35
36    #[command(flatten)]
37    tx: TransactionOpts,
38
39    #[command(flatten)]
40    eth: EthereumOpts,
41}
42
43#[derive(Debug, Parser)]
44pub enum EstimateSubcommands {
45    /// Estimate gas cost to deploy a smart contract
46    #[command(name = "--create")]
47    Create {
48        /// The bytecode of contract
49        code: String,
50
51        /// The signature of the constructor
52        sig: Option<String>,
53
54        /// Constructor arguments
55        args: Vec<String>,
56
57        /// Ether to send in the transaction
58        ///
59        /// Either specified in wei, or as a string with a unit type:
60        ///
61        /// Examples: 1ether, 10gwei, 0.01ether
62        #[arg(long, value_parser = parse_ether_value)]
63        value: Option<U256>,
64    },
65}
66
67impl EstimateArgs {
68    pub async fn run(self) -> Result<()> {
69        let Self { to, mut sig, mut args, mut tx, block, eth, command } = self;
70
71        let config = eth.load_config()?;
72        let provider = utils::get_provider(&config)?;
73        let sender = SenderKind::from_wallet_opts(eth.wallet).await?;
74
75        let code = if let Some(EstimateSubcommands::Create {
76            code,
77            sig: create_sig,
78            args: create_args,
79            value,
80        }) = command
81        {
82            sig = create_sig;
83            args = create_args;
84            if let Some(value) = value {
85                tx.value = Some(value);
86            }
87            Some(code)
88        } else {
89            None
90        };
91
92        let (tx, _) = CastTxBuilder::new(&provider, tx, &config)
93            .await?
94            .with_to(to)
95            .await?
96            .with_code_sig_and_args(code, sig, args)
97            .await?
98            .build_raw(sender)
99            .await?;
100
101        let gas = provider.estimate_gas(tx).block(block.unwrap_or_default()).await?;
102        sh_println!("{gas}")?;
103        Ok(())
104    }
105}
106
107#[cfg(test)]
108mod tests {
109    use super::*;
110
111    #[test]
112    fn parse_estimate_value() {
113        let args: EstimateArgs = EstimateArgs::parse_from(["foundry-cli", "--value", "100"]);
114        assert!(args.tx.value.is_some());
115    }
116}