402-mcp 4.1.2 → 4.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,91 @@
1
+ import type { LnurlcashNoteStore, StoredNote, SettledMelt } from '../store/lnurlcash-notes.js';
2
+ /** What a reconcile pass turned up that a caller may want to act on. */
3
+ export interface ReconcileReport {
4
+ /**
5
+ * Melts that had already settled by the time we asked again, with the
6
+ * preimage recovered. Empty on a quiet pass. Each one is also written to
7
+ * the store, so nothing depends on the caller reading this.
8
+ */
9
+ recovered: SettledMelt[];
10
+ }
11
+ /**
12
+ * Note operations shared by the wallet provider (which melts a note to pay a
13
+ * BOLT-11 invoice) and the lnurlcash HTTP rail (which hands a note straight to
14
+ * a paywall). Both need the same crash-safe split and the same reconciliation,
15
+ * and two copies of that would drift.
16
+ */
17
+ /** LUD-03/LUD-25 responses are either a success object or `{status:'ERROR'}`. */
18
+ export interface LnurlError {
19
+ status: 'ERROR';
20
+ reason?: string;
21
+ }
22
+ export interface WithdrawRequest {
23
+ status?: string;
24
+ tag?: string;
25
+ callback?: string;
26
+ k1?: string;
27
+ minWithdrawable?: number;
28
+ maxWithdrawable?: number;
29
+ }
30
+ export interface CallbackOk {
31
+ status?: string;
32
+ verify?: string;
33
+ pr?: string;
34
+ reason?: string;
35
+ }
36
+ export declare function isError(res: unknown): res is LnurlError;
37
+ /**
38
+ * Mint responses are the only thing safe to surface. Anything thrown by the
39
+ * HTTP layer may carry a URL, and our URLs carry note secrets in the query
40
+ * string, so exceptions are never stringified outward.
41
+ */
42
+ export declare class MintRefused extends Error {
43
+ }
44
+ /**
45
+ * The mint doesn't recognise a note we thought we held. Expected, not
46
+ * exceptional: a bearer note can be spent by anyone holding a copy, so every
47
+ * local balance is a cache and the mint is the only authority. Signals "drop
48
+ * this one and try the next", never "fail the payment".
49
+ */
50
+ export declare class NoteGone extends Error {
51
+ }
52
+ export interface NoteOpsOptions {
53
+ /** Per-request HTTP timeout. */
54
+ httpTimeoutMs?: number;
55
+ fetchImpl?: typeof fetch;
56
+ /** SSRF guard, matching farrier-kit's verifyLud21 hook. */
57
+ urlGuard?: (url: URL) => void | Promise<void>;
58
+ }
59
+ export interface ResolvedNote {
60
+ amountMsat: number;
61
+ callback: string;
62
+ }
63
+ /**
64
+ * `refused` is the mint saying it does not honour this note: unknown, already
65
+ * spent, or pending another operation. `unreachable` is the mint saying
66
+ * nothing at all. The difference matters because a note is only safe to drop
67
+ * on the first: a bearer note is money, and a flaky network must never destroy
68
+ * it.
69
+ */
70
+ export type NoteProbe = {
71
+ ok: true;
72
+ note: ResolvedNote;
73
+ } | {
74
+ ok: false;
75
+ reason: 'refused' | 'unreachable';
76
+ };
77
+ export interface NoteOps {
78
+ probeNote(mint: string, secret: string): Promise<NoteProbe>;
79
+ resolveNote(mint: string, secret: string): Promise<ResolvedNote | null>;
80
+ reconcile(): Promise<ReconcileReport>;
81
+ split(parent: StoredNote, amountMsat: number): Promise<StoredNote>;
82
+ }
83
+ /** Appends params to a callback URL that may already carry some. */
84
+ export declare function callbackUrl(base: string, params: Record<string, string>): string;
85
+ /**
86
+ * The note as a LUD-25 withdraw URL: the secret as `k1`, its value alongside.
87
+ * This is the form a wallet shows and the form a paywall is handed. The
88
+ * `amount` is only a claim; the mint's `maxWithdrawable` is authoritative.
89
+ */
90
+ export declare function noteUrl(note: Pick<StoredNote, 'mint' | 'secret' | 'amountMsat'>): string;
91
+ export declare function createNoteOps(store: LnurlcashNoteStore, options?: NoteOpsOptions): NoteOps;
@@ -0,0 +1,198 @@
1
+ import { generatePreimage, computePaymentHash, fetchJson, verifyLud21 } from 'farrier-kit';
2
+ export function isError(res) {
3
+ return typeof res === 'object' && res !== null && res.status === 'ERROR';
4
+ }
5
+ /**
6
+ * Mint responses are the only thing safe to surface. Anything thrown by the
7
+ * HTTP layer may carry a URL, and our URLs carry note secrets in the query
8
+ * string, so exceptions are never stringified outward.
9
+ */
10
+ export class MintRefused extends Error {
11
+ }
12
+ /**
13
+ * The mint doesn't recognise a note we thought we held. Expected, not
14
+ * exceptional: a bearer note can be spent by anyone holding a copy, so every
15
+ * local balance is a cache and the mint is the only authority. Signals "drop
16
+ * this one and try the next", never "fail the payment".
17
+ */
18
+ export class NoteGone extends Error {
19
+ }
20
+ const DEFAULT_HTTP_TIMEOUT_MS = 8_000;
21
+ /** Appends params to a callback URL that may already carry some. */
22
+ export function callbackUrl(base, params) {
23
+ const url = new URL(base);
24
+ for (const [k, v] of Object.entries(params))
25
+ url.searchParams.set(k, v);
26
+ return url.toString();
27
+ }
28
+ /**
29
+ * The note as a LUD-25 withdraw URL: the secret as `k1`, its value alongside.
30
+ * This is the form a wallet shows and the form a paywall is handed. The
31
+ * `amount` is only a claim; the mint's `maxWithdrawable` is authoritative.
32
+ */
33
+ export function noteUrl(note) {
34
+ const url = new URL('/w', note.mint);
35
+ url.searchParams.set('k1', note.secret);
36
+ url.searchParams.set('amount', String(note.amountMsat));
37
+ return url.toString();
38
+ }
39
+ export function createNoteOps(store, options = {}) {
40
+ const httpTimeoutMs = options.httpTimeoutMs ?? DEFAULT_HTTP_TIMEOUT_MS;
41
+ const get = async (url) => fetchJson(url, { timeoutMs: httpTimeoutMs, fetchImpl: options.fetchImpl });
42
+ /** Reads a note's current value from the mint, keeping why it failed. */
43
+ async function probeNote(mint, secret) {
44
+ let res;
45
+ try {
46
+ res = await get(callbackUrl(new URL('/w', mint).toString(), { k1: secret }));
47
+ }
48
+ catch {
49
+ return { ok: false, reason: 'unreachable' };
50
+ }
51
+ if (isError(res) || typeof res.maxWithdrawable !== 'number' || typeof res.callback !== 'string') {
52
+ return { ok: false, reason: 'refused' };
53
+ }
54
+ return { ok: true, note: { amountMsat: res.maxWithdrawable, callback: res.callback } };
55
+ }
56
+ /**
57
+ * Reads a note's current value from the mint. `null` means the mint doesn't
58
+ * recognise it: unknown, already spent, or pending another operation.
59
+ */
60
+ async function resolveNote(mint, secret) {
61
+ const probe = await probeNote(mint, secret);
62
+ return probe.ok ? probe.note : null;
63
+ }
64
+ /**
65
+ * Settles notes left in an indeterminate state by an earlier crash, a melt
66
+ * whose outcome never came back, or a note handed to a paywall that may or
67
+ * may not have rotated it. A provisional note the mint knows about means its
68
+ * split landed; one it doesn't means the split never happened. A melting note
69
+ * the mint still honours means the spend failed and the mint restored it.
70
+ */
71
+ async function reconcile() {
72
+ const recovered = [];
73
+ for (const note of store.byState('provisional')) {
74
+ const resolved = await resolveNote(note.mint, note.secret);
75
+ if (resolved) {
76
+ store.confirm(note.secret, resolved.amountMsat);
77
+ // A landed split burned its parent, whatever our local copy says.
78
+ if (note.parent)
79
+ store.remove(note.parent);
80
+ }
81
+ else {
82
+ store.remove(note.secret);
83
+ }
84
+ }
85
+ // A melting note is asked about in a different order, and the order is
86
+ // the whole fix. Previously the mint was asked whether it still had the
87
+ // note, and a "no" meant remove: but "no" is exactly what a SETTLED melt
88
+ // looks like, because settling burns the note. The preimage the payment
89
+ // bought went in the bin with it.
90
+ //
91
+ // So the verify URL is consulted FIRST, while the note is still on disk.
92
+ // Only once settlement has been ruled out is the note's own fate asked
93
+ // about, and even then an unrecognised note with an unsettled verify URL
94
+ // is left alone rather than dropped: that is a melt still in flight.
95
+ for (const note of store.byState('melting')) {
96
+ if (note.verifyUrl && note.paymentHashHex) {
97
+ let result;
98
+ try {
99
+ result = await verifyLud21({
100
+ verifyUrl: note.verifyUrl,
101
+ paymentHashHex: note.paymentHashHex,
102
+ fetchImpl: options.fetchImpl,
103
+ timeoutMs: httpTimeoutMs,
104
+ ...(options.urlGuard ? { urlGuard: options.urlGuard } : {}),
105
+ });
106
+ }
107
+ catch {
108
+ // The mint said nothing. Nothing said is not a verdict, and this
109
+ // note is holding a payment that may have landed.
110
+ continue;
111
+ }
112
+ if (result?.settled) {
113
+ if (result.verified && result.preimage) {
114
+ const melt = {
115
+ paymentHashHex: note.paymentHashHex,
116
+ preimage: result.preimage,
117
+ amountMsat: note.amountMsat,
118
+ mint: note.mint,
119
+ settledAt: new Date().toISOString(),
120
+ };
121
+ store.recordSettledMelt(melt);
122
+ recovered.push(melt);
123
+ }
124
+ // Settled either way, so the note is spent and must not come back.
125
+ store.remove(note.secret);
126
+ continue;
127
+ }
128
+ // Not settled. If the mint still has the note the melt failed and it
129
+ // is spendable again; if it does not, the payment is still in flight
130
+ // and this note stays put with its URL for the next pass.
131
+ const resolved = await resolveNote(note.mint, note.secret);
132
+ if (resolved)
133
+ store.confirm(note.secret, resolved.amountMsat);
134
+ continue;
135
+ }
136
+ // No proof to consult - an older record, or a mint that offered no
137
+ // verify URL. Nothing better than the previous behaviour is available.
138
+ const resolved = await resolveNote(note.mint, note.secret);
139
+ if (resolved)
140
+ store.confirm(note.secret, resolved.amountMsat);
141
+ else
142
+ store.remove(note.secret);
143
+ }
144
+ return { recovered };
145
+ }
146
+ /**
147
+ * Splits `parent` into a note worth exactly `amountMsat` plus change, and
148
+ * returns the exact-value note. A melt invoice must match the note value
149
+ * exactly and a paywall must not be overpaid, so this is how an arbitrary
150
+ * amount gets covered.
151
+ */
152
+ async function split(parent, amountMsat) {
153
+ const resolved = await resolveNote(parent.mint, parent.secret);
154
+ if (!resolved) {
155
+ store.remove(parent.secret);
156
+ throw new NoteGone('note not recognised by the mint');
157
+ }
158
+ const paySecret = generatePreimage();
159
+ const changeSecret = generatePreimage();
160
+ const addedAt = new Date().toISOString();
161
+ // Persisted BEFORE the request, deliberately. The mint keys the new notes
162
+ // to hashes of these secrets and never learns the secrets themselves, so a
163
+ // crash between its swap and our write would destroy the value outright.
164
+ store.addMany([
165
+ { secret: paySecret, mint: parent.mint, amountMsat, state: 'provisional', parent: parent.secret, addedAt },
166
+ { secret: changeSecret, mint: parent.mint, amountMsat: 0, state: 'provisional', parent: parent.secret, addedAt },
167
+ ]);
168
+ let res;
169
+ try {
170
+ res = await get(callbackUrl(resolved.callback, {
171
+ k1: parent.secret,
172
+ amount: String(amountMsat),
173
+ h: computePaymentHash(paySecret),
174
+ h2: computePaymentHash(changeSecret),
175
+ }));
176
+ }
177
+ catch {
178
+ // Outcome unknown. Leave both children provisional; reconcile() decides
179
+ // on the next call, once the mint can be asked again.
180
+ throw new MintRefused('Split outcome unknown; it will be reconciled on the next attempt');
181
+ }
182
+ if (isError(res)) {
183
+ // A refusal is synchronous and burns nothing, so the children are dead.
184
+ store.removeMany([paySecret, changeSecret]);
185
+ throw new MintRefused(res.reason ?? 'Mint refused the split');
186
+ }
187
+ store.remove(parent.secret);
188
+ store.confirm(paySecret, amountMsat);
189
+ const change = await resolveNote(parent.mint, changeSecret);
190
+ if (change)
191
+ store.confirm(changeSecret, change.amountMsat);
192
+ else
193
+ store.remove(changeSecret);
194
+ return store.find(paySecret);
195
+ }
196
+ return { probeNote, resolveNote, reconcile, split };
197
+ }
198
+ //# sourceMappingURL=lnurlcash-ops.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lnurlcash-ops.js","sourceRoot":"","sources":["../../src/wallet/lnurlcash-ops.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAgC1F,MAAM,UAAU,OAAO,CAAC,GAAY;IAClC,OAAO,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI,IAAK,GAAkB,CAAC,MAAM,KAAK,OAAO,CAAA;AAC1F,CAAC;AAED;;;;GAIG;AACH,MAAM,OAAO,WAAY,SAAQ,KAAK;CAAG;AAEzC;;;;;GAKG;AACH,MAAM,OAAO,QAAS,SAAQ,KAAK;CAAG;AAiCtC,MAAM,uBAAuB,GAAG,KAAK,CAAA;AAErC,oEAAoE;AACpE,MAAM,UAAU,WAAW,CAAC,IAAY,EAAE,MAA8B;IACtE,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,CAAA;IACzB,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC;QAAE,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;IACvE,OAAO,GAAG,CAAC,QAAQ,EAAE,CAAA;AACvB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,OAAO,CAAC,IAAwD;IAC9E,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,CAAA;IACpC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,CAAA;IACvC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAA;IACvD,OAAO,GAAG,CAAC,QAAQ,EAAE,CAAA;AACvB,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,KAAyB,EAAE,UAA0B,EAAE;IACnF,MAAM,aAAa,GAAG,OAAO,CAAC,aAAa,IAAI,uBAAuB,CAAA;IAEtE,MAAM,GAAG,GAAG,KAAK,EAAK,GAAW,EAAc,EAAE,CAC/C,SAAS,CAAI,GAAG,EAAE,EAAE,SAAS,EAAE,aAAa,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,CAAC,CAAA;IAE/E,yEAAyE;IACzE,KAAK,UAAU,SAAS,CAAC,IAAY,EAAE,MAAc;QACnD,IAAI,GAAiC,CAAA;QACrC,IAAI,CAAC;YACH,GAAG,GAAG,MAAM,GAAG,CAA+B,WAAW,CAAC,IAAI,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,QAAQ,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC,CAAA;QAC5G,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,CAAA;QAC7C,CAAC;QACD,IAAI,OAAO,CAAC,GAAG,CAAC,IAAI,OAAO,GAAG,CAAC,eAAe,KAAK,QAAQ,IAAI,OAAO,GAAG,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;YAChG,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,CAAA;QACzC,CAAC;QACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,UAAU,EAAE,GAAG,CAAC,eAAe,EAAE,QAAQ,EAAE,GAAG,CAAC,QAAQ,EAAE,EAAE,CAAA;IACxF,CAAC;IAED;;;OAGG;IACH,KAAK,UAAU,WAAW,CAAC,IAAY,EAAE,MAAc;QACrD,MAAM,KAAK,GAAG,MAAM,SAAS,CAAC,IAAI,EAAE,MAAM,CAAC,CAAA;QAC3C,OAAO,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAA;IACrC,CAAC;IAED;;;;;;OAMG;IACH,KAAK,UAAU,SAAS;QACtB,MAAM,SAAS,GAAkB,EAAE,CAAA;QAEnC,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,aAAa,CAAC,EAAE,CAAC;YAChD,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,CAAA;YAC1D,IAAI,QAAQ,EAAE,CAAC;gBACb,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,UAAU,CAAC,CAAA;gBAC/C,kEAAkE;gBAClE,IAAI,IAAI,CAAC,MAAM;oBAAE,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;YAC5C,CAAC;iBAAM,CAAC;gBACN,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;YAC3B,CAAC;QACH,CAAC;QAED,uEAAuE;QACvE,wEAAwE;QACxE,yEAAyE;QACzE,wEAAwE;QACxE,kCAAkC;QAClC,EAAE;QACF,yEAAyE;QACzE,uEAAuE;QACvE,yEAAyE;QACzE,qEAAqE;QACrE,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;YAC5C,IAAI,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;gBAC1C,IAAI,MAAM,CAAA;gBACV,IAAI,CAAC;oBACH,MAAM,GAAG,MAAM,WAAW,CAAC;wBACzB,SAAS,EAAE,IAAI,CAAC,SAAS;wBACzB,cAAc,EAAE,IAAI,CAAC,cAAc;wBACnC,SAAS,EAAE,OAAO,CAAC,SAAS;wBAC5B,SAAS,EAAE,aAAa;wBACxB,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;qBAC5D,CAAC,CAAA;gBACJ,CAAC;gBAAC,MAAM,CAAC;oBACP,iEAAiE;oBACjE,kDAAkD;oBAClD,SAAQ;gBACV,CAAC;gBAED,IAAI,MAAM,EAAE,OAAO,EAAE,CAAC;oBACpB,IAAI,MAAM,CAAC,QAAQ,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;wBACvC,MAAM,IAAI,GAAgB;4BACxB,cAAc,EAAE,IAAI,CAAC,cAAc;4BACnC,QAAQ,EAAE,MAAM,CAAC,QAAQ;4BACzB,UAAU,EAAE,IAAI,CAAC,UAAU;4BAC3B,IAAI,EAAE,IAAI,CAAC,IAAI;4BACf,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;yBACpC,CAAA;wBACD,KAAK,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAA;wBAC7B,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;oBACtB,CAAC;oBACD,mEAAmE;oBACnE,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;oBACzB,SAAQ;gBACV,CAAC;gBAED,qEAAqE;gBACrE,qEAAqE;gBACrE,0DAA0D;gBAC1D,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,CAAA;gBAC1D,IAAI,QAAQ;oBAAE,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,UAAU,CAAC,CAAA;gBAC7D,SAAQ;YACV,CAAC;YAED,mEAAmE;YACnE,uEAAuE;YACvE,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,CAAA;YAC1D,IAAI,QAAQ;gBAAE,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,UAAU,CAAC,CAAA;;gBACxD,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;QAChC,CAAC;QAED,OAAO,EAAE,SAAS,EAAE,CAAA;IACtB,CAAC;IAED;;;;;OAKG;IACH,KAAK,UAAU,KAAK,CAAC,MAAkB,EAAE,UAAkB;QACzD,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,CAAA;QAC9D,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;YAC3B,MAAM,IAAI,QAAQ,CAAC,iCAAiC,CAAC,CAAA;QACvD,CAAC;QAED,MAAM,SAAS,GAAG,gBAAgB,EAAE,CAAA;QACpC,MAAM,YAAY,GAAG,gBAAgB,EAAE,CAAA;QACvC,MAAM,OAAO,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAA;QAExC,0EAA0E;QAC1E,2EAA2E;QAC3E,yEAAyE;QACzE,KAAK,CAAC,OAAO,CAAC;YACZ,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,EAAE;YAC1G,EAAE,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,UAAU,EAAE,CAAC,EAAE,KAAK,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,EAAE;SACjH,CAAC,CAAA;QAEF,IAAI,GAA4B,CAAA;QAChC,IAAI,CAAC;YACH,GAAG,GAAG,MAAM,GAAG,CAA0B,WAAW,CAAC,QAAQ,CAAC,QAAQ,EAAE;gBACtE,EAAE,EAAE,MAAM,CAAC,MAAM;gBACjB,MAAM,EAAE,MAAM,CAAC,UAAU,CAAC;gBAC1B,CAAC,EAAE,kBAAkB,CAAC,SAAS,CAAC;gBAChC,EAAE,EAAE,kBAAkB,CAAC,YAAY,CAAC;aACrC,CAAC,CAAC,CAAA;QACL,CAAC;QAAC,MAAM,CAAC;YACP,wEAAwE;YACxE,sDAAsD;YACtD,MAAM,IAAI,WAAW,CAAC,kEAAkE,CAAC,CAAA;QAC3F,CAAC;QAED,IAAI,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;YACjB,wEAAwE;YACxE,KAAK,CAAC,UAAU,CAAC,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC,CAAA;YAC3C,MAAM,IAAI,WAAW,CAAC,GAAG,CAAC,MAAM,IAAI,wBAAwB,CAAC,CAAA;QAC/D,CAAC;QAED,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;QAC3B,KAAK,CAAC,OAAO,CAAC,SAAS,EAAE,UAAU,CAAC,CAAA;QAEpC,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,MAAM,CAAC,IAAI,EAAE,YAAY,CAAC,CAAA;QAC3D,IAAI,MAAM;YAAE,KAAK,CAAC,OAAO,CAAC,YAAY,EAAE,MAAM,CAAC,UAAU,CAAC,CAAA;;YACrD,KAAK,CAAC,MAAM,CAAC,YAAY,CAAC,CAAA;QAE/B,OAAO,KAAK,CAAC,IAAI,CAAC,SAAS,CAAE,CAAA;IAC/B,CAAC;IAED,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,SAAS,EAAE,KAAK,EAAE,CAAA;AACrD,CAAC"}
@@ -1,40 +1,22 @@
1
- import { tryDecodeBolt11, bolt11AmountMsats, generatePreimage, computePaymentHash, verifyLud21, fetchJson, } from 'farrier-kit';
1
+ import { tryDecodeBolt11, bolt11AmountMsats, verifyLud21, fetchJson, } from 'farrier-kit';
2
+ import { createNoteOps, callbackUrl, isError, MintRefused, NoteGone, } from './lnurlcash-ops.js';
2
3
  const METHOD = 'lnurlcash';
