-
Notifications
You must be signed in to change notification settings - Fork 54
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Payment Method Refactor #201
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,65 +1,82 @@ | ||
# NUT-04: Mint tokens | ||
# NUT-04: Minting tokens | ||
|
||
`mandatory` | ||
|
||
--- | ||
|
||
Minting tokens is a two-step process: requesting a mint quote and minting new tokens. Here, we describe both steps. | ||
Minting tokens is a two-step process: requesting a mint quote and minting new tokens. | ||
|
||
In the first request the wallet asks the mint for a quote for a specific `amount` and `unit` to mint, and the payment `method` to pay. The mint responds with a quote that includes a `quote` id and a payment `request`. The user pays the `request` and, if successful, requests minting of new tokens with the mint in a second request. The wallet includes the `quote` id and new `outputs` in the second request. | ||
1. The wallet **MUST** first request a mint quote by specifying the `amount`, `unit`, and payment `method`. | ||
- The mint **MUST** respond with a `quote` ID and a payment `request` for valid requests. | ||
2. After payment, the wallet **MUST** initiate the minting process by sending the `quote` ID and `outputs` in a second request. | ||
|
||
We limit this document to mint quotes of `unit="sat"` and `method="bolt11"` which requests a bolt11 Lightning invoice (typically generated by the mint to add Bitcoin to its reserves) to mint ecash denominated in Satoshis. | ||
--- | ||
|
||
## Mint Quote | ||
|
||
# Mint quote | ||
To request a mint quote, the wallet **MUST** send a `POST /v1/mint/quote/{method}` request. The `method` specifies the payment method (e.g., `bolt11`). | ||
|
||
To request a mint quote, the wallet of `Alice` makes a `POST /v1/mint/quote/{method}` request where `method` is the payment method requested (here `bolt11`). | ||
### Request Endpoint | ||
|
||
```http | ||
POST https://mint.host:3338/v1/mint/quote/bolt11 | ||
POST https://mint.host:3338/v1/mint/quote/{method} | ||
``` | ||
|
||
The wallet of `Alice` includes the following `PostMintQuoteBolt11Request` data in its request: | ||
### Request Body | ||
|
||
The request body **MUST** include the following fields: | ||
|
||
```json | ||
{ | ||
"amount": <int>, | ||
"unit": <str_enum["sat"]>, | ||
"description": <str|null> | ||
"unit": <str>, | ||
"opts": <obj|null> | ||
} | ||
``` | ||
|
||
with the requested `amount` and the `unit`. An optional `description` can be passed if the mint signals support for it in `MintMethodSetting`. | ||
- `amount`: The requested amount to mint. | ||
- `unit`: The unit of the amount. | ||
- `opts`: Options specific to the payment method. | ||
|
||
### Response | ||
|
||
The mint `Bob` then responds with a `PostMintQuoteBolt11Response`: | ||
The mint **MUST** respond with a `PostMintQuoteResponse`: | ||
|
||
```json | ||
{ | ||
"quote": <str>, | ||
"request": <str>, | ||
"state": <str_enum[STATE]>, | ||
"expiry": <int> | ||
"expiry": <int|null> | ||
} | ||
``` | ||
|
||
Where `quote` is the quote ID and `request` is the payment request to fulfill. `expiry` is the Unix timestamp until which the mint quote is valid. | ||
- `quote`: A unique ID for the quote. | ||
- `request`: The payment request. | ||
- `state`: The current state of the quote (`UNPAID`, `PAID`, or `ISSUED`). | ||
- `expiry`: The expiration timestamp for the quote (or `null` for quotes without expiration). | ||
|
||
`state` is an enum string field with possible values `"UNPAID"`, `"PAID"`, `"ISSUED"`: | ||
The wallet **MUST** store the `amount` and `quote` ID in its database for use during token minting after payment. | ||
|
||
- `"UNPAID"` means that the quote's request has not been paid yet. | ||
- `"PAID"` means that the request has been paid. | ||
- `"ISSUED"` means that the quote has already been issued. | ||
--- | ||
|
||
### Security Note | ||
|
||
Note: `quote` is a **unique and random** id generated by the mint to internally look up the payment state. `quote` **MUST** remain a secret between user and mint and **MUST NOT** be derivable from the payment request. A third party who knows the `quote` ID can front-run and steal the tokens that this operation mints. | ||
The `quote` ID **MUST** be unique and secret. It **MUST NOT** be derivable from the payment request. Leaking this ID allows third parties to steal tokens. | ||
|
||
--- | ||
|
||
## Example | ||
### Example: Requesting a Quote | ||
|
||
Request of `Alice` with curl: | ||
**Request:** | ||
|
||
```bash | ||
curl -X POST http://localhost:3338/v1/mint/quote/bolt11 -d '{"amount": 10, "unit": "sat"}' -H "Content-Type: application/json" | ||
curl -X POST https://mint.host:3338/v1/mint/quote/{method} \ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here, using |
||
-d '{"amount": 10, "unit": "sat"}' \ | ||
-H "Content-Type: application/json" | ||
``` | ||
|
||
Response of `Bob`: | ||
**Response:** | ||
|
||
```json | ||
{ | ||
|
@@ -70,33 +87,46 @@ Response of `Bob`: | |
} | ||
``` | ||
|
||
The wallet **MUST** store the `amount` in the request and the `quote` id in the response in its database so it can later request the tokens after paying the request. After payment, the wallet continues with the next section. | ||
--- | ||
|
||
## Check mint quote state | ||
## Checking Mint Quote State | ||
|
||
To check whether a mint quote has been paid, `Alice` makes a `GET /v1/mint/quote/bolt11/{quote_id}`. | ||
To check whether a mint quote has been paid, the wallet **MUST** send a `GET /v1/mint/quote/{method}/{quote_id}` request. | ||
|
||
```http | ||
GET https://mint.host:3338/v1/mint/quote/bolt11/{quote_id} | ||
``` | ||
### Example: Checking Quote State | ||
|
||
Like before, the mint `Bob` responds with a `PostMintQuoteBolt11Response`. | ||
|
||
Example request of `Alice` with curl: | ||
**Request:** | ||
|
||
```bash | ||
curl -X GET http://localhost:3338/v1/mint/quote/bolt11/DSGLX9kevM... | ||
curl -X GET https://mint.host:3338/v1/mint/quote/{method}/{quote_id} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Again, use concrete values in an example. |
||
``` | ||
|
||
# Minting tokens | ||
**Response:** | ||
|
||
After requesting a mint quote and paying the request, the wallet proceeds with minting new tokens by calling the `POST /v1/mint/{method}` endpoint where `method` is the payment method requested (here `bolt11`). | ||
```json | ||
{ | ||
"quote": "DSGLX9kevM...", | ||
"request": "lnbc100n1pj4apw9...", | ||
"state": "UNPAID", | ||
"expiry": 1701704757 | ||
} | ||
``` | ||
|
||
--- | ||
|
||
## Minting Tokens | ||
|
||
After completing the payment, the wallet **MUST** send a `POST /v1/mint/{method}` request to mint tokens. | ||
|
||
### Request Endpoint | ||
|
||
```http | ||
POST https://mint.host:3338/v1/mint/bolt11 | ||
POST https://mint.host:3338/v1/mint/{method} | ||
``` | ||
|
||
The wallet `Alice` includes the following `PostMintBolt11Request` data in its request | ||
### Request Body | ||
|
||
The request body **MUST** include: | ||
|
||
```json | ||
{ | ||
|
@@ -105,25 +135,31 @@ The wallet `Alice` includes the following `PostMintBolt11Request` data in its re | |
} | ||
``` | ||
|
||
with the `quote` being the quote ID from the previous step and `outputs` being `BlindedMessages` (see [NUT-00][00]) that the wallet requests signatures on whose sum is `amount` as requested in the quote. | ||
- `quote`: The quote ID. | ||
- `outputs`: Blinded messages (see [NUT-00](00.md)) for the requested amount. | ||
|
||
The mint `Bob` then responds with a `PostMintBolt11Response`: | ||
### Response | ||
|
||
The mint **MUST** respond with a `PostMintResponse`: | ||
|
||
```json | ||
{ | ||
"signatures": <Array[BlindSignature]> | ||
} | ||
``` | ||
|
||
where `signatures` is an array of blind signatures on the outputs. | ||
- `signatures`: Blind signatures for the outputs. | ||
|
||
--- | ||
|
||
## Example | ||
### Example: Minting Tokens | ||
|
||
Request of `Alice` with curl: | ||
**Request:** | ||
|
||
```bash | ||
curl -X POST https://mint.host:3338/v1/mint/bolt11 -H "Content-Type: application/json" -d \ | ||
'{ | ||
curl -X POST https://mint.host:3338/v1/mint/{method} \ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here too. |
||
-H "Content-Type: application/json" \ | ||
-d '{ | ||
"quote": "DSGLX9kevM...", | ||
"outputs": [ | ||
{ | ||
|
@@ -140,7 +176,7 @@ curl -X POST https://mint.host:3338/v1/mint/bolt11 -H "Content-Type: application | |
}' | ||
``` | ||
|
||
Response of `Bob`: | ||
**Response:** | ||
|
||
```json | ||
{ | ||
|
@@ -159,11 +195,15 @@ Response of `Bob`: | |
} | ||
``` | ||
|
||
If the invoice was not paid yet, `Bob` responds with an error. In that case, `Alice` **CAN** repeat the same request until the Lightning invoice is settled. | ||
If the payment is incomplete, the mint **MUST** return an error. The wallet **SHOULD** retry until the payment is completed. | ||
|
||
--- | ||
|
||
### Unblinding Signatures | ||
|
||
## Unblinding signatures | ||
After receiving blind signatures, the wallet **MUST** unblind them to generate `Proofs`. This involves the blinding factor `r` and the mint's public key `K` (see BDHKE in [NUT-00](00.md)). | ||
|
||
Upon receiving the `BlindSignatures` from the mint `Bob`, the wallet of `Alice` unblinds them to generate `Proofs` (using the blinding factor `r` and the mint's public key `K`, see BDHKE [NUT-00][00]). The wallet then stores these `Proofs` in its database: | ||
The wallet **MUST** store the `Proofs` in its database: | ||
|
||
```json | ||
[ | ||
|
@@ -184,7 +224,7 @@ Upon receiving the `BlindSignatures` from the mint `Bob`, the wallet of `Alice` | |
|
||
## Settings | ||
|
||
The settings for this nut indicate the supported method-unit pairs for minting and whether minting is disabled or not. They are part of the info response of the mint ([NUT-06][06]) which in this case reads | ||
The mint's [NUT-06](06.md) settings **MUST** indicate supported method-unit pairs for minting. It **MUST** also specify whether minting is disabled. | ||
|
||
```json | ||
{ | ||
|
@@ -198,22 +238,17 @@ The settings for this nut indicate the supported method-unit pairs for minting a | |
} | ||
``` | ||
|
||
`MintMethodSetting` indicates supported `method` and `unit` pairs and additional settings of the mint. `disabled` indicates whether this minting is disabled. | ||
|
||
`MintMethodSetting` is of the form: | ||
`MintMethodSetting` indicates supported `method` and `unit` pairs. The `disabled` field indicates whether this minting is disabled. The `min_amount` and `max_amount` fields indicate the minimum and maximum amount for an operation of this method-unit pair. | ||
|
||
```json | ||
{ | ||
"method": <str>, | ||
"unit": <str>, | ||
"min_amount": <int|null>, | ||
"max_amount": <int|null>, | ||
"description": <bool|null> | ||
} | ||
``` | ||
|
||
`min_amount` and `max_amount` indicate the minimum and maximum amount for an operation of this method-unit pair. | ||
|
||
Example `MintMethodSetting`: | ||
|
||
```json | ||
|
@@ -222,20 +257,8 @@ Example `MintMethodSetting`: | |
"unit": "sat", | ||
"min_amount": 0, | ||
"max_amount": 10000, | ||
"description": true | ||
} | ||
``` | ||
|
||
[00]: 00.md | ||
[01]: 01.md | ||
[02]: 02.md | ||
[03]: 03.md | ||
[04]: 04.md | ||
[05]: 05.md | ||
[06]: 06.md | ||
[07]: 07.md | ||
[08]: 08.md | ||
[09]: 09.md | ||
[10]: 10.md | ||
[11]: 11.md | ||
[12]: 12.md | ||
# Well-Known Payment Methods | ||
- [bolt11](20.md) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am in favor of the change, but strictly speaking it is a breaking change.