NUT-05: Melting tokens¶
mandatory
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 status paid and 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
}