github.com/okex/exchain@v1.8.0/libs/ibc-go/modules/apps/transfer/module.go (about)

     1  package transfer
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	"fmt"
     7  	"math"
     8  	"math/rand"
     9  
    10  	"github.com/gorilla/mux"
    11  	"github.com/grpc-ecosystem/grpc-gateway/runtime"
    12  	"github.com/spf13/cobra"
    13  
    14  	clientCtx "github.com/okex/exchain/libs/cosmos-sdk/client/context"
    15  	"github.com/okex/exchain/libs/cosmos-sdk/codec"
    16  	codectypes "github.com/okex/exchain/libs/cosmos-sdk/codec/types"
    17  	sdk "github.com/okex/exchain/libs/cosmos-sdk/types"
    18  	sdkerrors "github.com/okex/exchain/libs/cosmos-sdk/types/errors"
    19  	"github.com/okex/exchain/libs/cosmos-sdk/types/module"
    20  	"github.com/okex/exchain/libs/cosmos-sdk/types/upgrade"
    21  	capabilitytypes "github.com/okex/exchain/libs/cosmos-sdk/x/capability/types"
    22  	"github.com/okex/exchain/libs/cosmos-sdk/x/params"
    23  	simtypes "github.com/okex/exchain/libs/cosmos-sdk/x/simulation"
    24  	"github.com/okex/exchain/libs/ibc-go/modules/apps/transfer/client/cli"
    25  	"github.com/okex/exchain/libs/ibc-go/modules/apps/transfer/client/rest"
    26  	"github.com/okex/exchain/libs/ibc-go/modules/apps/transfer/keeper"
    27  	"github.com/okex/exchain/libs/ibc-go/modules/apps/transfer/simulation"
    28  	"github.com/okex/exchain/libs/ibc-go/modules/apps/transfer/types"
    29  	channeltypes "github.com/okex/exchain/libs/ibc-go/modules/core/04-channel/types"
    30  	porttypes "github.com/okex/exchain/libs/ibc-go/modules/core/05-port/types"
    31  	host "github.com/okex/exchain/libs/ibc-go/modules/core/24-host"
    32  	"github.com/okex/exchain/libs/ibc-go/modules/core/base"
    33  	ibcexported "github.com/okex/exchain/libs/ibc-go/modules/core/exported"
    34  	abci "github.com/okex/exchain/libs/tendermint/abci/types"
    35  )
    36  
    37  var (
    38  	_ module.AppModuleAdapter      = AppModule{}
    39  	_ porttypes.IBCModule          = AppModule{}
    40  	_ module.AppModuleBasicAdapter = AppModuleBasic{}
    41  )
    42  
    43  // AppModuleBasic is the IBC Transfer AppModuleBasic
    44  type AppModuleBasic struct{}
    45  
    46  // Name implements AppModuleBasic interface
    47  func (AppModuleBasic) Name() string {
    48  	return types.ModuleName
    49  }
    50  
    51  // RegisterLegacyAminoCodec implements AppModuleBasic interface
    52  //func (AppModuleBasic) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) {
    53  //	types.RegisterLegacyAminoCodec(cdc)
    54  //}
    55  
    56  func (AppModuleBasic) RegisterCodec(cdc *codec.Codec) {
    57  	types.RegisterLegacyAminoCodec(cdc)
    58  }
    59  
    60  // RegisterInterfaces registers module concrete types into protobuf Any.
    61  func (AppModuleBasic) RegisterInterfaces(registry codectypes.InterfaceRegistry) {
    62  	types.RegisterInterfaces(registry)
    63  }
    64  
    65  // DefaultGenesis returns default genesis state as raw bytes for the ibc
    66  // transfer module.
    67  func (AppModuleBasic) DefaultGenesis() json.RawMessage {
    68  	return nil
    69  }
    70  
    71  // ValidateGenesis performs genesis state validation for the mint module.
    72  func (AppModuleBasic) ValidateGenesis(bz json.RawMessage) error {
    73  	return nil
    74  }
    75  
    76  // RegisterRESTRoutes implements AppModuleBasic interface
    77  func (AppModuleBasic) RegisterRESTRoutes(ctx clientCtx.CLIContext, rtr *mux.Router) {}
    78  
    79  // RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for the ibc-transfer module.
    80  func (AppModuleBasic) RegisterGRPCGatewayRoutes(ctx clientCtx.CLIContext, mux *runtime.ServeMux) {
    81  	types.RegisterQueryHandlerClient(context.Background(), mux, types.NewQueryClient(ctx))
    82  
    83  }
    84  
    85  // GetTxCmd implements AppModuleBasic interface
    86  func (AppModuleBasic) GetTxCmd(cdc *codec.Codec) *cobra.Command {
    87  	return nil
    88  }
    89  
    90  func (am AppModuleBasic) GetTxCmdV2(cdc *codec.CodecProxy, reg codectypes.InterfaceRegistry) *cobra.Command {
    91  	return cli.NewTxCmd(cdc, reg)
    92  }
    93  
    94  // GetQueryCmd implements AppModuleBasic interface
    95  func (AppModuleBasic) GetQueryCmd(cdc *codec.Codec) *cobra.Command {
    96  	return nil
    97  }
    98  
    99  func (AppModuleBasic) GetQueryCmdV2(cdc *codec.CodecProxy, reg codectypes.InterfaceRegistry) *cobra.Command {
   100  	return cli.GetQueryCmd(cdc, reg)
   101  }
   102  
   103  func (am AppModuleBasic) RegisterRouterForGRPC(cliCtx clientCtx.CLIContext, r *mux.Router) {
   104  	rest.RegisterOriginRPCRoutersForGRPC(cliCtx, r)
   105  }
   106  
   107  // AppModule represents the AppModule for this module
   108  type AppModule struct {
   109  	AppModuleBasic
   110  	*base.BaseIBCUpgradeModule
   111  	keeper keeper.Keeper
   112  	m      *codec.CodecProxy
   113  }
   114  
   115  // NewAppModule creates a new 20-transfer module
   116  func NewAppModule(k keeper.Keeper, m *codec.CodecProxy) AppModule {
   117  	ret := AppModule{
   118  		keeper: k,
   119  	}
   120  	ret.BaseIBCUpgradeModule = base.NewBaseIBCUpgradeModule(ret.AppModuleBasic)
   121  	return ret
   122  }
   123  
   124  // RegisterInvariants implements the AppModule interface
   125  func (AppModule) RegisterInvariants(ir sdk.InvariantRegistry) {}
   126  
   127  // Route implements the AppModule interface
   128  func (am AppModule) Route() string {
   129  	return types.RouterKey
   130  }
   131  
   132  // QuerierRoute implements the AppModule interface
   133  func (AppModule) QuerierRoute() string {
   134  	return types.QuerierRoute
   135  }
   136  
   137  func (a AppModule) NewHandler() sdk.Handler {
   138  	return NewHandler(a.keeper)
   139  }
   140  
   141  // TODO
   142  func (am AppModule) NewQuerierHandler() sdk.Querier {
   143  	return NewQuerier(am.keeper)
   144  }
   145  
   146  // LegacyQuerierHandler implements the AppModule interface
   147  func (am AppModule) LegacyQuerierHandler(codec2 *codec.Codec) sdk.Querier {
   148  	return nil
   149  }
   150  
   151  // RegisterServices registers module services.
   152  func (am AppModule) RegisterServices(cfg module.Configurator) {
   153  	types.RegisterMsgServer(cfg.MsgServer(), am.keeper)
   154  	types.RegisterQueryServer(cfg.QueryServer(), am.keeper)
   155  }
   156  
   157  // InitGenesis performs genesis initialization for the ibc-transfer module. It returns
   158  // no validator updates.
   159  func (am AppModule) InitGenesis(ctx sdk.Context, data json.RawMessage) []abci.ValidatorUpdate {
   160  	return nil
   161  }
   162  
   163  func (am AppModule) initGenesis(ctx sdk.Context, data json.RawMessage) []abci.ValidatorUpdate {
   164  	var genesisState types.GenesisState
   165  	ModuleCdc.MustUnmarshalJSON(data, &genesisState)
   166  	am.keeper.InitGenesis(ctx, genesisState)
   167  	return []abci.ValidatorUpdate{}
   168  }
   169  
   170  // ExportGenesis returns the exported genesis state as raw bytes for the ibc-transfer
   171  // module.
   172  func (am AppModule) ExportGenesis(ctx sdk.Context) json.RawMessage {
   173  	return nil
   174  }
   175  func (am AppModule) exportGenesis(ctx sdk.Context) json.RawMessage {
   176  	gs := am.keeper.ExportGenesis(ctx)
   177  	return ModuleCdc.MustMarshalJSON(gs)
   178  }
   179  func lazeGenesis() json.RawMessage {
   180  	ret := types.DefaultGenesisState()
   181  	return ModuleCdc.MustMarshalJSON(ret)
   182  }
   183  
   184  // ConsensusVersion implements AppModule/ConsensusVersion.
   185  func (AppModule) ConsensusVersion() uint64 { return 1 }
   186  
   187  // BeginBlock implements the AppModule interface
   188  func (am AppModule) BeginBlock(_ sdk.Context, _ abci.RequestBeginBlock) {
   189  }
   190  
   191  // EndBlock implements the AppModule interface
   192  func (am AppModule) EndBlock(ctx sdk.Context, req abci.RequestEndBlock) []abci.ValidatorUpdate {
   193  	return []abci.ValidatorUpdate{}
   194  }
   195  
   196  // ____________________________________________________________________________
   197  
   198  // AppModuleSimulation functions
   199  
   200  // GenerateGenesisState creates a randomized GenState of the transfer module.
   201  func (AppModule) GenerateGenesisState(simState *module.SimulationState) {
   202  	simulation.RandomizedGenState(simState)
   203  }
   204  
   205  // ProposalContents doesn't return any content functions for governance proposals.
   206  func (AppModule) ProposalContents(_ module.SimulationState) []simtypes.WeightedProposalContent {
   207  	return nil
   208  }
   209  
   210  // RandomizedParams creates randomized ibc-transfer param changes for the simulator.
   211  func (AppModule) RandomizedParams(r *rand.Rand) []simtypes.ParamChange {
   212  	return simulation.ParamChanges(r)
   213  }
   214  
   215  // RegisterStoreDecoder registers a decoder for transfer module's types
   216  func (am AppModule) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) {
   217  	sdr[types.StoreKey] = simulation.NewDecodeStore(am.keeper)
   218  }
   219  
   220  // WeightedOperations returns the all the transfer module operations with their respective weights.
   221  func (am AppModule) WeightedOperations(_ module.SimulationState) []simtypes.WeightedOperation {
   222  	return nil
   223  }
   224  
   225  // ____________________________________________________________________________
   226  
   227  // ValidateTransferChannelParams does validation of a newly created transfer channel. A transfer
   228  // channel must be UNORDERED, use the correct port (by default 'transfer'), and use the current
   229  // supported version. Only 2^32 channels are allowed to be created.
   230  func ValidateTransferChannelParams(
   231  	ctx sdk.Context,
   232  	keeper keeper.Keeper,
   233  	order channeltypes.Order,
   234  	portID string,
   235  	channelID string,
   236  	version string,
   237  ) error {
   238  	if err := ValidateTransferChannelParamsV4(ctx, keeper, order, portID, channelID); nil != err {
   239  		return err
   240  	}
   241  
   242  	if version != types.Version {
   243  		return sdkerrors.Wrapf(types.ErrInvalidVersion, "got %s, expected %s", version, types.Version)
   244  	}
   245  	return nil
   246  }
   247  
   248  // ValidateTransferChannelParams does validation of a newly created transfer channel. A transfer
   249  // channel must be UNORDERED, use the correct port (by default 'transfer'), and use the current
   250  // supported version. Only 2^32 channels are allowed to be created.
   251  func ValidateTransferChannelParamsV4(
   252  	ctx sdk.Context,
   253  	keeper keeper.Keeper,
   254  	order channeltypes.Order,
   255  	portID string,
   256  	channelID string,
   257  ) error {
   258  	// NOTE: for escrow address security only 2^32 channels are allowed to be created
   259  	// Issue: https://github.com/cosmos/cosmos-sdk/issues/7737
   260  	channelSequence, err := channeltypes.ParseChannelSequence(channelID)
   261  	if err != nil {
   262  		return err
   263  	}
   264  	if channelSequence > uint64(math.MaxUint32) {
   265  		return sdkerrors.Wrapf(types.ErrMaxTransferChannels, "channel sequence %d is greater than max allowed transfer channels %d", channelSequence, uint64(math.MaxUint32))
   266  	}
   267  	if order != channeltypes.UNORDERED {
   268  		return sdkerrors.Wrapf(channeltypes.ErrInvalidChannelOrdering, "expected %s channel, got %s ", channeltypes.UNORDERED, order)
   269  	}
   270  
   271  	// Require portID is the portID transfer module is bound to
   272  	boundPort := keeper.GetPort(ctx)
   273  	if boundPort != portID {
   274  		return sdkerrors.Wrapf(porttypes.ErrInvalidPort, "invalid port: %s, expected %s", portID, boundPort)
   275  	}
   276  
   277  	return nil
   278  }
   279  
   280  // OnChanOpenInit implements the IBCModule interface
   281  func (am AppModule) OnChanOpenInit(
   282  	ctx sdk.Context,
   283  	order channeltypes.Order,
   284  	connectionHops []string,
   285  	portID string,
   286  	channelID string,
   287  	chanCap *capabilitytypes.Capability,
   288  	counterparty channeltypes.Counterparty,
   289  	version string,
   290  ) (string, error) {
   291  	if err := ValidateTransferChannelParams(ctx, am.keeper, order, portID, channelID, version); err != nil {
   292  		return "", err
   293  	}
   294  
   295  	// Claim channel capability passed back by IBC module
   296  	if err := am.keeper.ClaimCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)); err != nil {
   297  		return "", err
   298  	}
   299  
   300  	return version, nil
   301  }
   302  
   303  // OnChanOpenTry implements the IBCModule interface
   304  func (am AppModule) OnChanOpenTry(
   305  	ctx sdk.Context,
   306  	order channeltypes.Order,
   307  	connectionHops []string,
   308  	portID,
   309  	channelID string,
   310  	chanCap *capabilitytypes.Capability,
   311  	counterparty channeltypes.Counterparty,
   312  	version,
   313  	counterpartyVersion string,
   314  ) (string, error) {
   315  	if err := ValidateTransferChannelParams(ctx, am.keeper, order, portID, channelID, version); err != nil {
   316  		return "", err
   317  	}
   318  
   319  	if counterpartyVersion != types.Version {
   320  		return "", sdkerrors.Wrapf(types.ErrInvalidVersion, "invalid counterparty version: got: %s, expected %s", counterpartyVersion, types.Version)
   321  	}
   322  
   323  	// Module may have already claimed capability in OnChanOpenInit in the case of crossing hellos
   324  	// (ie chainA and chainB both call ChanOpenInit before one of them calls ChanOpenTry)
   325  	// If module can already authenticate the capability then module already owns it so we don't need to claim
   326  	// Otherwise, module does not have channel capability and we must claim it from IBC
   327  	if !am.keeper.AuthenticateCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)) {
   328  		// Only claim channel capability passed back by IBC module if we do not already own it
   329  		if err := am.keeper.ClaimCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)); err != nil {
   330  			return "", err
   331  		}
   332  	}
   333  
   334  	return types.Version, nil
   335  }
   336  
   337  // OnChanOpenAck implements the IBCModule interface
   338  func (im AppModule) OnChanOpenAck(
   339  	ctx sdk.Context,
   340  	portID,
   341  	channelID string,
   342  	_ string,
   343  	counterpartyVersion string,
   344  ) error {
   345  	if counterpartyVersion != types.Version {
   346  		return sdkerrors.Wrapf(types.ErrInvalidVersion, "invalid counterparty version: %s, expected %s", counterpartyVersion, types.Version)
   347  	}
   348  	return nil
   349  }
   350  
   351  // OnChanOpenConfirm implements the IBCModule interface
   352  func (am AppModule) OnChanOpenConfirm(
   353  	ctx sdk.Context,
   354  	portID,
   355  	channelID string,
   356  ) error {
   357  	return nil
   358  }
   359  
   360  // OnChanCloseInit implements the IBCModule interface
   361  func (am AppModule) OnChanCloseInit(
   362  	ctx sdk.Context,
   363  	portID,
   364  	channelID string,
   365  ) error {
   366  	// Disallow user-initiated channel closing for transfer channels
   367  	return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "user cannot close channel")
   368  }
   369  
   370  // OnChanCloseConfirm implements the IBCModule interface
   371  func (am AppModule) OnChanCloseConfirm(
   372  	ctx sdk.Context,
   373  	portID,
   374  	channelID string,
   375  ) error {
   376  	return nil
   377  }
   378  
   379  // OnRecvPacket implements the IBCModule interface. A successful acknowledgement
   380  // is returned if the packet data is succesfully decoded and the receive application
   381  // logic returns without error.
   382  func (am AppModule) OnRecvPacket(
   383  	ctx sdk.Context,
   384  	packet channeltypes.Packet,
   385  	relayer sdk.AccAddress,
   386  ) ibcexported.Acknowledgement {
   387  	ack := channeltypes.NewResultAcknowledgement([]byte{byte(1)})
   388  
   389  	var data types.FungibleTokenPacketData
   390  	if err := types.ModuleCdc.UnmarshalJSON(packet.GetData(), &data); err != nil {
   391  		ack = channeltypes.NewErrorAcknowledgement("cannot unmarshal ICS-20 transfer packet data")
   392  	}
   393  
   394  	// only attempt the application logic if the packet data
   395  	// was successfully decoded
   396  	if ack.Success() {
   397  		err := am.keeper.OnRecvPacket(ctx, packet, data)
   398  		if err != nil {
   399  			ack = channeltypes.NewErrorAcknowledgement(err.Error())
   400  		}
   401  	}
   402  
   403  	ctx.EventManager().EmitEvent(
   404  		sdk.NewEvent(
   405  			types.EventTypePacket,
   406  			sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName),
   407  			sdk.NewAttribute(types.AttributeKeyReceiver, data.Receiver),
   408  			sdk.NewAttribute(types.AttributeKeyDenom, data.Denom),
   409  			sdk.NewAttribute(types.AttributeKeyAmount, data.Amount),
   410  			sdk.NewAttribute(types.AttributeKeyAckSuccess, fmt.Sprintf("%t", ack.Success())),
   411  		),
   412  	)
   413  
   414  	// NOTE: acknowledgement will be written synchronously during IBC handler execution.
   415  	return ack
   416  }
   417  
   418  // OnAcknowledgementPacket implements the IBCModule interface
   419  func (am AppModule) OnAcknowledgementPacket(
   420  	ctx sdk.Context,
   421  	packet channeltypes.Packet,
   422  	acknowledgement []byte,
   423  	relayer sdk.AccAddress,
   424  ) error {
   425  	var ack channeltypes.Acknowledgement
   426  	if err := types.Marshal.GetProtocMarshal().UnmarshalJSON(acknowledgement, &ack); err != nil {
   427  		return sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "cannot unmarshal ICS-20 transfer packet acknowledgement: %v", err)
   428  	}
   429  	var data types.FungibleTokenPacketData
   430  	if err := types.ModuleCdc.UnmarshalJSON(packet.GetData(), &data); err != nil {
   431  		return sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "cannot unmarshal ICS-20 transfer packet data: %s", err.Error())
   432  	}
   433  
   434  	if err := am.keeper.OnAcknowledgementPacket(ctx, packet, data, ack); err != nil {
   435  		return err
   436  	}
   437  
   438  	ctx.EventManager().EmitEvent(
   439  		sdk.NewEvent(
   440  			types.EventTypePacket,
   441  			sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName),
   442  			sdk.NewAttribute(types.AttributeKeyReceiver, data.Receiver),
   443  			sdk.NewAttribute(types.AttributeKeyDenom, data.Denom),
   444  			sdk.NewAttribute(types.AttributeKeyAmount, data.Amount),
   445  			sdk.NewAttribute(types.AttributeKeyAck, ack.String()),
   446  		),
   447  	)
   448  
   449  	switch resp := ack.Response.(type) {
   450  	case *channeltypes.Acknowledgement_Result:
   451  		ctx.EventManager().EmitEvent(
   452  			sdk.NewEvent(
   453  				types.EventTypePacket,
   454  				sdk.NewAttribute(types.AttributeKeyAckSuccess, string(resp.Result)),
   455  			),
   456  		)
   457  	case *channeltypes.Acknowledgement_Error:
   458  		ctx.EventManager().EmitEvent(
   459  			sdk.NewEvent(
   460  				types.EventTypePacket,
   461  				sdk.NewAttribute(types.AttributeKeyAckError, resp.Error),
   462  			),
   463  		)
   464  	}
   465  
   466  	return nil
   467  }
   468  
   469  // OnTimeoutPacket implements the IBCModule interface
   470  func (am AppModule) OnTimeoutPacket(
   471  	ctx sdk.Context,
   472  	packet channeltypes.Packet,
   473  	relayer sdk.AccAddress,
   474  ) error {
   475  	var data types.FungibleTokenPacketData
   476  	if err := types.ModuleCdc.UnmarshalJSON(packet.GetData(), &data); err != nil {
   477  		return sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "cannot unmarshal ICS-20 transfer packet data: %s", err.Error())
   478  	}
   479  	// refund tokens
   480  	if err := am.keeper.OnTimeoutPacket(ctx, packet, data); err != nil {
   481  		return err
   482  	}
   483  
   484  	ctx.EventManager().EmitEvent(
   485  		sdk.NewEvent(
   486  			types.EventTypeTimeout,
   487  			sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName),
   488  			sdk.NewAttribute(types.AttributeKeyRefundReceiver, data.Sender),
   489  			sdk.NewAttribute(types.AttributeKeyRefundDenom, data.Denom),
   490  			sdk.NewAttribute(types.AttributeKeyRefundAmount, data.Amount),
   491  		),
   492  	)
   493  
   494  	return nil
   495  }
   496  
   497  // NegotiateAppVersion implements the IBCModule interface
   498  func (am AppModule) NegotiateAppVersion(
   499  	ctx sdk.Context,
   500  	order channeltypes.Order,
   501  	connectionID string,
   502  	portID string,
   503  	counterparty channeltypes.Counterparty,
   504  	proposedVersion string,
   505  ) (string, error) {
   506  	if proposedVersion != types.Version {
   507  		return "", sdkerrors.Wrapf(types.ErrInvalidVersion, "failed to negotiate app version: expected %s, got %s", types.Version, proposedVersion)
   508  	}
   509  
   510  	return types.Version, nil
   511  }
   512  
   513  func (am AppModule) RegisterTask() upgrade.HeightTask {
   514  	return upgrade.NewHeightTask(2, func(ctx sdk.Context) error {
   515  		if am.Sealed() {
   516  			return nil
   517  		}
   518  		data := lazeGenesis()
   519  		am.initGenesis(ctx, data)
   520  		return nil
   521  	})
   522  }
   523  
   524  func (am AppModule) RegisterParam() params.ParamSet {
   525  	return nil
   526  }