Skip to content

Instantly share code, notes, and snippets.

@t-bast
Last active November 8, 2023 16:46
Show Gist options
  • Save t-bast/69018875f4f95e660ec2cbbc80f711a6 to your computer and use it in GitHub Desktop.
Save t-bast/69018875f4f95e660ec2cbbc80f711a6 to your computer and use it in GitHub Desktop.
On-the-fly channel liquidity (prepaid by sender)

On-the-fly channel liquidity

Table of Contents

Abstract

When a wallet provider is asked to relay payments but the wallet user lacks inbound liquidity, the routing node usually simply fails that payment. That is a missed opportunity to earn fees, and a poor user experience. We propose a protocol to add more liquidity on-the-fly to be able to route those payments and earn additional fees for the liquidity provided.

This is particularly useful when combined with zero-conf (to avoid locking up HTLCs while the additional liquidity is waiting for confirmations) for mobile wallet users. But even without zero-conf, we will only lock a single, low-value prepayment HTLC, which should have a minimal impact on the network.

Specification

Feature bits

Bits Name Description Context Dependencies
260/261 on_the_fly_funding On-the-fly channel funding IN9 Bolt 12

Nodes may activate this feature bit when they want to add more liquidity to lightning channels when incoming payments require it. Wallets should set this feature bit in their Bolt 12 offers and invoices, since this feature requires the payment sender to collaborate.

Extensions for Bolt 12 messages

We add the following field to the encrypted_data payload that the recipient includes in its blinded path for its LSP, to let them know that they should provide inbound liquidity instead of relaying the incoming HTLC.

  1. tlv_stream: encrypted_data_tlv
  2. types:
    1. type: xxx (add_funding)
    2. data:
      • [u64:funding_amount_msat]

We add fields to the invoice message to tell the payer that we want them to prepay additional inbound liquidity, which will be subtracted from the invoice amount.

  1. tlv_stream: invoice

  2. types:

    1. type: xxx (funding_prepayments)
    2. data:
      • [...*funding_prepayment:funding_prepayments]
  3. subtype: funding_prepayment

  4. data:

    • [32*byte:prepayment_hash]
    • [u64:amount_msat]
    • [...*blinded_path:prepayment_paths]

We add fields to the invoice_request message to let the recipient know that we already prepaid for some additional inbound liquidity, but still could not send the remaining amount off-chain, and want an updated invoice for the same payment_hash.

  1. tlv_stream: invoice_request
  2. types:
    1. type: xxx (invreq_update_invoice)
    2. data:
      • [32*byte:payment_hash]
      • [...*32*byte:prepayment_preimages]

Requirements

The writer of invoice_request:

  • If it tried paying an invoice for a given payment_hash and received an error:
    • MUST include invreq_update_invoice with that payment_hash.
    • If it already made a prepayment and obtained the corresponding preimage:
      • MUST include it in prepayment_preimages.

The writer of invoice:

  • If it doesn't have enough inbound liquidity to receive the payment:
    • MUST include funding_prepayment using a random prepayment_preimage.
    • MUST include add_funding with an amount larger than the expected payment in the encrypted payload for its LSP in the prepayment_paths.
    • MUST set funding_prepayment.amount_msat to a fee sufficient to pay the LSP for the corresponding additional inbound liquidity.
    • If the invoice_request contains previous_prepayments:
      • If they match a previous invoice for that payment_hash:
        • MUST generate an invoice with the same payment_hash.
        • MUST include one funding_prepayment for each previous_prepayment, without any blinded path (they have already been paid).
      • Otherwise:
        • MUST ignore the invoice_request.
  • Otherwise:
    • MAY include funding_prepayment.

Rationale

The recipient of a payment may decide to split that payment into two parts: one that goes to its LSP to pay fees for additional on-the-fly inbound liquidity, and the other that should be paid off-chain using that additional liquidity. This can be done at any time, even if the recipient already has enough inbound liquidity (but wishes to increase it to prepare for other future payments).

