diff --git a/core/api/test/integration/services/lnd-service.spec.ts b/core/api/test/integration/services/lnd-service.spec.ts index 95fcf6ad9f..07ddf39181 100644 --- a/core/api/test/integration/services/lnd-service.spec.ts +++ b/core/api/test/integration/services/lnd-service.spec.ts @@ -6,13 +6,15 @@ import { LightningError as LnError, payViaPaymentDetails, payViaRoutes, + subscribeToInvoice, } from "lightning" -import { LND1_PUBKEY } from "@/config" +import { LND1_PUBKEY, MS_PER_SEC } from "@/config" import { WalletCurrency } from "@/domain/shared" import { toSats } from "@/domain/bitcoin" import { + InvoiceNotFoundError, LnAlreadyPaidError, PaymentNotFoundError, PaymentRejectedByDestinationError, @@ -38,6 +40,7 @@ import { openChannelTestingNoAccounting, resetIntegrationLnds, setChannelFees, + waitFor, } from "test/helpers" import { BitcoindWalletClient } from "test/helpers/bitcoind" @@ -373,6 +376,67 @@ describe("Lnd", () => { }) expect(deletedAttempt).not.toBeInstanceOf(Error) }) + + it("cancels invoice", async () => { + // Note: this is a test for gc-canceled-invoices-on-the-fly=true settings + + // Create invoice + const { request } = await createInvoice({ + lnd: lnd1, + tokens: amountInvoice, + }) + const lnInvoice = decodeInvoice(request) + if (lnInvoice instanceof Error) throw lnInvoice + const { paymentHash } = lnInvoice + + // Fetch invoice + const invoiceLookup = await lndService.lookupInvoice({ paymentHash }) + if (invoiceLookup instanceof Error) throw invoiceLookup + expect(invoiceLookup.paymentHash).toEqual(paymentHash) + + // Cancel invoice + const canceled = await lndService.cancelInvoice({ + pubkey: LND1_PUBKEY, + paymentHash, + }) + if (canceled instanceof Error) throw canceled + + // Retry fetching invoice + const invoiceReLookup = await lndService.lookupInvoice({ paymentHash }) + expect(invoiceReLookup).toBeInstanceOf(InvoiceNotFoundError) + }) + + it("handles expired invoices", async () => { + // Create invoice + const expires_at = new Date(Date.now() + MS_PER_SEC).toISOString() + const { request } = await createInvoice({ + lnd: lnd1, + tokens: amountInvoice, + expires_at, + }) + const lnInvoice = decodeInvoice(request) + if (lnInvoice instanceof Error) throw lnInvoice + const { paymentHash } = lnInvoice + + // Fetch invoice + const invoiceLookup = await lndService.lookupInvoice({ paymentHash }) + if (invoiceLookup instanceof Error) throw invoiceLookup + expect(invoiceLookup.paymentHash).toEqual(paymentHash) + + // Listen for expiry + let isCanceled = false + const sub = subscribeToInvoice({ lnd: lnd1, id: paymentHash }) + sub.on("invoice_updated", async (invoice) => { + await sleep(1000) + isCanceled = invoice.is_canceled + }) + await waitFor(async () => isCanceled) + sub.removeAllListeners() + + // Retry fetching invoice + const invoiceReLookup = await lndService.lookupInvoice({ paymentHash }) + expect(invoiceReLookup).toBeInstanceOf(InvoiceNotFoundError) + }) }) describe("'lightning' library error handling", () => { diff --git a/core/api/test/legacy-integration/services/lnd/utils.spec.ts b/core/api/test/legacy-integration/services/lnd/utils.spec.ts index dc01ce71e9..1ad4f23d78 100644 --- a/core/api/test/legacy-integration/services/lnd/utils.spec.ts +++ b/core/api/test/legacy-integration/services/lnd/utils.spec.ts @@ -4,19 +4,16 @@ import { baseLogger } from "@/services/logger" import { ledgerAdmin } from "@/services/mongodb" import { DbMetadata } from "@/services/mongoose/schema" -import { sleep, timestampDaysAgo } from "@/utils" +import { timestampDaysAgo } from "@/utils" import { - cancelHodlInvoice, clearAccountLocks, createInvoice, getForwards, - getInvoiceAttempt, lnd1, lndOutside1, lndOutside2, pay, - subscribeToInvoice, waitFor, } from "test/helpers" @@ -29,57 +26,9 @@ afterEach(() => { }) describe("lndUtils", () => { - // this is a test for gc-canceled-invoices-on-the-fly=true settings - it("test cancelling invoice effect", async () => { - const lnd = lndOutside2 - - const { id } = await createInvoice({ lnd, tokens: 10000 }) - - { - const invoice = await getInvoiceAttempt({ lnd, id }) - expect(invoice).toBeTruthy() - } - - await cancelHodlInvoice({ lnd, id }) - - { - const invoice = await getInvoiceAttempt({ lnd, id }) - expect(invoice).toBeNull() - } + it("placeholder", () => { + expect(true).toBeTruthy() }) - - it("test expiring invoice effect", async () => { - const lnd = lndOutside2 - - // expire in 1 second - const expires_at = new Date(Date.now() + 1000).toISOString() - - const { id } = await createInvoice({ lnd, tokens: 10000, expires_at }) - - { - const invoice = await getInvoiceAttempt({ lnd, id }) - expect(invoice).toBeTruthy() - } - - let isCanceled = false - const sub = subscribeToInvoice({ lnd, id }) - sub.on("invoice_updated", async (invoice) => { - await sleep(1000) - isCanceled = invoice.is_canceled - }) - - /* eslint @typescript-eslint/ban-ts-comment: "off" */ - // @ts-ignore-next-line no-implicit-any error - await waitFor(() => isCanceled) - - sub.removeAllListeners() - - { - const invoice = await getInvoiceAttempt({ lnd, id }) - expect(invoice).toBeNull() - } - }) - it.skip("sets routing fee correctly", async () => { // Skipped because this test is already broken. lndOutside1 and lndOutside2 // are directly connected and routing fees are 0.