From cc4da3670d07107f17e25d7d694e030e984fde34 Mon Sep 17 00:00:00 2001 From: ngutech21 Date: Mon, 11 Mar 2024 10:48:59 +0100 Subject: [PATCH 01/16] add specs for minting and melting tokens onchain --- 17.md | 201 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 18.md | 209 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 410 insertions(+) create mode 100644 17.md create mode 100644 18.md diff --git a/17.md b/17.md new file mode 100644 index 0000000..b3068d6 --- /dev/null +++ b/17.md @@ -0,0 +1,201 @@ +NUT-17: Mint tokens Bitcoin On-Chain +========================== + +`optional` + +--- + +This NUT describes the process of minting tokens on Bitcoin On-Chain analog to NUT-04 for Bitcoin Lightning. + +# Mint quote + +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 `btconchain`). + +```http +POST https://mint.host:3338/v1/mint/quote/btconchain +``` + +The wallet of `Alice` includes the following `PostMintQuoteBtcOnchainRequest` data in its request: + +```json +{ + "amount": , + "unit": +} +``` + with the requested `amount` and the `unit`. + + The mint `Bob` then responds with a `PostMintQuoteBtcOnchainResponse`: + +```json +{ + "quote": , + "address": , + "paid": , + "expiry": +} +``` + +Where `quote` is the quote ID and `address` is the payment request to fulfill. `paid` indicates whether the request as been paid and `expiry` is the Unix timestamp until which the mint quote is valid. + +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. + +## 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" +``` + +Response of `Bob`: + +```json +{ + "quote": "DSGLX9kevM...", + "address": "bc1qkyfgd7mus7ykfd7qkwakq75qsf7rtm...", + "paid": false, + "expiry": 1701704757 +} +``` + +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 + +To check whether a mint quote has been paid, `Alice` makes a `GET /v1/mint/quote/btconchain/{quote_id}`. + +```http +GET https://mint.host:3338/v1/mint/quote/btconchain/{quote_id} +``` + +Like before, the mint `Bob` responds with a `PostMintQuoteBtcOnchainResponse`. + +Example request of `Alice` with curl: + +```bash +curl -X GET https://mint.host:3338/v1/mint/quote/btconchain/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/{method}` endpoint where `method` is the payment method requested (here `btconchain`). + +```http +POST https://mint.host:3338/v1/mint/btconchain +``` + +The wallet `Alice` includes the following `PostMintBtcOnchainRequest` data in its request + +```json +{ + "quote": , + "outputs": +} +``` + 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 mint `Bob` then responds with a `PostMintBtcOnchainResponse`: + +```json +{ + "signatures": +} +``` + +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/btconchain -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" + } + ] +} +``` + +## 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" + } +] +``` + +## Settings +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 +{ + "14": { + "supported": true, + "methods": [ + { + "payment_method": "btconchain", + "unit": "sat", + "min_amount": 1000, + "max_amount": 1000000 + } + ] + } +} +``` + +[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 diff --git a/18.md b/18.md new file mode 100644 index 0000000..ee93a40 --- /dev/null +++ b/18.md @@ -0,0 +1,209 @@ +NUT-18: Melt tokens Bitcoin On-Chain +========================== + +`optional` + +--- + +This NUT describes the process of melting tokens on Bitcoin On-Chain analog to NUT-05 for Bitcoin Lightning. + +# Melt quote + +To request a melt quote, the wallet of `Alice` makes a `POST /v1/melt/quote/{method}` request where `method` is the payment method requested (here `btconchain`). + +```http +POST https://mint.host:3338/v1/melt/quote/btconchain +``` + +The wallet `Alice` includes the following `PostMeltQuoteBtcOnchainRequest` data in its request: + +```json +{ + "amount": , + "address": , + "unit": +} +``` + +Here, `address` is the Bitcoin on chain address to be paid and `unit` is the unit the wallet would like to pay with. + +The mint `Bob` then responds with an array of `PostMeltQuoteBtcOnchainResponse`: + + +```json +[ + { + "quote": , + "description": , + "amount": , + "fee": , + "paid": , + "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. + +## Example + +Request of `Alice` with curl: + +```bash +curl -X POST https://mint.host:3338/v1/melt/quote/btconchain -d \ +{ + "address": "bc1qkyfgd7mus7ykfd7qkwakq75qsf7rtm...", + "unit": "sat" +} +``` + +Response of `Bob`: + +```json +[ + { + "quote": "TRmjduhIsPxd...", + "description": "1 sat per vbyte", + "amount": 10, + "fee": 2, + "paid": false, + "expiry": 1701704757 + }, + { + "quote": "OewtRaqe...", + "description": "5 sat per vbyte", + "amount": 10, + "fee": 10, + "paid": false, + "expiry": 1701704757 + } +] +``` + +## Check melt quote state + +To check whether a melt quote has been paid, `Alice` makes a `GET /v1/melt/quote/btconchain/{quote_id}`. + +```http +GET https://mint.host:3338/v1/melt/quote/btconchain/{quote_id} +``` + +Like before, the mint `Bob` responds with a `PostMeltQuoteBtcOnchainResponse`. + +Example request of `Alice` with curl: + +```bash +curl -X GET https://mint.host:3338/v1/melt/quote/btconchain/TRmjduhIsPxd... +``` + +# Melting tokens + +Now that `Alice` knows what the total amount is (`amount + fee`) in her requested `unit`, she can proceed for melting tokens for which a payment will be executed by the mint. She calls the `POST /v1/melt/{method}` endpoint where `method` is the payment method requested (here `btconchain`). + +```http +POST https://mint.host:3338/v1/melt/btconchain +``` + +The wallet of `Alice` includes the following `PostMeltBtcOnchainRequest` data in its request + +```json +{ + "quote": , + "inputs": +} +``` + +Here, `quote` is the melt quote ID to be paid and `inputs` are the proofs with a total amount of at least `amount + fee` (see previous melt quote response). + +The mint `Bob` then responds with a `PostMeltBtcOnchainResponse`: + +```json +{ + "paid": , + "txid": +} +``` +`paid` is a boolean indicating whether the payment was successful, and `txid` is the Bitcoin on chain transaction id of the transmitted transaction. + +If `paid==true`, `Alice`'s wallet can delete the `inputs` from her database (or move them to a history). If `paid==false`, `Alice` can repeat the same request again until the payment is successful. + +## Example + +Request of `Alice` with curl: + +```bash +curl -X POST https://mint.host:3338/v1/melt/btconchain -d \ +'{ + "quote": "od4CN5smMMS3K3QVHkbGGNCTxfcAIyIXeq8IrfhP", + "inputs": [ + { + "amount": 4, + "id": "009a1f293253e41e", + "secret": "429700b812a58436be2629af8731a31a37fce54dbf8cbbe90b3f8553179d23f5", + "C": "03b01869f528337e161a6768b480fcf9f75fd248b649c382f5e352489fd84fd011", + }, + { + "amount": 8, + "id": "009a1f293253e41e", + "secret": "4f3155acef6481108fcf354f6d06e504ce8b441e617d30c88924991298cdbcad", + "C": "0278ab1c1af35487a5ea903b693e96447b2034d0fd6bac529e753097743bf73ca9", + } + ] +}' +``` + +Response of `Bob`: + +```json +{ + "paid": true, + "txid": "61470d1816e107165e08eb12a8526e7f6da9f6432fbb9da9f50fd0feb290a584" +} +``` + + +# Check transaction status: +To check whether a Bitcoin onchain transaction has been paid, `Alice` makes a `GET /v1/melt/btconchain/{tx_id}`. + +```http +GET https://mint.host:3338/v1/melt/btconchain/{tx_id} +``` + +The mint `Bob` responds with a `GetMeltBtcOnchainResponse`. + +```json +{ + "paid": false +} +``` + +# Settings +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 +{ + "15": { + "supported": true, + "methods": [ + { + "payment_method": "btconchain", + "unit": "sat", + "min_amount": 1000, + "max_amount": 1000000 + } + ] + } +} +``` + +[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 From 5a1edde2d41f9ad7d669371f3d0731da739cd971 Mon Sep 17 00:00:00 2001 From: Steffen <99717310+ngutech21@users.noreply.github.com> Date: Sat, 30 Mar 2024 09:25:31 +0100 Subject: [PATCH 02/16] chore: rename payment_method to method Co-authored-by: callebtc <93376500+callebtc@users.noreply.github.com> --- 17.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/17.md b/17.md index b3068d6..28d16fa 100644 --- a/17.md +++ b/17.md @@ -176,7 +176,7 @@ The settings for this nut indicate the supported method-unit pairs for minting a "supported": true, "methods": [ { - "payment_method": "btconchain", + "method": "btconchain", "unit": "sat", "min_amount": 1000, "max_amount": 1000000 From 2290606a1a6b9adec27c5efbdc69be32523ccfb5 Mon Sep 17 00:00:00 2001 From: Steffen <99717310+ngutech21@users.noreply.github.com> Date: Sat, 30 Mar 2024 09:26:04 +0100 Subject: [PATCH 03/16] chore: increase min_amount Co-authored-by: callebtc <93376500+callebtc@users.noreply.github.com> --- 17.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/17.md b/17.md index 28d16fa..6b3e8c5 100644 --- a/17.md +++ b/17.md @@ -178,7 +178,7 @@ The settings for this nut indicate the supported method-unit pairs for minting a { "method": "btconchain", "unit": "sat", - "min_amount": 1000, + "min_amount": 10000, "max_amount": 1000000 } ] From b4dc153760361af604643f138369d17a4d125576 Mon Sep 17 00:00:00 2001 From: Steffen <99717310+ngutech21@users.noreply.github.com> Date: Sun, 31 Mar 2024 12:53:10 +0200 Subject: [PATCH 04/16] chore: rename payment_method Co-authored-by: thesimplekid --- 18.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/18.md b/18.md index ee93a40..f267bef 100644 --- a/18.md +++ b/18.md @@ -184,7 +184,7 @@ The settings for this nut indicate the supported method-unit pairs for melting. "supported": true, "methods": [ { - "payment_method": "btconchain", + "method": "btconchain", "unit": "sat", "min_amount": 1000, "max_amount": 1000000 From 91f051f304acc62f5d46eef6eae556bc095067ae Mon Sep 17 00:00:00 2001 From: Steffen <99717310+ngutech21@users.noreply.github.com> Date: Tue, 18 Jun 2024 15:38:23 +0200 Subject: [PATCH 05/16] fix: typo in settings Co-authored-by: thesimplekid --- 17.md | 2 +- 18.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/17.md b/17.md index 6b3e8c5..6d1eae5 100644 --- a/17.md +++ b/17.md @@ -172,7 +172,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 { - "14": { + "17": { "supported": true, "methods": [ { diff --git a/18.md b/18.md index f267bef..04643de 100644 --- a/18.md +++ b/18.md @@ -180,7 +180,7 @@ The mint `Bob` responds with a `GetMeltBtcOnchainResponse`. 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 { - "15": { + "18": { "supported": true, "methods": [ { From 46f9867755ed714b808c51973485c9d667c3d8b9 Mon Sep 17 00:00:00 2001 From: Steffen <99717310+ngutech21@users.noreply.github.com> Date: Tue, 18 Jun 2024 15:44:42 +0200 Subject: [PATCH 06/16] fix: txid is optional Co-authored-by: thesimplekid --- 18.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/18.md b/18.md index 04643de..90c75d3 100644 --- a/18.md +++ b/18.md @@ -119,7 +119,7 @@ The mint `Bob` then responds with a `PostMeltBtcOnchainResponse`: ```json { "paid": , - "txid": + "txid": } ``` `paid` is a boolean indicating whether the payment was successful, and `txid` is the Bitcoin on chain transaction id of the transmitted transaction. From bba6d32cbc55d1ac3ff632147ad189f81129936d Mon Sep 17 00:00:00 2001 From: ngutech21 Date: Sun, 28 Jul 2024 15:44:58 +0200 Subject: [PATCH 07/16] chore: OnchainQuoteReponse.description is optional --- 18.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/18.md b/18.md index 90c75d3..af8c94a 100644 --- a/18.md +++ b/18.md @@ -34,7 +34,7 @@ The mint `Bob` then responds with an array of `PostMeltQuoteBtcOnchainResponse`: [ { "quote": , - "description": , + "description": , "amount": , "fee": , "paid": , From 1aaf174bf2a3d9adfe860f86069d9a36b47619dc Mon Sep 17 00:00:00 2001 From: Steffen <99717310+ngutech21@users.noreply.github.com> Date: Sun, 28 Jul 2024 16:17:35 +0200 Subject: [PATCH 08/16] chore: use state enum instead of bool Co-authored-by: thesimplekid --- 18.md | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/18.md b/18.md index af8c94a..dc42cf9 100644 --- a/18.md +++ b/18.md @@ -118,13 +118,18 @@ The mint `Bob` then responds with a `PostMeltBtcOnchainResponse`: ```json { - "paid": , + "state": , "txid": } -``` -`paid` is a boolean indicating whether the payment was successful, and `txid` is the Bitcoin on chain transaction id of the transmitted transaction. -If `paid==true`, `Alice`'s wallet can delete the `inputs` from her database (or move them to a history). If `paid==false`, `Alice` can repeat the same request again until the payment is successful. +`txid` is the Bitcoin on chain transaction id of the transmitted transaction. + +`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. + +If `state==PAID`, `Alice`'s wallet can delete the `inputs` from her database (or move them to a history). If `paid==PENDING`, `Alice` can repeat the same request again until the payment is successful. ## Example From 2e73249e7b72c684ddd67dc80c0d904fa7e39482 Mon Sep 17 00:00:00 2001 From: ngutech21 Date: Sun, 28 Jul 2024 16:29:41 +0200 Subject: [PATCH 09/16] chore: cleanup examples --- 18.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/18.md b/18.md index dc42cf9..08b6221 100644 --- a/18.md +++ b/18.md @@ -37,7 +37,7 @@ The mint `Bob` then responds with an array of `PostMeltQuoteBtcOnchainResponse`: "description": , "amount": , "fee": , - "paid": , + "state": , "expiry": } ] @@ -65,7 +65,7 @@ Response of `Bob`: "description": "1 sat per vbyte", "amount": 10, "fee": 2, - "paid": false, + "state": "UNPAID", "expiry": 1701704757 }, { @@ -73,7 +73,7 @@ Response of `Bob`: "description": "5 sat per vbyte", "amount": 10, "fee": 10, - "paid": false, + "state": "UNPAID", "expiry": 1701704757 } ] @@ -118,7 +118,7 @@ The mint `Bob` then responds with a `PostMeltBtcOnchainResponse`: ```json { - "state": , + "state": , "txid": } @@ -160,7 +160,7 @@ Response of `Bob`: ```json { - "paid": true, + "state": "PENDING", "txid": "61470d1816e107165e08eb12a8526e7f6da9f6432fbb9da9f50fd0feb290a584" } ``` @@ -177,7 +177,7 @@ The mint `Bob` responds with a `GetMeltBtcOnchainResponse`. ```json { - "paid": false + "state": "UNPAID" } ``` From 7b54066f687fea03da35238591f2fe556997cc41 Mon Sep 17 00:00:00 2001 From: Steffen <99717310+ngutech21@users.noreply.github.com> Date: Sun, 28 Jul 2024 16:36:29 +0200 Subject: [PATCH 10/16] chore: use state enum instead of paid flag Co-authored-by: thesimplekid --- 17.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/17.md b/17.md index 6d1eae5..f4fa7db 100644 --- a/17.md +++ b/17.md @@ -36,7 +36,13 @@ The wallet of `Alice` includes the following `PostMintQuoteBtcOnchainRequest` da } ``` -Where `quote` is the quote ID and `address` is the payment request to fulfill. `paid` indicates whether the request as been paid and `expiry` is the Unix timestamp until which the mint quote is valid. +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. 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. From 93a57f0d56fc4e551963fb9e0da54fdadd6465bb Mon Sep 17 00:00:00 2001 From: ngutech21 Date: Sun, 28 Jul 2024 16:38:50 +0200 Subject: [PATCH 11/16] chore: cleaup examples --- 17.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/17.md b/17.md index f4fa7db..b0abb6c 100644 --- a/17.md +++ b/17.md @@ -31,7 +31,7 @@ The wallet of `Alice` includes the following `PostMintQuoteBtcOnchainRequest` da { "quote": , "address": , - "paid": , + "state": , "expiry": } ``` @@ -60,7 +60,7 @@ Response of `Bob`: { "quote": "DSGLX9kevM...", "address": "bc1qkyfgd7mus7ykfd7qkwakq75qsf7rtm...", - "paid": false, + "state": "UNPAID", "expiry": 1701704757 } ``` From 03f4d5ce3b30d93330fab16aa28bc2003241ecb3 Mon Sep 17 00:00:00 2001 From: ngutech21 Date: Sun, 28 Jul 2024 16:45:42 +0200 Subject: [PATCH 12/16] chore: rename nuts --- 17.md | 207 -------------------------------------------------------- 18.md | 179 +++++++++++++++++++++++------------------------- 19.md | 214 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 300 insertions(+), 300 deletions(-) delete mode 100644 17.md create mode 100644 19.md diff --git a/17.md b/17.md deleted file mode 100644 index b0abb6c..0000000 --- a/17.md +++ /dev/null @@ -1,207 +0,0 @@ -NUT-17: Mint tokens Bitcoin On-Chain -========================== - -`optional` - ---- - -This NUT describes the process of minting tokens on Bitcoin On-Chain analog to NUT-04 for Bitcoin Lightning. - -# Mint quote - -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 `btconchain`). - -```http -POST https://mint.host:3338/v1/mint/quote/btconchain -``` - -The wallet of `Alice` includes the following `PostMintQuoteBtcOnchainRequest` data in its request: - -```json -{ - "amount": , - "unit": -} -``` - with the requested `amount` and the `unit`. - - The mint `Bob` then responds with a `PostMintQuoteBtcOnchainResponse`: - -```json -{ - "quote": , - "address": , - "state": , - "expiry": -} -``` - -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. - -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. - -## 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" -``` - -Response of `Bob`: - -```json -{ - "quote": "DSGLX9kevM...", - "address": "bc1qkyfgd7mus7ykfd7qkwakq75qsf7rtm...", - "state": "UNPAID", - "expiry": 1701704757 -} -``` - -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 - -To check whether a mint quote has been paid, `Alice` makes a `GET /v1/mint/quote/btconchain/{quote_id}`. - -```http -GET https://mint.host:3338/v1/mint/quote/btconchain/{quote_id} -``` - -Like before, the mint `Bob` responds with a `PostMintQuoteBtcOnchainResponse`. - -Example request of `Alice` with curl: - -```bash -curl -X GET https://mint.host:3338/v1/mint/quote/btconchain/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/{method}` endpoint where `method` is the payment method requested (here `btconchain`). - -```http -POST https://mint.host:3338/v1/mint/btconchain -``` - -The wallet `Alice` includes the following `PostMintBtcOnchainRequest` data in its request - -```json -{ - "quote": , - "outputs": -} -``` - 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 mint `Bob` then responds with a `PostMintBtcOnchainResponse`: - -```json -{ - "signatures": -} -``` - -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/btconchain -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" - } - ] -} -``` - -## 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" - } -] -``` - -## Settings -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 -{ - "17": { - "supported": true, - "methods": [ - { - "method": "btconchain", - "unit": "sat", - "min_amount": 10000, - "max_amount": 1000000 - } - ] - } -} -``` - -[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 diff --git a/18.md b/18.md index 08b6221..84ae62d 100644 --- a/18.md +++ b/18.md @@ -1,156 +1,134 @@ -NUT-18: Melt tokens Bitcoin On-Chain +NUT-18: Mint tokens Bitcoin On-Chain ========================== `optional` --- -This NUT describes the process of melting tokens on Bitcoin On-Chain analog to NUT-05 for Bitcoin Lightning. +This NUT describes the process of minting tokens on Bitcoin On-Chain analog to NUT-04 for Bitcoin Lightning. -# Melt quote +# Mint quote -To request a melt quote, the wallet of `Alice` makes a `POST /v1/melt/quote/{method}` request where `method` is the payment method requested (here `btconchain`). +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 `btconchain`). ```http -POST https://mint.host:3338/v1/melt/quote/btconchain +POST https://mint.host:3338/v1/mint/quote/btconchain ``` -The wallet `Alice` includes the following `PostMeltQuoteBtcOnchainRequest` data in its request: +The wallet of `Alice` includes the following `PostMintQuoteBtcOnchainRequest` data in its request: ```json { "amount": , - "address": , "unit": } ``` + with the requested `amount` and the `unit`. + + The mint `Bob` then responds with a `PostMintQuoteBtcOnchainResponse`: -Here, `address` is the Bitcoin on chain address to be paid and `unit` is the unit the wallet would like to pay with. +```json +{ + "quote": , + "address": , + "state": , + "expiry": +} +``` -The mint `Bob` then responds with an array of `PostMeltQuoteBtcOnchainResponse`: +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. -```json -[ - { - "quote": , - "description": , - "amount": , - "fee": , - "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. +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. ## Example Request of `Alice` with curl: ```bash -curl -X POST https://mint.host:3338/v1/melt/quote/btconchain -d \ -{ - "address": "bc1qkyfgd7mus7ykfd7qkwakq75qsf7rtm...", - "unit": "sat" -} +curl -X POST https://mint.host:3338/v1/mint/quote/btconchain -d '{"amount": 10, "unit": "sat"}' -H "Content-Type: application/json" ``` Response of `Bob`: ```json -[ - { - "quote": "TRmjduhIsPxd...", - "description": "1 sat per vbyte", - "amount": 10, - "fee": 2, +{ + "quote": "DSGLX9kevM...", + "address": "bc1qkyfgd7mus7ykfd7qkwakq75qsf7rtm...", "state": "UNPAID", - "expiry": 1701704757 - }, - { - "quote": "OewtRaqe...", - "description": "5 sat per vbyte", - "amount": 10, - "fee": 10, - "state": "UNPAID", - "expiry": 1701704757 - } -] + "expiry": 1701704757 +} ``` -## Check melt quote state +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 -To check whether a melt quote has been paid, `Alice` makes a `GET /v1/melt/quote/btconchain/{quote_id}`. +To check whether a mint quote has been paid, `Alice` makes a `GET /v1/mint/quote/btconchain/{quote_id}`. ```http -GET https://mint.host:3338/v1/melt/quote/btconchain/{quote_id} +GET https://mint.host:3338/v1/mint/quote/btconchain/{quote_id} ``` -Like before, the mint `Bob` responds with a `PostMeltQuoteBtcOnchainResponse`. +Like before, the mint `Bob` responds with a `PostMintQuoteBtcOnchainResponse`. Example request of `Alice` with curl: ```bash -curl -X GET https://mint.host:3338/v1/melt/quote/btconchain/TRmjduhIsPxd... +curl -X GET https://mint.host:3338/v1/mint/quote/btconchain/DSGLX9kevM... ``` -# Melting tokens +# Minting tokens -Now that `Alice` knows what the total amount is (`amount + fee`) in her requested `unit`, she can proceed for melting tokens for which a payment will be executed by the mint. She calls the `POST /v1/melt/{method}` endpoint where `method` is the payment method requested (here `btconchain`). +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`). ```http -POST https://mint.host:3338/v1/melt/btconchain +POST https://mint.host:3338/v1/mint/btconchain ``` -The wallet of `Alice` includes the following `PostMeltBtcOnchainRequest` data in its request +The wallet `Alice` includes the following `PostMintBtcOnchainRequest` data in its request ```json { "quote": , - "inputs": + "outputs": } ``` - -Here, `quote` is the melt quote ID to be paid and `inputs` are the proofs with a total amount of at least `amount + fee` (see previous melt quote response). - -The mint `Bob` then responds with a `PostMeltBtcOnchainResponse`: + 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 mint `Bob` then responds with a `PostMintBtcOnchainResponse`: ```json { - "state": , - "txid": + "signatures": } +``` -`txid` is the Bitcoin on chain transaction id of the transmitted transaction. - -`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. - -If `state==PAID`, `Alice`'s wallet can delete the `inputs` from her database (or move them to a history). If `paid==PENDING`, `Alice` can repeat the same request again until the payment is successful. +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/melt/btconchain -d \ +curl -X POST https://mint.host:3338/v1/mint/btconchain -H "Content-Type: application/json" -d \ '{ - "quote": "od4CN5smMMS3K3QVHkbGGNCTxfcAIyIXeq8IrfhP", - "inputs": [ + "quote": "DSGLX9kevM...", + "outputs": [ { - "amount": 4, + "amount": 8, "id": "009a1f293253e41e", - "secret": "429700b812a58436be2629af8731a31a37fce54dbf8cbbe90b3f8553179d23f5", - "C": "03b01869f528337e161a6768b480fcf9f75fd248b649c382f5e352489fd84fd011", + "B_": "035015e6d7ade60ba8426cefaf1832bbd27257636e44a76b922d78e79b47cb689d" }, { - "amount": 8, + "amount": 2, "id": "009a1f293253e41e", - "secret": "4f3155acef6481108fcf354f6d06e504ce8b441e617d30c88924991298cdbcad", - "C": "0278ab1c1af35487a5ea903b693e96447b2034d0fd6bac529e753097743bf73ca9", + "B_": "0288d7649652d0a83fc9c966c969fb217f15904431e61a44b14999fabc1b5d9ac6" } ] }' @@ -160,29 +138,44 @@ Response of `Bob`: ```json { - "state": "PENDING", - "txid": "61470d1816e107165e08eb12a8526e7f6da9f6432fbb9da9f50fd0feb290a584" + "signatures": [ + { + "id": "009a1f293253e41e", + "amount": 2, + "C_": "0224f1c4c564230ad3d96c5033efdc425582397a5a7691d600202732edc6d4b1ec" + }, + { + "id": "009a1f293253e41e", + "amount": 8, + "C_": "0277d1de806ed177007e5b94a8139343b6382e472c752a74e99949d511f7194f6c" + } + ] } ``` +## Unblinding signatures -# Check transaction status: -To check whether a Bitcoin onchain transaction has been paid, `Alice` makes a `GET /v1/melt/btconchain/{tx_id}`. - -```http -GET https://mint.host:3338/v1/melt/btconchain/{tx_id} -``` - -The mint `Bob` responds with a `GetMeltBtcOnchainResponse`. +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 -{ - "state": "UNPAID" -} +[ + { + "id": "009a1f293253e41e", + "amount": 2, + "secret": "407915bc212be61a77e3e6d2aeb4c727980bda51cd06a6afc29e2861768a7837", + "C": "02bc9097997d81afb2cc7346b5e4345a9346bd2a506eb7958598a72f0cf85163ea" + }, + { + "id": "009a1f293253e41e", + "amount": 8, + "secret": "fe15109314e61d7756b0f8ee0f23a624acaa3f4e042f61433c728c7057b931be", + "C": "029e8e5050b890a7d6c0968db16bc1d5d5fa040ea1de284f6ec69d61299f671059" + } +] ``` -# Settings -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 +## Settings +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": { @@ -191,7 +184,7 @@ The settings for this nut indicate the supported method-unit pairs for melting. { "method": "btconchain", "unit": "sat", - "min_amount": 1000, + "min_amount": 10000, "max_amount": 1000000 } ] diff --git a/19.md b/19.md new file mode 100644 index 0000000..5402f04 --- /dev/null +++ b/19.md @@ -0,0 +1,214 @@ +NUT-19: Melt tokens Bitcoin On-Chain +========================== + +`optional` + +--- + +This NUT describes the process of melting tokens on Bitcoin On-Chain analog to NUT-05 for Bitcoin Lightning. + +# Melt quote + +To request a melt quote, the wallet of `Alice` makes a `POST /v1/melt/quote/{method}` request where `method` is the payment method requested (here `btconchain`). + +```http +POST https://mint.host:3338/v1/melt/quote/btconchain +``` + +The wallet `Alice` includes the following `PostMeltQuoteBtcOnchainRequest` data in its request: + +```json +{ + "amount": , + "address": , + "unit": +} +``` + +Here, `address` is the Bitcoin on chain address to be paid and `unit` is the unit the wallet would like to pay with. + +The mint `Bob` then responds with an array of `PostMeltQuoteBtcOnchainResponse`: + + +```json +[ + { + "quote": , + "description": , + "amount": , + "fee": , + "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. + +## Example + +Request of `Alice` with curl: + +```bash +curl -X POST https://mint.host:3338/v1/melt/quote/btconchain -d \ +{ + "address": "bc1qkyfgd7mus7ykfd7qkwakq75qsf7rtm...", + "unit": "sat" +} +``` + +Response of `Bob`: + +```json +[ + { + "quote": "TRmjduhIsPxd...", + "description": "1 sat per vbyte", + "amount": 10, + "fee": 2, + "state": "UNPAID", + "expiry": 1701704757 + }, + { + "quote": "OewtRaqe...", + "description": "5 sat per vbyte", + "amount": 10, + "fee": 10, + "state": "UNPAID", + "expiry": 1701704757 + } +] +``` + +## Check melt quote state + +To check whether a melt quote has been paid, `Alice` makes a `GET /v1/melt/quote/btconchain/{quote_id}`. + +```http +GET https://mint.host:3338/v1/melt/quote/btconchain/{quote_id} +``` + +Like before, the mint `Bob` responds with a `PostMeltQuoteBtcOnchainResponse`. + +Example request of `Alice` with curl: + +```bash +curl -X GET https://mint.host:3338/v1/melt/quote/btconchain/TRmjduhIsPxd... +``` + +# Melting tokens + +Now that `Alice` knows what the total amount is (`amount + fee`) in her requested `unit`, she can proceed for melting tokens for which a payment will be executed by the mint. She calls the `POST /v1/melt/{method}` endpoint where `method` is the payment method requested (here `btconchain`). + +```http +POST https://mint.host:3338/v1/melt/btconchain +``` + +The wallet of `Alice` includes the following `PostMeltBtcOnchainRequest` data in its request + +```json +{ + "quote": , + "inputs": +} +``` + +Here, `quote` is the melt quote ID to be paid and `inputs` are the proofs with a total amount of at least `amount + fee` (see previous melt quote response). + +The mint `Bob` then responds with a `PostMeltBtcOnchainResponse`: + +```json +{ + "state": , + "txid": +} + +`txid` is the Bitcoin on chain transaction id of the transmitted transaction. + +`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. + +If `state==PAID`, `Alice`'s wallet can delete the `inputs` from her database (or move them to a history). If `paid==PENDING`, `Alice` can repeat the same request again until the payment is successful. + +## Example + +Request of `Alice` with curl: + +```bash +curl -X POST https://mint.host:3338/v1/melt/btconchain -d \ +'{ + "quote": "od4CN5smMMS3K3QVHkbGGNCTxfcAIyIXeq8IrfhP", + "inputs": [ + { + "amount": 4, + "id": "009a1f293253e41e", + "secret": "429700b812a58436be2629af8731a31a37fce54dbf8cbbe90b3f8553179d23f5", + "C": "03b01869f528337e161a6768b480fcf9f75fd248b649c382f5e352489fd84fd011", + }, + { + "amount": 8, + "id": "009a1f293253e41e", + "secret": "4f3155acef6481108fcf354f6d06e504ce8b441e617d30c88924991298cdbcad", + "C": "0278ab1c1af35487a5ea903b693e96447b2034d0fd6bac529e753097743bf73ca9", + } + ] +}' +``` + +Response of `Bob`: + +```json +{ + "state": "PENDING", + "txid": "61470d1816e107165e08eb12a8526e7f6da9f6432fbb9da9f50fd0feb290a584" +} +``` + + +# Check transaction status: +To check whether a Bitcoin onchain transaction has been paid, `Alice` makes a `GET /v1/melt/btconchain/{tx_id}`. + +```http +GET https://mint.host:3338/v1/melt/btconchain/{tx_id} +``` + +The mint `Bob` responds with a `GetMeltBtcOnchainResponse`. + +```json +{ + "state": "UNPAID" +} +``` + +# Settings +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, + "methods": [ + { + "method": "btconchain", + "unit": "sat", + "min_amount": 1000, + "max_amount": 1000000 + } + ] + } +} +``` + +[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 From f48d97ab5171f9abba1cbd1a6d7e27848ef2d903 Mon Sep 17 00:00:00 2001 From: ngutech21 Date: Mon, 29 Jul 2024 09:49:57 +0200 Subject: [PATCH 13/16] chore: add nut-18 and nut-19 to readme --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 910b52a..beb7b5a 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,8 @@ Wallets and mints `MUST` implement all mandatory specs and `CAN` implement optio | [15][15] | Partial multi-path payments (MPP) | [Nutshell][py] | [Nutshell][py] | | [16][16] | Animated QR codes | [Cashu.me][cashume] | - | | [17][17] | WebSocket subscriptions | [Nutshell][py] | [Nutshell][py] | +| [18][18] | Mint tokens Bitcoin On-Chain | [Moksha][moksha] | [Moksha][moksha] | +| [19][19] | Melt tokens Bitcoin On-Chain | [Moksha][moksha] | [Moksha][moksha] | #### Wallets: @@ -85,3 +87,5 @@ Wallets and mints `MUST` implement all mandatory specs and `CAN` implement optio [15]: 15.md [16]: 16.md [17]: 17.md +[18]: 18.md +[19]: 19.md From f2d660d2afa3d02f7fdd0b725f9918c755be821c Mon Sep 17 00:00:00 2001 From: ngutech21 Date: Mon, 29 Jul 2024 09:59:46 +0200 Subject: [PATCH 14/16] feat: add min-confirmations to info-endpoint --- 18.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/18.md b/18.md index 84ae62d..b8542ff 100644 --- a/18.md +++ b/18.md @@ -185,7 +185,8 @@ The settings for this nut indicate the supported method-unit pairs for minting a "method": "btconchain", "unit": "sat", "min_amount": 10000, - "max_amount": 1000000 + "max_amount": 1000000, + "min_confirmations": 3 } ] } From 94c139cdfa22d1759776da772a7be0e91f223308 Mon Sep 17 00:00:00 2001 From: ngutech21 Date: Mon, 29 Jul 2024 10:10:55 +0200 Subject: [PATCH 15/16] fix: formatting --- 19.md | 1 + 1 file changed, 1 insertion(+) diff --git a/19.md b/19.md index 5402f04..7c36de5 100644 --- a/19.md +++ b/19.md @@ -121,6 +121,7 @@ The mint `Bob` then responds with a `PostMeltBtcOnchainResponse`: "state": , "txid": } +``` `txid` is the Bitcoin on chain transaction id of the transmitted transaction. From 27a8e38705d666c07ab3f3557b12c7dd068505d7 Mon Sep 17 00:00:00 2001 From: ngutech21 Date: Mon, 29 Jul 2024 10:16:50 +0200 Subject: [PATCH 16/16] chore: remove check tx-status --- 19.md | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/19.md b/19.md index 7c36de5..c4340dd 100644 --- a/19.md +++ b/19.md @@ -167,21 +167,6 @@ Response of `Bob`: ``` -# Check transaction status: -To check whether a Bitcoin onchain transaction has been paid, `Alice` makes a `GET /v1/melt/btconchain/{tx_id}`. - -```http -GET https://mint.host:3338/v1/melt/btconchain/{tx_id} -``` - -The mint `Bob` responds with a `GetMeltBtcOnchainResponse`. - -```json -{ - "state": "UNPAID" -} -``` - # Settings 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