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.
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.
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.
tlv_stream
:encrypted_data_tlv
- types:
- type: xxx (
add_funding
) - data:
- [
u64
:funding_amount_msat
]
- [
- type: xxx (
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.
-
tlv_stream
:invoice
-
types:
- type: xxx (
funding_prepayments
) - data:
- [
...*funding_prepayment
:funding_prepayments
]
- [
- type: xxx (
-
subtype:
funding_prepayment
-
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
.
tlv_stream
:invoice_request
- types:
- type: xxx (
invreq_update_invoice
) - data:
- [
32*byte
:payment_hash
] - [
...*32*byte
:prepayment_preimages
]
- [
- type: xxx (
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 thatpayment_hash
. - If it already made a prepayment and obtained the corresponding preimage:
- MUST include it in
prepayment_preimages
.
- MUST include it in
- MUST include
The writer of invoice
:
- If it doesn't have enough inbound liquidity to receive the payment:
- MUST include
funding_prepayment
using a randomprepayment_preimage
. - MUST include
add_funding
with an amount larger than the expected payment in the encrypted payload for its LSP in theprepayment_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
containsprevious_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 eachprevious_prepayment
, without any blinded path (they have already been paid).
- MUST generate an invoice with the same
- Otherwise:
- MUST ignore the
invoice_request
.
- MUST ignore the
- If they match a previous invoice for that
- MUST include
- Otherwise:
- MAY include
funding_prepayment
.
- MAY include
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.
We add the following field to the open_channel2
and splice_init
messages,
to link inbound liquidity with a given HTLC:
-
tlv_stream
:open_channel2_tlvs
-
types:
- type: xxx (
prepayment_hash
) - data:
- [
32*byte
:prepayment_hash
]
- [
- type: xxx (
-
tlv_stream
:splice_init_tlvs
-
types:
- type: xxx (
prepayment_hash
) - data:
- [
32*byte
:prepayment_hash
]
- [
- type: xxx (
We add the following field to the tx_signatures
message, to fulfill the HTLC
linked with the additional inbound liquidity:
tlv_stream
:tx_signatures_tlvs
- types:
- type: xxx (
prepayment_preimage
) - data:
- [
32*byte
:preimage
]
- [
- type: xxx (
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
.
- MUST send an HTLC for the corresponding
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 theadd_funding
field:- If the HTLC's
amount_msat
matches the fees it requires to add at leastfunding_amount_msat
of liquidity towards the next node:- MUST NOT forward that HTLC.
- MUST send
open_channel2
orsplice_init
instead withprepayment_hash
set to the HTLC'spayment_hash
.
- Otherwise:
- MUST fail the HTLC.
- If the HTLC's
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
intx_signatures
.
- If the proposed funding amount is greater than the
The sender of tx_signatures
:
- If the interactive-tx protocol included a
prepayment_hash
:- MUST include the corresponding
prepayment_preimage
.
- MUST include the corresponding
The receiver of tx_signatures
:
- If it included a
prepayment_hash
inopen_channel2
orsplice_init
:- If
prepayment_preimage
is missing or does not matchprepayment_hash
:- MUST NOT send
tx_signatures
. - MUST abort the funding attempt.
- MUST fail the corresponding incoming HTLC.
- MUST NOT send
- Otherwise:
- MUST send
tx_signatures
and broadcast the funding transaction. - When it receives
channel_ready
orsplice_locked
:- MUST fulfill the corresponding incoming HTLC.
- If the corresponding incoming HTLC is close to its expiry:
- MUST fulfill it.
- MUST send
- If
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.
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) |
| |--------------------------------------->|
| | |
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) |
| |--------------------------------------->|
| | |
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) |
| |--------------------------------------->|
| | |
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) |
| |--------------------------------------->|
| | |
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) |
| |--------------------------------------->|
| | |
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 |<---------------------------------------| |
| | |
But it's dangerous for her to buy inbound liquidity here, that can be abused to make her buy unused liquidity, isn't it?
If I understand you correctly, you're suggesting that when Alice receives an
invoice_request
for an amount that won't fit into her existing channel, she buys liquidity from Bob, and then responds to theinvoice_request
(which should fit into the channel now)? But what if the payment then never comes? Alice will have paid for additional liquidity for no good reason. Anyone could make her pay for a large amount of inbound liquidity and thus drain her balance.It sounds safer to only buy more inbound liquidity when we're sure that a payment that requires it is coming in, isn't it?