diff --git a/__tests__/account.test.ts b/__tests__/account.test.ts index 74a923cdc..c67ae8c58 100644 --- a/__tests__/account.test.ts +++ b/__tests__/account.test.ts @@ -4,7 +4,6 @@ import { Contract, DeclareDeployUDCResponse, Provider, - TransactionStatus, TransactionType, cairo, contractClassResponseToLegacyCompiledContract, @@ -338,9 +337,7 @@ describe('deploy and test Wallet', () => { calldata: [erc20.address, '10', '0'], }); - await provider.waitForTransaction(transaction_hash, { - successStates: [TransactionStatus.ACCEPTED_ON_L2], - }); + await provider.waitForTransaction(transaction_hash); }); test('read balance of wallet after transfer', async () => { @@ -379,9 +376,7 @@ describe('deploy and test Wallet', () => { }, ]); - await provider.waitForTransaction(transaction_hash, { - successStates: [TransactionStatus.ACCEPTED_ON_L2], - }); + await provider.waitForTransaction(transaction_hash); const response = await dapp.get_number(account.address); expect(toBigInt(response.number as string).toString()).toStrictEqual('57'); diff --git a/src/provider/rpc.ts b/src/provider/rpc.ts index 263756ebc..a7195fec3 100644 --- a/src/provider/rpc.ts +++ b/src/provider/rpc.ts @@ -434,13 +434,15 @@ export class RpcProvider implements ProviderInterface { } public async waitForTransaction(txHash: string, options?: waitForTransactionOptions) { - const errorStates = [TransactionStatus.REJECTED, TransactionStatus.NOT_RECEIVED]; let { retries } = this; let onchain = false; let txReceipt: any = {}; - - const retryInterval = options?.retryInterval ?? 8000; - const successStates = options?.successStates ?? [ + const retryInterval = options?.retryInterval ?? 5000; + const errorStates: any = options?.errorStates ?? [ + TransactionStatus.REJECTED, + TransactionStatus.NOT_RECEIVED, + ]; + const successStates: any = options?.successStates ?? [ TransactionStatus.ACCEPTED_ON_L1, TransactionStatus.ACCEPTED_ON_L2, ]; @@ -451,9 +453,8 @@ export class RpcProvider implements ProviderInterface { try { // eslint-disable-next-line no-await-in-loop txReceipt = await this.getTransactionReceipt(txHash); - if (!('status' in txReceipt)) { - const error = new Error('transaction status'); + const error = new Error('waiting for transaction status'); throw error; } diff --git a/src/provider/sequencer.ts b/src/provider/sequencer.ts index 2a3a140ea..77d94d338 100644 --- a/src/provider/sequencer.ts +++ b/src/provider/sequencer.ts @@ -31,7 +31,8 @@ import { SequencerProviderOptions, SimulateTransactionResponse, StateUpdateResponse, - TransactionStatus, + TransactionExecutionStatus, + TransactionFinalityStatus, TransactionType, getEstimateFeeBulkOptions, getSimulateTransactionOptions, @@ -489,27 +490,46 @@ export class SequencerProvider implements ProviderInterface { } public async waitForTransaction(txHash: BigNumberish, options?: waitForTransactionOptions) { - const errorStates = [TransactionStatus.REJECTED, TransactionStatus.NOT_RECEIVED]; - let onchain = false; let res; - const retryInterval = options?.retryInterval ?? 8000; + let completed = false; + let retries = 0; + const retryInterval = options?.retryInterval ?? 5000; + const errorStates = options?.errorStates ?? [ + TransactionExecutionStatus.REJECTED, + TransactionFinalityStatus.NOT_RECEIVED, + TransactionExecutionStatus.REVERTED, + ]; const successStates = options?.successStates ?? [ - TransactionStatus.ACCEPTED_ON_L1, - TransactionStatus.ACCEPTED_ON_L2, + TransactionExecutionStatus.SUCCEEDED, + TransactionFinalityStatus.ACCEPTED_ON_L1, + TransactionFinalityStatus.ACCEPTED_ON_L2, ]; - while (!onchain) { + while (!completed) { // eslint-disable-next-line no-await-in-loop await wait(retryInterval); // eslint-disable-next-line no-await-in-loop res = await this.getTransactionStatus(txHash); - if (successStates.includes(res.tx_status)) { - onchain = true; - } else if (errorStates.includes(res.tx_status)) { - const message = res.tx_failure_reason - ? `${res.tx_status}: ${res.tx_failure_reason.code}\n${res.tx_failure_reason.error_message}` - : res.tx_status; + if (TransactionFinalityStatus.NOT_RECEIVED === res.finality_status && retries < 3) { + retries += 1; + } else if ( + successStates.includes(res.finality_status) || + successStates.includes(res.execution_status) + ) { + completed = true; + } else if ( + errorStates.includes(res.finality_status) || + errorStates.includes(res.execution_status) + ) { + let message; + if (res.tx_failure_reason) { + message = `${res.tx_status}: ${res.tx_failure_reason.code}\n${res.tx_failure_reason.error_message}`; + } else if (res.tx_revert_reason) { + message = `${res.tx_status}: ${res.tx_revert_reason}`; + } else { + message = res.tx_status; + } const error = new Error(message) as Error & { response: GetTransactionStatusResponse }; error.response = res; throw error; diff --git a/src/types/api/sequencer.ts b/src/types/api/sequencer.ts index bb446bd96..10b35bbe0 100644 --- a/src/types/api/sequencer.ts +++ b/src/types/api/sequencer.ts @@ -11,6 +11,8 @@ import { ContractClass, EntryPointType, RawCalldata, + TransactionExecutionStatus, + TransactionFinalityStatus, TransactionStatus, TransactionType, } from '../lib'; @@ -18,11 +20,14 @@ import { // #region | originally not included in the namespace export type GetTransactionStatusResponse = { tx_status: TransactionStatus; + execution_status: TransactionExecutionStatus; + finality_status: TransactionFinalityStatus; block_hash?: string; tx_failure_reason?: { code: string; error_message: string; }; + tx_revert_reason?: string; }; export type GetContractAddressesResponse = { diff --git a/src/types/lib/index.ts b/src/types/lib/index.ts index 930affd46..8588b77b3 100644 --- a/src/types/lib/index.ts +++ b/src/types/lib/index.ts @@ -133,12 +133,30 @@ export enum TransactionType { INVOKE = 'INVOKE_FUNCTION', } +/** + * new statuses are defined by props: finality_status and execution_status + * to be #deprecated + */ export enum TransactionStatus { NOT_RECEIVED = 'NOT_RECEIVED', RECEIVED = 'RECEIVED', ACCEPTED_ON_L2 = 'ACCEPTED_ON_L2', ACCEPTED_ON_L1 = 'ACCEPTED_ON_L1', REJECTED = 'REJECTED', + REVERTED = 'REVERTED', +} + +export enum TransactionFinalityStatus { + NOT_RECEIVED = 'NOT_RECEIVED', + RECEIVED = 'RECEIVED', + ACCEPTED_ON_L2 = 'ACCEPTED_ON_L2', + ACCEPTED_ON_L1 = 'ACCEPTED_ON_L1', +} + +export enum TransactionExecutionStatus { + REJECTED = 'REJECTED', + REVERTED = 'REVERTED', + SUCCEEDED = 'SUCCEEDED', } export enum BlockStatus { @@ -200,7 +218,8 @@ export type ParsedStruct = { export type waitForTransactionOptions = { retryInterval?: number; - successStates?: Array; + successStates?: Array; + errorStates?: Array; }; export type getSimulateTransactionOptions = {