Skip to content

Commit

Permalink
feat: ics 29 packet callbacks (#357)
Browse files Browse the repository at this point in the history
  • Loading branch information
charleenfei authored Dec 21, 2021
1 parent 885fb9a commit a737132
Show file tree
Hide file tree
Showing 11 changed files with 474 additions and 39 deletions.
24 changes: 24 additions & 0 deletions modules/apps/29-fee/fee_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@ import (

"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"
)
Expand Down Expand Up @@ -39,3 +42,24 @@ func (suite *FeeTestSuite) SetupTest() {
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,
)
}
87 changes: 80 additions & 7 deletions modules/apps/29-fee/ibc_module.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
"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"
ibcexported "github.com/cosmos/ibc-go/modules/core/exported"
"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.
Expand Down Expand Up @@ -171,32 +171,105 @@ func (im IBCModule) OnChanCloseConfirm(
}

// 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,
) ibcexported.Acknowledgement {
// TODO: Implement fee specific logic if fee is enabled for the given channel
return im.app.OnRecvPacket(ctx, packet, relayer)
) 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 {
// TODO: Implement fee specific logic if fee is enabled for the given channel
return im.app.OnAcknowledgementPacket(ctx, packet, acknowledgement, relayer)
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)
}

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 {
// TODO: Implement fee specific logic if fee is enabled for the given channel
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

0 comments on commit a737132

Please sign in to comment.