import { describe, it, expect } from 'vitest'; import { assertInvoiceAmount } from './verifyInvoice'; describe('assertInvoiceAmount', () => { it('accepts an invoice whose amount matches the expected sats', () => { // lnbc210n… = 210 * 1e-9 BTC = 21 sats expect(() => assertInvoiceAmount('lnbc210n1pvjluez', 21)).not.toThrow(); }); it('accepts a 1-sat rounding difference (millisat↔sat slack)', () => { // lnbc210n… = 21 sats, expected 22 → diff of 1 is allowed expect(() => assertInvoiceAmount('lnbc210n1pvjluez', 22)).not.toThrow(); }); it('rejects an over-charging invoice (the core attack it defends against)', () => { // Invoice requests 250,000 sats but the user intended 21. expect(() => assertInvoiceAmount('lnbc2500u1pvjluez', 21)).toThrow(/mismatch/i); }); it('rejects an amountless invoice when a concrete amount was expected', () => { expect(() => assertInvoiceAmount('lnbc1pvjluez', 21)).toThrow(/no fixed amount/i); }); it('rejects a malformed / unparseable invoice', () => { expect(() => assertInvoiceAmount('not-an-invoice', 21)).toThrow(/could not verify/i); }); it('rejects empty / non-string input', () => { expect(() => assertInvoiceAmount('', 21)).toThrow(/invalid invoice/i); // @ts-expect-error deliberately passing a non-string expect(() => assertInvoiceAmount(null, 21)).toThrow(/invalid invoice/i); }); it('allows an amountless invoice when nothing specific was expected', () => { expect(() => assertInvoiceAmount('lnbc1pvjluez', 0)).not.toThrow(); }); });