Skip to content

NUT-05: Melting tokens

mandatory

used in: NUT-08, NUT-15


Melting tokens is the opposite of minting tokens (see NUT-04). Like minting tokens, melting is a two-step process: requesting a melt quote and melting tokens. Here, we describe both steps.

In the first request the wallet asks the mint for a quote for a request it wants paid by the mint and the unit the wallet would like to spend as inputs. The mint responds with a quote that includes a quote id and an amount the mint demands in the requested unit. For the method bolt11, the mint includes a fee_reserve field indicating the reserve fee for a Lightning payment.

In the second request, the wallet includes the quote id and provides inputs that sum up to amount+fee_reserve in the first response. For the method bolt11, the wallet can also include outputs in order for the mint to return overpaid Lightning fees (see NUT-08). The mint responds with a payment state. If the state is "PAID" the response includes a payment_preimage as a proof of payment. If the request included outputs, the mint may respond with change for the overpaid fees (see NUT-08).

We limit this document to mint quotes of unit="sat" and method="bolt11" which requests a bolt11 Lightning payment (typically paid by the mint from its Bitcoin reserves) using ecash denominated in Satoshis.

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 bolt11).

POST https://mint.host:3338/v1/melt/quote/bolt11

The wallet Alice includes the following PostMeltQuoteBolt11Request data in its request:

{
  "request": <str>,
  "unit": <str_enum["sat"]>
}

Here, request is the bolt11 Lightning invoice to be paid and unit is the unit the wallet would like to pay with.

The mint Bob then responds with a PostMeltQuoteBolt11Response:

{
  "quote": <str>,
  "amount": <int>,
  "fee_reserve": <int>,
  "state": <str_enum[STATE]>,
  "expiry": <int>,
  "payment_preimage": <str|null>
}

Where quote is the quote ID, amount the amount that needs to be provided, and fee_reserve the additional fee reserve that is required. The mint expects Alice to include Proofs of at least total_amount = amount + fee_reserve. expiry is the Unix timestamp until which the melt quote is valid. payment_preimage is the bolt11 payment preimage in case of a successful payment.

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

Request of Alice with curl:

curl -X POST https://mint.host:3338/v1/melt/quote/bolt11 -d \
{
  "request": "lnbc100n1p3kdrv5sp5lpdxzghe5j67q...",
  "unit": "sat"
}

Response of Bob:

{
  "quote": "TRmjduhIsPxd...",
  "amount": 10,
  "fee_reserve": 2,
  "state": "UNPAID",
  "expiry": 1701704757
}

Check melt quote state

To check whether a melt quote has been paid, Alice makes a GET /v1/melt/quote/bolt11/{quote_id}.

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

Like before, the mint Bob responds with a PostMeltQuoteBolt11Response.

Example request of Alice with curl:

curl -X GET http://localhost:3338/v1/melt/quote/bolt11/TRmjduhIsPxd...

Melting tokens

Now that Alice knows what the total amount is (amount + fee_reserve) in her requested unit, she can proceed to 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 bolt11).

POST https://mint.host:3338/v1/melt/bolt11

⚠️ Attention: This call will block until the Lightning payment either succeeds or fails. This can take quite a long time in case the Lightning payment is slow. Make sure to use no (or a very long) timeout when making this call!

The wallet of Alice includes the following PostMeltBolt11Request data in its request

{
  "quote": <str>,
  "inputs": <Array[Proof]>
}

Here, quote is the melt quote ID to be paid and inputs are the proofs with a total amount of at least amount + fee_reserve (see previous melt quote response).

Like before, the mint Bob then responds with a PostMeltQuoteBolt11Response. If the payment was successful, the state field is set to "PAID" and the response includes the payment_preimage field containing the payment secret of the bolt11 payment.

If state=="PAID", Alice's wallet can delete the inputs from her database (or move them to a history). If state=="UNPAID", Alice can repeat the same request again until the payment is successful.

Example

Request of Alice with curl:

curl -X POST https://mint.host:3338/v1/melt/bolt11 -d \
'{
  "quote": "od4CN5smMMS3K3QVHkbGGNCTxfcAIyIXeq8IrfhP",
  "inputs": [
    {
      "amount": 4,
      "id": "009a1f293253e41e",
      "secret": "429700b812a58436be2629af8731a31a37fce54dbf8cbbe90b3f8553179d23f5",
      "C": "03b01869f528337e161a6768b480fcf9f75fd248b649c382f5e352489fd84fd011",
    },
    {
      "amount": 8,
      "id": "009a1f293253e41e",
      "secret": "4f3155acef6481108fcf354f6d06e504ce8b441e617d30c88924991298cdbcad",
      "C": "0278ab1c1af35487a5ea903b693e96447b2034d0fd6bac529e753097743bf73ca9",
    }
  ]
}'

Response PostMeltQuoteBolt11Response of Bob:

{
  "quote": "TRmjduhIsPxd...",
  "amount": 10,
  "fee_reserve": 2,
  "state": "PAID",
  "expiry": 1701704757,
  "payment_preimage": "c5a1ae1f639e1f4a3872e81500fd028bece7bedc1152f740cba5c3417b748c1b"
}

Settings

The mint's settings for this nut indicate the supported method-unit pairs for melting. They are part of the info response of the mint (NUT-06) which in this case reads

{
  "5": {
    "methods": [
      <MeltMethodSetting>,
      ...
    ],
    "disabled": <bool>
  }
}

MeltMethodSetting indicates supported method and unit pairs and additional settings of the mint. disabled indicates whether melting is disabled.

MeltMethodSetting is of the form:

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

min_amount and max_amount indicate the minimum and maximum amount for an operation of this method-unit pair.

Example MeltMethodSetting:

{
  "method": "bolt11",
  "unit": "sat",
  "min_amount": 100,
  "max_amount": 10000
}