Add wasm gov proposals to cli (#183)

* Add wasm gov proposals to cli

* Update changelog

* Rework gov proposal rest handlers

* Fix json naming

* Pretty print byte arrays in CLI

* Replace ambiguous cli flag and rest routes

* Minor cli usage doc update
This commit is contained in:
Alexander Peters 2020-07-14 13:30:41 +02:00 committed by GitHub
parent 09a20da7c6
commit 9ab18fc46f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 1392 additions and 225 deletions

View File

@ -37,6 +37,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
## [Unreleased]
### Features
* (wasmd) [\#178](https://github.com/CosmWasm/wasmd/issues/178) Add cli support for wasm gov proposals
* (wasmd) [\#163](https://github.com/CosmWasm/wasmd/issues/163) Control who can instantiate code
* (wasmd) [\#164](https://github.com/CosmWasm/wasmd/issues/164) Control who can upload code
* (wasmd) [\#173](https://github.com/CosmWasm/wasmd/issues/173) Gov proposal types and handler

View File

@ -5,9 +5,8 @@ import (
"os"
"path/filepath"
"github.com/spf13/viper"
"github.com/CosmWasm/wasmd/x/wasm"
wasmclient "github.com/CosmWasm/wasmd/x/wasm/client"
bam "github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/simapp"
@ -30,6 +29,7 @@ import (
"github.com/cosmos/cosmos-sdk/x/supply"
"github.com/cosmos/cosmos-sdk/x/upgrade"
upgradeclient "github.com/cosmos/cosmos-sdk/x/upgrade/client"
"github.com/spf13/viper"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/libs/cli"
"github.com/tendermint/tendermint/libs/log"
@ -56,7 +56,7 @@ var (
staking.AppModuleBasic{},
mint.AppModuleBasic{},
distr.AppModuleBasic{},
gov.NewAppModuleBasic(paramsclient.ProposalHandler, distr.ProposalHandler, upgradeclient.ProposalHandler),
gov.NewAppModuleBasic(append(wasmclient.ProposalHandlers, paramsclient.ProposalHandler, distr.ProposalHandler, upgradeclient.ProposalHandler)...),
params.AppModuleBasic{},
wasm.AppModuleBasic{},
crisis.AppModuleBasic{},

View File

@ -17,7 +17,6 @@ import (
authrest "github.com/cosmos/cosmos-sdk/x/auth/client/rest"
"github.com/cosmos/cosmos-sdk/x/bank"
bankcmd "github.com/cosmos/cosmos-sdk/x/bank/client/cli"
"github.com/spf13/cobra"
"github.com/spf13/viper"

295
x/wasm/client/cli/gov_tx.go Normal file
View File

@ -0,0 +1,295 @@
package cli
import (
"bufio"
"github.com/CosmWasm/wasmd/x/wasm/internal/types"
"github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/auth/client/utils"
"github.com/cosmos/cosmos-sdk/x/gov/client/cli"
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
func ProposalStoreCodeCmd(cdc *codec.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "wasm-store [wasm file] --source [source] --builder [builder] --title [text] --description [text] --run-as [address]",
Short: "Submit a wasm binary proposal",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
inBuf := bufio.NewReader(cmd.InOrStdin())
txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(utils.GetTxEncoder(cdc))
cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc)
src, err := parseStoreCodeArgs(args, cliCtx)
if err != nil {
return err
}
if len(viper.GetString(flagRunAs)) == 0 {
return errors.New("run-as address is required")
}
runAsAddr, err := sdk.AccAddressFromBech32(viper.GetString(flagRunAs))
if err != nil {
return errors.Wrap(err, "run-as")
}
content := types.StoreCodeProposal{
WasmProposal: types.WasmProposal{
Title: viper.GetString(cli.FlagTitle),
Description: viper.GetString(cli.FlagDescription),
},
RunAs: runAsAddr,
WASMByteCode: src.WASMByteCode,
Source: src.Source,
Builder: src.Builder,
InstantiatePermission: src.InstantiatePermission,
}
deposit, err := sdk.ParseCoins(viper.GetString(cli.FlagDeposit))
if err != nil {
return err
}
msg := govtypes.NewMsgSubmitProposal(content, deposit, cliCtx.GetFromAddress())
if err = msg.ValidateBasic(); err != nil {
return err
}
return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg})
},
}
cmd.Flags().String(flagSource, "", "A valid URI reference to the contract's source code, optional")
cmd.Flags().String(flagBuilder, "", "A valid docker tag for the build system, optional")
cmd.Flags().String(flagRunAs, "", "The address that is stored as code creator")
cmd.Flags().String(flagInstantiateByEverybody, "", "Everybody can instantiate a contract from the code, optional")
cmd.Flags().String(flagInstantiateByAddress, "", "Only this address can instantiate a contract instance from the code, optional")
// 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, "", "Type of proposal, types: store-code/instantiate/migrate/update-admin/clear-admin/text/parameter_change/software_upgrade")
return cmd
}
func ProposalInstantiateContractCmd(cdc *codec.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "instantiate-contract [code_id_int64] [json_encoded_init_args] --label [text] --title [text] --description [text] --run-as [address] --admin [address,optional] --amount [coins,optional]",
Short: "Submit an instantiate wasm contract proposal",
Args: cobra.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) error {
inBuf := bufio.NewReader(cmd.InOrStdin())
txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(utils.GetTxEncoder(cdc))
cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc)
src, err := parseInstantiateArgs(args, cliCtx)
if err != nil {
return err
}
if len(viper.GetString(flagRunAs)) == 0 {
return errors.New("creator address is required")
}
creator, err := sdk.AccAddressFromBech32(viper.GetString(flagRunAs))
if err != nil {
return errors.Wrap(err, "creator")
}
content := types.InstantiateContractProposal{
WasmProposal: types.WasmProposal{
Title: viper.GetString(cli.FlagTitle),
Description: viper.GetString(cli.FlagDescription),
},
RunAs: creator,
Admin: src.Admin,
Code: src.Code,
Label: src.Label,
InitMsg: src.InitMsg,
InitFunds: src.InitFunds,
}
deposit, err := sdk.ParseCoins(viper.GetString(cli.FlagDeposit))
if err != nil {
return err
}
msg := govtypes.NewMsgSubmitProposal(content, deposit, cliCtx.GetFromAddress())
if err = msg.ValidateBasic(); err != nil {
return err
}
return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg})
},
}
cmd.Flags().String(flagAmount, "", "Coins to send to the contract during instantiation")
cmd.Flags().String(flagLabel, "", "A human-readable name for this contract in lists")
cmd.Flags().String(flagAdmin, "", "Address of an admin")
cmd.Flags().String(flagRunAs, "", "The address that pays the init funds. It is the creator of the contract and passed to the contract as sender on proposal execution")
// 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, "", "Type of proposal, types: store-code/instantiate/migrate/update-admin/clear-admin/text/parameter_change/software_upgrade")
return cmd
}
func ProposalMigrateContractCmd(cdc *codec.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "migrate-contract [contract_addr_bech32] [new_code_id_int64] [json_encoded_migration_args]",
Short: "Submit a migrate wasm contract to a new code version proposal",
Args: cobra.ExactArgs(3),
RunE: func(cmd *cobra.Command, args []string) error {
inBuf := bufio.NewReader(cmd.InOrStdin())
txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(utils.GetTxEncoder(cdc))
cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc)
src, err := parseMigrateContractArgs(args, cliCtx)
if err != nil {
return err
}
if len(viper.GetString(flagRunAs)) == 0 {
return errors.New("run-as address is required")
}
runAs, err := sdk.AccAddressFromBech32(viper.GetString(flagRunAs))
if err != nil {
return errors.Wrap(err, "run-as")
}
content := types.MigrateContractProposal{
WasmProposal: types.WasmProposal{
Title: viper.GetString(cli.FlagTitle),
Description: viper.GetString(cli.FlagDescription),
},
Contract: src.Contract,
Code: src.Code,
MigrateMsg: src.MigrateMsg,
RunAs: runAs,
}
deposit, err := sdk.ParseCoins(viper.GetString(cli.FlagDeposit))
if err != nil {
return err
}
msg := govtypes.NewMsgSubmitProposal(content, deposit, cliCtx.GetFromAddress())
if err = msg.ValidateBasic(); err != nil {
return err
}
return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg})
},
}
cmd.Flags().String(flagRunAs, "", "The address that is passed as sender to the contract on proposal execution")
// 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, "", "Type of proposal, types: store-code/instantiate/migrate/update-admin/clear-admin/text/parameter_change/software_upgrade")
return cmd
}
func ProposalUpdateContractAdminCmd(cdc *codec.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "set-contract-admin [contract_addr_bech32] [new_admin_addr_bech32]",
Short: "Submit a new admin for a contract proposal",
Args: cobra.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) error {
inBuf := bufio.NewReader(cmd.InOrStdin())
txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(utils.GetTxEncoder(cdc))
cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc)
src, err := parseUpdateContractAdminArgs(args, cliCtx)
if err != nil {
return err
}
content := types.UpdateAdminProposal{
WasmProposal: types.WasmProposal{
Title: viper.GetString(cli.FlagTitle),
Description: viper.GetString(cli.FlagDescription),
},
Contract: src.Contract,
NewAdmin: src.NewAdmin,
}
deposit, err := sdk.ParseCoins(viper.GetString(cli.FlagDeposit))
if err != nil {
return err
}
msg := govtypes.NewMsgSubmitProposal(content, deposit, cliCtx.GetFromAddress())
if err = msg.ValidateBasic(); err != nil {
return err
}
return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{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, "", "Type of proposal, types: store-code/instantiate/migrate/update-admin/clear-admin/text/parameter_change/software_upgrade")
return cmd
}
func ProposalClearContractAdminCmd(cdc *codec.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "clear-contract-admin [contract_addr_bech32]",
Short: "Submit a clear admin for a contract to prevent further migrations proposal",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
inBuf := bufio.NewReader(cmd.InOrStdin())
txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(utils.GetTxEncoder(cdc))
cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc)
contractAddr, err := sdk.AccAddressFromBech32(args[0])
if err != nil {
return sdkerrors.Wrap(err, "contract")
}
content := types.ClearAdminProposal{
WasmProposal: types.WasmProposal{
Title: viper.GetString(cli.FlagTitle),
Description: viper.GetString(cli.FlagDescription),
},
Contract: contractAddr,
}
deposit, err := sdk.ParseCoins(viper.GetString(cli.FlagDeposit))
if err != nil {
return err
}
msg := govtypes.NewMsgSubmitProposal(content, deposit, cliCtx.GetFromAddress())
if err = msg.ValidateBasic(); err != nil {
return err
}
return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{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, "", "Type of proposal, types: store-code/instantiate/migrate/update-admin/clear-admin/text/parameter_change/software_upgrade")
return cmd
}

