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::{EthereumOpts, TransactionOpts},
10 utils::{self, LoadConfig, parse_ether_value},
11};
12use std::str::FromStr;
13
14#[derive(Debug, Parser)]
16pub struct EstimateArgs {
17 #[arg(value_parser = NameOrAddress::from_str)]
19 to: Option<NameOrAddress>,
20
21 sig: Option<String>,
23
24 #[arg(allow_negative_numbers = true)]
26 args: Vec<String>,
27
28 #[arg(long, short = 'B')]
32 block: Option<BlockId>,
33
34 #[arg(long)]
38 cost: bool,
39
40 #[command(subcommand)]
41 command: Option<EstimateSubcommands>,
42
43 #[command(flatten)]
44 tx: TransactionOpts,
45
46 #[command(flatten)]
47 eth: EthereumOpts,
48}
49
50#[derive(Debug, Parser)]
51pub enum EstimateSubcommands {
52 #[command(name = "--create")]
54 Create {
55 code: String,
57
58 sig: Option<String>,
60
61 #[arg(allow_negative_numbers = true)]
63 args: Vec<String>,
64
65 #[arg(long, value_parser = parse_ether_value)]
71 value: Option<U256>,
72 },
73}
74
75impl EstimateArgs {
76 pub async fn run(self) -> Result<()> {
77 let Self { to, mut sig, mut args, mut tx, block, cost, eth, command } = self;
78
79 let config = eth.load_config()?;
80 let provider = utils::get_provider(&config)?;
81 let sender = SenderKind::from_wallet_opts(eth.wallet).await?;
82
83 let code = if let Some(EstimateSubcommands::Create {
84 code,
85 sig: create_sig,
86 args: create_args,
87 value,
88 }) = command
89 {
90 sig = create_sig;
91 args = create_args;
92 if let Some(value) = value {
93 tx.value = Some(value);
94 }
95 Some(code)
96 } else {
97 None
98 };
99
100 let (tx, _) = CastTxBuilder::new(&provider, tx, &config)
101 .await?
102 .with_to(to)
103 .await?
104 .with_code_sig_and_args(code, sig, args)
105 .await?
106 .build_raw(sender)
107 .await?;
108
109 let gas = provider.estimate_gas(tx).block(block.unwrap_or_default()).await?;
110 if cost {
111 let gas_price_wei = provider.get_gas_price().await?;
112 let cost = gas_price_wei * gas as u128;
113 let cost_eth = cost as f64 / 1e18;
114 sh_println!("{cost_eth}")?;
115 } else {
116 sh_println!("{gas}")?;
117 }
118 Ok(())
119 }
120}
121
122#[cfg(test)]
123mod tests {
124 use super::*;
125
126 #[test]
127 fn parse_estimate_value() {
128 let args: EstimateArgs = EstimateArgs::parse_from(["foundry-cli", "--value", "100"]);
129 assert!(args.tx.value.is_some());
130 }
131}