From b01c0c9a7f2849e8b142f1567b0e140ccbdffde8 Mon Sep 17 00:00:00 2001 From: Gabriel Martinez Rodriguez Date: Mon, 9 Dec 2024 13:02:43 +0100 Subject: [PATCH 1/6] feat(txm): customizable retry policy for reverted transactions --- .../lib/RetryPolicyManager.ts | 80 +++++++++++++++++++ .../lib/TransactionManager.ts | 11 +++ packages/transaction-manager/lib/TxMonitor.ts | 28 +++---- 3 files changed, 101 insertions(+), 18 deletions(-) create mode 100644 packages/transaction-manager/lib/RetryPolicyManager.ts diff --git a/packages/transaction-manager/lib/RetryPolicyManager.ts b/packages/transaction-manager/lib/RetryPolicyManager.ts new file mode 100644 index 0000000000..4de417fb01 --- /dev/null +++ b/packages/transaction-manager/lib/RetryPolicyManager.ts @@ -0,0 +1,80 @@ +import type { Address, Hash, Hex, Log } from "viem" +import type { Attempt, Transaction } from "./Transaction" +import type { TransactionManager } from "./TransactionManager" + +export interface RevertedTransactionReceipt { + /** The actual value per gas deducted from the sender's account for blob gas. Only specified for blob transactions as defined by EIP-4844. */ + blobGasPrice?: bigint | undefined + /** The amount of blob gas used. Only specified for blob transactions as defined by EIP-4844. */ + blobGasUsed?: bigint | undefined + /** Hash of block containing this transaction */ + blockHash: Hash + /** Number of block containing this transaction */ + blockNumber: bigint + /** Address of new contract or `null` if no contract was created */ + contractAddress: Address | null | undefined + /** Gas used by this and all preceding transactions in this block */ + cumulativeGasUsed: bigint + /** Pre-London, it is equal to the transaction's gasPrice. Post-London, it is equal to the actual gas price paid for inclusion. */ + effectiveGasPrice: bigint + /** Transaction sender */ + from: Address + /** Gas used by this transaction */ + gasUsed: bigint + /** List of log objects generated by this transaction */ + logs: Log[] + /** Logs bloom filter */ + logsBloom: Hex + /** The post-transaction state root. Only specified for transactions included before the Byzantium upgrade. */ + root?: Hash | undefined + /** `success` if this transaction was successful or `reverted` if it failed */ + status: T + /** Transaction recipient or `null` if deploying a contract */ + to: Address | null + /** Hash of this transaction */ + transactionHash: Hash + /** Index of this transaction in the block */ + transactionIndex: number + /** Transaction type */ + type: "eip1559" +} + +export interface IRetryPolicyManager { + shouldRetry( + transactionManager: TransactionManager, + transaction: Transaction, + attempt: Attempt, + receipt: RevertedTransactionReceipt<"reverted">, + ): Promise +} + +export class RetryPolicyManager implements IRetryPolicyManager { + public async shouldRetry( + transactionManager: TransactionManager, + _: Transaction, + attempt: Attempt, + receipt: RevertedTransactionReceipt<"reverted">, + ): Promise { + return this.isOutOfGas(transactionManager, attempt, receipt) + } + + protected async isOutOfGas( + transactionManager: TransactionManager, + attempt: Attempt, + receipt: RevertedTransactionReceipt<"reverted">, + ): Promise { + const traceResult = transactionManager.rpcAllowDebug + ? await transactionManager.viemClient.safeDebugTransaction(attempt.hash, { + tracer: "callTracer", + }) + : undefined + + if (!traceResult || traceResult.isErr()) { + return receipt.gasUsed === attempt.gas + } + + const trace = traceResult.value + + return trace.revertReason === "Out of Gas" + } +} diff --git a/packages/transaction-manager/lib/TransactionManager.ts b/packages/transaction-manager/lib/TransactionManager.ts index 7914899dc1..6bc3c86be5 100644 --- a/packages/transaction-manager/lib/TransactionManager.ts +++ b/packages/transaction-manager/lib/TransactionManager.ts @@ -23,6 +23,7 @@ import { DefaultGasLimitEstimator, type GasEstimator } from "./GasEstimator.js" import { GasPriceOracle } from "./GasPriceOracle.js" import { HookManager, type TxmHookHandler, type TxmHookType } from "./HookManager.js" import { NonceManager } from "./NonceManager.js" +import { RetryPolicyManager } from "./RetryPolicyManager" import { Transaction, type TransactionConstructorConfig } from "./Transaction.js" import { TransactionCollector } from "./TransactionCollector.js" import { TransactionRepository } from "./TransactionRepository.js" @@ -119,6 +120,14 @@ export type TransactionManagerConfig = { * Default: {@link DefaultGasLimitEstimator} */ gasEstimator?: GasEstimator + + /** + * The retry policy manager to use for retrying failed transactions. + * You can provide your own implementation to override the default one. + * This is used to determine if a transaction should be retried based on the receipt of the transaction when it reverts. + * Default: {@link RetryPolicyManager} + */ + retryPolicyManager?: RetryPolicyManager } export type TransactionOriginator = (block: LatestBlock) => Promise @@ -144,6 +153,7 @@ export class TransactionManager { public readonly transactionCollector: TransactionCollector public readonly transactionSubmitter: TransactionSubmitter public readonly hookManager: HookManager + public readonly retryPolicyManager: RetryPolicyManager public readonly chainId: number public readonly eip1559: EIP1559Parameters @@ -228,6 +238,7 @@ export class TransactionManager { this.transactionCollector = new TransactionCollector(this) this.transactionSubmitter = new TransactionSubmitter(this) this.hookManager = new HookManager() + this.retryPolicyManager = _config.retryPolicyManager || new RetryPolicyManager() this.chainId = _config.chainId this.eip1559 = _config.eip1559 || opStackDefaultEIP1559Parameters diff --git a/packages/transaction-manager/lib/TxMonitor.ts b/packages/transaction-manager/lib/TxMonitor.ts index 0d68ea205f..56cbd2683f 100644 --- a/packages/transaction-manager/lib/TxMonitor.ts +++ b/packages/transaction-manager/lib/TxMonitor.ts @@ -3,6 +3,7 @@ import { type Result, ResultAsync, err, ok } from "neverthrow" import { type GetTransactionReceiptErrorType, type TransactionReceipt, TransactionReceiptNotFoundError } from "viem" import type { LatestBlock } from "./BlockMonitor.js" import { Topics, eventBus } from "./EventBus.js" +import type { RevertedTransactionReceipt } from "./RetryPolicyManager" import { type Attempt, AttemptType, type Transaction, TransactionStatus } from "./Transaction.js" import type { TransactionManager } from "./TransactionManager.js" @@ -123,28 +124,19 @@ export class TxMonitor { return transaction.changeStatus(TransactionStatus.Success) } - const traceResult = this.transactionManager.rpcAllowDebug - ? await this.transactionManager.viemClient.safeDebugTransaction(attempt.hash, { - tracer: "callTracer", - }) - : undefined + const shouldRetry = await this.transactionManager.retryPolicyManager.shouldRetry( + this.transactionManager, + transaction, + attempt, + receipt as RevertedTransactionReceipt<"reverted">, + ) - if (!traceResult || traceResult.isErr()) { - if (receipt.gasUsed === attempt.gas) { - return await this.handleOutOfGasTransaction(transaction) - } + if (!shouldRetry) { console.error(`Transaction ${transaction.intentId} failed`) return transaction.changeStatus(TransactionStatus.Failed) } - const trace = traceResult.value - - if (trace.revertReason === "Out of Gas") { - await this.handleOutOfGasTransaction(transaction) - } else { - console.error(`Transaction ${transaction.intentId} failed with reason: ${trace.revertReason}`) - return transaction.changeStatus(TransactionStatus.Failed) - } + return this.handleRetryTransaction(transaction) }) await Promise.all(promises) @@ -248,7 +240,7 @@ export class TxMonitor { } } - private async handleOutOfGasTransaction(transaction: Transaction): Promise { + private async handleRetryTransaction(transaction: Transaction): Promise { const nonce = this.transactionManager.nonceManager.requestNonce() const { maxFeePerGas: marketMaxFeePerGas, maxPriorityFeePerGas: marketMaxPriorityFeePerGas } = this.transactionManager.gasPriceOracle.suggestGasForNextBlock() From 508a67bc705cd7ca5e3239c2b493a010fa75d697 Mon Sep 17 00:00:00 2001 From: Gabriel Martinez Rodriguez Date: Mon, 9 Dec 2024 13:06:28 +0100 Subject: [PATCH 2/6] chore(txm): RetryPolicyManager implements a method to get the revert reason easier --- .../lib/RetryPolicyManager.ts | 29 +++++++++++++++---- 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/packages/transaction-manager/lib/RetryPolicyManager.ts b/packages/transaction-manager/lib/RetryPolicyManager.ts index 4de417fb01..e7b72138cd 100644 --- a/packages/transaction-manager/lib/RetryPolicyManager.ts +++ b/packages/transaction-manager/lib/RetryPolicyManager.ts @@ -58,11 +58,16 @@ export class RetryPolicyManager implements IRetryPolicyManager { return this.isOutOfGas(transactionManager, attempt, receipt) } - protected async isOutOfGas( + /** + * Get the revert reason from the transaction trace + * @param transactionManager - The transaction manager + * @param attempt - The attempt + * @returns The revert reason or undefined if it cannot be retrieved or the rpc does not allow debug + */ + protected async getRevertReason( transactionManager: TransactionManager, attempt: Attempt, - receipt: RevertedTransactionReceipt<"reverted">, - ): Promise { + ): Promise { const traceResult = transactionManager.rpcAllowDebug ? await transactionManager.viemClient.safeDebugTransaction(attempt.hash, { tracer: "callTracer", @@ -70,11 +75,23 @@ export class RetryPolicyManager implements IRetryPolicyManager { : undefined if (!traceResult || traceResult.isErr()) { - return receipt.gasUsed === attempt.gas + return undefined } - const trace = traceResult.value + return traceResult.value.revertReason + } + + protected async isOutOfGas( + transactionManager: TransactionManager, + attempt: Attempt, + receipt: RevertedTransactionReceipt<"reverted">, + ): Promise { + const revertReason = await this.getRevertReason(transactionManager, attempt) + + if (!revertReason) { + return receipt.gasUsed === attempt.gas + } - return trace.revertReason === "Out of Gas" + return revertReason === "Out of Gas" } } From cc060f64a76b12192fd9b3194940601e1ce207d7 Mon Sep 17 00:00:00 2001 From: Gabriel Martinez Rodriguez Date: Mon, 6 Jan 2025 15:56:15 +0100 Subject: [PATCH 3/6] chore(txm): use viem receipt --- .../lib/RetryPolicyManager.ts | 44 +++---------------- 1 file changed, 7 insertions(+), 37 deletions(-) diff --git a/packages/transaction-manager/lib/RetryPolicyManager.ts b/packages/transaction-manager/lib/RetryPolicyManager.ts index e7b72138cd..51389ffd56 100644 --- a/packages/transaction-manager/lib/RetryPolicyManager.ts +++ b/packages/transaction-manager/lib/RetryPolicyManager.ts @@ -1,43 +1,13 @@ -import type { Address, Hash, Hex, Log } from "viem" +import type { TransactionReceipt } from "viem" import type { Attempt, Transaction } from "./Transaction" import type { TransactionManager } from "./TransactionManager" -export interface RevertedTransactionReceipt { - /** The actual value per gas deducted from the sender's account for blob gas. Only specified for blob transactions as defined by EIP-4844. */ - blobGasPrice?: bigint | undefined - /** The amount of blob gas used. Only specified for blob transactions as defined by EIP-4844. */ - blobGasUsed?: bigint | undefined - /** Hash of block containing this transaction */ - blockHash: Hash - /** Number of block containing this transaction */ - blockNumber: bigint - /** Address of new contract or `null` if no contract was created */ - contractAddress: Address | null | undefined - /** Gas used by this and all preceding transactions in this block */ - cumulativeGasUsed: bigint - /** Pre-London, it is equal to the transaction's gasPrice. Post-London, it is equal to the actual gas price paid for inclusion. */ - effectiveGasPrice: bigint - /** Transaction sender */ - from: Address - /** Gas used by this transaction */ - gasUsed: bigint - /** List of log objects generated by this transaction */ - logs: Log[] - /** Logs bloom filter */ - logsBloom: Hex - /** The post-transaction state root. Only specified for transactions included before the Byzantium upgrade. */ - root?: Hash | undefined - /** `success` if this transaction was successful or `reverted` if it failed */ - status: T - /** Transaction recipient or `null` if deploying a contract */ - to: Address | null - /** Hash of this transaction */ - transactionHash: Hash - /** Index of this transaction in the block */ - transactionIndex: number - /** Transaction type */ - type: "eip1559" -} +export type RevertedTransactionReceipt = TransactionReceipt< + bigint, + number, + Status, + "eip1559" +> export interface IRetryPolicyManager { shouldRetry( From 7d752bb2622075fcab5ab4ded48f5a06f771f3fb Mon Sep 17 00:00:00 2001 From: Gabriel Martinez Rodriguez Date: Mon, 6 Jan 2025 16:30:41 +0100 Subject: [PATCH 4/6] chore(txm): retry policy pr review --- .../transaction-manager/lib/RetryPolicyManager.ts | 12 +++++++++--- .../transaction-manager/lib/TransactionManager.ts | 6 +++--- packages/transaction-manager/lib/TxMonitor.ts | 4 ++++ 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/packages/transaction-manager/lib/RetryPolicyManager.ts b/packages/transaction-manager/lib/RetryPolicyManager.ts index 51389ffd56..0af3fa3962 100644 --- a/packages/transaction-manager/lib/RetryPolicyManager.ts +++ b/packages/transaction-manager/lib/RetryPolicyManager.ts @@ -9,7 +9,12 @@ export type RevertedTransactionReceipt = "eip1559" > -export interface IRetryPolicyManager { +/** + * Implement this interface and provide it in the {@link TransactionManager} constructor to define your custom retry policy. + * The default implementation is {@link DefaultRetryPolicyManager}. + * The default implementation will only retry if the transaction runs out of gas. + **/ +export interface RetryPolicyManager { shouldRetry( transactionManager: TransactionManager, transaction: Transaction, @@ -18,7 +23,7 @@ export interface IRetryPolicyManager { ): Promise } -export class RetryPolicyManager implements IRetryPolicyManager { +export class DefaultRetryPolicyManager implements RetryPolicyManager { public async shouldRetry( transactionManager: TransactionManager, _: Transaction, @@ -29,7 +34,8 @@ export class RetryPolicyManager implements IRetryPolicyManager { } /** - * Get the revert reason from the transaction trace + * Retrieves the reason for transaction reversion by utilizing the debug_traceTransaction RPC method. + * Returns undefined if the request fails or if the transaction has not been reverted. * @param transactionManager - The transaction manager * @param attempt - The attempt * @returns The revert reason or undefined if it cannot be retrieved or the rpc does not allow debug diff --git a/packages/transaction-manager/lib/TransactionManager.ts b/packages/transaction-manager/lib/TransactionManager.ts index 6bc3c86be5..6cf652d7c0 100644 --- a/packages/transaction-manager/lib/TransactionManager.ts +++ b/packages/transaction-manager/lib/TransactionManager.ts @@ -23,7 +23,7 @@ import { DefaultGasLimitEstimator, type GasEstimator } from "./GasEstimator.js" import { GasPriceOracle } from "./GasPriceOracle.js" import { HookManager, type TxmHookHandler, type TxmHookType } from "./HookManager.js" import { NonceManager } from "./NonceManager.js" -import { RetryPolicyManager } from "./RetryPolicyManager" +import { DefaultRetryPolicyManager, type RetryPolicyManager } from "./RetryPolicyManager.js" import { Transaction, type TransactionConstructorConfig } from "./Transaction.js" import { TransactionCollector } from "./TransactionCollector.js" import { TransactionRepository } from "./TransactionRepository.js" @@ -125,7 +125,7 @@ export type TransactionManagerConfig = { * The retry policy manager to use for retrying failed transactions. * You can provide your own implementation to override the default one. * This is used to determine if a transaction should be retried based on the receipt of the transaction when it reverts. - * Default: {@link RetryPolicyManager} + * Default: {@link DefaultRetryPolicyManager} */ retryPolicyManager?: RetryPolicyManager } @@ -238,7 +238,7 @@ export class TransactionManager { this.transactionCollector = new TransactionCollector(this) this.transactionSubmitter = new TransactionSubmitter(this) this.hookManager = new HookManager() - this.retryPolicyManager = _config.retryPolicyManager || new RetryPolicyManager() + this.retryPolicyManager = _config.retryPolicyManager || new DefaultRetryPolicyManager() this.chainId = _config.chainId this.eip1559 = _config.eip1559 || opStackDefaultEIP1559Parameters diff --git a/packages/transaction-manager/lib/TxMonitor.ts b/packages/transaction-manager/lib/TxMonitor.ts index 56cbd2683f..c65b9aadeb 100644 --- a/packages/transaction-manager/lib/TxMonitor.ts +++ b/packages/transaction-manager/lib/TxMonitor.ts @@ -76,6 +76,10 @@ export class TxMonitor { let isResolved = false const { promise: receiptPromise, resolve, reject: _reject } = promiseWithResolvers() + /* + We request receipts for all attempts in parallel. Since only one attempt can have a receipt due to they have the same nonce, + we can terminate the process as soon as a receipt is obtained. This is why we use a promise race. + */ const promises: Promise>[] = inAirAttempts.map( async (attempt): Promise> => { From 4888ec632afd0f1d483e3060837b7b821e4ee8d9 Mon Sep 17 00:00:00 2001 From: Gabriel Martinez Rodriguez Date: Mon, 13 Jan 2025 13:59:57 +0100 Subject: [PATCH 5/6] chore(txm): pr review --- .../transaction-manager/lib/RetryPolicyManager.ts | 13 ++++--------- packages/transaction-manager/lib/Transaction.ts | 4 ++-- .../transaction-manager/lib/TransactionManager.ts | 11 ----------- packages/transaction-manager/lib/TxMonitor.ts | 12 +++++++----- 4 files changed, 13 insertions(+), 27 deletions(-) diff --git a/packages/transaction-manager/lib/RetryPolicyManager.ts b/packages/transaction-manager/lib/RetryPolicyManager.ts index 0af3fa3962..baf4d2bc05 100644 --- a/packages/transaction-manager/lib/RetryPolicyManager.ts +++ b/packages/transaction-manager/lib/RetryPolicyManager.ts @@ -2,12 +2,7 @@ import type { TransactionReceipt } from "viem" import type { Attempt, Transaction } from "./Transaction" import type { TransactionManager } from "./TransactionManager" -export type RevertedTransactionReceipt = TransactionReceipt< - bigint, - number, - Status, - "eip1559" -> +export type RevertedTransactionReceipt = TransactionReceipt /** * Implement this interface and provide it in the {@link TransactionManager} constructor to define your custom retry policy. @@ -19,7 +14,7 @@ export interface RetryPolicyManager { transactionManager: TransactionManager, transaction: Transaction, attempt: Attempt, - receipt: RevertedTransactionReceipt<"reverted">, + receipt: RevertedTransactionReceipt, ): Promise } @@ -28,7 +23,7 @@ export class DefaultRetryPolicyManager implements RetryPolicyManager { transactionManager: TransactionManager, _: Transaction, attempt: Attempt, - receipt: RevertedTransactionReceipt<"reverted">, + receipt: RevertedTransactionReceipt, ): Promise { return this.isOutOfGas(transactionManager, attempt, receipt) } @@ -60,7 +55,7 @@ export class DefaultRetryPolicyManager implements RetryPolicyManager { protected async isOutOfGas( transactionManager: TransactionManager, attempt: Attempt, - receipt: RevertedTransactionReceipt<"reverted">, + receipt: RevertedTransactionReceipt, ): Promise { const revertReason = await this.getRevertReason(transactionManager, attempt) diff --git a/packages/transaction-manager/lib/Transaction.ts b/packages/transaction-manager/lib/Transaction.ts index 67ca68c35f..48befbd9d8 100644 --- a/packages/transaction-manager/lib/Transaction.ts +++ b/packages/transaction-manager/lib/Transaction.ts @@ -157,8 +157,8 @@ export class Transaction { this.createdAt = createdAt ?? new Date() this.updatedAt = updatedAt ?? new Date() this.metadata = metadata ?? {} - this.pendingFlush = pendingFlush === undefined ? true : pendingFlush - this.notPersisted = notPersisted === undefined ? true : notPersisted + this.pendingFlush = pendingFlush ?? true + this.notPersisted = notPersisted ?? true } addAttempt(attempt: Attempt): void { diff --git a/packages/transaction-manager/lib/TransactionManager.ts b/packages/transaction-manager/lib/TransactionManager.ts index 6cf652d7c0..3e48e6e812 100644 --- a/packages/transaction-manager/lib/TransactionManager.ts +++ b/packages/transaction-manager/lib/TransactionManager.ts @@ -43,19 +43,16 @@ export type TransactionManagerConfig = { url: string /** * The timeout for the RPC node. - * It is very important that the value of (timeout + retryDelay) * retries be less than the time block to avoid slowing down the transaction manager. * Defaults to 500 milliseconds. */ timeout?: number /** * The number of retries for the RPC node. - * It is very important that the value of (timeout + retryDelay) * retries be less than the time block to avoid slowing down the transaction manager. * Defaults to 2. */ retries?: number /** * The delay between retries. - * It is very important that the value of (timeout + retryDelay) * retries be less than the time block to avoid slowing down the transaction manager. * Defaults to 50 milliseconds. */ retryDelay?: number @@ -250,13 +247,6 @@ export class TransactionManager { this.rpcAllowDebug = _config.rpc.allowDebug || false this.blockTime = _config.blockTime || 2n this.finalizedTransactionPurgeTime = _config.finalizedTransactionPurgeTime || 2 * 60 * 1000 - - const timePerRetry = timeout + retryDelay - if (timePerRetry * retries > this.blockTime * 1000n) { - console.warn( - "The value of (timeout + retryDelay) * retries is greater than the time block. This could slow down the transaction manager.", - ) - } } /** @@ -316,7 +306,6 @@ export class TransactionManager { if (rpcChainId.value !== this.chainId) { const errorMessage = `The chain ID of the RPC node (${rpcChainId.value}) does not match the chain ID of the transaction manager (${this.chainId}).` - console.error(errorMessage) throw new Error(errorMessage) } diff --git a/packages/transaction-manager/lib/TxMonitor.ts b/packages/transaction-manager/lib/TxMonitor.ts index c65b9aadeb..5cc922f457 100644 --- a/packages/transaction-manager/lib/TxMonitor.ts +++ b/packages/transaction-manager/lib/TxMonitor.ts @@ -76,10 +76,12 @@ export class TxMonitor { let isResolved = false const { promise: receiptPromise, resolve, reject: _reject } = promiseWithResolvers() - /* - We request receipts for all attempts in parallel. Since only one attempt can have a receipt due to they have the same nonce, - we can terminate the process as soon as a receipt is obtained. This is why we use a promise race. - */ + /** + * We request receipts for all attempts in parallel. Since only one attempt can have a receipt due to all of them sharing the same nonce, + * we can terminate the process as soon as a receipt is obtained. This is why we use a {@link Promise.race} + * between a promise that resolves on the receipt and all individual promises that resolve when + * the call returns (with {@link TransactionReceiptNotFoundError}). + */ const promises: Promise>[] = inAirAttempts.map( async (attempt): Promise> => { @@ -132,7 +134,7 @@ export class TxMonitor { this.transactionManager, transaction, attempt, - receipt as RevertedTransactionReceipt<"reverted">, + receipt as RevertedTransactionReceipt, ) if (!shouldRetry) { From 95598fd8363e3596d5ccfdad0b519883a176909e Mon Sep 17 00:00:00 2001 From: Gabriel Martinez Rodriguez Date: Tue, 21 Jan 2025 12:29:06 +0100 Subject: [PATCH 6/6] chore(txm): added docstring and microptimization --- packages/transaction-manager/lib/RetryPolicyManager.ts | 4 ++++ packages/transaction-manager/lib/TransactionRepository.ts | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/transaction-manager/lib/RetryPolicyManager.ts b/packages/transaction-manager/lib/RetryPolicyManager.ts index baf4d2bc05..f1a140aaf4 100644 --- a/packages/transaction-manager/lib/RetryPolicyManager.ts +++ b/packages/transaction-manager/lib/RetryPolicyManager.ts @@ -18,6 +18,10 @@ export interface RetryPolicyManager { ): Promise } +/** + * This is the default retry policy manager that will we used if no custom retry policy manager is provided. + * It will only retry if the transaction runs out of gas. + */ export class DefaultRetryPolicyManager implements RetryPolicyManager { public async shouldRetry( transactionManager: TransactionManager, diff --git a/packages/transaction-manager/lib/TransactionRepository.ts b/packages/transaction-manager/lib/TransactionRepository.ts index a47a8a1e5d..6106609f97 100644 --- a/packages/transaction-manager/lib/TransactionRepository.ts +++ b/packages/transaction-manager/lib/TransactionRepository.ts @@ -82,10 +82,10 @@ export class TransactionRepository { ) if (result.isOk()) { - this.notFinalizedTransactions.push(...notPersistedTransactions) this.notFinalizedTransactions = this.notFinalizedTransactions.filter((transaction) => NotFinalizedStatuses.includes(transaction.status), ) + this.notFinalizedTransactions.push(...notPersistedTransactions) transactions.forEach((t) => t.markFlushed()) }