Skip to content

Commit 842e0f3

Browse files
authored
fix: close subscription after Preconfirmation status when applicable (#3887)
1 parent 388ad98 commit 842e0f3

File tree

3 files changed

+151
-0
lines changed

3 files changed

+151
-0
lines changed

.changeset/rare-kids-grab.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@fuel-ts/account": patch
3+
---
4+
5+
fix: close subscription after `Preconfirmation` status when applicable

packages/account/src/providers/provider.test.ts

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import { mockIncompatibleVersions } from '../../test/utils/mockIncompabileVersio
2525
import { setupTestProviderAndWallets, launchNode, TestMessage, TestAssetId } from '../test-utils';
2626

2727
import type { GqlPageInfo } from './__generated__/operations';
28+
import { FuelGraphqlSubscriber } from './fuel-graphql-subscriber';
2829
import type { Block, ChainInfo, CursorPaginationArgs, NodeInfo } from './provider';
2930
import Provider, {
3031
BALANCES_PAGE_SIZE_LIMIT,
@@ -2648,4 +2649,143 @@ describe('Provider', () => {
26482649

26492650
vi.restoreAllMocks();
26502651
});
2652+
2653+
describe('Waiting for transaction statuses', () => {
2654+
const PreconfirmationSuccessStatus = 'PreconfirmationSuccessStatus';
2655+
const SuccessStatus = 'SuccessStatus';
2656+
2657+
it('should wait only for Preconfirmation status and close subscription', async () => {
2658+
using launched = await setupTestProviderAndWallets({
2659+
nodeOptions: {
2660+
args: ['--poa-instant', 'false', '--poa-interval-period', '1s'],
2661+
},
2662+
});
2663+
const {
2664+
wallets: [wallet],
2665+
} = launched;
2666+
2667+
const readEventSpy = vi.spyOn(FuelGraphqlSubscriber, 'readEvent');
2668+
2669+
const res = await wallet.transfer(wallet.address, 100_000);
2670+
await res.waitForPreConfirmation();
2671+
2672+
expect(readEventSpy.mock.results.length).toBeGreaterThan(0);
2673+
2674+
let readSuccessStatus = false;
2675+
let readPreconfirmationStatus = false;
2676+
2677+
// Loop through all the read events and ensure SuccessStatus was never read
2678+
for (let i = 0; i < readEventSpy.mock.results.length; i += 1) {
2679+
const {
2680+
event: {
2681+
data: { submitAndAwaitStatus },
2682+
},
2683+
} = await readEventSpy.mock.results[i].value;
2684+
if (submitAndAwaitStatus.type === SuccessStatus) {
2685+
readSuccessStatus = true;
2686+
}
2687+
2688+
if (submitAndAwaitStatus.type === PreconfirmationSuccessStatus) {
2689+
readPreconfirmationStatus = true;
2690+
}
2691+
2692+
expect(submitAndAwaitStatus.type).not.toBe(SuccessStatus);
2693+
}
2694+
2695+
expect(readSuccessStatus).toBeFalsy();
2696+
expect(readPreconfirmationStatus).toBeTruthy();
2697+
});
2698+
2699+
it('should wait for both preconfirmation and confirmation statuses', async () => {
2700+
using launched = await setupTestProviderAndWallets({
2701+
nodeOptions: {
2702+
args: ['--poa-instant', 'false', '--poa-interval-period', '1s'],
2703+
},
2704+
});
2705+
const {
2706+
wallets: [wallet],
2707+
} = launched;
2708+
2709+
const readEventSpy = vi.spyOn(FuelGraphqlSubscriber, 'readEvent');
2710+
2711+
const { waitForResult, waitForPreConfirmation } = await wallet.transfer(
2712+
wallet.address,
2713+
100_000
2714+
);
2715+
2716+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
2717+
waitForResult();
2718+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
2719+
waitForPreConfirmation();
2720+
2721+
await sleep(2500);
2722+
2723+
expect(readEventSpy.mock.results.length).toBeGreaterThan(0);
2724+
2725+
let readSuccessStatus = false;
2726+
let readPreconfirmationStatus = false;
2727+
2728+
// Loop through all the read events and ensure SuccessStatus was never read
2729+
for (let i = 0; i < readEventSpy.mock.results.length; i += 1) {
2730+
const {
2731+
event: {
2732+
data: { submitAndAwaitStatus },
2733+
},
2734+
} = await readEventSpy.mock.results[i].value;
2735+
2736+
if (submitAndAwaitStatus.type === PreconfirmationSuccessStatus) {
2737+
readPreconfirmationStatus = true;
2738+
}
2739+
2740+
if (submitAndAwaitStatus.type === SuccessStatus) {
2741+
readSuccessStatus = true;
2742+
}
2743+
}
2744+
2745+
expect(readPreconfirmationStatus).toBeTruthy();
2746+
expect(readSuccessStatus).toBeTruthy();
2747+
});
2748+
2749+
it('should wait for confirmation statuses', async () => {
2750+
using launched = await setupTestProviderAndWallets({
2751+
nodeOptions: {
2752+
args: ['--poa-instant', 'false', '--poa-interval-period', '1s'],
2753+
},
2754+
});
2755+
const {
2756+
wallets: [wallet],
2757+
} = launched;
2758+
2759+
const readEventSpy = vi.spyOn(FuelGraphqlSubscriber, 'readEvent');
2760+
2761+
const { waitForResult } = await wallet.transfer(wallet.address, 100_000);
2762+
2763+
await waitForResult();
2764+
2765+
expect(readEventSpy.mock.results.length).toBeGreaterThan(0);
2766+
2767+
let readSuccessStatus = false;
2768+
let readPreconfirmationStatus = false;
2769+
2770+
// Loop through all the read events and ensure SuccessStatus was never read
2771+
for (let i = 0; i < readEventSpy.mock.results.length; i += 1) {
2772+
const {
2773+
event: {
2774+
data: { submitAndAwaitStatus },
2775+
},
2776+
} = await readEventSpy.mock.results[i].value;
2777+
2778+
if (submitAndAwaitStatus.type === PreconfirmationSuccessStatus) {
2779+
readPreconfirmationStatus = true;
2780+
}
2781+
2782+
if (submitAndAwaitStatus.type === SuccessStatus) {
2783+
readSuccessStatus = true;
2784+
}
2785+
}
2786+
2787+
expect(readPreconfirmationStatus).toBeTruthy();
2788+
expect(readSuccessStatus).toBeTruthy();
2789+
});
2790+
});
26512791
});

packages/account/src/providers/transaction-response/transaction-response.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,12 @@ export class TransactionResponse {
420420
) {
421421
this.preConfirmationStatus = statusChange;
422422
this.resolveStatus('preConfirmation');
423+
// We should end the subscription here if we are not waiting for the confirmation status
424+
const pendingConfirmationResolvers = this.statusResolvers.get('confirmation');
425+
if (!pendingConfirmationResolvers) {
426+
this.waitingForStreamData = false;
427+
break;
428+
}
423429
}
424430

425431
if (statusChange.type === 'SuccessStatus' || statusChange.type === 'FailureStatus') {

0 commit comments

Comments
 (0)