Since we lose the atomicity property of normal lightning payments (because the prepayment may be fulfilled while the remaining amount may fail to route), we bundle them into a single invoice, which becomes stateful and accounts for the prepayments that have already been performed. After enough rounds of invoice update and prepayments, the sender should be able to pay the full amount. If the recipient is malicious and not revealing the invoice preimage, the sender will have a signed invoice and the preimages of the prepayments, which still act as some payment proof.

Extensions for interactive-tx messages

We add the following field to the open_channel2 and splice_init messages, to link inbound liquidity with a given HTLC:

  1. tlv_stream: open_channel2_tlvs

  2. types:

    1. type: xxx (prepayment_hash)
    2. data:
      • [32*byte:prepayment_hash]
  3. tlv_stream: splice_init_tlvs

  4. types:

    1. type: xxx (prepayment_hash)
    2. data:
      • [32*byte:prepayment_hash]

We add the following field to the tx_signatures message, to fulfill the HTLC linked with the additional inbound liquidity:

  1. tlv_stream: tx_signatures_tlvs
  2. types:
    1. type: xxx (prepayment_preimage)
    2. data:
      • [32*byte:preimage]

Requirements

The sender of update_add_htlc:

  • If the invoice contains a funding_prepayment for which it doesn't know the preimage:
    • MUST send an HTLC for the corresponding amount_msat using one of the blinded paths provided.
    • MUST NOT send a multi-part payment.
    • MUST NOT send HTLCs for the remaining invoice amount until it receives the prepayment_preimage.

The receiver of update_add_htlc, if it is not the final node:

  • If it is using blinded paths and the encrypted_data field contains the add_funding field:
    • If the HTLC's amount_msat matches the fees it requires to add at least funding_amount_msat of liquidity towards the next node:
      • MUST NOT forward that HTLC.
      • MUST send open_channel2 or splice_init instead with prepayment_hash set to the HTLC's payment_hash.
    • Otherwise:
      • MUST fail the HTLC.

The receiver of update_add_htlc, if it is the final node:

  • If the invoice contains prepayments:
    • MUST accept the HTLC set if the amount paid matches the invoice amount minus the prepayment amounts.

The receiver of open_channel2 or splice_init:

  • If it contains a prepayment_hash that matches an unpaid invoice:
    • If the proposed funding amount is greater than the funding_amount_msat it included in the corresponding blinded paths:
      • MUST accept the funding proposal.
      • MUST send the corresponding prepayment_preimage in tx_signatures.

The sender of tx_signatures:

  • If the interactive-tx protocol included a prepayment_hash:
    • MUST include the corresponding prepayment_preimage.

The receiver of tx_signatures:

  • If it included a prepayment_hash in open_channel2 or splice_init:
    • If prepayment_preimage is missing or does not match prepayment_hash:
      • MUST NOT send tx_signatures.
      • MUST abort the funding attempt.
      • MUST fail the corresponding incoming HTLC.
    • Otherwise:
      • MUST send tx_signatures and broadcast the funding transaction.
      • When it receives channel_ready or splice_locked:
        • MUST fulfill the corresponding incoming HTLC.
      • If the corresponding incoming HTLC is close to its expiry:
        • MUST fulfill it.

Rationale

The payment sender starts by prepaying to ensure that enough liquidity is available: then it can send the remaining payment amount which should have enough liquidity to reach the recipient. If the recipient still lacks some inbound liquidity (because concurrent HTLCs already used that liquidity), an updated invoice will be fetched and another prepayment will be made, until the invoice amount has been fully paid.

The payment recipient reveals the preimage for the prepayment once a funding transaction for at least the expected amount has been negotiated. This lets the sender know that they should be able to send payments for the rest of the invoice amount.

The prepayments are part of the invoice total amount: they should conceptually be paid by the recipient, not the sender. The recipient must thus reveal the invoice preimage if the prepayments and the HTLCs received add up to the invoice amount.

