diff --git a/04.md b/04.md index 9b1171d5..f97af445 100644 --- a/04.md +++ b/04.md @@ -43,12 +43,13 @@ Depending on the payment method, the request structure may vary, but all methods "unit": , "amount": , // Optional "description": , // Optional - "pubkey": // Optional, NUT-20 + "pubkey": , // Optional, NUT-20 + "expiry_seconds": // Optional // Additional method-specific fields may be required } ``` -`amount`, `description` and `pubkey` are common optional fields; method-specific NUTs make them required or ignore them as needed (e.g. NUT-23 requires `amount`, NUT-20 defines `pubkey`). +`amount`, `description`, `pubkey`, and `expiry_seconds` are common optional fields. Method-specific NUTs define their use. The mint `Bob` responds with a quote that includes some common fields for all methods: diff --git a/20.md b/20.md index f8a12fd8..e713ca91 100644 --- a/20.md +++ b/20.md @@ -27,7 +27,8 @@ The wallet of `Alice` includes the following `PostMintQuoteBolt11Request` data i "amount": , "unit": , "description": , // Optional - "pubkey": // Optional <-- New + "pubkey": , // Optional <-- New + "expiry_seconds": // Optional, NUT-23 } ``` @@ -82,7 +83,7 @@ The response is the same as the `bolt11` mint quote response in [NUT-23][23] exc Request of `Alice` with curl: ```bash -curl -X POST http://localhost:3338/v1/mint/quote/bolt11 -d '{"amount": 10, "unit": "sat", "pubkey": "03d56ce4e446a85bbdaa547b4ec2b073d40ff802831352b8272b7dd7a4de5a7cac"}' -H "Content-Type: application/json" +curl -X POST http://localhost:3338/v1/mint/quote/bolt11 -d '{"amount": 10, "unit": "sat", "pubkey": "03d56ce4e446a85bbdaa547b4ec2b073d40ff802831352b8272b7dd7a4de5a7cac", "expiry_seconds": 100}' -H "Content-Type: application/json" ``` Response of `Bob`: diff --git a/23.md b/23.md index 64fea463..9614554c 100644 --- a/23.md +++ b/23.md @@ -16,10 +16,15 @@ For the `bolt11` method, the wallet includes the following specific `PostMintQuo { "amount": , "unit": , - "description": // Optional + "description": , // Optional + "expiry_seconds": // Optional } ``` +`expiry_seconds` is the requested quote lifetime in seconds from quote creation. If omitted, the mint uses its default lifetime. + +Mints **MUST** return error `11018` if `expiry_seconds` is not positive, exceeds their maximum, or cannot be honored exactly. Mints **MUST NOT** silently clamp it. + The mint responds with a `PostMintQuoteBolt11Response`: ```json @@ -33,7 +38,7 @@ The mint responds with a `PostMintQuoteBolt11Response`: "amount_issued": , "updated_at": , "state": , // Deprecated, optional - "expiry": + "expiry": } ``` @@ -47,14 +52,14 @@ The mint responds with a `PostMintQuoteBolt11Response`: Wallets **SHOULD** use `amount_paid` and `amount_issued` instead of `state` whenever these fields are present. -`expiry` is the Unix timestamp until which the `request` can be paid (i.e. the bolt11 invoice expiry). +`expiry` is the invoice timestamp plus its BOLT11 expiry duration, expressed as a Unix timestamp. If `expiry_seconds` was set, it **MUST** be used as the invoice expiry duration. ### Example Request with curl: ```bash -curl -X POST http://localhost:3338/v1/mint/quote/bolt11 -d '{"amount": 10, "unit": "sat"}' -H "Content-Type: application/json" +curl -X POST http://localhost:3338/v1/mint/quote/bolt11 -d '{"amount": 10, "unit": "sat", "expiry_seconds": 100}' -H "Content-Type: application/json" ``` Response: @@ -124,6 +129,8 @@ Response: A `description` option **MUST** be set to indicate whether the `bolt11` payment method backend supports providing an invoice description. +`max_expiry_seconds` is the maximum `expiry_seconds` accepted by the mint. If omitted, the maximum is unknown. + ### Example `MintMethodSetting` ```json @@ -133,7 +140,8 @@ A `description` option **MUST** be set to indicate whether the `bolt11` payment "min_amount": 0, "max_amount": 10000, "options": { - "description": true + "description": true, + "max_expiry_seconds": 86400 } } ``` diff --git a/25.md b/25.md index c447e344..da7d98f5 100644 --- a/25.md +++ b/25.md @@ -17,7 +17,8 @@ For the `bolt12` method, the wallet includes the following specific `PostMintQuo "amount": , "unit": , "description": , - "pubkey": + "pubkey": , + "expiry_seconds": // Optional } ``` @@ -25,6 +26,10 @@ For the `bolt12` method, the wallet includes the following specific `PostMintQuo > **Privacy:** To prevent linking multiple mint quotes together, wallets **SHOULD** generate a unique public key for each mint quote request. +`expiry_seconds` is the requested quote lifetime in seconds from quote creation. If omitted, the mint uses its default lifetime. + +Mints **MUST** return error `11018` if `expiry_seconds` is not positive, exceeds their maximum, or cannot be honored exactly. Mints **MUST NOT** silently clamp it. + The mint responds with a `PostMintQuoteBolt12Response`: ```json @@ -46,7 +51,7 @@ Where: - `quote` is the quote ID - `request` is the bolt12 offer -- `expiry` is the Unix timestamp until which the mint quote is valid +- `expiry` is the BOLT12 offer's absolute expiry, or `null` if it does not expire. If `expiry_seconds` was set, `expiry` **MUST** equal the quote creation time plus `expiry_seconds` - `amount_paid` is the amount that has been paid to the mint via the bolt12 offer - `amount_issued` is the amount of ecash that has been issued for the given mint quote - `updated_at` is defined in [NUT-04][04] @@ -57,7 +62,7 @@ Where: ```bash curl -X POST http://localhost:3338/v1/mint/quote/bolt12 -d \ -'{"amount": 10, "unit": "sat", "pubkey": "03d56ce4e446a85bbdaa547b4ec2b073d40ff802831352b8272b7dd7a4de5a7cac"}' \ +'{"amount": 10, "unit": "sat", "pubkey": "03d56ce4e446a85bbdaa547b4ec2b073d40ff802831352b8272b7dd7a4de5a7cac", "expiry_seconds": 100}' \ -H "Content-Type: application/json" ``` @@ -132,6 +137,8 @@ Unlike BOLT11 invoices, BOLT12 offers can be paid multiple times, allowing the w A `description` option **SHOULD** be set to indicate whether the `bolt12` payment method backend supports providing an offer description. +`max_expiry_seconds` is the maximum `expiry_seconds` accepted by the mint. If omitted, the maximum is unknown. + ### Example `MintMethodSetting` ```json @@ -141,7 +148,8 @@ A `description` option **SHOULD** be set to indicate whether the `bolt12` paymen "min_amount": , "max_amount": , "options": { - "description": true + "description": true, + "max_expiry_seconds": 86400 } } ``` diff --git a/30.md b/30.md index 753f16a2..83fdda57 100644 --- a/30.md +++ b/30.md @@ -15,12 +15,17 @@ For the `onchain` method, the wallet includes the following specific `PostMintQu ```json { "unit": , - "pubkey": + "pubkey": , + "expiry_seconds": // Optional } ``` > **Note:** A [NUT-20][20] `pubkey` is required in this NUT and the mint **MUST NOT** issue a mint quote if one is not included. +`expiry_seconds` is the requested quote lifetime in seconds from quote creation. If omitted, the quote does not expire. + +Mints **MUST** return error `11018` if `expiry_seconds` is not positive, exceeds their maximum, or cannot be honored exactly. Mints **MUST NOT** silently clamp it. + The mint responds with a `PostMintQuoteOnchainResponse`: ```json @@ -41,13 +46,15 @@ Where: - `quote` is the quote ID - `request` is the Bitcoin address to send funds to -- `expiry` is the Unix timestamp until which the mint quote is valid +- `expiry` is the Unix timestamp until which the mint quote is valid, or `null` if `expiry_seconds` was omitted - `pubkey` is the public key from the request - `amount_paid` is the total confirmed amount paid to the request in UTXOs that are eligible for minting - `amount_issued` is the amount of ecash that has been issued for the given mint quote - `updated_at` is defined in [NUT-04][04] -If `expiry` is not `null`, the wallet **SHOULD NOT** send payments to the request after `expiry`. Mints **MUST** keep monitoring transactions they detected before `expiry` until the transaction reaches the required number of confirmations or is evicted or replaced. Payments first detected by the mint after `expiry` **MUST NOT** increase `amount_paid`. +The Bitcoin address does not expire; `expiry` only limits when payments are credited to the quote. If `expiry_seconds` was set, `expiry` **MUST** equal the quote creation time plus `expiry_seconds`. + +When `expiry` is not `null`, the wallet **SHOULD NOT** send payments that may be detected after it, and the mint **MUST** keep monitoring transactions detected before it until they reach the required number of confirmations or are evicted or replaced. The mint **MUST NOT** increase `amount_paid` for payments first detected after `expiry`. ### Example @@ -55,7 +62,7 @@ If `expiry` is not `null`, the wallet **SHOULD NOT** send payments to the reques ```bash curl -X POST http://localhost:3338/v1/mint/quote/onchain -d \ -'{"unit": "sat", "pubkey": "03d56ce4e446a85bbdaa547b4ec2b073d40ff802831352b8272b7dd7a4de5a7cac"}' \ +'{"unit": "sat", "pubkey": "03d56ce4e446a85bbdaa547b4ec2b073d40ff802831352b8272b7dd7a4de5a7cac", "expiry_seconds": 100}' \ -H "Content-Type: application/json" ``` @@ -152,6 +159,8 @@ A `confirmations` option **SHOULD** be set to indicate the minimum depth in the For the `onchain` mint method, `min_amount` indicates both the minimum mint operation amount and the minimum amount of an individual UTXO that the mint will credit to `amount_paid`. Wallets **SHOULD NOT** send onchain payments below `min_amount` to a quote address. +`max_expiry_seconds` is the maximum `expiry_seconds` accepted by the mint. If omitted, the maximum is unknown. + ### Example `MintMethodSetting` ```json @@ -161,7 +170,8 @@ For the `onchain` mint method, `min_amount` indicates both the minimum mint oper "min_amount": , "max_amount": , "options": { - "confirmations": + "confirmations": , + "max_expiry_seconds": 86400 } } ``` diff --git a/error_codes.md b/error_codes.md index a9f6aec2..b2befb95 100644 --- a/error_codes.md +++ b/error_codes.md @@ -20,6 +20,7 @@ | 11015 | Max outputs exceeded | [NUT-03][03], [NUT-04][04], [NUT-05][05] | | 11016 | Duplicate quote IDs provided | [NUT-29][29] | | 11017 | Max batch size exceeded | [NUT-29][29] | +| 11018 | Requested expiry cannot be honored | [NUT-23][23], [NUT-25][25], [NUT-30][30] | | 12001 | Keyset is not known | [NUT-02][02], [NUT-04][04] | | 12002 | Keyset is inactive, cannot sign messages | [NUT-02][02], [NUT-03][03], [NUT-04][04] | | 12003 | Keyset has expired | [NUT-02][02], [NUT-03][03], [NUT-04][04], [NUT-05][05] | @@ -55,4 +56,7 @@ [20]: 20.md [21]: 21.md [22]: 22.md +[23]: 23.md +[25]: 25.md [29]: 29.md +[30]: 30.md