diff --git a/x/committee/alias.go b/x/committee/alias.go index cd23dfbf..d58482a1 100644 --- a/x/committee/alias.go +++ b/x/committee/alias.go @@ -8,27 +8,40 @@ import ( ) const ( - DefaultNextProposalID = types.DefaultNextProposalID - DefaultParamspace = types.DefaultParamspace - ModuleName = types.ModuleName - QuerierRoute = types.QuerierRoute - RouterKey = types.RouterKey - StoreKey = types.StoreKey - TypeMsgSubmitProposal = types.TypeMsgSubmitProposal - TypeMsgVote = types.TypeMsgVote + AttributeKeyProposalID = types.AttributeKeyProposalID + DefaultNextProposalID = types.DefaultNextProposalID + DefaultParamspace = types.DefaultParamspace + EventTypeSubmitProposal = types.EventTypeSubmitProposal + ModuleName = types.ModuleName + QuerierRoute = types.QuerierRoute + QueryCommittee = types.QueryCommittee + QueryCommittees = types.QueryCommittees + QueryProposal = types.QueryProposal + QueryProposals = types.QueryProposals + QueryTally = types.QueryTally + QueryVote = types.QueryVote + QueryVotes = types.QueryVotes + RouterKey = types.RouterKey + StoreKey = types.StoreKey + TypeMsgSubmitProposal = types.TypeMsgSubmitProposal + TypeMsgVote = types.TypeMsgVote ) var ( // function aliases - NewKeeper = keeper.NewKeeper - DefaultGenesisState = types.DefaultGenesisState - GetKeyFromID = types.GetKeyFromID - GetVoteKey = types.GetVoteKey - NewGenesisState = types.NewGenesisState - NewMsgSubmitProposal = types.NewMsgSubmitProposal - NewMsgVote = types.NewMsgVote - RegisterCodec = types.RegisterCodec - Uint64FromBytes = types.Uint64FromBytes + NewKeeper = keeper.NewKeeper + NewQuerier = keeper.NewQuerier + DefaultGenesisState = types.DefaultGenesisState + GetKeyFromID = types.GetKeyFromID + GetVoteKey = types.GetVoteKey + NewGenesisState = types.NewGenesisState + NewMsgSubmitProposal = types.NewMsgSubmitProposal + NewMsgVote = types.NewMsgVote + NewQueryCommitteeParams = types.NewQueryCommitteeParams + NewQueryProposalParams = types.NewQueryProposalParams + NewQueryVoteParams = types.NewQueryVoteParams + RegisterCodec = types.RegisterCodec + Uint64FromBytes = types.Uint64FromBytes // variable aliases CommitteeKeyPrefix = types.CommitteeKeyPrefix @@ -53,6 +66,9 @@ type ( Permission = types.Permission Proposal = types.Proposal PubProposal = types.PubProposal + QueryCommitteeParams = types.QueryCommitteeParams + QueryProposalParams = types.QueryProposalParams + QueryVoteParams = types.QueryVoteParams ShutdownCDPDepsitPermission = types.ShutdownCDPDepsitPermission Vote = types.Vote ) diff --git a/x/committee/client/cli/query.go b/x/committee/client/cli/query.go new file mode 100644 index 00000000..23deeb76 --- /dev/null +++ b/x/committee/client/cli/query.go @@ -0,0 +1,392 @@ +package cli + +import ( + "fmt" + "strconv" + + "github.com/spf13/cobra" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/codec" + + comclient "github.com/kava-labs/kava/x/committee/client" + "github.com/kava-labs/kava/x/committee/types" +) + +// GetQueryCmd returns the cli query commands for this module +func GetQueryCmd(queryRoute string, cdc *codec.Codec) *cobra.Command { + // Group gov queries under a subcommand + govQueryCmd := &cobra.Command{ + Use: types.ModuleName, + Short: "Querying commands for the governance module", + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + RunE: client.ValidateCmd, + } + + govQueryCmd.AddCommand(client.GetCommands( + //GetCmdQueryCommittee(queryRoute, cdc), + GetCmdQueryCommittees(queryRoute, cdc), + GetCmdQueryProposal(queryRoute, cdc), + GetCmdQueryProposals(queryRoute, cdc), + //GetCmdQueryVote(queryRoute, cdc), + GetCmdQueryVotes(queryRoute, cdc), + //GetCmdQueryParams(queryRoute, cdc), + GetCmdQueryProposer(queryRoute, cdc), + GetCmdQueryTally(queryRoute, cdc))...) + + return govQueryCmd +} + +// GetCmdQueryProposals implements a query proposals command. +func GetCmdQueryCommittees(queryRoute string, cdc *codec.Codec) *cobra.Command { + cmd := &cobra.Command{ + Use: "committees", + Short: "Query all committees", + Long: "", // TODO + RunE: func(cmd *cobra.Command, args []string) error { + cliCtx := context.NewCLIContext().WithCodec(cdc) + + // Query + res, _, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/%s", queryRoute, types.QueryCommittees), nil) + if err != nil { + return err + } + + // Decode and print result + committees := []types.Committee{} + if err = cdc.UnmarshalJSON(res, &committees); err != nil { + return err + } + return cliCtx.PrintOutput(committees) + }, + } + return cmd +} + +// GetCmdQueryProposal implements the query proposal command. +func GetCmdQueryProposal(queryRoute string, cdc *codec.Codec) *cobra.Command { + return &cobra.Command{ + Use: "proposal [proposal-id]", + Args: cobra.ExactArgs(1), + Short: "Query details of a single proposal", + // Long: strings.TrimSpace( + // fmt.Sprintf(`Query details for a proposal. You can find the + // proposal-id by running "%s query gov proposals". + + // Example: + // $ %s query gov proposal 1 + // `, + // version.ClientName, version.ClientName, + // ), + // ), + RunE: func(cmd *cobra.Command, args []string) error { + cliCtx := context.NewCLIContext().WithCodec(cdc) + + // Prepare params for querier + proposalID, err := strconv.ParseUint(args[0], 10, 64) + if err != nil { + return fmt.Errorf("proposal-id %s not a valid uint", args[0]) + } + bz, err := cdc.MarshalJSON(types.NewQueryCommitteeParams(proposalID)) + if err != nil { + return err + } + + // Query + //res, err := gcutils.QueryProposalByID(proposalID, cliCtx, queryRoute) + res, _, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/%s", queryRoute, types.QueryProposal), bz) + if err != nil { + return err + } + + // Decode and print results + var proposal types.Proposal + cdc.MustUnmarshalJSON(res, &proposal) + return cliCtx.PrintOutput(proposal) + }, + } +} + +// GetCmdQueryProposals implements a query proposals command. +func GetCmdQueryProposals(queryRoute string, cdc *codec.Codec) *cobra.Command { + cmd := &cobra.Command{ + Use: "proposals [committee-id]", + Short: "Query proposals by committee.", + Args: cobra.ExactArgs(1), + // Long: strings.TrimSpace( + // fmt.Sprintf(`Query for a all proposals. You can filter the returns with the following flags. + + // Example: + // $ %s query gov proposals --depositor cosmos1skjwj5whet0lpe65qaq4rpq03hjxlwd9nf39lk + // $ %s query gov proposals --voter cosmos1skjwj5whet0lpe65qaq4rpq03hjxlwd9nf39lk + // $ %s query gov proposals --status (DepositPeriod|VotingPeriod|Passed|Rejected) + // `, + // version.ClientName, version.ClientName, version.ClientName, + // ), + // ), + RunE: func(cmd *cobra.Command, args []string) error { + cliCtx := context.NewCLIContext().WithCodec(cdc) + + // Prepare params for querier + committeeID, err := strconv.ParseUint(args[0], 10, 64) + if err != nil { + return fmt.Errorf("committee-id %s not a valid uint", args[0]) + } + bz, err := cdc.MarshalJSON(types.NewQueryCommitteeParams(committeeID)) + if err != nil { + return err + } + + // Query + res, _, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/proposals", queryRoute), bz) + if err != nil { + return err + } + + // Decode and print results + proposals := []types.Proposal{} // using empty (not nil) slice so json returns [] instead of null when there's no data // TODO check + err = cdc.UnmarshalJSON(res, &proposals) + if err != nil { + return err + } + return cliCtx.PrintOutput(proposals) + }, + } + return cmd +} + +// // Command to Get a Proposal Information +// // GetCmdQueryVote implements the query proposal vote command. +// func GetCmdQueryVote(queryRoute string, cdc *codec.Codec) *cobra.Command { +// return &cobra.Command{ +// Use: "vote [proposal-id] [voter-addr]", +// Args: cobra.ExactArgs(2), +// Short: "Query details of a single vote", +// Long: strings.TrimSpace( +// fmt.Sprintf(`Query details for a single vote on a proposal given its identifier. + +// Example: +// $ %s query gov vote 1 cosmos1skjwj5whet0lpe65qaq4rpq03hjxlwd9nf39lk +// `, +// version.ClientName, +// ), +// ), +// RunE: func(cmd *cobra.Command, args []string) error { +// cliCtx := context.NewCLIContext().WithCodec(cdc) + +// // validate that the proposal id is a uint +// proposalID, err := strconv.ParseUint(args[0], 10, 64) +// if err != nil { +// return fmt.Errorf("proposal-id %s not a valid int, please input a valid proposal-id", args[0]) +// } + +// // check to see if the proposal is in the store +// _, err = gcutils.QueryProposalByID(proposalID, cliCtx, queryRoute) +// if err != nil { +// return fmt.Errorf("failed to fetch proposal-id %d: %s", proposalID, err) +// } + +// voterAddr, err := sdk.AccAddressFromBech32(args[1]) +// if err != nil { +// return err +// } + +// params := types.NewQueryVoteParams(proposalID, voterAddr) +// bz, err := cdc.MarshalJSON(params) +// if err != nil { +// return err +// } + +// res, _, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/vote", queryRoute), bz) +// if err != nil { +// return err +// } + +// var vote types.Vote + +// // XXX: Allow the decoding to potentially fail as the vote may have been +// // pruned from state. If so, decoding will fail and so we need to check the +// // Empty() case. Consider updating Vote JSON decoding to not fail when empty. +// _ = cdc.UnmarshalJSON(res, &vote) + +// if vote.Empty() { +// res, err = gcutils.QueryVoteByTxQuery(cliCtx, params) +// if err != nil { +// return err +// } + +// if err := cdc.UnmarshalJSON(res, &vote); err != nil { +// return err +// } +// } + +// return cliCtx.PrintOutput(vote) +// }, +// } +// } + +// GetCmdQueryVotes implements the command to query for proposal votes. +func GetCmdQueryVotes(queryRoute string, cdc *codec.Codec) *cobra.Command { + return &cobra.Command{ + Use: "votes [proposal-id]", + Args: cobra.ExactArgs(1), + Short: "Query votes on a proposal", + // Long: strings.TrimSpace( + // fmt.Sprintf(`Query vote details for a single proposal by its identifier. + + // Example: + // $ %s query gov votes 1 + // `, + // version.ClientName, + // ), + // ), + RunE: func(cmd *cobra.Command, args []string) error { + cliCtx := context.NewCLIContext().WithCodec(cdc) + + // Prepare params for querier + proposalID, err := strconv.ParseUint(args[0], 10, 64) + if err != nil { + return fmt.Errorf("proposal-id %s not a valid int", args[0]) + } + bz, err := cdc.MarshalJSON(types.NewQueryProposalParams(proposalID)) + if err != nil { + return err + } + + // Query + res, _, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/%s", queryRoute, types.QueryVotes), bz) + if err != nil { + return err + } + + // Decode and print results + votes := []types.Vote{} // using empty (not nil) slice so json returns [] instead of null when there's no data // TODO check + err = cdc.UnmarshalJSON(res, &votes) + if err != nil { + return err + } + return cliCtx.PrintOutput(votes) + }, + } +} + +// GetCmdQueryTally implements the command to query for proposal tally result. +func GetCmdQueryTally(queryRoute string, cdc *codec.Codec) *cobra.Command { + return &cobra.Command{ + Use: "tally [proposal-id]", + Args: cobra.ExactArgs(1), + Short: "Get the tally of a proposal vote", + // Long: strings.TrimSpace( + // fmt.Sprintf(`Query tally of votes on a proposal. You can find + // the proposal-id by running "%s query gov proposals". + + // Example: + // $ %s query gov tally 1 + // `, + // version.ClientName, version.ClientName, + // ), + // ), + RunE: func(cmd *cobra.Command, args []string) error { + cliCtx := context.NewCLIContext().WithCodec(cdc) + + // Prepare params for querier + proposalID, err := strconv.ParseUint(args[0], 10, 64) + if err != nil { + return fmt.Errorf("proposal-id %s not a valid int", args[0]) + } + bz, err := cdc.MarshalJSON(types.NewQueryProposalParams(proposalID)) + if err != nil { + return err + } + + // Query + res, _, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/tally", queryRoute), bz) + if err != nil { + return err + } + + // Decode and print results + var tally bool + cdc.MustUnmarshalJSON(res, &tally) // TODO must or normal, what's the difference on the cli? + return cliCtx.PrintOutput(tally) + }, + } +} + +// // GetCmdQueryProposal implements the query proposal command. +// func GetCmdQueryParams(queryRoute string, cdc *codec.Codec) *cobra.Command { +// return &cobra.Command{ +// Use: "params", +// Short: "Query the parameters of the governance process", +// Long: strings.TrimSpace( +// fmt.Sprintf(`Query the all the parameters for the governance process. + +// Example: +// $ %s query gov params +// `, +// version.ClientName, +// ), +// ), +// Args: cobra.NoArgs, +// RunE: func(cmd *cobra.Command, args []string) error { +// cliCtx := context.NewCLIContext().WithCodec(cdc) +// tp, _, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/params/tallying", queryRoute), nil) +// if err != nil { +// return err +// } +// dp, _, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/params/deposit", queryRoute), nil) +// if err != nil { +// return err +// } +// vp, _, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/params/voting", queryRoute), nil) +// if err != nil { +// return err +// } + +// var tallyParams types.TallyParams +// cdc.MustUnmarshalJSON(tp, &tallyParams) +// var depositParams types.DepositParams +// cdc.MustUnmarshalJSON(dp, &depositParams) +// var votingParams types.VotingParams +// cdc.MustUnmarshalJSON(vp, &votingParams) + +// return cliCtx.PrintOutput(types.NewParams(votingParams, tallyParams, depositParams)) +// }, +// } +// } + +// GetCmdQueryProposer implements the query proposer command. +func GetCmdQueryProposer(queryRoute string, cdc *codec.Codec) *cobra.Command { + return &cobra.Command{ + Use: "proposer [proposal-id]", + Args: cobra.ExactArgs(1), + Short: "Query the proposer of a governance proposal", + // Long: strings.TrimSpace( + // fmt.Sprintf(`Query which address proposed a proposal with a given ID. + + // Example: + // $ %s query gov proposer 1 + // `, + // version.ClientName, + // ), + // ), + RunE: func(cmd *cobra.Command, args []string) error { + cliCtx := context.NewCLIContext().WithCodec(cdc) + + // validate that the proposalID is a uint + proposalID, err := strconv.ParseUint(args[0], 10, 64) + if err != nil { + return fmt.Errorf("proposal-id %s is not a valid uint", args[0]) + } + + prop, err := comclient.QueryProposer(cliCtx, proposalID) + if err != nil { + return err + } + + return cliCtx.PrintOutput(prop) + }, + } +} diff --git a/x/committee/client/cli/tx.go b/x/committee/client/cli/tx.go new file mode 100644 index 00000000..46674426 --- /dev/null +++ b/x/committee/client/cli/tx.go @@ -0,0 +1,177 @@ +package cli + +import ( + "fmt" + "io/ioutil" + "strconv" + + "github.com/spf13/cobra" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth" + "github.com/cosmos/cosmos-sdk/x/auth/client/utils" + + "github.com/kava-labs/kava/x/committee/types" +) + +// // Proposal flags +// const ( +// FlagTitle = "title" +// FlagDescription = "description" +// flagProposalType = "type" +// FlagDeposit = "deposit" +// flagVoter = "voter" +// flagDepositor = "depositor" +// flagStatus = "status" +// flagNumLimit = "limit" +// FlagProposal = "proposal" +// ) + +// type proposal struct { +// Title string +// Description string +// Type string +// Deposit string +// } + +// // ProposalFlags defines the core required fields of a proposal. It is used to +// // verify that these values are not provided in conjunction with a JSON proposal +// // file. +// var ProposalFlags = []string{ +// FlagTitle, +// FlagDescription, +// flagProposalType, +// FlagDeposit, +// } + +// GetTxCmd returns the transaction commands for this module +// governance ModuleClient is slightly different from other ModuleClients in that +// it contains a slice of "proposal" child commands. These commands are respective +// to proposal type handlers that are implemented in other modules but are mounted +// under the governance CLI (eg. parameter change proposals). +func GetTxCmd(storeKey string, cdc *codec.Codec /*, pcmds []*cobra.Command*/) *cobra.Command { // TODO why is storeKey here? + txCmd := &cobra.Command{ + Use: types.ModuleName, + Short: "committee governance transactions subcommands", + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + RunE: client.ValidateCmd, + } + + cmdSubmitProp := GetCmdSubmitProposal(cdc) + // for _, pcmd := range pcmds { + // cmdSubmitProp.AddCommand(client.PostCommands(pcmd)[0]) + // } + + txCmd.AddCommand(client.PostCommands( + GetCmdVote(cdc), + cmdSubmitProp, + )...) + + return txCmd +} + +// // GetCmdSubmitProposal is the root command on which commands for submitting proposals are registered. +// func GetCmdSubmitProposal(cdc *codec.Codec) *cobra.Command { +// cmd := &cobra.Command{ +// Use: "submit-proposal [committee-id]", +// Short: "Submit a governance proposal to a particular committee.", // TODO +// DisableFlagParsing: true, +// SuggestionsMinimumDistance: 2, +// RunE: client.ValidateCmd, +// } + +// return cmd +// } + +// GetCmdSubmitProposal +func GetCmdSubmitProposal(cdc *codec.Codec) *cobra.Command { + cmd := &cobra.Command{ + Use: "submit-proposal [committee-id] [proposal-file]", + Short: "Submit a governance proposal to a particular committee.", + Long: "", // TODO + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) + cliCtx := context.NewCLIContext().WithCodec(cdc) + + // Get proposing address + proposer := cliCtx.GetFromAddress() + + // Get committee ID + committeeID, err := strconv.ParseUint(args[0], 10, 64) + if err != nil { + return fmt.Errorf("committee-id %s not a valid int", args[0]) + } + + // Get the proposal + bz, err := ioutil.ReadFile(args[1]) + if err != nil { + return err + } + var pubProposal types.PubProposal + if err := cdc.UnmarshalJSON(bz, &pubProposal); err != nil { + return err + } + if err = pubProposal.ValidateBasic(); err != nil { + return err + } + + // Build message and run basic validation + msg := types.NewMsgSubmitProposal(pubProposal, proposer, committeeID) + err = msg.ValidateBasic() + if err != nil { + return err + } + + // Sign and broadcast message + return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) + }, + } + + return cmd +} + +// GetCmdVote implements creating a new vote command. +func GetCmdVote(cdc *codec.Codec) *cobra.Command { + return &cobra.Command{ + Use: "vote [proposal-id]", + Args: cobra.ExactArgs(2), + Short: "Vote for an active proposal", // TODO + // Long: strings.TrimSpace( + // fmt.Sprintf(`Submit a vote for an active proposal. You can + // find the proposal-id by running "%s query gov proposals". + + // Example: + // $ %s tx gov vote 1 yes --from mykey + // `, + // version.ClientName, version.ClientName, + // ), + // ), + RunE: func(cmd *cobra.Command, args []string) error { + txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) + cliCtx := context.NewCLIContext().WithCodec(cdc) + + // Get voting address + from := cliCtx.GetFromAddress() + + // validate that the proposal id is a uint + proposalID, err := strconv.ParseUint(args[0], 10, 64) + if err != nil { + return fmt.Errorf("proposal-id %s not a valid int, please input a valid proposal-id", args[0]) + } + + // Build vote message and run basic validation + msg := types.NewMsgVote(from, proposalID) + err = msg.ValidateBasic() + if err != nil { + return err + } + + return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) + }, + } +} diff --git a/x/committee/client/query_proposer.go b/x/committee/client/query_proposer.go new file mode 100644 index 00000000..29e61552 --- /dev/null +++ b/x/committee/client/query_proposer.go @@ -0,0 +1,58 @@ +package client + +import ( + "fmt" + + "github.com/cosmos/cosmos-sdk/client/context" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth/client/utils" + + "github.com/kava-labs/kava/x/committee/types" +) + +const ( + defaultPage = 1 + defaultLimit = 30 // should be consistent with tendermint/tendermint/rpc/core/pipe.go:19 // TODO what is this? +) + +// Proposer contains metadata of a governance proposal used for querying a proposer. +type Proposer struct { + ProposalID uint64 `json:"proposal_id" yaml:"proposal_id"` + Proposer string `json:"proposer" yaml:"proposer"` +} + +// NewProposer returns a new Proposer given id and proposer +func NewProposer(proposalID uint64, proposer string) Proposer { + return Proposer{proposalID, proposer} +} + +func (p Proposer) String() string { + return fmt.Sprintf("Proposal with ID %d was proposed by %s", p.ProposalID, p.Proposer) +} + +// QueryProposer will query for a proposer of a governance proposal by ID. +func QueryProposer(cliCtx context.CLIContext, proposalID uint64) (Proposer, error) { + events := []string{ + fmt.Sprintf("%s.%s='%s'", sdk.EventTypeMessage, sdk.AttributeKeyAction, types.TypeMsgSubmitProposal), + fmt.Sprintf("%s.%s='%s'", types.EventTypeSubmitProposal, types.AttributeKeyProposalID, []byte(fmt.Sprintf("%d", proposalID))), + } + + // NOTE: SearchTxs is used to facilitate the txs query which does not currently + // support configurable pagination. + searchResult, err := utils.QueryTxsByEvents(cliCtx, events, defaultPage, defaultLimit) + if err != nil { + return Proposer{}, err + } + + for _, info := range searchResult.Txs { + for _, msg := range info.Tx.GetMsgs() { + // there should only be a single proposal under the given conditions + if msg.Type() == types.TypeMsgSubmitProposal { + subMsg := msg.(types.MsgSubmitProposal) + return NewProposer(proposalID, subMsg.Proposer.String()), nil + } + } + } + + return Proposer{}, fmt.Errorf("failed to find the proposer for proposalID %d", proposalID) +} diff --git a/x/committee/keeper/proposal.go b/x/committee/keeper/proposal.go index 0bd65072..7500a91d 100644 --- a/x/committee/keeper/proposal.go +++ b/x/committee/keeper/proposal.go @@ -1,6 +1,8 @@ package keeper import ( + "fmt" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/kava-labs/kava/x/committee/types" @@ -28,7 +30,18 @@ func (k Keeper) SubmitProposal(ctx sdk.Context, proposer sdk.AccAddress, committ // Get a new ID and store the proposal deadline := ctx.BlockTime().Add(types.MaxProposalDuration) - return k.StoreNewProposal(ctx, pubProposal, committeeID, deadline) + proposalID, err := k.StoreNewProposal(ctx, pubProposal, committeeID, deadline) + if err != nil { + return 0, err + } + + ctx.EventManager().EmitEvent( + sdk.NewEvent( + types.EventTypeSubmitProposal, + sdk.NewAttribute(types.AttributeKeyProposalID, fmt.Sprintf("%d", proposalID)), + ), + ) + return proposalID, nil } func (k Keeper) AddVote(ctx sdk.Context, proposalID uint64, voter sdk.AccAddress) sdk.Error { diff --git a/x/committee/keeper/querier.go b/x/committee/keeper/querier.go index e0fa5439..44dfa877 100644 --- a/x/committee/keeper/querier.go +++ b/x/committee/keeper/querier.go @@ -40,7 +40,7 @@ func NewQuerier(keeper Keeper) sdk.Querier { // ---------- Committees ---------- -func queryCommittees(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) ([]byte, sdk.Error) { +func queryCommittees(ctx sdk.Context, path []string, _ abci.RequestQuery, keeper Keeper) ([]byte, sdk.Error) { committees := []types.Committee{} keeper.IterateCommittees(ctx, func(com types.Committee) bool { diff --git a/x/committee/module.go b/x/committee/module.go index 97752b05..a1164407 100644 --- a/x/committee/module.go +++ b/x/committee/module.go @@ -11,6 +11,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" abci "github.com/tendermint/tendermint/abci/types" + + "github.com/kava-labs/kava/x/committee/client/cli" ) var ( @@ -54,14 +56,12 @@ func (AppModuleBasic) RegisterRESTRoutes(ctx context.CLIContext, rtr *mux.Router // GetTxCmd returns the root tx command for the module. func (AppModuleBasic) GetTxCmd(cdc *codec.Codec) *cobra.Command { - //return cli.GetTxCmd(cdc) - return nil + return cli.GetTxCmd(StoreKey, cdc) } -// GetQueryCmd returns the root query command for the auction module. +// GetQueryCmd returns the root query command for the module. func (AppModuleBasic) GetQueryCmd(cdc *codec.Codec) *cobra.Command { - //return cli.GetQueryCmd(StoreKey, cdc) - return nil + return cli.GetQueryCmd(StoreKey, cdc) } //____________________________________________________________________________ @@ -118,8 +118,7 @@ func (AppModule) Route() string { // NewHandler module handler func (am AppModule) NewHandler() sdk.Handler { - //return NewHandler(am.keeper) - return nil + return NewHandler(am.keeper) } // QuerierRoute module querier route name @@ -129,8 +128,7 @@ func (AppModule) QuerierRoute() string { // NewQuerierHandler module querier func (am AppModule) NewQuerierHandler() sdk.Querier { - // return NewQuerier(am.keeper) - return nil + return NewQuerier(am.keeper) } // InitGenesis module init-genesis diff --git a/x/committee/types/events.go b/x/committee/types/events.go new file mode 100644 index 00000000..5037f606 --- /dev/null +++ b/x/committee/types/events.go @@ -0,0 +1,19 @@ +package types + +// Module event types +const ( + EventTypeSubmitProposal = "submit_proposal" + // EventTypeProposalVote = "proposal_vote" + // EventTypeInactiveProposal = "inactive_proposal" + // EventTypeActiveProposal = "active_proposal" + + // AttributeKeyProposalResult = "proposal_result" + // AttributeKeyOption = "option" + AttributeKeyProposalID = "proposal_id" + // AttributeKeyVotingPeriodStart = "voting_period_start" + // AttributeValueCategory = "governance" + // AttributeValueProposalDropped = "proposal_dropped" // didn't meet min deposit + // AttributeValueProposalPassed = "proposal_passed" // met vote quorum + // AttributeValueProposalRejected = "proposal_rejected" // didn't meet vote quorum + // AttributeValueProposalFailed = "proposal_failed" // error on proposal handler +) diff --git a/x/committee/types/msg.go b/x/committee/types/msg.go index e262260b..dd34e727 100644 --- a/x/committee/types/msg.go +++ b/x/committee/types/msg.go @@ -5,7 +5,7 @@ import ( ) const ( - TypeMsgSubmitProposal = "submit_proposal" + TypeMsgSubmitProposal = "submit_proposal" // TODO these are the same as the gov module, will there be collisions? TypeMsgVote = "vote" )