View File

@ -25,24 +25,12 @@ func MigrateContractCmd(cdc *codec.Codec) *cobra.Command {
txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(utils.GetTxEncoder(cdc))
cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc)
contractAddr, err := sdk.AccAddressFromBech32(args[0])
msg, err := parseMigrateContractArgs(args, cliCtx)
if err != nil {
return sdkerrors.Wrap(err, "contract")
return err
}
// get the id of the code to instantiate
codeID, err := strconv.ParseUint(args[1], 10, 64)
if err != nil {
return sdkerrors.Wrap(err, "code id")
}
migrateMsg := args[2]
msg := types.MsgMigrateContract{
Sender: cliCtx.GetFromAddress(),
Contract: contractAddr,
Code: codeID,
MigrateMsg: []byte(migrateMsg),
if err := msg.ValidateBasic(); err != nil {
return nil
}
return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg})
},
@ -50,6 +38,29 @@ func MigrateContractCmd(cdc *codec.Codec) *cobra.Command {
return cmd
}
func parseMigrateContractArgs(args []string, cliCtx context.CLIContext) (types.MsgMigrateContract, error) {
contractAddr, err := sdk.AccAddressFromBech32(args[0])
if err != nil {
return types.MsgMigrateContract{}, sdkerrors.Wrap(err, "contract")
}
// get the id of the code to instantiate
codeID, err := strconv.ParseUint(args[1], 10, 64)
if err != nil {
return types.MsgMigrateContract{}, sdkerrors.Wrap(err, "code id")
}
migrateMsg := args[2]
msg := types.MsgMigrateContract{
Sender: cliCtx.GetFromAddress(),
Contract: contractAddr,
Code: codeID,
MigrateMsg: []byte(migrateMsg),
}
return msg, nil
}
// UpdateContractAdminCmd sets an new admin for a contract
func UpdateContractAdminCmd(cdc *codec.Codec) *cobra.Command {
cmd := &cobra.Command{
@ -61,19 +72,12 @@ func UpdateContractAdminCmd(cdc *codec.Codec) *cobra.Command {
txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(utils.GetTxEncoder(cdc))
cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc)
contractAddr, err := sdk.AccAddressFromBech32(args[0])
msg, err := parseUpdateContractAdminArgs(args, cliCtx)
if err != nil {
return sdkerrors.Wrap(err, "contract")
return err
}
newAdmin, err := sdk.AccAddressFromBech32(args[1])
if err != nil {
return sdkerrors.Wrap(err, "new admin")
}
msg := types.MsgUpdateAdmin{
Sender: cliCtx.GetFromAddress(),
Contract: contractAddr,
NewAdmin: newAdmin,
if err := msg.ValidateBasic(); err != nil {
return err
}
return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg})
},
@ -81,6 +85,24 @@ func UpdateContractAdminCmd(cdc *codec.Codec) *cobra.Command {
return cmd
}
func parseUpdateContractAdminArgs(args []string, cliCtx context.CLIContext) (types.MsgUpdateAdmin, error) {
contractAddr, err := sdk.AccAddressFromBech32(args[0])
if err != nil {
return types.MsgUpdateAdmin{}, sdkerrors.Wrap(err, "contract")
}
newAdmin, err := sdk.AccAddressFromBech32(args[1])
if err != nil {
return types.MsgUpdateAdmin{}, sdkerrors.Wrap(err, "new admin")
}
msg := types.MsgUpdateAdmin{
Sender: cliCtx.GetFromAddress(),
Contract: contractAddr,
NewAdmin: newAdmin,
}
return msg, nil
}
// ClearContractAdminCmd clears an admin for a contract
func ClearContractAdminCmd(cdc *codec.Codec) *cobra.Command {
cmd := &cobra.Command{
@ -101,6 +123,9 @@ func ClearContractAdminCmd(cdc *codec.Codec) *cobra.Command {
Sender: cliCtx.GetFromAddress(),
Contract: contractAddr,
}
if err := msg.ValidateBasic(); err != nil {
return err
}
return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg})
},
}

View File

