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 +32 -0
- package/README.md +4 -0
- package/dist/index.d.ts +7 -1
- package/dist/index.js +21 -3
- package/package.json +2 -2
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 {
|
|
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.
|
|
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": "
|
|
63
|
+
"lnurlcash-conformance": "^0.1.1",
|
|
64
64
|
"tsup": "^8.5.0",
|
|
65
65
|
"typescript": "^5.7.0",
|
|
66
66
|
"vitest": "^3.0.0"
|