250 lines
6.6 KiB
Go
250 lines
6.6 KiB
Go
package cli
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/cosmos/cosmos-sdk/client/context"
|
|
"github.com/cosmos/cosmos-sdk/client/utils"
|
|
"github.com/cosmos/cosmos-sdk/codec"
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
authtxb "github.com/cosmos/cosmos-sdk/x/auth/client/txbuilder"
|
|
"github.com/cosmos/cosmos-sdk/x/gov"
|
|
|
|
"encoding/json"
|
|
"io/ioutil"
|
|
"strings"
|
|
|
|
govClientUtils "github.com/cosmos/cosmos-sdk/x/gov/client/utils"
|
|
"github.com/spf13/cobra"
|
|
"github.com/spf13/viper"
|
|
)
|
|
|
|
const (
|
|
flagProposalID = "proposal-id"
|
|
flagTitle = "title"
|
|
flagDescription = "description"
|
|
flagProposalType = "type"
|
|
flagDeposit = "deposit"
|
|
flagVoter = "voter"
|
|
flagOption = "option"
|
|
flagDepositer = "depositer"
|
|
flagStatus = "status"
|
|
flagNumLimit = "limit"
|
|
flagProposal = "proposal"
|
|
)
|
|
|
|
type proposal struct {
|
|
Title string
|
|
Description string
|
|
Type string
|
|
Deposit string
|
|
}
|
|
|
|
var proposalFlags = []string{
|
|
flagTitle,
|
|
flagDescription,
|
|
flagProposalType,
|
|
flagDeposit,
|
|
}
|
|
|
|
// GetCmdSubmitProposal implements submitting a proposal transaction command.
|
|
func GetCmdSubmitProposal(cdc *codec.Codec) *cobra.Command {
|
|
cmd := &cobra.Command{
|
|
Use: "submit-proposal",
|
|
Short: "Submit a proposal along with an initial deposit",
|
|
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"
|
|
|
|
where proposal.json contains:
|
|
|
|
{
|
|
"title": "Test Proposal",
|
|
"description": "My awesome proposal",
|
|
"type": "Text",
|
|
"deposit": "1000test"
|
|
}
|
|
|
|
is equivalent to
|
|
|
|
$ gaiacli gov submit-proposal --title="Test Proposal" --description="My awesome proposal" --type="Text" --deposit="1000test"
|
|
`),
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
proposal, err := parseSubmitProposalFlags()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
txBldr := authtxb.NewTxBuilderFromCLI().WithCodec(cdc)
|
|
cliCtx := context.NewCLIContext().
|
|
WithCodec(cdc).
|
|
WithAccountDecoder(cdc)
|
|
|
|
fromAddr, err := cliCtx.GetFromAddress()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
amount, err := sdk.ParseCoins(proposal.Deposit)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
proposalType, err := gov.ProposalTypeFromString(proposal.Type)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
msg := gov.NewMsgSubmitProposal(proposal.Title, proposal.Description, proposalType, fromAddr, amount)
|
|
err = msg.ValidateBasic()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if cliCtx.GenerateOnly {
|
|
return utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg}, false)
|
|
}
|
|
|
|
// Build and sign the transaction, then broadcast to Tendermint
|
|
// proposalID must be returned, and it is a part of response.
|
|
cliCtx.PrintResponse = true
|
|
return utils.CompleteAndBroadcastTxCli(txBldr, cliCtx, []sdk.Msg{msg})
|
|
},
|
|
}
|
|
|
|
cmd.Flags().String(flagTitle, "", "title of proposal")
|
|
cmd.Flags().String(flagDescription, "", "description of proposal")
|
|
cmd.Flags().String(flagProposalType, "", "proposalType of proposal, types: text/parameter_change/software_upgrade")
|
|
cmd.Flags().String(flagDeposit, "", "deposit of proposal")
|
|
cmd.Flags().String(flagProposal, "", "proposal file path (if this path is given, other proposal flags are ignored)")
|
|
|
|
return cmd
|
|
}
|
|
|
|
func parseSubmitProposalFlags() (*proposal, error) {
|
|
proposal := &proposal{}
|
|
proposalFile := viper.GetString(flagProposal)
|
|
|
|
if proposalFile == "" {
|
|
proposal.Title = viper.GetString(flagTitle)
|
|
proposal.Description = viper.GetString(flagDescription)
|
|
proposal.Type = govClientUtils.NormalizeProposalType(viper.GetString(flagProposalType))
|
|
proposal.Deposit = viper.GetString(flagDeposit)
|
|
return proposal, nil
|
|
}
|
|
|
|
for _, flag := range proposalFlags {
|
|
if viper.GetString(flag) != "" {
|
|
return nil, fmt.Errorf("--%s flag provided alongside --proposal, which is a noop", flag)
|
|
}
|
|
}
|
|
|
|
contents, err := ioutil.ReadFile(proposalFile)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
err = json.Unmarshal(contents, proposal)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return proposal, nil
|
|
}
|
|
|
|
// GetCmdDeposit implements depositing tokens for an active proposal.
|
|
func GetCmdDeposit(cdc *codec.Codec) *cobra.Command {
|
|
cmd := &cobra.Command{
|
|
Use: "deposit",
|
|
Short: "Deposit tokens for activing proposal",
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
txBldr := authtxb.NewTxBuilderFromCLI().WithCodec(cdc)
|
|
cliCtx := context.NewCLIContext().
|
|
WithCodec(cdc).
|
|
WithAccountDecoder(cdc)
|
|
|
|
depositerAddr, err := cliCtx.GetFromAddress()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
proposalID := uint64(viper.GetInt64(flagProposalID))
|
|
|
|
amount, err := sdk.ParseCoins(viper.GetString(flagDeposit))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
msg := gov.NewMsgDeposit(depositerAddr, proposalID, amount)
|
|
err = msg.ValidateBasic()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if cliCtx.GenerateOnly {
|
|
return utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg}, false)
|
|
}
|
|
|
|
// 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 {
|
|
cmd := &cobra.Command{
|
|
Use: "vote",
|
|
Short: "Vote for an active proposal, options: yes/no/no_with_veto/abstain",
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
txBldr := authtxb.NewTxBuilderFromCLI().WithCodec(cdc)
|
|
cliCtx := context.NewCLIContext().
|
|
WithCodec(cdc).
|
|
WithAccountDecoder(cdc)
|
|
|
|
voterAddr, err := cliCtx.GetFromAddress()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
proposalID := uint64(viper.GetInt64(flagProposalID))
|
|
option := viper.GetString(flagOption)
|
|
|
|
byteVoteOption, err := gov.VoteOptionFromString(govClientUtils.NormalizeVoteOption(option))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
msg := gov.NewMsgVote(voterAddr, proposalID, byteVoteOption)
|
|
err = msg.ValidateBasic()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if cliCtx.GenerateOnly {
|
|
return utils.PrintUnsignedStdTx(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.
|
|
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
|
|
}
|