diff --git a/x/wasm/keeper/proposal_handler.go b/x/wasm/keeper/proposal_handler.go index 79f6a9fc30..ddc94a23bb 100644 --- a/x/wasm/keeper/proposal_handler.go +++ b/x/wasm/keeper/proposal_handler.go @@ -77,9 +77,11 @@ func handleInstantiateProposal(ctx sdk.Context, k types.ContractOpsKeeper, p typ if err != nil { return sdkerrors.Wrap(err, "run as address") } - adminAddr, err := sdk.AccAddressFromBech32(p.Admin) - if err != nil { - return sdkerrors.Wrap(err, "admin") + var adminAddr sdk.AccAddress + if p.Admin != "" { + if adminAddr, err = sdk.AccAddressFromBech32(p.Admin); err != nil { + return sdkerrors.Wrap(err, "admin") + } } _, data, err := k.Instantiate(ctx, p.CodeID, runAsAddr, adminAddr, p.Msg, p.Label, p.Funds) diff --git a/x/wasm/keeper/proposal_integration_test.go b/x/wasm/keeper/proposal_integration_test.go index acf2e74f02..ea88f398d9 100644 --- a/x/wasm/keeper/proposal_integration_test.go +++ b/x/wasm/keeper/proposal_integration_test.go @@ -123,6 +123,80 @@ func TestInstantiateProposal(t *testing.T) { require.NotEmpty(t, em.Events()[2].Attributes[0]) } +func TestInstantiateProposal_NoAdmin(t *testing.T) { + ctx, keepers := CreateTestInput(t, false, "staking") + govKeeper, wasmKeeper := keepers.GovKeeper, keepers.WasmKeeper + wasmKeeper.SetParams(ctx, types.Params{ + CodeUploadAccess: types.AllowNobody, + InstantiateDefaultPermission: types.AccessTypeNobody, + }) + + wasmCode, err := ioutil.ReadFile("./testdata/hackatom.wasm") + require.NoError(t, err) + + require.NoError(t, wasmKeeper.importCode(ctx, 1, + types.CodeInfoFixture(types.WithSHA256CodeHash(wasmCode)), + wasmCode), + ) + + var ( + oneAddress sdk.AccAddress = bytes.Repeat([]byte{0x1}, types.ContractAddrLen) + ) + + // test invalid admin address + src := types.InstantiateContractProposalFixture(func(p *types.InstantiateContractProposal) { + p.CodeID = firstCodeID + p.RunAs = oneAddress.String() + p.Admin = "invalid" + p.Label = "testing" + }) + _, err = govKeeper.SubmitProposal(ctx, src) + require.Error(t, err) + + // test with no admin + src = types.InstantiateContractProposalFixture(func(p *types.InstantiateContractProposal) { + p.CodeID = firstCodeID + p.RunAs = oneAddress.String() + p.Admin = "" + p.Label = "testing" + }) + em := sdk.NewEventManager() + + // when stored + storedProposal, err := govKeeper.SubmitProposal(ctx, src) + require.NoError(t, err) + + // and proposal execute + handler := govKeeper.Router().GetRoute(storedProposal.ProposalRoute()) + err = handler(ctx.WithEventManager(em), storedProposal.GetContent()) + require.NoError(t, err) + + // then + contractAddr, err := sdk.AccAddressFromBech32("cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr") + require.NoError(t, err) + + cInfo := wasmKeeper.GetContractInfo(ctx, contractAddr) + require.NotNil(t, cInfo) + assert.Equal(t, uint64(1), cInfo.CodeID) + assert.Equal(t, oneAddress.String(), cInfo.Creator) + assert.Equal(t, "", cInfo.Admin) + assert.Equal(t, "testing", cInfo.Label) + expHistory := []types.ContractCodeHistoryEntry{{ + Operation: types.ContractCodeHistoryOperationTypeInit, + CodeID: src.CodeID, + Updated: types.NewAbsoluteTxPosition(ctx), + Msg: src.Msg, + }} + assert.Equal(t, expHistory, wasmKeeper.GetContractHistory(ctx, contractAddr)) + // and event + require.Len(t, em.Events(), 3, "%#v", em.Events()) + require.Equal(t, types.EventTypeInstantiate, em.Events()[0].Type) + require.Equal(t, types.WasmModuleEventType, em.Events()[1].Type) + require.Equal(t, types.EventTypeGovContractResult, em.Events()[2].Type) + require.Len(t, em.Events()[2].Attributes, 1) + require.NotEmpty(t, em.Events()[2].Attributes[0]) +} + func TestMigrateProposal(t *testing.T) { ctx, keepers := CreateTestInput(t, false, "staking") govKeeper, wasmKeeper := keepers.GovKeeper, keepers.WasmKeeper