diff --git a/x/tokenfactory/keeper/grpc_query.go b/x/tokenfactory/keeper/grpc_query.go index 98070f8a2..fdae9d452 100644 --- a/x/tokenfactory/keeper/grpc_query.go +++ b/x/tokenfactory/keeper/grpc_query.go @@ -64,7 +64,7 @@ func (k Keeper) QueryDenomInfo( return resp, err } - bankMetadata, _ := k.bankKeeper.GetDenomMetaData(ctx, denom) + bankMetadata, _ := k.BankKeeper.GetDenomMetaData(ctx, denom) return &types.QueryDenomInfoResponse{ Admin: tfMetadata.Admin, Metadata: bankMetadata, diff --git a/x/tokenfactory/keeper/keeper.go b/x/tokenfactory/keeper/keeper.go index bc2908d16..e47b377b2 100644 --- a/x/tokenfactory/keeper/keeper.go +++ b/x/tokenfactory/keeper/keeper.go @@ -23,7 +23,7 @@ type Keeper struct { Store StoreAPI // interfaces with other modules - bankKeeper tftypes.BankKeeper + BankKeeper tftypes.BankKeeper accountKeeper tftypes.AccountKeeper communityPoolKeeper tftypes.CommunityPoolKeeper @@ -61,7 +61,7 @@ func NewKeeper( bankKeeper: bk, }, cdc: cdc, - bankKeeper: bk, + BankKeeper: bk, accountKeeper: ak, communityPoolKeeper: communityPoolKeeper, authority: authority, diff --git a/x/tokenfactory/keeper/msg_server.go b/x/tokenfactory/keeper/msg_server.go index 2ef592a2e..623fabaae 100644 --- a/x/tokenfactory/keeper/msg_server.go +++ b/x/tokenfactory/keeper/msg_server.go @@ -150,7 +150,7 @@ func (k Keeper) mint( } coins := sdk.NewCoins(coin) - err := k.bankKeeper.MintCoins(ctx, types.ModuleName, coins) + err := k.BankKeeper.MintCoins(ctx, types.ModuleName, coins) if err != nil { return err } @@ -160,12 +160,12 @@ func (k Keeper) mint( return err } - if k.bankKeeper.BlockedAddr(mintToAddr) { + if k.BankKeeper.BlockedAddr(mintToAddr) { return types.ErrBlockedAddress.Wrapf( "failed to mint to %s", mintToAddr) } - return k.bankKeeper.SendCoinsFromModuleToAccount( + return k.BankKeeper.SendCoinsFromModuleToAccount( ctx, types.ModuleName, mintToAddr, coins, ) } @@ -225,19 +225,19 @@ func (k Keeper) burn( return err } - if k.bankKeeper.BlockedAddr(burnFromAddr) { + if k.BankKeeper.BlockedAddr(burnFromAddr) { return types.ErrBlockedAddress.Wrapf( "failed to burn from %s", burnFromAddr) } coins := sdk.NewCoins(coin) - if err = k.bankKeeper.SendCoinsFromAccountToModule( + if err = k.BankKeeper.SendCoinsFromAccountToModule( ctx, burnFromAddr, types.ModuleName, coins, ); err != nil { return err } - return k.bankKeeper.BurnCoins(ctx, types.ModuleName, coins) + return k.BankKeeper.BurnCoins(ctx, types.ModuleName, coins) } // SetDenomMetadata: Message handler for the abci.Msg: MsgSetDenomMetadata @@ -265,7 +265,7 @@ func (k Keeper) SetDenomMetadata( ) } - k.bankKeeper.SetDenomMetaData(ctx, txMsg.Metadata) + k.BankKeeper.SetDenomMetaData(ctx, txMsg.Metadata) return &types.MsgSetDenomMetadataResponse{}, ctx.EventManager(). EmitTypedEvent(&types.EventSetDenomMetadata{ diff --git a/x/tokenfactory/module.go b/x/tokenfactory/module.go index 9cc05ec99..9ede4e140 100644 --- a/x/tokenfactory/module.go +++ b/x/tokenfactory/module.go @@ -177,16 +177,23 @@ func (am AppModule) ExportGenesis(ctx sdk.Context, cdc sdkcodec.JSONCodec) json. return cdc.MustMarshalJSON(gs) } +// AppModuleSimulation functions + // GenerateGenesisState implements module.AppModuleSimulation. func (AppModule) GenerateGenesisState(simState *module.SimulationState) { simulation.RandomizedGenState(simState) } +// ProposalMsgs returns msgs used for governance proposals for simulations. +func (AppModule) ProposalMsgs(simState module.SimulationState) []simtypes.WeightedProposalMsg { + return simulation.ProposalMsgs() +} + // RegisterStoreDecoder implements module.AppModuleSimulation. func (AppModule) RegisterStoreDecoder(sdk.StoreDecoderRegistry) { } // WeightedOperations implements module.AppModuleSimulation. -func (AppModule) WeightedOperations(simState module.SimulationState) []simtypes.WeightedOperation { - return []simtypes.WeightedOperation{} +func (am AppModule) WeightedOperations(simState module.SimulationState) []simtypes.WeightedOperation { + return simulation.WeightedOperations(&simState, am.keeper, am.ak) } diff --git a/x/tokenfactory/simulation/operations.go b/x/tokenfactory/simulation/operations.go new file mode 100644 index 000000000..69c8b4411 --- /dev/null +++ b/x/tokenfactory/simulation/operations.go @@ -0,0 +1,403 @@ +package simulation + +import ( + "math/rand" + + "github.com/NibiruChain/nibiru/x/tokenfactory/keeper" + "github.com/NibiruChain/nibiru/x/tokenfactory/types" + "github.com/cosmos/cosmos-sdk/baseapp" + "github.com/cosmos/cosmos-sdk/codec" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" + "github.com/cosmos/cosmos-sdk/x/auth/tx" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/cosmos/cosmos-sdk/x/simulation" +) + +// Simulation parameter constants +const ( + DefaultWeightMsgCreateDenom int = 100 + DefaultWeightMsgMint int = 100 + DefaultWeightMsgBurn int = 100 + DefaultWeightMsgChangeAdmin int = 100 + DefaultWeightMsgSetDenomMetadata int = 100 +) + +// Simulation operation weights constants +// +//nolint:gosec +const ( + OpWeightMsgCreateDenom = "op_weight_msg_create_denom" + OpWeightMsgChangeAdmin = "op_weight_msg_change_admin" + OpWeightMsgMint = "op_weight_msg_mint" + OpWeightMsgBurn = "op_weight_msg_burn" + OpWeightMsgSetDenomMetadata = "op_weight_msg_set_denom_metadata" +) + +type BankKeeper interface { + simulation.BankKeeper + GetAllBalances(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins + GetBalance(ctx sdk.Context, addr sdk.AccAddress, denom string) sdk.Coin +} + +// BuildOperationInput helper to build object +func BuildOperationInput( + r *rand.Rand, + app *baseapp.BaseApp, + ctx sdk.Context, + msg interface { + sdk.Msg + Type() string + }, + simAccount simtypes.Account, + ak types.AccountKeeper, + bk BankKeeper, + deposit sdk.Coins, +) simulation.OperationInput { + interfaceRegistry := codectypes.NewInterfaceRegistry() + txConfig := tx.NewTxConfig(codec.NewProtoCodec(interfaceRegistry), tx.DefaultSignModes) + return simulation.OperationInput{ + R: r, + App: app, + TxGen: txConfig, + Cdc: nil, + Msg: msg, + MsgType: msg.Type(), + Context: ctx, + SimAccount: simAccount, + AccountKeeper: ak, + Bankkeeper: bk, + ModuleName: types.ModuleName, + CoinsSpentInMsg: deposit, + } +} + +func WeightedOperations( + simstate *module.SimulationState, + tfKeeper keeper.Keeper, + ak types.AccountKeeper, +) simulation.WeightedOperations { + + var ( + weightMsgCreateDenom int + weightMsgChangeAdmin int + weightMsgMint int + weightMsgBurn int + weightMsgSetDenomMetadata int + ) + + simstate.AppParams.GetOrGenerate(simstate.Cdc, OpWeightMsgCreateDenom, &weightMsgCreateDenom, nil, + func(_ *rand.Rand) { + weightMsgCreateDenom = DefaultWeightMsgCreateDenom + }, + ) + + simstate.AppParams.GetOrGenerate(simstate.Cdc, OpWeightMsgChangeAdmin, &weightMsgChangeAdmin, nil, + func(_ *rand.Rand) { + weightMsgChangeAdmin = DefaultWeightMsgChangeAdmin + }, + ) + + simstate.AppParams.GetOrGenerate(simstate.Cdc, OpWeightMsgMint, &weightMsgMint, nil, + func(_ *rand.Rand) { + weightMsgMint = DefaultWeightMsgMint + }, + ) + + simstate.AppParams.GetOrGenerate(simstate.Cdc, OpWeightMsgBurn, &weightMsgBurn, nil, + func(_ *rand.Rand) { + weightMsgBurn = DefaultWeightMsgBurn + }, + ) + + simstate.AppParams.GetOrGenerate(simstate.Cdc, OpWeightMsgSetDenomMetadata, &weightMsgSetDenomMetadata, nil, + func(_ *rand.Rand) { + weightMsgSetDenomMetadata = DefaultWeightMsgSetDenomMetadata + }, + ) + + return simulation.WeightedOperations{ + simulation.NewWeightedOperation( + weightMsgCreateDenom, + SimulateMsgCreateDenom( + tfKeeper, + ak, + ), + ), + simulation.NewWeightedOperation( + weightMsgChangeAdmin, + SimulateMsgChangeAdmin( + tfKeeper, + ak, + DefaultSimulationDenomSelector, + ), + ), + simulation.NewWeightedOperation( + weightMsgMint, + SimulateMsgMint( + tfKeeper, + ak, + DefaultSimulationDenomSelector, + ), + ), + simulation.NewWeightedOperation( + weightMsgBurn, + SimulateMsgBurn( + tfKeeper, + ak, + DefaultSimulationDenomSelector, + ), + ), + simulation.NewWeightedOperation( + weightMsgSetDenomMetadata, + SimulateMsgSetDenomMetadata( + tfKeeper, + ak, + DefaultSimulationDenomSelector, + ), + ), + } +} + +type DenomSelector = func(*rand.Rand, sdk.Context, keeper.Keeper, string) (string, bool) + +func DefaultSimulationDenomSelector(r *rand.Rand, ctx sdk.Context, tfKeeper keeper.Keeper, creator string) (string, bool) { + denoms := tfKeeper.QueryDenoms(ctx, creator) + if len(denoms) == 0 { + return "", false + } + randPos := r.Intn(len(denoms)) + + return denoms[randPos], true +} + +// Simulate msg create denom +func SimulateMsgCreateDenom( + tfKeeper keeper.Keeper, + ak types.AccountKeeper, +) simtypes.Operation { + return func( + r *rand.Rand, + app *baseapp.BaseApp, + ctx sdk.Context, + accs []simtypes.Account, + chainID string, + ) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { + // Get sims account + simAccount, _ := simtypes.RandomAcc(r, accs) + + // TODO: Check if sims account enough create fee when CreateDenom Msg charge + + // Create msg create denom + msg := types.MsgCreateDenom{ + Sender: simAccount.Address.String(), + Subdenom: simtypes.RandStringOfLength(r, 10), + } + + txCtx := BuildOperationInput(r, app, ctx, &msg, simAccount, ak, tfKeeper.BankKeeper, nil) + return simulation.GenAndDeliverTxWithRandFees(txCtx) + } +} + +func SimulateMsgChangeAdmin( + tfKeeper keeper.Keeper, + ak types.AccountKeeper, + denomSelector DenomSelector, +) simtypes.Operation { + return func( + r *rand.Rand, + app *baseapp.BaseApp, + ctx sdk.Context, + accs []simtypes.Account, + chainID string, + ) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { + // Get create denom account + createdDenomAccount, _ := simtypes.RandomAcc(r, accs) + + // Get demon + denom, hasDenom := denomSelector(r, ctx, tfKeeper, createdDenomAccount.Address.String()) + if !hasDenom { + return simtypes.NoOpMsg(types.ModuleName, types.MsgChangeAdmin{}.Type(), "sim account have no denom created"), nil, nil + } + + // Get admin of the denom + authData, err := tfKeeper.Store.GetDenomAuthorityMetadata(ctx, denom) + if err != nil { + return simtypes.NoOpMsg(types.ModuleName, types.MsgChangeAdmin{}.Type(), "error retrieving authority metadata: " + err.Error()), nil, err + } + curAdminAccount, found := simtypes.FindAccount(accs, sdk.MustAccAddressFromBech32(authData.Admin)) + if !found { + return simtypes.NoOpMsg(types.ModuleName, types.MsgChangeAdmin{}.Type(), "admin account not found"), nil, nil + } + + // Rand new admin account + newAdmin, _ := simtypes.RandomAcc(r, accs) + if newAdmin.Address.String() == curAdminAccount.Address.String() { + return simtypes.NoOpMsg(types.ModuleName, types.MsgChangeAdmin{}.Type(), "new admin cannot be the same as current admin"), nil, nil + } + + // Create msg + msg := types.MsgChangeAdmin{ + Sender: curAdminAccount.Address.String(), + Denom: denom, + NewAdmin: newAdmin.Address.String(), + } + + txCtx := BuildOperationInput(r, app, ctx, &msg, curAdminAccount, ak, tfKeeper.BankKeeper, nil) + return simulation.GenAndDeliverTxWithRandFees(txCtx) + } +} + +// Simulate msg mint denom +func SimulateMsgMint( + tfKeeper keeper.Keeper, + ak types.AccountKeeper, + denomSelector DenomSelector, +) simtypes.Operation { + return func( + r *rand.Rand, + app *baseapp.BaseApp, + ctx sdk.Context, + accs []simtypes.Account, + chainID string, + ) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { + // Get create denom account + createdDenomAccount, _ := simtypes.RandomAcc(r, accs) + + // Get demon + denom, hasDenom := denomSelector(r, ctx, tfKeeper, createdDenomAccount.Address.String()) + if !hasDenom { + return simtypes.NoOpMsg(types.ModuleName, types.MsgMint{}.Type(), "sim account have no denom created"), nil, nil + } + + // Get admin of the denom + authData, err := tfKeeper.Store.GetDenomAuthorityMetadata(ctx, denom) + if err != nil { + return simtypes.NoOpMsg(types.ModuleName, types.MsgMint{}.Type(), "err authority metadata"), nil, err + } + adminAccount, found := simtypes.FindAccount(accs, sdk.MustAccAddressFromBech32(authData.Admin)) + if !found { + return simtypes.NoOpMsg(types.ModuleName, types.MsgMint{}.Type(), "admin account not found"), nil, nil + } + + // Rand mint amount + mintAmount, _ := simtypes.RandPositiveInt(r, sdk.NewIntFromUint64(100_000_000)) + + // Create msg mint + msg := types.MsgMint{ + Sender: adminAccount.Address.String(), + Coin: sdk.NewCoin(denom, mintAmount), + } + + txCtx := BuildOperationInput(r, app, ctx, &msg, adminAccount, ak, tfKeeper.BankKeeper, nil) + return simulation.GenAndDeliverTxWithRandFees(txCtx) + } +} + +func SimulateMsgBurn( + tfKeeper keeper.Keeper, + ak types.AccountKeeper, + denomSelector DenomSelector, +) simtypes.Operation { + return func( + r *rand.Rand, + app *baseapp.BaseApp, + ctx sdk.Context, + accs []simtypes.Account, + chainID string, + ) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { + // Get create denom account + createdDenomAccount, _ := simtypes.RandomAcc(r, accs) + + // Get demon + denom, hasDenom := denomSelector(r, ctx, tfKeeper, createdDenomAccount.Address.String()) + if !hasDenom { + return simtypes.NoOpMsg(types.ModuleName, types.MsgBurn{}.Type(), "sim account have no denom created"), nil, nil + } + + // Get admin of the denom + authData, err := tfKeeper.Store.GetDenomAuthorityMetadata(ctx, denom) + if err != nil { + return simtypes.NoOpMsg(types.ModuleName, types.MsgBurn{}.Type(), "err authority metadata"), nil, err + } + adminAccount, found := simtypes.FindAccount(accs, sdk.MustAccAddressFromBech32(authData.Admin)) + if !found { + return simtypes.NoOpMsg(types.ModuleName, types.MsgBurn{}.Type(), "admin account not found"), nil, nil + } + + // Check if admin account balance = 0 + accountBalance := tfKeeper.BankKeeper.GetBalance(ctx, adminAccount.Address, denom) + if accountBalance.Amount.LTE(sdk.ZeroInt()) { + return simtypes.NoOpMsg(types.ModuleName, types.MsgBurn{}.Type(), "sim account have no balance"), nil, nil + } + + // Rand burn amount + amount, _ := simtypes.RandPositiveInt(r, accountBalance.Amount) + burnAmount := sdk.NewCoin(denom, amount) + + // Create msg + msg := types.MsgBurn{ + Sender: adminAccount.Address.String(), + Coin: burnAmount, + BurnFrom: adminAccount.Address.String(), + } + + txCtx := BuildOperationInput(r, app, ctx, &msg, adminAccount, ak, tfKeeper.BankKeeper, sdk.NewCoins(burnAmount)) + return simulation.GenAndDeliverTxWithRandFees(txCtx) + } +} + +func SimulateMsgSetDenomMetadata( + tfKeeper keeper.Keeper, + ak types.AccountKeeper, + denomSelector DenomSelector, +) simtypes.Operation { + return func( + r *rand.Rand, + app *baseapp.BaseApp, + ctx sdk.Context, + accs []simtypes.Account, + chainID string, + ) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { + // Get create denom account + createdDenomAccount, _ := simtypes.RandomAcc(r, accs) + + // Get demon + denom, hasDenom := denomSelector(r, ctx, tfKeeper, createdDenomAccount.Address.String()) + if !hasDenom { + return simtypes.NoOpMsg(types.ModuleName, types.MsgSetDenomMetadata{}.Type(), "sim account have no denom created"), nil, nil + } + + // Get admin of the denom + authData, err := tfKeeper.Store.GetDenomAuthorityMetadata(ctx, denom) + if err != nil { + return simtypes.NoOpMsg(types.ModuleName, types.MsgSetDenomMetadata{}.Type(), "err authority metadata"), nil, err + } + adminAccount, found := simtypes.FindAccount(accs, sdk.MustAccAddressFromBech32(authData.Admin)) + if !found { + return simtypes.NoOpMsg(types.ModuleName, types.MsgSetDenomMetadata{}.Type(), "admin account not found"), nil, nil + } + + metadata := banktypes.Metadata{ + Description: simtypes.RandStringOfLength(r, 10), + DenomUnits: []*banktypes.DenomUnit{{ + Denom: denom, + Exponent: 0, + }}, + Base: denom, + Display: denom, + Name: simtypes.RandStringOfLength(r, 10), + Symbol: simtypes.RandStringOfLength(r, 10), + } + + msg := types.MsgSetDenomMetadata{ + Sender: adminAccount.Address.String(), + Metadata: metadata, + } + + txCtx := BuildOperationInput(r, app, ctx, &msg, adminAccount, ak, tfKeeper.BankKeeper, nil) + return simulation.GenAndDeliverTxWithRandFees(txCtx) + } +} diff --git a/x/tokenfactory/simulation/proposals.go b/x/tokenfactory/simulation/proposals.go new file mode 100644 index 000000000..5e27d64b0 --- /dev/null +++ b/x/tokenfactory/simulation/proposals.go @@ -0,0 +1,44 @@ +package simulation + +import ( + "math/rand" + + "github.com/NibiruChain/nibiru/x/tokenfactory/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/address" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" + "github.com/cosmos/cosmos-sdk/x/simulation" +) + +// Simulation operation weights constants +const ( + DefaultWeightMsgUpdateModuleParams int = 100 + + OpWeightMsgUpdateModuleParams = "op_weight_msg_update_module_params" //nolint:gosec +) + +// ProposalMsgs defines the module weighted proposals' contents +func ProposalMsgs() []simtypes.WeightedProposalMsg { + return []simtypes.WeightedProposalMsg{ + simulation.NewWeightedProposalMsg( + OpWeightMsgUpdateModuleParams, + DefaultWeightMsgUpdateModuleParams, + SimulateMsgUpdateParams, + ), + } +} + +// SimulateMsgUpdateParams returns a random MsgUpdateParams +func SimulateMsgUpdateParams(r *rand.Rand, _ sdk.Context, _ []simtypes.Account) sdk.Msg { + // use the default gov module account address as authority + var authority sdk.AccAddress = address.Module("gov") + + params := types.ModuleParams{ + DenomCreationGasConsume: r.Uint64(), + } + + return &types.MsgUpdateModuleParams{ + Authority: authority.String(), + Params: params, + } +} diff --git a/x/tokenfactory/types/tx_msgs.go b/x/tokenfactory/types/tx_msgs.go index fb87e9fa8..9d023c694 100644 --- a/x/tokenfactory/types/tx_msgs.go +++ b/x/tokenfactory/types/tx_msgs.go @@ -6,6 +6,14 @@ import ( "github.com/cosmos/cosmos-sdk/x/auth/migrations/legacytx" ) +const ( + MsgCreateDenomType = "create_denom" + MsgChangeAdminType = "change_admin" + MsgMintType = "mint" + MsgBurnType = "burn" + MsgSetDenomMetadataType = "set_denom_metadata" +) + // ---------------------------------------------------------------- // MsgCreateDenom @@ -44,7 +52,7 @@ func (m MsgCreateDenom) Route() string { return RouterKey } // Type: Impl legacytx.LegacyMsg. Returns a human-readable string for the message, // intended for utilization within tags -func (m MsgCreateDenom) Type() string { return "create_denom" } +func (m MsgCreateDenom) Type() string { return MsgCreateDenomType } // GetSignBytes: Get the canonical byte representation of the Msg. Impl // legacytx.LegacyMsg. @@ -88,7 +96,7 @@ func (m MsgChangeAdmin) Route() string { return RouterKey } // Type: Impl legacytx.LegacyMsg. Returns a human-readable string for the message, // intended for utilization within tags -func (m MsgChangeAdmin) Type() string { return "create_denom" } +func (m MsgChangeAdmin) Type() string { return MsgChangeAdminType } // GetSignBytes: Get the canonical byte representation of the Msg. Impl // legacytx.LegacyMsg. @@ -99,7 +107,10 @@ func (m MsgChangeAdmin) GetSignBytes() []byte { // ---------------------------------------------------------------- // MsgMint -var _ sdk.Msg = &MsgMint{} +var ( + _ sdk.Msg = &MsgMint{} + _ legacytx.LegacyMsg = &MsgMint{} +) // ValidateBasic performs stateless validation checks. Impl sdk.Msg. func (m MsgMint) ValidateBasic() error { @@ -132,6 +143,19 @@ func (m MsgMint) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{sender} } +// Route: Impl legacytx.LegacyMsg. The mesage route must be alphanumeric or empty. +func (m MsgMint) Route() string { return RouterKey } + +// Type: Impl legacytx.LegacyMsg. Returns a human-readable string for the message, +// intended for utilization within tags +func (m MsgMint) Type() string { return MsgMintType } + +// GetSignBytes: Get the canonical byte representation of the Msg. Impl +// legacytx.LegacyMsg. +func (m MsgMint) GetSignBytes() []byte { + return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(&m)) +} + func validateCoin(coin sdk.Coin) error { if !coin.IsValid() || coin.IsZero() { return sdkerrors.ErrInvalidCoins.Wrap(coin.String()) @@ -175,6 +199,19 @@ func (m MsgBurn) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{sender} } +// Route: Impl legacytx.LegacyMsg. The mesage route must be alphanumeric or empty. +func (m MsgBurn) Route() string { return RouterKey } + +// Type: Impl legacytx.LegacyMsg. Returns a human-readable string for the message, +// intended for utilization within tags +func (m MsgBurn) Type() string { return MsgBurnType } + +// GetSignBytes: Get the canonical byte representation of the Msg. Impl +// legacytx.LegacyMsg. +func (m MsgBurn) GetSignBytes() []byte { + return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(&m)) +} + // ---------------------------------------------------------------- // MsgUpdateModuleParams @@ -215,3 +252,16 @@ func (m MsgSetDenomMetadata) GetSigners() []sdk.AccAddress { sender, _ := sdk.AccAddressFromBech32(m.Sender) return []sdk.AccAddress{sender} } + +// Route: Impl legacytx.LegacyMsg. The mesage route must be alphanumeric or empty. +func (m MsgSetDenomMetadata) Route() string { return RouterKey } + +// Type: Impl legacytx.LegacyMsg. Returns a human-readable string for the message, +// intended for utilization within tags +func (m MsgSetDenomMetadata) Type() string { return MsgSetDenomMetadataType } + +// GetSignBytes: Get the canonical byte representation of the Msg. Impl +// legacytx.LegacyMsg. +func (m MsgSetDenomMetadata) GetSignBytes() []byte { + return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(&m)) +}