From d17f9d252a377df5df15791da2140dcbb7a2479a Mon Sep 17 00:00:00 2001 From: Fabien Date: Fri, 20 Feb 2026 11:56:49 +0100 Subject: [PATCH] Trigger on confirmed transactions So far only unconfirmed (aka mempool) transactions are parsed. This means that any transaction that is mined before it reaches chronik's mempool will be ignored and the payment missed, which is obviously very bad. The transaction confirmed message is added to the list of managed chronik messages, and the success is checked before processing to avoid triggering the payment success twice. Note that the filter exists in the socket.ts txsListener but this is dead code and is removed in #619. Test Plan: yarn test Check with a widget test, pay for it, check the success and wait for the block to be mined: the payment animation is not replayed. --- .../lib/components/Widget/WidgetContainer.tsx | 22 ++++++++++++++----- react/lib/util/chronik.ts | 3 ++- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/react/lib/components/Widget/WidgetContainer.tsx b/react/lib/components/Widget/WidgetContainer.tsx index 18615cfb..5bd1293c 100644 --- a/react/lib/components/Widget/WidgetContainer.tsx +++ b/react/lib/components/Widget/WidgetContainer.tsx @@ -220,7 +220,16 @@ export const WidgetContainer: React.FunctionComponent = setSuccess(true); onSuccess?.(transaction); } else { - onTransaction?.(transaction); + // FIXME: Since the confirmed transactions are supported this could + // be called twice for the same transaction. In order to maintain + // the same behavior as before the confirmed transactions are + // supported we should only call onTransaction if the transaction is + // not confirmed. The proper fix would be to add a status so the + // callback know why it's called (added to mempool, finalized, + // confirmed, etc.). Fabien 2026-02-20 + if (transaction.confirmed === false) { + onTransaction?.(transaction); + } if (transactionText){ enqueueSnackbar( `${ @@ -275,14 +284,15 @@ export const WidgetContainer: React.FunctionComponent = const handleNewTransaction = useCallback( (tx: Transaction) => { - if ( - tx.confirmed === false && - isGreaterThanZero(resolveNumber(tx.amount)) - ) { + if (success) { + return; + } + + if (isGreaterThanZero(resolveNumber(tx.amount))) { handlePayment(tx); } }, - [handlePayment], + [handlePayment, success], ); const checkForTransactions = useCallback(async (): Promise => { diff --git a/react/lib/util/chronik.ts b/react/lib/util/chronik.ts index 7714d257..38ff42ae 100644 --- a/react/lib/util/chronik.ts +++ b/react/lib/util/chronik.ts @@ -249,7 +249,8 @@ export const parseWebsocketMessage = async ( } const { msgType } = wsMsg; switch (msgType) { - case 'TX_ADDED_TO_MEMPOOL': { + case 'TX_ADDED_TO_MEMPOOL': + case 'TX_CONFIRMED': { const rawTransaction = await chronik.tx(wsMsg.txid); const transaction = await getTransactionFromChronikTransaction(rawTransaction, address ?? '')