package keeper import ( "fmt" "github.com/tendermint/tendermint/libs/log" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" capabilitykeeper "github.com/cosmos/cosmos-sdk/x/capability/keeper" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" "github.com/cosmos/cosmos-sdk/x/ibc-transfer/types" channelexported "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" channeltypes "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types" host "github.com/cosmos/cosmos-sdk/x/ibc/24-host" ) // Keeper defines the IBC fungible transfer keeper type Keeper struct { storeKey sdk.StoreKey cdc codec.Marshaler channelKeeper types.ChannelKeeper portKeeper types.PortKeeper authKeeper types.AccountKeeper bankKeeper types.BankKeeper scopedKeeper capabilitykeeper.ScopedKeeper } // NewKeeper creates a new IBC transfer Keeper instance func NewKeeper( cdc codec.Marshaler, key sdk.StoreKey, channelKeeper types.ChannelKeeper, portKeeper types.PortKeeper, authKeeper types.AccountKeeper, bankKeeper types.BankKeeper, scopedKeeper capabilitykeeper.ScopedKeeper, ) Keeper { // ensure ibc transfer module account is set if addr := authKeeper.GetModuleAddress(types.ModuleName); addr == nil { panic("the IBC transfer module account has not been set") } return Keeper{ storeKey: key, cdc: cdc, channelKeeper: channelKeeper, portKeeper: portKeeper, authKeeper: authKeeper, bankKeeper: bankKeeper, scopedKeeper: scopedKeeper, } } // Logger returns a module-specific logger. func (k Keeper) Logger(ctx sdk.Context) log.Logger { return ctx.Logger().With("module", fmt.Sprintf("x/%s-%s", host.ModuleName, types.ModuleName)) } // GetTransferAccount returns the ICS20 - transfers ModuleAccount func (k Keeper) GetTransferAccount(ctx sdk.Context) authtypes.ModuleAccountI { return k.authKeeper.GetModuleAccount(ctx, types.ModuleName) } // PacketExecuted defines a wrapper function for the channel Keeper's function // in order to expose it to the ICS20 transfer handler. // Keeper retreives channel capability and passes it into channel keeper for authentication func (k Keeper) PacketExecuted(ctx sdk.Context, packet channelexported.PacketI, acknowledgement []byte) error { chanCap, ok := k.scopedKeeper.GetCapability(ctx, host.ChannelCapabilityPath(packet.GetDestPort(), packet.GetDestChannel())) if !ok { return sdkerrors.Wrap(channeltypes.ErrChannelCapabilityNotFound, "channel capability could not be retrieved for packet") } return k.channelKeeper.PacketExecuted(ctx, chanCap, packet, acknowledgement) } // ChanCloseInit defines a wrapper function for the channel Keeper's function // in order to expose it to the ICS20 trasfer handler. func (k Keeper) ChanCloseInit(ctx sdk.Context, portID, channelID string) error { capName := host.ChannelCapabilityPath(portID, channelID) chanCap, ok := k.scopedKeeper.GetCapability(ctx, capName) if !ok { return sdkerrors.Wrapf(channeltypes.ErrChannelCapabilityNotFound, "could not retrieve channel capability at: %s", capName) } return k.channelKeeper.ChanCloseInit(ctx, portID, channelID, chanCap) } // IsBound checks if the transfer module is already bound to the desired port func (k Keeper) IsBound(ctx sdk.Context, portID string) bool { _, ok := k.scopedKeeper.GetCapability(ctx, host.PortPath(portID)) return ok } // BindPort defines a wrapper function for the ort Keeper's function in // order to expose it to module's InitGenesis function func (k Keeper) BindPort(ctx sdk.Context, portID string) error { cap := k.portKeeper.BindPort(ctx, portID) return k.ClaimCapability(ctx, cap, host.PortPath(portID)) } // GetPort returns the portID for the transfer module. Used in ExportGenesis func (k Keeper) GetPort(ctx sdk.Context) string { store := ctx.KVStore(k.storeKey) return string(store.Get(types.PortKey)) } // SetPort sets the portID for the transfer module. Used in InitGenesis func (k Keeper) SetPort(ctx sdk.Context, portID string) { store := ctx.KVStore(k.storeKey) store.Set(types.PortKey, []byte(portID)) } // ClaimCapability allows the transfer module that can claim a capability that IBC module // passes to it func (k Keeper) ClaimCapability(ctx sdk.Context, cap *capabilitytypes.Capability, name string) error { return k.scopedKeeper.ClaimCapability(ctx, cap, name) }