Skip to content
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

On chain mint and melt #194

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
feat: mint onchain with NUT-19
  • Loading branch information
thesimplekid committed Nov 21, 2024
commit 05e7ae7b05cac4254c5717063af9039843f30cbf
69 changes: 46 additions & 23 deletions 22.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
NUT-18: Mint tokens Bitcoin On-Chain
NUT-22: Mint tokens Bitcoin On-Chain
==========================

`optional`

`depends on: [NUT-19][19]`
---

This NUT describes the process of minting tokens on Bitcoin On-Chain analog to NUT-04 for Bitcoin Lightning.
This NUT describes the process of minting tokens on Bitcoin On-Chain analog to [NUT-04][04] for Bitcoin Lightning.

# Mint quote

Expand All @@ -20,7 +21,8 @@ The wallet of `Alice` includes the following `PostMintQuoteBtcOnchainRequest` da
```json
{
"amount": <int>,
"unit": <str_enum["sat"]>
"unit": <str_enum["sat"]>,
"pubkey": <str>
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NUT-19 says this should be optional, depending on whether or not the MintInfo requires it.

```
with the requested `amount` and the `unit`.
Expand All @@ -31,41 +33,41 @@ The wallet of `Alice` includes the following `PostMintQuoteBtcOnchainRequest` da
{
"quote": <str>,
"address": <str>,
"state": <str_enum[STATE]>,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"address": <str>,
"request": <str>,

since in other places throughout this NUT request is being used rather than address

"expiry": <int>
"expiry": <int>,
"unconfirmed_amount", <int>,
"amount_paid": <int>,
"amount_issued": <int>,
"pubkey": <str>
}
```

Where `quote` is the quote ID and `address` is the payment request to fulfill.

`state` is an enum string field with possible values `"UNPAID"`, `"PAID"`, `"PENDING"`, `"ISSUED"`:
- `"UNPAID"` means that the quote's request has not been paid yet.
- `"PAID"` means that the request has been paid.
- `"PENDING"` means that the quote is currently being issued.
- `"ISSUED"` means that the quote has already been issued.
Where `quote` is the quote ID and `request` is the bitcoin onchain address. `expiry` is the Unix timestamp until which the mint quote is valid. `unconfirmed_amount` is the value of UTXOs in sats that has not met the minimum confirmations set in the info endpoint. `amount_paid` is the amount that has been paid to the mint via the onchain address. `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.

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**: Any UTXOs with a value less than the `min_amount` in the info response will not be added to the `amount_paid` value and will be considered dust. Ecash cannot be minted for these UTXOs.

## Example

Request of `Alice` with curl:

```bash
curl -X POST https://mint.host:3338/v1/mint/quote/btconchain -d '{"amount": 10, "unit": "sat"}' -H "Content-Type: application/json"
curl -X POST https://mint.host:3338/v1/mint/quote/btconchain -d '{"amount": 10, "unit": "sat", "pubkey": "03d56ce4e446a85bbdaa547b4ec2b073d40ff802831352b8272b7dd7a4de5a7cac"}' -H "Content-Type: application/json"
```

Response of `Bob`:

```json
{
"quote": "DSGLX9kevM...",
"address": "bc1qkyfgd7mus7ykfd7qkwakq75qsf7rtm...",
"state": "UNPAID",
"expiry": 1701704757
"request": "bc1q...",
"expiry": 1701704757,
"amount_paid": 0,
"amount_issued": 0,
"pubkey": "03d56ce4e446a85bbdaa547b4ec2b073d40ff802831352b8272b7dd7a4de5a7cac"
}
```

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.
The wallet **MUST** store 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

Expand All @@ -83,6 +85,23 @@ Example request of `Alice` with curl:
curl -X GET https://mint.host:3338/v1/mint/quote/btconchain/DSGLX9kevM...
```

Response of `Bob`:

```json
{
"quote": "DSGLX9kevM...",
"request": "bc1q...",
"expiry": 1701704757,
"amount_paid": 0,
"amount_issued": 0,
"pubkey": "03d56ce4e446a85bbdaa547b4ec2b073d40ff802831352b8272b7dd7a4de5a7cac"
}
```

### Witness

In order to mint ecash the wallet **MUST** include a signature as defined in [NUT-19][19].

Comment on lines +101 to +103
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be moved to the Minting tokens section where this field is used in the request.

# Minting tokens

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 `btconchain`).
Expand All @@ -96,10 +115,12 @@ The wallet `Alice` includes the following `PostMintBtcOnchainRequest` data in it
```json
{
"quote": <str>,
"outputs": <Array[BlindedMessage]>
"outputs": <Array[BlindedMessage]>,
"witness": <str>
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here as well. It's not clear if this NUT requires a Mint that requires NUT-19 signatures or only supports them.

```
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`). `witness` is the signature on the mint quote id as defined above.

The mint `Bob` then responds with a `PostMintBtcOnchainResponse`:

