lnurlcash-kit 0.1.0 → 0.1.2

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 CHANGED
@@ -3,6 +3,38 @@
3
3
  Semantic versioning. While the LUD-25 draft is unmerged, `0.x` minor bumps
4
4
  may carry breaking changes; pin an exact version.
5
5
 
6
+ ## 0.1.2 - 2026-08-21
7
+
8
+ - `mintFeeBand` and `withinMintFeeBand`. LUD-25 states the mint fee as
9
+ `base_fee_msat` plus a ppm cut and says nothing about rounding, and the
10
+ two live implementations read that differently: dni's lnurl-mint - the
11
+ reference, and what every public mint on the awesome list except moneyer
12
+ runs - ceilings the fee to a whole sat on purpose so the mint is "never
13
+ short a sat", while moneyer withholds the msat-exact amount.
14
+ - So `applyMintFee` is right about exactly one of them, and a wallet
15
+ comparing a credited note against it warns spuriously against the other.
16
+ Measured on real sats: 40,000 msat at a 1000 + 1000 ppm mint credited
17
+ 38,000, not the 38,960 the formula gives.
18
+ - `mintFeeBand` returns the range - the formula is the most a holder can be
19
+ credited, the sat-ceilinged fee the least - and `withinMintFeeBand` is
20
+ what a caller should compare against. `applyMintFee` is unchanged and
21
+ still means the formula; it is now documented as the generous edge rather
22
+ than the answer.
23
+ - Nothing here decides which reading is correct. That is a question for
24
+ lnurl/luds#301.
25
+
26
+ ## 0.1.1 - 2026-08-20
27
+
28
+ - `fetchMintAddress` now populates `nodeCapacityMsat`. The wire field is
29
+ `nodeCapacity`, and the response was spread through unmapped, so the typed
30
+ field was always `undefined` - inherited from lnurl-wallet, where the same
31
+ bug hides the mint's channel capacity in the UI. `nodeNumChannels` and
32
+ `nodeNumPeers` were never affected: those names match the wire.
33
+ - The conformance vectors now come from the published
34
+ `lnurlcash-conformance` package rather than a git ref, so the suite runs
35
+ against a released, attested set of vectors. Test-only; nothing consumers
36
+ install changes.
37
+
6
38
  ## 0.1.0 - 2026-08-20
7
39
 
8
40
  First release. The protocol layer of
