import { describe, expect, it } from 'vitest'; import { HDKey } from '@scure/bip32'; import { buildInvoiceOption } from '../src/option'; const seed = new Uint8Array(64).fill(9); const xpub = HDKey.fromMasterSeed(seed).derive("m/44'/60'/0'").publicExtendedKey; describe('buildInvoiceOption', () => { it('xpub mode: derives a fresh address at the wallet next index, exact pegged amount, no dust', () => { const built = buildInvoiceOption({ chain: 'base', fiatAmount: '100', rateUnits: 1_000000n, wallet: { kind: 'xpub', xpub, nextIndex: 4 }, }); expect(built.asset).toBe('USDC'); expect(built.cryptoAmount).toBe(100_000000n); expect(built.derivationIndex).toBe(4); expect(built.dustApplied).toBe(false); expect(built.address).toMatch(/^0x/); }); it('static mode: keeps the merchant address and applies a unique cent-dust suffix', () => { const built = buildInvoiceOption({ chain: 'tron', fiatAmount: '100', rateUnits: 1_000000n, wallet: { kind: 'static', staticAddress: 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t', nextIndex: 0 }, }); expect(built.asset).toBe('USDT'); expect(built.address).toBe('TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t'); expect(built.derivationIndex).toBeNull(); expect(built.dustApplied).toBe(true); expect(built.cryptoAmount).toBeGreaterThan(100_000000n); expect(built.cryptoAmount).toBeLessThanOrEqual(100_099900n); }); it('lazily creating per selection means differing rates peg per option (each call pegs its own)', () => { const early = buildInvoiceOption({ chain: 'base', fiatAmount: '100', rateUnits: 1_000000n, wallet: { kind: 'xpub', xpub, nextIndex: 0 }, }); const later = buildInvoiceOption({ chain: 'base', fiatAmount: '100', rateUnits: 999700n, wallet: { kind: 'xpub', xpub, nextIndex: 1 }, }); expect(early.cryptoAmount).toBe(100_000000n); expect(later.cryptoAmount).toBe(100_030010n); }); it('rejects misconfigured wallets', () => { expect(() => buildInvoiceOption({ chain: 'base', fiatAmount: '1', rateUnits: 1_000000n, wallet: { kind: 'xpub', nextIndex: 0 } }), ).toThrow(/missing/); expect(() => buildInvoiceOption({ chain: 'tron', fiatAmount: '1', rateUnits: 1_000000n, wallet: { kind: 'static', nextIndex: 0 } }), ).toThrow(/missing/); }); });