From e9cafc8681ec38bfc4000056071abe6827d27fc9 Mon Sep 17 00:00:00 2001 From: Thomas Nguy Date: Mon, 11 Oct 2021 13:59:07 +0900 Subject: [PATCH] support hooks in transfer app --- modules/apps/transfer/keeper/hooks.go | 52 ++++++++++++++++++++ modules/apps/transfer/keeper/keeper.go | 1 + modules/apps/transfer/keeper/relay.go | 24 +++++++-- modules/apps/transfer/types/hooks.go | 67 ++++++++++++++++++++++++++ 4 files changed, 141 insertions(+), 3 deletions(-) create mode 100644 modules/apps/transfer/keeper/hooks.go create mode 100644 modules/apps/transfer/types/hooks.go diff --git a/modules/apps/transfer/keeper/hooks.go b/modules/apps/transfer/keeper/hooks.go new file mode 100644 index 00000000000..beb46c7955b --- /dev/null +++ b/modules/apps/transfer/keeper/hooks.go @@ -0,0 +1,52 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/ibc-go/modules/apps/transfer/types" +) + +var _ types.TransferHooks = Keeper{} + +func (k Keeper) AfterSendTransfer( + ctx sdk.Context, + sourcePort, sourceChannel string, + token sdk.Coin, + sender sdk.AccAddress, + receiver string, + isSource bool) { + if k.hooks != nil { + k.hooks.AfterSendTransfer(ctx, sourcePort, sourceChannel, token, sender, receiver, isSource) + } +} + +func (k Keeper) AfterRecvTransfer( + ctx sdk.Context, + destPort, destChannel string, + token sdk.Coin, + receiver string, + isSource bool) { + if k.hooks != nil { + k.hooks.AfterRecvTransfer(ctx, destPort, destChannel, token, receiver, isSource) + } +} + +func (k Keeper) AfterRefundTransfer( + ctx sdk.Context, + sourcePort, sourceChannel string, + token sdk.Coin, + sender string, + isSource bool) { + if k.hooks != nil { + k.hooks.AfterRefundTransfer(ctx, sourcePort, sourceChannel, token, sender, isSource) + } +} + +func (k *Keeper) SetHooks(sh types.TransferHooks) *Keeper { + if k.hooks != nil { + panic("cannot set hooks twice") + } + + k.hooks = sh + + return k +} diff --git a/modules/apps/transfer/keeper/keeper.go b/modules/apps/transfer/keeper/keeper.go index 1d505debdb9..67c1fd6ce4f 100644 --- a/modules/apps/transfer/keeper/keeper.go +++ b/modules/apps/transfer/keeper/keeper.go @@ -26,6 +26,7 @@ type Keeper struct { authKeeper types.AccountKeeper bankKeeper types.BankKeeper scopedKeeper capabilitykeeper.ScopedKeeper + hooks types.TransferHooks } // NewKeeper creates a new IBC transfer Keeper instance diff --git a/modules/apps/transfer/keeper/relay.go b/modules/apps/transfer/keeper/relay.go index 161295d0b70..ca0270a63f9 100644 --- a/modules/apps/transfer/keeper/relay.go +++ b/modules/apps/transfer/keeper/relay.go @@ -110,7 +110,8 @@ func (k Keeper) SendTransfer( // chain inside the packet data. The receiving chain will perform denom // prefixing as necessary. - if types.SenderChainIsSource(sourcePort, sourceChannel, fullDenomPath) { + isSource := types.SenderChainIsSource(sourcePort, sourceChannel, fullDenomPath) + if isSource { labels = append(labels, telemetry.NewLabel(coretypes.LabelSource, "true")) // create the escrow address for the tokens @@ -176,6 +177,9 @@ func (k Keeper) SendTransfer( ) }() + if k.hooks != nil { + k.hooks.AfterSendTransfer(ctx, sourcePort, sourceChannel, token, sender, receiver, isSource) + } return nil } @@ -213,7 +217,8 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data t // chain would have prefixed with DestPort and DestChannel when originally // receiving this coin as seen in the "sender chain is the source" condition. - if types.ReceiverChainIsSource(packet.GetSourcePort(), packet.GetSourceChannel(), data.Denom) { + isSource := types.ReceiverChainIsSource(packet.GetSourcePort(), packet.GetSourceChannel(), data.Denom) + if isSource { // sender chain is not the source, unescrow tokens // remove prefix added by sender chain @@ -257,6 +262,9 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data t ) }() + if k.hooks != nil { + k.hooks.AfterRecvTransfer(ctx, packet.DestinationPort, packet.DestinationChannel, token, data.Receiver, isSource) + } return nil } @@ -316,6 +324,9 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data t ) }() + if k.hooks != nil { + k.hooks.AfterRecvTransfer(ctx, packet.DestinationPort, packet.DestinationChannel, voucher, data.Receiver, isSource) + } return nil } @@ -358,7 +369,8 @@ func (k Keeper) refundPacketToken(ctx sdk.Context, packet channeltypes.Packet, d return err } - if types.SenderChainIsSource(packet.GetSourcePort(), packet.GetSourceChannel(), data.Denom) { + isSource := types.SenderChainIsSource(packet.GetSourcePort(), packet.GetSourceChannel(), data.Denom) + if isSource { // unescrow tokens back to sender escrowAddress := types.GetEscrowAddress(packet.GetSourcePort(), packet.GetSourceChannel()) if err := k.bankKeeper.SendCoins(ctx, escrowAddress, sender, sdk.NewCoins(token)); err != nil { @@ -369,6 +381,9 @@ func (k Keeper) refundPacketToken(ctx sdk.Context, packet channeltypes.Packet, d return sdkerrors.Wrap(err, "unable to unescrow tokens, this may be caused by a malicious counterparty module or a bug: please open an issue on counterparty module") } + if k.hooks != nil { + k.hooks.AfterRefundTransfer(ctx, packet.SourcePort, packet.SourceChannel, token, data.Sender, isSource) + } return nil } @@ -383,6 +398,9 @@ func (k Keeper) refundPacketToken(ctx sdk.Context, packet channeltypes.Packet, d panic(fmt.Sprintf("unable to send coins from module to account despite previously minting coins to module account: %v", err)) } + if k.hooks != nil { + k.hooks.AfterRefundTransfer(ctx, packet.SourcePort, packet.SourceChannel, token, data.Sender, isSource) + } return nil } diff --git a/modules/apps/transfer/types/hooks.go b/modules/apps/transfer/types/hooks.go new file mode 100644 index 00000000000..6848cf111d2 --- /dev/null +++ b/modules/apps/transfer/types/hooks.go @@ -0,0 +1,67 @@ +package types + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +type TransferHooks interface { + AfterSendTransfer( + ctx sdk.Context, + sourcePort, sourceChannel string, + token sdk.Coin, + sender sdk.AccAddress, + receiver string, + isSource bool) + AfterRecvTransfer( + ctx sdk.Context, + destPort, destChannel string, + token sdk.Coin, + receiver string, + isSource bool) + AfterRefundTransfer( + ctx sdk.Context, + sourcePort, sourceChannel string, + token sdk.Coin, + sender string, + isSource bool) +} + +type MultiTransferHooks []TransferHooks + +func NewMultiTransferHooks(hooks ...TransferHooks) MultiTransferHooks { + return hooks +} + +func (mths MultiTransferHooks) AfterSendTransfer( + ctx sdk.Context, + sourcePort, sourceChannel string, + token sdk.Coin, + sender sdk.AccAddress, + receiver string, + isSource bool) { + for i := range mths { + mths[i].AfterSendTransfer(ctx, sourcePort, sourceChannel, token, sender, receiver, isSource) + } +} + +func (mths MultiTransferHooks) AfterRecvTransfer( + ctx sdk.Context, + destPort, destChannel string, + token sdk.Coin, + receiver string, + isSource bool) { + for i := range mths { + mths[i].AfterRecvTransfer(ctx, destPort, destChannel, token, receiver, isSource) + } +} + +func (mths MultiTransferHooks) AfterRefundTransfer( + ctx sdk.Context, + sourcePort, sourceChannel string, + token sdk.Coin, + sender string, + isSource bool) { + for i := range mths { + mths[i].AfterRefundTransfer(ctx, sourcePort, sourceChannel, token, sender, isSource) + } +} \ No newline at end of file