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 }