@@ -75,10 +75,15 @@ const handler: Processor<string, void, string> = async (job: Job<string>) => {
7575 return ;
7676 }
7777
78- // The transaction may be errored if it is manually retried.
79- // For example, the developer retried all failed transactions during an RPC outage.
80- // An errored queued transaction (resendCount = 0) is safe to retry: the transaction wasn't sent to RPC.
81- if ( transaction . status === "errored" && resendCount === 0 ) {
78+ // If the transaction is errored and has not yet been sent,
79+ // reset it to a QueuedTransaction to try again.
80+ // No transaction hashes means the transaction is not in-flight.
81+ if (
82+ transaction . status === "errored" &&
83+ ! transaction . isUserOp &&
84+ "sentTransactionHashes" in transaction &&
85+ transaction . sentTransactionHashes . length > 0
86+ ) {
8287 const { errorMessage, ...omitted } = transaction ;
8388 transaction = {
8489 ...omitted ,
@@ -438,7 +443,7 @@ const _resendTransaction = async (
438443
439444 // Populate the transaction with double gas.
440445 const { chainId, from, overrides, sentTransactionHashes } = sentTransaction ;
441- const populatedTransaction = await toSerializableTransaction ( {
446+ let populatedTransaction = await toSerializableTransaction ( {
442447 from : getChecksumAddress ( from ) ,
443448 transaction : {
444449 client : thirdwebClient ,
@@ -452,21 +457,12 @@ const _resendTransaction = async (
452457 } ,
453458 } ) ;
454459
455- // Double the gas fee settings each attempt up to 10x.
456- // Do not update gas if overrides were provided.
457- const gasMultiple = BigInt ( clamp ( job . attemptsMade * 2 , { min : 2 , max : 10 } ) ) ;
458- if ( populatedTransaction . gasPrice ) {
459- populatedTransaction . gasPrice *= gasMultiple ;
460- }
461- if ( populatedTransaction . maxFeePerGas && ! overrides ?. maxFeePerGas ) {
462- populatedTransaction . maxFeePerGas *= gasMultiple ;
463- }
464- if (
465- populatedTransaction . maxPriorityFeePerGas &&
466- ! overrides ?. maxPriorityFeePerGas
467- ) {
468- populatedTransaction . maxPriorityFeePerGas *= gasMultiple ;
469- }
460+ // Increase gas fees for this resend attempt.
461+ populatedTransaction = _updateGasFees (
462+ populatedTransaction ,
463+ sentTransaction . resendCount + 1 ,
464+ sentTransaction . overrides ,
465+ ) ;
470466
471467 job . log ( `Populated transaction: ${ stringify ( populatedTransaction ) } ` ) ;
472468
@@ -577,6 +573,47 @@ const _hasExceededTimeout = (
577573const _minutesFromNow = ( minutes : number ) =>
578574 new Date ( Date . now ( ) + minutes * 60_000 ) ;
579575
576+ /**
577+ * Computes the aggressive gas fees to use when resending a transaction.
578+ *
579+ * For legacy transactions (pre-EIP1559):
580+ * - Set gas price to 2 * current attempt, capped at 10x.
581+ *
582+ * For transactions with maxFeePerGas + maxPriorityFeePerGas:
583+ * - Set maxPriorityFeePerGas to 2x current attempt, capped at 10x.
584+ * - Set maxFeePerGas to 2 * current max fee, plus the maxPriorityFeePerGas.
585+ *
586+ * @param populatedTransaction The transaction with estimated gas from RPC.
587+ * @param resendCount The resend attempt #. Example: 2 = the transaction was initially sent, then resent once. This is the second resend attempt.
588+ */
589+ export const _updateGasFees = (
590+ populatedTransaction : PopulatedTransaction ,
591+ resendCount : number ,
592+ overrides : SentTransaction [ "overrides" ] ,
593+ ) : PopulatedTransaction => {
594+ if ( resendCount === 0 ) {
595+ return populatedTransaction ;
596+ }
597+
598+ const multiplier = BigInt ( clamp ( resendCount * 2 , { min : 2 , max : 10 } ) ) ;
599+
600+ const updated = { ...populatedTransaction } ;
601+ if ( updated . gasPrice ) {
602+ updated . gasPrice *= multiplier ;
603+ }
604+ // Don't update gas fees that are explicitly overridden.
605+ if ( updated . maxPriorityFeePerGas && ! overrides ?. maxPriorityFeePerGas ) {
606+ updated . maxPriorityFeePerGas *= multiplier ;
607+ }
608+ // Don't update gas fees that are explicitly overridden.
609+ if ( updated . maxFeePerGas && ! overrides ?. maxFeePerGas ) {
610+ updated . maxFeePerGas =
611+ updated . maxFeePerGas * 2n + ( updated . maxPriorityFeePerGas ?? 0n ) ;
612+ }
613+
614+ return updated ;
615+ } ;
616+
580617// Must be explicitly called for the worker to run on this host.
581618export const initSendTransactionWorker = ( ) => {
582619 const _worker = new Worker ( SendTransactionQueue . q . name , handler , {
0 commit comments