feat: nip-47 nwc wallet service engine with per-connection budgets

This commit is contained in:
2026-08-20 01:20:41 +02:00
parent 34c97708f8
commit 33318a5150
12 changed files with 2201 additions and 0 deletions
+37
View File
@@ -0,0 +1,37 @@
// The per-connection NWC budget: max msat per rolling period, persisted
// in storage/nwcConnections so a restart (or a browser crash mid-session)
// doesn't reset a client's allowance. The service serializes pay_invoice
// per connection through its request queue, which is what makes the
// check + record below atomic enough: no two pays of one connection ever
// run this concurrently.
import type {NwcConnectionRecord} from '../storage/nwcConnections'
import {persistNwcConnection} from '../storage/nwcConnections'
export const budgetRemainingMsat = (
record: NwcConnectionRecord,
nowMs: number
): number => {
const {maxMsat, periodMs} = record.budget
if (nowMs - record.spent.periodStart >= periodMs) return maxMsat
return Math.max(0, maxMsat - record.spent.msat)
}
// rolls the period when it expired, then adds the spend; persists (the
// caller's queue serialized this read-modify-write)
export const recordSpend = (
record: NwcConnectionRecord,
amountMsat: number,
nowMs: number
): NwcConnectionRecord => {
const expired = nowMs - record.spent.periodStart >= record.budget.periodMs
return persistNwcConnection({
...record,
spent: expired
? {periodStart: nowMs, msat: amountMsat}
: {
periodStart: record.spent.periodStart,
msat: record.spent.msat + amountMsat
}
})
}