diff --git a/Makefile b/Makefile index 58e9f17b..21693b87 100644 --- a/Makefile +++ b/Makefile @@ -7,9 +7,9 @@ DOCKER_BUF := $(DOCKER) run --rm -v $(CURDIR):/workspace --workdir /workspace bu ### Protobuf ### ############################################################################### -protoVer=0.14.0 -protoImageName=ghcr.io/cosmos/proto-builder:$(protoVer) -protoImage=$(DOCKER) run --rm -v $(CURDIR):/workspace --workdir /workspace $(protoImageName) +protoVer=v0.7 +protoImageName=tendermintdev/sdk-proto-gen:$(protoVer) +protoImage=$(DOCKER) run --network host --rm -v $(CURDIR):/workspace --workdir /workspace $(protoImageName) proto-all: proto-format proto-lint proto-gen diff --git a/go.mod b/go.mod index 6b6fa774..9614e09b 100644 --- a/go.mod +++ b/go.mod @@ -8,6 +8,7 @@ require ( github.com/cosmos/cosmos-proto v1.0.0-alpha8 github.com/cosmos/cosmos-sdk v0.46.12 github.com/cosmos/gogoproto v1.4.11 + github.com/gogo/protobuf v1.3.3 github.com/golang/protobuf v1.5.3 github.com/gorilla/mux v1.8.0 github.com/grpc-ecosystem/grpc-gateway v1.16.0 @@ -71,7 +72,6 @@ require ( github.com/go-logfmt/logfmt v0.5.1 // indirect github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect github.com/gogo/gateway v1.1.0 // indirect - github.com/gogo/protobuf v1.3.3 // indirect github.com/golang/glog v1.1.0 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/snappy v0.0.4 // indirect diff --git a/test/simapp/app.go b/test/simapp/app.go index 99ffedea..cd084885 100644 --- a/test/simapp/app.go +++ b/test/simapp/app.go @@ -119,6 +119,8 @@ var ( distrclient.ProposalHandler, upgradeclient.LegacyProposalHandler, upgradeclient.LegacyCancelProposalHandler, + multistaking.AddMultiStakingProposalHandler, + multistaking.UpdateBondWeightProposalHandler, }, ), groupmodule.AppModuleBasic{}, @@ -300,7 +302,8 @@ func NewSimApp( govRouter.AddRoute(govtypes.RouterKey, govv1beta1.ProposalHandler). AddRoute(paramproposal.RouterKey, params.NewParamChangeProposalHandler(app.ParamsKeeper)). AddRoute(distrtypes.RouterKey, distr.NewCommunityPoolSpendProposalHandler(app.DistrKeeper)). - AddRoute(upgradetypes.RouterKey, upgrade.NewSoftwareUpgradeProposalHandler(app.UpgradeKeeper)) + AddRoute(upgradetypes.RouterKey, upgrade.NewSoftwareUpgradeProposalHandler(app.UpgradeKeeper)). + AddRoute(multistakingtypes.RouterKey, multistaking.NewMultiStakingProposalHandler(&app.MultiStakingKeeper)) govConfig := govtypes.DefaultConfig() /* diff --git a/x/multi-staking/client/cli/proposal.go b/x/multi-staking/client/cli/proposal.go new file mode 100644 index 00000000..80e4f2aa --- /dev/null +++ b/x/multi-staking/client/cli/proposal.go @@ -0,0 +1,85 @@ +package cli + +import ( + "github.com/realio-tech/multi-staking-module/x/multi-staking/types" + "github.com/spf13/cobra" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/tx" + sdk "github.com/cosmos/cosmos-sdk/types" + govv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" +) + +func NewCmdSubmitAddMultiStakingCoinProposal() *cobra.Command { + cmd := &cobra.Command{ + Use: "add-multistaking-coin [title] [description] [denom] [bond_weight] [deposit]", + Args: cobra.ExactArgs(5), + Short: "Submit an add multistaking coin proposal", + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + bondWeight, err := sdk.NewDecFromStr(args[3]) + if err != nil { + return err + } + from := clientCtx.GetFromAddress() + content := types.NewAddMultiStakingCoinProposal( + args[0], args[1], args[2], bondWeight, + ) + + deposit, err := sdk.ParseCoinsNormalized(args[4]) + if err != nil { + return err + } + + msg, err := govv1beta1.NewMsgSubmitProposal(content, deposit, from) + if err != nil { + return err + } + + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } + + return cmd +} + +func NewCmdUpdateBondWeightProposal() *cobra.Command { + cmd := &cobra.Command{ + Use: "update-bond-weight [title] [description] [denom] [bond_weight] [deposit]", + Args: cobra.ExactArgs(5), + Short: "Submit update bond weight for bond coin proposal", + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + bondWeight, err := sdk.NewDecFromStr(args[3]) + if err != nil { + return err + } + from := clientCtx.GetFromAddress() + content := types.NewUpdateBondWeightProposal( + args[0], args[1], args[2], bondWeight, + ) + + deposit, err := sdk.ParseCoinsNormalized(args[4]) + if err != nil { + return err + } + + msg, err := govv1beta1.NewMsgSubmitProposal(content, deposit, from) + if err != nil { + return err + } + + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } + + return cmd +} diff --git a/x/multi-staking/keeper/keeper_test.go b/x/multi-staking/keeper/keeper_test.go index 1c425494..d99a7f6f 100644 --- a/x/multi-staking/keeper/keeper_test.go +++ b/x/multi-staking/keeper/keeper_test.go @@ -16,6 +16,7 @@ import ( codectypes "github.com/cosmos/cosmos-sdk/codec/types" sdk "github.com/cosmos/cosmos-sdk/types" + govkeeper "github.com/cosmos/cosmos-sdk/x/gov/keeper" minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" ) @@ -26,6 +27,7 @@ type KeeperTestSuite struct { app *simapp.SimApp ctx sdk.Context msKeeper *multistakingkeeper.Keeper + govKeeper govkeeper.Keeper msgServer stakingtypes.MsgServer } @@ -34,7 +36,7 @@ func (suite *KeeperTestSuite) SetupTest() { ctx := app.BaseApp.NewContext(false, tmproto.Header{Height: app.LastBlockHeight() + 1}) multiStakingMsgServer := multistakingkeeper.NewMsgServerImpl(app.MultiStakingKeeper) - suite.app, suite.ctx, suite.msKeeper, suite.msgServer = app, ctx, &app.MultiStakingKeeper, multiStakingMsgServer + suite.app, suite.ctx, suite.msKeeper, suite.govKeeper, suite.msgServer = app, ctx, &app.MultiStakingKeeper, app.GovKeeper, multiStakingMsgServer } func TestKeeperTestSuite(t *testing.T) { diff --git a/x/multi-staking/keeper/proposal.go b/x/multi-staking/keeper/proposal.go new file mode 100644 index 00000000..4307376f --- /dev/null +++ b/x/multi-staking/keeper/proposal.go @@ -0,0 +1,62 @@ +package keeper + +import ( + "fmt" + + "github.com/realio-tech/multi-staking-module/x/multi-staking/types" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// AddMultiStakingCoinProposal handles the proposals to add a new bond token +func (k Keeper) AddMultiStakingCoinProposal( + ctx sdk.Context, + p *types.AddMultiStakingCoinProposal, +) error { + _, found := k.GetBondWeight(ctx, p.Denom) + if found { + return fmt.Errorf("Error MultiStakingCoin %s already exist", p.Denom) //nolint:stylecheck + } + + bondWeight := *p.BondWeight + if bondWeight.LTE(sdk.ZeroDec()) { + return fmt.Errorf("Error MultiStakingCoin BondWeight %s invalid", bondWeight) //nolint:stylecheck + } + + k.SetBondWeight(ctx, p.Denom, bondWeight) + + ctx.EventManager().EmitEvent( + sdk.NewEvent( + types.EventTypeAddMultiStakingCoin, + sdk.NewAttribute(types.AttributeKeyDenom, p.Denom), + sdk.NewAttribute(types.AttributeKeyBondWeight, p.BondWeight.String()), + ), + ) + return nil +} + +func (k Keeper) BondWeightProposal( + ctx sdk.Context, + p *types.UpdateBondWeightProposal, +) error { + _, found := k.GetBondWeight(ctx, p.Denom) + if !found { + return fmt.Errorf("Error MultiStakingCoin %s not found", p.Denom) //nolint:stylecheck + } + + bondWeight := *p.UpdatedBondWeight + if bondWeight.LTE(sdk.ZeroDec()) { + return fmt.Errorf("Error MultiStakingCoin BondWeight %s invalid", bondWeight) //nolint:stylecheck + } + + k.SetBondWeight(ctx, p.Denom, bondWeight) + + ctx.EventManager().EmitEvent( + sdk.NewEvent( + types.EventTypeAddMultiStakingCoin, + sdk.NewAttribute(types.AttributeKeyDenom, p.Denom), + sdk.NewAttribute(types.AttributeKeyBondWeight, p.UpdatedBondWeight.String()), + ), + ) + return nil +} diff --git a/x/multi-staking/keeper/proposal_test.go b/x/multi-staking/keeper/proposal_test.go new file mode 100644 index 00000000..a7a91f95 --- /dev/null +++ b/x/multi-staking/keeper/proposal_test.go @@ -0,0 +1,141 @@ +package keeper_test + +import ( + "github.com/realio-tech/multi-staking-module/x/multi-staking/types" + + sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + govv1types "github.com/cosmos/cosmos-sdk/x/gov/types/v1" +) + +func (suite *KeeperTestSuite) TestAddMultiStakingCoinProposal() { + bondWeight := sdk.NewDec(1) + + for _, tc := range []struct { + desc string + malleate func(p *types.AddMultiStakingCoinProposal) + proposal *types.AddMultiStakingCoinProposal + shouldErr bool + }{ + { + desc: "Success", + malleate: func(p *types.AddMultiStakingCoinProposal) { + _, found := suite.msKeeper.GetBondWeight(suite.ctx, p.Denom) + suite.Require().False(found) + }, + proposal: &types.AddMultiStakingCoinProposal{ + Title: "Add multistaking coin", + Description: "Add new multistaking coin", + Denom: "stake1", + BondWeight: &bondWeight, + }, + shouldErr: false, + }, + { + desc: "Error multistaking coin already exists", + malleate: func(p *types.AddMultiStakingCoinProposal) { + suite.msKeeper.SetBondWeight(suite.ctx, p.Denom, *p.BondWeight) + }, + proposal: &types.AddMultiStakingCoinProposal{ + Title: "Add multistaking coin", + Description: "Add new multistaking coin", + Denom: "stake2", + BondWeight: &bondWeight, + }, + shouldErr: true, + }, + } { + tc := tc + suite.Run(tc.desc, func() { + suite.SetupTest() + tc.malleate(tc.proposal) + + legacyProposal, err := govv1types.NewLegacyContent(tc.proposal, authtypes.NewModuleAddress(govtypes.ModuleName).String()) + suite.Require().NoError(err) + + if !tc.shouldErr { + // store proposal + _, err = suite.govKeeper.SubmitProposal(suite.ctx, []sdk.Msg{legacyProposal}, "") + suite.Require().NoError(err) + + // execute proposal + handler := suite.govKeeper.LegacyRouter().GetRoute(tc.proposal.ProposalRoute()) + err = handler(suite.ctx, tc.proposal) + suite.Require().NoError(err) + + _, found := suite.msKeeper.GetBondWeight(suite.ctx, tc.proposal.Denom) + suite.Require().True(found) + } else { + // store proposal + _, err = suite.govKeeper.SubmitProposal(suite.ctx, []sdk.Msg{legacyProposal}, "") + suite.Require().Error(err) + } + }) + } +} + +func (suite *KeeperTestSuite) TestUpdateBondWeightProposal() { + bondWeight := sdk.NewDec(1) + + for _, tc := range []struct { + desc string + malleate func(p *types.UpdateBondWeightProposal) + proposal *types.UpdateBondWeightProposal + shouldErr bool + }{ + { + desc: "Success", + malleate: func(p *types.UpdateBondWeightProposal) { + oldBondWeight := sdk.NewDec(2) + suite.msKeeper.SetBondWeight(suite.ctx, p.Denom, oldBondWeight) + }, + proposal: &types.UpdateBondWeightProposal{ + Title: "Add multistaking coin", + Description: "Add new multistaking coin", + Denom: "stake1", + UpdatedBondWeight: &bondWeight, + }, + shouldErr: false, + }, + { + desc: "Error multistaking coin not exists", + malleate: func(p *types.UpdateBondWeightProposal) {}, + proposal: &types.UpdateBondWeightProposal{ + Title: "Add multistaking coin", + Description: "Add new multistaking coin", + Denom: "stake2", + UpdatedBondWeight: &bondWeight, + }, + shouldErr: true, + }, + } { + tc := tc + suite.Run(tc.desc, func() { + suite.SetupTest() + tc.malleate(tc.proposal) + + legacyProposal, err := govv1types.NewLegacyContent(tc.proposal, authtypes.NewModuleAddress(govtypes.ModuleName).String()) + suite.Require().NoError(err) + + if !tc.shouldErr { + // store proposal + _, err = suite.govKeeper.SubmitProposal(suite.ctx, []sdk.Msg{legacyProposal}, "") + suite.Require().NoError(err) + + // execute proposal + handler := suite.govKeeper.LegacyRouter().GetRoute(tc.proposal.ProposalRoute()) + err = handler(suite.ctx, tc.proposal) + suite.Require().NoError(err) + + weight, found := suite.msKeeper.GetBondWeight(suite.ctx, tc.proposal.Denom) + suite.Require().True(found) + suite.Require().True(weight.Equal(bondWeight)) + } else { + // store proposal + _, err = suite.govKeeper.SubmitProposal(suite.ctx, []sdk.Msg{legacyProposal}, "") + suite.Require().Error(err) + } + }) + } +} diff --git a/x/multi-staking/module.go b/x/multi-staking/module.go index d98a8fe3..c8428c7e 100644 --- a/x/multi-staking/module.go +++ b/x/multi-staking/module.go @@ -39,10 +39,12 @@ func (AppModuleBasic) Name() string { // RegisterLegacyAminoCodec register module codec func (am AppModuleBasic) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { + multistakingtypes.RegisterLegacyAminoCodec(cdc) } // RegisterInterfaces registers the module interface func (am AppModuleBasic) RegisterInterfaces(reg cdctypes.InterfaceRegistry) { + multistakingtypes.RegisterInterfaces(reg) } // DefaultGenesis returns multi-staking module default genesis state. diff --git a/x/multi-staking/proposal_handler.go b/x/multi-staking/proposal_handler.go index 3be3a2d0..f5c9bc3a 100644 --- a/x/multi-staking/proposal_handler.go +++ b/x/multi-staking/proposal_handler.go @@ -1,6 +1,7 @@ package multistaking import ( + "github.com/realio-tech/multi-staking-module/x/multi-staking/client/cli" "github.com/realio-tech/multi-staking-module/x/multi-staking/keeper" "github.com/realio-tech/multi-staking-module/x/multi-staking/types" @@ -8,55 +9,25 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" errortypes "github.com/cosmos/cosmos-sdk/types/errors" + govclient "github.com/cosmos/cosmos-sdk/x/gov/client" govv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" ) +var ( + AddMultiStakingProposalHandler = govclient.NewProposalHandler(cli.NewCmdSubmitAddMultiStakingCoinProposal) + UpdateBondWeightProposalHandler = govclient.NewProposalHandler(cli.NewCmdUpdateBondWeightProposal) +) + // NewMultiStakingProposalHandler creates a governance handler to manage Mult-Staking proposals. func NewMultiStakingProposalHandler(k *keeper.Keeper) govv1beta1.Handler { return func(ctx sdk.Context, content govv1beta1.Content) error { switch c := content.(type) { case *types.AddMultiStakingCoinProposal: - return handleAddMultiStakingCoinProposal(ctx, k, c) + return k.AddMultiStakingCoinProposal(ctx, c) case *types.UpdateBondWeightProposal: - return handleChangeTokenWeightProposal(ctx, k, c) + return k.BondWeightProposal(ctx, c) default: return sdkerrors.Wrapf(errortypes.ErrUnknownRequest, "unrecognized %s proposal content type: %T", types.ModuleName, c) } } } - -// handleAddMultiStakingCoinProposal handles the proposals to add a new bond token -func handleAddMultiStakingCoinProposal( - ctx sdk.Context, - k *keeper.Keeper, - p *types.AddMultiStakingCoinProposal, -) error { - k.SetBondWeight(ctx, p.Denom, *p.BondWeight) - - ctx.EventManager().EmitEvent( - sdk.NewEvent( - types.EventTypeAddMultiStakingCoin, - sdk.NewAttribute(types.AttributeKeyDenom, p.Denom), - sdk.NewAttribute(types.AttributeKeyBondWeight, p.BondWeight.String()), - ), - ) - return nil -} - -// handleChangeTokenWeightProposal handles the proposals to change a bond tokens weight -func handleChangeTokenWeightProposal( - ctx sdk.Context, - k *keeper.Keeper, - p *types.UpdateBondWeightProposal, -) error { - k.SetBondWeight(ctx, p.Denom, *p.UpdatedBondWeight) - - ctx.EventManager().EmitEvent( - sdk.NewEvent( - types.EventTypeUpdateBondWeight, - sdk.NewAttribute(types.AttributeKeyDenom, p.Denom), - sdk.NewAttribute(types.AttributeKeyBondWeight, p.UpdatedBondWeight.String()), - ), - ) - return nil -} diff --git a/x/multi-staking/types/codec.go b/x/multi-staking/types/codec.go new file mode 100644 index 00000000..68ad5149 --- /dev/null +++ b/x/multi-staking/types/codec.go @@ -0,0 +1,41 @@ +package types + +import ( + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/codec/types" + cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + v1beta1types "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" +) + +var ( + amino = codec.NewLegacyAmino() + + // AminoCdc references the global x/relationships module codec. Note, the codec should + // ONLY be used in certain instances of tests and for JSON encoding as Amino is + // still used for that purpose. + // + // The actual codec used for serialization should be provided to x/relationships and + // defined at the application level. + AminoCdc = codec.NewAminoCodec(amino) +) + +func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { + cdc.RegisterConcrete(&AddMultiStakingCoinProposal{}, "multistaking/AddMultiStakingCoinProposal", nil) + cdc.RegisterConcrete(&UpdateBondWeightProposal{}, "multistaking/UpdateBondWeightProposal", nil) + // this line is used by starport scaffolding # 2 +} + +func RegisterInterfaces(registry types.InterfaceRegistry) { + registry.RegisterImplementations( + (*v1beta1types.Content)(nil), + &AddMultiStakingCoinProposal{}, + &UpdateBondWeightProposal{}, + ) +} + +func init() { + RegisterLegacyAminoCodec(amino) + cryptocodec.RegisterCrypto(amino) + sdk.RegisterLegacyAminoCodec(amino) +} diff --git a/x/multi-staking/types/genesis.pb.go b/x/multi-staking/types/genesis.pb.go index d7618f5e..46e49670 100644 --- a/x/multi-staking/types/genesis.pb.go +++ b/x/multi-staking/types/genesis.pb.go @@ -11,7 +11,7 @@ import ( _ "github.com/cosmos/cosmos-sdk/types/msgservice" types "github.com/cosmos/cosmos-sdk/x/staking/types" _ "github.com/cosmos/gogoproto/gogoproto" - proto "github.com/cosmos/gogoproto/proto" + proto "github.com/gogo/protobuf/proto" _ "google.golang.org/protobuf/types/known/timestamppb" io "io" math "math" diff --git a/x/multi-staking/types/multi_staking.pb.go b/x/multi-staking/types/multi_staking.pb.go index cb92b8d5..1dd28bbd 100644 --- a/x/multi-staking/types/multi_staking.pb.go +++ b/x/multi-staking/types/multi_staking.pb.go @@ -9,7 +9,7 @@ import ( _ "github.com/cosmos/cosmos-sdk/types" github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" _ "github.com/cosmos/gogoproto/gogoproto" - proto "github.com/cosmos/gogoproto/proto" + proto "github.com/gogo/protobuf/proto" _ "google.golang.org/protobuf/types/known/timestamppb" io "io" math "math" diff --git a/x/multi-staking/types/proposals.pb.go b/x/multi-staking/types/proposals.pb.go index d031ecea..caf219ed 100644 --- a/x/multi-staking/types/proposals.pb.go +++ b/x/multi-staking/types/proposals.pb.go @@ -8,7 +8,7 @@ import ( _ "github.com/cosmos/cosmos-proto" github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" _ "github.com/cosmos/gogoproto/gogoproto" - proto "github.com/cosmos/gogoproto/proto" + proto "github.com/gogo/protobuf/proto" io "io" math "math" math_bits "math/bits" diff --git a/x/multi-staking/types/query.pb.go b/x/multi-staking/types/query.pb.go index f69a5d09..16de7be1 100644 --- a/x/multi-staking/types/query.pb.go +++ b/x/multi-staking/types/query.pb.go @@ -10,8 +10,8 @@ import ( github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" query "github.com/cosmos/cosmos-sdk/types/query" _ "github.com/cosmos/gogoproto/gogoproto" - grpc1 "github.com/cosmos/gogoproto/grpc" - proto "github.com/cosmos/gogoproto/proto" + grpc1 "github.com/gogo/protobuf/grpc" + proto "github.com/gogo/protobuf/proto" _ "google.golang.org/genproto/googleapis/api/annotations" grpc "google.golang.org/grpc" codes "google.golang.org/grpc/codes"