diff --git a/19.md b/19.md index 74cde56..4c91c99 100644 --- a/19.md +++ b/19.md @@ -1,10 +1,10 @@ -# NUT-18: Mint tokens via BOLT12 +# NUT-19: Mint tokens via BOLT12 `optional` --- -Similar to [NUT-04][04], which covers melting via BOLT11 invoices, melting via [BOLT12](https://github.com/lightning/bolts/blob/master/12-offer-encoding.md) is also a two-step process: requesting a melt quote and melting tokens. This document describes both steps, focusing on BOLT12-specific considerations. +Similar to [NUT-04][04], which covers minting via BOLT11 invoices, minting via [BOLT12](https://github.com/lightning/bolts/blob/master/12-offer-encoding.md) is also a two-step process: requesting a mint quote and minting tokens. This document describes both steps, focusing on BOLT12-specific considerations. # Mint quote @@ -18,13 +18,15 @@ The wallet of `Alice` includes the following `PostMintQuoteBolt12Request` data i ```json { - "amount": , + "amount": , "unit": , - "description": + "description": , + "expiry": , + "single_use": } ``` -with the requested `amount` and the `unit`. An optional `description` can be passed if the mint signals support for it in `MintMethodSetting`. +The `amount` field is optional and specifies the amount to mint. The `unit` field is mandatory. An optional `description` can be passed if the mint signals support for it in `MintMethodSetting`. If `single_use` is false, the offer can be paid multiple times. The optional `expiry` field specifies the unix timestamp when the offer expires. The mint `Bob` then responds with a `PostMintQuoteBolt12Response`: @@ -32,27 +34,22 @@ The mint `Bob` then responds with a `PostMintQuoteBolt12Response`: { "quote": , "request": , - "state": , - "expiry": + "expiry": , + "amount_paid": , + "amount_issued": } ``` -Where `quote` is the quote ID and `request` is the bolt12 offer. The bolt12 offer **MUST** be `single_use` and have the `absolute_expiry` and `amount` set to match the quote. `expiry` is the Unix timestamp until which the mint quote is valid. +Where `quote` is the quote ID and `request` is the bolt12 offer. `expiry` is the Unix timestamp until which the mint quote is valid. `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. `amount_paid` - `amount_issued` represents the amount of ecash a wallet can still mint. -`state` is an enum string field with possible values `"UNPAID"`, `"PAID"`, `"ISSUED"`: - -- `"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. - -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. +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 ecash that this operation mints. ## Example Request of `Alice` with curl: ```bash -curl -X POST http://localhost:3338/v1/mint/quote/bolt12 -d '{"amount": 10, "unit": "sat"}' -H "Content-Type: application/json" +curl -X POST http://localhost:3338/v1/mint/quote/bolt12 -d '{"amount": 10, "unit": "sat", "single_use": true}' -H "Content-Type: application/json" ``` Response of `Bob`: @@ -60,23 +57,24 @@ Response of `Bob`: ```json { "quote": "DSGLX9kevM...", - "request": "lnbc100n1pj4apw9...", - "state": "UNPAID", - "expiry": 1701704757 + "request": "lno1qcp...", + "expiry": 1701704757, + "amount_paid": 0, + "amount_issued": 0 } ``` -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. +After payment, the wallet continues with the next section. -## Check mint quote state +## Check mint quote -To check whether a mint quote has been paid, `Alice` makes a `GET /v1/mint/quote/bolt12/{quote_id}`. +To check whether a mint quote has been paid and has ecash that can be issued, `Alice` makes a `GET /v1/mint/quote/bolt12/{quote_id}`. ```http GET https://mint.host:3338/v1/mint/quote/bolt12/{quote_id} ``` -Like before, the mint `Bob` responds with a `PostMintQuoteBolt12Response`. +The mint `Bob` responds with a `PostMintQuoteBolt12Response`. Example request of `Alice` with curl: @@ -86,13 +84,13 @@ curl -X GET http://localhost:3338/v1/mint/quote/bolt12/DSGLX9kevM... # Minting tokens -After requesting a mint quote and paying the request, the wallet proceeds with minting new tokens by calling the `POST /v1/mint/bolt12`. +After requesting a mint quote and paying the request, the wallet proceeds with minting new tokens by calling `POST /v1/mint/bolt12`. ```http POST https://mint.host:3338/v1/mint/bolt12 ``` -The wallet `Alice` includes the following `PostMintBolt12Request` data in its request +The wallet `Alice` includes the following `PostMintBolt12Request` data in its request: ```json { @@ -101,7 +99,7 @@ The wallet `Alice` includes the following `PostMintBolt12Request` 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. +The `quote` is the quote ID from the previous step and `outputs` are `BlindedMessages` (see [NUT-00][00]) that the wallet requests signatures on. The sum of the outputs must equal the amount that can be minted (`amount_paid` - `amount_issued`). The mint `Bob` then responds with a `PostMintBolt12Response`: @@ -113,78 +111,17 @@ The mint `Bob` then responds with a `PostMintBolt12Response`: where `signatures` is an array of blind signatures on the outputs. -## Example - -Request of `Alice` with curl: - -```bash -curl -X POST https://mint.host:3338/v1/mint/bolt12 -H "Content-Type: application/json" -d \ -'{ - "quote": "DSGLX9kevM...", - "outputs": [ - { - "amount": 8, - "id": "009a1f293253e41e", - "B_": "035015e6d7ade60ba8426cefaf1832bbd27257636e44a76b922d78e79b47cb689d" - }, - { - "amount": 2, - "id": "009a1f293253e41e", - "B_": "0288d7649652d0a83fc9c966c969fb217f15904431e61a44b14999fabc1b5d9ac6" - } - ] -}' -``` - -Response of `Bob`: - -```json -{ - "signatures": [ - { - "id": "009a1f293253e41e", - "amount": 2, - "C_": "0224f1c4c564230ad3d96c5033efdc425582397a5a7691d600202732edc6d4b1ec" - }, - { - "id": "009a1f293253e41e", - "amount": 8, - "C_": "0277d1de806ed177007e5b94a8139343b6382e472c752a74e99949d511f7194f6c" - } - ] -} -``` - -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. +## Multiple issuances -## Unblinding signatures - -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: - -```json -[ - { - "id": "009a1f293253e41e", - "amount": 2, - "secret": "407915bc212be61a77e3e6d2aeb4c727980bda51cd06a6afc29e2861768a7837", - "C": "02bc9097997d81afb2cc7346b5e4345a9346bd2a506eb7958598a72f0cf85163ea" - }, - { - "id": "009a1f293253e41e", - "amount": 8, - "secret": "fe15109314e61d7756b0f8ee0f23a624acaa3f4e042f61433c728c7057b931be", - "C": "029e8e5050b890a7d6c0968db16bc1d5d5fa040ea1de284f6ec69d61299f671059" - } -] -``` +Unlike BOLT11 invoices, BOLT12 offers can be paid multiple times as long as the `single_use` flag is false. This allows the wallet to mint multiple times for one quote. The wallet can call the check bolt12 endpoint, where the mint will return the `PostMintQuoteBolt12Response` including `amount_paid` and `amount_issued`. The difference between these values represents how much the wallet can mint by calling the mint endpoint as defined above. ## 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 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: ```json { - "18": { + "19": { "methods": [ , ...