Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Inbound routing fees #18

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions blip-0002.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,14 @@ The following table contains extension tlv fields for the `ping` message:
|-------|-----------------------------|--------------------------------|
| 65536 | `tlv_field_name` | Link to the corresponding bLIP |

#### `channel_update`

The following table contains extension tlv fields for the `channel_update` message:

| Type | Name | Link |
|------------|-----------------------------|--------------------------------|
| 55555 | `inbound_discount` | [bLIP 18](./blip-0018.md) |

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The current implementation in lnd also applies to optional positive inbound fees. Should the wording be updated?


## Copyright

This bLIP is licensed under the CC0 license.
90 changes: 90 additions & 0 deletions blip-0018.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
```
bLIP: 14
Title: Inbound routing fees
Status: Draft
Author: Joost Jager <joost.jager@gmail.com>
Created: 2022-08-29
License: CC0
```

## Abstract

The Lightning BOLTs define a routing fee that is based on the policy of the
_outgoing_ channel. This makes it impossible for routing node operators to
differentiate in fees between incoming channels.

Incoming traffic from some peers may be more desired than from others, for
example because it balances out traffic in the opposite direction.

This bLIP defines an optional `channel_update` message field `inbound_fee` to
express an inbound fee.

## Copyright

This bLIP is licensed under the CC0 license.

## Specification

Routing node:

* MAY include a `channel_update` optional TLV record `inbound_fee` keyed by type
`55555` with the following value:

* [i32:base_msat]
* [i32:proportional_millionths]

* MAY choose to advertize a negative inbound fee to keep servicing senders who
don't understand inbound fees.

The given discount can be balanced with an increase of the outgoing fees to
effectively have a positive inbound fee.

* The inbound fee is calculated over the amount to forward plus the outbound
fee. This amount is called the net amount received (`net_received_amt`).

`net_received_amt = amt_to_fwd + outbound_fee(amt_to_fwd)`

`inbound_fee(net_received_amt) = inbound_fee.base_msat + inbound_fee.proportional_millionths * net_received_amt / 1e6`

Example:

`inbound fee = 1 + 10%, outbound fee = 7 + 3%, outgoing htlc amount = 100`

`--- 122 ---> (in fee: 12) (net_received_amt: 110) (out fee: 10) --- 100 --->`

* MUST accept a routing fee equal to or greater than the sum of inbound and
outbound fee. No attempt should be made to calculate the total fee in one go,
because rounding may cause the end result to be higher.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the current lnd implementation, the sum of outbound and inbound must not be negative. Should the blip be updated accordingly?

I think that negative fees should also be possible in the long term, but then we would probably need an additional boolean to signal a possible negative fee to the network. Otherwise sender nodes will not be able to see which routing might reject a payment with negative fees.


* The inbound fee does not apply to final hops.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this shows what's wrong with this proposal : If I open a channel to X, I should be able to pay X without paying fees, it would be unfair for X to ask me to pay an extra fee for receiving my payment. Well, it's exactly the same in case X is not the final recipient but only a relay. If X really thinks that traffic from channel a is better than traffic from channel b, then why should this preference no longer hold when X is the recipient?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because the recipient isn't providing a forwarding service. It plays a different role.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does it matter? Traffic is fungible.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd say it is different traffic, because there is no outgoing component. There is something to say for always charging, but I think it is not the best choice. I documented some thoughts about it here


* For `fee_insufficient` failures, the routing node SHOULD, in addition to the
outgoing channel policy, also return the incoming channel policy as a TLV
extension. But only if the sender signaled support for extended failure
messages.

TBD: allocate type for this and describe.

* MUST NOT set inbound fees on private channels. Inbound fees can't be
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this true? Seem like it could be encoded in the invoice with a new feature bit, with similar backwards compatibility as forwarding payments (start with a discount, and senders that don't understand it will overpay).

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should have been "can't currently be communicated". We could add a new tag for the inbound fees, but would need to be careful not to duplicate too much information and increase the size of a qr code unnecessarily.

Perhaps it's possible to do a TLV extension of the r field, but not sure if decoders might trip over it.

I've also looked into folding the inbound and outbound fee into a single fee, but that doesn't seem to be possible. If for example the final destination requires an inbound fee, there is no way to express that through the outbound fee of the second-last node. It will still always only send the payment amount to the final hop and not more.

communicated through bolt11 invoices yet and senders will not be aware of
them.

Sender node:

* MUST pay each routing node at least the sum of its advertised inbound and
outbound fee for the incoming and outgoing channel that is used (formula above).

* SHOULD signal to each node along the route that they can interpret [extended failure messages](https://github.com/lightning/bolts/pull/1021).

* SHOULD apply all channels updates that accompany a `fee_insufficent` failure.
The update for the incoming channel may be present in the TLV extension.

## Universality

This feature is defined as a BLIP because it's experimental.

## Backwards Compatibility

By defining the inbound fee as a negative number, senders who don't understand
the new field will still be able to make payments. Routing nodes will accept
overpayment on fees.