diff --git a/lib/lightning/PendingPaymentTracker.ts b/lib/lightning/PendingPaymentTracker.ts index bf37b321..fb6bc054 100644 --- a/lib/lightning/PendingPaymentTracker.ts +++ b/lib/lightning/PendingPaymentTracker.ts @@ -230,11 +230,7 @@ class PendingPaymentTracker { this.lightningTrackers[lightningClient.type].isPermanentError(e); // CLN xpay does throw errors while the payment is still pending - if ( - lightningClient.type === NodeType.CLN && - !isPermanentError && - ClnPendingPaymentTracker.shouldBeWatched(e) - ) { + if (lightningClient.type === NodeType.CLN && !isPermanentError) { this.lightningTrackers[lightningClient.type].watchPayment( lightningClient, swap.invoice!, diff --git a/lib/lightning/cln/ClnClient.ts b/lib/lightning/cln/ClnClient.ts index 0c7a4e45..f568ed35 100644 --- a/lib/lightning/cln/ClnClient.ts +++ b/lib/lightning/cln/ClnClient.ts @@ -658,18 +658,14 @@ class ClnClient public checkPayStatus = async ( invoice: string, ): Promise => { - const decoded = await this.decodeInvoice(invoice); - - const listPayReq = new noderpc.ListpaysRequest(); - listPayReq.setBolt11(invoice); - - const pays = ( - await this.unaryNodeCall< - noderpc.ListpaysRequest, - noderpc.ListpaysResponse - >('listPays', listPayReq, false) - ).getPaysList(); + const { decoded, pays } = await this.listPays(invoice); + return this.checkListPaysStatus(decoded, pays); + }; + public checkListPaysStatus = async ( + decoded: Awaited>, + pays: noderpc.ListpaysPays[], + ): Promise => { // Check if the payment succeeded, ... const completedAttempts = pays.filter( (attempt) => attempt.getStatus() === ListpaysPaysStatus.COMPLETE, @@ -728,6 +724,25 @@ class ClnClient return undefined; }; + public listPays = async (invoice: string) => { + const decoded = await this.decodeInvoice(invoice); + + const listPayReq = new noderpc.ListpaysRequest(); + listPayReq.setBolt11(invoice); + + const pays = ( + await this.unaryNodeCall< + noderpc.ListpaysRequest, + noderpc.ListpaysResponse + >('listPays', listPayReq, false) + ).getPaysList(); + + return { + pays, + decoded, + }; + }; + public subscribeTrackHoldInvoices = () => { if (this.trackAllSubscription) { this.trackAllSubscription.cancel(); diff --git a/lib/lightning/paymentTrackers/ClnPendingPaymentTracker.ts b/lib/lightning/paymentTrackers/ClnPendingPaymentTracker.ts index 6a7b66e7..d20938ac 100644 --- a/lib/lightning/paymentTrackers/ClnPendingPaymentTracker.ts +++ b/lib/lightning/paymentTrackers/ClnPendingPaymentTracker.ts @@ -29,15 +29,6 @@ class ClnPendingPaymentTracker extends NodePendingPendingTracker { ); } - public static shouldBeWatched = (error: unknown) => { - const msg = formatError(error); - return ( - (msg.includes('Failed after') && msg.includes('attempts')) || - msg.includes('xpay') || - msg === 'Connection dropped' - ); - }; - public stop = () => { clearInterval(this.checkInterval as unknown as number); }; @@ -52,10 +43,7 @@ class ClnPendingPaymentTracker extends NodePendingPendingTracker { .then((result) => this.handleSucceededPayment(preimageHash, result)) .catch((error) => { // CLN xpay throws errors while the payment is still pending - if ( - !this.isPermanentError(error) && - ClnPendingPaymentTracker.shouldBeWatched(error) - ) { + if (!this.isPermanentError(error)) { this.watchPayment(client, invoice, preimageHash); } else { this.handleFailedPayment(client, preimageHash, error); @@ -93,12 +81,21 @@ class ClnPendingPaymentTracker extends NodePendingPendingTracker { { client, invoice }, ] of this.paymentsToWatch.entries()) { try { - const res = await client.checkPayStatus(invoice); - if (res === undefined) { - continue; - } + const { decoded, pays } = await client.listPays(invoice); + const res = await client.checkListPaysStatus(decoded, pays); + if (pays.length === 0) { + this.handleFailedPayment( + client, + preimageHash, + 'no attempts have been made', + ); + } else { + if (res === undefined) { + continue; + } - await this.handleSucceededPayment(preimageHash, res); + await this.handleSucceededPayment(preimageHash, res); + } } catch (e) { // Ignore when the payment is pending; it's not a payment error if (e === ClnClient.paymentPendingError) { diff --git a/test/integration/lightning/paymentTrackers/ClnPendingPaymentTracker.spec.ts b/test/integration/lightning/paymentTrackers/ClnPendingPaymentTracker.spec.ts index fed4471f..464d9ee7 100644 --- a/test/integration/lightning/paymentTrackers/ClnPendingPaymentTracker.spec.ts +++ b/test/integration/lightning/paymentTrackers/ClnPendingPaymentTracker.spec.ts @@ -92,6 +92,8 @@ describe('ClnPendingPaymentTracker', () => { tracker.trackPayment(clnClient, preimageHash, invoice, promise); await expect(promise).rejects.toEqual(expect.anything()); + await tracker['checkPendingPayments'](); + expect(LightningPaymentRepository.setStatus).toHaveBeenCalledTimes(1); expect(LightningPaymentRepository.setStatus).toHaveBeenCalledWith( preimageHash, @@ -99,6 +101,8 @@ describe('ClnPendingPaymentTracker', () => { LightningPaymentStatus.TemporaryFailure, undefined, ); + + expect(tracker['paymentsToWatch'].size).toEqual(0); }); });