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鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

ILQPv2: Replace ILQP with End-to-End Quoting #309

Closed
wants to merge 4 commits into from
Closed
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
126 changes: 126 additions & 0 deletions 0000-interledger-quoting-protocol-v2.md
@@ -0,0 +1,126 @@
---
title: Interledger Quoting Protocol v2 (ILQPv2)
draft: 1
---

# Interledger Quoting Protocol v2 (ILQPv2)

Replaces IL-RFC-8: Interledger Quoting Protocol, which should be considered deprecated if this proposal is accepted.

## Preface

ILQPv2 is an end-to-end protocol implemented by Interledger senders and receivers (**not** connectors, in contrast to ILQPv1). It allows a sender to determine the exchange rate between their ledger and the receiver's ledger by sending a specially crafted test payment to the receiver.

## Introduction

### Motivation

In general, the motivation for a quoting protocol is to allow senders to determine the exchange rate between their assets and the receiver's assets before making a payment.

The motivations for replacing ILQPv1 are as follows:

1. **Simplification of the Interledger Layer and Connector** - Previously, all Interledger connectors needed to implement both the Interledger Protocol and the Interledger Quoting Protocol in order to be fully compatible with the protocol. By making quoting an end-to-end concern, this simplifies connector implementations and what we think of as the Interledger Layer of the stack.
2. **Futility of Relying on Connector Quotes** - ILQP quotes were never intended to be binding, but rather to give senders a sense of the expected cost of a payment. Aside from the problems posed by malicious connectors, there were other reasons that quotes could not be relied upon. For example, exchange rates and connectors' liquidity positions are likely to change over time, rendering even honest quotes untrustworthy.

Choose a reason for hiding this comment

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

I agree, if the quote is not binding, it's merely an information poll.

I do wonder if it's possible to catch fluctuations between package prices?
For example, a chunked payment: <chunk1>, <chunk2>, ..., <chunkN>
Ideally the cost is somewhat bounded... but if no limits are set a malicious connector could suddenly bump the price during a stream.

These or other protections could go on the app level? Which implies that the receiver would be honest to te sender (and not accept the bumped price over the mutually agreed limit). Otherwise, one could put limits inside of the package?

Copy link
Member Author

Choose a reason for hiding this comment

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

This is definitely a tough part about doing streaming payments. We'd have to build this into the streaming payments transport protocol, but there are limits to what it can do. It would probably be a good idea to have the receiver reject the incoming payment if the amount that arrives is less than expected, because that would disincentivize connectors from deliberately changing their rates in the middle of the stream.