Examples

Initial channel creation

In this example, Alice doesn't have any channel yet.

           Alice                                     Bob                                     Carol
             |                                        |                                        |
             |                                        |             onion_message              |
             |                                        |<---------------------------------------|
             |       invoice_request(50000 sat)       |                                        |
             |<---------------------------------------|                                        |
             |             onion_message              |                                        |
             |--------------------------------------->|                                        |
             |                                        |                invoice                 |
             |                                        |--------------------------------------->| The invoice contains:
             |                                        |                                        |  - payment_hash = H1 = SHA256(p1)
             |                                        |                                        |  - amount = 50 000 sat
             |                                        |                                        |  - prepayment_hash = H2 = SHA256(p2)
             |                                        |                                        |  - prepayment_amount = 3 000 sat
             |                                        |    update_add_htlc(0, H2, 3000 sat)    |
             |                                        |<---------------------------------------|
             |    open_channel2(prepayment_hash=H2)   |                                        |
             |<---------------------------------------|                                        |
             |            accept_channel2             |                                        |
             |--------------------------------------->|                                        |
             |                  ...                   |                                        |
             |            <interactive-tx>            |                                        |
             |                  ...                   |                                        |
             |       tx_signatures(preimage=p2)       |                                        |
             |--------------------------------------->|                                        |
             |              tx_signatures             |                                        |
             |<---------------------------------------|                                        |
             |              channel_ready             |                                        |
             |--------------------------------------->|                                        |
             |              channel_ready             |       update_fulfill_htlc(0, p2)       |
             |<---------------------------------------|--------------------------------------->|
             |                                        |    update_add_htlc(1, H1, 22010 sat)   | Carol uses MPP to send the remaining amount.
             |                                        |<---------------------------------------| She sets total_amount = 47 000 sat in the onion.
             |    update_add_htlc(0, H1, 22000 sat)   |                                        |
             |<---------------------------------------|                                        |
             |                                        |    update_add_htlc(2, H1, 27015 sat)   |
             |                                        |<---------------------------------------|
             |    update_add_htlc(1, H1, 27000 sat)   |                                        |
             |<---------------------------------------|                                        |
             |       update_fulfill_htlc(0, p1)       |                                        |
             |--------------------------------------->|                                        |
             |       update_fulfill_htlc(1, p1)       |       update_fulfill_htlc(1, p1)       |
             |--------------------------------------->|--------------------------------------->|
             |                                        |       update_fulfill_htlc(2, p1)       |
             |                                        |--------------------------------------->|
             |                                        |                                        |

Adding liquidity with splicing

