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

feat: adding RegisterPayee rpc to ics29 fee middleware #1491

Merged
merged 8 commits into from
Jun 8, 2022
47 changes: 39 additions & 8 deletions docs/ibc/proto-docs.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@
- [MsgPayPacketFeeResponse](#ibc.applications.fee.v1.MsgPayPacketFeeResponse)
- [MsgRegisterCounterpartyAddress](#ibc.applications.fee.v1.MsgRegisterCounterpartyAddress)
- [MsgRegisterCounterpartyAddressResponse](#ibc.applications.fee.v1.MsgRegisterCounterpartyAddressResponse)
- [MsgRegisterPayee](#ibc.applications.fee.v1.MsgRegisterPayee)
- [MsgRegisterPayeeResponse](#ibc.applications.fee.v1.MsgRegisterPayeeResponse)

- [Msg](#ibc.applications.fee.v1.Msg)

Expand Down Expand Up @@ -1209,14 +1211,14 @@ Query defines the ICS29 gRPC querier service.
| Method Name | Request Type | Response Type | Description | HTTP Verb | Endpoint |
| ----------- | ------------ | ------------- | ------------| ------- | -------- |
| `IncentivizedPackets` | [QueryIncentivizedPacketsRequest](#ibc.applications.fee.v1.QueryIncentivizedPacketsRequest) | [QueryIncentivizedPacketsResponse](#ibc.applications.fee.v1.QueryIncentivizedPacketsResponse) | IncentivizedPackets returns all incentivized packets and their associated fees | GET|/ibc/apps/fee/v1/incentivized_packets|
| `IncentivizedPacket` | [QueryIncentivizedPacketRequest](#ibc.applications.fee.v1.QueryIncentivizedPacketRequest) | [QueryIncentivizedPacketResponse](#ibc.applications.fee.v1.QueryIncentivizedPacketResponse) | IncentivizedPacket returns all packet fees for a packet given its identifier | GET|/ibc/apps/fee/v1/incentivized_packet/port/{packet_id.port_id}/channel/{packet_id.channel_id}/sequence/{packet_id.sequence}|
| `IncentivizedPacketsForChannel` | [QueryIncentivizedPacketsForChannelRequest](#ibc.applications.fee.v1.QueryIncentivizedPacketsForChannelRequest) | [QueryIncentivizedPacketsForChannelResponse](#ibc.applications.fee.v1.QueryIncentivizedPacketsForChannelResponse) | Gets all incentivized packets for a specific channel | GET|/ibc/apps/fee/v1/incentivized_packets/port/{port_id}/channel/{channel_id}|
| `TotalRecvFees` | [QueryTotalRecvFeesRequest](#ibc.applications.fee.v1.QueryTotalRecvFeesRequest) | [QueryTotalRecvFeesResponse](#ibc.applications.fee.v1.QueryTotalRecvFeesResponse) | TotalRecvFees returns the total receive fees for a packet given its identifier | GET|/ibc/apps/fee/v1/total_recv_fees/port/{packet_id.port_id}/channel/{packet_id.channel_id}/sequence/{packet_id.sequence}|
| `TotalAckFees` | [QueryTotalAckFeesRequest](#ibc.applications.fee.v1.QueryTotalAckFeesRequest) | [QueryTotalAckFeesResponse](#ibc.applications.fee.v1.QueryTotalAckFeesResponse) | TotalAckFees returns the total acknowledgement fees for a packet given its identifier | GET|/ibc/apps/fee/v1/total_ack_fees/port/{packet_id.port_id}/channel/{packet_id.channel_id}/sequence/{packet_id.sequence}|
| `TotalTimeoutFees` | [QueryTotalTimeoutFeesRequest](#ibc.applications.fee.v1.QueryTotalTimeoutFeesRequest) | [QueryTotalTimeoutFeesResponse](#ibc.applications.fee.v1.QueryTotalTimeoutFeesResponse) | TotalTimeoutFees returns the total timeout fees for a packet given its identifier | GET|/ibc/apps/fee/v1/total_timeout_fees/port/{packet_id.port_id}/channel/{packet_id.channel_id}/sequence/{packet_id.sequence}|
| `CounterpartyAddress` | [QueryCounterpartyAddressRequest](#ibc.applications.fee.v1.QueryCounterpartyAddressRequest) | [QueryCounterpartyAddressResponse](#ibc.applications.fee.v1.QueryCounterpartyAddressResponse) | CounterpartyAddress returns the registered counterparty address for forward relaying | GET|/ibc/apps/fee/v1/counterparty_address/{relayer_address}/channel/{channel_id}|
| `IncentivizedPacket` | [QueryIncentivizedPacketRequest](#ibc.applications.fee.v1.QueryIncentivizedPacketRequest) | [QueryIncentivizedPacketResponse](#ibc.applications.fee.v1.QueryIncentivizedPacketResponse) | IncentivizedPacket returns all packet fees for a packet given its identifier | GET|/ibc/apps/fee/v1/channels/{packet_id.channel_id}/ports/{packet_id.port_id}/sequences/{packet_id.sequence}/incentivized_packet|
| `IncentivizedPacketsForChannel` | [QueryIncentivizedPacketsForChannelRequest](#ibc.applications.fee.v1.QueryIncentivizedPacketsForChannelRequest) | [QueryIncentivizedPacketsForChannelResponse](#ibc.applications.fee.v1.QueryIncentivizedPacketsForChannelResponse) | Gets all incentivized packets for a specific channel | GET|/ibc/apps/fee/v1/channels/{channel_id}/ports/{port_id}/incentivized_packets|
| `TotalRecvFees` | [QueryTotalRecvFeesRequest](#ibc.applications.fee.v1.QueryTotalRecvFeesRequest) | [QueryTotalRecvFeesResponse](#ibc.applications.fee.v1.QueryTotalRecvFeesResponse) | TotalRecvFees returns the total receive fees for a packet given its identifier | GET|/ibc/apps/fee/v1/channels/{packet_id.channel_id}/ports/{packet_id.port_id}/sequences/{packet_id.sequence}/total_recv_fees|
| `TotalAckFees` | [QueryTotalAckFeesRequest](#ibc.applications.fee.v1.QueryTotalAckFeesRequest) | [QueryTotalAckFeesResponse](#ibc.applications.fee.v1.QueryTotalAckFeesResponse) | TotalAckFees returns the total acknowledgement fees for a packet given its identifier | GET|/ibc/apps/fee/v1/channels/{packet_id.channel_id}/ports/{packet_id.port_id}/sequences/{packet_id.sequence}/total_ack_fees|
| `TotalTimeoutFees` | [QueryTotalTimeoutFeesRequest](#ibc.applications.fee.v1.QueryTotalTimeoutFeesRequest) | [QueryTotalTimeoutFeesResponse](#ibc.applications.fee.v1.QueryTotalTimeoutFeesResponse) | TotalTimeoutFees returns the total timeout fees for a packet given its identifier | GET|/ibc/apps/fee/v1/channels/{packet_id.channel_id}/ports/{packet_id.port_id}/sequences/{packet_id.sequence}/total_timeout_fees|
| `CounterpartyAddress` | [QueryCounterpartyAddressRequest](#ibc.applications.fee.v1.QueryCounterpartyAddressRequest) | [QueryCounterpartyAddressResponse](#ibc.applications.fee.v1.QueryCounterpartyAddressResponse) | CounterpartyAddress returns the registered counterparty address for forward relaying | GET|/ibc/apps/fee/v1/channels/{channel_id}/relayers/{relayer_address}/counterparty_address|
| `FeeEnabledChannels` | [QueryFeeEnabledChannelsRequest](#ibc.applications.fee.v1.QueryFeeEnabledChannelsRequest) | [QueryFeeEnabledChannelsResponse](#ibc.applications.fee.v1.QueryFeeEnabledChannelsResponse) | FeeEnabledChannels returns a list of all fee enabled channels | GET|/ibc/apps/fee/v1/fee_enabled|
| `FeeEnabledChannel` | [QueryFeeEnabledChannelRequest](#ibc.applications.fee.v1.QueryFeeEnabledChannelRequest) | [QueryFeeEnabledChannelResponse](#ibc.applications.fee.v1.QueryFeeEnabledChannelResponse) | FeeEnabledChannel returns true if the provided port and channel identifiers belong to a fee enabled channel | GET|/ibc/apps/fee/v1/fee_enabled/port/{port_id}/channel/{channel_id}|
| `FeeEnabledChannel` | [QueryFeeEnabledChannelRequest](#ibc.applications.fee.v1.QueryFeeEnabledChannelRequest) | [QueryFeeEnabledChannelResponse](#ibc.applications.fee.v1.QueryFeeEnabledChannelResponse) | FeeEnabledChannel returns true if the provided port and channel identifiers belong to a fee enabled channel | GET|/ibc/apps/fee/v1/channels/{channel_id}/ports/{port_id}/fee_enabled|

<!-- end services -->

Expand Down Expand Up @@ -1314,6 +1316,34 @@ MsgRegisterCounterpartyAddressResponse defines the response type for the Registe




<a name="ibc.applications.fee.v1.MsgRegisterPayee"></a>

### MsgRegisterPayee
MsgRegisterPayee defines the request type for the RegisterPayee rpc


| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `port_id` | [string](#string) | | unique port identifier |
| `channel_id` | [string](#string) | | unique channel identifier |
| `relayer_address` | [string](#string) | | the relayer address |
| `payee` | [string](#string) | | the fee payee address |






<a name="ibc.applications.fee.v1.MsgRegisterPayeeResponse"></a>

### MsgRegisterPayeeResponse
MsgRegisterPayeeResponse defines the response type for the RegisterPayee rpc





<!-- end messages -->

<!-- end enums -->
Expand All @@ -1328,7 +1358,8 @@ Msg defines the ICS29 Msg service.

| Method Name | Request Type | Response Type | Description | HTTP Verb | Endpoint |
| ----------- | ------------ | ------------- | ------------| ------- | -------- |
| `RegisterCounterpartyAddress` | [MsgRegisterCounterpartyAddress](#ibc.applications.fee.v1.MsgRegisterCounterpartyAddress) | [MsgRegisterCounterpartyAddressResponse](#ibc.applications.fee.v1.MsgRegisterCounterpartyAddressResponse) | RegisterCounterpartyAddress defines a rpc handler method for MsgRegisterCounterpartyAddress RegisterCounterpartyAddress is called by the relayer on each channelEnd and allows them to specify their counterparty address before relaying. This ensures they will be properly compensated for forward relaying since destination chain must send back relayer's source address (counterparty address) in acknowledgement. This function may be called more than once by a relayer, in which case, latest counterparty address is always used. | |
| `RegisterPayee` | [MsgRegisterPayee](#ibc.applications.fee.v1.MsgRegisterPayee) | [MsgRegisterPayeeResponse](#ibc.applications.fee.v1.MsgRegisterPayeeResponse) | RegisterPayee defines a rpc handler method for MsgRegisterPayee RegisterPayee is called by the relayer on each channelEnd and allows them to set an optional payee to which escrowed packet fees will be paid out. The payee should be registered on the source chain from which packets originate as this is where fee distribution takes place. This function may be called more than once by a relayer, in which case, the latest payee is always used. | |
| `RegisterCounterpartyAddress` | [MsgRegisterCounterpartyAddress](#ibc.applications.fee.v1.MsgRegisterCounterpartyAddress) | [MsgRegisterCounterpartyAddressResponse](#ibc.applications.fee.v1.MsgRegisterCounterpartyAddressResponse) | RegisterCounterpartyAddress defines a rpc handler method for MsgRegisterCounterpartyAddress RegisterCounterpartyAddress is called by the relayer on each channelEnd and allows them to specify their counterparty address before relaying. This ensures they will be properly compensated for forward relaying since destination chain must send back relayer's source address (counterparty address) in acknowledgement. This function may be called more than once by a relayer, in which case, the latest counterparty address is always used. | |
| `PayPacketFee` | [MsgPayPacketFee](#ibc.applications.fee.v1.MsgPayPacketFee) | [MsgPayPacketFeeResponse](#ibc.applications.fee.v1.MsgPayPacketFeeResponse) | PayPacketFee defines a rpc handler method for MsgPayPacketFee PayPacketFee is an open callback that may be called by any module/user that wishes to escrow funds in order to incentivize the relaying of the packet at the next sequence NOTE: This method is intended to be used within a multi msg transaction, where the subsequent msg that follows initiates the lifecycle of the incentivized packet | |
| `PayPacketFeeAsync` | [MsgPayPacketFeeAsync](#ibc.applications.fee.v1.MsgPayPacketFeeAsync) | [MsgPayPacketFeeAsyncResponse](#ibc.applications.fee.v1.MsgPayPacketFeeAsyncResponse) | PayPacketFeeAsync defines a rpc handler method for MsgPayPacketFeeAsync PayPacketFeeAsync is an open callback that may be called by any module/user that wishes to escrow funds in order to incentivize the relaying of a known packet (i.e. at a particular sequence) | |

Expand Down
3 changes: 2 additions & 1 deletion modules/apps/29-fee/client/cli/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,9 @@ func NewTxCmd() *cobra.Command {
}

txCmd.AddCommand(
NewRegisterPayeeCmd(),
NewPayPacketFeeAsyncTxCmd(),
NewRegisterCounterpartyAddress(),
NewRegisterCounterpartyAddressCmd(),
)

return txCmd
Expand Down
29 changes: 27 additions & 2 deletions modules/apps/29-fee/client/cli/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,31 @@ const (
flagTimeoutFee = "timeout-fee"
)

// NewRegisterPayeeCmd returns the command to create a MsgRegisterPayee
func NewRegisterPayeeCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "register-payee [port-id] [channel-id] [relayer-address] [payee-address] ",
Short: "Register a payee on a given channel.",
Long: strings.TrimSpace(`Register a payee address on a given channel.`),
Example: fmt.Sprintf("%s tx ibc-fee register-payee transfer channel-0 cosmos1rsp837a4kvtgp2m4uqzdge0zzu6efqgucm0qdh cosmos153lf4zntqt33a4v0sm5cytrxyqn78q7kz8j8x5", version.AppName),
Args: cobra.ExactArgs(4),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}

msg := types.NewMsgRegisterPayee(args[0], args[1], args[2], args[3])

return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
},
}

flags.AddTxFlagsToCmd(cmd)

return cmd
}

// NewPayPacketFeeAsyncTxCmd returns the command to create a MsgPayPacketFeeAsync
func NewPayPacketFeeAsyncTxCmd() *cobra.Command {
cmd := &cobra.Command{
Expand Down Expand Up @@ -98,8 +123,8 @@ func NewPayPacketFeeAsyncTxCmd() *cobra.Command {
return cmd
}

// NewRegisterCounterpartyAddress returns the command to create a MsgRegisterCounterpartyAddress
func NewRegisterCounterpartyAddress() *cobra.Command {
// NewRegisterCounterpartyAddressCmd returns the command to create a MsgRegisterCounterpartyAddress
func NewRegisterCounterpartyAddressCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "register-counterparty [port-id] [channel-id] [address] [counterparty-address] ",
Short: "Register a counterparty relayer address on a given channel.",
Expand Down
18 changes: 18 additions & 0 deletions modules/apps/29-fee/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,24 @@ func (k Keeper) GetAllFeeEnabledChannels(ctx sdk.Context) []types.FeeEnabledChan
return enabledChArr
}

// GetPayeeAddress retrieves the fee payee address stored in state given the provided channel identifier and relayer address
func (k Keeper) GetPayeeAddress(ctx sdk.Context, relayerAddr, channelID string) (string, bool) {
store := ctx.KVStore(k.storeKey)
key := types.KeyPayeeAddress(relayerAddr, channelID)

if !store.Has(key) {
return "", false
}

return string(store.Get(key)), true
}

// SetPayeeAddress stores the fee payee address in state keyed by the provided channel identifier and relayer address
func (k Keeper) SetPayeeAddress(ctx sdk.Context, relayerAddr, payeeAddr, channelID string) {
store := ctx.KVStore(k.storeKey)
store.Set(types.KeyPayeeAddress(relayerAddr, channelID), []byte(payeeAddr))
}

// SetCounterpartyAddress maps the destination chain relayer address to the source relayer address
// The receiving chain must store the mapping from: address -> counterpartyAddress for the given channel
func (k Keeper) SetCounterpartyAddress(ctx sdk.Context, address, counterpartyAddress, channelID string) {
Expand Down
19 changes: 19 additions & 0 deletions modules/apps/29-fee/keeper/keeper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,25 @@ func (suite *KeeperTestSuite) TestEscrowAccountHasBalance() {
suite.Require().False(suite.chainA.GetSimApp().IBCFeeKeeper.EscrowAccountHasBalance(suite.chainA.GetContext(), fee.Total()))
}

func (suite *KeeperTestSuite) TestGetSetPayeeAddress() {
suite.coordinator.Setup(suite.path)

payeeAddr, found := suite.chainA.GetSimApp().IBCFeeKeeper.GetPayeeAddress(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress().String(), suite.path.EndpointA.ChannelID)
suite.Require().False(found)
suite.Require().Empty(payeeAddr)

suite.chainA.GetSimApp().IBCFeeKeeper.SetPayeeAddress(
suite.chainA.GetContext(),
suite.chainA.SenderAccounts[0].SenderAccount.GetAddress().String(),
suite.chainA.SenderAccounts[1].SenderAccount.GetAddress().String(),
suite.path.EndpointA.ChannelID,
)

payeeAddr, found = suite.chainA.GetSimApp().IBCFeeKeeper.GetPayeeAddress(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress().String(), suite.path.EndpointA.ChannelID)
suite.Require().True(found)
suite.Require().Equal(suite.chainA.SenderAccounts[1].SenderAccount.GetAddress().String(), payeeAddr)
}

func (suite *KeeperTestSuite) TestFeesInEscrow() {
suite.coordinator.Setup(suite.path)

Expand Down
28 changes: 25 additions & 3 deletions modules/apps/29-fee/keeper/msg_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,30 @@ import (

var _ types.MsgServer = Keeper{}

// RegisterPayee defines a rpc handler method for MsgRegisterPayee
// RegisterPayee is called by the relayer on each channelEnd and allows them to set an optional
// payee to which escrowed packet fees will be paid out. The payee should be registered on the source chain from which
// packets originate as this is where fee distribution takes place. This function may be called more than once by a relayer,
// in which case, the latest payee is always used.
func (k Keeper) RegisterPayee(goCtx context.Context, msg *types.MsgRegisterPayee) (*types.MsgRegisterPayeeResponse, error) {
ctx := sdk.UnwrapSDKContext(goCtx)

// only register payee address if the channel exists and is fee enabled
if _, found := k.channelKeeper.GetChannel(ctx, msg.PortId, msg.ChannelId); !found {
return nil, channeltypes.ErrChannelNotFound
}

if !k.IsFeeEnabled(ctx, msg.PortId, msg.ChannelId) {
return nil, types.ErrFeeNotEnabled
}

k.SetPayeeAddress(ctx, msg.RelayerAddress, msg.Payee, msg.ChannelId)

k.Logger(ctx).Info("registering payee address for relayer", "relayer address", msg.RelayerAddress, "payee address", msg.Payee, "channel", msg.ChannelId)

return &types.MsgRegisterPayeeResponse{}, nil
}

// RegisterCounterpartyAddress is called by the relayer on each channelEnd and allows them to specify their counterparty address before relaying
// This ensures they will be properly compensated for forward relaying on the source chain since the destination chain must send back relayer's source address (counterparty address) in acknowledgement
// This function may be called more than once by relayers, in which case, the previous counterparty address will be overwritten by the new counterparty address
Expand All @@ -27,9 +51,7 @@ func (k Keeper) RegisterCounterpartyAddress(goCtx context.Context, msg *types.Ms
return nil, types.ErrFeeNotEnabled
}

k.SetCounterpartyAddress(
ctx, msg.Address, msg.CounterpartyAddress, msg.ChannelId,
)
k.SetCounterpartyAddress(ctx, msg.Address, msg.CounterpartyAddress, msg.ChannelId)

k.Logger(ctx).Info("registering counterparty address for relayer", "address", msg.Address, "counterparty address", msg.CounterpartyAddress, "channel", msg.ChannelId)

Expand Down
64 changes: 64 additions & 0 deletions modules/apps/29-fee/keeper/msg_server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,70 @@ import (
ibctesting "github.com/cosmos/ibc-go/v3/testing"
)

func (suite *KeeperTestSuite) TestRegisterPayee() {
var (
msg *types.MsgRegisterPayee
)

testCases := []struct {
name string
expPass bool
malleate func()
}{
{
"success",
true,
func() {},
},
{
"channel does not exist",
false,
func() {
msg.ChannelId = "channel-100"
},
},
{
"channel is not fee enabled",
false,
func() {
suite.chainA.GetSimApp().IBCFeeKeeper.DeleteFeeEnabled(suite.chainA.GetContext(), suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID)
},
},
}

for _, tc := range testCases {
suite.SetupTest()
suite.coordinator.Setup(suite.path)

msg = types.NewMsgRegisterPayee(
suite.path.EndpointA.ChannelConfig.PortID,
suite.path.EndpointA.ChannelID,
suite.chainA.SenderAccounts[0].SenderAccount.GetAddress().String(),
suite.chainA.SenderAccounts[1].SenderAccount.GetAddress().String(),
)

tc.malleate()

res, err := suite.chainA.GetSimApp().IBCFeeKeeper.RegisterPayee(sdk.WrapSDKContext(suite.chainA.GetContext()), msg)

if tc.expPass {
suite.Require().NoError(err)
suite.Require().NotNil(res)

payeeAddr, found := suite.chainA.GetSimApp().IBCFeeKeeper.GetPayeeAddress(
suite.chainA.GetContext(),
suite.chainA.SenderAccount.GetAddress().String(),
suite.path.EndpointA.ChannelID,
)

suite.Require().True(found)
suite.Require().Equal(suite.chainA.SenderAccounts[1].SenderAccount.GetAddress().String(), payeeAddr)
} else {
suite.Require().Error(err)
}
}
}

func (suite *KeeperTestSuite) TestRegisterCounterpartyAddress() {
var (
sender string
Expand Down
Loading