@@ -9,12 +9,12 @@ use crate::{
99 update_progress,
1010} ;
1111use ethers:: {
12- prelude:: { Signer , SignerMiddleware , TxHash } ,
13- providers:: Middleware ,
12+ prelude:: { Provider , Signer , SignerMiddleware , TxHash } ,
13+ providers:: { JsonRpcClient , Middleware } ,
1414 types:: transaction:: eip2718:: TypedTransaction ,
1515 utils:: format_units,
1616} ;
17- use eyre:: ContextCompat ;
17+ use eyre:: { ContextCompat , WrapErr } ;
1818use foundry_common:: { get_http_provider, RetryProvider } ;
1919use foundry_config:: Chain ;
2020use futures:: StreamExt ;
@@ -188,9 +188,9 @@ impl ScriptArgs {
188188 }
189189
190190 match signer {
191- WalletType :: Local ( signer) => broadcast ( signer, tx) . await ,
192- WalletType :: Ledger ( signer) => broadcast ( signer, tx) . await ,
193- WalletType :: Trezor ( signer) => broadcast ( signer, tx) . await ,
191+ WalletType :: Local ( signer) => self . broadcast ( signer, tx) . await ,
192+ WalletType :: Ledger ( signer) => self . broadcast ( signer, tx) . await ,
193+ WalletType :: Trezor ( signer) => self . broadcast ( signer, tx) . await ,
194194 }
195195 }
196196
@@ -277,43 +277,106 @@ impl ScriptArgs {
277277 for mut tx in txes. into_iter ( ) {
278278 tx. change_type ( is_legacy) ;
279279
280- let typed_tx = tx. typed_tx_mut ( ) ;
280+ if !self . skip_simulation {
281+ let typed_tx = tx. typed_tx_mut ( ) ;
281282
282- if has_different_gas_calc ( chain) || self . skip_simulation {
283- typed_tx. set_gas (
284- provider. estimate_gas ( typed_tx) . await ? * self . gas_estimate_multiplier / 100 ,
285- ) ;
286- }
283+ if has_different_gas_calc ( chain) {
284+ self . estimate_gas ( typed_tx, & provider) . await ?;
285+ }
287286
288- total_gas += * typed_tx. gas ( ) . expect ( "gas is set" ) ;
287+ total_gas += * typed_tx. gas ( ) . expect ( "gas is set" ) ;
288+ }
289289
290290 new_txes. push_back ( tx) ;
291291 }
292292
293- // We don't store it in the transactions, since we want the most updated value. Right before
294- // broadcasting.
295- let per_gas = if let Some ( gas_price) = self . with_gas_price {
296- gas_price
297- } else {
298- match new_txes. front ( ) . unwrap ( ) . typed_tx ( ) {
299- TypedTransaction :: Legacy ( _) | TypedTransaction :: Eip2930 ( _) => {
300- provider. get_gas_price ( ) . await ?
293+ if !self . skip_simulation {
294+ // We don't store it in the transactions, since we want the most updated value. Right
295+ // before broadcasting.
296+ let per_gas = if let Some ( gas_price) = self . with_gas_price {
297+ gas_price
298+ } else {
299+ match new_txes. front ( ) . unwrap ( ) . typed_tx ( ) {
300+ TypedTransaction :: Legacy ( _) | TypedTransaction :: Eip2930 ( _) => {
301+ provider. get_gas_price ( ) . await ?
302+ }
303+ TypedTransaction :: Eip1559 ( _) => provider. estimate_eip1559_fees ( None ) . await ?. 0 ,
301304 }
302- TypedTransaction :: Eip1559 ( _) => provider. estimate_eip1559_fees ( None ) . await ?. 0 ,
303- }
304- } ;
305+ } ;
305306
306- println ! ( "\n ==========================" ) ;
307- println ! ( "\n Estimated total gas used for script: {}" , total_gas) ;
308- println ! (
309- "\n Estimated amount required: {} ETH" ,
310- format_units( total_gas. saturating_mul( per_gas) , 18 )
311- . unwrap_or_else( |_| "[Could not calculate]" . to_string( ) )
312- . trim_end_matches( '0' )
313- ) ;
314- println ! ( "\n ==========================" ) ;
307+ println ! ( "\n ==========================" ) ;
308+ println ! ( "\n Estimated total gas used for script: {}" , total_gas) ;
309+ println ! (
310+ "\n Estimated amount required: {} ETH" ,
311+ format_units( total_gas. saturating_mul( per_gas) , 18 )
312+ . unwrap_or_else( |_| "[Could not calculate]" . to_string( ) )
313+ . trim_end_matches( '0' )
314+ ) ;
315+ println ! ( "\n ==========================" ) ;
316+ }
315317 Ok ( new_txes)
316318 }
319+ /// Uses the signer to submit a transaction to the network. If it fails, it tries to retrieve
320+ /// the transaction hash that can be used on a later run with `--resume`.
321+ async fn broadcast < T , U > (
322+ & self ,
323+ signer : & SignerMiddleware < T , U > ,
324+ mut legacy_or_1559 : TypedTransaction ,
325+ ) -> Result < TxHash , BroadcastError >
326+ where
327+ T : Middleware ,
328+ U : Signer ,
329+ {
330+ tracing:: debug!( "sending transaction: {:?}" , legacy_or_1559) ;
331+
332+ // Chains which use `eth_estimateGas` are being sent sequentially and require their gas to
333+ // be re-estimated right before broadcasting.
334+ if has_different_gas_calc ( signer. signer ( ) . chain_id ( ) ) || self . skip_simulation {
335+ // if already set, some RPC endpoints might simply return the gas value that is already
336+ // set in the request and omit the estimate altogether, so we remove it here
337+ let _ = legacy_or_1559. gas_mut ( ) . take ( ) ;
338+
339+ self . estimate_gas ( & mut legacy_or_1559, signer. provider ( ) ) . await ?;
340+ }
341+
342+ // Signing manually so we skip `fill_transaction` and its `eth_createAccessList` request.
343+ let signature = signer
344+ . sign_transaction (
345+ & legacy_or_1559,
346+ * legacy_or_1559. from ( ) . expect ( "Tx should have a `from`." ) ,
347+ )
348+ . await
349+ . map_err ( |err| BroadcastError :: Simple ( err. to_string ( ) ) ) ?;
350+
351+ // Submit the raw transaction
352+ let pending = signer
353+ . provider ( )
354+ . send_raw_transaction ( legacy_or_1559. rlp_signed ( & signature) )
355+ . await
356+ . map_err ( |err| BroadcastError :: Simple ( err. to_string ( ) ) ) ?;
357+
358+ Ok ( pending. tx_hash ( ) )
359+ }
360+
361+ async fn estimate_gas < T > (
362+ & self ,
363+ tx : & mut TypedTransaction ,
364+ provider : & Provider < T > ,
365+ ) -> Result < ( ) , BroadcastError >
366+ where
367+ T : JsonRpcClient ,
368+ {
369+ tx. set_gas (
370+ provider
371+ . estimate_gas ( tx)
372+ . await
373+ . wrap_err_with ( || format ! ( "Failed to estimate gas for tx: {}" , tx. sighash( ) ) )
374+ . map_err ( |err| BroadcastError :: Simple ( err. to_string ( ) ) ) ? *
375+ self . gas_estimate_multiplier /
376+ 100 ,
377+ ) ;
378+ Ok ( ( ) )
379+ }
317380}
318381
319382#[ derive( thiserror:: Error , Debug , Clone ) ]
@@ -332,50 +395,3 @@ impl fmt::Display for BroadcastError {
332395 }
333396 }
334397}
335-
336- /// Uses the signer to submit a transaction to the network. If it fails, it tries to retrieve the
337- /// transaction hash that can be used on a later run with `--resume`.
338- async fn broadcast < T , U > (
339- signer : & SignerMiddleware < T , U > ,
340- mut legacy_or_1559 : TypedTransaction ,
341- ) -> Result < TxHash , BroadcastError >
342- where
343- T : Middleware ,
344- U : Signer ,
345- {
346- tracing:: debug!( "sending transaction: {:?}" , legacy_or_1559) ;
347-
348- // Chains which use `eth_estimateGas` are being sent sequentially and require their gas to be
349- // re-estimated right before broadcasting.
350- if has_different_gas_calc ( signer. signer ( ) . chain_id ( ) ) {
351- // if already set, some RPC endpoints might simply return the gas value that is already set
352- // in the request and omit the estimate altogether, so we remove it here
353- let _ = legacy_or_1559. gas_mut ( ) . take ( ) ;
354-
355- legacy_or_1559. set_gas (
356- signer
357- . provider ( )
358- . estimate_gas ( & legacy_or_1559)
359- . await
360- . map_err ( |err| BroadcastError :: Simple ( err. to_string ( ) ) ) ?,
361- ) ;
362- }
363-
364- // Signing manually so we skip `fill_transaction` and its `eth_createAccessList` request.
365- let signature = signer
366- . sign_transaction (
367- & legacy_or_1559,
368- * legacy_or_1559. from ( ) . expect ( "Tx should have a `from`." ) ,
369- )
370- . await
371- . map_err ( |err| BroadcastError :: Simple ( err. to_string ( ) ) ) ?;
372-
373- // Submit the raw transaction
374- let pending = signer
375- . provider ( )
376- . send_raw_transaction ( legacy_or_1559. rlp_signed ( & signature) )
377- . await
378- . map_err ( |err| BroadcastError :: Simple ( err. to_string ( ) ) ) ?;
379-
380- Ok ( pending. tx_hash ( ) )
381- }
0 commit comments