@forgesworn/moneyer 0.17.1 → 0.18.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.
- package/CHANGELOG.md +28 -0
- package/README.md +11 -7
- package/dist/admin.js +21 -5
- package/dist/live-check.js +4 -2
- package/dist/melt.d.ts +9 -1
- package/dist/melt.js +15 -12
- package/dist/server.d.ts +1 -0
- package/dist/server.js +39 -13
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,33 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.18.1 - 2026-10-07
|
|
4
|
+
|
|
5
|
+
- **Bound mint receipts verify in current wallets again.** Since
|
|
6
|
+
`@lnurlcash/kit` moved to taproot notes, a wallet checks a settled
|
|
7
|
+
`/verify` receipt's `mint.sig` as a `cs1` over the note's Q. moneyer still
|
|
8
|
+
sent a bare hex signature over the bearer `h`, which the kit drops as
|
|
9
|
+
unreadable, so a sealed signer could not confirm a note minted here. The
|
|
10
|
+
receipt now carries the note's ordinary certificate, and a quote or
|
|
11
|
+
receipt for a note named by its `cp1` repeats that `cp1` rather than the
|
|
12
|
+
hex of its Q, which a wallet would read as a bearer `h`.
|
|
13
|
+
- `@lnurlcash/kit` 0.20.2. `moneyer admin verify-note` checks a certificate
|
|
14
|
+
over the note's Q, or over `sha256(k1)` for a bearer note certified before
|
|
15
|
+
that, and still reads a pre-`cs1` signature from a note URL's `sig`. The
|
|
16
|
+
mint page and the live bound-mint check name a quote by its bare `h`.
|
|
17
|
+
|
|
18
|
+
## 0.18.0 - 2026-10-07
|
|
19
|
+
|
|
20
|
+
- **A melt that cannot leave is answered with its reason.** The callback
|
|
21
|
+
used to reply `OK` the moment the note was reserved, so a melt with no
|
|
22
|
+
route looked like success until the wallet checked again. It now waits up
|
|
23
|
+
to two seconds for the payment: if the funding source confirms nothing
|
|
24
|
+
went out, the note is restored first and the answer is `ERROR` with the
|
|
25
|
+
reason (for lnd, "Could not find a route to pay this invoice."). A
|
|
26
|
+
payment still in flight, or one that settles, is `OK` as before. The
|
|
27
|
+
hodl-invoice rule stands: a failure report is acted on only once the
|
|
28
|
+
funding source confirms it. The invoice itself is still refused if tried
|
|
29
|
+
again, as it was after a background restore.
|
|
30
|
+
|
|
3
31
|
## 0.17.1 - 2026-10-06
|
|
4
32
|
|
|
5
33
|
- **The expiry sweep no longer deletes paid mint invoices.** A mint invoice
|
package/README.md
CHANGED
|
@@ -37,10 +37,13 @@ lesson, that behaviour is kept deliberately and tested.
|
|
|
37
37
|
from the start.
|
|
38
38
|
- Signs every note it mints with its own mint key (secp256k1, the standard
|
|
39
39
|
`Lightning Signed Message` construction) for LUD-25 offline verification.
|
|
40
|
-
- The melt discipline:
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
40
|
+
- The melt discipline: reserve the note, then give the payment up to two
|
|
41
|
+
seconds. A payment the funding source confirms never left (no route, say)
|
|
42
|
+
is answered `ERROR` with its reason and the note is outstanding again;
|
|
43
|
+
anything else is answered `OK` and finishes in the background. Burn only
|
|
44
|
+
on confirmed payment, restore only on confirmed non-payment, and park
|
|
45
|
+
everything else as pending for reconciliation - which also runs at
|
|
46
|
+
startup, so a crash mid-melt never guesses.
|
|
44
47
|
|
|
45
48
|
## Run
|
|
46
49
|
|
|
@@ -417,10 +420,11 @@ The rules:
|
|
|
417
420
|
true`, so a wallet knows this mint takes the parameter before it asks
|
|
418
421
|
rather than after it pays.
|
|
419
422
|
- When signing and LUD-21 verification are enabled, the quote also carries
|
|
420
|
-
`mint: {h, amount}`. This is the exact output
|
|
421
|
-
|
|
423
|
+
`mint: {h, amount}`. This is the exact output, in the spelling the wallet
|
|
424
|
+
named it (a bearer note's hex `h`, or its `cp1`), and the net millisatoshi
|
|
425
|
+
value the invoice will mint; it never carries `sig` before settlement.
|
|
422
426
|
- Once settled, `/verify` repeats the same `h` and `amount` and adds `sig`,
|
|
423
|
-
the ordinary LUD-25
|
|
427
|
+
the note's ordinary LUD-25 certificate: a `cs1` over its Q. A sealed
|
|
424
428
|
signer can verify that receipt against the pre-payment commitment and
|
|
425
429
|
pinned `mintPubkey`, then confirm its staged note without exporting `k1`.
|
|
426
430
|
- Claiming needs nothing else. `GET /w?k1=<the secret>` brings the note
|
package/dist/admin.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { existsSync } from 'node:fs';
|
|
2
2
|
import { bytesToHex, hexToBytes, randomBytes } from '@noble/hashes/utils.js';
|
|
3
3
|
import { secp256k1 } from '@noble/curves/secp256k1.js';
|
|
4
|
-
import { noteDeclaredAmount, noteK1, noteSignature,
|
|
4
|
+
import { encodeCs1WithAmount, hashK1, noteDeclaredAmount, noteK1, noteSignature, verifyNoteSignatureForKey } from '@lnurlcash/kit';
|
|
5
5
|
import { decodeNote, decodeSpend } from "./spend.js";
|
|
6
6
|
import { configFromEnv, pubkeyHex } from "./config.js";
|
|
7
7
|
import { NoteStore } from "./store.js";
|
|
@@ -374,7 +374,20 @@ export const runAdmin = async (argv, deps = {}) => {
|
|
|
374
374
|
}
|
|
375
375
|
const id = bytesToHex(spend.outputKey);
|
|
376
376
|
const declared = noteDeclaredAmount(url);
|
|
377
|
-
|
|
377
|
+
// `c` since the taproot unification; `sig` on a note URL from before.
|
|
378
|
+
let signature = noteSignature(url);
|
|
379
|
+
if (!signature) {
|
|
380
|
+
try {
|
|
381
|
+
signature = new URL(url).searchParams.get('sig');
|
|
382
|
+
}
|
|
383
|
+
catch { }
|
|
384
|
+
}
|
|
385
|
+
// The kit reads only a cs1 now. A certificate from before that was
|
|
386
|
+
// the bare 65-byte signature in hex, its amount on the URL beside
|
|
387
|
+
// it: put the amount back into a cs1 so it can still be checked.
|
|
388
|
+
if (signature && declared !== null && /^[0-9a-f]{130}$/i.test(signature)) {
|
|
389
|
+
signature = encodeCs1WithAmount(declared, hexToBytes(signature));
|
|
390
|
+
}
|
|
378
391
|
const current = signingPubkey(config);
|
|
379
392
|
const keys = [...(current ? [current] : []), ...(config.previousSigningPubkeys ?? [])];
|
|
380
393
|
out(`note id ${id}`);
|
|
@@ -387,9 +400,12 @@ export const runAdmin = async (argv, deps = {}) => {
|
|
|
387
400
|
out('signature present, but the URL declares no amount to check it against');
|
|
388
401
|
}
|
|
389
402
|
else {
|
|
390
|
-
// Over Q, as LUD-25 certifies every note now, or
|
|
391
|
-
//
|
|
392
|
-
|
|
403
|
+
// Over Q, as LUD-25 certifies every note now, or, for a bearer
|
|
404
|
+
// note certified before that, over its old id sha256(k1). A key
|
|
405
|
+
// note's old id was its key, which is Q already.
|
|
406
|
+
const legacyId = spend.kind === 'script' && /^[0-9a-f]{64}$/i.test(k1.trim()) ? hashK1(k1.trim()) : null;
|
|
407
|
+
const signedBy = keys.find(pubkey => verifyNoteSignatureForKey(id, declared, signature, pubkey) ||
|
|
408
|
+
(legacyId !== null && verifyNoteSignatureForKey(legacyId, declared, signature, pubkey)));
|
|
393
409
|
out(signedBy === undefined
|
|
394
410
|
? 'signature DOES NOT verify against this mint'
|
|
395
411
|
: `signature verifies against ${signedBy === current ? 'the current key' : `a previous key (${signedBy})`}`);
|
package/dist/live-check.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { randomBytes } from 'node:crypto';
|
|
2
2
|
import { lstat, open, readFile, rename, unlink } from 'node:fs/promises';
|
|
3
3
|
import { decodeBolt11 } from 'farrier-kit/bolt11';
|
|
4
|
-
import { NoteSpentError, PendingNoteError, buildNoteUrl, decodeBolt11AmountMsat, fetchInvoiceVerification, fetchPayRequest, hashK1, isBolt11Invoice, isPreimage, meltNote, probeBurnedNote,
|
|
4
|
+
import { NoteSpentError, PendingNoteError, buildNoteUrl, decodeBolt11AmountMsat, fetchInvoiceVerification, fetchPayRequest, hashK1, isBolt11Invoice, isPreimage, meltNote, probeBurnedNote, requestInvoiceShort, requireBoundMintQuote, validateBoundMintReceipt, withinMintFeeBand } from '@lnurlcash/kit';
|
|
5
5
|
import { claimMintedNote } from "./claim.js";
|
|
6
6
|
const stages = new Set(['prepared', 'quoted', 'settled', 'claimed', 'retiring', 'retired']);
|
|
7
7
|
const errno = (error) => error && typeof error === 'object' && 'code' in error && typeof error.code === 'string' ? error.code : undefined;
|
|
@@ -216,7 +216,9 @@ export const runLiveBoundMintCheck = async (options) => {
|
|
|
216
216
|
if (state.grossMsat < pay.minSendable || state.grossMsat > pay.maxSendable) {
|
|
217
217
|
throw new Error(`Test amount is outside the mint range ${pay.minSendable}-${pay.maxSendable} msat.`);
|
|
218
218
|
}
|
|
219
|
-
|
|
219
|
+
// Named by the bare h, which the kit reads as a bearer note's h and
|
|
220
|
+
// normalises to its Q on both sides of the comparison below.
|
|
221
|
+
const quote = await requestInvoiceShort(pay.callback, state.grossMsat, state.h);
|
|
220
222
|
if (!quote.verify || !quote.mint)
|
|
221
223
|
throw new Error('Mint did not bind this quote to h and a verification URL.');
|
|
222
224
|
const netMsat = quote.mint.amountMsat;
|
package/dist/melt.d.ts
CHANGED
|
@@ -7,6 +7,14 @@ export type MeltJob = {
|
|
|
7
7
|
amountMsat: number;
|
|
8
8
|
payAmountMsat?: number;
|
|
9
9
|
};
|
|
10
|
+
export type MeltOutcome = {
|
|
11
|
+
kind: 'paid';
|
|
12
|
+
} | {
|
|
13
|
+
kind: 'restored';
|
|
14
|
+
reason: string;
|
|
15
|
+
} | {
|
|
16
|
+
kind: 'unresolved';
|
|
17
|
+
};
|
|
10
18
|
export type MeltDeps = {
|
|
11
19
|
store: NoteStore;
|
|
12
20
|
backend: LightningBackend;
|
|
@@ -14,5 +22,5 @@ export type MeltDeps = {
|
|
|
14
22
|
confirmDelaysMs?: number[];
|
|
15
23
|
log?: (message: string) => void;
|
|
16
24
|
};
|
|
17
|
-
export declare const runMelt: (job: MeltJob, deps: MeltDeps) => Promise<
|
|
25
|
+
export declare const runMelt: (job: MeltJob, deps: MeltDeps) => Promise<MeltOutcome>;
|
|
18
26
|
export declare const reconcilePendingMelts: (store: NoteStore, backend: LightningBackend, inFlight: ReadonlySet<string>, log?: (message: string) => void) => Promise<void>;
|
package/dist/melt.js
CHANGED
|
@@ -2,7 +2,7 @@ import { verifyPreimage } from 'farrier-kit/preimage';
|
|
|
2
2
|
import { PaymentAlreadyKnownError, PaymentFailedError, PaymentPendingError } from "./backends/types.js";
|
|
3
3
|
const DEFAULT_CONFIRM_DELAYS_MS = [0, 2_000, 4_000, 9_000, 16_000];
|
|
4
4
|
const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));
|
|
5
|
-
const confirmThenSettle = async (job, deps) => {
|
|
5
|
+
const confirmThenSettle = async (job, deps, reason) => {
|
|
6
6
|
const log = deps.log ?? (() => { });
|
|
7
7
|
for (const delay of deps.confirmDelaysMs ?? DEFAULT_CONFIRM_DELAYS_MS) {
|
|
8
8
|
if (delay > 0)
|
|
@@ -11,12 +11,11 @@ const confirmThenSettle = async (job, deps) => {
|
|
|
11
11
|
const complete = await deps.backend.isPaymentComplete(job.paymentHash);
|
|
12
12
|
if (complete) {
|
|
13
13
|
deps.store.finalizeMelt(job.paymentHash);
|
|
14
|
+
return { kind: 'paid' };
|
|
14
15
|
}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
}
|
|
19
|
-
return;
|
|
16
|
+
log(`melt ${job.noteId}: confirmed not paid - restoring`);
|
|
17
|
+
deps.store.restoreMelt(job.paymentHash);
|
|
18
|
+
return { kind: 'restored', reason };
|
|
20
19
|
}
|
|
21
20
|
catch (err) {
|
|
22
21
|
if (!(err instanceof PaymentPendingError)) {
|
|
@@ -25,6 +24,7 @@ const confirmThenSettle = async (job, deps) => {
|
|
|
25
24
|
}
|
|
26
25
|
}
|
|
27
26
|
log(`melt ${job.noteId}: payment status unconfirmable - note left pending for reconciliation`);
|
|
27
|
+
return { kind: 'unresolved' };
|
|
28
28
|
};
|
|
29
29
|
export const runMelt = async (job, deps) => {
|
|
30
30
|
const log = deps.log ?? (() => { });
|
|
@@ -47,23 +47,26 @@ export const runMelt = async (job, deps) => {
|
|
|
47
47
|
// lands between that check and the send.
|
|
48
48
|
log(`melt ${job.noteId}: the funding source already knew this hash - restored (shared-node replay?)`);
|
|
49
49
|
deps.store.restoreMelt(job.paymentHash);
|
|
50
|
-
return;
|
|
50
|
+
return { kind: 'restored', reason: 'Invoice already used by an earlier melt - use a fresh one.' };
|
|
51
51
|
}
|
|
52
|
-
|
|
52
|
+
// A clean failure's message is the backend's reason, written for a
|
|
53
|
+
// wallet ("Could not find a route..."); an ambiguous one is transport
|
|
54
|
+
// detail, so a wallet gets a plain sentence instead.
|
|
55
|
+
const clean = err instanceof PaymentFailedError;
|
|
56
|
+
if (!clean) {
|
|
53
57
|
log(`melt ${job.noteId}: payment attempt failed ambiguously (${err.message})`);
|
|
54
58
|
}
|
|
55
|
-
|
|
56
|
-
return;
|
|
59
|
+
return confirmThenSettle(job, deps, clean ? err.message : 'Payment failed.');
|
|
57
60
|
}
|
|
58
61
|
if (outcome.preimageHex !== null && !verifyPreimage(outcome.preimageHex, job.paymentHash)) {
|
|
59
62
|
// The backend claims success with a preimage that does not settle this
|
|
60
63
|
// invoice. That is a statement about the evidence, not the money - fall
|
|
61
64
|
// back to the tracker rather than trusting either way.
|
|
62
65
|
log(`melt ${job.noteId}: backend preimage does not settle this invoice - reconfirming`);
|
|
63
|
-
|
|
64
|
-
return;
|
|
66
|
+
return confirmThenSettle(job, deps, 'Payment failed.');
|
|
65
67
|
}
|
|
66
68
|
deps.store.finalizeMelt(job.paymentHash);
|
|
69
|
+
return { kind: 'paid' };
|
|
67
70
|
};
|
|
68
71
|
// Resolves melts an earlier process left pending - a crash mid-melt, or an
|
|
69
72
|
// outcome that could not be confirmed at the time. Melts whose attempt is
|
package/dist/server.d.ts
CHANGED
package/dist/server.js
CHANGED
|
@@ -5,7 +5,7 @@ import { applyMintFee, encodeCs1WithAmount, grossUpForMintFee, hashK1 } from '@l
|
|
|
5
5
|
import { tryDecodeBolt11 } from 'farrier-kit/bolt11';
|
|
6
6
|
import { NotePendingError, NoteStore, NoteUnavailableError, OutputCollisionError, swapFingerprint } from "./store.js";
|
|
7
7
|
import { createNoteSigner } from "./signing.js";
|
|
8
|
-
import { bearerNoteId, decodeNote, decodeSpend, spendDomainOf, verifySpend } from "./spend.js";
|
|
8
|
+
import { bearerNoteId, decodeNote, decodeSpend, encodeCp1, spendDomainOf, verifySpend } from "./spend.js";
|
|
9
9
|
import { createKernelVerifier } from "./kernel.js";
|
|
10
10
|
import { describeFee } from "./fee-words.js";
|
|
11
11
|
import { createFakeBackend } from "./backends/fake.js";
|
|
@@ -25,6 +25,10 @@ const namedRef = (value) => {
|
|
|
25
25
|
const q = decodeNote(value);
|
|
26
26
|
return q ? { q, named: HEX32.test(value) ? value : q } : null;
|
|
27
27
|
};
|
|
28
|
+
// The name a quote or receipt repeats back, in the spelling the wallet used.
|
|
29
|
+
// A wallet reads bare hex there as a bearer note's h, so a note named by its
|
|
30
|
+
// cp1 has to come back as that cp1, never as the hex of its Q.
|
|
31
|
+
const echoedName = (q, named) => (named === q ? encodeCp1(hexToBytes(q)) : named);
|
|
28
32
|
const INVALID_K1 = 'Invalid or already spent k1.';
|
|
29
33
|
// LUD-25's own reason for an output that names a note already credited.
|
|
30
34
|
const IN_USE = 'already in use';
|
|
@@ -45,6 +49,9 @@ const renamedRef = (q, name, legacy) => {
|
|
|
45
49
|
// more than a name and a note, and an unbounded read on a public endpoint
|
|
46
50
|
// is a way to run a mint out of memory.
|
|
47
51
|
const MAX_BODY_BYTES = 8 * 1024;
|
|
52
|
+
// How long a melt callback waits for the payment's outcome before answering
|
|
53
|
+
// OK. Long enough for a no-route failure, short against a wallet's timeout.
|
|
54
|
+
const MELT_ANSWER_WINDOW_MS = 2_000;
|
|
48
55
|
const readBody = async (req, limit = MAX_BODY_BYTES) => {
|
|
49
56
|
const chunks = [];
|
|
50
57
|
let size = 0;
|
|
@@ -836,7 +843,7 @@ export const createMoneyer = async (config, deps = {}) => {
|
|
|
836
843
|
// value this invoice will mint. It is only offered when /verify can
|
|
837
844
|
// later authenticate settlement with this mint's signing key.
|
|
838
845
|
...(config.verify && signer
|
|
839
|
-
? { mint: { h: commentRef.named, amount: net } }
|
|
846
|
+
? { mint: { h: echoedName(commentRef.q, commentRef.named), amount: net } }
|
|
840
847
|
: {}),
|
|
841
848
|
// Every current-draft mint quote is comment-bound, so the LUD-21
|
|
842
849
|
// preimage is ordinary settlement proof and safe to disclose after
|
|
@@ -876,19 +883,21 @@ export const createMoneyer = async (config, deps = {}) => {
|
|
|
876
883
|
preimage: preimageHex,
|
|
877
884
|
pr: invoice.pr,
|
|
878
885
|
// Repeating h and amount binds this response to the quote. The
|
|
879
|
-
//
|
|
880
|
-
//
|
|
881
|
-
//
|
|
882
|
-
//
|
|
883
|
-
//
|
|
886
|
+
// signature appears only once value exists there, and it is the
|
|
887
|
+
// note's ordinary certificate: a cs1 over its Q, which is what a
|
|
888
|
+
// receipt validator derives from the repeated name and checks.
|
|
889
|
+
// A quote from before notes were keyed by Q stored the bearer h
|
|
890
|
+
// as its output and no separate name.
|
|
884
891
|
...(currentInvoice.outputId !== null && signer
|
|
885
892
|
? (() => {
|
|
893
|
+
const legacy = currentInvoice.outputNamed === null;
|
|
894
|
+
const q = legacy ? bearerNoteId(currentInvoice.outputId) : currentInvoice.outputId;
|
|
886
895
|
const named = currentInvoice.outputNamed ?? currentInvoice.outputId;
|
|
887
896
|
return {
|
|
888
897
|
mint: {
|
|
889
|
-
h: named,
|
|
898
|
+
h: echoedName(q, named),
|
|
890
899
|
amount: currentInvoice.netMsat,
|
|
891
|
-
...(settled ? { sig:
|
|
900
|
+
...(settled ? { sig: certify(q, currentInvoice.netMsat) } : {})
|
|
892
901
|
}
|
|
893
902
|
};
|
|
894
903
|
})()
|
|
@@ -1161,17 +1170,34 @@ export const createMoneyer = async (config, deps = {}) => {
|
|
|
1161
1170
|
return fail('Invoice already used by an earlier melt - use a fresh one.');
|
|
1162
1171
|
}
|
|
1163
1172
|
inFlight.add(paymentHash);
|
|
1164
|
-
|
|
1173
|
+
const melt = runMelt({
|
|
1165
1174
|
paymentHash,
|
|
1166
1175
|
noteId: inputIds[0],
|
|
1167
1176
|
pr: pr.trim(),
|
|
1168
1177
|
amountMsat: totalMsat,
|
|
1169
1178
|
...(payAmountMsat !== null ? { payAmountMsat } : {})
|
|
1170
1179
|
}, { store, backend, feeLimitMsat: meltFeeLimitMsat, log, ...(deps.confirmDelaysMs ? { confirmDelaysMs: deps.confirmDelaysMs } : {}) })
|
|
1171
|
-
.catch(err =>
|
|
1180
|
+
.catch((err) => {
|
|
1181
|
+
log(`melt ${inputIds[0]}: ${err.message}`);
|
|
1182
|
+
return { kind: 'unresolved' };
|
|
1183
|
+
})
|
|
1172
1184
|
.finally(() => inFlight.delete(paymentHash));
|
|
1173
|
-
//
|
|
1174
|
-
//
|
|
1185
|
+
// A payment that cannot leave usually says so within a second (lnd
|
|
1186
|
+
// answers no-route before sending any HTLC), so wait briefly: a
|
|
1187
|
+
// melt the funding source has confirmed never went out is answered
|
|
1188
|
+
// with its reason, and the note is already outstanding again. Any
|
|
1189
|
+
// other outcome, or none yet, is OK as LUD-03 has it: the melt is
|
|
1190
|
+
// requested and the note reserved, never that it settled.
|
|
1191
|
+
let windowTimer;
|
|
1192
|
+
const outcome = await Promise.race([
|
|
1193
|
+
melt,
|
|
1194
|
+
new Promise(resolve => {
|
|
1195
|
+
windowTimer = setTimeout(() => resolve(null), deps.meltAnswerWindowMs ?? MELT_ANSWER_WINDOW_MS);
|
|
1196
|
+
})
|
|
1197
|
+
]);
|
|
1198
|
+
clearTimeout(windowTimer);
|
|
1199
|
+
if (outcome?.kind === 'restored')
|
|
1200
|
+
return fail(outcome.reason);
|
|
1175
1201
|
return send({
|
|
1176
1202
|
status: 'OK',
|
|
1177
1203
|
...(config.verify ? { pr: pr.trim(), verify: `${origin}/verify/${paymentHash}` } : {})
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@forgesworn/moneyer",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.18.1",
|
|
4
4
|
"description": "An LNURLcash (LUD-25) mint - strikes Lightning bearer notes. Independent implementation, cln/lnd funding sources, SQLite, zero HTTP framework.",
|
|
5
5
|
"author": "TheCryptoDonkey",
|
|
6
6
|
"license": "MIT",
|
|
@@ -74,7 +74,7 @@
|
|
|
74
74
|
"live:bound-mint": "npm run build && node scripts/live-bound-mint-check.mjs"
|
|
75
75
|
},
|
|
76
76
|
"dependencies": {
|
|
77
|
-
"@lnurlcash/kit": "0.
|
|
77
|
+
"@lnurlcash/kit": "0.20.2",
|
|
78
78
|
"@noble/curves": "^2.3.0",
|
|
79
79
|
"@noble/hashes": "^2.3.0",
|
|
80
80
|
"@scure/base": "^1.2.4",
|