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

General Fee Payment Spec #581

Merged
merged 26 commits into from
Jul 9, 2021
Merged
Changes from 5 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
4b57075
Start defining general relayer fee payment protocol
ethanfrey Jun 1, 2021
b1d5114
Provide high-level implementation details
ethanfrey Jun 1, 2021
98d35ce
add to example
AdityaSripal Jun 2, 2021
9eaaadb
writeup interfaces
AdityaSripal Jun 2, 2021
8f6d4c0
writeup connection/channel changes
AdityaSripal Jun 2, 2021
5372351
Apply suggestions from code review
AdityaSripal Jun 3, 2021
6f0c93b
address reviews
AdityaSripal Jun 3, 2021
0c920c1
Merge branch 'start-fee-payment-spec' of github.com:cosmos/ibc into s…
AdityaSripal Jun 3, 2021
c85b2bd
writeup fee module requirements
AdityaSripal Jun 3, 2021
a8dfa2c
simplify connection version
AdityaSripal Jun 3, 2021
eda8453
partially address chris reviews
AdityaSripal Jun 7, 2021
c276b67
Apply suggestions from code review
AdityaSripal Jun 7, 2021
811d986
address ethan, chris reviews
AdityaSripal Jun 7, 2021
e4e6116
Merge branch 'start-fee-payment-spec' of github.com:cosmos/ibc into s…
AdityaSripal Jun 7, 2021
7944b5e
add fee middleware
AdityaSripal Jun 8, 2021
274ddcc
Merge branch 'master' of github.com:cosmos/ibc into start-fee-payment…
AdityaSripal Jun 8, 2021
dcdd939
Update spec/app/ics-029-fee-payment/README.md
AdityaSripal Jun 15, 2021
7d3693d
add port discussion, remove backwards compatibility from app and move…
AdityaSripal Jun 18, 2021
aa3e2c7
update metadata
AdityaSripal Jun 18, 2021
b57ff40
Merge branch 'start-fee-payment-spec' of github.com:cosmos/ibc into s…
AdityaSripal Jun 18, 2021
4ead1f3
add middleware spec
AdityaSripal Jun 21, 2021
a2b17cb
cleanup and complete specs
AdityaSripal Jun 23, 2021
40e1930
add fee definitions
AdityaSripal Jun 23, 2021
524697f
clarify fee payment messages
AdityaSripal Jun 24, 2021
7a2f416
clarify forward relaying and ics4 wrapper logic
AdityaSripal Jul 7, 2021
c838afb
update correctness section
AdityaSripal Jul 7, 2021
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
203 changes: 203 additions & 0 deletions spec/app/ics-029-fee-payment/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
---
ics: 29
title: General Fee Payment
stage: draft
category: IBC/APP
requires: 20, 25, 26
kind: instantiation
author: Ethan Frey <[email protected]>
created: 2021-06-01
modified: 2021-06-01
---

## Synopsis

This standard document specifies packet data structure, state machine handling logic, and encoding details for handling fee
payments on top of any ICS application protocol. It requires some standard packet changes, but can be adopted by any
application, without forcing other applications to use this implementation.

### Motivation

