Skip to content

Align NUT-04 mint quote accounting with amount_paid / amount_issued#377

Open
Egge21M wants to merge 1 commit into
cashubtc:mainfrom
Egge21M:generic-paid-issued
Open

Align NUT-04 mint quote accounting with amount_paid / amount_issued#377
Egge21M wants to merge 1 commit into
cashubtc:mainfrom
Egge21M:generic-paid-issued

Conversation

@Egge21M

@Egge21M Egge21M commented May 24, 2026

Copy link
Copy Markdown
Contributor

This updates NUT-04 to make amount_paid and amount_issued the
canonical way to track mint quote accounting, matching the reusable
quote model already used by NUT-25 and NUT-30.

The deprecated state field is kept as an optional compatibility
field for single-use quotes, with derivation rules documented from
amount_paid and amount_issued. This also adds updated_at to mint
quote responses so clients can avoid applying stale quote updates.

Changes:

  • Define common amount_paid, amount_issued, and updated_at fields in
    NUT-04 mint quote responses
  • Document mintable amount as amount_paid - amount_issued
  • Deprecate state while preserving compatibility guidance
  • Add stale-update handling guidance using updated_at
  • Update NUT-20, NUT-23, NUT-25, NUT-29, and NUT-30 examples/schemas
    to match

@robwoodgate

This comment was marked as outdated.

@robwoodgate

Copy link
Copy Markdown
Contributor

The updated_at param is a good idea, both for monotonic state tracking as noted, as well as being potentially useful for tracking stalled or failed payments.

@a1denvalu3

Copy link
Copy Markdown
Contributor

Agreed.

@robwoodgate robwoodgate left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

ACK

@Egge21M

Egge21M commented Jun 8, 2026

Copy link
Copy Markdown
Contributor Author

Chatted with some folks offline. They raised the point that the combination of amount_issued and amount_paid is already enough to allow monotonic state updates (e.g. new_amount_issued + new_amount_paid > old_amount_issued + old_amount_paid). However this is less explicit and mints should not have any issue adding updated_at.

Should I kick it, or keep it?

@robwoodgate

Copy link
Copy Markdown
Contributor

Chatted with some folks offline. They raised the point that the combination of amount_issued and amount_paid is already enough to allow monotonic state updates (e.g. new_amount_issued + new_amount_paid > old_amount_issued + old_amount_paid). However this is less explicit and mints should not have any issue adding updated_at.

Should I kick it, or keep it?

I think it has utility - whilst the combination does tell you if the state has changed, it doesn't tell you WHEN.

So unless payload size is a concern, it might be more useful than not, esp for consumer apps.

@Egge21M Egge21M force-pushed the generic-paid-issued branch from d251850 to 4f4f697 Compare June 9, 2026 09:48
@thesimplekid thesimplekid self-requested a review June 9, 2026 14:48
Comment thread 04.md

For reusable quotes, no finite `state` can fully represent whether the quote may receive future payments. Wallets **MUST** use `amount_paid` and `amount_issued` to determine the currently mintable amount.

Mints **MUST** update `updated_at` whenever `amount_paid` or `amount_issued` changes. Mints **SHOULD** ensure that `updated_at` monotonically increases for each quote, even if multiple updates occur within the same timestamp resolution. Wallets that receive multiple responses for the same quote **MUST NOT** replace locally stored quote data with a response whose `updated_at` is lower than the latest processed value for that quote. Wallets **MUST NOT** decrease locally stored `amount_paid` or `amount_issued` values based on stale responses.

@robwoodgate robwoodgate Jun 12, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Have implemented this in cashu-ts (cashubtc/cashu-ts#693). The derivation rules round-trip cleanly in both directions, so transition handling is straightforward.

The only wrinkle is how to handle the case when updated_at is absent (any pre-accounting mint). Suggest we add:

Suggested change
Mints **MUST** update `updated_at` whenever `amount_paid` or `amount_issued` changes. Mints **SHOULD** ensure that `updated_at` monotonically increases for each quote, even if multiple updates occur within the same timestamp resolution. Wallets that receive multiple responses for the same quote **MUST NOT** replace locally stored quote data with a response whose `updated_at` is lower than the latest processed value for that quote. Wallets **MUST NOT** decrease locally stored `amount_paid` or `amount_issued` values based on stale responses.
Mints **MUST** update `updated_at` whenever `amount_paid` or `amount_issued` changes. Mints **SHOULD** ensure that `updated_at` monotonically increases for each quote, even if multiple updates occur within the same timestamp resolution. Wallets that receive multiple responses for the same quote **MUST NOT** replace locally stored quote data with a response whose `updated_at` is lower than the latest processed value for that quote. Wallets **MUST NOT** decrease locally stored `amount_paid` or `amount_issued` values based on stale responses, or when the response has no `updated_at` value.

robwoodgate added a commit to robwoodgate/cashu-ts that referenced this pull request Jun 12, 2026
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.
robwoodgate added a commit to robwoodgate/cashu-ts that referenced this pull request Jun 12, 2026
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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Backlog

Development

Successfully merging this pull request may close these issues.

5 participants