@ -23,13 +23,15 @@ import (
)
const (
flagTo = "to"
flagAmount = "amount"
flagSource = "source"
flagBuilder = "builder"
flagLabel = "label"
flagAdmin = "admin"
flagNoAdmin = "no-admin"
flagAmount = "amount"
flagSource = "source"
flagBuilder = "builder"
flagLabel = "label"
flagAdmin = "admin"
flagRunAs = "run-as"
flagInstantiateByEverybody = "instantiate-everybody"
flagInstantiateByAddress = "instantiate-only-address"
flagProposalType = "type"
)
// GetTxCmd returns the transaction commands for this module
@ -63,37 +65,11 @@ func StoreCodeCmd(cdc *codec.Codec) *cobra.Command {
txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(utils.GetTxEncoder(cdc))
cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc)
// parse coins trying to be sent
wasm, err := ioutil.ReadFile(args[0])
msg, err := parseStoreCodeArgs(args, cliCtx)
if err != nil {
return err
}
source := viper.GetString(flagSource)
builder := viper.GetString(flagBuilder)
// gzip the wasm file
if wasmUtils.IsWasm(wasm) {
wasm, err = wasmUtils.GzipIt(wasm)
if err != nil {
return err
}
} else if !wasmUtils.IsGzip(wasm) {
return fmt.Errorf("invalid input file. Use wasm binary or gzip")
}
// build and sign the transaction, then broadcast to Tendermint
msg := types.MsgStoreCode{
Sender: cliCtx.GetFromAddress(),
WASMByteCode: wasm,
Source: source,
Builder: builder,
}
err = msg.ValidateBasic()
if err != nil {
if err = msg.ValidateBasic(); err != nil {
return err
}
@ -103,58 +79,70 @@ func StoreCodeCmd(cdc *codec.Codec) *cobra.Command {
cmd.Flags().String(flagSource, "", "A valid URI reference to the contract's source code, optional")
cmd.Flags().String(flagBuilder, "", "A valid docker tag for the build system, optional")
cmd.Flags().String(flagInstantiateByEverybody, "", "Everybody can instantiate a contract from the code, optional")
cmd.Flags().String(flagInstantiateByAddress, "", "Only this address can instantiate a contract instance from the code, optional")
return cmd
}
func parseStoreCodeArgs(args []string, cliCtx context.CLIContext) (types.MsgStoreCode, error) {
wasm, err := ioutil.ReadFile(args[0])
if err != nil {
return types.MsgStoreCode{}, err
}
// gzip the wasm file
if wasmUtils.IsWasm(wasm) {
wasm, err = wasmUtils.GzipIt(wasm)
if err != nil {
return types.MsgStoreCode{}, err
}
} else if !wasmUtils.IsGzip(wasm) {
return types.MsgStoreCode{}, fmt.Errorf("invalid input file. Use wasm binary or gzip")
}
var perm *types.AccessConfig
if onlyAddrStr := viper.GetString(flagInstantiateByAddress); onlyAddrStr != "" {
allowedAddr, err := sdk.AccAddressFromBech32(onlyAddrStr)
if err != nil {
return types.MsgStoreCode{}, sdkerrors.Wrap(err, flagInstantiateByAddress)
}
x := types.OnlyAddress.With(allowedAddr)
perm = &x
} else if everybody := viper.GetBool(flagInstantiateByEverybody); everybody {
perm = &types.AllowEverybody
}
// build and sign the transaction, then broadcast to Tendermint
msg := types.MsgStoreCode{
Sender: cliCtx.GetFromAddress(),
WASMByteCode: wasm,
Source: viper.GetString(flagSource),
Builder: viper.GetString(flagBuilder),
InstantiatePermission: perm,
}
return msg, nil
}
// InstantiateContractCmd will instantiate a contract from previously uploaded code.
func InstantiateContractCmd(cdc *codec.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "instantiate [code_id_int64] [json_encoded_init_args]",
Use: "instantiate [code_id_int64] [json_encoded_init_args] --label [text] --admin [address,optional] --amount [coins,optional]",
Short: "Instantiate a wasm contract",
Args: cobra.RangeArgs(2, 3),
Args: cobra.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) error {
inBuf := bufio.NewReader(cmd.InOrStdin())
txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(utils.GetTxEncoder(cdc))
cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc)
// get the id of the code to instantiate
codeID, err := strconv.ParseUint(args[0], 10, 64)
msg, err := parseInstantiateArgs(args, cliCtx)
if err != nil {
return err
}
amounstStr := viper.GetString(flagAmount)
amount, err := sdk.ParseCoins(amounstStr)
if err != nil {
if err := msg.ValidateBasic(); err != nil {
return err
}
label := viper.GetString(flagLabel)
if label == "" {
return fmt.Errorf("Label is required on all contracts")
}
initMsg := args[1]
adminStr := viper.GetString(flagAdmin)
var adminAddr sdk.AccAddress
if len(adminStr) != 0 {
adminAddr, err = sdk.AccAddressFromBech32(adminStr)
if err != nil {
return sdkerrors.Wrap(err, "admin")
}
}
// build and sign the transaction, then broadcast to Tendermint
msg := types.MsgInstantiateContract{
Sender: cliCtx.GetFromAddress(),
Code: codeID,
Label: label,
InitFunds: amount,
InitMsg: []byte(initMsg),
Admin: adminAddr,
}
return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg})
},
}
@ -165,6 +153,47 @@ func InstantiateContractCmd(cdc *codec.Codec) *cobra.Command {
return cmd
}
func parseInstantiateArgs(args []string, cliCtx context.CLIContext) (types.MsgInstantiateContract, error) {
// get the id of the code to instantiate
codeID, err := strconv.ParseUint(args[0], 10, 64)
if err != nil {
return types.MsgInstantiateContract{}, err
}
amounstStr := viper.GetString(flagAmount)
amount, err := sdk.ParseCoins(amounstStr)
if err != nil {
return types.MsgInstantiateContract{}, err
}
label := viper.GetString(flagLabel)
if label == "" {
return types.MsgInstantiateContract{}, fmt.Errorf("Label is required on all contracts")
}
initMsg := args[1]
adminStr := viper.GetString(flagAdmin)
var adminAddr sdk.AccAddress
if len(adminStr) != 0 {
adminAddr, err = sdk.AccAddressFromBech32(adminStr)
if err != nil {
return types.MsgInstantiateContract{}, sdkerrors.Wrap(err, "admin")
}
}
// build and sign the transaction, then broadcast to Tendermint
msg := types.MsgInstantiateContract{
Sender: cliCtx.GetFromAddress(),
Code: codeID,
Label: label,
InitFunds: amount,
InitMsg: []byte(initMsg),
Admin: adminAddr,
}
return msg, nil
}
// ExecuteContractCmd will instantiate a contract from previously uploaded code.
func ExecuteContractCmd(cdc *codec.Codec) *cobra.Command {
cmd := &cobra.Command{

View File

@ -0,0 +1,16 @@
package client
import (
"github.com/CosmWasm/wasmd/x/wasm/client/cli"
"github.com/CosmWasm/wasmd/x/wasm/client/rest"
govclient "github.com/cosmos/cosmos-sdk/x/gov/client"
)
// ProposalHandlers define the wasm cli proposal types and rest handler.
var ProposalHandlers = []govclient.ProposalHandler{
govclient.NewProposalHandler(cli.ProposalStoreCodeCmd, rest.StoreCodeProposalHandler),
govclient.NewProposalHandler(cli.ProposalInstantiateContractCmd, rest.InstantiateProposalHandler),
govclient.NewProposalHandler(cli.ProposalMigrateContractCmd, rest.MigrateProposalHandler),
govclient.NewProposalHandler(cli.ProposalUpdateContractAdminCmd, rest.UpdateContractAdminProposalHandler),
govclient.NewProposalHandler(cli.ProposalClearContractAdminCmd, rest.ClearContractAdminProposalHandler),
}

File diff suppressed because one or more lines are too long

270
x/wasm/client/rest/gov.go Normal file
View File

@ -0,0 +1,270 @@
package rest
import (
"encoding/json"
"net/http"
"github.com/CosmWasm/wasmd/x/wasm/internal/types"
"github.com/cosmos/cosmos-sdk/client/context"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/rest"
"github.com/cosmos/cosmos-sdk/x/auth/client/utils"
"github.com/cosmos/cosmos-sdk/x/gov"
govrest "github.com/cosmos/cosmos-sdk/x/gov/client/rest"
)
type StoreCodeProposalJsonReq struct {
BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"`
Title string `json:"title" yaml:"title"`
Description string `json:"description" yaml:"description"`
Proposer sdk.AccAddress `json:"proposer" yaml:"proposer"`
Deposit sdk.Coins `json:"deposit" yaml:"deposit"`
RunAs sdk.AccAddress `json:"run_as" yaml:"run_as"`
// WASMByteCode can be raw or gzip compressed
WASMByteCode []byte `json:"wasm_byte_code" yaml:"wasm_byte_code"`
// Source is a valid absolute HTTPS URI to the contract's source code, optional
Source string `json:"source" yaml:"source"`
// Builder is a valid docker image name with tag, optional
Builder string `json:"builder" yaml:"builder"`
// InstantiatePermission to apply on contract creation, optional
InstantiatePermission *types.AccessConfig `json:"instantiate_permission" yaml:"instantiate_permission"`
}
func (s StoreCodeProposalJsonReq) Content() gov.Content {
return types.StoreCodeProposal{
WasmProposal: types.WasmProposal{
Title: s.Title,
Description: s.Description,
},
RunAs: s.RunAs,
WASMByteCode: s.WASMByteCode,
Source: s.Source,
Builder: s.Builder,
InstantiatePermission: s.InstantiatePermission,
}
}
func (s StoreCodeProposalJsonReq) GetProposer() sdk.AccAddress {
return s.Proposer
}
func (s StoreCodeProposalJsonReq) GetDeposit() sdk.Coins {
return s.Deposit
}
func (s StoreCodeProposalJsonReq) GetBaseReq() rest.BaseReq {
return s.BaseReq
}
func StoreCodeProposalHandler(cliCtx context.CLIContext) govrest.ProposalRESTHandler {
return govrest.ProposalRESTHandler{
SubRoute: "wasm_store_code",
Handler: func(w http.ResponseWriter, r *http.Request) {
var req StoreCodeProposalJsonReq
if !rest.ReadRESTReq(w, r, cliCtx.Codec, &req) {
return
}
toStdTxResponse(cliCtx, w, req)
},
}
}
type InstantiateProposalJsonReq struct {
BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"`
Title string `json:"title" yaml:"title"`
Description string `json:"description" yaml:"description"`
Proposer sdk.AccAddress `json:"proposer" yaml:"proposer"`
Deposit sdk.Coins `json:"deposit" yaml:"deposit"`
RunAs sdk.AccAddress `json:"run_as" yaml:"run_as"`
// Admin is an optional address that can execute migrations
Admin sdk.AccAddress `json:"admin,omitempty" yaml:"admin"`
Code uint64 `json:"code_id" yaml:"code_id"`
Label string `json:"label" yaml:"label"`
InitMsg json.RawMessage `json:"init_msg" yaml:"init_msg"`
InitFunds sdk.Coins `json:"init_funds" yaml:"init_funds"`
}
func (s InstantiateProposalJsonReq) Content() gov.Content {
return types.InstantiateContractProposal{
WasmProposal: types.WasmProposal{Title: s.Title, Description: s.Description},
RunAs: s.RunAs,
Admin: s.Admin,
Code: s.Code,
Label: s.Label,
InitMsg: s.InitMsg,
InitFunds: s.InitFunds,
}
}
func (s InstantiateProposalJsonReq) GetProposer() sdk.AccAddress {
return s.Proposer
}
func (s InstantiateProposalJsonReq) GetDeposit() sdk.Coins {
return s.Deposit
}
func (s InstantiateProposalJsonReq) GetBaseReq() rest.BaseReq {
return s.BaseReq
}
func InstantiateProposalHandler(cliCtx context.CLIContext) govrest.ProposalRESTHandler {
return govrest.ProposalRESTHandler{
SubRoute: "wasm_instantiate",
Handler: func(w http.ResponseWriter, r *http.Request) {
var req InstantiateProposalJsonReq
if !rest.ReadRESTReq(w, r, cliCtx.Codec, &req) {
return
}
toStdTxResponse(cliCtx, w, req)
},
}
}
type MigrateProposalJsonReq struct {
BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"`
Title string `json:"title" yaml:"title"`
Description string `json:"description" yaml:"description"`
Proposer sdk.AccAddress `json:"proposer" yaml:"proposer"`
Deposit sdk.Coins `json:"deposit" yaml:"deposit"`
Contract sdk.AccAddress `json:"contract" yaml:"contract"`
Code uint64 `json:"code_id" yaml:"code_id"`
MigrateMsg json.RawMessage `json:"msg" yaml:"msg"`
// RunAs is the role that is passed to the contract's environment
RunAs sdk.AccAddress `json:"run_as" yaml:"run_as"`
}
func (s MigrateProposalJsonReq) Content() gov.Content {
return types.MigrateContractProposal{
WasmProposal: types.WasmProposal{Title: s.Title, Description: s.Description},
Contract: s.Contract,
Code: s.Code,
MigrateMsg: s.MigrateMsg,
RunAs: s.RunAs,
}
}
func (s MigrateProposalJsonReq) GetProposer() sdk.AccAddress {
return s.Proposer
}
func (s MigrateProposalJsonReq) GetDeposit() sdk.Coins {
return s.Deposit
}
func (s MigrateProposalJsonReq) GetBaseReq() rest.BaseReq {
return s.BaseReq
}
func MigrateProposalHandler(cliCtx context.CLIContext) govrest.ProposalRESTHandler {
return govrest.ProposalRESTHandler{
SubRoute: "wasm_migrate",
Handler: func(w http.ResponseWriter, r *http.Request) {
var req MigrateProposalJsonReq
if !rest.ReadRESTReq(w, r, cliCtx.Codec, &req) {
return
}
toStdTxResponse(cliCtx, w, req)
},
}
}
type UpdateAdminJsonReq struct {
BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"`
Title string `json:"title" yaml:"title"`
Description string `json:"description" yaml:"description"`
Proposer sdk.AccAddress `json:"proposer" yaml:"proposer"`
Deposit sdk.Coins `json:"deposit" yaml:"deposit"`
NewAdmin sdk.AccAddress `json:"new_admin" yaml:"new_admin"`
Contract sdk.AccAddress `json:"contract" yaml:"contract"`
}
func (s UpdateAdminJsonReq) Content() gov.Content {
return types.UpdateAdminProposal{
WasmProposal: types.WasmProposal{Title: s.Title, Description: s.Description},
Contract: s.Contract,
NewAdmin: s.NewAdmin,
}
}
func (s UpdateAdminJsonReq) GetProposer() sdk.AccAddress {
return s.Proposer
}
func (s UpdateAdminJsonReq) GetDeposit() sdk.Coins {
return s.Deposit
}
func (s UpdateAdminJsonReq) GetBaseReq() rest.BaseReq {
return s.BaseReq
}
func UpdateContractAdminProposalHandler(cliCtx context.CLIContext) govrest.ProposalRESTHandler {
return govrest.ProposalRESTHandler{
SubRoute: "wasm_update_admin",
Handler: func(w http.ResponseWriter, r *http.Request) {
var req UpdateAdminJsonReq
if !rest.ReadRESTReq(w, r, cliCtx.Codec, &req) {
return
}
toStdTxResponse(cliCtx, w, req)
},
}
}
type ClearAdminJsonReq struct {
BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"`
Title string `json:"title" yaml:"title"`
Description string `json:"description" yaml:"description"`
Proposer sdk.AccAddress `json:"proposer" yaml:"proposer"`
Deposit sdk.Coins `json:"deposit" yaml:"deposit"`
Contract sdk.AccAddress `json:"contract" yaml:"contract"`
}
func (s ClearAdminJsonReq) Content() gov.Content {
return types.ClearAdminProposal{
WasmProposal: types.WasmProposal{Title: s.Title, Description: s.Description},
Contract: s.Contract,
}
}
func (s ClearAdminJsonReq) GetProposer() sdk.AccAddress {
return s.Proposer
}
func (s ClearAdminJsonReq) GetDeposit() sdk.Coins {
return s.Deposit
}
func (s ClearAdminJsonReq) GetBaseReq() rest.BaseReq {
return s.BaseReq
}
func ClearContractAdminProposalHandler(cliCtx context.CLIContext) govrest.ProposalRESTHandler {
return govrest.ProposalRESTHandler{
SubRoute: "wasm_clear_admin",
Handler: func(w http.ResponseWriter, r *http.Request) {
var req ClearAdminJsonReq
if !rest.ReadRESTReq(w, r, cliCtx.Codec, &req) {
return
}
toStdTxResponse(cliCtx, w, req)
},
}
}
type wasmProposalData interface {
Content() gov.Content
GetProposer() sdk.AccAddress
GetDeposit() sdk.Coins
GetBaseReq() rest.BaseReq
}
func toStdTxResponse(cliCtx context.CLIContext, w http.ResponseWriter, data wasmProposalData) {
msg := gov.NewMsgSubmitProposal(data.Content(), data.GetDeposit(), data.GetProposer())
if err := msg.ValidateBasic(); err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
baseReq := data.GetBaseReq().Sanitize()
if !baseReq.ValidateBasic(w) {
return
}
utils.WriteGenerateStdTxResponse(w, cliCtx, baseReq, []sdk.Msg{msg})
}

View File

@ -197,7 +197,7 @@ func (k Keeper) instantiate(ctx sdk.Context, codeID uint64, creator, admin sdk.A
store := ctx.KVStore(k.storeKey)
bz := store.Get(types.GetCodeKey(codeID))
if bz == nil {
return nil, sdkerrors.Wrap(types.ErrNotFound, "contract")
return nil, sdkerrors.Wrap(types.ErrNotFound, "code")
}
var codeInfo types.CodeInfo
k.cdc.MustUnmarshalBinaryBare(bz, &codeInfo)

View File

@ -47,7 +47,7 @@ func handleStoreCodeProposal(ctx sdk.Context, k Keeper, p types.StoreCodeProposa
return err
}
codeID, err := k.create(ctx, p.Creator, p.WASMByteCode, p.Source, p.Builder, p.InstantiatePermission, GovAuthorizationPolicy{})
codeID, err := k.create(ctx, p.RunAs, p.WASMByteCode, p.Source, p.Builder, p.InstantiatePermission, GovAuthorizationPolicy{})
if err != nil {
return err
}
@ -55,7 +55,7 @@ func handleStoreCodeProposal(ctx sdk.Context, k Keeper, p types.StoreCodeProposa
ourEvent := sdk.NewEvent(
sdk.EventTypeMessage,
sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName),
//sdk.NewAttribute(AttributeSigner, p.Creator.String()), // todo: creator is not signer. rename attribute?
//sdk.NewAttribute(AttributeSigner, p.RunAs.String()), // todo: creator is not signer. rename attribute?
sdk.NewAttribute(AttributeKeyCodeID, fmt.Sprintf("%d", codeID)),
)
ctx.EventManager().EmitEvent(ourEvent)
@ -67,7 +67,7 @@ func handleInstantiateProposal(ctx sdk.Context, k Keeper, p types.InstantiateCon
return err
}
contractAddr, err := k.instantiate(ctx, p.Code, p.Creator, p.Admin, p.InitMsg, p.Label, p.InitFunds, GovAuthorizationPolicy{})
contractAddr, err := k.instantiate(ctx, p.Code, p.RunAs, p.Admin, p.InitMsg, p.Label, p.InitFunds, GovAuthorizationPolicy{})
if err != nil {
return err
}
@ -75,7 +75,7 @@ func handleInstantiateProposal(ctx sdk.Context, k Keeper, p types.InstantiateCon
ourEvent := sdk.NewEvent(
sdk.EventTypeMessage,
sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName),
//sdk.NewAttribute(AttributeSigner, p.Creator.String()),
//sdk.NewAttribute(AttributeSigner, p.RunAs.String()),
sdk.NewAttribute(AttributeKeyCodeID, fmt.Sprintf("%d", p.Code)),
sdk.NewAttribute(AttributeKeyContract, contractAddr.String()),
)
@ -88,7 +88,7 @@ func handleMigrateProposal(ctx sdk.Context, k Keeper, p types.MigrateContractPro
return err
}
res, err := k.migrate(ctx, p.Contract, p.Sender, p.Code, p.MigrateMsg, GovAuthorizationPolicy{})
res, err := k.migrate(ctx, p.Contract, p.RunAs, p.Code, p.MigrateMsg, GovAuthorizationPolicy{})
if err != nil {
return err
}
@ -96,7 +96,7 @@ func handleMigrateProposal(ctx sdk.Context, k Keeper, p types.MigrateContractPro
ourEvent := sdk.NewEvent(
sdk.EventTypeMessage,
sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName),
//sdk.NewAttribute(AttributeSigner, p.Creator.String()),
//sdk.NewAttribute(AttributeSigner, p.RunAs.String()),
sdk.NewAttribute(AttributeKeyContract, p.Contract.String()),
)
ctx.EventManager().EmitEvents(append(res.Events, ourEvent))
@ -108,14 +108,14 @@ func handleUpdateAdminProposal(ctx sdk.Context, k Keeper, p types.UpdateAdminPro
return err
}
if err := k.setContractAdmin(ctx, p.Contract, p.Sender, p.NewAdmin, GovAuthorizationPolicy{}); err != nil {
if err := k.setContractAdmin(ctx, p.Contract, nil, p.NewAdmin, GovAuthorizationPolicy{}); err != nil {
return err
}
ourEvent := sdk.NewEvent(
sdk.EventTypeMessage,
sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName),
//sdk.NewAttribute(AttributeSigner, p.Creator.String()),
//sdk.NewAttribute(AttributeSigner, p.RunAs.String()),
sdk.NewAttribute(AttributeKeyContract, p.Contract.String()),
)
ctx.EventManager().EmitEvent(ourEvent)
@ -127,13 +127,13 @@ func handleClearAdminProposal(ctx sdk.Context, k Keeper, p types.ClearAdminPropo
return err
}
if err := k.setContractAdmin(ctx, p.Contract, p.Sender, nil, GovAuthorizationPolicy{}); err != nil {
if err := k.setContractAdmin(ctx, p.Contract, nil, nil, GovAuthorizationPolicy{}); err != nil {
return err
}
ourEvent := sdk.NewEvent(
sdk.EventTypeMessage,
sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName),
//sdk.NewAttribute(AttributeSigner, p.Creator.String()),
//sdk.NewAttribute(AttributeSigner, p.RunAs.String()),
sdk.NewAttribute(AttributeKeyContract, p.Contract.String()),
)
ctx.EventManager().EmitEvent(ourEvent)

View File

@ -30,7 +30,7 @@ func TestStoreCodeProposal(t *testing.T) {
var anyAddress sdk.AccAddress = make([]byte, sdk.AddrLen)
src := types.StoreCodeProposalFixture(func(p *types.StoreCodeProposal) {
p.Creator = anyAddress
p.RunAs = anyAddress
p.WASMByteCode = wasmCode
p.Source = "https://example.com/mysource"
p.Builder = "foo/bar:v0.0.0"
@ -80,7 +80,7 @@ func TestInstantiateProposal(t *testing.T) {
)
src := types.InstantiateContractProposalFixture(func(p *types.InstantiateContractProposal) {
p.Code = 1
p.Creator = oneAddress
p.RunAs = oneAddress
p.Admin = otherAddress
p.Label = "testing"
})
@ -152,7 +152,7 @@ func TestMigrateProposal(t *testing.T) {
Code: 2,
Contract: contractAddr,
MigrateMsg: migMsgBz,
Sender: otherAddress,
RunAs: otherAddress,
}
// when stored
@ -176,7 +176,6 @@ func TestMigrateProposal(t *testing.T) {
func TestAdminProposals(t *testing.T) {
var (
anyAddress sdk.AccAddress = bytes.Repeat([]byte{0x1}, sdk.AddrLen)
otherAddress sdk.AccAddress = bytes.Repeat([]byte{0x2}, sdk.AddrLen)
contractAddr = contractAddress(1, 1)
)
@ -196,7 +195,6 @@ func TestAdminProposals(t *testing.T) {
Description: "Bar",
},
Contract: contractAddr,
Sender: anyAddress,
NewAdmin: otherAddress,
},
expAdmin: otherAddress,
@ -211,7 +209,6 @@ func TestAdminProposals(t *testing.T) {
Description: "Bar",
},
Contract: contractAddr,
Sender: anyAddress,
NewAdmin: otherAddress,
},
expAdmin: otherAddress,
@ -224,7 +221,6 @@ func TestAdminProposals(t *testing.T) {
Description: "Bar",
},
Contract: contractAddr,
Sender: anyAddress,
},
expAdmin: nil,
},
@ -238,7 +234,6 @@ func TestAdminProposals(t *testing.T) {
Description: "Bar",
},
Contract: contractAddr,
Sender: anyAddress,
},
expAdmin: nil,
},

View File

@ -0,0 +1,219 @@
{
"genesis_time": "2020-07-13T07:49:08.2945876Z",
"chain_id": "testing",
"consensus_params": {
"block": {
"max_bytes": "22020096",
"max_gas": "-1",
"time_iota_ms": "1000"
},
"evidence": {
"max_age_num_blocks": "100000",
"max_age_duration": "172800000000000"
},
"validator": {
"pub_key_types": [
"ed25519"
]
}
},
"app_hash": "",
"app_state": {
"upgrade": {},
"evidence": {
"params": {
"max_evidence_age": "120000000000"
},
"evidence": []
},
"supply": {
"supply": []
},
"mint": {
"minter": {
"inflation": "0.130000000000000000",
"annual_provisions": "0.000000000000000000"
},
"params": {
"mint_denom": "ustake",
"inflation_rate_change": "0.130000000000000000",
"inflation_max": "0.200000000000000000",
"inflation_min": "0.070000000000000000",
"goal_bonded": "0.670000000000000000",
"blocks_per_year": "6311520"
}
},
"gov": {
"starting_proposal_id": "1",
"deposits": null,
"votes": null,
"proposals": null,
"deposit_params": {
"min_deposit": [
{
"denom": "ustake",
"amount": "1"
}
],
"max_deposit_period": "172800000000000"
},
"voting_params": {
"voting_period": "60000000000",
"voting_period_desc": "1minute"
},
"tally_params": {
"quorum": "0.000000000000000001",
"threshold": "0.000000000000000001",
"veto": "0.334000000000000000"
}
},
"slashing": {
"params": {
"signed_blocks_window": "100",
"min_signed_per_window": "0.500000000000000000",
"downtime_jail_duration": "600000000000",
"slash_fraction_double_sign": "0.050000000000000000",
"slash_fraction_downtime": "0.010000000000000000"
},
"signing_infos": {},
"missed_blocks": {}
},
"wasm": {
"params": {
"upload_access": {
"type": 3,
"address": ""
},
"instantiate_default_permission": 3
},
"codes": null,
"contracts": null,
"sequences": null
},
"bank": {
"send_enabled": true
},
"distribution": {
"params": {
"community_tax": "0.020000000000000000",
"base_proposer_reward": "0.010000000000000000",
"bonus_proposer_reward": "0.040000000000000000",
"withdraw_addr_enabled": true
},
"fee_pool": {
"community_pool": []
},
"delegator_withdraw_infos": [],
"previous_proposer": "",
"outstanding_rewards": [],
"validator_accumulated_commissions": [],
"validator_historical_rewards": [],
"validator_current_rewards": [],
"delegator_starting_infos": [],
"validator_slash_events": []
},
"crisis": {
"constant_fee": {
"denom": "ustake",
"amount": "1000"
}
},
"genutil": {
"gentxs": [
{
"type": "cosmos-sdk/StdTx",
"value": {
"msg": [
{
"type": "cosmos-sdk/MsgCreateValidator",
"value": {
"description": {
"moniker": "testing",
"identity": "",
"website": "",
"security_contact": "",
"details": ""
},
"commission": {
"rate": "0.100000000000000000",
"max_rate": "0.200000000000000000",
"max_change_rate": "0.010000000000000000"
},
"min_self_delegation": "1",
"delegator_address": "cosmos1ve557a5g9yw2g2z57js3pdmcvd5my6g8ze20np",
"validator_address": "cosmosvaloper1ve557a5g9yw2g2z57js3pdmcvd5my6g88d76lj",
"pubkey": "cosmosvalconspub1zcjduepqddfln4tujr2p8actpgqz4h2xnls9y7tu9c9tu5lqkdglmdjalzuqah4neg",
"value": {
"denom": "ustake",
"amount": "250000000"
}
}
}
],
"fee": {
"amount": [],
"gas": "200000"
},
"signatures": [
{
"pub_key": {
"type": "tendermint/PubKeySecp256k1",
"value": "A//cqZxkpH1re0VrHBtH308nb5t8K+Y/hF0GeRdRBmaJ"
},
"signature": "5QEEIuUVQTEBMuAtOOHnnKo6rPsIbmfzUxUqRnDFERVqwVr1Kg+ex4f/UGIK0yrOAvOG8zDADwFP4yF8lw+o5g=="
}
],
"memo": "836fc54e9cad58f4ed6420223ec6290f75342afa@172.17.0.2:26656"
}
}
]
},
"auth": {
"params": {
"max_memo_characters": "256",
"tx_sig_limit": "7",
"tx_size_cost_per_byte": "10",
"sig_verify_cost_ed25519": "590",
"sig_verify_cost_secp256k1": "1000"
},
"accounts": [
{
"type": "cosmos-sdk/Account",
"value": {
"address": "cosmos1ve557a5g9yw2g2z57js3pdmcvd5my6g8ze20np",
"coins": [
{
"denom": "ucosm",
"amount": "1000000000"
},
{
"denom": "ustake",
"amount": "1000000000"
}
],
"public_key": "",
"account_number": 0,
"sequence": 0
}
}
]
},
"params": null,
"staking": {
"params": {
"unbonding_time": "1814400000000000",
"max_validators": 100,
"max_entries": 7,
"historical_entries": 0,
"bond_denom": "ustake"
},
"last_total_power": "0",
"last_validator_powers": null,
"validators": null,
"delegations": null,
"unbonding_delegations": null,
"redelegations": null,
"exported": false
}
}
}

View File

@ -13,11 +13,11 @@ func RegisterCodec(cdc *codec.Codec) {
cdc.RegisterConcrete(&MsgUpdateAdmin{}, "wasm/update-contract-admin", nil)
cdc.RegisterConcrete(&MsgClearAdmin{}, "wasm/clear-contract-admin", nil)
cdc.RegisterConcrete(&StoreCodeProposal{}, "wasm/store-proposal", nil)
cdc.RegisterConcrete(&InstantiateContractProposal{}, "wasm/instantiate-proposal", nil)
cdc.RegisterConcrete(&MigrateContractProposal{}, "wasm/migrate-proposal", nil)
cdc.RegisterConcrete(&UpdateAdminProposal{}, "wasm/update-admin-proposal", nil)
cdc.RegisterConcrete(&ClearAdminProposal{}, "wasm/clear-admin-proposal", nil)
cdc.RegisterConcrete(StoreCodeProposal{}, "wasm/store-proposal", nil)
cdc.RegisterConcrete(InstantiateContractProposal{}, "wasm/instantiate-proposal", nil)
cdc.RegisterConcrete(MigrateContractProposal{}, "wasm/migrate-proposal", nil)
cdc.RegisterConcrete(UpdateAdminProposal{}, "wasm/update-admin-proposal", nil)
cdc.RegisterConcrete(ClearAdminProposal{}, "wasm/clear-admin-proposal", nil)
}
// ModuleCdc generic sealed codec to be used throughout module

View File

@ -1,6 +1,7 @@
package types
import (
"encoding/base64"
"encoding/json"
"fmt"
"strings"
@ -26,6 +27,19 @@ var DefaultEnabledProposals = map[string]struct{}{
ProposalTypeClearAdmin: {},
}
func init() { // register new content types with the sdk
govtypes.RegisterProposalType(ProposalTypeStoreCode)
govtypes.RegisterProposalType(ProposalTypeStoreInstantiateContract)
govtypes.RegisterProposalType(ProposalTypeMigrateContract)
govtypes.RegisterProposalType(ProposalTypeUpdateAdmin)
govtypes.RegisterProposalType(ProposalTypeClearAdmin)
govtypes.RegisterProposalTypeCodec(StoreCodeProposal{}, "wasm/store-proposal")
govtypes.RegisterProposalTypeCodec(InstantiateContractProposal{}, "wasm/instantiate-proposal")
govtypes.RegisterProposalTypeCodec(MigrateContractProposal{}, "wasm/migrate-proposal")
govtypes.RegisterProposalTypeCodec(UpdateAdminProposal{}, "wasm/update-admin-proposal")
govtypes.RegisterProposalTypeCodec(ClearAdminProposal{}, "wasm/clear-admin-proposal")
}
type WasmProposal struct {
Title string `json:"title" yaml:"title"`
Description string `json:"description" yaml:"description"`
@ -65,16 +79,16 @@ func (p WasmProposal) ValidateBasic() error {
type StoreCodeProposal struct {
WasmProposal
// Creator is the address that "owns" the code object
Creator sdk.AccAddress `json:"creator" yaml:"creator"`
// RunAs is the address that "owns" the code object
RunAs sdk.AccAddress `json:"run_as"`
// WASMByteCode can be raw or gzip compressed
WASMByteCode []byte `json:"wasm_byte_code" yaml:"wasm_byte_code"`
WASMByteCode []byte `json:"wasm_byte_code"`
// Source is a valid absolute HTTPS URI to the contract's source code, optional
Source string `json:"source" yaml:"source"`
Source string `json:"source"`
// Builder is a valid docker image name with tag, optional
Builder string `json:"builder" yaml:"builder"`
Builder string `json:"builder"`
// InstantiatePermission to apply on contract creation, optional
InstantiatePermission *AccessConfig `json:"instantiate_permission" yaml:"instantiate_permission"`
InstantiatePermission *AccessConfig `json:"instantiate_permission"`
}
// ProposalType returns the type
@ -85,8 +99,8 @@ func (p StoreCodeProposal) ValidateBasic() error {
if err := p.WasmProposal.ValidateBasic(); err != nil {
return err
}
if err := sdk.VerifyAddressFormat(p.Creator); err != nil {
return err
if err := sdk.VerifyAddressFormat(p.RunAs); err != nil {
return sdkerrors.Wrap(err, "run as")
}
if err := validateWasmCode(p.WASMByteCode); err != nil {
@ -113,23 +127,41 @@ func (p StoreCodeProposal) String() string {
return fmt.Sprintf(`Store Code Proposal:
Title: %s
Description: %s
Creator: %s
Run as: %s
WasmCode: %X
Source: %s
Builder: %s
`, p.Title, p.Description, p.Creator, p.WASMByteCode, p.Source, p.Builder)
`, p.Title, p.Description, p.RunAs, p.WASMByteCode, p.Source, p.Builder)
}
func (p StoreCodeProposal) MarshalYAML() (interface{}, error) {
return struct {
WasmProposal `yaml:",inline"`
RunAs sdk.AccAddress `yaml:"run_as"`
WASMByteCode string `yaml:"wasm_byte_code"`
Source string `yaml:"source"`
Builder string `yaml:"builder"`
InstantiatePermission *AccessConfig `yaml:"instantiate_permission"`
}{
WasmProposal: p.WasmProposal,
RunAs: p.RunAs,
WASMByteCode: base64.StdEncoding.EncodeToString(p.WASMByteCode),
Source: p.Source,
Builder: p.Builder,
InstantiatePermission: p.InstantiatePermission,
}, nil
}
type InstantiateContractProposal struct {
WasmProposal
// Creator is the address that pays the init funds
Creator sdk.AccAddress `json:"sender" yaml:"sender"`
// RunAs is the address that pays the init funds
RunAs sdk.AccAddress `json:"run_as"`
// Admin is an optional address that can execute migrations
Admin sdk.AccAddress `json:"admin,omitempty" yaml:"admin"`
Code uint64 `json:"code_id" yaml:"code_id"`
Label string `json:"label" yaml:"label"`
InitMsg json.RawMessage `json:"init_msg" yaml:"init_msg"`
InitFunds sdk.Coins `json:"init_funds" yaml:"init_funds"`
Admin sdk.AccAddress `json:"admin,omitempty"`
Code uint64 `json:"code_id"`
Label string `json:"label"`
InitMsg json.RawMessage `json:"init_msg"`
InitFunds sdk.Coins `json:"init_funds"`
}
// ProposalType returns the type
@ -142,12 +174,12 @@ func (p InstantiateContractProposal) ValidateBasic() error {
if err := p.WasmProposal.ValidateBasic(); err != nil {
return err
}
if err := sdk.VerifyAddressFormat(p.Creator); err != nil {
return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "creator is required")
if err := sdk.VerifyAddressFormat(p.RunAs); err != nil {
return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "run as")
}
if p.Code == 0 {
return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "code_id is required")
return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "code id is required")
}
if err := validateLabel(p.Label); err != nil {
@ -172,23 +204,42 @@ func (p InstantiateContractProposal) String() string {
return fmt.Sprintf(`Instantiate Code Proposal:
Title: %s
Description: %s
Creator: %s
Run as: %s
Admin: %s
Code id: %d
Label: %s
InitMsg: %q
InitFunds: %s
`, p.Title, p.Description, p.Creator, p.Admin, p.Code, p.Label, p.InitMsg, p.InitFunds)
`, p.Title, p.Description, p.RunAs, p.Admin, p.Code, p.Label, p.InitMsg, p.InitFunds)
}
func (p InstantiateContractProposal) MarshalYAML() (interface{}, error) {
return struct {
WasmProposal `yaml:",inline"`
RunAs sdk.AccAddress `yaml:"run_as"`
Admin sdk.AccAddress `yaml:"admin"`
Code uint64 `yaml:"code_id"`
Label string `yaml:"label"`
InitMsg string `yaml:"init_msg"`
InitFunds sdk.Coins `yaml:"init_funds"`
}{
WasmProposal: p.WasmProposal,
RunAs: p.RunAs,
Admin: p.Admin,
Code: p.Code,
Label: p.Label,
InitMsg: string(p.InitMsg),
InitFunds: p.InitFunds,
}, nil
}
type MigrateContractProposal struct {
WasmProposal
Contract sdk.AccAddress `json:"contract" yaml:"contract"`
Code uint64 `json:"code_id" yaml:"code_id"`
MigrateMsg json.RawMessage `json:"msg" yaml:"msg"`
// Sender is the role that is passed to the contract's environment
Sender sdk.AccAddress `json:"sender" yaml:"sender"`
WasmProposal `yaml:",inline"`
Contract sdk.AccAddress `json:"contract"`
Code uint64 `json:"code_id"`
MigrateMsg json.RawMessage `json:"msg"`
// RunAs is the address that is passed to the contract's environment as sender
RunAs sdk.AccAddress `json:"run_as"`
}
// ProposalType returns the type
@ -205,8 +256,8 @@ func (p MigrateContractProposal) ValidateBasic() error {
if err := sdk.VerifyAddressFormat(p.Contract); err != nil {
return sdkerrors.Wrap(err, "contract")
}
if err := sdk.VerifyAddressFormat(p.Sender); err != nil {
return sdkerrors.Wrap(err, "sender")
if err := sdk.VerifyAddressFormat(p.RunAs); err != nil {
return sdkerrors.Wrap(err, "run as")
}
return nil
}
@ -218,17 +269,31 @@ func (p MigrateContractProposal) String() string {
Description: %s
Contract: %s
Code id: %d
Sender: %s
Run as: %s
MigrateMsg %q
`, p.Title, p.Description, p.Contract, p.Code, p.Sender, p.MigrateMsg)
`, p.Title, p.Description, p.Contract, p.Code, p.RunAs, p.MigrateMsg)
}
func (p MigrateContractProposal) MarshalYAML() (interface{}, error) {
return struct {
WasmProposal `yaml:",inline"`
Contract sdk.AccAddress `yaml:"contract"`
Code uint64 `yaml:"code_id"`
MigrateMsg string `yaml:"msg"`
RunAs sdk.AccAddress `yaml:"run_as"`
}{
WasmProposal: p.WasmProposal,
Contract: p.Contract,
Code: p.Code,
MigrateMsg: string(p.MigrateMsg),
RunAs: p.RunAs,
}, nil
}
type UpdateAdminProposal struct {
WasmProposal
NewAdmin sdk.AccAddress `json:"new_admin" yaml:"new_admin"`
Contract sdk.AccAddress `json:"contract" yaml:"contract"`
// Sender is the role that is passed to the contract's environment
Sender sdk.AccAddress `json:"sender" yaml:"sender"`
WasmProposal `yaml:",inline"`
NewAdmin sdk.AccAddress `json:"new_admin" yaml:"new_admin"`
Contract sdk.AccAddress `json:"contract" yaml:"contract"`
}
// ProposalType returns the type
@ -245,9 +310,6 @@ func (p UpdateAdminProposal) ValidateBasic() error {
if err := sdk.VerifyAddressFormat(p.NewAdmin); err != nil {
return sdkerrors.Wrap(err, "new admin")
}
if err := sdk.VerifyAddressFormat(p.Sender); err != nil {
return sdkerrors.Wrap(err, "sender")
}
return nil
}
@ -257,17 +319,14 @@ func (p UpdateAdminProposal) String() string {
Title: %s
Description: %s
Contract: %s
Sender: %s
New Admin: %s
`, p.Title, p.Description, p.Contract, p.Sender, p.NewAdmin)
`, p.Title, p.Description, p.Contract, p.NewAdmin)
}
type ClearAdminProposal struct {
WasmProposal
WasmProposal `yaml:",inline"`
Contract sdk.AccAddress `json:"contract" yaml:"contract"`
// Sender is the role that is passed to the contract's environment
Sender sdk.AccAddress `json:"sender" yaml:"sender"`
}
// ProposalType returns the type
@ -281,9 +340,6 @@ func (p ClearAdminProposal) ValidateBasic() error {
if err := sdk.VerifyAddressFormat(p.Contract); err != nil {
return sdkerrors.Wrap(err, "contract")
}
if err := sdk.VerifyAddressFormat(p.Sender); err != nil {
return sdkerrors.Wrap(err, "sender")
}
return nil
}
@ -293,6 +349,5 @@ func (p ClearAdminProposal) String() string {
Title: %s
Description: %s
Contract: %s
Sender: %s
`, p.Title, p.Description, p.Contract, p.Sender)
`, p.Title, p.Description, p.Contract)
}

View File

@ -10,6 +10,7 @@ import (
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"gopkg.in/yaml.v2"
)
func TestValidateWasmProposal(t *testing.T) {
@ -119,15 +120,15 @@ func TestValidateStoreCodeProposal(t *testing.T) {
}),
expErr: true,
},
"creator missing": {
"run_as missing": {
src: StoreCodeProposalFixture(func(p *StoreCodeProposal) {
p.Creator = nil
p.RunAs = nil
}),
expErr: true,
},
"creator invalid": {
"run_as invalid": {
src: StoreCodeProposalFixture(func(p *StoreCodeProposal) {
p.Creator = invalidAddress
p.RunAs = invalidAddress
}),
expErr: true,
},
@ -207,15 +208,15 @@ func TestValidateInstantiateContractProposal(t *testing.T) {
}),
expErr: true,
},
"creator missing": {
"run_as missing": {
src: InstantiateContractProposalFixture(func(p *InstantiateContractProposal) {
p.Creator = nil
p.RunAs = nil
}),
expErr: true,
},
"creator invalid": {
"run_as invalid": {
src: InstantiateContractProposalFixture(func(p *InstantiateContractProposal) {
p.Creator = invalidAddress
p.RunAs = invalidAddress
}),
expErr: true,
},
@ -303,15 +304,15 @@ func TestValidateMigrateContractProposal(t *testing.T) {
}),
expErr: true,
},
"sender missing": {
"run_as missing": {
src: MigrateContractProposalFixture(func(p *MigrateContractProposal) {
p.Sender = nil
p.RunAs = nil
}),
expErr: true,
},
"sender invalid": {
"run_as invalid": {
src: MigrateContractProposalFixture(func(p *MigrateContractProposal) {
p.Sender = invalidAddress
p.RunAs = invalidAddress
}),
expErr: true,
},
@ -370,18 +371,6 @@ func TestValidateUpdateAdminProposal(t *testing.T) {
}),
expErr: true,
},
"sender missing": {
src: UpdateAdminProposalFixture(func(p *UpdateAdminProposal) {
p.Sender = nil
}),
expErr: true,
},
"sender invalid": {
src: UpdateAdminProposalFixture(func(p *UpdateAdminProposal) {
p.Sender = invalidAddress
}),
expErr: true,
},
}
for msg, spec := range specs {
t.Run(msg, func(t *testing.T) {
@ -425,18 +414,6 @@ func TestValidateClearAdminProposal(t *testing.T) {
}),
expErr: true,
},
"sender missing": {
src: ClearAdminProposalFixture(func(p *ClearAdminProposal) {
p.Sender = nil
}),
expErr: true,
},
"sender invalid": {
src: ClearAdminProposalFixture(func(p *ClearAdminProposal) {
p.Sender = invalidAddress
}),
expErr: true,
},
}
for msg, spec := range specs {
t.Run(msg, func(t *testing.T) {
@ -462,7 +439,7 @@ func TestProposalStrings(t *testing.T) {
exp: `Store Code Proposal:
Title: Foo
Description: Bar
Creator: cosmos1qyqszqgpqyqszqgpqyqszqgpqyqszqgpjnp7du
Run as: cosmos1qyqszqgpqyqszqgpqyqszqgpqyqszqgpjnp7du
WasmCode: 0102030405060708090A
Source: https://example.com/code
Builder: foo/bar:latest
@ -475,7 +452,7 @@ func TestProposalStrings(t *testing.T) {
exp: `Instantiate Code Proposal:
Title: Foo
Description: Bar
Creator: cosmos1qyqszqgpqyqszqgpqyqszqgpqyqszqgpjnp7du
Run as: cosmos1qyqszqgpqyqszqgpqyqszqgpqyqszqgpjnp7du
Admin: cosmos1qyqszqgpqyqszqgpqyqszqgpqyqszqgpjnp7du
Code id: 1
Label: testing
@ -488,7 +465,7 @@ func TestProposalStrings(t *testing.T) {
exp: `Instantiate Code Proposal:
Title: Foo
Description: Bar
Creator: cosmos1qyqszqgpqyqszqgpqyqszqgpqyqszqgpjnp7du
Run as: cosmos1qyqszqgpqyqszqgpqyqszqgpqyqszqgpjnp7du
Admin: cosmos1qyqszqgpqyqszqgpqyqszqgpqyqszqgpjnp7du
Code id: 1
Label: testing
@ -501,7 +478,7 @@ func TestProposalStrings(t *testing.T) {
exp: `Instantiate Code Proposal:
Title: Foo
Description: Bar
Creator: cosmos1qyqszqgpqyqszqgpqyqszqgpqyqszqgpjnp7du
Run as: cosmos1qyqszqgpqyqszqgpqyqszqgpqyqszqgpjnp7du
Admin:
Code id: 1
Label: testing
@ -516,7 +493,7 @@ func TestProposalStrings(t *testing.T) {
Description: Bar
Contract: cosmos18vd8fpwxzck93qlwghaj6arh4p7c5n89uzcee5
Code id: 1
Sender: cosmos1qyqszqgpqyqszqgpqyqszqgpqyqszqgpjnp7du
Run as: cosmos1qyqszqgpqyqszqgpqyqszqgpqyqszqgpjnp7du
MigrateMsg "{\"verifier\":\"cosmos1qyqszqgpqyqszqgpqyqszqgpqyqszqgpjnp7du\"}"
`,
},
@ -526,7 +503,6 @@ func TestProposalStrings(t *testing.T) {
Title: Foo
Description: Bar
Contract: cosmos18vd8fpwxzck93qlwghaj6arh4p7c5n89uzcee5
Sender: cosmos1qyqszqgpqyqszqgpqyqszqgpqyqszqgpjnp7du
New Admin: cosmos1qyqszqgpqyqszqgpqyqszqgpqyqszqgpjnp7du
`,
},
@ -536,7 +512,6 @@ func TestProposalStrings(t *testing.T) {
Title: Foo
Description: Bar
Contract: cosmos18vd8fpwxzck93qlwghaj6arh4p7c5n89uzcee5
Sender: cosmos1qyqszqgpqyqszqgpqyqszqgpqyqszqgpjnp7du
`,
},
}
@ -545,5 +520,99 @@ func TestProposalStrings(t *testing.T) {
assert.Equal(t, spec.exp, spec.src.String())
})
}
}
func TestProposalYaml(t *testing.T) {
specs := map[string]struct {
src gov.Content
exp string
}{
"store code": {
src: StoreCodeProposalFixture(func(p *StoreCodeProposal) {
p.WASMByteCode = []byte{01, 02, 03, 04, 05, 06, 07, 0x08, 0x09, 0x0a}
}),
exp: `title: Foo
description: Bar
run_as: cosmos1qyqszqgpqyqszqgpqyqszqgpqyqszqgpjnp7du
wasm_byte_code: AQIDBAUGBwgJCg==
source: https://example.com/code
builder: foo/bar:latest
instantiate_permission: null
`,
},
"instantiate contract": {
src: InstantiateContractProposalFixture(func(p *InstantiateContractProposal) {
p.InitFunds = sdk.Coins{{Denom: "foo", Amount: sdk.NewInt(1)}, {Denom: "bar", Amount: sdk.NewInt(2)}}
}),
exp: `title: Foo
description: Bar
run_as: cosmos1qyqszqgpqyqszqgpqyqszqgpqyqszqgpjnp7du
admin: cosmos1qyqszqgpqyqszqgpqyqszqgpqyqszqgpjnp7du
code_id: 1
label: testing
init_msg: '{"verifier":"cosmos1qyqszqgpqyqszqgpqyqszqgpqyqszqgpjnp7du","beneficiary":"cosmos1qyqszqgpqyqszqgpqyqszqgpqyqszqgpjnp7du"}'
init_funds:
- denom: foo
amount: "1"
- denom: bar
amount: "2"
`,
},
"instantiate contract without funds": {
src: InstantiateContractProposalFixture(func(p *InstantiateContractProposal) { p.InitFunds = nil }),
exp: `title: Foo
description: Bar
run_as: cosmos1qyqszqgpqyqszqgpqyqszqgpqyqszqgpjnp7du
admin: cosmos1qyqszqgpqyqszqgpqyqszqgpqyqszqgpjnp7du
code_id: 1
label: testing
init_msg: '{"verifier":"cosmos1qyqszqgpqyqszqgpqyqszqgpqyqszqgpjnp7du","beneficiary":"cosmos1qyqszqgpqyqszqgpqyqszqgpqyqszqgpjnp7du"}'
init_funds: []
`,
},
"instantiate contract without admin": {
src: InstantiateContractProposalFixture(func(p *InstantiateContractProposal) { p.Admin = nil }),
exp: `title: Foo
description: Bar
run_as: cosmos1qyqszqgpqyqszqgpqyqszqgpqyqszqgpjnp7du
admin: ""
code_id: 1
label: testing
init_msg: '{"verifier":"cosmos1qyqszqgpqyqszqgpqyqszqgpqyqszqgpjnp7du","beneficiary":"cosmos1qyqszqgpqyqszqgpqyqszqgpqyqszqgpjnp7du"}'
init_funds: []
`,
},
"migrate contract": {
src: MigrateContractProposalFixture(),
exp: `title: Foo
description: Bar
contract: cosmos18vd8fpwxzck93qlwghaj6arh4p7c5n89uzcee5
code_id: 1
msg: '{"verifier":"cosmos1qyqszqgpqyqszqgpqyqszqgpqyqszqgpjnp7du"}'
run_as: cosmos1qyqszqgpqyqszqgpqyqszqgpqyqszqgpjnp7du
`,
},
"update admin": {
src: UpdateAdminProposalFixture(),
exp: `title: Foo
description: Bar
new_admin: cosmos1qyqszqgpqyqszqgpqyqszqgpqyqszqgpjnp7du
contract: cosmos18vd8fpwxzck93qlwghaj6arh4p7c5n89uzcee5
`,
},
"clear admin": {
src: ClearAdminProposalFixture(),
exp: `title: Foo
description: Bar
contract: cosmos18vd8fpwxzck93qlwghaj6arh4p7c5n89uzcee5
`,
},
}
for msg, spec := range specs {
t.Run(msg, func(t *testing.T) {
v, err := yaml.Marshal(&spec.src)
require.NoError(t, err)
assert.Equal(t, spec.exp, string(v))
})
}
}

View File

@ -119,7 +119,7 @@ func StoreCodeProposalFixture(mutators ...func(*StoreCodeProposal)) StoreCodePro
Title: "Foo",
Description: "Bar",
},
Creator: anyValidAddress,
RunAs: anyValidAddress,
WASMByteCode: []byte{0x0},
Source: "https://example.com/code",
Builder: "foo/bar:latest",
@ -152,7 +152,7 @@ func InstantiateContractProposalFixture(mutators ...func(p *InstantiateContractP
Title: "Foo",
Description: "Bar",
},
Creator: anyValidAddress,
RunAs: anyValidAddress,
Admin: anyValidAddress,
Code: 1,
Label: "testing",
@ -192,7 +192,7 @@ func MigrateContractProposalFixture(mutators ...func(p *MigrateContractProposal)
Contract: contractAddr,
Code: 1,
MigrateMsg: migMsgBz,
Sender: anyValidAddress,
RunAs: anyValidAddress,
}
for _, m := range mutators {
@ -216,7 +216,6 @@ func UpdateAdminProposalFixture(mutators ...func(p *UpdateAdminProposal)) Update
},
NewAdmin: anyValidAddress,
Contract: contractAddr,
Sender: anyValidAddress,
}
for _, m := range mutators {
m(&p)
@ -225,8 +224,6 @@ func UpdateAdminProposalFixture(mutators ...func(p *UpdateAdminProposal)) Update
}
func ClearAdminProposalFixture(mutators ...func(p *ClearAdminProposal)) ClearAdminProposal {
var anyValidAddress sdk.AccAddress = bytes.Repeat([]byte{0x1}, sdk.AddrLen)
contractAddr, err := sdk.AccAddressFromBech32("cosmos18vd8fpwxzck93qlwghaj6arh4p7c5n89uzcee5")
if err != nil {
panic(err)
@ -238,7 +235,6 @@ func ClearAdminProposalFixture(mutators ...func(p *ClearAdminProposal)) ClearAdm
Description: "Bar",
},
Contract: contractAddr,
Sender: anyValidAddress,
}
for _, m := range mutators {
m(&p)