Address gov cli ux issues and add additional input validation for better errors (#2938)
* Fix governance cli ux issues and add additional transaction validation
This commit is contained in:
parent
13e78166ee
commit
886bd35670
|
@ -359,7 +359,7 @@ func TestGaiaCLISubmitProposal(t *testing.T) {
|
|||
fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli query account %s %v", fooAddr, flags))
|
||||
require.Equal(t, int64(45), fooAcc.GetCoins().AmountOf(stakeTypes.DefaultBondDenom).Int64())
|
||||
|
||||
proposal1 := executeGetProposal(t, fmt.Sprintf("gaiacli query gov proposal --proposal-id=1 --output=json %v", flags))
|
||||
proposal1 := executeGetProposal(t, fmt.Sprintf("gaiacli query gov proposal 1 --output=json %v", flags))
|
||||
require.Equal(t, uint64(1), proposal1.GetProposalID())
|
||||
require.Equal(t, gov.StatusDepositPeriod, proposal1.GetStatus())
|
||||
|
||||
|
@ -367,14 +367,12 @@ func TestGaiaCLISubmitProposal(t *testing.T) {
|
|||
require.Equal(t, " 1 - Test", proposalsQuery)
|
||||
|
||||
deposit := executeGetDeposit(t,
|
||||
fmt.Sprintf("gaiacli query gov deposit --proposal-id=1 --depositor=%s --output=json %v",
|
||||
fmt.Sprintf("gaiacli query gov deposit 1 %s --output=json %v",
|
||||
fooAddr, flags))
|
||||
require.Equal(t, int64(5), deposit.Amount.AmountOf(stakeTypes.DefaultBondDenom).Int64())
|
||||
|
||||
depositStr := fmt.Sprintf("gaiacli tx gov deposit %v", flags)
|
||||
depositStr := fmt.Sprintf("gaiacli tx gov deposit 1 %s %v", fmt.Sprintf("10%s", stakeTypes.DefaultBondDenom), flags)
|
||||
depositStr += fmt.Sprintf(" --from=%s", "foo")
|
||||
depositStr += fmt.Sprintf(" --deposit=%s", fmt.Sprintf("10%s", stakeTypes.DefaultBondDenom))
|
||||
depositStr += fmt.Sprintf(" --proposal-id=%s", "1")
|
||||
|
||||
// Test generate only
|
||||
success, stdout, stderr = executeWriteRetStdStreams(t, depositStr+" --generate-only", app.DefaultKeyPass)
|
||||
|
@ -391,12 +389,12 @@ func TestGaiaCLISubmitProposal(t *testing.T) {
|
|||
|
||||
// test query deposit
|
||||
deposits := executeGetDeposits(t,
|
||||
fmt.Sprintf("gaiacli query gov deposits --proposal-id=1 --output=json %v", flags))
|
||||
fmt.Sprintf("gaiacli query gov deposits 1 --output=json %v", flags))
|
||||
require.Len(t, deposits, 1)
|
||||
require.Equal(t, int64(15), deposits[0].Amount.AmountOf(stakeTypes.DefaultBondDenom).Int64())
|
||||
|
||||
deposit = executeGetDeposit(t,
|
||||
fmt.Sprintf("gaiacli query gov deposit --proposal-id=1 --depositor=%s --output=json %v",
|
||||
fmt.Sprintf("gaiacli query gov deposit 1 %s --output=json %v",
|
||||
fooAddr, flags))
|
||||
require.Equal(t, int64(15), deposit.Amount.AmountOf(stakeTypes.DefaultBondDenom).Int64())
|
||||
|
||||
|
@ -406,14 +404,12 @@ func TestGaiaCLISubmitProposal(t *testing.T) {
|
|||
fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli query account %s %v", fooAddr, flags))
|
||||
|
||||
require.Equal(t, int64(35), fooAcc.GetCoins().AmountOf(stakeTypes.DefaultBondDenom).Int64())
|
||||
proposal1 = executeGetProposal(t, fmt.Sprintf("gaiacli query gov proposal --proposal-id=1 --output=json %v", flags))
|
||||
proposal1 = executeGetProposal(t, fmt.Sprintf("gaiacli query gov proposal 1 --output=json %v", flags))
|
||||
require.Equal(t, uint64(1), proposal1.GetProposalID())
|
||||
require.Equal(t, gov.StatusVotingPeriod, proposal1.GetStatus())
|
||||
|
||||
voteStr := fmt.Sprintf("gaiacli tx gov vote %v", flags)
|
||||
voteStr := fmt.Sprintf("gaiacli tx gov vote 1 Yes %v", flags)
|
||||
voteStr += fmt.Sprintf(" --from=%s", "foo")
|
||||
voteStr += fmt.Sprintf(" --proposal-id=%s", "1")
|
||||
voteStr += fmt.Sprintf(" --option=%s", "Yes")
|
||||
|
||||
// Test generate only
|
||||
success, stdout, stderr = executeWriteRetStdStreams(t, voteStr+" --generate-only", app.DefaultKeyPass)
|
||||
|
@ -428,11 +424,11 @@ func TestGaiaCLISubmitProposal(t *testing.T) {
|
|||
executeWrite(t, voteStr, app.DefaultKeyPass)
|
||||
tests.WaitForNextNBlocksTM(1, port)
|
||||
|
||||
vote := executeGetVote(t, fmt.Sprintf("gaiacli query gov vote --proposal-id=1 --voter=%s --output=json %v", fooAddr, flags))
|
||||
vote := executeGetVote(t, fmt.Sprintf("gaiacli query gov vote 1 %s --output=json %v", fooAddr, flags))
|
||||
require.Equal(t, uint64(1), vote.ProposalID)
|
||||
require.Equal(t, gov.OptionYes, vote.Option)
|
||||
|
||||
votes := executeGetVotes(t, fmt.Sprintf("gaiacli query gov votes --proposal-id=1 --output=json %v", flags))
|
||||
votes := executeGetVotes(t, fmt.Sprintf("gaiacli query gov votes 1 --output=json %v", flags))
|
||||
require.Len(t, votes, 1)
|
||||
require.Equal(t, uint64(1), votes[0].ProposalID)
|
||||
require.Equal(t, gov.OptionYes, votes[0].Option)
|
||||
|
|
|
@ -216,7 +216,7 @@ gaiacli query txs --tags='<tag1>:<value1>&<tag2>:<value2>'
|
|||
|
||||
::: tip Note
|
||||
|
||||
The action tag always equals the message type returned by the `Type()` function of the relevant message.
|
||||
The action tag always equals the message type returned by the `Type()` function of the relevant message.
|
||||
|
||||
You can find a list of available `tags` on each of the SDK modules:
|
||||
|
||||
|
@ -461,7 +461,7 @@ gaiacli tx gov submit-proposal \
|
|||
Once created, you can now query information of the proposal:
|
||||
|
||||
```bash
|
||||
gaiacli query gov proposal --proposal-id=<proposal_id>
|
||||
gaiacli query gov proposal <proposal_id>
|
||||
```
|
||||
|
||||
Or query all available proposals:
|
||||
|
@ -477,9 +477,7 @@ You can also query proposals filtered by `voter` or `depositor` by using the cor
|
|||
In order for a proposal to be broadcasted to the network, the amount deposited must be above a `minDeposit` value (default: `10 steak`). If the proposal you previously created didn't meet this requirement, you can still increase the total amount deposited to activate it. Once the minimum deposit is reached, the proposal enters voting period:
|
||||
|
||||
```bash
|
||||
gaiacli tx gov deposit \
|
||||
--proposal-id=<proposal_id> \
|
||||
--deposit=<200steak> \
|
||||
gaiacli tx gov deposit <proposal_id> <200steak> \
|
||||
--from=<name> \
|
||||
--chain-id=<chain_id>
|
||||
```
|
||||
|
@ -491,15 +489,13 @@ gaiacli tx gov deposit \
|
|||
Once a new proposal is created, you can query all the deposits submitted to it:
|
||||
|
||||
```bash
|
||||
gaiacli query gov deposits --proposal-id=<proposal_id>
|
||||
gaiacli query gov deposits <proposal_id>
|
||||
```
|
||||
|
||||
You can also query a deposit submitted by a specific address:
|
||||
|
||||
```bash
|
||||
gaiacli query gov deposit \
|
||||
--proposal-id=<proposal_id> \
|
||||
--depositor=<account_cosmos>
|
||||
gaiacli query gov deposit <proposal_id> <depositor_address>
|
||||
```
|
||||
|
||||
#### Vote on a proposal
|
||||
|
@ -507,9 +503,7 @@ gaiacli query gov deposit \
|
|||
After a proposal's deposit reaches the `MinDeposit` value, the voting period opens. Bonded `Atom` holders can then cast vote on it:
|
||||
|
||||
```bash
|
||||
gaiacli tx gov vote \
|
||||
--proposal-id=<proposal_id> \
|
||||
--option=<Yes/No/NoWithVeto/Abstain> \
|
||||
gaiacli tx gov vote <proposal_id> <Yes/No/NoWithVeto/Abstain> \
|
||||
--from=<name> \
|
||||
--chain-id=<chain_id>
|
||||
```
|
||||
|
@ -519,15 +513,13 @@ gaiacli tx gov vote \
|
|||
Check the vote with the option you just submitted:
|
||||
|
||||
```bash
|
||||
gaiacli query gov vote \
|
||||
--proposal-id=<proposal_id> \
|
||||
--voter=<account_cosmos>
|
||||
gaiacli query gov vote <proposal_id> <voter_address>
|
||||
```
|
||||
|
||||
You can also get all the previous votes submitted to the proposal with:
|
||||
|
||||
```bash
|
||||
gaiacli query gov votes --proposal-id=<proposal_id>
|
||||
gaiacli query gov votes <proposal_id>
|
||||
```
|
||||
|
||||
#### Query proposal tally results
|
||||
|
@ -535,5 +527,15 @@ gaiacli query gov votes --proposal-id=<proposal_id>
|
|||
To check the current tally of a given proposal you can use the `tally` command:
|
||||
|
||||
```bash
|
||||
gaiacli query gov tally --proposal-id=<proposal_id>
|
||||
gaiacli query gov tally <proposal_id>
|
||||
```
|
||||
|
||||
#### Query governance parameters
|
||||
|
||||
To check the current governance parameters run:
|
||||
|
||||
```bash
|
||||
gaiacli query gov param voting
|
||||
gaiacli query gov param tallying
|
||||
gaiacli query gov param deposit
|
||||
```
|
||||
|
|
|
@ -2,6 +2,8 @@ package cli
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client/context"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
|
@ -15,19 +17,25 @@ import (
|
|||
// GetCmdQueryProposal implements the query proposal command.
|
||||
func GetCmdQueryProposal(queryRoute string, cdc *codec.Codec) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "proposal",
|
||||
Use: "proposal [proposal-id]",
|
||||
Args: cobra.ExactArgs(1),
|
||||
Short: "Query details of a single proposal",
|
||||
Long: strings.TrimSpace(`
|
||||
Query details for a proposal. You can find the proposal-id by running gaiacli query gov proposals:
|
||||
|
||||
$ gaiacli query gov proposal 1
|
||||
`),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
cliCtx := context.NewCLIContext().WithCodec(cdc)
|
||||
proposalID := uint64(viper.GetInt64(flagProposalID))
|
||||
|
||||
params := gov.NewQueryProposalParams(proposalID)
|
||||
bz, err := cdc.MarshalJSON(params)
|
||||
// validate that the proposal id is a uint
|
||||
proposalID, err := strconv.ParseUint(args[0], 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("proposal-id %s not a valid uint, please input a valid proposal-id", args[0])
|
||||
}
|
||||
|
||||
res, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/proposal", queryRoute), bz)
|
||||
// Query the proposal
|
||||
res, err := queryProposal(proposalID, cliCtx, cdc, queryRoute)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -37,16 +45,37 @@ func GetCmdQueryProposal(queryRoute string, cdc *codec.Codec) *cobra.Command {
|
|||
},
|
||||
}
|
||||
|
||||
cmd.Flags().String(flagProposalID, "", "proposalID of proposal being queried")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func queryProposal(proposalID uint64, cliCtx context.CLIContext, cdc *codec.Codec, queryRoute string) ([]byte, error) {
|
||||
// Construct query
|
||||
params := gov.NewQueryProposalParams(proposalID)
|
||||
bz, err := cdc.MarshalJSON(params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Query store
|
||||
res, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/proposal", queryRoute), bz)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return res, err
|
||||
}
|
||||
|
||||
// GetCmdQueryProposals implements a query proposals command.
|
||||
func GetCmdQueryProposals(queryRoute string, cdc *codec.Codec) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "proposals",
|
||||
Short: "Query proposals with optional filters",
|
||||
Long: strings.TrimSpace(`
|
||||
Query for a all proposals. You can filter the returns with the following flags:
|
||||
|
||||
$ gaiacli query gov proposals --depositor cosmos1skjwj5whet0lpe65qaq4rpq03hjxlwd9nf39lk
|
||||
$ gaiacli query gov proposals --voter cosmos1skjwj5whet0lpe65qaq4rpq03hjxlwd9nf39lk
|
||||
$ gaiacli query gov proposals --status (DepositPeriod|VotingPeriod|Passed|Rejected)
|
||||
`),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
bechDepositorAddr := viper.GetString(flagDepositor)
|
||||
bechVoterAddr := viper.GetString(flagVoter)
|
||||
|
@ -126,23 +155,43 @@ func GetCmdQueryProposals(queryRoute string, cdc *codec.Codec) *cobra.Command {
|
|||
// GetCmdQueryVote implements the query proposal vote command.
|
||||
func GetCmdQueryVote(queryRoute string, cdc *codec.Codec) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "vote",
|
||||
Use: "vote [proposal-id] [voter-address]",
|
||||
Args: cobra.ExactArgs(2),
|
||||
Short: "Query details of a single vote",
|
||||
Long: strings.TrimSpace(`
|
||||
Query details for a single vote on a proposal. You can find the proposal-id by running gaiacli query gov proposals:
|
||||
|
||||
$ gaiacli query gov vote 1 cosmos1skjwj5whet0lpe65qaq4rpq03hjxlwd9nf39lk
|
||||
`),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
cliCtx := context.NewCLIContext().WithCodec(cdc)
|
||||
proposalID := uint64(viper.GetInt64(flagProposalID))
|
||||
|
||||
voterAddr, err := sdk.AccAddressFromBech32(viper.GetString(flagVoter))
|
||||
// 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 = queryProposal(proposalID, cliCtx, cdc, queryRoute)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to fetch proposal-id %d: %s", proposalID, err)
|
||||
}
|
||||
|
||||
// get voter address
|
||||
voterAddr, err := sdk.AccAddressFromBech32(args[1])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Construct query
|
||||
params := gov.NewQueryVoteParams(proposalID, voterAddr)
|
||||
bz, err := cdc.MarshalJSON(params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Query store
|
||||
res, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/vote", queryRoute), bz)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -153,27 +202,43 @@ func GetCmdQueryVote(queryRoute string, cdc *codec.Codec) *cobra.Command {
|
|||
},
|
||||
}
|
||||
|
||||
cmd.Flags().String(flagProposalID, "", "proposalID of proposal voting on")
|
||||
cmd.Flags().String(flagVoter, "", "bech32 voter address")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
// GetCmdQueryVotes implements the command to query for proposal votes.
|
||||
func GetCmdQueryVotes(queryRoute string, cdc *codec.Codec) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "votes",
|
||||
Use: "votes [proposal-id]",
|
||||
Args: cobra.ExactArgs(1),
|
||||
Short: "Query votes on a proposal",
|
||||
Long: strings.TrimSpace(`
|
||||
Query vote details for a single proposal. You can find the proposal-id by running gaiacli query gov proposals:
|
||||
|
||||
$ gaiacli query gov votes 1
|
||||
`),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
cliCtx := context.NewCLIContext().WithCodec(cdc)
|
||||
proposalID := uint64(viper.GetInt64(flagProposalID))
|
||||
|
||||
// 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 = queryProposal(proposalID, cliCtx, cdc, queryRoute)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to fetch proposal-id %d: %s", proposalID, err)
|
||||
}
|
||||
|
||||
// Construct query
|
||||
params := gov.NewQueryProposalParams(proposalID)
|
||||
bz, err := cdc.MarshalJSON(params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Query store
|
||||
res, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/votes", queryRoute), bz)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -184,8 +249,6 @@ func GetCmdQueryVotes(queryRoute string, cdc *codec.Codec) *cobra.Command {
|
|||
},
|
||||
}
|
||||
|
||||
cmd.Flags().String(flagProposalID, "", "proposalID of which proposal's votes are being queried")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
|
@ -193,23 +256,43 @@ func GetCmdQueryVotes(queryRoute string, cdc *codec.Codec) *cobra.Command {
|
|||
// GetCmdQueryDeposit implements the query proposal deposit command.
|
||||
func GetCmdQueryDeposit(queryRoute string, cdc *codec.Codec) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "deposit",
|
||||
Use: "deposit [proposal-id] [depositer-address]",
|
||||
Args: cobra.ExactArgs(2),
|
||||
Short: "Query details of a deposit",
|
||||
Long: strings.TrimSpace(`
|
||||
Query details for a single proposal deposit on a proposal. You can find the proposal-id by running gaiacli query gov proposals:
|
||||
|
||||
$ gaiacli query gov deposit 1 cosmos1skjwj5whet0lpe65qaq4rpq03hjxlwd9nf39lk
|
||||
`),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
cliCtx := context.NewCLIContext().WithCodec(cdc)
|
||||
proposalID := uint64(viper.GetInt64(flagProposalID))
|
||||
|
||||
depositorAddr, err := sdk.AccAddressFromBech32(viper.GetString(flagDepositor))
|
||||
// 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 uint, please input a valid proposal-id", args[0])
|
||||
}
|
||||
|
||||
// check to see if the proposal is in the store
|
||||
_, err = queryProposal(proposalID, cliCtx, cdc, queryRoute)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to fetch proposal-id %d: %s", proposalID, err)
|
||||
}
|
||||
|
||||
// Get the depositer address
|
||||
depositorAddr, err := sdk.AccAddressFromBech32(args[1])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Construct query
|
||||
params := gov.NewQueryDepositParams(proposalID, depositorAddr)
|
||||
bz, err := cdc.MarshalJSON(params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Query store
|
||||
res, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/deposit", queryRoute), bz)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -220,27 +303,43 @@ func GetCmdQueryDeposit(queryRoute string, cdc *codec.Codec) *cobra.Command {
|
|||
},
|
||||
}
|
||||
|
||||
cmd.Flags().String(flagProposalID, "", "proposalID of proposal deposited on")
|
||||
cmd.Flags().String(flagDepositor, "", "bech32 depositor address")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
// GetCmdQueryDeposits implements the command to query for proposal deposits.
|
||||
func GetCmdQueryDeposits(queryRoute string, cdc *codec.Codec) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "deposits",
|
||||
Use: "deposits [proposal-id]",
|
||||
Args: cobra.ExactArgs(1),
|
||||
Short: "Query deposits on a proposal",
|
||||
Long: strings.TrimSpace(`
|
||||
Query details for all deposits on a proposal. You can find the proposal-id by running gaiacli query gov proposals:
|
||||
|
||||
$ gaiacli query gov deposits 1
|
||||
`),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
cliCtx := context.NewCLIContext().WithCodec(cdc)
|
||||
proposalID := uint64(viper.GetInt64(flagProposalID))
|
||||
|
||||
// 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 uint, please input a valid proposal-id", args[0])
|
||||
}
|
||||
|
||||
// check to see if the proposal is in the store
|
||||
_, err = queryProposal(proposalID, cliCtx, cdc, queryRoute)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to fetch proposal-id %d: %s", proposalID, err)
|
||||
}
|
||||
|
||||
// Construct query
|
||||
params := gov.NewQueryProposalParams(proposalID)
|
||||
bz, err := cdc.MarshalJSON(params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Query store
|
||||
res, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/deposits", queryRoute), bz)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -251,26 +350,43 @@ func GetCmdQueryDeposits(queryRoute string, cdc *codec.Codec) *cobra.Command {
|
|||
},
|
||||
}
|
||||
|
||||
cmd.Flags().String(flagProposalID, "", "proposalID of which proposal's deposits are being queried")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
// GetCmdQueryTally implements the command to query for proposal tally result.
|
||||
func GetCmdQueryTally(queryRoute string, cdc *codec.Codec) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "tally",
|
||||
Use: "tally [proposal-id]",
|
||||
Args: cobra.ExactArgs(1),
|
||||
Short: "Get the tally of a proposal vote",
|
||||
Long: strings.TrimSpace(`
|
||||
Query tally of votes on a proposal. You can find the proposal-id by running gaiacli query gov proposals:
|
||||
|
||||
$ gaiacli query gov tally 1
|
||||
`),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
cliCtx := context.NewCLIContext().WithCodec(cdc)
|
||||
proposalID := uint64(viper.GetInt64(flagProposalID))
|
||||
|
||||
// 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 = queryProposal(proposalID, cliCtx, cdc, queryRoute)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to fetch proposal-id %d: %s", proposalID, err)
|
||||
}
|
||||
|
||||
// Construct query
|
||||
params := gov.NewQueryProposalParams(proposalID)
|
||||
bz, err := cdc.MarshalJSON(params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Query store
|
||||
res, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/tally", queryRoute), bz)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -281,8 +397,6 @@ func GetCmdQueryTally(queryRoute string, cdc *codec.Codec) *cobra.Command {
|
|||
},
|
||||
}
|
||||
|
||||
cmd.Flags().String(flagProposalID, "", "proposalID of which proposal is being tallied")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
|
@ -290,14 +404,13 @@ func GetCmdQueryTally(queryRoute string, cdc *codec.Codec) *cobra.Command {
|
|||
func GetCmdQueryParams(queryRoute string, cdc *codec.Codec) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "param [param-type]",
|
||||
Short: "Query the parameters (voting|tallying|deposit) of the governance process",
|
||||
Args: cobra.ExactArgs(1),
|
||||
Short: "Query the parameters (voting|tallying|deposit) of the governance process",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
paramType := args[0]
|
||||
|
||||
cliCtx := context.NewCLIContext().WithCodec(cdc)
|
||||
|
||||
res, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/params/%s", queryRoute, paramType), nil)
|
||||
// Query store
|
||||
res, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/params/%s", queryRoute, args[0]), nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package cli
|
|||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client/context"
|
||||
"github.com/cosmos/cosmos-sdk/client/utils"
|
||||
|
@ -10,6 +11,7 @@ import (
|
|||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
authtxb "github.com/cosmos/cosmos-sdk/x/auth/client/txbuilder"
|
||||
"github.com/cosmos/cosmos-sdk/x/gov"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
|
@ -21,7 +23,6 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
flagProposalID = "proposal-id"
|
||||
flagTitle = "title"
|
||||
flagDescription = "description"
|
||||
flagProposalType = "type"
|
||||
|
@ -56,7 +57,7 @@ func GetCmdSubmitProposal(cdc *codec.Codec) *cobra.Command {
|
|||
Long: strings.TrimSpace(`
|
||||
Submit a proposal along with an initial deposit. Proposal title, description, type and deposit can be given directly or through a proposal JSON file. For example:
|
||||
|
||||
$ gaiacli gov submit-proposal --proposal="path/to/proposal.json"
|
||||
$ gaiacli gov submit-proposal --proposal="path/to/proposal.json" --from mykey
|
||||
|
||||
where proposal.json contains:
|
||||
|
||||
|
@ -64,12 +65,12 @@ where proposal.json contains:
|
|||
"title": "Test Proposal",
|
||||
"description": "My awesome proposal",
|
||||
"type": "Text",
|
||||
"deposit": "1000test"
|
||||
"deposit": "10test"
|
||||
}
|
||||
|
||||
is equivalent to
|
||||
|
||||
$ gaiacli gov submit-proposal --title="Test Proposal" --description="My awesome proposal" --type="Text" --deposit="1000test"
|
||||
$ gaiacli gov submit-proposal --title="Test Proposal" --description="My awesome proposal" --type="Text" --deposit="10test" --from mykey
|
||||
`),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
proposal, err := parseSubmitProposalFlags()
|
||||
|
@ -82,22 +83,35 @@ $ gaiacli gov submit-proposal --title="Test Proposal" --description="My awesome
|
|||
WithCodec(cdc).
|
||||
WithAccountDecoder(cdc)
|
||||
|
||||
fromAddr, err := cliCtx.GetFromAddress()
|
||||
// Get from address
|
||||
from, err := cliCtx.GetFromAddress()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Pull associated account
|
||||
account, err := cliCtx.GetAccount(from)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Find deposit amount
|
||||
amount, err := sdk.ParseCoins(proposal.Deposit)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// ensure account has enough coins
|
||||
if !account.GetCoins().IsAllGTE(amount) {
|
||||
return errors.Errorf("Address %s doesn't have enough coins to pay for this transaction.", from)
|
||||
}
|
||||
|
||||
proposalType, err := gov.ProposalTypeFromString(proposal.Type)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
msg := gov.NewMsgSubmitProposal(proposal.Title, proposal.Description, proposalType, fromAddr, amount)
|
||||
msg := gov.NewMsgSubmitProposal(proposal.Title, proposal.Description, proposalType, from, amount)
|
||||
err = msg.ValidateBasic()
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -155,29 +169,58 @@ func parseSubmitProposalFlags() (*proposal, error) {
|
|||
}
|
||||
|
||||
// GetCmdDeposit implements depositing tokens for an active proposal.
|
||||
func GetCmdDeposit(cdc *codec.Codec) *cobra.Command {
|
||||
func GetCmdDeposit(queryRoute string, cdc *codec.Codec) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "deposit",
|
||||
Use: "deposit [proposal-id] [deposit]",
|
||||
Args: cobra.ExactArgs(2),
|
||||
Short: "Deposit tokens for activing proposal",
|
||||
Long: strings.TrimSpace(`
|
||||
Submit a deposit for an acive proposal. You can find the proposal-id by running gaiacli query gov proposals:
|
||||
|
||||
$ gaiacli tx gov deposit 1 10STAKE --from mykey
|
||||
`),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
txBldr := authtxb.NewTxBuilderFromCLI().WithCodec(cdc)
|
||||
cliCtx := context.NewCLIContext().
|
||||
WithCodec(cdc).
|
||||
WithAccountDecoder(cdc)
|
||||
|
||||
depositorAddr, err := 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 uint, please input a valid proposal-id", args[0])
|
||||
}
|
||||
|
||||
// check to see if the proposal is in the store
|
||||
_, err = queryProposal(proposalID, cliCtx, cdc, queryRoute)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to fetch proposal-id %d: %s", proposalID, err)
|
||||
}
|
||||
|
||||
// Get from address
|
||||
from, err := cliCtx.GetFromAddress()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
proposalID := uint64(viper.GetInt64(flagProposalID))
|
||||
|
||||
amount, err := sdk.ParseCoins(viper.GetString(flagDeposit))
|
||||
// Fetch associated account
|
||||
account, err := cliCtx.GetAccount(from)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
msg := gov.NewMsgDeposit(depositorAddr, proposalID, amount)
|
||||
// Get amount of coins
|
||||
amount, err := sdk.ParseCoins(args[1])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// ensure account has enough coins
|
||||
if !account.GetCoins().IsAllGTE(amount) {
|
||||
return errors.Errorf("Address %s doesn't have enough coins to pay for this transaction.", from)
|
||||
}
|
||||
|
||||
msg := gov.NewMsgDeposit(from, proposalID, amount)
|
||||
err = msg.ValidateBasic()
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -187,64 +230,71 @@ func GetCmdDeposit(cdc *codec.Codec) *cobra.Command {
|
|||
return utils.PrintUnsignedStdTx(os.Stdout, txBldr, cliCtx, []sdk.Msg{msg}, false)
|
||||
}
|
||||
|
||||
// Build and sign the transaction, then broadcast to a Tendermint
|
||||
// node.
|
||||
// Build and sign the transaction, then broadcast to a Tendermint node.
|
||||
return utils.CompleteAndBroadcastTxCli(txBldr, cliCtx, []sdk.Msg{msg})
|
||||
},
|
||||
}
|
||||
|
||||
cmd.Flags().String(flagProposalID, "", "proposalID of proposal depositing on")
|
||||
cmd.Flags().String(flagDeposit, "", "amount of deposit")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
// GetCmdVote implements creating a new vote command.
|
||||
func GetCmdVote(cdc *codec.Codec) *cobra.Command {
|
||||
func GetCmdVote(queryRoute string, cdc *codec.Codec) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "vote",
|
||||
Use: "vote [proposal-id] [option]",
|
||||
Args: cobra.ExactArgs(2),
|
||||
Short: "Vote for an active proposal, options: yes/no/no_with_veto/abstain",
|
||||
Long: strings.TrimSpace(`
|
||||
Submit a vote for an acive proposal. You can find the proposal-id by running gaiacli query gov proposals:
|
||||
|
||||
$ gaiacli tx gov vote 1 yes --from mykey
|
||||
`),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
txBldr := authtxb.NewTxBuilderFromCLI().WithCodec(cdc)
|
||||
cliCtx := context.NewCLIContext().
|
||||
WithCodec(cdc).
|
||||
WithAccountDecoder(cdc)
|
||||
|
||||
voterAddr, err := cliCtx.GetFromAddress()
|
||||
// Get voting address
|
||||
from, err := cliCtx.GetFromAddress()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
proposalID := uint64(viper.GetInt64(flagProposalID))
|
||||
option := viper.GetString(flagOption)
|
||||
// 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])
|
||||
}
|
||||
|
||||
byteVoteOption, err := gov.VoteOptionFromString(govClientUtils.NormalizeVoteOption(option))
|
||||
// check to see if the proposal is in the store
|
||||
_, err = queryProposal(proposalID, cliCtx, cdc, queryRoute)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to fetch proposal-id %d: %s", proposalID, err)
|
||||
}
|
||||
|
||||
// Find out which vote option user chose
|
||||
byteVoteOption, err := gov.VoteOptionFromString(govClientUtils.NormalizeVoteOption(args[1]))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
msg := gov.NewMsgVote(voterAddr, proposalID, byteVoteOption)
|
||||
// Build vote message and run basic validation
|
||||
msg := gov.NewMsgVote(from, proposalID, byteVoteOption)
|
||||
err = msg.ValidateBasic()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// If generate only print the transaction
|
||||
if cliCtx.GenerateOnly {
|
||||
return utils.PrintUnsignedStdTx(os.Stdout, txBldr, cliCtx, []sdk.Msg{msg}, false)
|
||||
}
|
||||
|
||||
fmt.Printf("Vote[Voter:%s,ProposalID:%d,Option:%s]",
|
||||
voterAddr.String(), msg.ProposalID, msg.Option.String(),
|
||||
)
|
||||
|
||||
// Build and sign the transaction, then broadcast to a Tendermint
|
||||
// node.
|
||||
// Build and sign the transaction, then broadcast to a Tendermint node.
|
||||
return utils.CompleteAndBroadcastTxCli(txBldr, cliCtx, []sdk.Msg{msg})
|
||||
},
|
||||
}
|
||||
|
||||
cmd.Flags().String(flagProposalID, "", "proposalID of proposal voting on")
|
||||
cmd.Flags().String(flagOption, "", "vote option {yes, no, no_with_veto, abstain}")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
|
|
@ -46,8 +46,8 @@ func (mc ModuleClient) GetTxCmd() *cobra.Command {
|
|||
}
|
||||
|
||||
govTxCmd.AddCommand(client.PostCommands(
|
||||
govCli.GetCmdDeposit(mc.cdc),
|
||||
govCli.GetCmdVote(mc.cdc),
|
||||
govCli.GetCmdDeposit(mc.storeKey, mc.cdc),
|
||||
govCli.GetCmdVote(mc.storeKey, mc.cdc),
|
||||
govCli.GetCmdSubmitProposal(mc.cdc),
|
||||
)...)
|
||||
|
||||
|
|
Loading…
Reference in New Issue