Skip to content

Commit

Permalink
feat: multiple mint bolt12
Browse files Browse the repository at this point in the history
  • Loading branch information
thesimplekid committed Oct 25, 2024
1 parent 5565d0b commit 55355b0
Showing 1 changed file with 28 additions and 91 deletions.
119 changes: 28 additions & 91 deletions 19.md
Original file line number Diff line number Diff line change
@@ -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

Expand All @@ -18,65 +18,63 @@ The wallet of `Alice` includes the following `PostMintQuoteBolt12Request` data i

```json
{
"amount": <int>,
"amount": <int|null>,
"unit": <str_enum["sat"]>,
"description": <str|null>
"description": <str|null>,
"expiry": <int|null>,
"single_use": <bool>
}
```

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`:

```json
{
"quote": <str>,
"request": <str>,
"state": <str_enum[STATE]>,
"expiry": <int>
"expiry": <int>,
"amount_paid": <int>,
"amount_issued": <int>
}
```

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`:

```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:

Expand All @@ -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
{
Expand All @@ -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`:

Expand All @@ -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": [
<MintMethodSetting>,
...
Expand Down

0 comments on commit 55355b0

Please sign in to comment.