lnurlcash-kit 0.1.0-next.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 +59 -0
- package/LICENSE +26 -0
- package/README.md +199 -0
- package/SECURITY.md +39 -0
- package/THREAT-MODEL.md +158 -0
- package/dist/index.d.ts +193 -0
- package/dist/index.js +708 -0
- package/llms.txt +66 -0
- package/package.json +68 -0
package/llms.txt
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# lnurlcash-kit
|
|
2
|
+
|
|
3
|
+
LNURLcash (LUD-25) bearer note client for TypeScript. ESM-only, Node 22+,
|
|
4
|
+
browsers, Deno, Bun. MIT.
|
|
5
|
+
|
|
6
|
+
Install: npm install lnurlcash-kit
|
|
7
|
+
|
|
8
|
+
## What this is
|
|
9
|
+
|
|
10
|
+
LNURLcash notes are LUD-03 withdrawRequest links whose k1 IS the asset:
|
|
11
|
+
lnurlw://mint.example/w?k1=<32-byte-hex>&amount=<msat>. Whoever knows the k1
|
|
12
|
+
can spend it. Amounts are ALWAYS integer milli-satoshis.
|
|
13
|
+
|
|
14
|
+
Draft spec: https://github.com/lnurl/luds/pull/301
|
|
15
|
+
Reference mint: https://github.com/dni/lnurl-mint
|
|
16
|
+
Reference wallet: https://github.com/dni/lnurl-wallet
|
|
17
|
+
|
|
18
|
+
## Core API
|
|
19
|
+
|
|
20
|
+
resolveNoteInput(text) -> url | null accepts bech32 LNURL, lnurlw://, https
|
|
21
|
+
fetchNoteInfo(url, opts?) -> {callback, k1, maxWithdrawable, mintPubkey?}
|
|
22
|
+
rotateNote(callback, k1, opts?) -> {k1, signature?}
|
|
23
|
+
splitNote(callback, k1s, amountMsat, opts?) -> {k1, change, signature?, changeSignature?}
|
|
24
|
+
mergeNotes(callback, k1s, opts?) -> {k1, signature?}
|
|
25
|
+
meltNote(callback, k1, bolt11, opts?) -> {pr?, verify?}
|
|
26
|
+
settleNote(baseUrl, k1, expectedMsat, sig?, opts?) -> {k1, amountMsat, signature?, callback}
|
|
27
|
+
probeBurnedNote(url, opts?) -> 'live' | 'gone' | 'unknown'
|
|
28
|
+
verifyNoteSignature(k1, amountMsat, sigHex, mintPubkeyHex) -> boolean
|
|
29
|
+
fetchPayRequest(url, opts?) / requestInvoice(cb, msat, opts?) / fetchInvoiceVerification(url, opts?)
|
|
30
|
+
parseMintFee(metadata) / applyMintFee(gross, fee) / grossUpForMintFee(net, fee)
|
|
31
|
+
createClient(opts) -> all of the above with opts bound
|
|
32
|
+
|
|
33
|
+
Options (always last): {fetch?, timeoutMs?, offline?, randomSecret?}
|
|
34
|
+
|
|
35
|
+
## Rules an implementation MUST follow
|
|
36
|
+
|
|
37
|
+
1. maxWithdrawable from fetchNoteInfo is the ONLY authoritative value. The
|
|
38
|
+
`amount` in a note URL is an unverified claim.
|
|
39
|
+
2. On rotate/split/merge the WALLET generates the replacement secret and
|
|
40
|
+
discloses only sha256(secret). Never accept a service-supplied k1.
|
|
41
|
+
3. Catch AmbiguousMutationError, PERSIST err.newSecrets before anything
|
|
42
|
+
else, then call probeBurnedNote to learn what happened. Treating it as
|
|
43
|
+
failure destroys money the service may already have minted.
|
|
44
|
+
4. RequestRefusedError means nothing was sent - safe to treat as no-op.
|
|
45
|
+
5. A melt's OK means IN FLIGHT, not spent. PendingNoteError means retry, not
|
|
46
|
+
spent.
|
|
47
|
+
6. Rotate immediately after claiming a minted note: the mint generated that
|
|
48
|
+
preimage, and LUD-21 verify exposes it to anyone who saw the invoice.
|
|
49
|
+
7. Never log note URLs. The secret is in the query string.
|
|
50
|
+
8. Never branch on error message text. Branch on the error class.
|
|
51
|
+
|
|
52
|
+
## Error classes
|
|
53
|
+
|
|
54
|
+
RequestRefusedError nothing sent, note untouched
|
|
55
|
+
ServiceRejectedError processed and refused (definitive)
|
|
56
|
+
PendingNoteError a melt is in flight on this k1 - retry
|
|
57
|
+
NoteSpentError authoritative: already burned
|
|
58
|
+
NoteUnknownError service does not recognise it
|
|
59
|
+
AmbiguousMintError outcome UNKNOWN - assume nothing
|
|
60
|
+
AmbiguousMutationError carries .newSecrets - persist them
|
|
61
|
+
ProtocolError a non-mutating response did not match the spec
|
|
62
|
+
|
|
63
|
+
## Conformance
|
|
64
|
+
|
|
65
|
+
Vectors and an adversarial mock mint:
|
|
66
|
+
https://github.com/TheCryptoDonkey/lnurlcash-conformance
|
package/package.json
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "lnurlcash-kit",
|
|
3
|
+
"version": "0.1.0-next.0",
|
|
4
|
+
"description": "LNURLcash (LUD-25) bearer note client for TypeScript - mint, rotate, split, merge, melt, and verify offline",
|
|
5
|
+
"author": "TheCryptoDonkey",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"publishConfig": {
|
|
8
|
+
"provenance": true
|
|
9
|
+
},
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "git+https://github.com/TheCryptoDonkey/lnurlcash-kit.git"
|
|
13
|
+
},
|
|
14
|
+
"homepage": "https://github.com/TheCryptoDonkey/lnurlcash-kit#readme",
|
|
15
|
+
"bugs": {
|
|
16
|
+
"url": "https://github.com/TheCryptoDonkey/lnurlcash-kit/issues"
|
|
17
|
+
},
|
|
18
|
+
"type": "module",
|
|
19
|
+
"sideEffects": false,
|
|
20
|
+
"engines": {
|
|
21
|
+
"node": ">=22"
|
|
22
|
+
},
|
|
23
|
+
"keywords": [
|
|
24
|
+
"lnurl",
|
|
25
|
+
"lnurlcash",
|
|
26
|
+
"lud-25",
|
|
27
|
+
"lightning",
|
|
28
|
+
"bitcoin",
|
|
29
|
+
"bearer",
|
|
30
|
+
"ecash"
|
|
31
|
+
],
|
|
32
|
+
"files": [
|
|
33
|
+
"dist",
|
|
34
|
+
"LICENSE",
|
|
35
|
+
"README.md",
|
|
36
|
+
"CHANGELOG.md",
|
|
37
|
+
"SECURITY.md",
|
|
38
|
+
"THREAT-MODEL.md",
|
|
39
|
+
"llms.txt"
|
|
40
|
+
],
|
|
41
|
+
"exports": {
|
|
42
|
+
".": {
|
|
43
|
+
"types": "./dist/index.d.ts",
|
|
44
|
+
"import": "./dist/index.js"
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
"scripts": {
|
|
48
|
+
"build": "tsup",
|
|
49
|
+
"test": "vitest run",
|
|
50
|
+
"test:watch": "vitest",
|
|
51
|
+
"typecheck": "tsc --noEmit",
|
|
52
|
+
"check": "npm run typecheck && npm run test && npm run build",
|
|
53
|
+
"prepare": "npm run build",
|
|
54
|
+
"prepublishOnly": "npm run check"
|
|
55
|
+
},
|
|
56
|
+
"dependencies": {
|
|
57
|
+
"@noble/curves": "^2.3.0",
|
|
58
|
+
"@noble/hashes": "^2.3.0",
|
|
59
|
+
"@scure/base": "^1.2.4"
|
|
60
|
+
},
|
|
61
|
+
"devDependencies": {
|
|
62
|
+
"@types/node": "^26.2.0",
|
|
63
|
+
"lnurlcash-conformance": "github:TheCryptoDonkey/lnurlcash-conformance",
|
|
64
|
+
"tsup": "^8.5.0",
|
|
65
|
+
"typescript": "^5.7.0",
|
|
66
|
+
"vitest": "^3.0.0"
|
|
67
|
+
}
|
|
68
|
+
}
|