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 }