package/README.md CHANGED
@@ -178,6 +178,10 @@ The reference implementations, both dni's, both MIT:
178
178
  - [lnurl-mint](https://github.com/dni/lnurl-mint) — the reference service
179
179
  - [lnurl-wallet](https://github.com/dni/lnurl-wallet) — the reference wallet
180
180
 
181
+ Everything else built on LNURLcash — the other wallets and mints, the
182
+ hardware vault, the sibling language ports — is indexed in
183
+ [awesome-lnurlcash](https://github.com/TheCryptoDonkey/awesome-lnurlcash).
184
+
181
185
  Changes made on extraction are listed in [CHANGELOG.md](CHANGELOG.md); two
182
186
  are behavioural fixes worth reading if you are porting from that code.
183
187
 
package/dist/index.d.ts CHANGED
@@ -36,6 +36,12 @@ type MintFee = {
36
36
  };
37
37
  declare const parseMintFee: (metadata: string) => MintFee | null;
38
38
  declare const applyMintFee: (grossMsat: number, fee: MintFee) => number;
39
+ type MintFeeBand = {
40
+ minNetMsat: number;
41
+ maxNetMsat: number;
42
+ };
43
+ declare const mintFeeBand: (grossMsat: number, fee: MintFee) => MintFeeBand;
44
+ declare const withinMintFeeBand: (grossMsat: number, netMsat: number, fee: MintFee) => boolean;
39
45
  declare const grossUpForMintFee: (netMsat: number, fee: MintFee) => number;
40
46
  declare const formatFeePercent: (ppm: number) => string;
41
47
  declare const describeMintFee: (fee: MintFee) => string;
@@ -190,4 +196,4 @@ declare const createClient: (options?: LnurlcashOptions) => {
190
196
  };
191
197
  type LnurlcashClient = ReturnType<typeof createClient>;
192
198
 
193
- export { AmbiguousMintError, AmbiguousMutationError, type HashedMutationResult, type HashedSplitResult, type InvoiceResult, type LnurlcashClient, LnurlcashError, type LnurlcashOptions, type MeltResult, type MintAddressInfo, type MintFee, NoteSpentError, NoteUnknownError, type PayRequestInfo, PendingNoteError, ProtocolError, type RandomSecret, RequestRefusedError, type RotateResult, ServiceRejectedError, type SettledNote, type SplitResult, type VerifyResult, type WithdrawRequestInfo, type WithdrawSuccessResponse, applyMintFee, buildNoteUrl, classifyNoteError, createClient, decodeBolt11AmountMsat, defaultRandomSecret, describeMintFee, fetchInvoiceVerification, fetchMintAddress, fetchNoteInfo, fetchPayRequest, formatFeePercent, fromBech32Lnurl, fromLud17, grossUpForMintFee, hashK1, isAllowedServiceUrl, isBech32Lnurl, isBolt11Invoice, isLightningAddress, isPreimage, isValidNoteInput, lightningAddressUsername, meltNote, mergeNotes, mergeNotesWithHash, mintAddressUrl, noteDeclaredAmount, noteK1, noteSignature, noteSignatureDigest, noteSignatureMessage, parseMintFee, probeBurnedNote, requestInvoice, requireNoteK1, resolveLnurlInput, resolveMintInput, resolveNoteInput, rotateNote, rotateNoteWithHash, sameInvoice, serverOf, settleNote, splitNote, splitNoteWithHash, toBech32Lnurl, toLud17w, verifyNoteSignature, withNewK1, withoutK1 };
199
+ export { AmbiguousMintError, AmbiguousMutationError, type HashedMutationResult, type HashedSplitResult, type InvoiceResult, type LnurlcashClient, LnurlcashError, type LnurlcashOptions, type MeltResult, type MintAddressInfo, type MintFee, type MintFeeBand, NoteSpentError, NoteUnknownError, type PayRequestInfo, PendingNoteError, ProtocolError, type RandomSecret, RequestRefusedError, type RotateResult, ServiceRejectedError, type SettledNote, type SplitResult, type VerifyResult, type WithdrawRequestInfo, type WithdrawSuccessResponse, applyMintFee, buildNoteUrl, classifyNoteError, createClient, decodeBolt11AmountMsat, defaultRandomSecret, describeMintFee, fetchInvoiceVerification, fetchMintAddress, fetchNoteInfo, fetchPayRequest, formatFeePercent, fromBech32Lnurl, fromLud17, grossUpForMintFee, hashK1, isAllowedServiceUrl, isBech32Lnurl, isBolt11Invoice, isLightningAddress, isPreimage, isValidNoteInput, lightningAddressUsername, meltNote, mergeNotes, mergeNotesWithHash, mintAddressUrl, mintFeeBand, noteDeclaredAmount, noteK1, noteSignature, noteSignatureDigest, noteSignatureMessage, parseMintFee, probeBurnedNote, requestInvoice, requireNoteK1, resolveLnurlInput, resolveMintInput, resolveNoteInput, rotateNote, rotateNoteWithHash, sameInvoice, serverOf, settleNote, splitNote, splitNoteWithHash, toBech32Lnurl, toLud17w, verifyNoteSignature, withNewK1, withinMintFeeBand, withoutK1 };
package/dist/index.js CHANGED
@@ -253,6 +253,18 @@ var parseMintFee = (metadata) => {
253
253
  };
254
254
  var proportionalFee = (grossMsat, feePpm) => Math.floor(grossMsat / 1e6) * feePpm + Math.floor(grossMsat % 1e6 * feePpm / 1e6);
255
255
  var applyMintFee = (grossMsat, fee) => Math.max(0, grossMsat - fee.baseFeeMsat - proportionalFee(grossMsat, fee.feePpm));
256
+ var mintFeeBand = (grossMsat, fee) => {
257
+ const exactFee = fee.baseFeeMsat + proportionalFee(grossMsat, fee.feePpm);
258
+ const satCeilinged = Math.ceil(exactFee / 1e3) * 1e3;
259
+ return {
260
+ minNetMsat: Math.max(0, grossMsat - satCeilinged),
261
+ maxNetMsat: Math.max(0, grossMsat - exactFee)
262
+ };
263
+ };
264
+ var withinMintFeeBand = (grossMsat, netMsat, fee) => {
265
+ const { minNetMsat, maxNetMsat } = mintFeeBand(grossMsat, fee);
266
+ return netMsat >= minNetMsat && netMsat <= maxNetMsat;
267
+ };
256
268
  var grossUpForMintFee = (netMsat, fee) => {
257
269
  if (netMsat <= 0) return 0;
258
270
  let hi = netMsat + fee.baseFeeMsat;
@@ -494,8 +506,14 @@ var fetchMintAddress = async (url, options = {}) => {
494
506
  if (body?.tag !== "withdrawRequest" || typeof body.callback !== "string" || typeof body.payLink !== "string" || typeof body.maxWithdrawable !== "number") {
495
507
  throw new ProtocolError("Not a mint address response (unexpected shape).");
496
508
  }
497
- const { mintPubkey, ...rest } = body;
498
- return { ...rest, nodePubkey: mintPubkey };
509
+ const { mintPubkey, nodeCapacity, ...rest } = body;
510
+ return {
511
+ ...rest,
512
+ nodePubkey: mintPubkey,
513
+ // Renamed fields have to be mapped, not spread: the spread carries the
514
+ // wire name through, so the typed one would read undefined forever.
515
+ nodeCapacityMsat: typeof nodeCapacity === "number" ? nodeCapacity : void 0
516
+ };
499
517
  };
500
518
  var callbackRequest = async (callback, params, options) => {
501
519
  const opts = resolveOptions(options);
@@ -705,4 +723,4 @@ var createClient = (options = {}) => ({
705
723
  fetchInvoiceVerification: (verifyUrl) => fetchInvoiceVerification(verifyUrl, options)
706
724
  });
707
725
 
708
- export { AmbiguousMintError, AmbiguousMutationError, LnurlcashError, NoteSpentError, NoteUnknownError, PendingNoteError, ProtocolError, RequestRefusedError, ServiceRejectedError, applyMintFee, buildNoteUrl, classifyNoteError, createClient, decodeBolt11AmountMsat, defaultRandomSecret, describeMintFee, fetchInvoiceVerification, fetchMintAddress, fetchNoteInfo, fetchPayRequest, formatFeePercent, fromBech32Lnurl, fromLud17, grossUpForMintFee, hashK1, isAllowedServiceUrl, isBech32Lnurl, isBolt11Invoice, isLightningAddress, isPreimage, isValidNoteInput, lightningAddressUsername, meltNote, mergeNotes, mergeNotesWithHash, mintAddressUrl, noteDeclaredAmount, noteK1, noteSignature, noteSignatureDigest, noteSignatureMessage, parseMintFee, probeBurnedNote, requestInvoice, requireNoteK1, resolveLnurlInput, resolveMintInput, resolveNoteInput, rotateNote, rotateNoteWithHash, sameInvoice, serverOf, settleNote, splitNote, splitNoteWithHash, toBech32Lnurl, toLud17w, verifyNoteSignature, withNewK1, withoutK1 };
726
+ export { AmbiguousMintError, AmbiguousMutationError, LnurlcashError, NoteSpentError, NoteUnknownError, PendingNoteError, ProtocolError, RequestRefusedError, ServiceRejectedError, applyMintFee, buildNoteUrl, classifyNoteError, createClient, decodeBolt11AmountMsat, defaultRandomSecret, describeMintFee, fetchInvoiceVerification, fetchMintAddress, fetchNoteInfo, fetchPayRequest, formatFeePercent, fromBech32Lnurl, fromLud17, grossUpForMintFee, hashK1, isAllowedServiceUrl, isBech32Lnurl, isBolt11Invoice, isLightningAddress, isPreimage, isValidNoteInput, lightningAddressUsername, meltNote, mergeNotes, mergeNotesWithHash, mintAddressUrl, mintFeeBand, noteDeclaredAmount, noteK1, noteSignature, noteSignatureDigest, noteSignatureMessage, parseMintFee, probeBurnedNote, requestInvoice, requireNoteK1, resolveLnurlInput, resolveMintInput, resolveNoteInput, rotateNote, rotateNoteWithHash, sameInvoice, serverOf, settleNote, splitNote, splitNoteWithHash, toBech32Lnurl, toLud17w, verifyNoteSignature, withNewK1, withinMintFeeBand, withoutK1 };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lnurlcash-kit",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
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": "github:TheCryptoDonkey/lnurlcash-conformance",
63
+ "lnurlcash-conformance": "^0.1.1",
64
64
  "tsup": "^8.5.0",
65
65
  "typescript": "^5.7.0",
66
66
  "vitest": "^3.0.0"