Lightning payment primitives · v1.1.3
Decode it. Prove it.
Then believe it.
farrier-kit is the read-and-verify layer for Lightning: what an invoice commits to, whether a preimage proves it was paid, and whether a URL is safe to fetch. Browser and Node run the same code, and the bench below is that code, in your browser, right now.
npm install farrier-kit
The sample is a BOLT-11 specification vector: unsigned, long expired and worth nothing. Change one character of it and watch the checksum refuse.
Generate a pair, then change one character of either field. The comparison is constant-time, so a near-miss takes exactly as long to reject as a wild one.
Load the set, then change the amount. The hash still matches and the gate still refuses, which is the entire point of the amount check.
Try http://example.com, https://10.0.0.1/x,
https://user:pw@example.com, https://localhost./x,
or alice@Wallet.Example.COM.
The vectors, run here, now
farrier-kit ships language-neutral conformance vectors so a port can prove it agrees byte for byte. They are not a private test fixture: they are the contract, and this button runs the whole file set against the bundle you would install.
Tier 1 is correctness, tier 2 is policy. A conformant decoder must match tier 1. Tier 2 is farrier-kit refusing things the spec merely leaves open — an ambiguous amount in the human-readable part, a numeric field that would overflow — and a port that wants security parity should match those too. The next milestone is a Kotlin build of the pure surface checked against these same files, so a native Android app verifies a payment identically to the web.
The narrow slice
Most Lightning libraries either just decode invoices or are whole wallet toolkits. farrier-kit takes the security-critical gap they leave: safely resolving where to pay, and proving that a payment happened.
/bolt11- Amount, payment hash, network, expiry, description and description hash. No signature recovery and no route hints, because a payer's wallet does that. It answers one question: what does this invoice commit to?
/preimage-
payment_hash = SHA-256(preimage), compared in constant time. This is the only thing that proves a payment settled, and it is the check most integrations skip. /lnurl- LUD-06 and LUD-16 resolution, LUD-21 verification, an SSRF guard and a four-way gate on the invoice that comes back — amount, description hash, network and payment hash all checked before it reaches you.
/http- A timeout- and size-capped, redirect-safe JSON fetch. Every one of those limits exists because an untrusted endpoint is on the other end.
/node- The one Node-only entry: DNS-pinned fetch, so a hostname that resolves inward is caught where the browser cannot look. Gated out of the browser bundle and never reachable from the root.
Not in scope, deliberately
- Sending a payment, or any wallet function
- WebLN, boostagrams, L402, BIP-21
- NWC and wallet transport — that is nwc-kit
- General Nostr cryptography
- Fiat pricing and unrelated handle formats
An invoice's payment_hash alone is not a commitment. The payee picks
the preimage, so they can mint a second invoice carrying the same hash and a different
amount. Pass the agreed amount to verifyInvoiceCommitment whenever real
money is about to move; the bench's third tab exists to make that failure visible.
The rest of the rail
Each of these does one job and refuses the next one. Together they are a payment rail an application can assemble itself, without any single piece asking to be trusted with everything.
farrier-kit
The money checks. Decode, prove, and gate what you are about to fetch. You are here.
farrier-kitnwc-kit
The wallet connection. NIP-47 over NIP-44 v2, authenticated, with the relay untrusted.
@forgesworn/nwc-kittoll-booth
The other side of the counter. L402 middleware that makes any API payable in one line.
@forgesworn/toll-booth402-mcp
The agent's end. Discovers, pays for and consumes L402 APIs across the rail.
402-mcp