NUT-04: Mint tokens¶
mandatory
Minting tokens is a two-step process: requesting a mint quote and minting new tokens. Here, we describe both steps.
In the first request the wallet asks the mint for a quote for a specific amount
and unit
to mint, and the payment method
to pay. The mint responds with a quote that includes a quote
id and a payment request
. The user pays the request
and, if successful, requests minting of new tokens with the mint in a second request. The wallet includes the quote
id and new outputs
in the second request.
We limit this document to mint quotes of unit="sat"
and method="bolt11"
which requests a bolt11 Lightning invoice (typically generated by the mint to add Bitcoin to its reserves) to mint ecash denominated in Satoshis.
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 bolt11
).
POST https://mint.host:3338/v1/mint/quote/bolt11
The wallet of Alice
includes the following PostMintQuoteBolt11Request
data in its request:
{
"amount": <int>,
"unit": <str_enum["sat"]>,
"description": <str|null>
}
with the requested amount
and the unit
. An optional description
can be passed if the mint signals support for it in MintMethodSetting
.
The mint Bob
then responds with a PostMintQuoteBolt11Response
:
{
"quote": <str>,
"request": <str>,
"state": <str_enum[STATE]>,
"expiry": <int>
}
Where quote
is the quote ID and request
is the payment request to fulfill. expiry
is the Unix timestamp until which the mint quote is valid.
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.
Example¶
Request of Alice
with curl:
curl -X POST http://localhost:3338/v1/mint/quote/bolt11 -d '{"amount": 10, "unit": "sat"}' -H "Content-Type: application/json"
Response of Bob
:
{
"quote": "DSGLX9kevM...",
"request": "lnbc100n1pj4apw9...",
"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/bolt11/{quote_id}
.
GET https://mint.host:3338/v1/mint/quote/bolt11/{quote_id}
Like before, the mint Bob
responds with a PostMintQuoteBolt11Response
.
Example request of Alice
with curl:
curl -X GET http://localhost:3338/v1/mint/quote/bolt11/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 bolt11
).
POST https://mint.host:3338/v1/mint/bolt11
The wallet Alice
includes the following PostMintBolt11Request
data in its request
{
"quote": <str>,
"outputs": <Array[BlindedMessage]>
}
with the quote
being the quote ID from the previous step and outputs
being BlindedMessages
(see NUT-00) that the wallet requests signatures on whose sum is amount
as requested in the quote.
The mint Bob
then responds with a PostMintBolt11Response
:
{
"signatures": <Array[BlindSignature]>
}
where signatures
is an array of blind signatures on the outputs.
Example¶
Request of Alice
with curl:
curl -X POST https://mint.host:3338/v1/mint/bolt11 -H "Content-Type: application/json" -d \
'{
"quote": "DSGLX9kevM...",
"outputs": [
{
"amount": 8,
"id": "009a1f293253e41e",
"B_": "035015e6d7ade60ba8426cefaf1832bbd27257636e44a76b922d78e79b47cb689d"
},
{
"amount": 2,
"id": "009a1f293253e41e",
"B_": "0288d7649652d0a83fc9c966c969fb217f15904431e61a44b14999fabc1b5d9ac6"
}
]
}'
Response of Bob
:
{
"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.
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). The wallet then stores these Proofs
in its database:
[
{
"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 disabled or not. They are part of the info response of the mint (NUT-06) which in this case reads
{
"4": {
"methods": [
<MintMethodSetting>,
...
],
"disabled": <bool>
}
}
MintMethodSetting
indicates supported method
and unit
pairs and additional settings of the mint. disabled
indicates whether this minting is disabled.
MintMethodSetting
is of the form:
{
"method": <str>,
"unit": <str>,
"min_amount": <int|null>,
"max_amount": <int|null>,
"description": <bool|null>
}
min_amount
and max_amount
indicate the minimum and maximum amount for an operation of this method-unit pair.
Example MintMethodSetting
:
{
"method": "bolt11",
"unit": "sat",
"min_amount": 0,
"max_amount": 10000,
"description": true
}