diff --git a/.changeset/twenty-plants-hide.md b/.changeset/twenty-plants-hide.md new file mode 100644 index 000000000..7e34ead2b --- /dev/null +++ b/.changeset/twenty-plants-hide.md @@ -0,0 +1,5 @@ +--- +"@layerzerolabs/devtools": patch +--- + +Return pending (unsubmitted) transactions when signing and sending diff --git a/packages/devtools/src/transactions/signer.ts b/packages/devtools/src/transactions/signer.ts index c1b23b765..da19dd120 100644 --- a/packages/devtools/src/transactions/signer.ts +++ b/packages/devtools/src/transactions/signer.ts @@ -1,7 +1,15 @@ import { createModuleLogger, pluralizeNoun, pluralizeOrdinal } from '@layerzerolabs/io-devtools' -import type { OmniSignerFactory, OmniTransaction, OmniTransactionWithReceipt } from './types' +import type { OmniSignerFactory, OmniTransaction, OmniTransactionWithError, OmniTransactionWithReceipt } from './types' import { formatOmniPoint } from '@/omnigraph/format' -import type { OmniError } from '@/omnigraph/types' + +export type SignAndSendResult = [ + // All the successful transactions + successful: OmniTransactionWithReceipt[], + // The failed transactions along with the errors + errors: OmniTransactionWithError[], + // All the transactions that have not been executed (including the failed ones) + pending: OmniTransaction[], +] /** * Creates a sign & send utility for a list of transaction @@ -14,14 +22,14 @@ export const createSignAndSend = async ( transactions: OmniTransaction[], onProgress?: (result: OmniTransactionWithReceipt, results: OmniTransactionWithReceipt[]) => unknown - ): Promise<[successful: OmniTransactionWithReceipt[], errors: OmniError[]]> => { + ): Promise => { const logger = createModuleLogger('sign & send') // Put it here so that we don't need to type like seven toilet rolls of variable names const n = transactions.length // Just exit when there is nothing to sign - if (n === 0) return logger.debug(`No transactions to sign, exiting`), [[], []] + if (n === 0) return logger.debug(`No transactions to sign, exiting`), [[], [], []] // Tell the user how many we are signing logger.debug(`Signing ${n} ${pluralizeNoun(n, 'transaction')}`) @@ -55,12 +63,12 @@ export const createSignAndSend = } catch (error) { logger.debug(`Failed to process ${ordinal} transaction: ${error}`) - return [successful, [{ point: transaction.point, error }]] + return [successful, [{ transaction, error }], transactions.slice(index)] } } // Tell the inquisitive user what a good job we did logger.debug(`Successfully signed ${n} ${pluralizeNoun(n, 'transaction')}`) - return [successful, []] + return [successful, [], []] } diff --git a/packages/devtools/src/transactions/types.ts b/packages/devtools/src/transactions/types.ts index 48ab129fd..b311ad947 100644 --- a/packages/devtools/src/transactions/types.ts +++ b/packages/devtools/src/transactions/types.ts @@ -19,6 +19,11 @@ export interface OmniTransactionWithReceipt { + transaction: OmniTransaction + error: TError +} + export interface OmniTransactionResponse { transactionHash: string wait: (confirmations?: number) => Promise diff --git a/packages/devtools/test/transactions/signer.test.ts b/packages/devtools/test/transactions/signer.test.ts index 9c49f6750..0229d26cf 100644 --- a/packages/devtools/test/transactions/signer.test.ts +++ b/packages/devtools/test/transactions/signer.test.ts @@ -15,7 +15,7 @@ describe('transactions/signer', () => { const signerFactory: OmniSignerFactory = () => ({ signAndSend, sign }) const signAndSendTransactions = createSignAndSend(signerFactory) - expect(await signAndSendTransactions([])).toEqual([[], []]) + expect(await signAndSendTransactions([])).toEqual([[], [], []]) expect(signAndSend).not.toHaveBeenCalled() expect(sign).not.toHaveBeenCalled() @@ -42,10 +42,11 @@ describe('transactions/signer', () => { const signAndSendTransactions = createSignAndSend(signerFactory) // Now we send all the transactions to the flow and observe the output - const [successful, errors] = await signAndSendTransactions(transactions) + const [successful, errors, pending] = await signAndSendTransactions(transactions) expect(successful).toEqual(transactions.map((transaction) => ({ transaction, receipt }))) expect(errors).toEqual([]) + expect(pending).toEqual([]) // We also check that the signer factory has been called with the eids for (const transaction of transactions) { @@ -100,10 +101,11 @@ describe('transactions/signer', () => { // Now we send all the transactions to the flow and observe the output const transactions = [...firstBatch, failedTransaction, ...secondBatch] - const [successful, errors] = await signAndSendTransactions(transactions) + const [successful, errors, pending] = await signAndSendTransactions(transactions) expect(successful).toEqual(firstBatch.map((transaction) => ({ transaction, receipt }))) - expect(errors).toEqual([{ point: failedTransaction.point, error }]) + expect(errors).toEqual([{ transaction: failedTransaction, error }]) + expect(pending).toEqual([failedTransaction, ...secondBatch]) // We also check that the signer factory has been called with the eids expect(signerFactory).toHaveBeenCalledWith(failedTransaction.point.eid) @@ -151,10 +153,11 @@ describe('transactions/signer', () => { // Now we send all the transactions to the flow and observe the output const transactions = [...firstBatch, failedTransaction, ...secondBatch] - const [successful, errors] = await signAndSendTransactions(transactions) + const [successful, errors, pending] = await signAndSendTransactions(transactions) expect(successful).toEqual(firstBatch.map((transaction) => ({ transaction, receipt }))) - expect(errors).toEqual([{ point: failedTransaction.point, error }]) + expect(errors).toEqual([{ transaction: failedTransaction, error }]) + expect(pending).toEqual([failedTransaction, ...secondBatch]) // We also check that the signer factory has been called with the eids expect(signerFactory).toHaveBeenCalledWith(failedTransaction.point.eid)