In this example, Alice has a channel but doesn't have enough liquidity to receive the payment because of concurrent HTLCs.

           Alice                                     Bob                                     Carol
             |                                        |                                        |
             |                                        |             onion_message              |
             |                                        |<---------------------------------------|
             |       invoice_request(50000 sat)       |                                        |
             |<---------------------------------------|                                        |
             |             onion_message              |                                        |
             |--------------------------------------->|                                        |
             |                                        |                invoice                 |
             |                                        |--------------------------------------->| The invoice contains:
             |                                        |                                        |  - payment_hash = H1 = SHA256(p1)
             |                                        |                                        |  - amount = 50 000 sat
             |                                        |                                        |
             |                                        |    update_add_htlc(0, H1, 30020 sat)   | Carol uses MPP to pay the invoice.
             |                                        |<---------------------------------------| This HTLC contains the first part.
             |    update_add_htlc(0, H1, 30000 sat)   |                                        |
             |<---------------------------------------|                                        |
             |                                        |    update_add_htlc(1, Hn, 10010 sat)   | Carol (or someone else) sends an unrelated payment.
             |                                        |<---------------------------------------|
             |    update_add_htlc(1, Hn, 10000 sat)   |                                        |
             |<---------------------------------------|                                        |
             |                                        |    update_add_htlc(2, H1, 20015 sat)   | Carol uses MPP to pay the invoice.
             |                                        |<---------------------------------------| This HTLC contains the second part.
             |                     not enough liquidy |                                        |
             |                           X------------|                                        |
             |                                        |          update_fail_htlc(2)           |
             |                                        |--------------------------------------->|
 MPP timeout |          update_fail_htlc(0)           |                                        |
             |--------------------------------------->|                                        |
             |                                        |          update_fail_htlc(0)           |
             |                                        |--------------------------------------->|
             |                                        |             onion_message              |
             |                                        |<---------------------------------------|
             |       invoice_request(50000 sat)       |                                        |
             |        invreq_update_invoice=H1        |                                        |
             |<---------------------------------------|                                        |
             |             onion_message              |                                        |
             |--------------------------------------->|                                        |
             |                                        |                invoice                 |
             |                                        |--------------------------------------->| The invoice contains:
             |                                        |                                        |  - payment_hash = H1 = SHA256(p1)
             |                                        |                                        |  - amount = 50 000 sat
             |                                        |                                        |  - prepayment_hash = H2 = SHA256(p2)
             |                                        |                                        |  - prepayment_amount = 3 000 sat
             |                                        |    update_add_htlc(3, H2, 3000 sat)    |
             |                                        |<---------------------------------------|
             |     splice_init(prepayment_hash=H2)    |                                        |
             |<---------------------------------------|                                        |
             |               splice_ack               |                                        |
             |--------------------------------------->|                                        |
             |                  ...                   |                                        |
             |            <interactive-tx>            |                                        |
             |                  ...                   |                                        |
             |       tx_signatures(preimage=p2)       |                                        |
             |--------------------------------------->|                                        |
             |              tx_signatures             |                                        |
             |<---------------------------------------|                                        |
             |              splice_locked             |                                        |
             |--------------------------------------->|                                        |
             |              splice_locked             |       update_fulfill_htlc(3, p2)       |
             |<---------------------------------------|--------------------------------------->|
             |                                        |    update_add_htlc(4, H1, 22010 sat)   | Carol uses MPP to send the remaining amount.
             |                                        |<---------------------------------------| She sets total_amount = 47 000 sat in the onion.
             |    update_add_htlc(2, H1, 22000 sat)   |                                        |
             |<---------------------------------------|                                        |
             |                                        |    update_add_htlc(5, H1, 27015 sat)   |
             |                                        |<---------------------------------------|
             |    update_add_htlc(3, H1, 27000 sat)   |                                        |
             |<---------------------------------------|                                        |
             |       update_fulfill_htlc(2, p1)       |                                        |
             |--------------------------------------->|                                        |
             |       update_fulfill_htlc(3, p1)       |       update_fulfill_htlc(4, p1)       |
             |--------------------------------------->|--------------------------------------->|
             |                                        |       update_fulfill_htlc(5, p1)       |
             |                                        |--------------------------------------->|
             |                                        |                                        |

Multiple prepayments