There has been much discussion on a general incentivization mechanism for relayers. A simple proposal was created to
[extend ICS20 to incentivize relaying](https://github.com/cosmos/ibc/pull/577) on the destination chain. However,
it was very specific to ICS20 and would not work for other protocols. This was then extended to a more
[general fee payment design](https://github.com/cosmos/ibc/issues/578) that could be adopted by any ICS application
protocol.

In general, the Interchain dream will never scale unless there is a clear way to incentivize relayers. We seek to
define a clear interface that can be easily adopted by any application, but not preclude chains that don't use tokens.

### Desired Properties

- Incentivize timely delivery of the packet (`OnReceivePacket` called)
- Incentivize relaying acks for these packets (`OnAcknowledgement` called)
- Incentivize relaying timeouts for these packets when the receive fee was too low (`OnTimeout` called)
AdityaSripal marked this conversation as resolved.
Show resolved Hide resolved
- Produces no extra IBC packets
- One direction works, even when one chain does not support concept of fungible tokens
AdityaSripal marked this conversation as resolved.
Show resolved Hide resolved
- Opt-in for each chain implementing this. eg. ICS27 with fee support on chain A could connect to ICS27 without fee support on chain B.
- Standardized interface for each chain implementing this extension
- Allow each chain/application to customize fee-handling logic
- Permissionless relaying
AdityaSripal marked this conversation as resolved.
Show resolved Hide resolved

cwgoes marked this conversation as resolved.
Show resolved Hide resolved
## Technical Specification

### General Design

In order to avoid extra packets on the order of the number of fee packets, as well as provide an opt-in approach, we
store all fee payment info only on the source chain. The source chain is the one location where the sender can provide tokens
to incentivize the packet. The fee distribution may be implementation specific and thus does not need to be in the ibc spec
AdityaSripal marked this conversation as resolved.
Show resolved Hide resolved
(just high-level requirements are needed in this doc).

We require that the [relayer address is exposed to application modules](https://github.com/cosmos/ibc/pull/579) for
all packet-related messages, so the modules are able to incentivize the packet relayer. `OnAcknowledgement`, `OnTimeout`,
and `OnTimeoutClose` messages will therefore have the relayer address and be capable of sending escrowed tokens to such address.
ethanfrey marked this conversation as resolved.
Show resolved Hide resolved
However, we need a way to reliably get the address of the relayer that submitted `OnReceivePacket` on the destination chain to
the source chain. In fact, we need a *source address* for this relayer to pay out to, not the *destination address* that signed
the packet.

Given this, the flow would be:

1. User/module submits a send packet on the `source` chain, along with some tokens and fee information on how to distribute them
AdityaSripal marked this conversation as resolved.
Show resolved Hide resolved
2. Relayer submits `OnReceivePacket` on the `destination` chain. Along with this message, the *forward relayer* will submit a `payToOnSource` address where payment should be sent.
AdityaSripal marked this conversation as resolved.
Show resolved Hide resolved
AdityaSripal marked this conversation as resolved.
Show resolved Hide resolved
3. Destination application includes this `payToOnSource` in the acknowledgement (there are multiple approaches to discuss below)
4. Relayer submits `OnAcknowledgement` which provides the *return relayer* address on the source chain, along with the `payToOnSource` address
AdityaSripal marked this conversation as resolved.
Show resolved Hide resolved
5. Source application can distribute the tokens escrowed in (1) to both the *forward* and the *return* relayers.

Alternate flow:

1. User/module submits a send packet on the `source` chain, along with some tokens and fee information on how to distribute them
2. Relayer submits `OnTimeout` which provides their address on the source chain
AdityaSripal marked this conversation as resolved.
Show resolved Hide resolved
3. Source application can distribute the tokens escrowed in (1) to this relayer, and potentially return extra tokens to the original packet sender.
AdityaSripal marked this conversation as resolved.
Show resolved Hide resolved

### Fee details

For an example implementation in the Cosmos SDK, we consider 3 potential fee payments, which may be defined. Each one may be
paid out in a different token. Imagine a connection between IrisNet and the Cosmos Hub. They may define:

- ReceiveFee: 0.003 channel-7/ATOM vouchers (ATOMs already on IrisNet via ICS20)
- AckFee: 0.001 IRIS
ethanfrey marked this conversation as resolved.
Show resolved Hide resolved
- TimeoutFee: 0.002 IRIS

Ideally the fees can easily be redeemed in native tokens on both sides, but relayers may select others. In this example, the relayer collects a fair bit of IRIS, covering it's costs there and more. It also collects channel-7/ATOM vouchers from many packets. After relaying a few thousand packets, the account on the Cosmos Hub is running low, so the relayer will send those channel-7/ATOM vouchers back over channel-7 to it's account on the Hub to replenish the supply there.
AdityaSripal marked this conversation as resolved.
Show resolved Hide resolved

The sender chain will escrow 0.003 channel-7/ATOM and 0.002 IRIS. In the case that a forward relayer submits the `MsgRecvPacket` and a reverse relayer submits the `MsgAckPacket`, the forward relayer is reqarded 0.003 channel-7/ATOM and the reverse relayer is rewarded 0.001 IRIS. In the case where the packet times out, the timeout relayer receives 0.002 IRIS and 0.003 channel-7/ATOM is refunded to the original fee payer.
AdityaSripal marked this conversation as resolved.
Show resolved Hide resolved

The logic involved in collecting fees from users and then paying it out to the relevant relayers is encapsulated by a separate fee module and may vary between implementations. However, all fee modules must implement a uniform interface such that the ICS-4 handlers can correctly pay out fees to the right relayers, and so that relayers themselves can easily determine the fees they can expect for relaying a packet.
ethanfrey marked this conversation as resolved.
Show resolved Hide resolved

### Fee Module Contract

```typescript
function PayFee(packet: Packet, forward_relayer: string, reverse_relayer: string) {
ethanfrey marked this conversation as resolved.
Show resolved Hide resolved
// pay the forward fee to the forward relayer address
// pay the reverse fee to the reverse relayer address
// refund extra tokens to original fee payer(s)
}

ethanfrey marked this conversation as resolved.
Show resolved Hide resolved
function PayTimeoutFee(packet: Packet, timeout_relayer: string) {
// pay the timeout fee to the timeout relayer address
// refund extra tokens to original fee payer(s)
}
```


The fee module should also expose the following queries so that relayers may query their expected fee:

```typescript
// Gets the fee expected for submitting ReceivePacket msg for this packet
function GetReceiveFee(packet) Fee
AdityaSripal marked this conversation as resolved.
Show resolved Hide resolved

// Gets the fee expected for submitting AcknowledgePacket msg for this packet
function GetAckFee(packet) Fee

// Gets the fee expected for submitting TimeoutPacket msg for this packet
function GetTimeoutFee(packet) Fee
```

Since different chains may have different representations for fungible tokens and this information is not being sent to other chains; this ICS does not specify a particular representation for the `Fee`. Each chain may choose its own representation, it is incumbent on relayers to interpret the Fee correctly.
AdityaSripal marked this conversation as resolved.
Show resolved Hide resolved

### Connection Negotiation

The chains must agree to enable the incentivization feature during the connection handshake. This can be done by adding an incentivization feature to the connection version.

```{"1", ["ORDER_ORDERED", "ORDER_UNORDERED", "INCENTIVE_V1"]}```
AdityaSripal marked this conversation as resolved.
Show resolved Hide resolved

If the negotiated connection includes the incentivization feature, then the ICS-4 `WriteAcknowledgement` function must write the forward relayer address into a structured acknowledgement and the ICS-4 handlers for `AcknowledgePacket` and `TimeoutPacket` must pay fees through the ibc fee module callbacks. If the negotiated connection does not include the incentivization feature, then the ICS-4 handlers must not modify the acknowledgement provided by the application and should not call any fee callbacks even if relayer incentivization is enabled on the chain.

AdityaSripal marked this conversation as resolved.
Show resolved Hide resolved
### Channel Changes

The ibc-fee callbacks will then be utilized in the ICS-4 handlers like so:

```typescript
function acknowledgePacket(
packet: OpaquePacket,
acknowledgement: bytes,
proof: CommitmentProof,
proofHeight: Height,
relayer: string): Packet {
// get the forward relayer from the acknowledgement
// and pay fees to forward and reverse relayers.
// reverse_relayer is submitter of acknowledgement message
// provided in function arguments
// NOTE: Fee may be zero
forward_relayer = getForwardRelayer(acknowledgement)
AdityaSripal marked this conversation as resolved.
Show resolved Hide resolved
PayFee(packet, forward_relayer, relayer)
}

function timeoutPacket(
packet: OpaquePacket,
proof: CommitmentProof,
proofHeight: Height,
nextSequenceRecv: Maybe<uint64>,
relayer: string): Packet {
// get the timeout relayer from function arguments
// and pay timeout fee.
// NOTE: Fee may be zero
PayTimeoutFee(packet, relayer)
}
```

#### Reasoning

This proposal satisfies the desired properties. All parts of the packet flow (receive/acknowledge/timeout) can be properly incentivized and rewarded. The protocol does not specify the relayer beforehand, thus the incentivization is permissionless. The escrowing and distribution of funds is completely handled on source chain, thus there is no need for additional IBC packets or the use of ICS-20 in the fee protocol. The fee protocol only assumes existence of fungible tokens on the source chain. Using the connection version, the protocol enables opt-in incentivization and backwards compatibility. The fee module can implement arbitrary custom logic so long as it respects the callback interfaces that IBC expects.
AdityaSripal marked this conversation as resolved.
Show resolved Hide resolved

##### Correctness

The fee module is responsible for correctly escrowing and distributing funds to the provided relayers. It is IBC's responsibility to provide the fee module with the correct relayers. The ack and timeout relayers are trivially retrievable since they are the senders of the acknowledgment and timeout message.

The receive relayer submits the message to the counterparty chain. Thus the counterparty chain must communicate the knowledge of who relayed the receive packet to the source chain using the acknowledgement. The address that is sent back **must** be the address of the forward relayer on the source chain.
AdityaSripal marked this conversation as resolved.
Show resolved Hide resolved

With the forward relayer embedded in the acknowledgement, and the reverse and timeout relayers available directly in the message; IBC is able to provide the correct relayer addresses to the fee module for each step of the packet flow.

#### Optional addenda

## Backwards Compatibility
AdityaSripal marked this conversation as resolved.
Show resolved Hide resolved

This can be added to any existing protocol without breaking it on the other side.

## Forwards Compatibility

## Example Implementation

Coming soon.

## Other Implementations

Coming soon.

## History

Jul 15, 2019 - Draft written

Jul 29, 2019 - Major revisions; cleanup

Aug 25, 2019 - Major revisions, more cleanup

Feb 3, 2020 - Revisions to handle acknowledgements of success & failure

Feb 24, 2020 - Revisions to infer source field, inclusion of version string

July 27, 2020 - Re-addition of source field

## Copyright

All content herein is licensed under [Apache 2.0](https://www.apache.org/licenses/LICENSE-2.0).