lnurlcash-kit 0.5.0 → 0.6.0
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 +13 -0
- package/README.md +18 -31
- package/dist/index.js +11 -2
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## Unreleased
|
|
4
|
+
|
|
5
|
+
## 0.6.0 - 2026-08-31
|
|
6
|
+
|
|
7
|
+
- `namesMintOutput()` now requires `commentAllowed >= 64`; the additive
|
|
8
|
+
`mintToHash` advertisement alone no longer authorizes minting.
|
|
9
|
+
- `fetchPayRequest()` rejects a minting payRequest that cannot carry the
|
|
10
|
+
mandatory 64-character commitment, so a caller cannot proceed into an
|
|
11
|
+
invoice flow that has no conforming output name.
|
|
12
|
+
- Mint requests carrying an output hash continue to send identical
|
|
13
|
+
`comment` and `h` fields. Documentation now treats the former as mandatory
|
|
14
|
+
LUD-25 and the latter as the Moneyer/ForgeSworn receipt extension.
|
|
15
|
+
|
|
3
16
|
Semantic versioning. While the LUD-25 draft is unmerged, `0.x` minor bumps
|
|
4
17
|
may carry breaking changes; pin an exact version.
|
|
5
18
|
|
package/README.md
CHANGED
|
@@ -154,18 +154,10 @@ callback — it is only observable as the note becoming spendable again. Other
|
|
|
154
154
|
operations on that `k1` raise `PendingNoteError` meanwhile; retry, never
|
|
155
155
|
read it as spent.
|
|
156
156
|
|
|
157
|
-
**5.
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
the invoice. First rotater wins. A wallet that rotates on settlement wins by
|
|
162
|
-
construction; a human copying a preimage by hand does not.
|
|
163
|
-
|
|
164
|
-
That is a race, and the way to win a race is not to enter it. Where a mint
|
|
165
|
-
advertises `mintToHash`, name the note you are buying and the preimage is
|
|
166
|
-
not its secret at all: see
|
|
167
|
-
[Minting a note you named yourself](#minting-a-note-you-named-yourself).
|
|
168
|
-
The rule above stands for every mint that does not offer it.
|
|
157
|
+
**5. Persist the mint secret before requesting the invoice.** Current
|
|
158
|
+
LUD-25 requires `comment=hex(sha256(secret))`; there is no preimage-backed
|
|
159
|
+
creation fallback. If the payRequest cannot carry that 64-character comment,
|
|
160
|
+
do not mint. Existing notes still redeem through ordinary LUD-03.
|
|
169
161
|
|
|
170
162
|
## Offline verification
|
|
171
163
|
|
|
@@ -297,18 +289,19 @@ can poll LUD-21 `verify` with the payment hash inside it and take the
|
|
|
297
289
|
preimage the moment it settles, which is what a QR code on a desktop screen
|
|
298
290
|
hands out.
|
|
299
291
|
|
|
300
|
-
A mint
|
|
301
|
-
|
|
302
|
-
|
|
292
|
+
A current-draft mint binds the note to the hash supplied in the mandatory
|
|
293
|
+
LUD-12 comment. The kit repeats the same value as `h` for the additive
|
|
294
|
+
Moneyer/ForgeSworn receipt extension. You chose the secret, nobody else ever
|
|
295
|
+
had it, and the preimage is ordinary payment proof.
|
|
303
296
|
|
|
304
297
|
```ts
|
|
305
298
|
import {
|
|
306
299
|
fetchPayRequest, requestInvoice, claimMintedNote,
|
|
307
|
-
deriveNoteRoot, deriveNoteSecret, hashK1
|
|
300
|
+
deriveNoteRoot, deriveNoteSecret, hashK1, namesMintOutput
|
|
308
301
|
} from 'lnurlcash-kit'
|
|
309
302
|
|
|
310
303
|
const pay = await fetchPayRequest(payUrl) // a Lightning Address resolves here
|
|
311
|
-
if (!pay
|
|
304
|
+
if (!namesMintOutput(pay)) throw new Error('mint lacks commentAllowed: 64')
|
|
312
305
|
|
|
313
306
|
const root = deriveNoteRoot(seed)
|
|
314
307
|
const k1 = deriveNoteSecret(root, 'mint.example', nextIndex)
|
|
@@ -322,26 +315,20 @@ const claim = await claimMintedNote(pay.withdrawLink!, k1)
|
|
|
322
315
|
// 'minted' -> claim.amountMsat is what it is worth, claim.callback melts it
|
|
323
316
|
```
|
|
324
317
|
|
|
325
|
-
Ask before you buy. `
|
|
326
|
-
|
|
327
|
-
for one whose secret three other parties can learn. It turns up in three
|
|
328
|
-
places, saying three different things:
|
|
318
|
+
Ask before you buy. `commentAllowed >= 64` is the normative minting
|
|
319
|
+
capability. `mintToHash` describes only the additive `h` and receipt fields:
|
|
329
320
|
|
|
330
321
|
| Where | What it means |
|
|
331
322
|
| --- | --- |
|
|
332
|
-
| `PayRequestInfo.
|
|
323
|
+
| `PayRequestInfo.commentAllowed` | room for the mandatory hash comment; required for minting |
|
|
324
|
+
| `PayRequestInfo.mintToHash` | "I also accept the matching `h` extension." |
|
|
333
325
|
| `MintAddressInfo.mintToHash` | the same fact on the experimental discovery document |
|
|
334
326
|
| `InvoiceResult.mintToHash` | "I bound *this quote* to the hash you named" |
|
|
335
327
|
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
`
|
|
339
|
-
|
|
340
|
-
that says it in neither place ignores the `h`, keys the note by the preimage
|
|
341
|
-
as it always has, and the verify path is unchanged. Anything that is not
|
|
342
|
-
exactly `true` is a no, everywhere, and `false` on the invoice result is
|
|
343
|
-
silence rather than a refusal, so decide from the advertisement and claim by
|
|
344
|
-
probing.
|
|
328
|
+
Decide whether minting is possible from `commentAllowed` on the payRequest;
|
|
329
|
+
never substitute the mint-address extension field. Anything other than
|
|
330
|
+
boolean `true` is no for `mintToHash`, but that affects only extension receipt
|
|
331
|
+
handling. The note remains comment-bound either way.
|
|
345
332
|
|
|
346
333
|
**Persist the secret before you ask for the invoice.** Paying for a note and
|
|
347
334
|
then losing the secret is the one way this is worse than the preimage scheme,
|
package/dist/index.js
CHANGED
|
@@ -1048,14 +1048,23 @@ var fetchPayRequest = async (url, options = {}) => {
|
|
|
1048
1048
|
throw new ProtocolError("Not a payRequest (unexpected response).");
|
|
1049
1049
|
}
|
|
1050
1050
|
const mintFee = typeof body.metadata === "string" ? parseMintFee(body.metadata) : null;
|
|
1051
|
+
const commentAllowed = asNumber(body.commentAllowed);
|
|
1052
|
+
if (body.withdrawLink !== void 0 && typeof body.withdrawLink !== "string") {
|
|
1053
|
+
throw new ProtocolError("A minting payRequest has an invalid withdrawLink.");
|
|
1054
|
+
}
|
|
1055
|
+
if (typeof body.withdrawLink === "string" && !(typeof commentAllowed === "number" && commentAllowed >= 64)) {
|
|
1056
|
+
throw new ProtocolError(
|
|
1057
|
+
"A minting payRequest must allow a 64-character output commitment."
|
|
1058
|
+
);
|
|
1059
|
+
}
|
|
1051
1060
|
return {
|
|
1052
1061
|
...body,
|
|
1053
1062
|
mintFee: mintFee ?? void 0,
|
|
1054
1063
|
mintToHash: asBoolean(body.mintToHash),
|
|
1055
|
-
commentAllowed
|
|
1064
|
+
commentAllowed
|
|
1056
1065
|
};
|
|
1057
1066
|
};
|
|
1058
|
-
var namesMintOutput = (info) =>
|
|
1067
|
+
var namesMintOutput = (info) => typeof info.commentAllowed === "number" && info.commentAllowed >= 64;
|
|
1059
1068
|
var asBoundMintCommitment = (value) => {
|
|
1060
1069
|
if (!value || typeof value !== "object") return void 0;
|
|
1061
1070
|
const raw = value;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lnurlcash-kit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "LNURLcash (LUD-25) bearer note client for TypeScript - mint, rotate, split, merge, melt, and verify offline",
|
|
5
5
|
"author": "TheCryptoDonkey",
|
|
6
6
|
"license": "MIT",
|
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
},
|
|
61
61
|
"devDependencies": {
|
|
62
62
|
"@types/node": "^26.2.0",
|
|
63
|
-
"lnurlcash-conformance": "^0.
|
|
63
|
+
"lnurlcash-conformance": "^0.5.0",
|
|
64
64
|
"tsup": "^8.5.0",
|
|
65
65
|
"typescript": "^5.7.0",
|
|
66
66
|
"vitest": "^3.0.0"
|