diff --git a/x/wasm/client/cli/gov_tx.go b/x/wasm/client/cli/gov_tx.go index 1f9ba80c82..9679a5eb83 100644 --- a/x/wasm/client/cli/gov_tx.go +++ b/x/wasm/client/cli/gov_tx.go @@ -2,6 +2,7 @@ package cli import ( "fmt" + "strconv" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/tx" @@ -351,3 +352,133 @@ func ProposalClearContractAdminCmd() *cobra.Command { cmd.Flags().String(flagProposalType, "", "Permission of proposal, types: store-code/instantiate/migrate/update-admin/clear-admin/text/parameter_change/software_upgrade") return cmd } + +func ProposalPinCodesCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "pin-codes [code-ids]", + Short: "Submit a pin code proposal for pinning a code to cache", + Args: cobra.MinimumNArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + proposalTitle, err := cmd.Flags().GetString(cli.FlagTitle) + if err != nil { + return fmt.Errorf("proposal title: %s", err) + } + proposalDescr, err := cmd.Flags().GetString(cli.FlagDescription) + if err != nil { + return fmt.Errorf("proposal description: %s", err) + } + depositArg, err := cmd.Flags().GetString(cli.FlagDeposit) + if err != nil { + return fmt.Errorf("deposit: %s", err) + } + deposit, err := sdk.ParseCoinsNormalized(depositArg) + if err != nil { + return err + } + codeIds, err := parsePinCodesArgs(args) + if err != nil { + return err + } + + content := types.PinCodesProposal{ + Title: proposalTitle, + Description: proposalDescr, + CodeIDs: codeIds, + } + + msg, err := govtypes.NewMsgSubmitProposal(&content, deposit, clientCtx.GetFromAddress()) + if err != nil { + return err + } + if err = msg.ValidateBasic(); err != nil { + return err + } + + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } + // proposal flags + cmd.Flags().String(cli.FlagTitle, "", "Title of proposal") + cmd.Flags().String(cli.FlagDescription, "", "Description of proposal") + cmd.Flags().String(cli.FlagDeposit, "", "Deposit of proposal") + cmd.Flags().String(cli.FlagProposal, "", "Proposal file path (if this path is given, other proposal flags are ignored)") + // type values must match the "ProposalHandler" "routes" in cli + cmd.Flags().String(flagProposalType, "", "Permission of proposal, types: store-code/instantiate/migrate/update-admin/clear-admin/text/parameter_change/software_upgrade") + return cmd +} + +func parsePinCodesArgs(args []string) ([]uint64, error) { + var codeIds []uint64 + for _, c := range args { + codeID, err := strconv.ParseUint(c, 10, 64) + if err != nil { + return codeIds, fmt.Errorf("code IDs: %s", err) + } + codeIds = append(codeIds, codeID) + } + return codeIds, nil +} + +func ProposalUnpinCodesCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "unpin-codes [code-ids]", + Short: "Submit a unpin code proposal for unpinning a code to cache", + Args: cobra.MinimumNArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + proposalTitle, err := cmd.Flags().GetString(cli.FlagTitle) + if err != nil { + return fmt.Errorf("proposal title: %s", err) + } + proposalDescr, err := cmd.Flags().GetString(cli.FlagDescription) + if err != nil { + return fmt.Errorf("proposal description: %s", err) + } + depositArg, err := cmd.Flags().GetString(cli.FlagDeposit) + if err != nil { + return fmt.Errorf("deposit: %s", err) + } + deposit, err := sdk.ParseCoinsNormalized(depositArg) + if err != nil { + return err + } + codeIds, err := parsePinCodesArgs(args) + if err != nil { + return err + } + + content := types.UnpinCodesProposal{ + Title: proposalTitle, + Description: proposalDescr, + CodeIDs: codeIds, + } + + msg, err := govtypes.NewMsgSubmitProposal(&content, deposit, clientCtx.GetFromAddress()) + if err != nil { + return err + } + if err = msg.ValidateBasic(); err != nil { + return err + } + + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } + // proposal flags + cmd.Flags().String(cli.FlagTitle, "", "Title of proposal") + cmd.Flags().String(cli.FlagDescription, "", "Description of proposal") + cmd.Flags().String(cli.FlagDeposit, "", "Deposit of proposal") + cmd.Flags().String(cli.FlagProposal, "", "Proposal file path (if this path is given, other proposal flags are ignored)") + // type values must match the "ProposalHandler" "routes" in cli + cmd.Flags().String(flagProposalType, "", "Permission of proposal, types: store-code/instantiate/migrate/update-admin/clear-admin/text/parameter_change/software_upgrade") + return cmd +} \ No newline at end of file diff --git a/x/wasm/client/proposal_handler.go b/x/wasm/client/proposal_handler.go index 8e01d75266..02007a4edf 100644 --- a/x/wasm/client/proposal_handler.go +++ b/x/wasm/client/proposal_handler.go @@ -14,4 +14,6 @@ var ProposalHandlers = []govclient.ProposalHandler{ govclient.NewProposalHandler(cli.ProposalMigrateContractCmd, rest.MigrateProposalHandler), govclient.NewProposalHandler(cli.ProposalUpdateContractAdminCmd, rest.UpdateContractAdminProposalHandler), govclient.NewProposalHandler(cli.ProposalClearContractAdminCmd, rest.ClearContractAdminProposalHandler), + govclient.NewProposalHandler(cli.ProposalPinCodesCmd, rest.PinCodeProposalHandler), + govclient.NewProposalHandler(cli.ProposalUnpinCodesCmd, rest.UnpinCodeProposalHandler), } diff --git a/x/wasm/client/rest/gov.go b/x/wasm/client/rest/gov.go index 213c41a842..05b22d4554 100644 --- a/x/wasm/client/rest/gov.go +++ b/x/wasm/client/rest/gov.go @@ -246,6 +246,90 @@ func ClearContractAdminProposalHandler(cliCtx client.Context) govrest.ProposalRE } } +type PinCodeJSONReq struct { + BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"` + + Title string `json:"title" yaml:"title"` + Description string `json:"description" yaml:"description"` + + Proposer string `json:"proposer" yaml:"proposer"` + Deposit sdk.Coins `json:"deposit" yaml:"deposit"` + + CodeIDs []uint64 `json:"code_ids" yaml:"code_ids"` +} + +func (s PinCodeJSONReq) Content() govtypes.Content { + return &types.PinCodesProposal{ + Title: s.Title, + Description: s.Description, + CodeIDs: s.CodeIDs, + } +} +func (s PinCodeJSONReq) GetProposer() string { + return s.Proposer +} +func (s PinCodeJSONReq) GetDeposit() sdk.Coins { + return s.Deposit +} +func (s PinCodeJSONReq) GetBaseReq() rest.BaseReq { + return s.BaseReq +} + +func PinCodeProposalHandler(cliCtx client.Context) govrest.ProposalRESTHandler { + return govrest.ProposalRESTHandler{ + SubRoute: "pin_code", + Handler: func(w http.ResponseWriter, r *http.Request) { + var req PinCodeJSONReq + if !rest.ReadRESTReq(w, r, cliCtx.LegacyAmino, &req) { + return + } + toStdTxResponse(cliCtx, w, req) + }, + } +} + +type UnpinCodeJSONReq struct { + BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"` + + Title string `json:"title" yaml:"title"` + Description string `json:"description" yaml:"description"` + + Proposer string `json:"proposer" yaml:"proposer"` + Deposit sdk.Coins `json:"deposit" yaml:"deposit"` + + CodeIDs []uint64 `json:"code_ids" yaml:"code_ids"` +} + +func (s UnpinCodeJSONReq) Content() govtypes.Content { + return &types.UnpinCodesProposal{ + Title: s.Title, + Description: s.Description, + CodeIDs: s.CodeIDs, + } +} +func (s UnpinCodeJSONReq) GetProposer() string { + return s.Proposer +} +func (s UnpinCodeJSONReq) GetDeposit() sdk.Coins { + return s.Deposit +} +func (s UnpinCodeJSONReq) GetBaseReq() rest.BaseReq { + return s.BaseReq +} + +func UnpinCodeProposalHandler(cliCtx client.Context) govrest.ProposalRESTHandler { + return govrest.ProposalRESTHandler{ + SubRoute: "pin_code", + Handler: func(w http.ResponseWriter, r *http.Request) { + var req UnpinCodeJSONReq + if !rest.ReadRESTReq(w, r, cliCtx.LegacyAmino, &req) { + return + } + toStdTxResponse(cliCtx, w, req) + }, + } +} + type wasmProposalData interface { Content() govtypes.Content GetProposer() string