diff --git a/test/integration/app/wallets/update-pending-invoices.spec.ts b/test/integration/app/wallets/update-pending-invoices.spec.ts new file mode 100644 index 0000000000..cdb9cde689 --- /dev/null +++ b/test/integration/app/wallets/update-pending-invoices.spec.ts @@ -0,0 +1,62 @@ +import { randomUUID } from "crypto" + +import { handleHeldInvoices } from "@app/wallets" +import * as UpdatePendingInvoicesImpl from "@app/wallets/update-pending-invoices" + +import { DEFAULT_EXPIRATIONS } from "@domain/bitcoin/lightning/invoice-expiration" +import { WalletCurrency } from "@domain/shared" +import { baseLogger } from "@services/logger" +import { WalletInvoicesRepository } from "@services/mongoose" +import { WalletInvoice } from "@services/mongoose/schema" +import { getSecretAndPaymentHash } from "@domain/bitcoin/lightning" + +afterEach(async () => { + await WalletInvoice.deleteMany({}) +}) + +describe("update pending invoices", () => { + describe("handleHeldInvoices", () => { + it("declines USD invoice with expired 'createdAt'", async () => { + // Setup mocks + const declineHeldInvoiceMock = jest.fn() + const declineHeldInvoiceSpy = jest + .spyOn(UpdatePendingInvoicesImpl, "declineHeldInvoice") + .mockImplementation(declineHeldInvoiceMock) + + // Setup expired USD wallet invoice + const { paymentHash } = getSecretAndPaymentHash() + const expiredUsdWalletInvoice = { + paymentHash, + secret: "secretPreImage" as SecretPreImage, + selfGenerated: true, + pubkey: "pubkey" as Pubkey, + recipientWalletDescriptor: { + id: randomUUID() as WalletId, + currency: WalletCurrency.Usd, + }, + paid: false, + } + const persisted = await WalletInvoicesRepository().persistNew( + expiredUsdWalletInvoice, + ) + if (persisted instanceof Error) throw persisted + + const usdDelayMs = DEFAULT_EXPIRATIONS.USD.delay * 1000 + const pastCreatedAt = new Date(Date.now() - usdDelayMs) + await WalletInvoice.findOneAndUpdate( + { _id: paymentHash }, + { timestamp: pastCreatedAt }, + ) + + // Handle invoices + await handleHeldInvoices(baseLogger) + + // Expect declined invoice + expect(declineHeldInvoiceMock.mock.calls.length).toBe(1) + expect(declineHeldInvoiceMock.mock.calls[0][0].paymentHash).toBe(paymentHash) + + // Restore system state + declineHeldInvoiceSpy.mockRestore() + }) + }) +}) diff --git a/test/legacy-integration/02-user-wallet/02-receive-lightning.spec.ts b/test/legacy-integration/02-user-wallet/02-receive-lightning.spec.ts index 6f7e3f4e52..3d5188a164 100644 --- a/test/legacy-integration/02-user-wallet/02-receive-lightning.spec.ts +++ b/test/legacy-integration/02-user-wallet/02-receive-lightning.spec.ts @@ -14,14 +14,10 @@ import { CouldNotFindWalletInvoiceError } from "@domain/errors" import { WalletInvoicesRepository } from "@services/mongoose" import { LedgerService } from "@services/ledger" import { LndService } from "@services/lnd" -import { KnownLndErrorDetails } from "@services/lnd/errors" import { baseLogger } from "@services/logger" -import { setupInvoiceSubscribe } from "@servers/trigger" import { sleep } from "@utils" -import { parseLndErrorDetails } from "@services/lnd/config" - import { WalletInvoice } from "@services/mongoose/schema" import { @@ -33,17 +29,14 @@ import { getHash, getPubKey, getUsdWalletIdByPhone, - lnd1, lndOutside1, pay, randomPhone, safePay, - subscribeToInvoices, } from "test/helpers" let walletIdB: WalletId let walletIdUsdB: WalletId -let walletIdUsdF: WalletId let initBalanceB: Satoshis let initBalanceUsdB: UsdCents @@ -55,7 +48,6 @@ beforeAll(async () => { await createUserAndWalletFromPhone(phoneF) walletIdB = await getDefaultWalletIdByPhone(phoneB) walletIdUsdB = await getUsdWalletIdByPhone(phoneB) - walletIdUsdF = await getUsdWalletIdByPhone(phoneF) }) beforeEach(async () => { @@ -275,55 +267,3 @@ describe("UserWallet - Lightning", () => { ]) }) }) - -describe("Invoice handling from trigger", () => { - describe("usd recipient invoice", () => { - const cents = toCents(100) - - it("should decline held invoice when trigger comes back up", async () => { - // Create invoice for self - const lnInvoice = await Wallets.addInvoiceForSelfForUsdWallet({ - walletId: walletIdUsdF, - amount: cents, - }) - expect(lnInvoice).not.toBeInstanceOf(Error) - if (lnInvoice instanceof Error) throw lnInvoice - - // fake timestamp in wallet invoice to avoid the use of fake timers - await WalletInvoice.findOneAndUpdate( - { _id: lnInvoice.paymentHash }, - { timestamp: new Date(Date.now() - SECS_PER_10_MINS * 1000) }, - ) - - // Pay invoice promise - const startPay = async () => { - try { - return await pay({ - lnd: lndOutside1, - request: lnInvoice.paymentRequest, - }) - } catch (err) { - return parseLndErrorDetails(err) - } - } - - // Listener promise - const delayedListener = async (subInvoices) => { - await sleep(500) - setupInvoiceSubscribe({ - lnd: lnd1, - pubkey: process.env.LND1_PUBKEY as Pubkey, - subInvoices, - }) - } - - // Pay and then listen - const subInvoices = subscribeToInvoices({ lnd: lnd1 }) - const [result] = await Promise.all([startPay(), delayedListener(subInvoices)]) - - // See successful payment - expect(result).toMatch(KnownLndErrorDetails.PaymentRejectedByDestination) - subInvoices.removeAllListeners() - }) - }) -})