In this example, there are multiple rounds of prepayments before Alice has enough liquidity to receive the complete payment amount.

           Alice                                     Bob                                     Carol
             |                                        |                                        |
             |                                        |             onion_message              |
             |                                        |<---------------------------------------|
             |       invoice_request(50000 sat)       |                                        |
             |<---------------------------------------|                                        |
             |             onion_message              |                                        |
             |--------------------------------------->|                                        |
             |                                        |                invoice                 |
             |                                        |--------------------------------------->| The invoice contains:
             |                                        |                                        |  - payment_hash = H1 = SHA256(p1)
             |                                        |                                        |  - amount = 50 000 sat
             |                                        |                                        |  - prepayment_hash = H2 = SHA256(p2)
             |                                        |                                        |  - prepayment_amount = 3 000 sat
             |                                        |    update_add_htlc(0, H2, 3000 sat)    |
             |                                        |<---------------------------------------|
             |     splice_init(prepayment_hash=H2)    |                                        |
             |<---------------------------------------|                                        |
             |               splice_ack               |                                        |
             |--------------------------------------->|                                        |
             |                  ...                   |                                        |
             |            <interactive-tx>            |                                        |
             |                  ...                   |                                        |
             |       tx_signatures(preimage=p2)       |                                        |
             |--------------------------------------->|                                        |
             |              tx_signatures             |                                        |
             |<---------------------------------------|                                        |
             |              splice_locked             |                                        |
             |--------------------------------------->|                                        |
             |              splice_locked             |       update_fulfill_htlc(0, p2)       |
             |<---------------------------------------|--------------------------------------->|
             |                                        |    update_add_htlc(1, H1, 47050 sat)   |
             |                                        |<---------------------------------------|
             |    update_add_htlc(0, H1, 47000 sat)   |                                        |
             |<---------------------------------------|                                        |
             |           update_fail_htlc(0)          |                                        |
             |--------------------------------------->|                                        |
             |                                        |           update_fail_htlc(1)          |
             |                                        |--------------------------------------->|
             |                                        |             onion_message              |
             |                                        |<---------------------------------------|
             |       invoice_request(50000 sat)       |                                        |
             |        invreq_update_invoice=H1        |                                        |
             |         prepayment_preimage=p2         |                                        |
             |<---------------------------------------|                                        |
             |             onion_message              |                                        |
             |--------------------------------------->|                                        |
             |                                        |                invoice                 |
             |                                        |--------------------------------------->| The invoice contains:
             |                                        |                                        |  - payment_hash = H1 = SHA256(p1)
             |                                        |                                        |  - amount = 50 000 sat
             |                                        |                                        |  - prepayment_hash = H2 = SHA256(p2)
             |                                        |                                        |  - prepayment_amount = 3 000 sat
             |                                        |                                        |  - prepayment_hash = H3 = SHA256(p3)
             |                                        |                                        |  - prepayment_amount = 2 000 sat
             |                                        |    update_add_htlc(2, H3, 2000 sat)    |
             |                                        |<---------------------------------------|
             |     splice_init(prepayment_hash=H3)    |                                        |
             |<---------------------------------------|                                        |
             |               splice_ack               |                                        |
             |--------------------------------------->|                                        |
             |                  ...                   |                                        |
             |            <interactive-tx>            |                                        |
             |                  ...                   |                                        |
             |       tx_signatures(preimage=p3)       |                                        |
             |--------------------------------------->|                                        |
             |              tx_signatures             |                                        |
             |<---------------------------------------|                                        |
             |              splice_locked             |                                        |
             |--------------------------------------->|                                        |
             |              splice_locked             |       update_fulfill_htlc(2, p3)       |
             |<---------------------------------------|--------------------------------------->|
             |                                        |    update_add_htlc(3, H1, 45050 sat)   | Carol pays the remaining amount.
             |                                        |<---------------------------------------| She sets total_amount = 45 000 sat in the onion.
             |    update_add_htlc(1, H1, 45000 sat)   |                                        |
             |<---------------------------------------|                                        |
             |       update_fulfill_htlc(1, p1)       |                                        |
             |--------------------------------------->|                                        |
             |                                        |       update_fulfill_htlc(3, p1)       |
             |                                        |--------------------------------------->|
             |                                        |                                        |

Fake prepayment