Expand Down Expand Up @@ -130,7 +151,8 @@ curl -X POST https://mint.host:3338/v1/mint/btconchain -H "Content-Type: applica
"id": "009a1f293253e41e",
"B_": "0288d7649652d0a83fc9c966c969fb217f15904431e61a44b14999fabc1b5d9ac6"
}
]
],
"witness": "d4b386f21f7aa7172f0994ee6e4dd966539484247ea71c99b81b8e09b1bb2acbc0026a43c221fd773471dc30d6a32b04692e6837ddaccf0830a63128308e4ee0"
}'
```

Expand Down Expand Up @@ -178,8 +200,7 @@ Upon receiving the `BlindSignatures` from the mint `Bob`, the wallet of `Alice`
The settings for this nut indicate the supported method-unit pairs for minting and whether minting is supported or not. They are part of the info response of the mint ([NUT-06][06]) which in this case reads
```json
{
"18": {
"supported": true,
"22": {
"methods": [
{
"method": "btconchain",
Expand All @@ -188,7 +209,8 @@ The settings for this nut indicate the supported method-unit pairs for minting a
"max_amount": 1000000,
"min_confirmations": 3
}
]
],
"disabled": false,
}
}
```
Expand All @@ -206,3 +228,4 @@ The settings for this nut indicate the supported method-unit pairs for minting a
[10]: 10.md
[11]: 11.md
[12]: 12.md
[19]: 19.md
26 changes: 19 additions & 7 deletions 23.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
NUT-19: Melt tokens Bitcoin On-Chain
NUT-23: Melt tokens Bitcoin On-Chain
==========================

`optional`
Expand Down Expand Up @@ -34,15 +34,24 @@ The mint `Bob` then responds with an array of `PostMeltQuoteBtcOnchainResponse`:
[
{
"quote": <str>,
"description": <str|null>,
"amount": <int>,
"fee": <int>,
"estimated_blocks": <int>,
"state": <str_enum[STATE]>,
"expiry": <int>
}
]
```
The mint can return multiple `PostMeltQuoteBtcOnchainResponse` with different `fees` and `expiry` dates. The wallet can choose which one to pay and the other ones will expire. Where `quote` is the quote ID, `amount` the amount that needs to be provided, and `fee` the additional fee that is required. The mint expects `Alice` to include `Proofs` of *at least* `total_amount = amount + fee`. `paid` indicates whether the request as been paid and `expiry` is the Unix timestamp until which the melt quote is valid.
The mint can return multiple `PostMeltQuoteBtcOnchainResponse` with different `fees` and `expiry` dates. The wallet can choose which one to pay and the other ones will expire. Where `quote` is the quote ID, `amount` the amount that needs to be provided, and `fee` the additional fee that is required in the unit of the `PostMeltQuoteBtcOnchainRequest`. `estimated_blocks` is the number of blocks estimated untill confimation. The mint expects `Alice` to include `Proofs` of *at least* `total_amount = amount + fee`. `expiry` is the Unix timestamp until which the melt quote is valid.


`state` is an enum string field with possible values `"UNPAID"`, `"PENDING"`, `"PAID"`:

- `"UNPAID"` means that the request has not been paid yet.
- `"PENDING"` means that the request is currently being paid.
- `"PAID"` means that the request has been paid successfully.



## Example

Expand All @@ -53,6 +62,7 @@ curl -X POST https://mint.host:3338/v1/melt/quote/btconchain -d \
{
"address": "bc1qkyfgd7mus7ykfd7qkwakq75qsf7rtm...",
"unit": "sat"
"amount": 100000
}
```

Expand All @@ -64,15 +74,17 @@ Response of `Bob`:
"quote": "TRmjduhIsPxd...",
"description": "1 sat per vbyte",
"amount": 10,
"fee": 2,
"fee": 3000,
"estimated_blocks": 1,
"state": "UNPAID",
"expiry": 1701704757
},
{
"quote": "OewtRaqe...",
"description": "5 sat per vbyte",
"amount": 10,
"fee": 10,
"fee": 300,
"estimated_blocks": 50,
"state": "UNPAID",
"expiry": 1701704757
}
Expand Down Expand Up @@ -171,8 +183,7 @@ Response of `Bob`:
The settings for this nut indicate the supported method-unit pairs for melting. They are part of the info response of the mint ([NUT-06][06]) which in this case reads
```json
{
"19": {
"supported": true,
"23": {
"methods": [
{
"method": "btconchain",
Expand All @@ -181,6 +192,7 @@ The settings for this nut indicate the supported method-unit pairs for melting.
"max_amount": 1000000
}
]
"disabled": false,
}
}
```
Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@ Wallets and mints `MUST` implement all mandatory specs and `CAN` implement optio
| [16][16] | Animated QR codes | [Cashu.me][cashume] | - |
| [17][17] | WebSocket subscriptions | [Nutshell][py] | [Nutshell][py] |
| [18][18] | Payment requests | [Cashu.me][cashume], [Boardwalk][bwc], [cdk-cli] | - |

| [22][22] | Minting onchain | | |
| [23][23] | Melting onchain | | |

#### Wallets:

- [Nutshell][py]
Expand Down
Loading