Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 5 additions & 10 deletions 29.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ This spec describes how a wallet can mint multiple quotes in one batched operati

## 1. Batch Checking Mint Quotes

Before minting, the wallet SHOULD verify each mint quote's current accounting state. It does this by sending:
Before minting, the wallet SHOULD verify each mint quote's current accounting data. It does this by sending:

```http
POST https://mint.host:3338/v1/mint/quote/{method}/check
Expand All @@ -28,7 +28,7 @@ The wallet includes the following body in its request:

where `quotes` is an array of _unique_ mint quote IDs.

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.

For the check endpoint specifically: is an empty quotes array allowed (→ empty response)? And are duplicate IDs rejected like in batch mint (11016), or answered positionally? Both are undefined for check.


The mint returns a JSON array of mint quote objects as defined by the payment method's NUT specification. The quotes in this array MUST be in the same order as in the request.
The mint returns a JSON array of mint quote objects as defined by the payment method's NUT specification. The mint MUST omit quote IDs that it does not know or cannot parse. The quotes that are returned MUST be in the same relative order as their quote IDs in the request.
Comment thread
Egge21M marked this conversation as resolved.
Outdated

#### Example

Expand All @@ -55,7 +55,6 @@ Content-Type: application/json
"amount_paid": 100,
"amount_issued": 0,
"updated_at": 1234567800,
"state": "PAID",
"unit": "sat",
"amount": 100,
"expiry": 1234567890
Expand All @@ -66,20 +65,16 @@ Content-Type: application/json
"amount_paid": 0,
"amount_issued": 0,
"updated_at": 1234567800,
"state": "UNPAID",
"unit": "sat",
"amount": 50,
"expiry": 1234567890
}
]
```

#### Error Handling
#### Unknown or Malformed Quote IDs

This is a query endpoint that uses all-or-nothing error handling, matching the behavior of the batch mint endpoint:

- If any `quote_id` is not known by the mint, the mint MUST reject the entire request and return an appropriate error
- If any `quote_id` cannot be parsed (invalid format), the mint MUST reject the entire request and return an appropriate error
This is a query endpoint and does not use the all-or-nothing error handling of the batch mint endpoint. If a quote ID is unknown or cannot be parsed, the mint MUST omit it from the response and continue processing the other quote IDs. If none of the quote IDs can be handled, the mint MUST return an empty JSON array.
Comment thread
Egge21M marked this conversation as resolved.
Outdated

---
Comment thread
Egge21M marked this conversation as resolved.

Expand Down Expand Up @@ -192,7 +187,7 @@ The mint MUST validate the following before processing a batch mint request:
3. **Valid quote IDs**: All quote IDs MUST exist in the mint's database
4. **Payment method consistency**: All quotes MUST have the same payment method, matching `{method}` in the URL path
5. **Currency unit consistency**: All quotes MUST use the same currency unit
6. **Quote state**: All quotes MUST be in PAID state (or have a mintable amount for payment methods that allow multiple mint operations like bolt12)
6. **Mintable amount**: All quotes MUST have a positive currently mintable amount (`amount_paid - amount_issued`)

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.

Dropping the PAID-state rule also drops any mention of expiry from mint validation: nothing in this list says whether an expired (but paid) quote can still be batch-minted. Some mints will reject, some won't — should be stated explicitly, especially since the check section now requires returning expired quotes.

7. **Amount balance**: The sum of amounts contained in the `outputs` MUST equal the sum of `quote_amounts` (bolt11) or MUST NOT exceed it (bolt12)

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.

With rule 6 loosened to "positive mintable amount", a batch can now include an already partially-minted bolt11 quote — but this equality check doesn't say what the target is in that case: the quote's original amount, or its currently mintable amount (amount_paid - amount_issued)? If it's the original amount, a mint can be pushed past NUT-04's cap. Worth defining, including what quote_amounts means for a partially-issued quote.

8. **Signature validation (NUT-20)**: The `signatures` array length MUST match the `quotes` array length; locked quotes MUST include a valid signature; unlocked quotes MUST NOT include one

Expand Down
30 changes: 21 additions & 9 deletions tests/29-tests.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,23 +20,35 @@ The following is the corresponding response with a blind signature.
}
```

## Check endpoint with unknown quotes
## Check endpoint omits unknown and malformed quotes
Comment thread
Egge21M marked this conversation as resolved.
Outdated

The following is an invalid check request containing an unknown quote ID.
The following check request contains two known quote IDs, one malformed quote ID, and one unknown quote ID.

```json
{ "quotes": ["known-1", "bogus", "unknown-2"] }
{ "quotes": ["known-1", "not-a-valid-quote-id", "unknown-2", "known-2"] }
```

Per NUT-29, quote check uses all-or-nothing error handling. If any quote is unknown, the entire request must be rejected.
The mint omits the malformed and unknown quote IDs. It returns the known quotes in the same relative order as their IDs in the request.
Comment thread
Egge21M marked this conversation as resolved.
Outdated

```json
{
"code": "UNKNOWN_QUOTE",
"error": "one or more quote IDs are unknown"
}
[
{
"quote": "known-1",
"amount_paid": 5,
"amount_issued": 0,
"updated_at": 1234567800
},
{
"quote": "known-2",
"amount_paid": 0,
"amount_issued": 0,
"updated_at": 1234567800
}
]
Comment thread
Egge21M marked this conversation as resolved.
```

If the mint cannot handle any of the requested quote IDs, it returns an empty JSON array.

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.

Suggested change
If the mint cannot handle any of the requested quote IDs, it returns an empty JSON array.
If the mint cannot handle any of the requested quote IDs, every entry in the response is an `unknown` entry. The response is never shorter than the request.

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.

In CTS, I have a failIf(quotes.length != responses.length), so if the view is to make an exception for fully failed lookup, I will need to loosen that.

@a1denvalu3 a1denvalu3 Aug 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.

This contradicts 29.md: the spec now says a successful response always has exactly one entry per requested ID, but this line still says an empty array is returned. An empty response to a non-empty request breaks the positional contract. Shouldn't this read that every entry is an unknown entry (response never shorter than the request)?

EDIT: just needs to be updated ig


## Batch mint atomic failure

The following is an invalid batch mint request containing one unknown quote ID, causing the entire batch to fail atomically with no partial minting.
Expand All @@ -52,7 +64,7 @@ Expected behavior:

- The mint rejects the whole request with an error.
- No outputs are signed.
- No quote state is consumed/changed by partial processing.
- No quote's `amount_issued` is increased by partial processing.

## Batch mint rejects empty quotes array

Expand Down
Loading