From b32e09e44c77628bb3376aaa5decef5aaf5f550c Mon Sep 17 00:00:00 2001 From: orestis Date: Thu, 13 Nov 2025 16:44:30 +0000 Subject: [PATCH 1/2] test: verify transaction received --- .../integration-test/client-request.test.ts | 84 +++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/packages/snap/integration-test/client-request.test.ts b/packages/snap/integration-test/client-request.test.ts index 89111e22e..d7610d56d 100644 --- a/packages/snap/integration-test/client-request.test.ts +++ b/packages/snap/integration-test/client-request.test.ts @@ -439,4 +439,88 @@ describe('OnClientRequestHandler', () => { }); }); }); + + describe('TransactionReceived tracking event behavior', () => { + it('does not emit TransactionReceived for sender when syncing own broadcast, but does emit for receiver', async () => { + // Step 1: Send a transaction (sender scenario) + // This will broadcast a tx and add it to the account + const sendResponse = await snap.onClientRequest({ + method: 'confirmSend', + params: { + fromAccountId: account.id, + toAddress: TEST_ADDRESS_REGTEST, + assetId: Caip19Asset.Regtest, + amount: '0.001', + }, + }); + + expect(sendResponse).toRespondWith( + expect.objectContaining({ + type: 'send', + id: expect.any(String), + }), + ); + + const sentTxId = (sendResponse.response as { result: { id: string } }) + .result.id; + + // Verify TransactionSubmitted was fired for the broadcast + /* eslint-disable @typescript-eslint/naming-convention */ + expect(sendResponse).toTrackEvent({ + event: TrackingSnapEvent.TransactionSubmitted, + properties: { + account_type: BtcAccountType.P2wpkh, + chain_id_caip: BtcScope.Regtest, + message: 'Snap transaction submitted', + origin: expect.any(String), + tx_id: sentTxId, + }, + }); + /* eslint-enable @typescript-eslint/naming-convention */ + + // Step 2: Sync the account (still as sender) + // The transaction is already in the account, so TransactionReceived should NOT fire + const syncResponse = await snap.onCronjob({ + method: 'synchronizeAccounts', + }); + + expect(syncResponse).toRespondWith(null); + + // TransactionReceived should NOT be emitted for our own sent transaction + expect(syncResponse).not.toTrackEvent({ + event: TrackingSnapEvent.TransactionReceived, + properties: expect.objectContaining({ + // eslint-disable-next-line @typescript-eslint/naming-convention + tx_id: sentTxId, + }), + }); + + // Step 3: Receive BTC from external source (receiver scenario) + await blockchain.sendToAddress(account.address, 1); + + // Step 4: Sync again - this time we should get TransactionReceived + const syncWithIncomingResponse = await snap.onCronjob({ + method: 'synchronizeAccounts', + }); + + expect(syncWithIncomingResponse).toRespondWith(null); + + // TransactionReceived SHOULD be emitted for the incoming transaction + /* eslint-disable @typescript-eslint/naming-convention */ + expect(syncWithIncomingResponse).toTrackEvent({ + event: TrackingSnapEvent.TransactionReceived, + properties: { + account_type: BtcAccountType.P2wpkh, + chain_id_caip: BtcScope.Regtest, + message: 'Snap transaction received', + origin: 'cron', + tx_id: expect.any(String), + }, + }); + /* eslint-enable @typescript-eslint/naming-convention */ + + // Verify the received transaction has a different ID than the one we sent + // (TransactionReceived should only fire for incoming transactions, not our own broadcast) + }); + }); }); From 0e2581c158185dafe64111b1ed055bdf3afdb6d5 Mon Sep 17 00:00:00 2001 From: orestis Date: Thu, 13 Nov 2025 17:01:58 +0000 Subject: [PATCH 2/2] test: verify transaction finalized --- .../integration-test/client-request.test.ts | 49 ++++++++++++++++--- 1 file changed, 43 insertions(+), 6 deletions(-) diff --git a/packages/snap/integration-test/client-request.test.ts b/packages/snap/integration-test/client-request.test.ts index d7610d56d..c9104ca86 100644 --- a/packages/snap/integration-test/client-request.test.ts +++ b/packages/snap/integration-test/client-request.test.ts @@ -498,16 +498,17 @@ describe('OnClientRequestHandler', () => { // Step 3: Receive BTC from external source (receiver scenario) await blockchain.sendToAddress(account.address, 1); - // Step 4: Sync again - this time we should get TransactionReceived - const syncWithIncomingResponse = await snap.onCronjob({ + // Step 4: Sync - should get TransactionReceived for the incoming unconfirmed transaction + const syncWithIncomingUnconfirmedResponse = await snap.onCronjob({ method: 'synchronizeAccounts', }); - expect(syncWithIncomingResponse).toRespondWith(null); + expect(syncWithIncomingUnconfirmedResponse).toRespondWith(null); // TransactionReceived SHOULD be emitted for the incoming transaction + // We verify it exists but don't know the exact tx_id since it came from external blockchain /* eslint-disable @typescript-eslint/naming-convention */ - expect(syncWithIncomingResponse).toTrackEvent({ + expect(syncWithIncomingUnconfirmedResponse).toTrackEvent({ event: TrackingSnapEvent.TransactionReceived, properties: { account_type: BtcAccountType.P2wpkh, @@ -519,8 +520,44 @@ describe('OnClientRequestHandler', () => { }); /* eslint-enable @typescript-eslint/naming-convention */ - // Verify the received transaction has a different ID than the one we sent - // (TransactionReceived should only fire for incoming transactions, not our own broadcast) + // Step 5: Mine blocks to confirm both transactions + await blockchain.mineBlocks(6); + + // Step 6: Sync - should emit TransactionFinalized for BOTH transactions + const syncAfterConfirmed = await snap.onCronjob({ + method: 'synchronizeAccounts', + }); + + expect(syncAfterConfirmed).toRespondWith(null); + + // TransactionFinalized SHOULD be emitted for BOTH transactions + // We verify both the sent and received transactions are finalized + /* eslint-disable @typescript-eslint/naming-convention */ + + // Verify the sent transaction is finalized + expect(syncAfterConfirmed).toTrackEvent({ + event: TrackingSnapEvent.TransactionFinalized, + properties: { + account_type: BtcAccountType.P2wpkh, + chain_id_caip: BtcScope.Regtest, + message: 'Snap transaction finalized', + origin: 'cron', + tx_id: sentTxId, + }, + }); + + // Verify the received transaction is also finalized (different tx_id) + expect(syncAfterConfirmed).toTrackEvent({ + event: TrackingSnapEvent.TransactionFinalized, + properties: { + account_type: BtcAccountType.P2wpkh, + chain_id_caip: BtcScope.Regtest, + message: 'Snap transaction finalized', + origin: 'cron', + tx_id: expect.not.stringContaining(sentTxId), + }, + }); + /* eslint-enable @typescript-eslint/naming-convention */ }); }); });