Skip to content

NUT-04: Mint tokens

mandatory

used in: NUT-20, NUT-23


Minting tokens is a two-step process: requesting a mint quote and minting new tokens. This document describes the general flow that applies to all payment methods, with specifics for each supported payment method provided in dedicated NUTs.

Supported methods

Method-specific NUTs describe how to handle different payment methods. The currently specified models are:

  • NUT-23 for bolt11 Lightning invoices
  • NUT-25 for bolt12 Lightning offers
  • NUT-30 for onchain Bitcoin transactions

General Flow

The minting process follows these steps for all payment methods:

  1. The wallet requests a mint quote for the unit to mint, specifying the payment method.
  2. The mint responds with a quote that includes a quote id and a payment request.
  3. The user pays the request using the specified payment method.
  4. The wallet then requests minting of new tokens with the mint, including the quote id and new outputs.
  5. The mint verifies payment and returns blind signatures.

Common Request and Response Formats

Requesting a 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 (e.g., bolt11, bolt12, etc.). method MUST match [a-z0-9_-]+.

POST https://mint.host:3338/v1/mint/quote/{method}

Depending on the payment method, the request structure may vary, but all methods will include at minimum:

{
  "unit": <str_enum[UNIT]>
  // Additional method-specific fields may be required
}

The mint Bob responds with a quote that includes some common fields for all methods:

{
  "quote": <str>, // UUID v7
  "request": <str>,
  "unit":  <str_enum[UNIT]>,
  "method": <str>,
  "amount_paid": <int>,
  "amount_issued": <int>,
  "updated_at": <int>,
  // Additional method-specific fields will be included
}

Where:

  • quote is the quote ID in UUID v7 format
  • request is the payment request for the quote
  • unit corresponds to the value provided in the request
  • method is the payment method of the quote
  • amount_paid is the total amount that has been paid to the mint for this quote, denominated in unit
  • amount_issued is the total amount of ecash that has been issued for this quote, denominated in unit
  • updated_at is a Unix timestamp integer indicating when the quote was last updated

Mints MUST include amount_paid, amount_issued, and updated_at in all mint quote responses. amount_paid and amount_issued MUST be non-negative integers, and amount_issued MUST NOT exceed amount_paid.

The amount currently mintable for a quote is amount_paid - amount_issued. Mints MUST NOT issue ecash whose total output amount exceeds amount_paid - amount_issued. If a wallet mints less than the currently mintable amount, amount_issued only increases by the amount that was issued.

Mints MUST update updated_at whenever amount_paid or amount_issued changes. Mints MUST ensure that updated_at monotonically increases for each quote, even if multiple updates occur within the same timestamp resolution. Wallets that receive multiple responses for the same quote MUST NOT replace locally stored quote data with a response whose updated_at is lower than the latest processed value for that quote. Wallets MUST NOT decrease locally stored amount_paid or amount_issued values based on stale responses.

[!CAUTION]

quote is a unique and random id generated by the mint to internally look up the payment state. quote SHOULD be UUID v7 with all 74 variable bits generated by a CSPRNG and 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. To prevent this, use NUT-20 locks to enforce public key authentication during minting.

Check Mint Quote

To check the current accounting data of a mint quote, the wallet makes a GET /v1/mint/quote/{method}/{quote_id}.

GET https://mint.host:3338/v1/mint/quote/{method}/{quote_id}

The mint responds with the same structure as the initial quote response.

Executing a Mint Quote

After requesting a mint quote and paying the request, the wallet proceeds with minting new tokens by calling the POST /v1/mint/{method} endpoint.

POST https://mint.host:3338/v1/mint/{method}

The wallet includes the following common 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. The total output amount MUST NOT exceed the quote's currently mintable amount, amount_paid - amount_issued.

The mint then responds with:

{
  "signatures": <Array[BlindSignature]>
}

where signatures is an array of blind signatures on the outputs.

Adding New Payment Methods

To add a new payment method (e.g., BOLT12), implement the following:

  1. Define the method-specific request and response structures following the pattern above
  2. Implement the three required endpoints: quote request, quote check, and mint execution
  3. Update the settings to include the new method

Settings

The settings for this NUT indicate the supported method-unit pairs for minting. They are part of the info response of the mint (NUT-06) which reads:

{
  "4": {
    "methods": [
      <MintMethodSetting>,
      ...
    ],
    "disabled": <bool>
  }
}

MintMethodSetting indicates supported method and unit pairs and additional settings of the mint. disabled indicates whether minting is disabled.

MintMethodSetting is of the form:

{
  "method": <str>,
  "unit": <str>,
  "method_name": <str|null>,
  "min_amount": <int|null>,
  "max_amount": <int|null>,
  "options": <Object|null>
}

min_amount and max_amount indicate the minimum and maximum amount for an operation of this method-unit pair. options are method-specific and can be defined in method-specific NUTs.

method_name is a human-readable name for the payment method. If null or omitted, wallets SHOULD derive it from method by replacing _ and - with spaces and title-casing each word (e.g. bolt11 -> Bolt11, apple-pay -> Apple Pay).

Unblinding Signatures

Upon receiving the BlindSignatures from the mint, the wallet 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.