diff --git a/22.md b/22.md index b8542ff..1b5e29d 100644 --- a/22.md +++ b/22.md @@ -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 @@ -20,7 +21,8 @@ The wallet of `Alice` includes the following `PostMintQuoteBtcOnchainRequest` da ```json { "amount": , - "unit": + "unit": , + "pubkey": } ``` with the requested `amount` and the `unit`. @@ -31,27 +33,25 @@ The wallet of `Alice` includes the following `PostMintQuoteBtcOnchainRequest` da { "quote": , "address": , - "state": , - "expiry": + "expiry": , + "unconfirmed_amount", , + "amount_paid": , + "amount_issued": , + "pubkey": } ``` -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`: @@ -59,13 +59,15 @@ 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 @@ -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]. + # 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`). @@ -96,10 +115,12 @@ The wallet `Alice` includes the following `PostMintBtcOnchainRequest` data in it ```json { "quote": , - "outputs": + "outputs": , + "witness": } ``` - 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`: @@ -130,7 +151,8 @@ curl -X POST https://mint.host:3338/v1/mint/btconchain -H "Content-Type: applica "id": "009a1f293253e41e", "B_": "0288d7649652d0a83fc9c966c969fb217f15904431e61a44b14999fabc1b5d9ac6" } - ] + ], + "witness": "d4b386f21f7aa7172f0994ee6e4dd966539484247ea71c99b81b8e09b1bb2acbc0026a43c221fd773471dc30d6a32b04692e6837ddaccf0830a63128308e4ee0" }' ``` @@ -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", @@ -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, } } ``` @@ -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 diff --git a/23.md b/23.md index c4340dd..17bd1b1 100644 --- a/23.md +++ b/23.md @@ -1,4 +1,4 @@ -NUT-19: Melt tokens Bitcoin On-Chain +NUT-23: Melt tokens Bitcoin On-Chain ========================== `optional` @@ -34,15 +34,24 @@ The mint `Bob` then responds with an array of `PostMeltQuoteBtcOnchainResponse`: [ { "quote": , - "description": , "amount": , "fee": , + "estimated_blocks": , "state": , "expiry": } ] ``` -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 @@ -53,6 +62,7 @@ curl -X POST https://mint.host:3338/v1/melt/quote/btconchain -d \ { "address": "bc1qkyfgd7mus7ykfd7qkwakq75qsf7rtm...", "unit": "sat" + "amount": 100000 } ``` @@ -64,7 +74,8 @@ Response of `Bob`: "quote": "TRmjduhIsPxd...", "description": "1 sat per vbyte", "amount": 10, - "fee": 2, + "fee": 3000, + "estimated_blocks": 1, "state": "UNPAID", "expiry": 1701704757 }, @@ -72,7 +83,8 @@ Response of `Bob`: "quote": "OewtRaqe...", "description": "5 sat per vbyte", "amount": 10, - "fee": 10, + "fee": 300, + "estimated_blocks": 50, "state": "UNPAID", "expiry": 1701704757 } @@ -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", @@ -181,6 +192,7 @@ The settings for this nut indicate the supported method-unit pairs for melting. "max_amount": 1000000 } ] + "disabled": false, } } ``` diff --git a/README.md b/README.md index b63ab38..254e8d5 100644 --- a/README.md +++ b/README.md @@ -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]