mirror of
https://github.com/tompro/sattle.git
synced 2026-10-26 01:49:58 +00:00
107 lines
4.0 KiB
TypeScript
107 lines
4.0 KiB
TypeScript
import {describe, expect, it} from 'vitest'
|
|
import {hashK1, noteK1} from 'lnurlcash-kit'
|
|
|
|
import {claimMintedNote, OutputSecretAllocationRequiredError, prepareMint} from './ops'
|
|
import {requiredValue} from './test-utils'
|
|
import type {Mint} from './ops.testHarness'
|
|
import {allocateOutputSecrets, mint, persistOutput, secret, settleLastInvoice} from './ops.testHarness'
|
|
|
|
const HEX32 = /^[0-9a-f]{64}$/
|
|
|
|
const boundInvoice = (instance: Mint) =>
|
|
[...instance.state.invoices.values()].find((invoice) => invoice.boundTo)
|
|
|
|
describe('mint -> claim, comment-bound output', () => {
|
|
it('names the quote with the hash of a wallet-chosen secret', async () => {
|
|
const instance = await mint({testHooks: true})
|
|
const prepared = await prepareMint(`mint@127.0.0.1:${instance.port}`, 21_000, {
|
|
persistOutput,
|
|
allocateOutputSecrets,
|
|
})
|
|
expect(prepared.noteSecret).toMatch(HEX32)
|
|
expect(boundInvoice(instance)?.boundTo).toBe(hashK1(prepared.noteSecret))
|
|
})
|
|
|
|
it('claims the output at the wallet secret without rotating it', async () => {
|
|
const instance = await mint({testHooks: true})
|
|
const prepared = await prepareMint(`mint@127.0.0.1:${instance.port}`, 21_000, {
|
|
persistOutput,
|
|
allocateOutputSecrets,
|
|
})
|
|
const preimage = await settleLastInvoice(instance)
|
|
const claimed = await claimMintedNote(prepared, {
|
|
intervalMs: 10,
|
|
intervalCapMs: 50,
|
|
maxWaitMs: 5_000,
|
|
})
|
|
expect(claimed.note.verified).toBe(true)
|
|
expect(claimed.note.amount).toBe(21_000)
|
|
expect(claimed.note.callback).toBe(`${instance.url}/w/cb`)
|
|
expect(noteK1(claimed.note.url)).toBe(prepared.noteSecret)
|
|
expect(instance.state.noteState(prepared.noteSecret)).toBe('outstanding')
|
|
expect(instance.state.noteState(preimage)).toBeNull()
|
|
})
|
|
|
|
it('times out cleanly when the invoice is never paid', async () => {
|
|
const instance = await mint({testHooks: true})
|
|
const prepared = await prepareMint(`mint@127.0.0.1:${instance.port}`, 21_000, {
|
|
persistOutput,
|
|
allocateOutputSecrets,
|
|
})
|
|
await expect(
|
|
claimMintedNote(prepared, {intervalMs: 10, intervalCapMs: 20, maxWaitMs: 100}),
|
|
).rejects.toThrow(/not confirmed/i)
|
|
})
|
|
|
|
it('uses the required comment even when the optional h extension is advertised', async () => {
|
|
const instance = await mint({mintToHash: true, testHooks: true})
|
|
const prepared = await prepareMint(`mint@127.0.0.1:${instance.port}`, 21_000, {
|
|
persistOutput,
|
|
allocateOutputSecrets,
|
|
})
|
|
expect(boundInvoice(instance)?.boundTo).toBe(hashK1(prepared.noteSecret))
|
|
await settleLastInvoice(instance)
|
|
const claimed = await claimMintedNote(prepared, {
|
|
intervalMs: 10,
|
|
intervalCapMs: 50,
|
|
maxWaitMs: 5_000,
|
|
})
|
|
expect(noteK1(claimed.note.url)).toBe(prepared.noteSecret)
|
|
expect(requiredValue(noteK1(claimed.note.url))).toMatch(HEX32)
|
|
})
|
|
|
|
it('draws the staged note secret from the caller allocation path', async () => {
|
|
const instance = await mint({testHooks: true})
|
|
const allocations: Array<{server: string; count: number}> = []
|
|
const allocated = [secret('90')]
|
|
|
|
const prepared = await prepareMint(`mint@127.0.0.1:${instance.port}`, 21_000, {
|
|
persistOutput,
|
|
allocateOutputSecrets: (server, count) => {
|
|
allocations.push({server, count})
|
|
return Promise.resolve(allocated.slice(0, count))
|
|
},
|
|
})
|
|
|
|
expect(allocations).toEqual([{server: `127.0.0.1:${instance.port}`, count: 1}])
|
|
expect(prepared.noteSecret).toBe(allocated[0])
|
|
expect(boundInvoice(instance)?.boundTo).toBe(hashK1(requiredValue(allocated[0])))
|
|
})
|
|
|
|
it('refuses to prepare without an allocation path - nothing staged, no invoice', async () => {
|
|
const instance = await mint({testHooks: true})
|
|
let persisted = 0
|
|
|
|
await expect(
|
|
prepareMint(`mint@127.0.0.1:${instance.port}`, 21_000, {
|
|
persistOutput: () => {
|
|
persisted += 1
|
|
},
|
|
}),
|
|
).rejects.toBeInstanceOf(OutputSecretAllocationRequiredError)
|
|
|
|
expect(persisted).toBe(0)
|
|
expect(instance.state.invoices.size).toBe(0)
|
|
})
|
|
})
|