1use crate::tx::{CastTxBuilder, SenderKind};
2use alloy_ens::NameOrAddress;
3use alloy_primitives::U256;
4use alloy_provider::Provider;
5use alloy_rpc_types::BlockId;
6use clap::Parser;
7use eyre::Result;
8use foundry_cli::{
9 opts::{RpcOpts, TransactionOpts},
10 utils::{self, LoadConfig, parse_ether_value},
11};
12use foundry_wallets::WalletOpts;
13use std::str::FromStr;
14
15#[derive(Debug, Parser)]
17pub struct EstimateArgs {
18 #[arg(value_parser = NameOrAddress::from_str)]
20 to: Option<NameOrAddress>,
21
22 sig: Option<String>,
24
25 #[arg(allow_negative_numbers = true)]
27 args: Vec<String>,
28
29 #[arg(long, short = 'B')]
33 block: Option<BlockId>,
34
35 #[arg(long)]
39 cost: bool,
40
41 #[command(flatten)]
42 wallet: WalletOpts,
43
44 #[command(subcommand)]
45 command: Option<EstimateSubcommands>,
46
47 #[command(flatten)]
48 tx: TransactionOpts,
49
50 #[command(flatten)]
51 rpc: RpcOpts,
52}
53
54#[derive(Debug, Parser)]
55pub enum EstimateSubcommands {
56 #[command(name = "--create")]
58 Create {
59 code: String,
61
62 sig: Option<String>,
64
65 #[arg(allow_negative_numbers = true)]
67 args: Vec<String>,
68
69 #[arg(long, value_parser = parse_ether_value)]
75 value: Option<U256>,
76 },
77}
78
79impl EstimateArgs {
80 pub async fn run(self) -> Result<()> {
81 let Self { to, mut sig, mut args, mut tx, block, cost, wallet, rpc, command } = self;
82
83 let config = rpc.load_config()?;
84 let provider = utils::get_provider(&config)?;
85 let sender = SenderKind::from_wallet_opts(wallet).await?;
86
87 let code = if let Some(EstimateSubcommands::Create {
88 code,
89 sig: create_sig,
90 args: create_args,
91 value,
92 }) = command
93 {
94 sig = create_sig;
95 args = create_args;
96 if let Some(value) = value {
97 tx.value = Some(value);
98 }
99 Some(code)
100 } else {
101 None
102 };
103
104 let (tx, _) = CastTxBuilder::new(&provider, tx, &config)
105 .await?
106 .with_to(to)
107 .await?
108 .with_code_sig_and_args(code, sig, args)
109 .await?
110 .build_raw(sender)
111 .await?;
112
113 let gas = provider.estimate_gas(tx).block(block.unwrap_or_default()).await?;
114 if cost {
115 let gas_price_wei = provider.get_gas_price().await?;
116 let cost = gas_price_wei * gas as u128;
117 let cost_eth = cost as f64 / 1e18;
118 sh_println!("{cost_eth}")?;
119 } else {
120 sh_println!("{gas}")?;
121 }
122 Ok(())
123 }
124}
125
126#[cfg(test)]
127mod tests {
128 use super::*;
129
130 #[test]
131 fn parse_estimate_value() {
132 let args: EstimateArgs = EstimateArgs::parse_from(["foundry-cli", "--value", "100"]);
133 assert!(args.tx.value.is_some());
134 }
135}