package keeper import ( tmbytes "github.com/tendermint/tendermint/libs/bytes" "github.com/tendermint/tendermint/libs/log" "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/store/prefix" 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/applications/transfer/types" channeltypes "github.com/cosmos/cosmos-sdk/x/ibc/core/04-channel/types" host "github.com/cosmos/cosmos-sdk/x/ibc/core/24-host" paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" ) // Keeper defines the IBC fungible transfer keeper type Keeper struct { storeKey sdk.StoreKey cdc codec.BinaryMarshaler paramSpace paramtypes.Subspace 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.BinaryMarshaler, key sdk.StoreKey, paramSpace paramtypes.Subspace, 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") } // set KeyTable if it has not already been set if !paramSpace.HasKeyTable() { paramSpace = paramSpace.WithKeyTable(types.ParamKeyTable()) } return Keeper{ cdc: cdc, storeKey: key, paramSpace: paramSpace, 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", "x/"+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) } // ChanCloseInit defines a wrapper function for the channel Keeper's function // in order to expose it to the ICS20 transfer 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)) } // GetDenomTrace retreives the full identifiers trace and base denomination from the store. func (k Keeper) GetDenomTrace(ctx sdk.Context, denomTraceHash tmbytes.HexBytes) (types.DenomTrace, bool) { store := prefix.NewStore(ctx.KVStore(k.storeKey), types.DenomTraceKey) bz := store.Get(denomTraceHash) if bz == nil { return types.DenomTrace{}, false } denomTrace := k.MustUnmarshalDenomTrace(bz) return denomTrace, true } // HasDenomTrace checks if a the key with the given denomination trace hash exists on the store. func (k Keeper) HasDenomTrace(ctx sdk.Context, denomTraceHash tmbytes.HexBytes) bool { store := prefix.NewStore(ctx.KVStore(k.storeKey), types.DenomTraceKey) return store.Has(denomTraceHash) } // SetDenomTrace sets a new {trace hash -> denom trace} pair to the store. func (k Keeper) SetDenomTrace(ctx sdk.Context, denomTrace types.DenomTrace) { store := prefix.NewStore(ctx.KVStore(k.storeKey), types.DenomTraceKey) bz := k.MustMarshalDenomTrace(denomTrace) store.Set(denomTrace.Hash(), bz) } // GetAllDenomTraces returns the trace information for all the denominations. func (k Keeper) GetAllDenomTraces(ctx sdk.Context) types.Traces { traces := types.Traces{} k.IterateDenomTraces(ctx, func(denomTrace types.DenomTrace) bool { traces = append(traces, denomTrace) return false }) return traces.Sort() } // IterateDenomTraces iterates over the denomination traces in the store // and performs a callback function. func (k Keeper) IterateDenomTraces(ctx sdk.Context, cb func(denomTrace types.DenomTrace) bool) { store := ctx.KVStore(k.storeKey) iterator := sdk.KVStorePrefixIterator(store, types.DenomTraceKey) defer iterator.Close() for ; iterator.Valid(); iterator.Next() { denomTrace := k.MustUnmarshalDenomTrace(iterator.Value()) if cb(denomTrace) { break } } } // AuthenticateCapability wraps the scopedKeeper's AuthenticateCapability function func (k Keeper) AuthenticateCapability(ctx sdk.Context, cap *capabilitytypes.Capability, name string) bool { return k.scopedKeeper.AuthenticateCapability(ctx, cap, name) } // 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) }