3
4
  const DEFAULTS = {
4
5
  meltTimeoutMs: 60_000,
5
6
  meltPollMs: 1_000,
6
7
  httpTimeoutMs: 8_000,
7
8
  };
8
- function isError(res) {
9
- return typeof res === 'object' && res !== null && res.status === 'ERROR';
10
- }
11
- /**
12
- * Mint responses are the only thing safe to surface. Anything thrown by the
13
- * HTTP layer may carry a URL, and our URLs carry note secrets in the query
14
- * string, so exceptions are never stringified outward.
15
- */
16
- class MintRefused extends Error {
17
- }
18
- /**
19
- * The mint doesn't recognise a note we thought we held. Expected, not
20
- * exceptional: a bearer note can be spent by anyone holding a copy, so every
21
- * local balance is a cache and the mint is the only authority. Signals "drop
22
- * this one and try the next", never "fail the payment".
23
- */
24
- class NoteGone extends Error {
25
- }
26
9
  function sleep(ms) {
27
10
  return new Promise(resolve => setTimeout(resolve, ms));
28
11
  }
29
- /** Appends params to a callback URL that may already carry some. */
30
- function callbackUrl(base, params) {
31
- const url = new URL(base);
32
- for (const [k, v] of Object.entries(params))
33
- url.searchParams.set(k, v);
34
- return url.toString();
35
- }
36
12
  export function createLnurlcashWallet(store, options = {}, lock) {
37
13
  const cfg = { ...DEFAULTS, ...options };
14
+ const ops = createNoteOps(store, {
15
+ httpTimeoutMs: cfg.httpTimeoutMs,
16
+ fetchImpl: cfg.fetchImpl,
17
+ // reconcile polls verify URLs of its own now, so the guard has to reach it
18
+ ...(cfg.urlGuard ? { urlGuard: cfg.urlGuard } : {}),
19
+ });
38
20
  let internalLock = Promise.resolve();
39
21
  const defaultLock = (fn) => {
40
22
  const result = internalLock.catch(() => { }).then(() => fn());
@@ -46,95 +28,9 @@ export function createLnurlcashWallet(store, options = {}, lock) {
46
28
  timeoutMs: cfg.httpTimeoutMs,
47
29
  fetchImpl: cfg.fetchImpl,
48
30
  });
49
- /**
50
- * Reads a note's current value from the mint. `null` means the mint doesn't
51
- * recognise it: unknown, already spent, or pending another operation.
52
- */
53
- async function resolveNote(mint, secret) {
54
- let res;
55
- try {
56
- res = await get(callbackUrl(new URL('/w', mint).toString(), { k1: secret }));
57
- }
58
- catch {
59
- return null;
60
- }
61
- if (isError(res) || typeof res.maxWithdrawable !== 'number' || typeof res.callback !== 'string')
62
- return null;
63
- return { amountMsat: res.maxWithdrawable, callback: res.callback };
64
- }
65
- /**
66
- * Settles notes left in an indeterminate state by an earlier crash or a melt
67
- * whose outcome never came back. A provisional note the mint knows about
68
- * means its split landed; one it doesn't means the split never happened. A
69
- * melting note the mint still honours means the payment failed and the mint
70
- * restored it.
71
- */
72
- async function reconcile() {
73
- for (const note of [...store.byState('provisional'), ...store.byState('melting')]) {
74
- const resolved = await resolveNote(note.mint, note.secret);
75
- if (resolved) {
76
- store.confirm(note.secret, resolved.amountMsat);
77
- // A landed split burned its parent, whatever our local copy says.
78
- if (note.parent)
79
- store.remove(note.parent);
80
- }
81
- else {
82
- store.remove(note.secret);
83
- }
84
- }
85
- }
86
- /**
87
- * Splits `parent` into a note worth exactly `amountMsat` plus change, and
88
- * returns the exact-value note. The mint requires a melt invoice to match
89
- * the note value exactly, so this is how an arbitrary invoice gets paid.
90
- */
91
- async function split(parent, amountMsat) {
92
- const resolved = await resolveNote(parent.mint, parent.secret);
93
- if (!resolved) {
94
- store.remove(parent.secret);
95
- throw new NoteGone('note not recognised by the mint');
96
- }
97
- const paySecret = generatePreimage();
98
- const changeSecret = generatePreimage();
99
- const addedAt = new Date().toISOString();
100
- // Persisted BEFORE the request, deliberately. The mint keys the new notes
101
- // to hashes of these secrets and never learns the secrets themselves, so a
102
- // crash between its swap and our write would destroy the value outright.
103
- store.addMany([
104
- { secret: paySecret, mint: parent.mint, amountMsat, state: 'provisional', parent: parent.secret, addedAt },
105
- { secret: changeSecret, mint: parent.mint, amountMsat: 0, state: 'provisional', parent: parent.secret, addedAt },
106
- ]);
107
- let res;
108
- try {
109
- res = await get(callbackUrl(resolved.callback, {
110
- k1: parent.secret,
111
- amount: String(amountMsat),
112
- h: computePaymentHash(paySecret),
113
- h2: computePaymentHash(changeSecret),
114
- }));
115
- }
116
- catch {
117
- // Outcome unknown. Leave both children provisional; reconcile() decides
118
- // on the next call, once the mint can be asked again.
119
- throw new MintRefused('Split outcome unknown; it will be reconciled on the next attempt');
120
- }
121
- if (isError(res)) {
122
- // A refusal is synchronous and burns nothing, so the children are dead.
123
- store.removeMany([paySecret, changeSecret]);
124
- throw new MintRefused(res.reason ?? 'Mint refused the split');
125
- }
126
- store.remove(parent.secret);
127
- store.confirm(paySecret, amountMsat);
128
- const change = await resolveNote(parent.mint, changeSecret);
129
- if (change)
130
- store.confirm(changeSecret, change.amountMsat);
131
- else
132
- store.remove(changeSecret);
133
- return store.find(paySecret);
134
- }
135
31
  /** Melts `note` against `invoice` and waits for cryptographic settlement proof. */
136
32
  async function melt(note, invoice, paymentHashHex) {
137
- const resolved = await resolveNote(note.mint, note.secret);
33
+ const resolved = await ops.resolveNote(note.mint, note.secret);
138
34
  if (!resolved) {
139
35
  store.remove(note.secret);
140
36
  throw new NoteGone('note not recognised by the mint');
@@ -169,6 +65,12 @@ export function createLnurlcashWallet(store, options = {}, lock) {
169
65
  reason: 'Mint accepted the melt but offers no LUD-21 verify URL, so settlement cannot be proven.',
170
66
  };
171
67
  }
68
+ // Persisted before the first poll, not after the last one. A melt that
69
+ // settles late still spends the note, and the verify URL is the only
70
+ // route back to the preimage it bought. Keeping it in a local variable
71
+ // meant a timeout - or a crash, or the process being killed - threw the
72
+ // credential away while the sats were already gone.
73
+ store.setMeltProof(note.secret, res.verify, paymentHashHex);
172
74
  const deadline = Date.now() + cfg.meltTimeoutMs;
173
75
  for (;;) {
174
76
  let result;
@@ -185,10 +87,20 @@ export function createLnurlcashWallet(store, options = {}, lock) {
185
87
  result = undefined;
186
88
  }
187
89
  if (result?.settled) {
188
- store.remove(note.secret);
189
90
  if (result.verified && result.preimage) {
91
+ // Recorded before the note goes, so a crash between the two lines
92
+ // cannot lose what the payment bought.
93
+ store.recordSettledMelt({
94
+ paymentHashHex,
95
+ preimage: result.preimage,
96
+ amountMsat: note.amountMsat,
97
+ mint: note.mint,
98
+ settledAt: new Date().toISOString(),
99
+ });
100
+ store.remove(note.secret);
190
101
  return { paid: true, preimage: result.preimage, method: METHOD };
191
102
  }
103
+ store.remove(note.secret);
192
104
  // Settled per the mint, but unproven. Same stance as the NWC provider:
193
105
  // the note is spent either way, so it must not go back in the store.
194
106
  return {
@@ -203,7 +115,8 @@ export function createLnurlcashWallet(store, options = {}, lock) {
203
115
  paid: false,
204
116
  method: METHOD,
205
117
  outcome: 'unknown',
206
- reason: 'Melt did not settle before the timeout. The note is held pending and will be reconciled before the next payment.',
118
+ verifyUrl: res.verify,
119
+ reason: 'Melt did not settle before the timeout. The note is held with its verify URL, so a later reconcile can still recover the preimage if the payment lands.',
207
120
  };
208
121
  }
209
122
  await sleep(cfg.meltPollMs);
@@ -220,8 +133,20 @@ export function createLnurlcashWallet(store, options = {}, lock) {
220
133
  if (needMsat === null) {
221
134
  return { paid: false, method: METHOD, reason: 'Amountless BOLT-11 invoices require an explicit amount and are refused' };
222
135
  }
136
+ // A reconcile can turn up a payment that landed after an earlier attempt
137
+ // gave up on it. That preimage is a credential somebody paid for, so it
138
+ // is said out loud here rather than only filed: the caller is a wallet
139
+ // asking to spend, and "by the way, that payment you wrote off did go
140
+ // through" changes what they do next.
141
+ let recoveredNote = '';
223
142
  try {
224
- await reconcile();
143
+ const report = await ops.reconcile();
144
+ if (report.recovered.length > 0) {
145
+ const each = report.recovered
146
+ .map(m => `${m.paymentHashHex.slice(0, 12)}… preimage ${m.preimage}`)
147
+ .join('; ');
148
+ recoveredNote = ` Also recovered ${report.recovered.length} earlier melt(s) that settled after being written off: ${each}.`;
149
+ }
225
150
  }
226
151
  catch { /* best effort; selection below simply sees fewer notes */ }
227
152
  const live = store.live();
@@ -239,8 +164,11 @@ export function createLnurlcashWallet(store, options = {}, lock) {
239
164
  try {
240
165
  const exact = candidate.amountMsat === needMsat
241
166
  ? candidate
242
- : await split(candidate, needMsat);
243
- return await melt(exact, invoice, decoded.paymentHashHex);
167
+ : await ops.split(candidate, needMsat);
168
+ const result = await melt(exact, invoice, decoded.paymentHashHex);
169
+ return recoveredNote
170
+ ? { ...result, reason: `${result.reason ?? 'Paid.'}${recoveredNote}` }
171
+ : result;
244
172
  }
245
173
  catch (error) {
246
174
  if (error instanceof NoteGone) {
@@ -259,7 +187,7 @@ export function createLnurlcashWallet(store, options = {}, lock) {
259
187
  return {
260
188
  paid: false,
261
189
  method: METHOD,
262
- reason: `No note large enough: need ${needMsat} msat, largest available is ${best} msat${staleNote}`,
190
+ reason: `No note large enough: need ${needMsat} msat, largest available is ${best} msat${staleNote}${recoveredNote}`,
263
191
  };
264
192
  }
265
193
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"lnurlcash.js","sourceRoot":"","sources":["../../src/wallet/lnurlcash.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"lnurlcash.js","sourceRoot":"","sources":["../../src/wallet/lnurlcash.ts"],"names":[],"mappings":"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"}
@@ -9,6 +9,12 @@ export interface PaymentResult {
9
9
  reason?: string;
10
10
  /** The request may have executed but settlement could not be proven. */
11
11
  outcome?: 'unknown';
12
+ /**
13
+ * Where settlement can still be proven later, for an `unknown` outcome
14
+ * that has one. A caller holding this can ask again rather than treating
15
+ * the payment as lost; reconcile also polls it on its own.
16
+ */
17
+ verifyUrl?: string;
12
18
  }
13
19
  export interface WalletProvider {
14
20
  method: WalletMethod;
@@ -0,0 +1,27 @@
1
+ export interface LnurlcashChallenge {
2
+ /** Price in sats. */
3
+ amount: number;
4
+ unit: 'sat';
5
+ /** Mints whose notes the server will accept, as hosts or URLs. */
6
+ mints: string[];
7
+ }
8
+ /** Detects whether a 402 response carries an lnurlcash challenge. */
9
+ export declare function isLnurlcashChallenge(headers: Headers): boolean;
10
+ /**
11
+ * Parses an lnurlcash payment request from the X-LNURLcash header value:
12
+ * `lnurlcashreq1` followed by unpadded base64url of the request's RFC 8785
13
+ * canonical JSON.
14
+ *
15
+ * The request is `{ v, id, amount, currency, methodDetails: { mints } }`,
16
+ * with the amount a decimal STRING of whole sats. That is the shape the
17
+ * conformance vectors pin and `lnurlcash-kit` encodes.
18
+ *
19
+ * A shorter object, `{ a: number, u, m }`, briefly went out under the same
20
+ * prefix before the format settled. It is still read here, because a decoder
21
+ * that returns nothing on a string it can plainly understand helps no one,
22
+ * and because the kit's own decoder accepts it too. Nothing emits it.
23
+ *
24
+ * Only `sat` exists today; anything else returns null rather than guessing at
25
+ * a denomination.
26
+ */
27
+ export declare function parseLnurlcashChallenge(header: string): LnurlcashChallenge | null;