From cad8cad4bcc7a39dcb1c812987a2fe3986ead7db Mon Sep 17 00:00:00 2001 From: Rob Woodgate Date: Wed, 18 Feb 2026 21:12:53 +0000 Subject: [PATCH 1/2] define UInt64Json, int, u64. Use UInt64Json for JSON amounts --- 00.md | 23 ++++++++++++++++++----- 01.md | 2 +- 04.md | 4 ++-- 05.md | 8 ++++---- 08.md | 2 +- 11.md | 2 +- 12.md | 4 ++-- 15.md | 2 +- 18.md | 4 ++-- 20.md | 2 +- 23.md | 10 +++++----- 24.md | 5 +++-- 25.md | 22 +++++++++++----------- 28.md | 2 +- 14 files changed, 53 insertions(+), 39 deletions(-) diff --git a/00.md b/00.md index d7184a73..035cfc65 100644 --- a/00.md +++ b/00.md @@ -56,11 +56,24 @@ These specifications use elliptic curve public key cryptography over the field a ### Types -Values in these specification are one of: +Values in this specification are one of: - Scalars: integers modulo the curve order `n` - Curve points: elements of the elliptic curve group (including the identity point at infinity) - Byte sequences +- `int` / `u64`: unsigned 64-bit integer in the range: `0..2^64-1`. + +#### UInt64Json + +For JSON fields, `int` / `u64` values are encoded as `UInt64Json`. + +`UInt64Json` **MAY** be represented as a JSON integer number or a base-10 decimal string. + +Implementations **MUST** accept both forms. + +Values greater than `9007199254740991 (2^53-1)` **MUST** be represented as decimal strings. + +This preserves integer precision in environments where JSON numbers use IEEE-754. ### Byte Operations And Encodings @@ -82,7 +95,7 @@ An encrypted ("blinded") secret and an amount is sent from `Alice` to `Bob` for ```json { - "amount": int, + "amount": UInt64Json, "id": hex_str, "B_": hex_str } @@ -96,7 +109,7 @@ A `BlindSignature` is sent from `Bob` to `Alice` after [minting tokens][04] or a ```json { - "amount": int, + "amount": UInt64Json, "id": hex_str, "C_": hex_str } @@ -110,7 +123,7 @@ A `Proof` is also called an _input_ and is generated by `Alice` from a `BlindSig ```json { - "amount": int, + "amount": UInt64Json, "id": hex_str, "secret": str, "C": hex_str, @@ -260,7 +273,7 @@ For readability, the structure of a TokenV4 object is shown below in its equival "i": bytes, // keyset ID (short or long form) "p": [ // proofs with this keyset ID { - "a": int, // amount + "a": UInt64Json, // amount "s": str, // secret "c": bytes, // signature "d": { // optional DLEQ proof diff --git a/01.md b/01.md index 5a85bd2d..5ce8e3d1 100644 --- a/01.md +++ b/01.md @@ -67,7 +67,7 @@ Response `GetKeysResponse` of `Bob`: "input_fee_ppk": , "final_expiry": "keys": { - : , + : , ... } } diff --git a/04.md b/04.md index 2353daaf..305c571c 100644 --- a/04.md +++ b/04.md @@ -132,8 +132,8 @@ The settings for this NUT indicate the supported method-unit pairs for minting. { "method": , "unit": , - "min_amount": , - "max_amount": , + "min_amount": , + "max_amount": , "options": } ``` diff --git a/05.md b/05.md index ad48a801..ca3e847a 100644 --- a/05.md +++ b/05.md @@ -55,7 +55,7 @@ The mint `Bob` responds with a quote that includes some common fields for all me ```json { "quote": , - "amount": , + "amount": , "unit": , "state": , "expiry": @@ -133,7 +133,7 @@ Content-Type: application/json ```json { "quote": , - "amount": , + "amount": , "unit": , "state": "PENDING", "expiry": @@ -230,8 +230,8 @@ The mint's settings for this NUT indicate the supported method-unit pairs for me { "method": , "unit": , - "min_amount": , - "max_amount": , + "min_amount": , + "max_amount": , "options": } ``` diff --git a/08.md b/08.md index c6749f36..55bfa791 100644 --- a/08.md +++ b/08.md @@ -68,7 +68,7 @@ The mint `Bob` then responds with a `PostMeltQuoteBolt11Response`: { "quote": , "request": , - "amount": , + "amount": , "unit": , "fee_reserve": , "state": , diff --git a/11.md b/11.md index a529d414..bcca3d55 100644 --- a/11.md +++ b/11.md @@ -107,7 +107,7 @@ A `Proof` (an input) with a signature `P2PKWitness.signatures` on `secret` is th ```json { - "amount": , + "amount": , "secret": , "C": , "id": , diff --git a/12.md b/12.md index ced19d48..a43f6ae9 100644 --- a/12.md +++ b/12.md @@ -58,7 +58,7 @@ The mint produces these DLEQ proofs when returning `BlindSignature`'s in the res ```json { "id": , - "amount": , + "amount": , "C_": , "dleq": { <-- New: DLEQ proof "e": , @@ -77,7 +77,7 @@ In order for `Alice` to communicate the DLEQ to another user `Carol`, we extend ```json { "id": , - "amount": , + "amount": , "secret": , "C": , "dleq": { <-- New: DLEQ proof diff --git a/15.md b/15.md index e1e186f1..a936f8ac 100644 --- a/15.md +++ b/15.md @@ -30,7 +30,7 @@ The wallet `Alice` includes the following `PostMeltQuoteBolt11Request` data in i "unit": , "options": { "mpp": { - "amount": + "amount": } } } diff --git a/18.md b/18.md index 34571360..f30843c4 100644 --- a/18.md +++ b/18.md @@ -20,7 +20,7 @@ A Payment Request is defined as follows ```json { "i": str , - "a": int , + "a": UInt64Json , "u": str , "s": bool , "m": Array[str] , @@ -32,7 +32,7 @@ A Payment Request is defined as follows Here, the fields are -- `i`: Payment id to be included in the payment payload +- `i`: Payment id to be included in the payment payload as [UInt64Json][00] - `a`: The amount of the requested payment - `u`: The unit of the requested payment (MUST be set if `a` is set) - `s`: Whether the payment request is for single use diff --git a/20.md b/20.md index 5c945057..f2ebb940 100644 --- a/20.md +++ b/20.md @@ -24,7 +24,7 @@ The wallet of `Alice` includes the following `PostMintQuoteBolt11Request` data i ```json { - "amount": , + "amount": , "unit": , "description": , // Optional "pubkey": // Optional <-- New diff --git a/23.md b/23.md index 3a3a22d2..b82c9ad9 100644 --- a/23.md +++ b/23.md @@ -14,7 +14,7 @@ For the `bolt11` method, the wallet includes the following specific `PostMintQuo ```json { - "amount": , + "amount": , "unit": , "description": // Optional } @@ -26,7 +26,7 @@ The mint responds with a `PostMintQuoteBolt11Response`: { "quote": , "request": , // The bolt11 invoice to pay - "amount": , + "amount": , "unit": , "state": , "expiry": @@ -136,7 +136,7 @@ For the `bolt11` method, the wallet includes the following specific `PostMeltQuo "unit": , "options": { // Optional "amountless": { - "amount_msat": + "amount_msat": } } } @@ -150,7 +150,7 @@ The mint responds with a `PostMeltQuoteBolt11Response`: { "quote": , "request": , - "amount": , + "amount": , "unit": , "fee_reserve": , "state": , @@ -179,7 +179,7 @@ If the `outputs` field is included and there is excess from the `fee_reserve`, t { "quote": , "request": , - "amount": , + "amount": , "unit": , "fee_reserve": , "state": , diff --git a/24.md b/24.md index 05822628..38af3c51 100644 --- a/24.md +++ b/24.md @@ -16,14 +16,14 @@ HTTP servers may respond with the HTTP status code 402 with a `X-Cashu` header c ``` { - "a": int, + "a": UInt64Json, "u": str, "m": Array[str], "nut10": NUT10Option } ``` -- `a`: The amount required in the specified unit +- `a`: The amount required in the specified unit as [UInt64Json][00] - `u`: The currency unit (e.g., "sat", "usd", "api") - `m`: Array of mint URLs that the server accepts tokens from - `nut10`: The required [NUT-10][10] locking condition @@ -40,6 +40,7 @@ The token MUST be from one of the mints listed in the `mints` array, and MUST be If the server receives tokens from a mint that is not in the `mints` array, an incorrect `unit`, an insufficient amount of tokens, or with insufficient locking conditions, it should respond with a HTTP `400` status code. +[00]: 00.md [10]: 10.md [12]: 12.md [18]: 18.md diff --git a/25.md b/25.md index 7bbd3a60..96b18993 100644 --- a/25.md +++ b/25.md @@ -14,7 +14,7 @@ For the `bolt12` method, the wallet includes the following specific `PostMintQuo ```json { - "amount": , + "amount": , "unit": , "description": , "pubkey": @@ -31,12 +31,12 @@ The mint responds with a `PostMintQuoteBolt12Response`: { "quote": , "request": , - "amount": , + "amount": , "unit": , "expiry": , "pubkey": , - "amount_paid": , - "amount_issued": + "amount_paid": , + "amount_issued": } ``` @@ -133,8 +133,8 @@ A `description` option **SHOULD** be set to indicate whether the `bolt12` paymen { "method": "bolt12", "unit": , - "min_amount": , - "max_amount": , + "min_amount": , + "max_amount": , "options": { "description": true } @@ -151,7 +151,7 @@ For the `bolt12` method, the wallet includes the following specific `PostMeltQuo "unit": , "options": { // Optional "amountless": { - "amount_msat": + "amount_msat": } } } @@ -165,7 +165,7 @@ The mint responds with a `PostMeltQuoteBolt12Response`: { "quote": , "request": , - "amount": , + "amount": , "unit": , "fee_reserve": , "state": , @@ -200,7 +200,7 @@ If the `outputs` field is included and there is excess from the `fee_reserve`, t { "quote": , "request": , - "amount": , + "amount": , "unit": , "fee_reserve": , "state": , @@ -267,8 +267,8 @@ curl -X POST https://mint.host:3338/v1/melt/bolt12 -d \ { "method": "bolt12", "unit": , - "min_amount": , - "max_amount": + "min_amount": , + "max_amount": } ``` diff --git a/28.md b/28.md index 8080f3d6..d50f8fce 100644 --- a/28.md +++ b/28.md @@ -99,7 +99,7 @@ Each proof adds a single new metadata field: ```jsonc { - "amount": int, + "amount": UInt64Json, "id": hex_str, "secret": str, // still ["P2PK", {...}] "C": hex_str, From 271f56c68364b5a4d6038069a7a5d474cda1f0a1 Mon Sep 17 00:00:00 2001 From: Rob Woodgate Date: Tue, 7 Apr 2026 16:31:35 +0100 Subject: [PATCH 2/2] address review comments --- 00.md | 14 ++++++-------- 04.md | 4 ++-- 05.md | 8 ++++---- 08.md | 2 +- 11.md | 2 +- 12.md | 4 ++-- 15.md | 2 +- 18.md | 6 +++--- 20.md | 2 +- 23.md | 10 +++++----- 24.md | 4 ++-- 25.md | 22 +++++++++++----------- 28.md | 2 +- 13 files changed, 40 insertions(+), 42 deletions(-) diff --git a/00.md b/00.md index 035cfc65..2be98266 100644 --- a/00.md +++ b/00.md @@ -63,11 +63,9 @@ Values in this specification are one of: - Byte sequences - `int` / `u64`: unsigned 64-bit integer in the range: `0..2^64-1`. -#### UInt64Json +#### Unsigned 64-bit integers in JSON fields -For JSON fields, `int` / `u64` values are encoded as `UInt64Json`. - -`UInt64Json` **MAY** be represented as a JSON integer number or a base-10 decimal string. +For JSON fields, `int` / `u64` values may be encoded as a JSON integer number or a base-10 decimal string. Implementations **MUST** accept both forms. @@ -95,7 +93,7 @@ An encrypted ("blinded") secret and an amount is sent from `Alice` to `Bob` for ```json { - "amount": UInt64Json, + "amount": int, "id": hex_str, "B_": hex_str } @@ -109,7 +107,7 @@ A `BlindSignature` is sent from `Bob` to `Alice` after [minting tokens][04] or a ```json { - "amount": UInt64Json, + "amount": int, "id": hex_str, "C_": hex_str } @@ -123,7 +121,7 @@ A `Proof` is also called an _input_ and is generated by `Alice` from a `BlindSig ```json { - "amount": UInt64Json, + "amount": int, "id": hex_str, "secret": str, "C": hex_str, @@ -273,7 +271,7 @@ For readability, the structure of a TokenV4 object is shown below in its equival "i": bytes, // keyset ID (short or long form) "p": [ // proofs with this keyset ID { - "a": UInt64Json, // amount + "a": int, // amount "s": str, // secret "c": bytes, // signature "d": { // optional DLEQ proof diff --git a/04.md b/04.md index 305c571c..2353daaf 100644 --- a/04.md +++ b/04.md @@ -132,8 +132,8 @@ The settings for this NUT indicate the supported method-unit pairs for minting. { "method": , "unit": , - "min_amount": , - "max_amount": , + "min_amount": , + "max_amount": , "options": } ``` diff --git a/05.md b/05.md index ca3e847a..ad48a801 100644 --- a/05.md +++ b/05.md @@ -55,7 +55,7 @@ The mint `Bob` responds with a quote that includes some common fields for all me ```json { "quote": , - "amount": , + "amount": , "unit": , "state": , "expiry": @@ -133,7 +133,7 @@ Content-Type: application/json ```json { "quote": , - "amount": , + "amount": , "unit": , "state": "PENDING", "expiry": @@ -230,8 +230,8 @@ The mint's settings for this NUT indicate the supported method-unit pairs for me { "method": , "unit": , - "min_amount": , - "max_amount": , + "min_amount": , + "max_amount": , "options": } ``` diff --git a/08.md b/08.md index 55bfa791..c6749f36 100644 --- a/08.md +++ b/08.md @@ -68,7 +68,7 @@ The mint `Bob` then responds with a `PostMeltQuoteBolt11Response`: { "quote": , "request": , - "amount": , + "amount": , "unit": , "fee_reserve": , "state": , diff --git a/11.md b/11.md index bcca3d55..a529d414 100644 --- a/11.md +++ b/11.md @@ -107,7 +107,7 @@ A `Proof` (an input) with a signature `P2PKWitness.signatures` on `secret` is th ```json { - "amount": , + "amount": , "secret": , "C": , "id": , diff --git a/12.md b/12.md index a43f6ae9..ced19d48 100644 --- a/12.md +++ b/12.md @@ -58,7 +58,7 @@ The mint produces these DLEQ proofs when returning `BlindSignature`'s in the res ```json { "id": , - "amount": , + "amount": , "C_": , "dleq": { <-- New: DLEQ proof "e": , @@ -77,7 +77,7 @@ In order for `Alice` to communicate the DLEQ to another user `Carol`, we extend ```json { "id": , - "amount": , + "amount": , "secret": , "C": , "dleq": { <-- New: DLEQ proof diff --git a/15.md b/15.md index a936f8ac..e1e186f1 100644 --- a/15.md +++ b/15.md @@ -30,7 +30,7 @@ The wallet `Alice` includes the following `PostMeltQuoteBolt11Request` data in i "unit": , "options": { "mpp": { - "amount": + "amount": } } } diff --git a/18.md b/18.md index f30843c4..1967afb6 100644 --- a/18.md +++ b/18.md @@ -20,7 +20,7 @@ A Payment Request is defined as follows ```json { "i": str , - "a": UInt64Json , + "a": int , "u": str , "s": bool , "m": Array[str] , @@ -32,8 +32,8 @@ A Payment Request is defined as follows Here, the fields are -- `i`: Payment id to be included in the payment payload as [UInt64Json][00] -- `a`: The amount of the requested payment +- `i`: Payment id to be included in the payment payload +- `a`: The amount of the requested payment as an [unsigned int][00] - `u`: The unit of the requested payment (MUST be set if `a` is set) - `s`: Whether the payment request is for single use - `m`: A set of mints from which the payment is requested diff --git a/20.md b/20.md index f2ebb940..5c945057 100644 --- a/20.md +++ b/20.md @@ -24,7 +24,7 @@ The wallet of `Alice` includes the following `PostMintQuoteBolt11Request` data i ```json { - "amount": , + "amount": , "unit": , "description": , // Optional "pubkey": // Optional <-- New diff --git a/23.md b/23.md index b82c9ad9..3a3a22d2 100644 --- a/23.md +++ b/23.md @@ -14,7 +14,7 @@ For the `bolt11` method, the wallet includes the following specific `PostMintQuo ```json { - "amount": , + "amount": , "unit": , "description": // Optional } @@ -26,7 +26,7 @@ The mint responds with a `PostMintQuoteBolt11Response`: { "quote": , "request": , // The bolt11 invoice to pay - "amount": , + "amount": , "unit": , "state": , "expiry": @@ -136,7 +136,7 @@ For the `bolt11` method, the wallet includes the following specific `PostMeltQuo "unit": , "options": { // Optional "amountless": { - "amount_msat": + "amount_msat": } } } @@ -150,7 +150,7 @@ The mint responds with a `PostMeltQuoteBolt11Response`: { "quote": , "request": , - "amount": , + "amount": , "unit": , "fee_reserve": , "state": , @@ -179,7 +179,7 @@ If the `outputs` field is included and there is excess from the `fee_reserve`, t { "quote": , "request": , - "amount": , + "amount": , "unit": , "fee_reserve": , "state": , diff --git a/24.md b/24.md index 38af3c51..2417b907 100644 --- a/24.md +++ b/24.md @@ -16,14 +16,14 @@ HTTP servers may respond with the HTTP status code 402 with a `X-Cashu` header c ``` { - "a": UInt64Json, + "a": int, "u": str, "m": Array[str], "nut10": NUT10Option } ``` -- `a`: The amount required in the specified unit as [UInt64Json][00] +- `a`: The amount required in the specified unit as an [unsigned int][00] - `u`: The currency unit (e.g., "sat", "usd", "api") - `m`: Array of mint URLs that the server accepts tokens from - `nut10`: The required [NUT-10][10] locking condition diff --git a/25.md b/25.md index 96b18993..7bbd3a60 100644 --- a/25.md +++ b/25.md @@ -14,7 +14,7 @@ For the `bolt12` method, the wallet includes the following specific `PostMintQuo ```json { - "amount": , + "amount": , "unit": , "description": , "pubkey": @@ -31,12 +31,12 @@ The mint responds with a `PostMintQuoteBolt12Response`: { "quote": , "request": , - "amount": , + "amount": , "unit": , "expiry": , "pubkey": , - "amount_paid": , - "amount_issued": + "amount_paid": , + "amount_issued": } ``` @@ -133,8 +133,8 @@ A `description` option **SHOULD** be set to indicate whether the `bolt12` paymen { "method": "bolt12", "unit": , - "min_amount": , - "max_amount": , + "min_amount": , + "max_amount": , "options": { "description": true } @@ -151,7 +151,7 @@ For the `bolt12` method, the wallet includes the following specific `PostMeltQuo "unit": , "options": { // Optional "amountless": { - "amount_msat": + "amount_msat": } } } @@ -165,7 +165,7 @@ The mint responds with a `PostMeltQuoteBolt12Response`: { "quote": , "request": , - "amount": , + "amount": , "unit": , "fee_reserve": , "state": , @@ -200,7 +200,7 @@ If the `outputs` field is included and there is excess from the `fee_reserve`, t { "quote": , "request": , - "amount": , + "amount": , "unit": , "fee_reserve": , "state": , @@ -267,8 +267,8 @@ curl -X POST https://mint.host:3338/v1/melt/bolt12 -d \ { "method": "bolt12", "unit": , - "min_amount": , - "max_amount": + "min_amount": , + "max_amount": } ``` diff --git a/28.md b/28.md index d50f8fce..8080f3d6 100644 --- a/28.md +++ b/28.md @@ -99,7 +99,7 @@ Each proof adds a single new metadata field: ```jsonc { - "amount": UInt64Json, + "amount": int, "id": hex_str, "secret": str, // still ["P2PK", {...}] "C": hex_str,