github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/x/wasm/keeper/proposal_handler.go (about) 1 package keeper 2 3 import ( 4 "encoding/hex" 5 "fmt" 6 "sort" 7 "strings" 8 9 sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types" 10 sdkerrors "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types/errors" 11 types2 "github.com/fibonacci-chain/fbc/libs/tendermint/types" 12 govtypes "github.com/fibonacci-chain/fbc/x/gov/types" 13 "github.com/fibonacci-chain/fbc/x/wasm/types" 14 ) 15 16 // NewWasmProposalHandler creates a new governance Handler for wasm proposals 17 func NewWasmProposalHandler(k decoratedKeeper, enabledProposalTypes []types.ProposalType) govtypes.Handler { 18 return NewWasmProposalHandlerX(NewGovPermissionKeeper(k), enabledProposalTypes) 19 } 20 21 // NewWasmProposalHandlerX creates a new governance Handler for wasm proposals 22 func NewWasmProposalHandlerX(k types.ContractOpsKeeper, enabledProposalTypes []types.ProposalType) govtypes.Handler { 23 enabledTypes := make(map[string]struct{}, len(enabledProposalTypes)) 24 for i := range enabledProposalTypes { 25 enabledTypes[string(enabledProposalTypes[i])] = struct{}{} 26 } 27 return func(ctx sdk.Context, proposal *govtypes.Proposal) sdk.Error { 28 if !types2.HigherThanEarth(ctx.BlockHeight()) { 29 errMsg := fmt.Sprintf("wasm not supprt at height %d", ctx.BlockHeight()) 30 return sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, errMsg) 31 } 32 content := proposal.Content 33 if content == nil { 34 return sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, "content must not be empty") 35 } 36 if _, ok := enabledTypes[content.ProposalType()]; !ok { 37 return sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unsupported wasm proposal content type: %q", content.ProposalType()) 38 } 39 switch c := content.(type) { 40 case *types.StoreCodeProposal: 41 return handleStoreCodeProposal(ctx, k, *c) 42 case *types.InstantiateContractProposal: 43 return handleInstantiateProposal(ctx, k, *c) 44 case *types.MigrateContractProposal: 45 return handleMigrateProposal(ctx, k, *c) 46 case *types.SudoContractProposal: 47 return handleSudoProposal(ctx, k, *c) 48 case *types.ExecuteContractProposal: 49 return handleExecuteProposal(ctx, k, *c) 50 case *types.UpdateAdminProposal: 51 return handleUpdateAdminProposal(ctx, k, *c) 52 case *types.ClearAdminProposal: 53 return handleClearAdminProposal(ctx, k, *c) 54 case *types.PinCodesProposal: 55 return handlePinCodesProposal(ctx, k, *c) 56 case *types.UnpinCodesProposal: 57 return handleUnpinCodesProposal(ctx, k, *c) 58 case *types.UpdateInstantiateConfigProposal: 59 return handleUpdateInstantiateConfigProposal(ctx, k, *c) 60 case *types.UpdateDeploymentWhitelistProposal: 61 return handleUpdateDeploymentWhitelistProposal(ctx, k, *c) 62 case *types.UpdateWASMContractMethodBlockedListProposal: 63 return handleUpdateWASMContractMethodBlockedListProposal(ctx, k, *c) 64 default: 65 return sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized wasm proposal content type: %T", c) 66 } 67 } 68 } 69 70 func handleStoreCodeProposal(ctx sdk.Context, k types.ContractOpsKeeper, p types.StoreCodeProposal) error { 71 if err := p.ValidateBasic(); err != nil { 72 return err 73 } 74 75 runAsAddr, err := sdk.AccAddressFromBech32(p.RunAs) 76 if err != nil { 77 return sdkerrors.Wrap(err, "run as address") 78 } 79 codeID, err := k.Create(ctx, runAsAddr, p.WASMByteCode, p.InstantiatePermission) 80 if err != nil { 81 return err 82 } 83 return k.PinCode(ctx, codeID) 84 } 85 86 func handleInstantiateProposal(ctx sdk.Context, k types.ContractOpsKeeper, p types.InstantiateContractProposal) error { 87 if err := p.ValidateBasic(); err != nil { 88 return err 89 } 90 runAsAddr, err := sdk.AccAddressFromBech32(p.RunAs) 91 if err != nil { 92 return sdkerrors.Wrap(err, "run as address") 93 } 94 var adminAddr sdk.AccAddress 95 if p.Admin != "" { 96 if adminAddr, err = sdk.AccAddressFromBech32(p.Admin); err != nil { 97 return sdkerrors.Wrap(err, "admin") 98 } 99 } 100 101 _, data, err := k.Instantiate(ctx, p.CodeID, runAsAddr, adminAddr, p.Msg, p.Label, sdk.CoinAdaptersToCoins(p.Funds)) 102 if err != nil { 103 return err 104 } 105 106 ctx.EventManager().EmitEvent(sdk.NewEvent( 107 types.EventTypeGovContractResult, 108 sdk.NewAttribute(types.AttributeKeyResultDataHex, hex.EncodeToString(data)), 109 )) 110 return nil 111 } 112 113 func handleMigrateProposal(ctx sdk.Context, k types.ContractOpsKeeper, p types.MigrateContractProposal) error { 114 if err := p.ValidateBasic(); err != nil { 115 return err 116 } 117 118 contractAddr, err := sdk.AccAddressFromBech32(p.Contract) 119 if err != nil { 120 return sdkerrors.Wrap(err, "contract") 121 } 122 if err != nil { 123 return sdkerrors.Wrap(err, "run as address") 124 } 125 126 if err = k.ClearContractAdmin(ctx, contractAddr, contractAddr); err != nil { 127 return err 128 } 129 130 // runAs is not used if this is permissioned, so just put any valid address there (second contractAddr) 131 data, err := k.Migrate(ctx, contractAddr, contractAddr, p.CodeID, p.Msg) 132 if err != nil { 133 return err 134 } 135 136 ctx.EventManager().EmitEvent(sdk.NewEvent( 137 types.EventTypeGovContractResult, 138 sdk.NewAttribute(types.AttributeKeyResultDataHex, hex.EncodeToString(data)), 139 )) 140 return nil 141 } 142 143 func handleSudoProposal(ctx sdk.Context, k types.ContractOpsKeeper, p types.SudoContractProposal) error { 144 if err := p.ValidateBasic(); err != nil { 145 return err 146 } 147 148 contractAddr, err := sdk.AccAddressFromBech32(p.Contract) 149 if err != nil { 150 return sdkerrors.Wrap(err, "contract") 151 } 152 data, err := k.Sudo(ctx, contractAddr, p.Msg) 153 if err != nil { 154 return err 155 } 156 157 ctx.EventManager().EmitEvent(sdk.NewEvent( 158 types.EventTypeGovContractResult, 159 sdk.NewAttribute(types.AttributeKeyResultDataHex, hex.EncodeToString(data)), 160 )) 161 return nil 162 } 163 164 func handleExecuteProposal(ctx sdk.Context, k types.ContractOpsKeeper, p types.ExecuteContractProposal) error { 165 if err := p.ValidateBasic(); err != nil { 166 return err 167 } 168 169 contractAddr, err := sdk.AccAddressFromBech32(p.Contract) 170 if err != nil { 171 return sdkerrors.Wrap(err, "contract") 172 } 173 runAsAddr, err := sdk.AccAddressFromBech32(p.RunAs) 174 if err != nil { 175 return sdkerrors.Wrap(err, "run as address") 176 } 177 data, err := k.Execute(ctx, contractAddr, runAsAddr, p.Msg, sdk.CoinAdaptersToCoins(p.Funds)) 178 if err != nil { 179 return err 180 } 181 182 ctx.EventManager().EmitEvent(sdk.NewEvent( 183 types.EventTypeGovContractResult, 184 sdk.NewAttribute(types.AttributeKeyResultDataHex, hex.EncodeToString(data)), 185 )) 186 return nil 187 } 188 189 func handleUpdateAdminProposal(ctx sdk.Context, k types.ContractOpsKeeper, p types.UpdateAdminProposal) error { 190 if err := p.ValidateBasic(); err != nil { 191 return err 192 } 193 contractAddr, err := sdk.AccAddressFromBech32(p.Contract) 194 if err != nil { 195 return sdkerrors.Wrap(err, "contract") 196 } 197 newAdminAddr, err := sdk.AccAddressFromBech32(p.NewAdmin) 198 if err != nil { 199 return sdkerrors.Wrap(err, "run as address") 200 } 201 202 return k.UpdateContractAdmin(ctx, contractAddr, nil, newAdminAddr) 203 } 204 205 func handleClearAdminProposal(ctx sdk.Context, k types.ContractOpsKeeper, p types.ClearAdminProposal) error { 206 if err := p.ValidateBasic(); err != nil { 207 return err 208 } 209 210 contractAddr, err := sdk.AccAddressFromBech32(p.Contract) 211 if err != nil { 212 return sdkerrors.Wrap(err, "contract") 213 } 214 if err := k.ClearContractAdmin(ctx, contractAddr, nil); err != nil { 215 return err 216 } 217 return nil 218 } 219 220 func handlePinCodesProposal(ctx sdk.Context, k types.ContractOpsKeeper, p types.PinCodesProposal) error { 221 if err := p.ValidateBasic(); err != nil { 222 return err 223 } 224 for _, v := range p.CodeIDs { 225 if err := k.PinCode(ctx, v); err != nil { 226 return sdkerrors.Wrapf(err, "code id: %d", v) 227 } 228 } 229 return nil 230 } 231 232 func handleUnpinCodesProposal(ctx sdk.Context, k types.ContractOpsKeeper, p types.UnpinCodesProposal) error { 233 if err := p.ValidateBasic(); err != nil { 234 return err 235 } 236 for _, v := range p.CodeIDs { 237 if err := k.UnpinCode(ctx, v); err != nil { 238 return sdkerrors.Wrapf(err, "code id: %d", v) 239 } 240 } 241 return nil 242 } 243 244 func handleUpdateInstantiateConfigProposal(ctx sdk.Context, k types.ContractOpsKeeper, p types.UpdateInstantiateConfigProposal) error { 245 if err := p.ValidateBasic(); err != nil { 246 return err 247 } 248 249 for _, accessConfigUpdate := range p.AccessConfigUpdates { 250 if err := k.SetAccessConfig(ctx, accessConfigUpdate.CodeID, accessConfigUpdate.InstantiatePermission); err != nil { 251 return sdkerrors.Wrapf(err, "code id: %d", accessConfigUpdate.CodeID) 252 } 253 } 254 return nil 255 } 256 257 func handleUpdateDeploymentWhitelistProposal(ctx sdk.Context, k types.ContractOpsKeeper, p types.UpdateDeploymentWhitelistProposal) error { 258 if err := p.ValidateBasic(); err != nil { 259 return err 260 } 261 262 var config types.AccessConfig 263 if len(p.DistributorAddrs) == 0 { 264 config.Permission = types.AccessTypeNobody 265 } else if types.IsAllAddress(p.DistributorAddrs) { 266 config.Permission = types.AccessTypeEverybody 267 } else { 268 sort.Strings(p.DistributorAddrs) 269 config.Permission = types.AccessTypeOnlyAddress 270 config.Address = strings.Join(p.DistributorAddrs, ",") 271 } 272 273 k.UpdateUploadAccessConfig(ctx, config) 274 return nil 275 } 276 277 func handleUpdateWASMContractMethodBlockedListProposal(ctx sdk.Context, k types.ContractOpsKeeper, p types.UpdateWASMContractMethodBlockedListProposal) error { 278 if err := p.ValidateBasic(); err != nil { 279 return err 280 } 281 contractAddr, err := sdk.AccAddressFromBech32(p.BlockedMethods.ContractAddr) 282 if err != nil { 283 return sdkerrors.Wrap(err, "contract") 284 } 285 if err = k.ClearContractAdmin(ctx, contractAddr, contractAddr); err != nil { 286 return err 287 } 288 return k.UpdateContractMethodBlockedList(ctx, p.BlockedMethods, p.IsDelete) 289 }