Alice may also request a prepayment, without tying it to additional inbound liquidity (because she doesn't want the sender to probe her balance). She may also do the opposite, and request additional inbound liquidity even though she has enough funds to receive the payment amount.

           Alice                                     Bob                                     Carol
             |                                        |                                        |
             |                                        |             onion_message              |
             |                                        |<---------------------------------------|
             |       invoice_request(50000 sat)       |                                        |
             |<---------------------------------------|                                        |
             |             onion_message              |                                        |
             |--------------------------------------->|                                        |
             |                                        |                invoice                 |
             |                                        |--------------------------------------->| The invoice contains:
             |                                        |                                        |  - payment_hash = H1 = SHA256(p1)
             |                                        |                                        |  - amount = 50 000 sat
             |                                        |                                        |  - prepayment_hash = H2 = SHA256(p2)
             |                                        |                                        |  - prepayment_amount = 3 000 sat
             |                                        |                                        |  - but the encrypted_data does *not* contain add_funding
             |                                        |    update_add_htlc(0, H2, 3000 sat)    |
             |                                        |<---------------------------------------|
             |    update_add_htlc(0, H2, 3000 sat)    |                                        |
             |<---------------------------------------|                                        |
             |       update_fulfill_htlc(0, p2)       |                                        |
             |--------------------------------------->|                                        |
             |                                        |       update_fulfill_htlc(0, p2)       |
             |                                        |--------------------------------------->|
             |                                        |    update_add_htlc(1, H1, 47000 sat)   |
             |                                        |<---------------------------------------|
             |    update_add_htlc(1, H1, 47000 sat)   |                                        |
             |<---------------------------------------|                                        |
             |       update_fulfill_htlc(1, p1)       |                                        |
             |--------------------------------------->|                                        |
             |                                        |       update_fulfill_htlc(1, p1)       |
             |                                        |--------------------------------------->|
             |                                        |                                        |

Invalid prepayment amount

If Carol tries to send a smaller prepayment, the LSP won't initiate an interactive-tx session.

           Alice                                     Bob                                     Carol
             |                                        |                                        |
             |                                        |             onion_message              |
             |                                        |<---------------------------------------|
             |       invoice_request(50000 sat)       |                                        |
             |<---------------------------------------|                                        |
             |             onion_message              |                                        |
             |--------------------------------------->|                                        |
             |                                        |                invoice                 |
             |                                        |--------------------------------------->| The invoice contains:
             |                                        |                                        |  - payment_hash = H1 = SHA256(p1)
             |                                        |                                        |  - amount = 50 000 sat
             |                                        |                                        |  - prepayment_hash = H2 = SHA256(p2)
             |                                        |                                        |  - prepayment_amount = 3 000 sat
             |                                        |    update_add_htlc(0, H2, 2000 sat)    |
             |                                        |<---------------------------------------|
             |                                        |          update_fail_htlc(0)           |
             |                                        |--------------------------------------->|
             |                                        |                                        |

Invalid prepayment preimage

If Carol doesn't have the prepayment preimage, she cannot trick Alice into updating the initial invoice.

           Alice                                     Bob                                     Carol
             |                                        |                                        |
             |                                        |             onion_message              |
             |                                        |<---------------------------------------|
             |       invoice_request(50000 sat)       |                                        |
             |<---------------------------------------|                                        |
             |             onion_message              |                                        |
             |--------------------------------------->|                                        |
             |                                        |                invoice                 |
             |                                        |--------------------------------------->| The invoice contains:
             |                                        |                                        |  - payment_hash = H1 = SHA256(p1)
             |                                        |                                        |  - amount = 50 000 sat
             |                                        |                                        |  - prepayment_hash = H2 = SHA256(p2)
             |                                        |                                        |  - prepayment_amount = 3 000 sat
             |                                        |             onion_message              |
             |                                        |<---------------------------------------|
             |       invoice_request(50000 sat)       |                                        |
             |        invreq_update_invoice=H1        |                                        |
             |        prepayment_preimage=xxxx        |                                        |
     ignored |<---------------------------------------|                                        |
             |                                        |                                        |
@t-bast
Copy link
Author

t-bast commented Nov 8, 2023

Would they also be used by this proposal to communicate the expected fee the payment receiver should pay their LSP for a given amount of additional inbound liquidity?

Yes, this isn't detailed here, but the payment receiver would use the liquidity rates provided by the LSP to compute the add_funding field.

Some misc editing suggestions:

Thanks, I'll update those!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment