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

Fee Middleware: Escrow logic #465

Merged
merged 50 commits into from
Nov 5, 2021
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
435efc7
fix: adding second endpoint for async pay fee + renaming types
seantking Oct 1, 2021
8f2c51a
feat: adding escrow logic
seantking Oct 1, 2021
a410af6
feat: updating proto types & escrow logic
seantking Oct 4, 2021
0e6823f
fix: stub fn & proto comment
seantking Oct 5, 2021
f41e520
feat: adding PayFee & PayFeeTimeout & escrow_test
seantking Oct 6, 2021
e4bd49a
test: adding happy path for EscrowPacketFee
seantking Oct 6, 2021
ca7f4e2
fix: comments, error handling
seantking Oct 7, 2021
6a5add7
fix: comments & grammar
seantking Oct 7, 2021
535e2c6
test: adding unhappy path for escrow
seantking Oct 8, 2021
5bd0e32
tests(escrow): adding hasBalance check for module acc
seantking Oct 8, 2021
31fcee3
test(PayFee): adding happy path for PayFee tests
seantking Oct 8, 2021
487f78d
tests(PayFee, PayFeeTimeout): adding tests
seantking Oct 8, 2021
f25932f
fix: adding relayers back to IdentifiedPacket
seantking Oct 11, 2021
38566bc
fix: removing refund acc from key
seantking Oct 11, 2021
dd0044b
fix: storing IdentifiedPacketFee in state instead of Fee
seantking Oct 11, 2021
5b4a395
feat: adding msg_server test for registerCPAddr, wiring for codec + s…
seantking Oct 11, 2021
c9af582
test: adding msg_server test for PayPacketFee
seantking Oct 12, 2021
d325146
test: adding PayPacketFeeAsync msg_server test
seantking Oct 12, 2021
ea9b30b
chore: updating PayFee -> DistributeFee & minor nits
seantking Oct 13, 2021
ac7584f
nit: removing unnecessary nil check
seantking Oct 13, 2021
c44a81c
refactor: add portId to store key & use packetId as param
seantking Oct 13, 2021
a8c3cff
fix: add DeleteFeeInEscrow & remove fee on successful distribution
seantking Oct 13, 2021
4f490ea
tests: adding validation & signer tests for PayFee/Async & updating p…
seantking Oct 13, 2021
f1fde1d
chore: adding NewIdentifiedPacketFee fn
seantking Oct 13, 2021
eeb4376
fix: getter/setter for counterparty address + fix NewIdentifiedPacketFee
seantking Oct 14, 2021
4612bf2
fix: updating EscrowPacketFee with correct usage of coins api
seantking Oct 14, 2021
3494a0f
test: adding balance check for refund acc after escrow
seantking Oct 14, 2021
f4c37e6
fix: remove unncessary errors
seantking Oct 14, 2021
0b733ab
test: updating escrow tests + miscellaneous fixes
seantking Nov 3, 2021
2be4ab5
nit: updating var names
seantking Nov 3, 2021
cb2cbc3
docs: godoc
seantking Nov 3, 2021
66454c6
refactor: IdentifiedPacketFee & Fee no longer pointers
seantking Nov 3, 2021
06d4c25
fixes: small fixes
seantking Nov 3, 2021
f336ca7
Update modules/apps/29-fee/keeper/escrow.go
seantking Nov 4, 2021
8e2eb8f
Update modules/apps/29-fee/keeper/escrow.go
seantking Nov 4, 2021
52fa63e
Update modules/apps/29-fee/keeper/keeper.go
seantking Nov 4, 2021
0587a3c
Update modules/apps/29-fee/keeper/msg_server.go
seantking Nov 4, 2021
63e7a1a
Update modules/apps/29-fee/keeper/msg_server.go
seantking Nov 4, 2021
a40159f
Update modules/apps/29-fee/types/msgs.go
seantking Nov 4, 2021
f379aaf
nit: proto doc & error fix
seantking Nov 4, 2021
2f649a8
fix: escrow test
seantking Nov 5, 2021
b100ee0
test: updating distribute fee tests
seantking Nov 5, 2021
b19ebd2
test: adding validation check for fee and updating tests
seantking Nov 5, 2021
a51e2ff
test: allow counterparty address to be arbitrary string
seantking Nov 5, 2021
bbfd8d7
fix: message validation should pass if one fee is valid
seantking Nov 5, 2021
6640660
Update modules/apps/29-fee/keeper/escrow.go
seantking Nov 5, 2021
4610c99
Update modules/apps/29-fee/keeper/escrow.go
seantking Nov 5, 2021
bec52c0
fix: nits
seantking Nov 5, 2021
2c9185c
Update modules/apps/29-fee/keeper/escrow.go
seantking Nov 5, 2021
f4de334
test: adding isZero check for msgs
seantking Nov 5, 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
64 changes: 46 additions & 18 deletions docs/ibc/proto-docs.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,10 @@
- [Query](#ibc.applications.fee.v1.Query)

- [ibc/applications/fee/v1/tx.proto](#ibc/applications/fee/v1/tx.proto)
- [MsgEscrowPacketFee](#ibc.applications.fee.v1.MsgEscrowPacketFee)
- [MsgEscrowPacketFeeResponse](#ibc.applications.fee.v1.MsgEscrowPacketFeeResponse)
- [MsgPayPacketFee](#ibc.applications.fee.v1.MsgPayPacketFee)
- [MsgPayPacketFeeAsync](#ibc.applications.fee.v1.MsgPayPacketFeeAsync)
- [MsgPayPacketFeeAsyncResponse](#ibc.applications.fee.v1.MsgPayPacketFeeAsyncResponse)
- [MsgPayPacketFeeResponse](#ibc.applications.fee.v1.MsgPayPacketFeeResponse)
- [MsgRegisterCounterpartyAddress](#ibc.applications.fee.v1.MsgRegisterCounterpartyAddress)
- [MsgRegisterCounterpartyAddressResponse](#ibc.applications.fee.v1.MsgRegisterCounterpartyAddressResponse)

Expand Down Expand Up @@ -628,7 +630,9 @@ https://github.com/cosmos/ibc/tree/master/spec/app/ics-029-fee-payment#fee-middl

| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `amount` | [cosmos.base.v1beta1.Coin](#cosmos.base.v1beta1.Coin) | repeated | |
| `receive_fee` | [cosmos.base.v1beta1.Coin](#cosmos.base.v1beta1.Coin) | | |
| `ack_fee` | [cosmos.base.v1beta1.Coin](#cosmos.base.v1beta1.Coin) | | |
| `timeout_fee` | [cosmos.base.v1beta1.Coin](#cosmos.base.v1beta1.Coin) | | |



Expand All @@ -644,10 +648,7 @@ Fee associated with a packet_id
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `packet_id` | [ibc.core.channel.v1.PacketId](#ibc.core.channel.v1.PacketId) | | |
| `receive_fee` | [Fee](#ibc.applications.fee.v1.Fee) | | |
| `ack_fee` | [Fee](#ibc.applications.fee.v1.Fee) | | |
| `timeout_fee` | [Fee](#ibc.applications.fee.v1.Fee) | | |
| `relayers` | [string](#string) | repeated | |
| `fee` | [Fee](#ibc.applications.fee.v1.Fee) | | |



Expand Down Expand Up @@ -676,11 +677,6 @@ Fee associated with a packet_id
GenesisState defines the fee middleware genesis state


| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `packets_fees` | [IdentifiedPacketFee](#ibc.applications.fee.v1.IdentifiedPacketFee) | repeated | A mapping of packets -> escrowed fees |





Expand Down Expand Up @@ -889,25 +885,56 @@ Query provides defines the gRPC querier service.



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

### MsgEscrowPacketFee
### MsgPayPacketFee
MsgEscrowPacketFee defines the request type EscrowPacketFee RPC


| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `incentivized_packet` | [IdentifiedPacketFee](#ibc.applications.fee.v1.IdentifiedPacketFee) | | |
| `fee` | [Fee](#ibc.applications.fee.v1.Fee) | | |
| `source_port_id` | [string](#string) | | source channel port identifier |
| `source_channel_id` | [string](#string) | | source channel unique identifier |
| `refund_account` | [string](#string) | | account address to refund fee if necessary |
| `relayers` | [string](#string) | repeated | |






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

### MsgPayPacketFeeAsync
MsgEscrowPacketFeeAsync defines the request type EscrowPacketFeeAsync RPC


| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `fee` | [Fee](#ibc.applications.fee.v1.Fee) | | source channel port identifier |
| `packet_id` | [ibc.core.channel.v1.PacketId](#ibc.core.channel.v1.PacketId) | | source channel unique identifier |
| `refund_account` | [string](#string) | | account address to refund fee if necessary |
| `relayers` | [string](#string) | repeated | |






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

### MsgPayPacketFeeAsyncResponse
MsgEscrowPacketFeeAsyncResponse defines the response type for Msg/EscrowPacketFeeAsync






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

### MsgEscrowPacketFeeResponse
### MsgPayPacketFeeResponse
MsgEscrowPacketFeeResponse defines the response type for Msg/EscrowPacketFee


Expand Down Expand Up @@ -955,7 +982,8 @@ Msg defines the ibc/fee 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. | |
| `EscrowPacketFee` | [MsgEscrowPacketFee](#ibc.applications.fee.v1.MsgEscrowPacketFee) | [MsgEscrowPacketFeeResponse](#ibc.applications.fee.v1.MsgEscrowPacketFeeResponse) | EscrowPacketFee defines a rpc handler method for MsgEscrowPacketFee EscrowPacketFee 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 given packet. | |
| `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 | |
| `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 | |

<!-- end services -->

Expand Down
132 changes: 132 additions & 0 deletions modules/apps/29-fee/keeper/escrow.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
package keeper

import (
"fmt"

sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"

"github.com/cosmos/ibc-go/modules/apps/29-fee/types"
channeltypes "github.com/cosmos/ibc-go/modules/core/04-channel/types"
)

// TODO: add optional relayers arr
func (k Keeper) EscrowPacketFee(ctx sdk.Context, refundAcc sdk.AccAddress, fee types.Fee, packetID channeltypes.PacketId) error {
// check if the refund account exists
hasRefundAcc := k.authKeeper.GetAccount(ctx, refundAcc)
if hasRefundAcc == nil {
return sdkerrors.Wrap(types.ErrRefundAccNotFound, fmt.Sprintf("Account with address: %s not found", refundAcc.String()))
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
return sdkerrors.Wrap(types.ErrRefundAccNotFound, fmt.Sprintf("Account with address: %s not found", refundAcc.String()))
return sdkerrors.Wrapf(types.ErrRefundAccNotFound, "account with address: %s not found", refundAcc)

if %s is used, .String() should automatically be called (unless I am mistaken?)

}

fees := sdk.Coins{
*fee.AckFee, *fee.ReceiveFee, *fee.TimeoutFee,
}

// check if refundAcc has balance for each fee
colin-axner marked this conversation as resolved.
Show resolved Hide resolved
for _, f := range fees {
hasBalance := k.bankKeeper.HasBalance(ctx, refundAcc, f)
if !hasBalance {
return sdkerrors.Wrap(types.ErrBalanceNotFound, fmt.Sprintf("%s", refundAcc.String()))
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
return sdkerrors.Wrap(types.ErrBalanceNotFound, fmt.Sprintf("%s", refundAcc.String()))
return sdkerrors.Wrap(types.ErrBalanceNotFound, refundAcc.String())

Copy link
Contributor

Choose a reason for hiding this comment

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

Should this error be insufficient balance?

}
}

for _, coin := range fees {
// escrow each fee with account module
if err := k.bankKeeper.SendCoinsFromAccountToModule(
AdityaSripal marked this conversation as resolved.
Show resolved Hide resolved
ctx, refundAcc, types.ModuleName, sdk.Coins{coin},
); err != nil {
return err
colin-axner marked this conversation as resolved.
Show resolved Hide resolved
}
}
Copy link
Member

Choose a reason for hiding this comment

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

We can be more capital efficient here.

Really we just need to escrow the max(fee.TimeoutFee, fee.RecvFee+fee.AckFee)

Since the packet will only go down one of those 2 paths. There's never a point where all 3 fees are paid out

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I was under the impression that each coin could be of a separate denom?

Copy link
Member

Choose a reason for hiding this comment

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

That is correct. You can still calculate max.

Suppose:
RecvFee: 50 stake
AckFee: 30 atoms
TimeoutFee: 70 stake

Then you need to escrow: 30 atom, 70 stake.

If packet gets acked, then you refund: 20 stake.

If packet times out, you refund 30 atoms

Same logic would hold for sdk.Coins fee

Copy link
Member

Choose a reason for hiding this comment

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

You can check if there's a utility function in sdk/types to help you out with this. Otherwise you can implement the utility function yourself.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Okay, thanks, makes sense.

Copy link
Contributor

Choose a reason for hiding this comment

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

I'd prefer to go with the simple approach and do this as a future optimization (like how we pushed consensus state pruning until after launch). It is additional complexity

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Agree with @colin-axner 👍


// Store fee in state for reference later
// feeInEscrow/<refund-account>/<channel-id>/packet/<sequence-id>/ -> Fee (timeout, ack, onrecv)
k.SetFeeInEscrow(ctx, fee, refundAcc.String(), packetID.ChannelId, packetID.Sequence)
return nil
}

func (k Keeper) payFee(ctx sdk.Context, refundAcc, forwardRelayer, reverseRelayer sdk.AccAddress, packetID channeltypes.PacketId) error {
// check if there is a Fee in escrow for the given packetId
feeInEscrow, hasFee := k.GetFeeInEscrow(ctx, refundAcc.String(), packetID.ChannelId, packetID.Sequence)
if !hasFee {
return sdkerrors.Wrap(types.ErrFeeNotFound, fmt.Sprintf("%s", refundAcc.String()))
Copy link
Contributor

Choose a reason for hiding this comment

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

Shouldn't the error indicate for the channel/sequence?

}

// get module accAddr
feeModuleAccAddr := k.authKeeper.GetModuleAddress(types.ModuleName)

// send ack fee to forward relayer
if feeInEscrow.AckFee != nil {
err := k.bankKeeper.SendCoins(ctx, feeModuleAccAddr, forwardRelayer, sdk.Coins{*feeInEscrow.AckFee})
if err != nil {
return sdkerrors.Wrap(types.ErrFeeNotFound, fmt.Sprintf("%s", refundAcc.String()))
}
feeInEscrow.AckFee = nil
k.SetFeeInEscrow(ctx, feeInEscrow, refundAcc.String(), packetID.ChannelId, packetID.Sequence)
}

// send ack fee to forward relayer
if feeInEscrow.ReceiveFee != nil {
err := k.bankKeeper.SendCoins(ctx, feeModuleAccAddr, reverseRelayer, sdk.Coins{*feeInEscrow.AckFee})
if err != nil {
return sdkerrors.Wrap(types.ErrFeeNotFound, fmt.Sprintf("%s", refundAcc.String()))
}
feeInEscrow.ReceiveFee = nil
k.SetFeeInEscrow(ctx, feeInEscrow, refundAcc.String(), packetID.ChannelId, packetID.Sequence)
}

// refund timeout fee to refundAddr
if feeInEscrow.TimeoutFee != nil {
err := k.bankKeeper.SendCoins(ctx, feeModuleAccAddr, refundAcc, sdk.Coins{*feeInEscrow.AckFee})
if err != nil {
return sdkerrors.Wrap(types.ErrFeeNotFound, fmt.Sprintf("%s", refundAcc.String()))
}
// set fee as an empty struct (if we reach this point Fee is paid in full)
k.SetFeeInEscrow(ctx, types.Fee{}, refundAcc.String(), packetID.ChannelId, packetID.Sequence)
}

return nil
}

func (k Keeper) payFeeTimeout(ctx sdk.Context, refundAcc, forwardRelayer, reverseRelayer sdk.AccAddress, packetID channeltypes.PacketId) error {
// check if there is a Fee in escrow for the given packetId
feeInEscrow, hasFee := k.GetFeeInEscrow(ctx, refundAcc.String(), packetID.ChannelId, packetID.Sequence)
if !hasFee {
return sdkerrors.Wrap(types.ErrFeeNotFound, fmt.Sprintf("%s", refundAcc.String()))
}

// get module accAddr
feeModuleAccAddr := k.authKeeper.GetModuleAddress(types.ModuleName)

// send ack fee to forward relayer
if feeInEscrow.AckFee != nil {
err := k.bankKeeper.SendCoins(ctx, feeModuleAccAddr, refundAcc, sdk.Coins{*feeInEscrow.AckFee})
if err != nil {
return sdkerrors.Wrap(types.ErrFeeNotFound, fmt.Sprintf("%s", refundAcc.String()))
}
feeInEscrow.AckFee = nil
k.SetFeeInEscrow(ctx, feeInEscrow, refundAcc.String(), packetID.ChannelId, packetID.Sequence)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@AdityaSripal Same issue here when we return an error on SendCoin. We need to keep track of the state of the Fee (say in the case where AckFee is sent but the TimeoutFee fails, we don't want to lose track of the fact that AckFee was escrowed).

I think the solution is to only do the send here in the case that all are successful. I was thinking we could use the cacheContext similar to how we are doing this with interchain accounts?

Copy link
Member

Choose a reason for hiding this comment

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

checkout baseapp.go in the SDK. runTx already wraps entire tx execution in cache context.

What we did in ibc-go was because we wanted the tx to pass (and thus commit IBC state) while reverting any changes in callbacks. That's not necessary here. You already get atomicity out of the box with SDK

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ahhh very good. That makes things much simpler. Thank you 🤝

}

// send ack fee to forward relayer
if feeInEscrow.ReceiveFee != nil {
err := k.bankKeeper.SendCoins(ctx, feeModuleAccAddr, refundAcc, sdk.Coins{*feeInEscrow.AckFee})
if err != nil {
return sdkerrors.Wrap(types.ErrFeeNotFound, fmt.Sprintf("%s", refundAcc.String()))
}
feeInEscrow.ReceiveFee = nil
k.SetFeeInEscrow(ctx, feeInEscrow, refundAcc.String(), packetID.ChannelId, packetID.Sequence)
}

// refund timeout fee to refundAddr
if feeInEscrow.TimeoutFee != nil {
err := k.bankKeeper.SendCoins(ctx, feeModuleAccAddr, forwardRelayer, sdk.Coins{*feeInEscrow.AckFee})
if err != nil {
return sdkerrors.Wrap(types.ErrFeeNotFound, fmt.Sprintf("%s", refundAcc.String()))
}
// set fee as an empty struct (if we reach this point Fee is paid in full)
k.SetFeeInEscrow(ctx, types.Fee{}, refundAcc.String(), packetID.ChannelId, packetID.Sequence)
}

return nil
}
51 changes: 51 additions & 0 deletions modules/apps/29-fee/keeper/escrow_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package keeper_test

import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/ibc-go/modules/apps/29-fee/types"
channeltypes "github.com/cosmos/ibc-go/modules/core/04-channel/types"
seantking marked this conversation as resolved.
Show resolved Hide resolved
)

func (suite *KeeperTestSuite) TestEscrowPacketFee() {
var (
err error
)

testCases := []struct {
AdityaSripal marked this conversation as resolved.
Show resolved Hide resolved
name string
malleate func()
expPass bool
}{
{
"success", func() {}, true,
},
}

for _, tc := range testCases {
tc := tc

suite.Run(tc.name, func() {
suite.SetupTest() // reset

// setup
refundAcc := suite.chainA.SenderAccount.GetAddress()
ackFee := &sdk.Coin{Denom: "stake", Amount: sdk.NewInt(100)}
recieveFee := &sdk.Coin{Denom: "stake", Amount: sdk.NewInt(100)}
timeoutFee := &sdk.Coin{Denom: "stake", Amount: sdk.NewInt(100)}
fee := types.Fee{ackFee, recieveFee, timeoutFee}
packetId := channeltypes.PacketId{ChannelId: "channel-0", PortId: "fee", Sequence: uint64(1)}

tc.malleate() // explicitly change fields in channel and testChannel

// escrow the packet fee
err = suite.chainA.GetSimApp().IBCFeeKeeper.EscrowPacketFee(suite.chainA.GetContext(), refundAcc, fee, packetId)

if tc.expPass {
suite.Require().NoError(err)
} else {
suite.Require().Error(err)
}

})
}
}
47 changes: 46 additions & 1 deletion modules/apps/29-fee/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (

"github.com/cosmos/ibc-go/modules/apps/29-fee/types"
channeltypes "github.com/cosmos/ibc-go/modules/core/04-channel/types"

Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change

host "github.com/cosmos/ibc-go/modules/core/24-host"
ibcexported "github.com/cosmos/ibc-go/modules/core/exported"
)
Expand All @@ -26,21 +27,25 @@ type Keeper struct {
storeKey sdk.StoreKey
cdc codec.BinaryCodec

authKeeper types.AccountKeeper
channelKeeper types.ChannelKeeper
portKeeper types.PortKeeper
bankKeeper types.BankKeeper
}

// NewKeeper creates a new 29-fee Keeper instance
func NewKeeper(
cdc codec.BinaryCodec, key sdk.StoreKey, paramSpace paramtypes.Subspace,
channelKeeper types.ChannelKeeper, portKeeper types.PortKeeper,
channelKeeper types.ChannelKeeper, portKeeper types.PortKeeper, authKeeper types.AccountKeeper, bankKeeper types.BankKeeper,
) Keeper {

return Keeper{
cdc: cdc,
storeKey: key,
channelKeeper: channelKeeper,
portKeeper: portKeeper,
authKeeper: authKeeper,
bankKeeper: bankKeeper,
}
}

Expand Down Expand Up @@ -70,6 +75,11 @@ func (k Keeper) GetNextSequenceSend(ctx sdk.Context, portID, channelID string) (
return k.channelKeeper.GetNextSequenceSend(ctx, portID, channelID)
}

// GetFeeAccount returns the ICS29 - fee ModuleAccount address
colin-axner marked this conversation as resolved.
Show resolved Hide resolved
func (k Keeper) GetFeeModuleAddress() sdk.AccAddress {
return k.authKeeper.GetModuleAddress(types.ModuleName)
}

// SendPacket wraps IBC ChannelKeeper's SendPacket function
func (k Keeper) SendPacket(ctx sdk.Context, chanCap *capabilitytypes.Capability, packet ibcexported.PacketI) error {
return k.channelKeeper.SendPacket(ctx, chanCap, packet)
Expand Down Expand Up @@ -113,3 +123,38 @@ func (k Keeper) GetCounterpartyAddress(ctx sdk.Context, address sdk.AccAddress)

return store.Get(key), true
}

// Stores a Fee for a given packet in state
func (k Keeper) SetFeeInEscrow(ctx sdk.Context, fee types.Fee, account, channelId string, sequenceId uint64) {
store := ctx.KVStore(k.storeKey)
bz := k.MustMarshalFee(fee)
store.Set(types.KeyFeeInEscrow(account, channelId, sequenceId), bz)
}

// Gets a Fee for a given packet
func (k Keeper) GetFeeInEscrow(ctx sdk.Context, account, channelId string, sequenceId uint64) (types.Fee, bool) {
store := ctx.KVStore(k.storeKey)
key := types.KeyFeeInEscrow(account, channelId, sequenceId)
bz := store.Get(key)
if bz == nil {
return types.Fee{}, false
}

fee := k.MustUnmarshalFee(bz)

Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change

return fee, true
}

// MustMarshalFee attempts to encode a Fee object and returns the
// raw encoded bytes. It panics on error.
func (k Keeper) MustMarshalFee(fee types.Fee) []byte {
return k.cdc.MustMarshal(&fee)
}

// MustUnmarshalFee attempts to decode and return a Fee object from
// raw encoded bytes. It panics on error.
func (k Keeper) MustUnmarshalFee(bz []byte) types.Fee {
var fee types.Fee
k.cdc.MustUnmarshal(bz, &fee)
return fee
}
Loading