@@ -389,24 +389,77 @@ impl<C: Chain> EoaExecutorWorker<C> {
389389 inner_error, ..
390390 } = & e
391391 {
392- if should_update_balance_threshold ( inner_error) {
393- if let Err ( e) = self . update_balance_threshold ( ) . await {
394- tracing:: error!( "Failed to update balance threshold: {}" , e) ;
395- }
392+ if should_update_balance_threshold ( inner_error)
393+ && let Err ( e) = self . update_balance_threshold ( ) . await
394+ {
395+ tracing:: error!( "Failed to update balance threshold: {}" , e) ;
396+ }
397+ } else if let EoaExecutorWorkerError :: RpcError { inner_error, .. } = & e
398+ && should_update_balance_threshold ( inner_error)
399+ && let Err ( e) = self . update_balance_threshold ( ) . await
400+ {
401+ tracing:: error!( "Failed to update balance threshold: {}" , e) ;
402+ }
403+ // Check if nonce has moved ahead since we started the gas bump
404+ // This handles the race condition where the original transaction
405+ // confirmed between our initial nonce check and the gas bump attempt
406+ let fresh_transaction_counts = match self
407+ . chain
408+ . provider ( )
409+ . get_transaction_counts_with_flashblocks_support (
410+ self . eoa ,
411+ self . chain . chain_id ( ) ,
412+ )
413+ . await
414+ {
415+ Ok ( counts) => counts,
416+ Err ( rpc_error) => {
417+ tracing:: warn!(
418+ transaction_id = ?newest_transaction_data. transaction_id,
419+ nonce = expected_nonce,
420+ error = ?e,
421+ rpc_check_error = ?rpc_error,
422+ "Failed to build typed transaction for gas bump and also failed to check nonce"
423+ ) ;
424+ return Err ( e) ;
396425 }
397- } else if let EoaExecutorWorkerError :: RpcError { inner_error, .. } = & e {
398- if should_update_balance_threshold ( inner_error) {
399- if let Err ( e) = self . update_balance_threshold ( ) . await {
400- tracing:: error!( "Failed to update balance threshold: {}" , e) ;
426+ } ;
427+
428+ // If nonce has moved ahead, the transaction likely confirmed
429+ // Break out of gas bump flow and let regular confirmation flow handle it
430+ if fresh_transaction_counts. preconfirmed > expected_nonce {
431+ tracing:: info!(
432+ transaction_id = ?newest_transaction_data. transaction_id,
433+ nonce = expected_nonce,
434+ current_preconfirmed_nonce = fresh_transaction_counts. preconfirmed,
435+ current_latest_nonce = fresh_transaction_counts. latest,
436+ "Gas bump simulation failed but nonce has moved ahead - transaction likely confirmed. Breaking out of gas bump flow."
437+ ) ;
438+
439+ if let Ok ( mut health) = self . get_eoa_health ( ) . await {
440+ let now = EoaExecutorStore :: now ( ) ;
441+ health. last_nonce_movement_at = now;
442+ health. last_confirmation_at = now;
443+ if let Err ( update_err) = self . store . update_health_data ( & health) . await {
444+ tracing:: warn!(
445+ error = ?update_err,
446+ nonce = expected_nonce,
447+ "Detected nonce movement but failed to refresh health data"
448+ ) ;
401449 }
402450 }
451+ // Return success to break out of gas bump flow
452+ // The regular confirmation flow will handle the confirmed transaction
453+ return Ok ( true ) ;
403454 }
404455
405456 tracing:: warn!(
406457 transaction_id = ?newest_transaction_data. transaction_id,
407458 nonce = expected_nonce,
459+ current_preconfirmed_nonce = fresh_transaction_counts. preconfirmed,
460+ current_latest_nonce = fresh_transaction_counts. latest,
408461 error = ?e,
409- "Failed to build typed transaction for gas bump"
462+ "Failed to build typed transaction for gas bump and nonce has not moved ahead "
410463 ) ;
411464 return Err ( e) ;
412465 }
0 commit comments