Skip to content

Latest commit

 

History

History
248 lines (192 loc) · 8.21 KB

17.md

File metadata and controls

248 lines (192 loc) · 8.21 KB

NUT-17: Exchanging tokens

optional


Token exchanges are atomic swaps enabled by HTLCs (see [NUT-14][14]). Token exchanges provide a way for eCash tokens to be exchanged for lightning payments without the issuing mint having to run a lightning node. Token exchanges allow for lightning payments to be provided by other users of the same mint, users of a different mint supporting [NUT-17][17], or a mint supporting NUT-05.

The exchange has several steps:

  1. Alice submits a request for quote to the mint
  2. Bob gets the request and submits a quote to the mint. The quote data includes his pubkey.
  3. Alice gets the quote and submits HTLC tokens to the mint
  4. Bob obtains the HTLC preimage by completing the requested payment and redeems the HTLC tokens

In the first request, the wallet of Alice asks the mint for a quote for a request it wants paid and the unit the wallet would like to spend as inputs. The wallet of Bob responds with a quote that includes a quote id and an amount being demanded in the requested unit. For the method bolt11, the Bob includes a fee_reserve field indicating the reserve fee for a Lightning payment. The wallet of Alice includes the quote id and provides HTLC 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 Bob 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 using ecash denominated in Satoshis.

Exchange quote

To request an exchange quote, the wallet of Alice makes a POST /v1/exchange/quote/{method} request where method is the payment method requested (here bolt11).

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

The wallet Alice includes the following PostexchangeQuoteBolt11Request 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.

To obtain the array of outstanding requests, wallet Bob makes a GET /v1/exchange/request/{method} request where method is the payment method requested (here bolt11).

GET https://mint.host:3338/v1/exchange/quote/bolt11

To submit an exchange quote, the wallet of Bob makes a POST /v1/melt/quote/{method}/{invoice} request where method is the payment method requested (here bolt11).

POST https://mint.host:3338/v1/exchange/quote/bolt11/{invoice}

The wallet Bob includes the following PostexchangeQuoteBolt11Response data in its request:

{
  "quote": <str>,
  "amount": <int>,
  "fee_reserve": <int>,
  "expiry": <int>
  "pubkey": <str>
}

Where quote is the quote id, amount the amount that needs to be provided, and fee_reserve the additional fee reserve that is required. Bob expects Alice to include Proofs of at least total_amount = amount + fee_reserve in the form of NUT-14 tokens addressed to pubkey. expiry is the Unix timestamp until which the exchange quote is valid.

To obtain the array of quotes, wallet Alice makes a GET /v1/exchange/request/{method}/{invoice} request where method is the payment method requested (here bolt11).

GET https://mint.host:3338/v1/exchange/quote/bolt11/{invoice}

Wallet Alice submits HTLC proofs as payments for the quote by making a POST /v1/exchange/request/{method}/{invoice}/{quote_id} request where method is the payment method requested (here bolt11).

POST https://mint.host:3338/v1/exchange/quote/bolt11/{invoice}/{quote_id}

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

{
  "inputs": <Array[Proof]>
}

The wallet Bob obtains the HTLC proofs by making a GET /v1/exchange/request/{method}/{invoice}/{quote_id} request where method is the payment method requested (here bolt11). The wallet Bob pays invoice to obtain preimage and uses preimage to redeem the HTLC tokens.

THIS IS THE END OF NUT-17 FOR NOW. EVERYTHING BELOW THIS LINE IS LEFTOVER TEXT FROM NUT-05.

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,
  "paid": false,
  "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 for 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).

The mint Bob then responds with a PostMeltBolt11Response:

{
  "paid": <bool>,
  "payment_preimage": <str|null>
}

paid is a boolean indicating whether the payment was successful, and payment_preimage is the bolt11 payment preimage in case of a successful payment.

If paid==true, Alice's wallet can delete the inputs from her database (or move them to a history). If paid==false, 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 of Bob:

{
  "paid": true,
  "payment_preimage": "c5a1ae1f639e1f4a3872e81500fd028bece7bedc1152f740cba5c3417b748c1b"
}

Settings

The 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 this 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        
}