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

ICS 29: Fee Middleware #276

Merged
merged 87 commits into from
Apr 6, 2022
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
87 commits
Select commit Hold shift + click to select a range
18feadf
scaffolding for 29-fee (#274)
colin-axner Jul 21, 2021
4b9a832
feat: adding proto files for fee payment middleware (#272)
seantking Jul 26, 2021
158a251
fix: removing unncessary fields MsgEscrow & adding query params (#300)
seantking Jul 27, 2021
c63af4a
Merge branch 'main' into ics29-fee-middleware
colin-axner Aug 12, 2021
e3704c6
feat: #258 Register Counterparty Address (#376)
seantking Sep 8, 2021
70c58af
fix: remove comments for imports (#385)
seantking Sep 9, 2021
dd4f8c7
feat: Add handshake logic to ics29 (#307)
AdityaSripal Sep 27, 2021
67bd594
Fee Middleware: Escrow logic (#465)
seantking Nov 5, 2021
405f193
feat: update protos, grpc queries (#488)
charleenfei Nov 10, 2021
8ebbe18
store refund address in IdentifiedPacketFee (#546)
AdityaSripal Nov 18, 2021
d419972
29-Fee: Genesis (#557)
seantking Nov 24, 2021
4dbc83e
feat: adding genesis validation + tests (#561)
seantking Nov 24, 2021
c4dff6c
feat: add incentivised ack proto (#564)
charleenfei Nov 29, 2021
edd11c6
Fee Closing Handshake (#551)
AdityaSripal Nov 29, 2021
885fb9a
Fee Middleware: Add ICS4 wrapper (#562)
seantking Dec 1, 2021
a737132
feat: ics 29 packet callbacks (#357)
charleenfei Dec 21, 2021
53b2f67
Merge branch 'main' of github.com:cosmos/ibc-go into ics29-fee-middle…
colin-axner Jan 12, 2022
e0cc81a
update imports to v3
colin-axner Jan 12, 2022
120fd76
regenerate proto files
colin-axner Jan 12, 2022
0fbc6bb
fix build
colin-axner Jan 12, 2022
dbda885
update ics29 to tip of main (#716)
colin-axner Jan 12, 2022
9285133
fix: event caching for fee distribution (#661)
charleenfei Jan 12, 2022
f3e9f95
ics4 callbacks fee middleware (#580)
seantking Jan 12, 2022
26731ce
chore: making PacketId non nullable (#737)
seantking Jan 18, 2022
764df84
nits: proto spacing + naming (#739)
seantking Jan 20, 2022
d761982
sean/fix-proto-identified-fee-not-null (#746)
seantking Jan 20, 2022
f552fb2
nits: more ics29 nits (#741)
seantking Jan 20, 2022
16e452b
nit: update err syntax (#747)
seantking Jan 20, 2022
b16353e
feat: adding Route, Type, GetSignBytes for all messages (#743)
seantking Jan 21, 2022
b618f02
hygiene: add validate fn for Fee (#748)
seantking Jan 21, 2022
13f77de
fix: app.go (#789)
seantking Jan 26, 2022
6cb4a38
refactor: ics29 json encoded version metadata (#883)
damiannolan Feb 9, 2022
e0161a7
Merge branch 'main' of github.com:cosmos/ibc-go into ics29-fee-middle…
colin-axner Feb 10, 2022
dedbb57
chore: bump ics29 to tip of main (#900)
colin-axner Feb 10, 2022
6f19978
fix: return nil on OnRecvPacket for async pay (#911)
seantking Feb 15, 2022
ea2984b
nit: ics29 comments (#910)
seantking Feb 15, 2022
323c574
Merge branch 'main' into ics29-fee-middleware
colin-axner Feb 15, 2022
fb243c6
chore: Add transfer test for ics29 (#901)
colin-axner Feb 16, 2022
8d226de
refactor: ics29 OnChanOpenInit callback tests now use mock module (#924)
colin-axner Feb 16, 2022
2c1ff0b
feat: allow multiple addrs to incentivize packets (#915)
damiannolan Feb 16, 2022
39ef8d7
chore: remove spec directory from ics29 (#934)
colin-axner Feb 17, 2022
1fb4b5a
refactor: use mock module for ics29 closing handshakes (#926)
colin-axner Feb 17, 2022
9895948
refactor: use mock module for ics29 grpc_query_test.go (#933)
colin-axner Feb 17, 2022
acc699d
refactor: readjust keeper_test.go to use mock module (#930)
colin-axner Feb 17, 2022
9b2d96d
fix: fields for genesis should be non nullable (#938)
seantking Feb 17, 2022
06f2730
refactor: use mock module for ics29 escrow_test.go (#932)
colin-axner Feb 17, 2022
ff15335
refactor: use mock module for ics29 genesis_test.go (#931)
colin-axner Feb 17, 2022
d8b9821
ics29:feat: emit event escrow (#914)
seantking Feb 17, 2022
adc66d2
refactor: OnRecvPacket to use mock module (#927)
colin-axner Feb 18, 2022
4326c14
refactor: ics29 OnChanOpenTry/Ack use mock module for testing instead…
colin-axner Feb 18, 2022
ad7827f
refactor: use mock module for OnAcknowledgePacket callback testing (#…
colin-axner Feb 21, 2022
7c6076f
refactor: OnTimeoutPacket to use mock module (#928)
colin-axner Feb 21, 2022
179c4f4
chore: add packet id arg to EscrowPacketFee (#951)
damiannolan Feb 21, 2022
c14d2b4
chore: remove legacy testing functions (#954)
colin-axner Feb 21, 2022
99db143
fix:ics29: WriteAck update + adding success bool to IncentivizedAck (…
seantking Feb 21, 2022
74afccd
chore: add cli cmd to incentivize existing packet (async) (#965)
colin-axner Feb 22, 2022
6928af7
ics29:fix: counterparty addr must contain channelID (#937)
seantking Feb 22, 2022
6999e10
chore: fix err msg (#971)
colin-axner Feb 22, 2022
4fb6d18
ics29:fix: store source address for query later on WriteAck (#912)
seantking Feb 23, 2022
b02d193
refactor: make fee storage more efficient (#956)
damiannolan Feb 23, 2022
15fa37b
chore: update ics29 genesis state to support multiple packet fees (#957)
damiannolan Feb 23, 2022
9350d53
chore: update MsgPayPacketFeeAsync fields (#979)
damiannolan Feb 24, 2022
f1ba06f
chore: add ParseKeyFeesInEscrow helper function (#998)
colin-axner Feb 24, 2022
fcea26d
chore: update grpc queries to handle multiple fees (#967)
damiannolan Feb 24, 2022
9c508d2
feat: CLI cmd for MsgRegisterCounterpartyAddress (#987)
seantking Feb 24, 2022
7991f79
fix: ics29: switch source with destintion for chan/port IDs (#961)
seantking Feb 25, 2022
9ece5da
test: cleanup 29-fee/types tests (#1006)
damiannolan Feb 25, 2022
f8b4345
feat: grpc query total recv packet fees (#1015)
damiannolan Mar 1, 2022
e51e2c9
chore: switch code ordering (#1025)
colin-axner Mar 1, 2022
5f8fc9f
feat: Add ParseKeyFeeEnabled and rename FeeEnabledKey -> KeyFeeEnable…
colin-axner Mar 1, 2022
4623772
feat: ics29 cli for query total recv fees (#1035)
damiannolan Mar 1, 2022
8d380ba
feat: grpc query total ack fees (#1032)
damiannolan Mar 1, 2022
9137084
feat: grpc query total timeout fees (#1033)
damiannolan Mar 2, 2022
d788adf
feat: adding clis for total ack and timeout queries (#1043)
damiannolan Mar 2, 2022
478db4f
add ParseKeyForwardRelayerAddress function + test (#1046)
charleenfei Mar 2, 2022
71167c4
chore: remove unused ics29 keeper funcs (#1044)
damiannolan Mar 3, 2022
4bf859a
chore: add gRPC for querying incentivized packets for a specific chan…
colin-axner Mar 3, 2022
b33b0a7
add function EscrowAccountHasBalance (#1042)
colin-axner Mar 3, 2022
f3ee8de
feat: ParseKeyCounterpartyRelayer function (#1047)
charleenfei Mar 3, 2022
db88c84
chore: adding queries to cmd builder (#1057)
damiannolan Mar 3, 2022
637652d
chore: update ics29 protodocs (#1055)
damiannolan Mar 4, 2022
4a0e00c
Merge branch 'main' into ics29-fee-middleware
Mar 22, 2022
ab90f07
add counter party channel ID to argument list of on channel open ack …
Mar 22, 2022
3ab2251
ADR 004: Fee module locking in the presence of severe bugs (#1060)
colin-axner Mar 29, 2022
e1cca36
nit: packetID var name (#1214)
seantking Apr 5, 2022
e65e881
Merge branch 'main' into ics29-fee-middleware
Apr 6, 2022
39d4c56
ics29: update with changes from main (#1221)
seantking Apr 6, 2022
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
964 changes: 684 additions & 280 deletions docs/ibc/proto-docs.md

Large diffs are not rendered by default.

39 changes: 39 additions & 0 deletions modules/apps/29-fee/client/cli/cli.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package cli

import (
"github.com/cosmos/cosmos-sdk/client"
"github.com/spf13/cobra"
)

// GetQueryCmd returns the query commands for 29-fee
func GetQueryCmd() *cobra.Command {
queryCmd := &cobra.Command{
Use: "ibc-fee",
Short: "", // TODO
DisableFlagParsing: true,
SuggestionsMinimumDistance: 2,
}

queryCmd.AddCommand(
// TODO
)

return queryCmd
}

// NewTxCmd returns the transaction commands for 29-fee
func NewTxCmd() *cobra.Command {
txCmd := &cobra.Command{
Use: "ibc-fee",
Short: "", // TODO
DisableFlagParsing: true,
SuggestionsMinimumDistance: 2,
RunE: client.ValidateCmd,
}

txCmd.AddCommand(
// TODO
)

return txCmd
}
3 changes: 3 additions & 0 deletions modules/apps/29-fee/client/cli/query.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package cli

// TODO
3 changes: 3 additions & 0 deletions modules/apps/29-fee/client/cli/tx.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package cli

// TODO
65 changes: 65 additions & 0 deletions modules/apps/29-fee/fee_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package fee_test

import (
"testing"

"github.com/stretchr/testify/suite"

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

"github.com/cosmos/ibc-go/modules/apps/29-fee/types"
transfertypes "github.com/cosmos/ibc-go/modules/apps/transfer/types"
clienttypes "github.com/cosmos/ibc-go/modules/core/02-client/types"
channeltypes "github.com/cosmos/ibc-go/modules/core/04-channel/types"
ibctesting "github.com/cosmos/ibc-go/testing"
)

type FeeTestSuite struct {
suite.Suite

coordinator *ibctesting.Coordinator

chainA *ibctesting.TestChain
chainB *ibctesting.TestChain

path *ibctesting.Path
}

func (suite *FeeTestSuite) SetupTest() {
suite.coordinator = ibctesting.NewCoordinator(suite.T(), 2)
suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(0))
suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(1))

path := ibctesting.NewPath(suite.chainA, suite.chainB)
feeTransferVersion := channeltypes.MergeChannelVersions(types.Version, transfertypes.Version)
path.EndpointA.ChannelConfig.Version = feeTransferVersion
path.EndpointB.ChannelConfig.Version = feeTransferVersion
path.EndpointA.ChannelConfig.PortID = transfertypes.PortID
path.EndpointB.ChannelConfig.PortID = transfertypes.PortID
suite.path = path
}

func TestIBCFeeTestSuite(t *testing.T) {
suite.Run(t, new(FeeTestSuite))
}

func (suite *FeeTestSuite) CreateICS20Packet(coin sdk.Coin) channeltypes.Packet {

fungibleTokenPacket := transfertypes.NewFungibleTokenPacketData(
coin.Denom,
sdk.NewInt(100).Uint64(),
suite.chainA.SenderAccount.GetAddress().String(),
suite.chainB.SenderAccount.GetAddress().String(),
)

return channeltypes.NewPacket(
fungibleTokenPacket.GetBytes(),
suite.chainA.SenderAccount.GetSequence(),
suite.path.EndpointA.ChannelConfig.PortID,
suite.path.EndpointA.ChannelID,
suite.path.EndpointB.ChannelConfig.PortID,
suite.path.EndpointB.ChannelID,
clienttypes.NewHeight(0, 100),
0,
)
}
275 changes: 275 additions & 0 deletions modules/apps/29-fee/ibc_module.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,275 @@
package fee

import (
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types"

"github.com/cosmos/ibc-go/modules/apps/29-fee/keeper"
"github.com/cosmos/ibc-go/modules/apps/29-fee/types"
channeltypes "github.com/cosmos/ibc-go/modules/core/04-channel/types"
porttypes "github.com/cosmos/ibc-go/modules/core/05-port/types"
"github.com/cosmos/ibc-go/modules/core/exported"
)

// IBCModule implements the ICS26 callbacks for the fee middleware given the fee keeper and the underlying application.
type IBCModule struct {
keeper keeper.Keeper
app porttypes.IBCModule
}

// NewIBCModule creates a new IBCModule given the keeper and underlying application
func NewIBCModule(k keeper.Keeper, app porttypes.IBCModule) IBCModule {
return IBCModule{
keeper: k,
app: app,
}
}

// OnChanOpenInit implements the IBCModule interface
func (im IBCModule) OnChanOpenInit(
ctx sdk.Context,
order channeltypes.Order,
connectionHops []string,
portID string,
channelID string,
chanCap *capabilitytypes.Capability,
counterparty channeltypes.Counterparty,
version string,
) error {
mwVersion, appVersion := channeltypes.SplitChannelVersion(version)
// Since it is valid for fee version to not be specified, the above middleware version may be for a middleware
// lower down in the stack. Thus, if it is not a fee version we pass the entire version string onto the underlying
// application.
// If an invalid fee version was passed, we expect the underlying application to fail on its version negotiation.
if mwVersion == types.Version {
im.keeper.SetFeeEnabled(ctx, portID, channelID)
} else {
// middleware version is not the expected version for this midddleware. Pass the full version string along,
// if it not valid version for any other lower middleware, an error will be returned by base application.
appVersion = version
}

// call underlying app's OnChanOpenInit callback with the appVersion
return im.app.OnChanOpenInit(ctx, order, connectionHops, portID, channelID,
chanCap, counterparty, appVersion)
}

// OnChanOpenTry implements the IBCModule interface
func (im IBCModule) OnChanOpenTry(
ctx sdk.Context,
order channeltypes.Order,
connectionHops []string,
portID,
channelID string,
chanCap *capabilitytypes.Capability,
counterparty channeltypes.Counterparty,
version,
counterpartyVersion string,
) error {
mwVersion, appVersion := channeltypes.SplitChannelVersion(version)
cpMwVersion, cpAppVersion := channeltypes.SplitChannelVersion(counterpartyVersion)

// Since it is valid for fee version to not be specified, the above middleware version may be for a middleware
// lower down in the stack. Thus, if it is not a fee version we pass the entire version string onto the underlying
// application.
// If an invalid fee version was passed, we expect the underlying application to fail on its version negotiation.
if mwVersion == types.Version || cpMwVersion == types.Version {
if cpMwVersion != mwVersion {
return sdkerrors.Wrapf(types.ErrInvalidVersion, "fee versions do not match. self version: %s, counterparty version: %s", mwVersion, cpMwVersion)
}

im.keeper.SetFeeEnabled(ctx, portID, channelID)
} else {
// middleware versions are not the expected version for this midddleware. Pass the full version strings along,
// if it not valid version for any other lower middleware, an error will be returned by base application.
appVersion = version
cpAppVersion = counterpartyVersion
}

// call underlying app's OnChanOpenTry callback with the app versions
return im.app.OnChanOpenTry(ctx, order, connectionHops, portID, channelID,
chanCap, counterparty, appVersion, cpAppVersion)
}

// OnChanOpenAck implements the IBCModule interface
func (im IBCModule) OnChanOpenAck(
ctx sdk.Context,
portID,
channelID string,
counterpartyVersion string,
) error {
// If handshake was initialized with fee enabled it must complete with fee enabled.
// If handshake was initialized with fee disabled it must complete with fee disabled.
cpAppVersion := counterpartyVersion
if im.keeper.IsFeeEnabled(ctx, portID, channelID) {
var cpFeeVersion string
cpFeeVersion, cpAppVersion = channeltypes.SplitChannelVersion(counterpartyVersion)

if cpFeeVersion != types.Version {
return sdkerrors.Wrapf(types.ErrInvalidVersion, "expected counterparty version: %s, got: %s", types.Version, cpFeeVersion)
}
}
// call underlying app's OnChanOpenAck callback with the counterparty app version.
return im.app.OnChanOpenAck(ctx, portID, channelID, cpAppVersion)
}

// OnChanOpenConfirm implements the IBCModule interface
func (im IBCModule) OnChanOpenConfirm(
ctx sdk.Context,
portID,
channelID string,
) error {
// call underlying app's OnChanOpenConfirm callback.
return im.app.OnChanOpenConfirm(ctx, portID, channelID)
}

// OnChanCloseInit implements the IBCModule interface
func (im IBCModule) OnChanCloseInit(
ctx sdk.Context,
portID,
channelID string,
) error {
// delete fee enabled on channel
// and refund any remaining fees escrowed on channel
im.keeper.DeleteFeeEnabled(ctx, portID, channelID)
err := im.keeper.RefundFeesOnChannel(ctx, portID, channelID)
// error should only be non-nil if there is a bug in the code
// that causes module account to have insufficient funds to refund
// all escrowed fees on the channel.
// Disable all channels to allow for coordinated fix to the issue
// and mitigate/reverse damage.
// NOTE: Underlying application's packets will still go through, but
// fee module will be disabled for all channels
if err != nil {
im.keeper.DisableAllChannels(ctx)

Choose a reason for hiding this comment

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

Is it safe to just disable the fee for all channels on one chain, without notifying the counterparty chains?

According to the logic of OnRecvPacket and OnAcknowledgementPacket, whether the fee module is enabled or not depends on the local state of the chain. So what would happen if one chain has fee enabled and the other chain has fee disabled, either via DisableAllChannels or some other corner cases? Would it cause the raw Acknowledgement to be serialized and deserialized in different ways, thereby causing the deserialization to fail?

}
return im.app.OnChanCloseInit(ctx, portID, channelID)
}

// OnChanCloseConfirm implements the IBCModule interface
func (im IBCModule) OnChanCloseConfirm(
ctx sdk.Context,
portID,
channelID string,
) error {
// delete fee enabled on channel
// and refund any remaining fees escrowed on channel
im.keeper.DeleteFeeEnabled(ctx, portID, channelID)
err := im.keeper.RefundFeesOnChannel(ctx, portID, channelID)
// error should only be non-nil if there is a bug in the code
// that causes module account to have insufficient funds to refund
// all escrowed fees on the channel.
// Disable all channels to allow for coordinated fix to the issue
// and mitigate/reverse damage.
// NOTE: Underlying application's packets will still go through, but
// fee module will be disabled for all channels
if err != nil {
im.keeper.DisableAllChannels(ctx)
}
return im.app.OnChanCloseConfirm(ctx, portID, channelID)
}

// OnRecvPacket implements the IBCModule interface.
// If fees are not enabled, this callback will default to the ibc-core packet callback
func (im IBCModule) OnRecvPacket(
ctx sdk.Context,
packet channeltypes.Packet,
relayer sdk.AccAddress,
) exported.Acknowledgement {
if !im.keeper.IsFeeEnabled(ctx, packet.DestinationPort, packet.DestinationChannel) {
return im.app.OnRecvPacket(ctx, packet, relayer)
}

ack := im.app.OnRecvPacket(ctx, packet, relayer)

forwardRelayer, found := im.keeper.GetCounterpartyAddress(ctx, relayer.String())
if !found {
forwardRelayer = ""
}

return types.IncentivizedAcknowledgement{
Result: ack.Acknowledgement(),
ForwardRelayerAddress: forwardRelayer,
}
}

// OnAcknowledgementPacket implements the IBCModule interface
// If fees are not enabled, this callback will default to the ibc-core packet callback
func (im IBCModule) OnAcknowledgementPacket(
ctx sdk.Context,
packet channeltypes.Packet,
acknowledgement []byte,
relayer sdk.AccAddress,
) error {
if !im.keeper.IsFeeEnabled(ctx, packet.SourcePort, packet.SourceChannel) {
return im.app.OnAcknowledgementPacket(ctx, packet, acknowledgement, relayer)
}

ack := new(types.IncentivizedAcknowledgement)
if err := types.ModuleCdc.UnmarshalJSON(acknowledgement, ack); err != nil {
return sdkerrors.Wrapf(err, "cannot unmarshal ICS-29 incentivized packet acknowledgement: %v", ack)

Choose a reason for hiding this comment

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

I'm not sure of the exact semantics of UnmarshalJSON, but given the prevalent practices in Go, would this unmarshalling succeed for any JSON result regardless of whether it contains the expected fields? If so, the error condition would not be triggered unless it contains non-JSON content.

I have been thinking that it may be more practical if the fee middleware can be enabled/disabled for each chain individually without requiring negotiation. Looking at all the protocol interaction, the only requirement for both sides to enable fee simultaneously is so the ack bytes containing the forward relayer addresss can be decoded correctly.

We should instead re-design this such that in case the decoding of the acknowledgement bytes fail, it would simply refund the escrowed receive fee and forward the raw ack to the inner module. Granted, this would also require UnmarshalJSON to indeed fail if the JSON raw content do not contain the forward relayer address and result fields.

}

packetId := channeltypes.NewPacketId(packet.SourceChannel, packet.SourcePort, packet.Sequence)
identifiedPacketFee, found := im.keeper.GetFeeInEscrow(ctx, packetId)

if !found {
// return underlying callback if no fee found for given packetID
return im.app.OnAcknowledgementPacket(ctx, packet, ack.Result, relayer)
}

// cache context before trying to distribute the fee
cacheCtx, writeFn := ctx.CacheContext()

forwardRelayer, _ := sdk.AccAddressFromBech32(ack.ForwardRelayerAddress)
refundAcc, _ := sdk.AccAddressFromBech32(identifiedPacketFee.RefundAddress)

err := im.keeper.DistributeFee(cacheCtx, refundAcc, forwardRelayer, relayer, packetId)

if err == nil {
// write the cache and then call underlying callback
writeFn()
// NOTE: The context returned by CacheContext() refers to a new EventManager, so it needs to explicitly set events to the original context.
ctx.EventManager().EmitEvents(cacheCtx.EventManager().Events())
}
// otherwise discard cache and call underlying callback
return im.app.OnAcknowledgementPacket(ctx, packet, ack.Result, relayer)
}

// OnTimeoutPacket implements the IBCModule interface
// If fees are not enabled, this callback will default to the ibc-core packet callback
func (im IBCModule) OnTimeoutPacket(
ctx sdk.Context,
packet channeltypes.Packet,
relayer sdk.AccAddress,
) error {
if !im.keeper.IsFeeEnabled(ctx, packet.SourcePort, packet.SourceChannel) {
return im.app.OnTimeoutPacket(ctx, packet, relayer)
}

packetId := channeltypes.NewPacketId(packet.SourceChannel, packet.SourcePort, packet.Sequence)

identifiedPacketFee, found := im.keeper.GetFeeInEscrow(ctx, packetId)

if !found {
// return underlying callback if fee not found for given packetID
return im.app.OnTimeoutPacket(ctx, packet, relayer)
}

// cache context before trying to distribute the fee
cacheCtx, writeFn := ctx.CacheContext()

refundAcc, _ := sdk.AccAddressFromBech32(identifiedPacketFee.RefundAddress)
err := im.keeper.DistributeFeeTimeout(cacheCtx, refundAcc, relayer, packetId)

if err == nil {
// write the cache and then call underlying callback
writeFn()
// NOTE: The context returned by CacheContext() refers to a new EventManager, so it needs to explicitly set events to the original context.
ctx.EventManager().EmitEvents(cacheCtx.EventManager().Events())
}

// otherwise discard cache and call underlying callback
return im.app.OnTimeoutPacket(ctx, packet, relayer)
}
Loading