Skip to content

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
}