github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/x/wasm/types/proposal.go (about)

     1  package types
     2  
     3  import (
     4  	"encoding/base64"
     5  	"fmt"
     6  	"strings"
     7  
     8  	sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types"
     9  	sdkerrors "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types/errors"
    10  	govtypes "github.com/fibonacci-chain/fbc/x/gov/types"
    11  )
    12  
    13  type ProposalType string
    14  
    15  const (
    16  	ProposalTypeStoreCode                           ProposalType = "StoreCode"
    17  	ProposalTypeInstantiateContract                 ProposalType = "InstantiateContract"
    18  	ProposalTypeMigrateContract                     ProposalType = "MigrateContract"
    19  	ProposalTypeSudoContract                        ProposalType = "SudoContract"
    20  	ProposalTypeExecuteContract                     ProposalType = "ExecuteContract"
    21  	ProposalTypeUpdateAdmin                         ProposalType = "UpdateAdmin"
    22  	ProposalTypeClearAdmin                          ProposalType = "ClearAdmin"
    23  	ProposalTypePinCodes                            ProposalType = "PinCodes"
    24  	ProposalTypeUnpinCodes                          ProposalType = "UnpinCodes"
    25  	ProposalTypeUpdateInstantiateConfig             ProposalType = "UpdateInstantiateConfig"
    26  	ProposalTypeUpdateDeploymentWhitelist           ProposalType = "UpdateDeploymentWhitelist"
    27  	ProposalTypeUpdateWasmContractMethodBlockedList ProposalType = "UpdateWasmContractMethodBlockedList"
    28  )
    29  
    30  // DisableAllProposals contains no wasm gov types.
    31  var DisableAllProposals []ProposalType
    32  
    33  // EnableAllProposals contains all wasm gov types as keys.
    34  var EnableAllProposals = []ProposalType{
    35  	ProposalTypeStoreCode,
    36  	ProposalTypeInstantiateContract,
    37  	ProposalTypeMigrateContract,
    38  	ProposalTypeSudoContract,
    39  	ProposalTypeExecuteContract,
    40  	ProposalTypeUpdateAdmin,
    41  	ProposalTypeClearAdmin,
    42  	ProposalTypePinCodes,
    43  	ProposalTypeUnpinCodes,
    44  	ProposalTypeUpdateInstantiateConfig,
    45  	ProposalTypeUpdateDeploymentWhitelist,
    46  	ProposalTypeUpdateWasmContractMethodBlockedList,
    47  }
    48  
    49  // NecessaryProposals contains necessary wasm gov types as keys.
    50  var NecessaryProposals = []ProposalType{
    51  	ProposalTypeUpdateAdmin,
    52  	ProposalTypeClearAdmin,
    53  	ProposalTypeMigrateContract,
    54  	ProposalTypePinCodes,
    55  	ProposalTypeUnpinCodes,
    56  	ProposalTypeUpdateDeploymentWhitelist,
    57  	ProposalTypeUpdateWasmContractMethodBlockedList,
    58  }
    59  
    60  // ConvertToProposals maps each key to a ProposalType and returns a typed list.
    61  // If any string is not a valid type (in this file), then return an error
    62  func ConvertToProposals(keys []string) ([]ProposalType, error) {
    63  	valid := make(map[string]bool, len(EnableAllProposals))
    64  	for _, key := range EnableAllProposals {
    65  		valid[string(key)] = true
    66  	}
    67  
    68  	proposals := make([]ProposalType, len(keys))
    69  	for i, key := range keys {
    70  		if _, ok := valid[key]; !ok {
    71  			return nil, sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "'%s' is not a valid ProposalType", key)
    72  		}
    73  		proposals[i] = ProposalType(key)
    74  	}
    75  	return proposals, nil
    76  }
    77  
    78  func init() { // register new content types with the sdk
    79  	govtypes.RegisterProposalType(string(ProposalTypeStoreCode))
    80  	govtypes.RegisterProposalType(string(ProposalTypeInstantiateContract))
    81  	govtypes.RegisterProposalType(string(ProposalTypeMigrateContract))
    82  	govtypes.RegisterProposalType(string(ProposalTypeSudoContract))
    83  	govtypes.RegisterProposalType(string(ProposalTypeExecuteContract))
    84  	govtypes.RegisterProposalType(string(ProposalTypeUpdateAdmin))
    85  	govtypes.RegisterProposalType(string(ProposalTypeClearAdmin))
    86  	govtypes.RegisterProposalType(string(ProposalTypePinCodes))
    87  	govtypes.RegisterProposalType(string(ProposalTypeUnpinCodes))
    88  	govtypes.RegisterProposalType(string(ProposalTypeUpdateInstantiateConfig))
    89  	govtypes.RegisterProposalType(string(ProposalTypeUpdateDeploymentWhitelist))
    90  	govtypes.RegisterProposalType(string(ProposalTypeUpdateWasmContractMethodBlockedList))
    91  	govtypes.RegisterProposalTypeCodec(&StoreCodeProposal{}, "wasm/StoreCodeProposal")
    92  	govtypes.RegisterProposalTypeCodec(&InstantiateContractProposal{}, "wasm/InstantiateContractProposal")
    93  	govtypes.RegisterProposalTypeCodec(&MigrateContractProposal{}, "wasm/MigrateContractProposal")
    94  	govtypes.RegisterProposalTypeCodec(&SudoContractProposal{}, "wasm/SudoContractProposal")
    95  	govtypes.RegisterProposalTypeCodec(&ExecuteContractProposal{}, "wasm/ExecuteContractProposal")
    96  	govtypes.RegisterProposalTypeCodec(&UpdateAdminProposal{}, "wasm/UpdateAdminProposal")
    97  	govtypes.RegisterProposalTypeCodec(&ClearAdminProposal{}, "wasm/ClearAdminProposal")
    98  	govtypes.RegisterProposalTypeCodec(&PinCodesProposal{}, "wasm/PinCodesProposal")
    99  	govtypes.RegisterProposalTypeCodec(&UnpinCodesProposal{}, "wasm/UnpinCodesProposal")
   100  	govtypes.RegisterProposalTypeCodec(&UpdateInstantiateConfigProposal{}, "wasm/UpdateInstantiateConfigProposal")
   101  	govtypes.RegisterProposalTypeCodec(&UpdateDeploymentWhitelistProposal{}, "wasm/UpdateDeploymentWhitelistProposal")
   102  	govtypes.RegisterProposalTypeCodec(&UpdateWASMContractMethodBlockedListProposal{}, "wasm/UpdateWASMContractMethodBlockedListProposal")
   103  }
   104  
   105  // ProposalRoute returns the routing key of a parameter change proposal.
   106  func (p StoreCodeProposal) ProposalRoute() string { return RouterKey }
   107  
   108  // GetTitle returns the title of the proposal
   109  func (p *StoreCodeProposal) GetTitle() string { return p.Title }
   110  
   111  // GetDescription returns the human readable description of the proposal
   112  func (p StoreCodeProposal) GetDescription() string { return p.Description }
   113  
   114  // ProposalType returns the type
   115  func (p StoreCodeProposal) ProposalType() string { return string(ProposalTypeStoreCode) }
   116  
   117  // ValidateBasic validates the proposal
   118  func (p StoreCodeProposal) ValidateBasic() error {
   119  	if err := validateProposalCommons(p.Title, p.Description); err != nil {
   120  		return err
   121  	}
   122  	if _, err := sdk.AccAddressFromBech32(p.RunAs); err != nil {
   123  		return sdkerrors.Wrap(err, "run as")
   124  	}
   125  
   126  	if err := validateWasmCode(p.WASMByteCode); err != nil {
   127  		return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "code bytes %s", err.Error())
   128  	}
   129  
   130  	if p.InstantiatePermission != nil {
   131  		if err := p.InstantiatePermission.ValidateBasic(); err != nil {
   132  			return sdkerrors.Wrap(err, "instantiate permission")
   133  		}
   134  	}
   135  	return nil
   136  }
   137  
   138  // String implements the Stringer interface.
   139  func (p StoreCodeProposal) String() string {
   140  	return fmt.Sprintf(`Store Code Proposal:
   141    Title:       %s
   142    Description: %s
   143    Run as:      %s
   144    WasmCode:    %X
   145  `, p.Title, p.Description, p.RunAs, p.WASMByteCode)
   146  }
   147  
   148  // MarshalYAML pretty prints the wasm byte code
   149  func (p StoreCodeProposal) MarshalYAML() (interface{}, error) {
   150  	return struct {
   151  		Title                 string        `yaml:"title"`
   152  		Description           string        `yaml:"description"`
   153  		RunAs                 string        `yaml:"run_as"`
   154  		WASMByteCode          string        `yaml:"wasm_byte_code"`
   155  		InstantiatePermission *AccessConfig `yaml:"instantiate_permission"`
   156  	}{
   157  		Title:                 p.Title,
   158  		Description:           p.Description,
   159  		RunAs:                 p.RunAs,
   160  		WASMByteCode:          base64.StdEncoding.EncodeToString(p.WASMByteCode),
   161  		InstantiatePermission: p.InstantiatePermission,
   162  	}, nil
   163  }
   164  
   165  // ProposalRoute returns the routing key of a parameter change proposal.
   166  func (p InstantiateContractProposal) ProposalRoute() string { return RouterKey }
   167  
   168  // GetTitle returns the title of the proposal
   169  func (p *InstantiateContractProposal) GetTitle() string { return p.Title }
   170  
   171  // GetDescription returns the human readable description of the proposal
   172  func (p InstantiateContractProposal) GetDescription() string { return p.Description }
   173  
   174  // ProposalType returns the type
   175  func (p InstantiateContractProposal) ProposalType() string {
   176  	return string(ProposalTypeInstantiateContract)
   177  }
   178  
   179  // ValidateBasic validates the proposal
   180  func (p InstantiateContractProposal) ValidateBasic() error {
   181  	if err := validateProposalCommons(p.Title, p.Description); err != nil {
   182  		return err
   183  	}
   184  	if _, err := sdk.AccAddressFromBech32(p.RunAs); err != nil {
   185  		return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "run as")
   186  	}
   187  
   188  	if p.CodeID == 0 {
   189  		return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "code id is required")
   190  	}
   191  
   192  	if err := validateLabel(p.Label); err != nil {
   193  		return err
   194  	}
   195  
   196  	if !p.Funds.IsValid() {
   197  		return sdkerrors.ErrInvalidCoins
   198  	}
   199  
   200  	if len(p.Admin) != 0 {
   201  		if _, err := sdk.AccAddressFromBech32(p.Admin); err != nil {
   202  			return err
   203  		}
   204  	}
   205  	if err := p.Msg.ValidateBasic(); err != nil {
   206  		return sdkerrors.Wrap(err, "payload msg")
   207  	}
   208  	return nil
   209  }
   210  
   211  // String implements the Stringer interface.
   212  func (p InstantiateContractProposal) String() string {
   213  	return fmt.Sprintf(`Instantiate Code Proposal:
   214    Title:       %s
   215    Description: %s
   216    Run as:      %s
   217    Admin:       %s
   218    Code id:     %d
   219    Label:       %s
   220    Msg:         %q
   221    Funds:       %s
   222  `, p.Title, p.Description, p.RunAs, p.Admin, p.CodeID, p.Label, p.Msg, p.Funds)
   223  }
   224  
   225  // MarshalYAML pretty prints the init message
   226  func (p InstantiateContractProposal) MarshalYAML() (interface{}, error) {
   227  	return struct {
   228  		Title       string    `yaml:"title"`
   229  		Description string    `yaml:"description"`
   230  		RunAs       string    `yaml:"run_as"`
   231  		Admin       string    `yaml:"admin"`
   232  		CodeID      uint64    `yaml:"code_id"`
   233  		Label       string    `yaml:"label"`
   234  		Msg         string    `yaml:"msg"`
   235  		Funds       sdk.Coins `yaml:"funds"`
   236  	}{
   237  		Title:       p.Title,
   238  		Description: p.Description,
   239  		RunAs:       p.RunAs,
   240  		Admin:       p.Admin,
   241  		CodeID:      p.CodeID,
   242  		Label:       p.Label,
   243  		Msg:         string(p.Msg),
   244  		Funds:       sdk.CoinAdaptersToCoins(p.Funds),
   245  	}, nil
   246  }
   247  
   248  // ProposalRoute returns the routing key of a parameter change proposal.
   249  func (p MigrateContractProposal) ProposalRoute() string { return RouterKey }
   250  
   251  // GetTitle returns the title of the proposal
   252  func (p *MigrateContractProposal) GetTitle() string { return p.Title }
   253  
   254  // GetDescription returns the human readable description of the proposal
   255  func (p MigrateContractProposal) GetDescription() string { return p.Description }
   256  
   257  // ProposalType returns the type
   258  func (p MigrateContractProposal) ProposalType() string { return string(ProposalTypeMigrateContract) }
   259  
   260  // ValidateBasic validates the proposal
   261  func (p MigrateContractProposal) ValidateBasic() error {
   262  	if err := validateProposalCommons(p.Title, p.Description); err != nil {
   263  		return err
   264  	}
   265  	if p.CodeID == 0 {
   266  		return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "code_id is required")
   267  	}
   268  	if _, err := sdk.AccAddressFromBech32(p.Contract); err != nil {
   269  		return sdkerrors.Wrap(err, "contract")
   270  	}
   271  	if err := p.Msg.ValidateBasic(); err != nil {
   272  		return sdkerrors.Wrap(err, "payload msg")
   273  	}
   274  	return nil
   275  }
   276  
   277  // String implements the Stringer interface.
   278  func (p MigrateContractProposal) String() string {
   279  	return fmt.Sprintf(`Migrate Contract Proposal:
   280    Title:       %s
   281    Description: %s
   282    Contract:    %s
   283    Code id:     %d
   284    Msg:         %q
   285  `, p.Title, p.Description, p.Contract, p.CodeID, p.Msg)
   286  }
   287  
   288  // MarshalYAML pretty prints the migrate message
   289  func (p MigrateContractProposal) MarshalYAML() (interface{}, error) {
   290  	return struct {
   291  		Title       string `yaml:"title"`
   292  		Description string `yaml:"description"`
   293  		Contract    string `yaml:"contract"`
   294  		CodeID      uint64 `yaml:"code_id"`
   295  		Msg         string `yaml:"msg"`
   296  	}{
   297  		Title:       p.Title,
   298  		Description: p.Description,
   299  		Contract:    p.Contract,
   300  		CodeID:      p.CodeID,
   301  		Msg:         string(p.Msg),
   302  	}, nil
   303  }
   304  
   305  // ProposalRoute returns the routing key of a parameter change proposal.
   306  func (p SudoContractProposal) ProposalRoute() string { return RouterKey }
   307  
   308  // GetTitle returns the title of the proposal
   309  func (p *SudoContractProposal) GetTitle() string { return p.Title }
   310  
   311  // GetDescription returns the human readable description of the proposal
   312  func (p SudoContractProposal) GetDescription() string { return p.Description }
   313  
   314  // ProposalType returns the type
   315  func (p SudoContractProposal) ProposalType() string { return string(ProposalTypeSudoContract) }
   316  
   317  // ValidateBasic validates the proposal
   318  func (p SudoContractProposal) ValidateBasic() error {
   319  	if err := validateProposalCommons(p.Title, p.Description); err != nil {
   320  		return err
   321  	}
   322  	if _, err := sdk.AccAddressFromBech32(p.Contract); err != nil {
   323  		return sdkerrors.Wrap(err, "contract")
   324  	}
   325  	if err := p.Msg.ValidateBasic(); err != nil {
   326  		return sdkerrors.Wrap(err, "payload msg")
   327  	}
   328  	return nil
   329  }
   330  
   331  // String implements the Stringer interface.
   332  func (p SudoContractProposal) String() string {
   333  	return fmt.Sprintf(`Migrate Contract Proposal:
   334    Title:       %s
   335    Description: %s
   336    Contract:    %s
   337    Msg:         %q
   338  `, p.Title, p.Description, p.Contract, p.Msg)
   339  }
   340  
   341  // MarshalYAML pretty prints the migrate message
   342  func (p SudoContractProposal) MarshalYAML() (interface{}, error) {
   343  	return struct {
   344  		Title       string `yaml:"title"`
   345  		Description string `yaml:"description"`
   346  		Contract    string `yaml:"contract"`
   347  		Msg         string `yaml:"msg"`
   348  	}{
   349  		Title:       p.Title,
   350  		Description: p.Description,
   351  		Contract:    p.Contract,
   352  		Msg:         string(p.Msg),
   353  	}, nil
   354  }
   355  
   356  // ProposalRoute returns the routing key of a parameter change proposal.
   357  func (p ExecuteContractProposal) ProposalRoute() string { return RouterKey }
   358  
   359  // GetTitle returns the title of the proposal
   360  func (p *ExecuteContractProposal) GetTitle() string { return p.Title }
   361  
   362  // GetDescription returns the human readable description of the proposal
   363  func (p ExecuteContractProposal) GetDescription() string { return p.Description }
   364  
   365  // ProposalType returns the type
   366  func (p ExecuteContractProposal) ProposalType() string { return string(ProposalTypeExecuteContract) }
   367  
   368  // ValidateBasic validates the proposal
   369  func (p ExecuteContractProposal) ValidateBasic() error {
   370  	if err := validateProposalCommons(p.Title, p.Description); err != nil {
   371  		return err
   372  	}
   373  	if _, err := sdk.AccAddressFromBech32(p.Contract); err != nil {
   374  		return sdkerrors.Wrap(err, "contract")
   375  	}
   376  	if _, err := sdk.AccAddressFromBech32(p.RunAs); err != nil {
   377  		return sdkerrors.Wrap(err, "run as")
   378  	}
   379  	if !p.Funds.IsValid() {
   380  		return sdkerrors.ErrInvalidCoins
   381  	}
   382  	if err := p.Msg.ValidateBasic(); err != nil {
   383  		return sdkerrors.Wrap(err, "payload msg")
   384  	}
   385  	return nil
   386  }
   387  
   388  // String implements the Stringer interface.
   389  func (p ExecuteContractProposal) String() string {
   390  	return fmt.Sprintf(`Migrate Contract Proposal:
   391    Title:       %s
   392    Description: %s
   393    Contract:    %s
   394    Run as:      %s
   395    Msg:         %q
   396    Funds:       %s
   397  `, p.Title, p.Description, p.Contract, p.RunAs, p.Msg, p.Funds)
   398  }
   399  
   400  // MarshalYAML pretty prints the migrate message
   401  func (p ExecuteContractProposal) MarshalYAML() (interface{}, error) {
   402  	return struct {
   403  		Title       string    `yaml:"title"`
   404  		Description string    `yaml:"description"`
   405  		Contract    string    `yaml:"contract"`
   406  		Msg         string    `yaml:"msg"`
   407  		RunAs       string    `yaml:"run_as"`
   408  		Funds       sdk.Coins `yaml:"funds"`
   409  	}{
   410  		Title:       p.Title,
   411  		Description: p.Description,
   412  		Contract:    p.Contract,
   413  		Msg:         string(p.Msg),
   414  		RunAs:       p.RunAs,
   415  		Funds:       sdk.CoinAdaptersToCoins(p.Funds),
   416  	}, nil
   417  }
   418  
   419  // ProposalRoute returns the routing key of a parameter change proposal.
   420  func (p UpdateAdminProposal) ProposalRoute() string { return RouterKey }
   421  
   422  // GetTitle returns the title of the proposal
   423  func (p *UpdateAdminProposal) GetTitle() string { return p.Title }
   424  
   425  // GetDescription returns the human readable description of the proposal
   426  func (p UpdateAdminProposal) GetDescription() string { return p.Description }
   427  
   428  // ProposalType returns the type
   429  func (p UpdateAdminProposal) ProposalType() string { return string(ProposalTypeUpdateAdmin) }
   430  
   431  // ValidateBasic validates the proposal
   432  func (p UpdateAdminProposal) ValidateBasic() error {
   433  	if err := validateProposalCommons(p.Title, p.Description); err != nil {
   434  		return err
   435  	}
   436  	if _, err := sdk.AccAddressFromBech32(p.Contract); err != nil {
   437  		return sdkerrors.Wrap(err, "contract")
   438  	}
   439  	if _, err := sdk.AccAddressFromBech32(p.NewAdmin); err != nil {
   440  		return sdkerrors.Wrap(err, "new admin")
   441  	}
   442  	return nil
   443  }
   444  
   445  // String implements the Stringer interface.
   446  func (p UpdateAdminProposal) String() string {
   447  	return fmt.Sprintf(`Update Contract Admin Proposal:
   448    Title:       %s
   449    Description: %s
   450    Contract:    %s
   451    New Admin:   %s
   452  `, p.Title, p.Description, p.Contract, p.NewAdmin)
   453  }
   454  
   455  // ProposalRoute returns the routing key of a parameter change proposal.
   456  func (p ClearAdminProposal) ProposalRoute() string { return RouterKey }
   457  
   458  // GetTitle returns the title of the proposal
   459  func (p *ClearAdminProposal) GetTitle() string { return p.Title }
   460  
   461  // GetDescription returns the human readable description of the proposal
   462  func (p ClearAdminProposal) GetDescription() string { return p.Description }
   463  
   464  // ProposalType returns the type
   465  func (p ClearAdminProposal) ProposalType() string { return string(ProposalTypeClearAdmin) }
   466  
   467  // ValidateBasic validates the proposal
   468  func (p ClearAdminProposal) ValidateBasic() error {
   469  	if err := validateProposalCommons(p.Title, p.Description); err != nil {
   470  		return err
   471  	}
   472  	if _, err := sdk.AccAddressFromBech32(p.Contract); err != nil {
   473  		return sdkerrors.Wrap(err, "contract")
   474  	}
   475  	return nil
   476  }
   477  
   478  // String implements the Stringer interface.
   479  func (p ClearAdminProposal) String() string {
   480  	return fmt.Sprintf(`Clear Contract Admin Proposal:
   481    Title:       %s
   482    Description: %s
   483    Contract:    %s
   484  `, p.Title, p.Description, p.Contract)
   485  }
   486  
   487  // ProposalRoute returns the routing key of a parameter change proposal.
   488  func (p PinCodesProposal) ProposalRoute() string { return RouterKey }
   489  
   490  // GetTitle returns the title of the proposal
   491  func (p *PinCodesProposal) GetTitle() string { return p.Title }
   492  
   493  // GetDescription returns the human readable description of the proposal
   494  func (p PinCodesProposal) GetDescription() string { return p.Description }
   495  
   496  // ProposalType returns the type
   497  func (p PinCodesProposal) ProposalType() string { return string(ProposalTypePinCodes) }
   498  
   499  // ValidateBasic validates the proposal
   500  func (p PinCodesProposal) ValidateBasic() error {
   501  	if err := validateProposalCommons(p.Title, p.Description); err != nil {
   502  		return err
   503  	}
   504  	if len(p.CodeIDs) == 0 {
   505  		return sdkerrors.Wrap(ErrEmpty, "code ids")
   506  	}
   507  	return nil
   508  }
   509  
   510  // String implements the Stringer interface.
   511  func (p PinCodesProposal) String() string {
   512  	return fmt.Sprintf(`Pin Wasm Codes Proposal:
   513    Title:       %s
   514    Description: %s
   515    Codes:       %v
   516  `, p.Title, p.Description, p.CodeIDs)
   517  }
   518  
   519  // ProposalRoute returns the routing key of a parameter change proposal.
   520  func (p UnpinCodesProposal) ProposalRoute() string { return RouterKey }
   521  
   522  // GetTitle returns the title of the proposal
   523  func (p *UnpinCodesProposal) GetTitle() string { return p.Title }
   524  
   525  // GetDescription returns the human readable description of the proposal
   526  func (p UnpinCodesProposal) GetDescription() string { return p.Description }
   527  
   528  // ProposalType returns the type
   529  func (p UnpinCodesProposal) ProposalType() string { return string(ProposalTypeUnpinCodes) }
   530  
   531  // ValidateBasic validates the proposal
   532  func (p UnpinCodesProposal) ValidateBasic() error {
   533  	if err := validateProposalCommons(p.Title, p.Description); err != nil {
   534  		return err
   535  	}
   536  	if len(p.CodeIDs) == 0 {
   537  		return sdkerrors.Wrap(ErrEmpty, "code ids")
   538  	}
   539  	return nil
   540  }
   541  
   542  // String implements the Stringer interface.
   543  func (p UnpinCodesProposal) String() string {
   544  	return fmt.Sprintf(`Unpin Wasm Codes Proposal:
   545    Title:       %s
   546    Description: %s
   547    Codes:       %v
   548  `, p.Title, p.Description, p.CodeIDs)
   549  }
   550  
   551  func validateProposalCommons(title, description string) error {
   552  	if strings.TrimSpace(title) != title {
   553  		return govtypes.ErrInvalidProposalContent("proposal title must not start/end with white spaces")
   554  	}
   555  	if len(title) == 0 {
   556  		return govtypes.ErrInvalidProposalContent("proposal title cannot be blank")
   557  	}
   558  	if len(title) > govtypes.MaxTitleLength {
   559  		return govtypes.ErrInvalidProposalContent(fmt.Sprintf("proposal title is longer than max length of %d", govtypes.MaxTitleLength))
   560  	}
   561  	if strings.TrimSpace(description) != description {
   562  		return govtypes.ErrInvalidProposalContent("proposal description must not start/end with white spaces")
   563  	}
   564  	if len(description) == 0 {
   565  		return govtypes.ErrInvalidProposalContent("proposal description cannot be blank")
   566  	}
   567  	if len(description) > govtypes.MaxDescriptionLength {
   568  		return govtypes.ErrInvalidProposalContent(fmt.Sprintf("proposal description is longer than max length of %d", govtypes.MaxDescriptionLength))
   569  	}
   570  	return nil
   571  }
   572  
   573  // ProposalRoute returns the routing key of a parameter change proposal.
   574  func (p UpdateInstantiateConfigProposal) ProposalRoute() string { return RouterKey }
   575  
   576  // GetTitle returns the title of the proposal
   577  func (p *UpdateInstantiateConfigProposal) GetTitle() string { return p.Title }
   578  
   579  // GetDescription returns the human readable description of the proposal
   580  func (p UpdateInstantiateConfigProposal) GetDescription() string { return p.Description }
   581  
   582  // ProposalType returns the type
   583  func (p UpdateInstantiateConfigProposal) ProposalType() string {
   584  	return string(ProposalTypeUpdateInstantiateConfig)
   585  }
   586  
   587  // ValidateBasic validates the proposal
   588  func (p UpdateInstantiateConfigProposal) ValidateBasic() error {
   589  	if err := validateProposalCommons(p.Title, p.Description); err != nil {
   590  		return err
   591  	}
   592  	if len(p.AccessConfigUpdates) == 0 {
   593  		return sdkerrors.Wrap(ErrEmpty, "code updates")
   594  	}
   595  	dedup := make(map[uint64]bool)
   596  	for _, codeUpdate := range p.AccessConfigUpdates {
   597  		_, found := dedup[codeUpdate.CodeID]
   598  		if found {
   599  			return sdkerrors.Wrapf(ErrDuplicate, "duplicate code: %d", codeUpdate.CodeID)
   600  		}
   601  		if err := codeUpdate.InstantiatePermission.ValidateBasic(); err != nil {
   602  			return sdkerrors.Wrap(err, "instantiate permission")
   603  		}
   604  		dedup[codeUpdate.CodeID] = true
   605  	}
   606  	return nil
   607  }
   608  
   609  // String implements the Stringer interface.
   610  func (p UpdateInstantiateConfigProposal) String() string {
   611  	return fmt.Sprintf(`Update Instantiate Config Proposal:
   612    Title:       %s
   613    Description: %s
   614    AccessConfigUpdates: %v
   615  `, p.Title, p.Description, p.AccessConfigUpdates)
   616  }
   617  
   618  // String implements the Stringer interface.
   619  func (c AccessConfigUpdate) String() string {
   620  	return fmt.Sprintf(`AccessConfigUpdate:
   621    CodeID:       %d
   622    AccessConfig: %v
   623  `, c.CodeID, c.InstantiatePermission)
   624  }