feat(nut17)!: method-neutral quote subscriptions - #668
Closed
robwoodgate wants to merge 11 commits into
Closed
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## feat/nut04-05-widening #668 +/- ##
==========================================================
+ Coverage 92.35% 92.42% +0.07%
==========================================================
Files 54 54
Lines 5020 5040 +20
Branches 1238 1244 +6
==========================================================
+ Hits 4636 4658 +22
- Misses 163 165 +2
+ Partials 221 217 -4
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
robwoodgate
force-pushed
the
fix/nut17-generic-subscription-kinds-main
branch
2 times, most recently
from
May 21, 2026 23:47
efdb5df to
48feb21
Compare
robwoodgate
marked this pull request as ready for review
May 21, 2026 23:48
robwoodgate
force-pushed
the
fix/nut17-generic-subscription-kinds-main
branch
from
May 23, 2026 09:00
b868621 to
04aea5b
Compare
Implements cashubtc/nuts#377: amount_paid, amount_issued and updated_at become base mint quote response fields for every payment method. For mints that predate quote accounting, the amounts are derived from the legacy single-use state; conversely, a missing bolt11 state is derived from the accounting fields. updated_at is null when not reported. Generic mint quote responses now get base normalization (quote, request, unit, accounting) like melt quotes already did, and the wallet enforces the mintable amount (paid minus issued) for all methods, not just bolt12/onchain. BREAKING CHANGE: MintQuoteBaseResponse requires amount_paid, amount_issued and updated_at; non-conformant mint quote responses that previously passed through unvalidated now throw.
Implements the base-shape harmonization proposed on cashubtc/nuts#382: - MintQuoteBaseRequest gains optional amount and description; method NUTs tighten as needed (bolt11 requires amount). - MintQuoteBaseResponse gains expiry (normalized to null when unset), subsuming the per-method expiry fields. - MeltQuoteBaseRequest gains optional amount (onchain requires it). - MeltQuoteBaseResponse gains request and optional fee_reserve; bolt methods keep fee_reserve required. - Melt base validation now requires the payment request for every method, and normalizes fee_reserve when present. - New MintQuoteGenericResponse/MeltQuoteGenericResponse passthrough types are the defaults on the generic quote methods, so custom-method fields are reachable without casting. BREAKING CHANGE: melt quote responses without a request field now throw; generic quote methods default to the Generic response types.
…ctivity The canonical bolt11 flow is create quote -> pay externally -> mint with the original quote object, so a 0/0 accounting snapshot is indistinguishable from a stale pre-payment quote. Skip the client-side mintable-amount check in that case and let the mint decide; once amount_paid is non-zero the snapshot proves a payment event and the check applies as before.
Implements cashubtc/nuts#387: every mint and melt quote response carries a method field. The wallet always knows the method from the request endpoint, so normalization populates it when the mint omits it (no mint ships the field yet) and throws when a reported method disagrees with the endpoint. Once mints implement it, NUT-17 generic mint_quote/melt_quote notifications become routable by method.
Custom mint example reads quote progress via the accounting fields instead of state, and both generic examples note the automatic base normalization and the Generic response type defaults.
robwoodgate
force-pushed
the
fix/nut17-generic-subscription-kinds-main
branch
from
June 18, 2026 20:29
fbdb3bb to
c72201e
Compare
robwoodgate
force-pushed
the
fix/nut17-generic-subscription-kinds-main
branch
2 times, most recently
from
June 18, 2026 20:47
3e8620a to
002d5e9
Compare
Subscribe to mint/melt quote updates independent of payment method: prefer the generic mint_quote/melt_quote kinds when the mint advertises them, else fan out across the per-method kinds it advertises (bolt11, bolt12, custom) and merge them. Fanned-out kinds isolate errors, so one kind's subscribe failure no longer tears down the siblings that work. Quote event helpers are now generic over the response type (default generic), and "paid" is accounting-based (amount_paid > amount_issued) with a legacy state fallback. Builds on #698.
robwoodgate
force-pushed
the
fix/nut17-generic-subscription-kinds-main
branch
from
June 18, 2026 21:04
002d5e9 to
8af05b0
Compare
Document the fan-out fallback's intentional tradeoff: with only a quote id the wallet can't map a quote to the kind that owns it, so a subscribe rejection on the relevant kind is masked while an idle sibling keeps the alive count above zero. Add a test for that masking and one proving the once* timeoutMs escape still terminates the wait.
robwoodgate
force-pushed
the
feat/nut04-05-widening
branch
from
July 3, 2026 13:36
e8e17a6 to
6a06679
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
NUT - cashubtc/nuts#372
Summary
Makes NUT-17 quote subscriptions method-neutral.
mintQuoteUpdates/meltQuoteUpdates/mintQuotePaid/meltQuotePaidand theonce*helpers no longer assume bolt11:mint_quote/melt_quotekinds when the mint advertises them, otherwise fan out across every per-method kind it advertises for the unit (bolt11_*,bolt12_*, custom) and merge them into one stream. When both a generic and per-method kinds are advertised, only the generic one is used.MintQuoteGenericResponse/MeltQuoteGenericResponse; callers narrow (e.g.MintQuoteBolt12Response) when they know the method of the quotes they created.amount_paid>amount_issued(falling back to the legacystatefor pre-accounting mints); melt quotes usestate === PAID.RpcSubKindsenumerates the first-class kinds (generic + bolt11 + bolt12); custom<method>_*kinds are forwarded at runtime but not enumerated.Motivation
The previous implementation only handled
bolt11_*kinds, so bolt12 (NUT-25) quotes — already supported elsewhere in the wallet — could not be watched, and custom payment methods had no path at all. A per-method helper API would explode as methods are added; keeping the helpers method-neutral keeps the public surface stable while covering bolt11, bolt12, and future/custom methods.The originating wallet already knows each quote's method, so a generic payload with optional
Tnarrowing is enough for the common case. The notificationmethodfield (cashubtc/nuts#387) is additive, unlocking runtime discrimination, mixed-method subscriptions, and observers that did not create the quote.Sequencing
Builds on #698 (quote accounting + custom-method base structs). Suggested merge order: #675 → #698 → #668.