Skip to content

NUT-04/05: custom payment methods#382

Open
asmogo wants to merge 10 commits into
cashubtc:mainfrom
asmogo:generic-payment-method
Open

NUT-04/05: custom payment methods#382
asmogo wants to merge 10 commits into
cashubtc:mainfrom
asmogo:generic-payment-method

Conversation

@asmogo

@asmogo asmogo commented May 27, 2026

Copy link
Copy Markdown
Contributor

Implementations

support custom payment methods not defined in a dedicated NUT.

@robwoodgate robwoodgate left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is a fantastic step forward for wallets to be able to better support unknown methods - I've added some suggested tweaks to the base structs to make life even better.

Comment thread 04.md Outdated
Comment thread 05.md Outdated
Comment thread 04.md
Comment thread 04.md
Comment thread 05.md
Comment thread 05.md Outdated
@robwoodgate

Copy link
Copy Markdown
Collaborator

Sorry @asmogo - I questioned an earlier draft that included method in the quote structs (thinking mint and wallet know by virtue of the endpoint used to request it), but this related issue highlights that for WS, and especially with the suggestion on harmonizing the base structs for custom methods, the distinction is easy to blur/lose.

So maybe we DO need to include method: <str>, in the quote structs for both mint and melt.

@robwoodgate

Copy link
Copy Markdown
Collaborator

Related #377

which adds the amount_oaid, amount_issued, updated_at parms to default quote structs

@robwoodgate robwoodgate left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have implemented custom method support in cashu-ts on top of this + #377 + #387 (cashubtc/cashu-ts#698) and it works nicely. Wallets can quote, mint and melt methods they don't fully understand using just the base structs.

A few tweaks below that came out of implementing. Note the suggestions assume #377 merges first.

Related to my base struct suggestions above: expiry really wants to be in the common mint quote response - every method has one, and a wallet showing a quote for an unknown method needs to know when to stop polling. With #377 in, it's the only field from the suggested base response still left as method-specific.

(method in the quote structs is now covered by #387, which also resolves the WS routing question from #378.)

Can also confirm the optional fee_reserve in the melt base works in practice - onchain can't make it required (it uses fee_options), and bolt11/12 tighten it to required in their own NUTs.

Comment thread 04.md Outdated
Comment thread 05.md Outdated
robwoodgate added a commit to robwoodgate/cashu-ts that referenced this pull request Jun 12, 2026
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.
robwoodgate added a commit to robwoodgate/cashu-ts that referenced this pull request Jun 12, 2026
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.
Consolidates review feedback on the generic payment method PR. Scoped to
the delta NOT covered by cashubtc#377 (accounting fields) or cashubtc#387 (method), so
those can merge independently:

- common mint quote request: optional amount, description, pubkey
- common melt quote request: optional amount
- common mint quote response: expiry, optional pubkey
- common melt quote response: request, optional fee_reserve
- custom mint quotes MUST carry the accounting fields
- custom melt quotes MUST use the standard UNPAID/PENDING/PAID states
@robwoodgate

Copy link
Copy Markdown
Collaborator

Added asmogo#1 with my suggestions ready to merge into this PR if acceptable.

Comment thread 04.md Outdated

@robwoodgate robwoodgate left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@robwoodgate robwoodgate requested a review from callebtc July 3, 2026 12:52
robwoodgate added a commit to cashubtc/cashu-ts that referenced this pull request Jul 3, 2026
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.
@callebtc callebtc changed the title custom payment methods NUT-04/05: custom payment methods Jul 4, 2026
@robwoodgate

Copy link
Copy Markdown
Collaborator

@callebtc - I've fixed the merge conflicts in this one.

robwoodgate added a commit to cashubtc/cashu-ts that referenced this pull request Jul 8, 2026
…cts (#698)

Matures the NUT-04/05 base payloads so wallets can handle generic and
custom payment methods, implementing:

- **cashubtc/nuts#377** — mint quote accounting: `amount_paid`,
`amount_issued` and `updated_at` become base mint quote response fields
for every payment method; `state` is deprecated (but always populated
for bolt11).
- **cashubtc/nuts#382** — custom payment methods: base request/response
structs widened per the shapes suggested in review, generic quote
responses get base normalization + validation, and new
`MintQuoteGenericResponse` / `MeltQuoteGenericResponse` passthrough
types are the defaults on the generic quote methods so custom-method
fields are reachable without casting.

- **cashubtc/nuts#387** — every quote response carries a `method` field:
populated from the request endpoint when the mint omits it (no mint
ships it yet), throwing when a reported method disagrees with the
endpoint. Once mints implement it, NUT-17 generic
`mint_quote`/`melt_quote` notifications become routable by method.

Follows up on #672 (nuts#374 `method_name`), which already merged.

## Design notes

- **Required-but-derived accounting.** For mints that predate quote
accounting, `amount_paid`/`amount_issued` are derived from the legacy
single-use `state` + `amount` (UNPAID → 0/0, PAID → amount/0, ISSUED →
amount/amount); conversely a missing bolt11 `state` is derived from the
accounting fields. Underivable responses throw, matching the existing
melt-side strictness. `updated_at` is `number | null` (null when the
mint does not report it — it cannot be derived).
- **Base shapes per the nuts#382 review suggestions.** Mint quote
request base gains optional `amount`/`description`; `expiry` moves into
the mint quote response base (normalized to `null` when unset); melt
quote request base gains optional `amount`; melt quote response base
gains required `request` and optional `fee_reserve` (bolt methods keep
it required, onchain keeps `fee_options`).
- **Mintable amount enforced for all methods.**
`validateMintQuoteAvailableAmount` loses its bolt12/onchain gate:
mintable = `amount_paid − amount_issued` is checked whenever the quote
object carries accounting fields. Stored quotes without them
(pre-accounting) skip the check, as before.
- Method-id validation (`^[a-z0-9_-]+$`) and the generic
`/v1/{mint,melt}/quote/{method}` plumbing already existed and are
unchanged.

## Breaking changes

- `MintQuoteBaseResponse` requires `amount_paid`, `amount_issued`,
`updated_at`, `expiry`; `MeltQuoteBaseResponse` requires `request`.
Type-breaking for code constructing quote literals; runtime consumers
are unaffected because normalization guarantees the fields.
- Non-conformant quote responses that previously passed through
unvalidated (mint quotes missing `quote`/`request`/`unit` or underivable
accounting; melt quotes missing `request`) now throw `Invalid response
from mint`.
Comment thread 04.md
Comment thread 04.md Outdated
Comment thread 04.md Outdated
Comment thread 04.md Outdated
Comment thread 04.md Outdated
Comment thread 05.md Outdated
@robwoodgate robwoodgate requested a review from thesimplekid July 10, 2026 12:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Backlog

Development

Successfully merging this pull request may close these issues.

5 participants