However, you'd also need to have logic related to the specific application about whether you would switch provider or just stop if it gets too expensive. For example, if you're streaming a movie, maybe you could switch to a different host if one gets too expensive (whether it's the receiver's fault or some connector doesn't matter to you). If you're doing a streaming (chunked) payment, there might not be that much recourse. If it gets sufficiently expensive you might just want to stop and hope the receiver sends you your money back 馃槙

3. **Recognition of Quoting as an Application-Specific Concern** - Given the unreliability of quotes, different applications will need to handle fluctuating rates and liquidity differently. For example, the mechanism used to judge the cost of a stream of payments versus a single payment must actively take into account the changing rates. This suggests that different applications may need different types of quoting functionality or may not use quoting at all.
4. **Enabling Evolution of the Quoting Protocol** - Protocols on the Interledger Layer must be implemented by all participants and will thus be more difficult to update. Taking quoting out of the realm of connectors will enable different quoting protocols to evolve over time.

Note that ILQPv2 assumes all connector exchange rates are linear, rather than using Liquidity Curves like ILQPv1. See [Appendix A: Linear Exchange Rates](#appendix-a-linear-exchange-rates) for details.
Copy link
Member

Choose a reason for hiding this comment

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

Probably worth taking a moment to stop and clarify that we're not just assuming variable fees are linear, but also the absence of fixed fees. (I think that's an ok assumption, we can have fixed fees be deducted without being represented in the amounts OR even charge a monthly fee instead of fixed fees per payment.)


### Scope

ILQPv2 is intended for senders to determine the rate between the source and destination amounts for a payment.

It is primarily designed for individual payments. While it may be used for streams of payments, other protocols that actively take into account exchange rates changing over time may be better suited for such use cases.

### Operation

Senders may use a dedicated quoting module or ILQPv2 may be included in a Transport Layer protocol. A sender's ILQPv2 module is responsible for initiating specially crafted test payments to receivers. The receiver's ILQPv2 module is responsible for handling the incoming test payment and rejecting it with a specific error message.

## Overview

### Relation to Other Protocols

ILQPv2 uses payments sent with the Interledger Protocol. In order for this protocol to work, Interledger connectors MUST ignore the amount in the ILP Packet, and neither attempt to deliver the exact amount in the packet or reject payments where the transfer amount is lower than the amount in the packet. Connectors MUST relay error messages back to the sender.

ILQPv2 is intended to be incorporated into Transport Layer protocols. Transport Protocols such as the Pre-Shared Key protocol should ensure that the normal logic for fulfilling or rejecting transfers does not interfere with ILQPv2.

## Model of Operation

### Fixed Source Amount

This details the steps for a sender to get a quote for a fixed source amount ("if I send this much, how much will the receiver get?"):

1. The sender constructs an ILP packet with the receiver's ILP Address, an amount of `0`, and data beginning with `ILQP/2.0\n`.
2. The sender uses their ILP module to send the packet on a transfer with the amount set to the fixed source amount of their quote request.
3. Connectors forward the payment to the receiver. (Note that connectors that recognize the special condition MAY "forward" the payment without actually reserving funds, since they know the payment will not be executed.)
4. When the receiver is notified of the incoming transfer, they reject the transfer with an error message including the amount that arrived in the transfer and the amount of time they have before the transfer expires.
5. Connectors relay the error message back to the sender.
6. When the sender is notified that their test transfer was rejected, they inspect the error message to determine how much arrived at the receiver's ledger and how much time the receiver had to respond before the transfer would time out. The sender can then adjust the values before sending the actual payment.

### Fixed Destination Amount

The steps are the same as for Fixed Source Amount quotes, except that the transfer amount is set to an arbitrary probe value. When the sender gets the error response from the receiver, they compute the exchange rate based on the amount they sent and the amount that arrived. The sender then divides the fixed destination amount from the quote request by that exchange rate.
Copy link
Contributor

Choose a reason for hiding this comment

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

This the e2e implementation of quote-by-destination makes the assumption that all curves are simple rates (i.e. they only have 2 points, [0,0] and [x,y]).

Copy link
Member Author

Choose a reason for hiding this comment

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

Yup. That's definitely one of the debatable points about this proposal. I would argue that's a good simplification to make for a number of reasons (note I'm partially trying to channel @justmoon's arguments here):

  1. If paths have a relatively small Maximum Transfer Size (MTS), you wouldn't need the rates to change much - Whether we like it or not, there will be a maximum size for an individual payment that the network will support. If I had to guess, I'd imagine that it would be on the order of $10-100, not $10k. Between the Interledger Universal mode risk and liquidity issues, I think connectors will be incentivized to keep the MTS relatively small. If that's the case, there's less of a reason to vary the rate based on the size. Do you really care about charging a different exchange rate for a payment of $0.01 as compared with $10? You might care more if the MTS was $100 million, but I think that's unrealistic.
  2. Curves don't help for streaming payments - If the MTS is smaller than the payments some people want to make, we're going to need to chunk those payments up. If you do streaming payments, then you really want to know liquidity information over time, not just a static snapshot. Attempting to express that would be so complicated it's not worth it. But if you don't do that, the snapshot curve doesn't help because it could change anyway. You just need to start sending, constantly monitor the rate, and adjust who you're sending through if the rate changes a lot.
  3. Assuming "curves" are just lines simplifies routing a lot - No matter what, routing money is probably going to be more complex than routing IP packets, which is already very complex. If you have to route packets in different directions based on the size, that means you need to keep multiple routing tables for different payment sizes. That would make it much more complex.
  4. We didn't use curves in practice - When we were running the community network of ilp-kits, everyone was just using a % spread on top of a linear exchange rate pulled from fixer.io. It doesn't seem like you really need them to be much more complicated than that -- and @justmoon has made the good point that connectors may not charge customers on a per-payment basis anyway.
  5. Simplification - if there's any way we can make do without liquidity curves, then we should do without them. They'll go on the long list of things we've spent loads of time on and then axed because they weren't strictly needed (nested transfers / source routing, multi-credit multi-debit transfers, fees in transfers, split payment paths, atomic mode, crypto condition-based payments, and now maybe ILQP).

...these points should probably go in the RFC. Thanks @sentientwaffle for asking the question!


Note that ILQPv2 assumes all connector exchange rates are linear. See [Appendix A: Linear Exchange Rates](#appendix-a-linear-exchange-rates) for details.

## Specification

### Test Payment Fields

#### ILP Packet Amount

The `amount` SHOULD be set to `0`.

#### ILP Packet Data

The `data` field MUST start with the UTF-8 string `ILQP/2.0\n`. The `data` field MAY contain other data, although ILQPv2.0 does not specify the use or encoding for this additional data.

#### Condition

ILQPv2 test payments SHOULD use the condition:

`0000000000000000000000000000000000000000000000000000000000000000`, encoded as hexadecimal.

Or `AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA`, encoded in Base64-URL.

#### Expiry

Test payments are RECOMMENDED to use a transfer expiry of 60 seconds.

If the first attempt at a quote request is rejected with an `R02: Insufficient Timeout` error, the sender MAY increase the expiry and retry.

### Error Message Format

The receiver MUST reject the test payment with an ILP Error of the form:

- Status Code: `S00`
- Status Name: `Ok`
- Data:

```asn.1
IlqpResponse ::= SEQUENCE {
destinationAmount UInt64 -- Amount that arrived at the destination
}
```

## Alternatives Considered

### Encrypted Quotes

Senders MAY wish to hide the fact that certain transfers are intended as quote requests, for example if connectors attempt to block payments that are likely to fail. Instead of using a well-known condition and sending the string `ILQP/2.0\n` in the clear, senders could, for example, send payments that look from the outside like normal Pre-Shared Key (PSK) payments. The condition could be a random string, for which the fulfillment is not known and the fact that the payment is for quoting could be communicated inside the encrypted PSK data.

This option was not chosen because it is slightly more complicated, more tied to PSK, and may not effectively hide which payments are being used for quotes. For example, if implementations always send a quote as the first payment, connectors could identify these just by determining whether a given payment is the first in a series.

Furthermore, using a well-known condition makes it so that connectors MAY implement special logic to avoid placing funds on hold for payments that are guaranteed to be rolled back. This would reduce the burden of failed payments on connectors, which would reduce their incentive to block such payments in the first place.

## Appendix A: Linear Exchange Rates

In contrast to ILQPv1, ILQPv2 assumes that all connectors use linear exchange rates. This means that connectors SHOULD NOT charge different rates for payments of different sizes.

The motivations for this change are as follows:

1. **If paths have a relatively small Maximum Transfer Size (MTS), you wouldn't need the rates to change much** - Whether we like it or not, there will be a maximum size for an individual payment that the network will support. Between the Interledger Universal mode risk and liquidity issues, connectors will likely be incentivized to keep the MTS relatively small. If that's the case, there is less of a reason to vary the rate based on the size. Charging a different rate for a payment of $0.01 versus $10 makes less sense than charging a different rate for a payment of $100 million.
Copy link
Member

Choose a reason for hiding this comment

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

you wouldn't need the rates to change much

Colloquial tone. Who is "you"?

2. **Curves don't help for streaming payments** - If the MTS is smaller than the payments some people want to make, streaming payments will be required to chunk those payments up. In the case of streaming payments, the sender needs to understand the liquidity information over time, rather than just a static snapshot. Attempting to express liquidity over time would be too complicated to be worth it. But without that dynamic view, the snapshot curve does not help because it could change anyway. Therefore, in the case of streaming payments, senders will need to start sending, constantly monitor the rate, and adjust who they are sending through if the rate changes a lot.
3. **Assuming liquidity curves are just lines significantly simplifies routing** - Routing money is more complex than routing IP packets, which is already very complex. If connectors needed to route packets in different directions based on the payment size, connectors would need to maintain multiple routing tables for different sizes. This would make routing even more complex.
4. **We didn't use curves in practice** - When we were running the community network of ilp-kits, everyone was just using a % spread on top of a linear exchange rate pulled from fixer.io. It seems unlikely that connectors will need more complicated fee structures than that, and connectors may end up charging customers on monthly or other bases rather than per-payment.
5. **Simplification** - if there's any way we can make do without liquidity curves, then we should do without them. They will go on the long list of things we have spent loads of time on and then axed because they weren't strictly needed (nested transfers / source routing, multi-credit multi-debit transfers, fees in transfers, split payment paths, atomic mode, crypto condition-based payments, and now maybe ILQP).
Copy link
Member

Choose a reason for hiding this comment

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

Tone. "make do", "loads of time"