From 393a3efa49fbf0723913c75480a63591d0bc6fdb Mon Sep 17 00:00:00 2001 From: t-bast Date: Tue, 5 Mar 2024 17:54:56 +0100 Subject: [PATCH 1/2] Advertise liquidity ads rates Add the ability to advertise rates at which nodes wish to sell their liquidity. Buyers can then connect to sellers and request liquidity, at one of the advertised rates. This can be used when creating a dual-funded channel, where both participants contribute to the funding transaction, and one of them is paid for (some of) their contribution. This can also be used to splice additional liquidity into existing channels, when splicing is supported. We don't add any constraints to the commitment transaction. The lease duration isn't protected by script opcodes, which means that the seller could immediately close the channel, or splice funds out. It is up to the buyer to then blacklist that seller. We can in the future modify the commitment transactions to restrict the seller: a dedicated feature bit will let us add this seamlessly if it is considered useful. --- 01-messaging.md | 3 ++ 02-peer-protocol.md | 121 +++++++++++++++++++++++++++++++++++++++++++ 07-routing-gossip.md | 59 +++++++++++++++++++++ 3 files changed, 183 insertions(+) diff --git a/01-messaging.md b/01-messaging.md index 066d7b4da..f6cd54d5c 100644 --- a/01-messaging.md +++ b/01-messaging.md @@ -283,6 +283,9 @@ The `features` field MUST be padded to bytes with 0s. 1. type: 3 (`remote_addr`) 2. data: * [`...*byte`:`data`] + 1. type: 5 (`option_will_fund`) + 2. data: + * [`...*16*byte`:`lease_rates`] The optional `networks` indicates the chains the node is interested in. The optional `remote_addr` can be used to circumvent NAT issues. diff --git a/02-peer-protocol.md b/02-peer-protocol.md index 38e2b72ac..b678851b0 100644 --- a/02-peer-protocol.md +++ b/02-peer-protocol.md @@ -44,6 +44,7 @@ operation, and closing. * [Completing the Transition to the Updated State: `revoke_and_ack`](#completing-the-transition-to-the-updated-state-revoke_and_ack) * [Updating Fees: `update_fee`](#updating-fees-update_fee) * [Message Retransmission: `channel_reestablish` message](#message-retransmission) + * [Funding Lease Fee](#funding-lease-fee) * [Authors](#authors) # Channel @@ -1171,6 +1172,11 @@ This message initiates the v2 channel establishment workflow. 2. data: * [`...*byte`:`type`] 1. type: 2 (`require_confirmed_inputs`) + 1. type: 3 (`request_funds`) + 2. data: + * [`u64`:`requested_sats`] + * [`u16`:`lease_duration`] + * [`u32`:`lease_expiry`] Rationale and Requirements are the same as for [`open_channel`](#the-open_channel-message), with the following additions. @@ -1185,11 +1191,20 @@ The sending node: - MUST set `funding_feerate_perkw` to the feerate for this transaction - If it requires the receiving node to only use confirmed inputs: - MUST set `require_confirmed_inputs` + - If it wants the receiving node to contribute to the funding transaction + using `option_will_fund`: + - MUST set `lease_duration` to one of the lease durations offered by the + receiving node in `init` or `node_announcement`. + - MUST set `requested_sats` to the amount of sats it wants to pay for at + the advertised `lease_rate`. + - MUST set `lease_expiry` to be `lease_duration` blocks in the future. The receiving node: - MAY fail the negotiation if: - the `locktime` is unacceptable - the `funding_feerate_perkw` is unacceptable + - `request_funds.lease_duration` does not match a duration it advertised. + - `request_funds.lease_expiry` is too far in the past or in the future. - MUST fail the negotiation if: - `require_confirmed_inputs` is set but it cannot provide confirmed inputs @@ -1258,6 +1273,14 @@ acceptance of the new channel. 2. data: * [`...*byte`:`type`] 1. type: 2 (`require_confirmed_inputs`) + 1. type: 3 (`will_fund`) + 2. data: + * [`signature`:`signature`] + * [`u16`:`funding_weight`] + * [`u16`:`lease_fee_basis`] + * [`u32`:`lease_fee_base_sat`] + * [`u16`:`max_channel_fee_basis`] + * [`u32`:`max_channel_fee_base_msat`] Rationale and Requirements are the same as listed above, for [`accept_channel`](#the-accept_channel-message) with the following @@ -1270,10 +1293,36 @@ The accepting node: - MAY respond with a `funding_satoshis` value of zero. - If it requires the opening node to only use confirmed inputs: - MUST set `require_confirmed_inputs` + - If the `request_funds` tlv was sent in `open_channel2`: + - If it does not want to contribute funds or to be paid for its + funding contributions: + - SHOULD omit the `will_fund` tlv. + - Otherwise, if it decides to be paid for its contributions: + - MUST include the `will_fund` tlv. + - MUST set `funding_satoshis` to a value greater than `0`. + - MAY set `funding_satoshis` less or more than `requested_sats`. + - MUST fill the `will_fund` tlv with values from the `lease_rate` + that matches the `lease_duration` from `request_funds`. + - MUST set `signature` to the ECDSA signature of the SHA256 hash + of the corresponding `lease_witness` using the `node_id` key. The receiving node: + - MAY fail the negotiation if: + - It sent `request_funds` and `will_fund` is set and: + - `funding_satoshis` is smaller than requested. + - SHOULD fail the negotiation if: + - It sent `request_funds` and `will_fund` is set and: + - `funding_weight` is too high. + - `lease_fee_basis` is too high. + - `lease_fee_base_sat` is too high. + - `max_channel_fee_basis` is too high. + - `max_channel_fee_base_msat` is too high. - MUST fail the negotiation if: - `require_confirmed_inputs` is set but it cannot provide confirmed inputs + - `will_fund` is set but `request_funds` was not sent in `open_channel2`. + - `will_fund` is set but the `signature` is invalid. + - MUST pay fees for the `option_will_fund` amount (if any) as detailed in the + [funding lease fee section](funding-lease-fee). #### Rationale @@ -1286,6 +1335,14 @@ Instead, the channel reserve is fixed at 1% of the total channel balance rounded down to the nearest whole satoshi or the `dust_limit_satoshis`, whichever is greater. +If the opener sent `request_funds` in their `open_channel2` message, the +accepter node may choose to contribute funds, but they don't have to. + +If the accepter node has run out of available funds, they should either fail +the negotiation or reply with a `funding_satoshis` set to `0` and omit the +`will_fund` TLV, allowing the opener to decide whether they want to proceed +anyway or fail the negotiation. + ### Funding Composition Funding composition for channel establishment v2 makes use of the @@ -2578,6 +2635,70 @@ interactive transaction construction, or safely abort that transaction if it was not signed by one of the peers, who has thus already removed it from its state. +## Funding Lease Fee + +When `request_funds` and `will_fund` have been set in `open_channel2` and +`accept_channel2`, the opener must pay fees to the accepter for the funding +they provide to the channel based on the agreed upon `lease_rate`. + +The lease fee is taken from the opener's funding inputs and added to the +accepter's channel balance during the funding flow. The opener must contribute +enough funds to cover `open_channel2.funding_satoshis`, the lease fee, and the +on-chain fees for the weight of the funding transaction they're responsible for. + +The lease fee has three components: + +* a fixed amount: `lease_fee_base_sat` +* a proportional amount based on the accepter's funding contribution: + * `paid_funding_contribution = min(accept_channel2.funding_satoshis, open_channel2.requested_sats)` + * `lease_fee_proportional_sat = paid_funding_contribution * lease_fee_basis / 10_000` +* a contribution to the on-chain fees paid by the accepter: + * `lease_fee_mining_sat = funding_weight * funding_feerate_perkw / 1000` + +The lease fee is then `lease_fee_total = lease_fee_base_sat + lease_fee_proportional_sat + lease_fee_mining_sat`. + +### Example + +A node contributes `500_000 sats` to a channel and requests `1_000_000 sats` +from its peer, at a feerate of `2500 sat/kw`. The total weight of their inputs +and outputs in the funding transaction is 720. More details about transaction +weight can be found in the [interactive-tx section](interactive-transaction-construction). + +The accepter contributes `1_100_000 sats` with the following `lease_rate`: + + funding_weight = 444 + lease_fee_base_sat = 233 sats + lease_fee_basis = 22 + +The lease fee is: + + lease_fee_base_sat = 233 sats + lease_fee_proportional_sat = min(1_000_000, 1_100_000) * 22 / 10_000 = 2200 sats + lease_fee_mining_sat = 444 * 2500 / 1000 = 1110 sats + lease_fee_total = 3543 sats + +The outputs to the peers in the commitment transaction will be + + to-opener: 500_000 sats + to-accepter: 1_103_543 sats + +The miner fee for the opener will be `720 * 2500 / 1000 = 1800 sats`. + +Minimum funds that the opener must contribute to the funding transaction: + + open_channel2.funding_satoshis: 500_000 sats + lease fee: 3_543 sats + miner fee: 1_800 sats + total required contribution: 505_343 sats + +Minimum funds that the accepter must contribute to the funding transaction: + + accept_channel2.funding_satoshis: 1_100_000 sats + miner fee [1]: 1_110 sats + total required contribution: 1_101_110 sats + +[1] assumes `funding_weight = 444` is their total weight for this transaction. + # Authors [ FIXME: Insert Author List ] diff --git a/07-routing-gossip.md b/07-routing-gossip.md index ea6fac689..c3675eaf2 100644 --- a/07-routing-gossip.md +++ b/07-routing-gossip.md @@ -270,6 +270,32 @@ nodes not associated with an already known channel are ignored. * [`32*byte`:`alias`] * [`u16`:`addrlen`] * [`addrlen*byte`:`addresses`] + * [`node_announcement_tlvs`:`tlvs`] + +1. `tlv_stream`: `node_announcement_tlvs` +2. types: + 1. type: 1 (`option_will_fund`) + 2. data: + * [`...*16*byte`:`lease_rates`] + +1. subtype: `lease_rate` +2. data: + * [`u16`:`lease_duration`] + * [`u16`:`funding_weight`] + * [`u16`:`lease_fee_basis`] + * [`u32`:`lease_fee_base_sat`] + * [`u16`:`max_channel_fee_basis`] + * [`u32`:`max_channel_fee_base_msat`] + +1. subtype: `lease_witness` +2. data: + * [`16*byte`:`0x6f7074696f6e5f77696c6c5f66756e64`] + * [`u16`:`funding_script_size`] + * [`funding_script_size`:`funding_script`] + * [`u16`:`lease_duration`] + * [`u32`:`lease_expiry`] + * [`u16`:`max_channel_fee_basis`] + * [`u32`:`max_channel_fee_base_msat`] `timestamp` allows for the ordering of messages, in the case of multiple announcements. `rgb_color` and `alias` allow intelligence services to assign @@ -280,6 +306,14 @@ connections: it contains a series of `address descriptor`s for connecting to the node. The first byte describes the address type and is followed by the appropriate number of bytes for that type. +`lease_rates` allows nodes to announce their willingness to provide funding to +other nodes for a fee. They also commit to a maximum routing fee they will charge +for transmitting funds over the channel for the duration of the funding lease. + +`lease_witness` contains the data that is signed when committing to a funding +lease. It starts with `option_will_fund` in ASCII to ensure that this signature +cannot be used in a different context. + The following `address descriptor` types are defined: * `1`: ipv4; data = `[4:ipv4_addr][2:port]` (length 6) @@ -323,6 +357,21 @@ The origin node: bits it sets. - SHOULD not announce a Tor v2 onion service. - MUST NOT announce more than one `type 5` DNS hostname. + - If it includes `option_will_fund`: + - MUST set `lease_duration` to the number of blocks during which the lease + will be active. + - SHOULD include one `lease_rate` for each lease duration it supports. + - MUST set `lease_fee_base_sat` to the base fee (in satoshi) it will charge. + - MUST set `lease_fee_basis` to the amount it will charge per contributed + satoshi (in basis points, ie 1/10_000). + - MUST set `funding_weight` to the transaction weight that will be charged. + It ensures that the funding node is refunded for some of the on-chain + fees it will pay to contribute the requested funds to a channel. + - MUST set `max_channel_fee_base_msat` to the maximum `fee_base_msat` it + will use in its `channel_update` while the lease is active. + - MUST set `max_channel_fee_basis` to match (when converted from basis + points to millionths) the maximum `fee_proportional_millionths` it will + use in its `channel_update` while the lease is active. The receiving node: - if `node_id` is NOT a valid compressed public key: @@ -377,6 +426,11 @@ to be ordered in ascending order, unknown ones can be safely ignored. Additional fields beyond `addresses` may also be added in the future—with optional padding within `addresses`, if they require certain alignment. +When using `option_will_fund`, a `signature` will be provided over the +`lease_witness`. This provides the buyer with a proof in case the seller +does not honor the lease terms, for example by updating the routing fees +of their `channel_update` to a greater value than the `lease_rate`. + ### Security Considerations for Node Aliases Node aliases are user-defined and provide a potential avenue for injection @@ -498,6 +552,11 @@ The origin node: - SHOULD NOT create redundant `channel_update`s - If it creates a new `channel_update` with updated channel parameters: - SHOULD keep accepting the previous channel parameters for 10 minutes + - If it is the seller of a currently active lease on this channel (`option_will_fund`): + - MUST NOT set `fee_base_msat` greater than `max_channel_fee_base_msat` + (as committed to in `accept_channel2.will_fund.signature`). + - MUST NOT set `fee_proportional_millionths` greater than `max_channel_fee_basis` * 100 + (as committed to in `accept_channel2.will_fund.signature`). The receiving node: - if the `short_channel_id` does NOT match a previous `channel_announcement`, From 07e511f703dbaab99cc96e8825c6c3447840905e Mon Sep 17 00:00:00 2001 From: Bastien Teinturier <31281497+t-bast@users.noreply.github.com> Date: Thu, 11 Apr 2024 18:03:41 +0200 Subject: [PATCH 2/2] Add amount range to `lease_rate` (#1) Add amount range to `lease_rate`. --- 01-messaging.md | 2 +- 07-routing-gossip.md | 10 +++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/01-messaging.md b/01-messaging.md index f6cd54d5c..97d33ee0c 100644 --- a/01-messaging.md +++ b/01-messaging.md @@ -285,7 +285,7 @@ The `features` field MUST be padded to bytes with 0s. * [`...*byte`:`data`] 1. type: 5 (`option_will_fund`) 2. data: - * [`...*16*byte`:`lease_rates`] + * [`...*24*byte`:`lease_rates`] The optional `networks` indicates the chains the node is interested in. The optional `remote_addr` can be used to circumvent NAT issues. diff --git a/07-routing-gossip.md b/07-routing-gossip.md index c3675eaf2..16c1f7144 100644 --- a/07-routing-gossip.md +++ b/07-routing-gossip.md @@ -276,11 +276,13 @@ nodes not associated with an already known channel are ignored. 2. types: 1. type: 1 (`option_will_fund`) 2. data: - * [`...*16*byte`:`lease_rates`] + * [`...*24*byte`:`lease_rates`] 1. subtype: `lease_rate` 2. data: * [`u16`:`lease_duration`] + * [`u32`:`min_lease_amount_sat`] + * [`u32`:`max_lease_amount_sat`] * [`u16`:`funding_weight`] * [`u16`:`lease_fee_basis`] * [`u32`:`lease_fee_base_sat`] @@ -360,7 +362,11 @@ The origin node: - If it includes `option_will_fund`: - MUST set `lease_duration` to the number of blocks during which the lease will be active. + - MUST set `min_lease_amount_sat` and `max_lease_amount_sat` to the minimum + and maximum amount it will contribute at this rate. - SHOULD include one `lease_rate` for each lease duration it supports. + - SHOULD include one `lease_rate` for each amount range it supports. + - MUST NOT include more than ten `lease_rate`s. - MUST set `lease_fee_base_sat` to the base fee (in satoshi) it will charge. - MUST set `lease_fee_basis` to the amount it will charge per contributed satoshi (in basis points, ie 1/10_000). @@ -412,6 +418,8 @@ any future fields appended to the end): - if more than one `type 5` address is announced: - SHOULD ignore the additional data. - MUST not forward the `node_announcement`. + - if more than ten `lease_rate`s are included: + - MUST not forward the `node_announcement`. ### Rationale