diff --git a/Makefile b/Makefile index 6ca03f3e38..d85996fbe9 100644 --- a/Makefile +++ b/Makefile @@ -149,8 +149,9 @@ test-sim-multi-seed-short: runsim ############################################################################### format-tools: - go install mvdan.cc/gofumpt@v0.3.1 + go install mvdan.cc/gofumpt@v0.4.0 go install github.com/client9/misspell/cmd/misspell@v0.3.4 + go install golang.org/x/tools/cmd/goimports@latest lint: format-tools golangci-lint run --tests=false diff --git a/app/test_helpers.go b/app/test_helpers.go index ceff625168..d15e155560 100644 --- a/app/test_helpers.go +++ b/app/test_helpers.go @@ -363,7 +363,7 @@ func SignCheckDeliver( // ibc testing package causes checkState and deliverState to diverge in block time. func SignAndDeliver( t *testing.T, txCfg client.TxConfig, app *bam.BaseApp, header tmproto.Header, msgs []sdk.Msg, - chainID string, accNums, accSeqs []uint64, expSimPass, expPass bool, priv ...cryptotypes.PrivKey, + chainID string, accNums, accSeqs []uint64, priv ...cryptotypes.PrivKey, ) (sdk.GasInfo, *sdk.Result, error) { tx, err := helpers.GenTx( txCfg, @@ -381,14 +381,6 @@ func SignAndDeliver( app.BeginBlock(abci.RequestBeginBlock{Header: header}) gInfo, res, err := app.Deliver(txCfg.TxEncoder(), tx) - if expPass { - require.NoError(t, err) - require.NotNil(t, res) - } else { - require.Error(t, err) - require.Nil(t, res) - } - app.EndBlock(abci.RequestEndBlock{}) app.Commit() diff --git a/docs/proto/proto-docs.md b/docs/proto/proto-docs.md index fdf641c81a..dedd98bd21 100644 --- a/docs/proto/proto-docs.md +++ b/docs/proto/proto-docs.md @@ -4,6 +4,17 @@ ## Table of Contents +- [cosmwasm/wasm/v1/authz.proto](#cosmwasm/wasm/v1/authz.proto) + - [AcceptedMessageKeysFilter](#cosmwasm.wasm.v1.AcceptedMessageKeysFilter) + - [AcceptedMessagesFilter](#cosmwasm.wasm.v1.AcceptedMessagesFilter) + - [AllowAllMessagesFilter](#cosmwasm.wasm.v1.AllowAllMessagesFilter) + - [CombinedLimit](#cosmwasm.wasm.v1.CombinedLimit) + - [ContractExecutionAuthorization](#cosmwasm.wasm.v1.ContractExecutionAuthorization) + - [ContractGrant](#cosmwasm.wasm.v1.ContractGrant) + - [ContractMigrationAuthorization](#cosmwasm.wasm.v1.ContractMigrationAuthorization) + - [MaxCallsLimit](#cosmwasm.wasm.v1.MaxCallsLimit) + - [MaxFundsLimit](#cosmwasm.wasm.v1.MaxFundsLimit) + - [cosmwasm/wasm/v1/types.proto](#cosmwasm/wasm/v1/types.proto) - [AbsoluteTxPosition](#cosmwasm.wasm.v1.AbsoluteTxPosition) - [AccessConfig](#cosmwasm.wasm.v1.AccessConfig) @@ -90,6 +101,168 @@ + +

Top

+ +## cosmwasm/wasm/v1/authz.proto + + + + + +### AcceptedMessageKeysFilter +AcceptedMessageKeysFilter accept only the specific contract message keys in +the json object to be executed. +Since: wasmd 0.30 + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `keys` | [string](#string) | repeated | Messages is the list of unique keys | + + + + + + + + +### AcceptedMessagesFilter +AcceptedMessagesFilter accept only the specific raw contract messages to be +executed. +Since: wasmd 0.30 + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `messages` | [bytes](#bytes) | repeated | Messages is the list of raw contract messages | + + + + + + + + +### AllowAllMessagesFilter +AllowAllMessagesFilter is a wildcard to allow any type of contract payload +message. +Since: wasmd 0.30 + + + + + + + + +### CombinedLimit +CombinedLimit defines the maximal amounts that can be sent to a contract and +the maximal number of calls executable. Both need to remain >0 to be valid. +Since: wasmd 0.30 + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `calls_remaining` | [uint64](#uint64) | | Remaining number that is decremented on each execution | +| `amounts` | [cosmos.base.v1beta1.Coin](#cosmos.base.v1beta1.Coin) | repeated | Amounts is the maximal amount of tokens transferable to the contract. | + + + + + + + + +### ContractExecutionAuthorization +ContractExecutionAuthorization defines authorization for wasm execute. +Since: wasmd 0.30 + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `grants` | [ContractGrant](#cosmwasm.wasm.v1.ContractGrant) | repeated | Grants for contract executions | + + + + + + + + +### ContractGrant +ContractGrant a granted permission for a single contract +Since: wasmd 0.30 + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `contract` | [string](#string) | | Contract is the bech32 address of the smart contract | +| `limit` | [google.protobuf.Any](#google.protobuf.Any) | | Limit defines execution limits that are enforced and updated when the grant is applied. When the limit lapsed the grant is removed. | +| `filter` | [google.protobuf.Any](#google.protobuf.Any) | | Filter define more fine-grained control on the message payload passed to the contract in the operation. When no filter applies on execution, the operation is prohibited. | + + + + + + + + +### ContractMigrationAuthorization +ContractMigrationAuthorization defines authorization for wasm contract +migration. Since: wasmd 0.30 + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `grants` | [ContractGrant](#cosmwasm.wasm.v1.ContractGrant) | repeated | Grants for contract migrations | + + + + + + + + +### MaxCallsLimit +MaxCallsLimit limited number of calls to the contract. No funds transferable. +Since: wasmd 0.30 + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `remaining` | [uint64](#uint64) | | Remaining number that is decremented on each execution | + + + + + + + + +### MaxFundsLimit +MaxFundsLimit defines the maximal amounts that can be sent to the contract. +Since: wasmd 0.30 + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `amounts` | [cosmos.base.v1beta1.Coin](#cosmos.base.v1beta1.Coin) | repeated | Amounts is the maximal amount of tokens transferable to the contract. | + + + + + + + + + + + + + + +

Top

diff --git a/proto/cosmwasm/wasm/v1/authz.proto b/proto/cosmwasm/wasm/v1/authz.proto new file mode 100644 index 0000000000..96ecbfb38d --- /dev/null +++ b/proto/cosmwasm/wasm/v1/authz.proto @@ -0,0 +1,109 @@ +syntax = "proto3"; +package cosmwasm.wasm.v1; + +import "gogoproto/gogo.proto"; +import "cosmos_proto/cosmos.proto"; +import "cosmos/base/v1beta1/coin.proto"; +import "google/protobuf/any.proto"; + +option go_package = "github.com/CosmWasm/wasmd/x/wasm/types"; +option (gogoproto.goproto_getters_all) = false; + +// ContractExecutionAuthorization defines authorization for wasm execute. +// Since: wasmd 0.30 +message ContractExecutionAuthorization { + option (cosmos_proto.implements_interface) = "Authorization"; + + // Grants for contract executions + repeated ContractGrant grants = 1 [ (gogoproto.nullable) = false ]; +} + +// ContractMigrationAuthorization defines authorization for wasm contract +// migration. Since: wasmd 0.30 +message ContractMigrationAuthorization { + option (cosmos_proto.implements_interface) = "Authorization"; + + // Grants for contract migrations + repeated ContractGrant grants = 1 [ (gogoproto.nullable) = false ]; +} + +// ContractGrant a granted permission for a single contract +// Since: wasmd 0.30 +message ContractGrant { + // Contract is the bech32 address of the smart contract + string contract = 1; + + // Limit defines execution limits that are enforced and updated when the grant + // is applied. When the limit lapsed the grant is removed. + google.protobuf.Any limit = 2 + [ (cosmos_proto.accepts_interface) = "ContractAuthzLimitX" ]; + + // Filter define more fine-grained control on the message payload passed + // to the contract in the operation. When no filter applies on execution, the + // operation is prohibited. + google.protobuf.Any filter = 3 + [ (cosmos_proto.accepts_interface) = "ContractAuthzFilterX" ]; +} + +// MaxCallsLimit limited number of calls to the contract. No funds transferable. +// Since: wasmd 0.30 +message MaxCallsLimit { + option (cosmos_proto.implements_interface) = "ContractAuthzLimitX"; + + // Remaining number that is decremented on each execution + uint64 remaining = 1; +} + +// MaxFundsLimit defines the maximal amounts that can be sent to the contract. +// Since: wasmd 0.30 +message MaxFundsLimit { + option (cosmos_proto.implements_interface) = "ContractAuthzLimitX"; + + // Amounts is the maximal amount of tokens transferable to the contract. + repeated cosmos.base.v1beta1.Coin amounts = 1 [ + (gogoproto.nullable) = false, + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins" + ]; +} + +// CombinedLimit defines the maximal amounts that can be sent to a contract and +// the maximal number of calls executable. Both need to remain >0 to be valid. +// Since: wasmd 0.30 +message CombinedLimit { + option (cosmos_proto.implements_interface) = "ContractAuthzLimitX"; + + // Remaining number that is decremented on each execution + uint64 calls_remaining = 1; + // Amounts is the maximal amount of tokens transferable to the contract. + repeated cosmos.base.v1beta1.Coin amounts = 2 [ + (gogoproto.nullable) = false, + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins" + ]; +} + +// AllowAllMessagesFilter is a wildcard to allow any type of contract payload +// message. +// Since: wasmd 0.30 +message AllowAllMessagesFilter { + option (cosmos_proto.implements_interface) = "ContractAuthzFilterX"; +} + +// AcceptedMessageKeysFilter accept only the specific contract message keys in +// the json object to be executed. +// Since: wasmd 0.30 +message AcceptedMessageKeysFilter { + option (cosmos_proto.implements_interface) = "ContractAuthzFilterX"; + + // Messages is the list of unique keys + repeated string keys = 1; +} + +// AcceptedMessagesFilter accept only the specific raw contract messages to be +// executed. +// Since: wasmd 0.30 +message AcceptedMessagesFilter { + option (cosmos_proto.implements_interface) = "ContractAuthzFilterX"; + + // Messages is the list of raw contract messages + repeated bytes messages = 1 [ (gogoproto.casttype) = "RawContractMessage" ]; +} diff --git a/tests/e2e/README.md b/tests/e2e/README.md new file mode 100644 index 0000000000..dae38fe2df --- /dev/null +++ b/tests/e2e/README.md @@ -0,0 +1,3 @@ +# End To End Testing - e2e + +Scenario tests that run against on or multiple chain instances. diff --git a/tests/e2e/grants_test.go b/tests/e2e/grants_test.go new file mode 100644 index 0000000000..0920fa0a3d --- /dev/null +++ b/tests/e2e/grants_test.go @@ -0,0 +1,116 @@ +package e2e_test + +import ( + "fmt" + "testing" + "time" + + "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/cosmos-sdk/x/authz" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/CosmWasm/wasmd/x/wasm/ibctesting" + "github.com/CosmWasm/wasmd/x/wasm/types" +) + +func TestGrants(t *testing.T) { + // Given a contract by address A + // And a grant for address B by A created + // When B sends an execute with tokens from A + // Then the grant is executed as defined + // And + // - balance A reduced (on success) + // - balance B not touched + + chain := ibctesting.NewCoordinator(t, 1).GetChain(ibctesting.GetChainID(0)) + codeID := chain.StoreCodeFile("../../x/wasm/keeper/testdata/reflect_1_1.wasm").CodeID + contractAddr := chain.InstantiateContract(codeID, []byte(`{}`)) + require.NotEmpty(t, contractAddr) + + granterAddr := chain.SenderAccount.GetAddress() + granteePrivKey := secp256k1.GenPrivKey() + granteeAddr := sdk.AccAddress(granteePrivKey.PubKey().Address().Bytes()) + otherPrivKey := secp256k1.GenPrivKey() + otherAddr := sdk.AccAddress(otherPrivKey.PubKey().Address().Bytes()) + + chain.Fund(granteeAddr, sdk.NewInt(1_000_000)) + chain.Fund(otherAddr, sdk.NewInt(1_000_000)) + assert.Equal(t, sdk.NewInt(1_000_000), chain.Balance(granteeAddr, sdk.DefaultBondDenom).Amount) + + myAmount := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(2_000_000)) + + specs := map[string]struct { + limit types.ContractAuthzLimitX + filter types.ContractAuthzFilterX + transferAmount sdk.Coin + senderKey cryptotypes.PrivKey + expErr *sdkerrors.Error + }{ + "in limits and filter": { + limit: types.NewMaxFundsLimit(myAmount), + filter: types.NewAllowAllMessagesFilter(), + transferAmount: myAmount, + senderKey: granteePrivKey, + }, + "exceed limits": { + limit: types.NewMaxFundsLimit(myAmount), + filter: types.NewAllowAllMessagesFilter(), + transferAmount: myAmount.Add(sdk.NewCoin(sdk.DefaultBondDenom, sdk.OneInt())), + senderKey: granteePrivKey, + expErr: sdkerrors.ErrUnauthorized, + }, + "not match filter": { + limit: types.NewMaxFundsLimit(myAmount), + filter: types.NewAcceptedMessageKeysFilter("foo"), + transferAmount: sdk.NewCoin(sdk.DefaultBondDenom, sdk.OneInt()), + senderKey: granteePrivKey, + expErr: sdkerrors.ErrUnauthorized, + }, + "non authorized sender address": { // sanity check - testing sdk + limit: types.NewMaxFundsLimit(myAmount), + filter: types.NewAllowAllMessagesFilter(), + senderKey: otherPrivKey, + transferAmount: myAmount, + expErr: sdkerrors.ErrUnauthorized, + }, + } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + // setup grant + grant, err := types.NewContractGrant(contractAddr, spec.limit, spec.filter) + require.NoError(t, err) + authorization := types.NewContractExecutionAuthorization(*grant) + grantMsg, err := authz.NewMsgGrant(granterAddr, granteeAddr, authorization, time.Now().Add(time.Hour)) + require.NoError(t, err) + _, err = chain.SendMsgs(grantMsg) + require.NoError(t, err) + + granterStartBalance := chain.Balance(granterAddr, sdk.DefaultBondDenom).Amount + + // when + anyValidReflectMsg := []byte(fmt.Sprintf(`{"reflect_msg": {"msgs": [{"bank":{"burn":{"amount":[{"denom":%q, "amount": %q}]}}}]}}`, sdk.DefaultBondDenom, myAmount.Amount.String())) + execMsg := authz.NewMsgExec(spec.senderKey.PubKey().Address().Bytes(), []sdk.Msg{&types.MsgExecuteContract{ + Sender: granterAddr.String(), + Contract: contractAddr.String(), + Msg: anyValidReflectMsg, + Funds: sdk.NewCoins(spec.transferAmount), + }}) + _, gotErr := chain.SendNonDefaultSenderMsgs(spec.senderKey, &execMsg) + + // then + if spec.expErr != nil { + require.ErrorIs(t, gotErr, spec.expErr) + assert.Equal(t, sdk.NewInt(1_000_000), chain.Balance(granteeAddr, sdk.DefaultBondDenom).Amount) + assert.Equal(t, granterStartBalance, chain.Balance(granterAddr, sdk.DefaultBondDenom).Amount) + return + } + require.NoError(t, gotErr) + assert.Equal(t, sdk.NewInt(1_000_000), chain.Balance(granteeAddr, sdk.DefaultBondDenom).Amount) + assert.Equal(t, granterStartBalance.Sub(spec.transferAmount.Amount), chain.Balance(granterAddr, sdk.DefaultBondDenom).Amount) + }) + } +} diff --git a/x/wasm/client/cli/tx.go b/x/wasm/client/cli/tx.go index 7e4c6e36f0..d8227f7cd3 100644 --- a/x/wasm/client/cli/tx.go +++ b/x/wasm/client/cli/tx.go @@ -32,6 +32,9 @@ const ( flagInstantiateByAddress = "instantiate-only-address" flagInstantiateByAnyOfAddress = "instantiate-anyof-addresses" flagUnpinCode = "unpin-code" + flagAllowedMsgs = "allow-msgs" + flagRunOnce = "run-once" + flagExpiration = "expiration" ) // GetTxCmd returns the transaction commands for this module @@ -52,6 +55,7 @@ func GetTxCmd() *cobra.Command { MigrateContractCmd(), UpdateContractAdminCmd(), ClearContractAdminCmd(), + GrantAuthorizationCmd(), ) return txCmd } @@ -377,3 +381,57 @@ func parseExecuteArgs(contractAddr string, execMsg string, sender sdk.AccAddress Msg: []byte(execMsg), }, nil } + +func GrantAuthorizationCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "grant [grantee] [contract_addr_bech32] --allow-msgs [msg1,msg2,...]", + Short: "Grant authorization to an address", + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + grantee, err := sdk.AccAddressFromBech32(args[0]) + if err != nil { + return err + } + + contract, err := sdk.AccAddressFromBech32(args[1]) + if err != nil { + return err + } + + msgs, err := cmd.Flags().GetStringSlice(flagAllowedMsgs) + if err != nil { + return err + } + + once, err := cmd.Flags().GetBool(flagRunOnce) + if err != nil { + return err + } + + exp, err := cmd.Flags().GetInt64(flagExpiration) + if err != nil { + return err + } + if exp == 0 { + return errors.New("expiration must be set") + } + _ = clientCtx + _ = grantee + _ = msgs + _ = once + _ = contract + + return errors.New("not implemented") + }, + } + flags.AddTxFlagsToCmd(cmd) + cmd.Flags().StringSlice(flagAllowedMsgs, []string{}, "Allowed msgs") + cmd.Flags().Bool(flagRunOnce, false, "Allow to execute only once") + cmd.Flags().Int64(flagExpiration, 0, "The Unix timestamp.") + return cmd +} diff --git a/x/wasm/ibctesting/chain.go b/x/wasm/ibctesting/chain.go index 8d0adfb72a..fb24372d8a 100644 --- a/x/wasm/ibctesting/chain.go +++ b/x/wasm/ibctesting/chain.go @@ -145,7 +145,7 @@ func (chain *TestChain) QueryProof(key []byte) ([]byte, clienttypes.Height) { return chain.QueryProofAtHeight(key, chain.App.LastBlockHeight()) } -// QueryProof performs an abci query with the given key and returns the proto encoded merkle proof +// QueryProofAtHeight performs an abci query with the given key and returns the proto encoded merkle proof // for the query and the height at which the proof will succeed on a tendermint verifier. func (chain *TestChain) QueryProofAtHeight(key []byte, height int64) ([]byte, clienttypes.Height) { res := chain.App.Query(abci.RequestQuery{ @@ -251,50 +251,15 @@ func (chain *TestChain) SendMsgs(msgs ...sdk.Msg) (*sdk.Result, error) { chain.ChainID, []uint64{chain.SenderAccount.GetAccountNumber()}, []uint64{chain.SenderAccount.GetSequence()}, - true, true, chain.SenderPrivKey, + chain.SenderPrivKey, ) - if err != nil { - return nil, err - } // SignAndDeliver calls app.Commit() chain.NextBlock() - - // increment sequence for successful transaction execution - err = chain.SenderAccount.SetSequence(chain.SenderAccount.GetSequence() + 1) if err != nil { - return nil, err + return r, err } - chain.Coordinator.IncrementTime() - - chain.captureIBCEvents(r) - - return r, nil -} - -func (chain *TestChain) SendMsgsExpPass(expPass bool, msgs ...sdk.Msg) (*sdk.Result, error) { - // ensure the chain has the latest time - chain.Coordinator.UpdateTimeForChain(chain) - - _, r, err := app.SignAndDeliver( - chain.t, - chain.TxConfig, - chain.App.BaseApp, - chain.GetContext().BlockHeader(), - msgs, - chain.ChainID, - []uint64{chain.SenderAccount.GetAccountNumber()}, - []uint64{chain.SenderAccount.GetSequence()}, - true, expPass, chain.SenderPrivKey, - ) - if err != nil { - return nil, err - } - - // SignAndDeliver calls app.Commit() - chain.NextBlock() - // increment sequence for successful transaction execution err = chain.SenderAccount.SetSequence(chain.SenderAccount.GetSequence() + 1) if err != nil { diff --git a/x/wasm/ibctesting/faucet.go b/x/wasm/ibctesting/faucet.go new file mode 100644 index 0000000000..d5098c34c8 --- /dev/null +++ b/x/wasm/ibctesting/faucet.go @@ -0,0 +1,52 @@ +package ibctesting + +import ( + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + sdk "github.com/cosmos/cosmos-sdk/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/stretchr/testify/require" + + "github.com/CosmWasm/wasmd/app" +) + +// Fund an address with the given amount in default denom +func (chain *TestChain) Fund(addr sdk.AccAddress, amount sdk.Int) { + require.NoError(chain.t, chain.sendMsgs(&banktypes.MsgSend{ + FromAddress: chain.SenderAccount.GetAddress().String(), + ToAddress: addr.String(), + Amount: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, amount)), + })) +} + +// SendNonDefaultSenderMsgs delivers a transaction through the application. It returns the result and error if one +// occurred. +func (chain *TestChain) SendNonDefaultSenderMsgs(senderPrivKey cryptotypes.PrivKey, msgs ...sdk.Msg) (*sdk.Result, error) { + require.NotEqual(chain.t, chain.SenderPrivKey, senderPrivKey, "use SendMsgs method") + + // ensure the chain has the latest time + chain.Coordinator.UpdateTimeForChain(chain) + + addr := sdk.AccAddress(senderPrivKey.PubKey().Address().Bytes()) + account := chain.App.AccountKeeper.GetAccount(chain.GetContext(), addr) + require.NotNil(chain.t, account) + _, r, err := app.SignAndDeliver( + chain.t, + chain.TxConfig, + chain.App.BaseApp, + chain.GetContext().BlockHeader(), + msgs, + chain.ChainID, + []uint64{account.GetAccountNumber()}, + []uint64{account.GetSequence()}, + senderPrivKey, + ) + + // SignAndDeliver calls app.Commit() + chain.NextBlock() + chain.Coordinator.IncrementTime() + if err != nil { + return r, err + } + chain.captureIBCEvents(r) + return r, nil +} diff --git a/x/wasm/relay_test.go b/x/wasm/relay_test.go index 7645f42365..4e72bd84f6 100644 --- a/x/wasm/relay_test.go +++ b/x/wasm/relay_test.go @@ -416,7 +416,7 @@ func TestContractEmulateIBCTransferMessageOnDiffContractIBCChannel(t *testing.T) }.GetBytes(), Funds: sdk.NewCoins(coinToSendToB), } - _, err := chainA.SendMsgsExpPass(false, startMsg) + _, err := chainA.SendMsgs(startMsg) require.Error(t, err) } @@ -519,7 +519,7 @@ func TestContractHandlesChannelCloseNotOwned(t *testing.T) { Funds: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100))), } - _, err := chainA.SendMsgsExpPass(false, closeIBCChannelMsg) + _, err := chainA.SendMsgs(closeIBCChannelMsg) require.Error(t, err) } diff --git a/x/wasm/types/authz.go b/x/wasm/types/authz.go new file mode 100644 index 0000000000..10dd2606c9 --- /dev/null +++ b/x/wasm/types/authz.go @@ -0,0 +1,534 @@ +package types + +import ( + "strings" + + "github.com/gogo/protobuf/proto" + + cdctypes "github.com/cosmos/cosmos-sdk/codec/types" + + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + authztypes "github.com/cosmos/cosmos-sdk/x/authz" +) + +const gasDeserializationCostPerByte = uint64(1) + +var ( + _ authztypes.Authorization = &ContractExecutionAuthorization{} + _ authztypes.Authorization = &ContractMigrationAuthorization{} + _ cdctypes.UnpackInterfacesMessage = &ContractExecutionAuthorization{} + _ cdctypes.UnpackInterfacesMessage = &ContractMigrationAuthorization{} +) + +// AuthzableWasmMsg is abstract wasm tx message that is supported in authz +type AuthzableWasmMsg interface { + GetFunds() sdk.Coins + GetMsg() RawContractMessage + GetContract() string + ValidateBasic() error +} + +// NewContractExecutionAuthorization constructor +func NewContractExecutionAuthorization(grants ...ContractGrant) *ContractExecutionAuthorization { + return &ContractExecutionAuthorization{ + Grants: grants, + } +} + +// MsgTypeURL implements Authorization.MsgTypeURL. +func (a ContractExecutionAuthorization) MsgTypeURL() string { + return sdk.MsgTypeURL(&MsgExecuteContract{}) +} + +// NewAuthz factory method to create an Authorization with updated grants +func (a ContractExecutionAuthorization) NewAuthz(g []ContractGrant) authztypes.Authorization { + return NewContractExecutionAuthorization(g...) +} + +// Accept implements Authorization.Accept. +func (a *ContractExecutionAuthorization) Accept(ctx sdk.Context, msg sdk.Msg) (authztypes.AcceptResponse, error) { + return AcceptGrantedMessage[*MsgExecuteContract](ctx, a.Grants, msg, a) +} + +// ValidateBasic implements Authorization.ValidateBasic. +func (a ContractExecutionAuthorization) ValidateBasic() error { + return validateGrants(a.Grants) +} + +// UnpackInterfaces implements UnpackInterfacesMessage.UnpackInterfaces +func (a ContractExecutionAuthorization) UnpackInterfaces(unpacker cdctypes.AnyUnpacker) error { + for _, g := range a.Grants { + if err := g.UnpackInterfaces(unpacker); err != nil { + return err + } + } + return nil +} + +// NewContractMigrationAuthorization constructor +func NewContractMigrationAuthorization(grants ...ContractGrant) *ContractMigrationAuthorization { + return &ContractMigrationAuthorization{ + Grants: grants, + } +} + +// MsgTypeURL implements Authorization.MsgTypeURL. +func (a ContractMigrationAuthorization) MsgTypeURL() string { + return sdk.MsgTypeURL(&MsgMigrateContract{}) +} + +// Accept implements Authorization.Accept. +func (a *ContractMigrationAuthorization) Accept(ctx sdk.Context, msg sdk.Msg) (authztypes.AcceptResponse, error) { + return AcceptGrantedMessage[*MsgMigrateContract](ctx, a.Grants, msg, a) +} + +// NewAuthz factory method to create an Authorization with updated grants +func (a ContractMigrationAuthorization) NewAuthz(g []ContractGrant) authztypes.Authorization { + return NewContractMigrationAuthorization(g...) +} + +// ValidateBasic implements Authorization.ValidateBasic. +func (a ContractMigrationAuthorization) ValidateBasic() error { + return validateGrants(a.Grants) +} + +// UnpackInterfaces implements UnpackInterfacesMessage.UnpackInterfaces +func (a ContractMigrationAuthorization) UnpackInterfaces(unpacker cdctypes.AnyUnpacker) error { + for _, g := range a.Grants { + if err := g.UnpackInterfaces(unpacker); err != nil { + return err + } + } + return nil +} + +func validateGrants(g []ContractGrant) error { + if len(g) == 0 { + return ErrEmpty.Wrap("grants") + } + for i, v := range g { + if err := v.ValidateBasic(); err != nil { + return sdkerrors.Wrapf(err, "position %d", i) + } + } + // allow multiple grants for a contract: + // contractA:doThis:1,doThat:* has with different counters for different methods + return nil +} + +// ContractAuthzFactory factory to create an updated Authorization object +type ContractAuthzFactory interface { + NewAuthz([]ContractGrant) authztypes.Authorization +} + +// AcceptGrantedMessage determines whether this grant permits the provided sdk.Msg to be performed, +// and if so provides an upgraded authorization instance. +func AcceptGrantedMessage[T AuthzableWasmMsg](ctx sdk.Context, grants []ContractGrant, msg sdk.Msg, factory ContractAuthzFactory) (authztypes.AcceptResponse, error) { + exec, ok := msg.(T) + if !ok { + return authztypes.AcceptResponse{}, sdkerrors.ErrInvalidType.Wrap("type mismatch") + } + if exec.GetMsg() == nil { + return authztypes.AcceptResponse{}, sdkerrors.ErrInvalidType.Wrap("empty message") + } + if err := exec.ValidateBasic(); err != nil { + return authztypes.AcceptResponse{}, err + } + + // iterate though all grants + for i, g := range grants { + if g.Contract != exec.GetContract() { + continue + } + + // first check limits + result, err := g.GetLimit().Accept(ctx, exec) + switch { + case err != nil: + return authztypes.AcceptResponse{}, sdkerrors.Wrap(err, "limit") + case result == nil: // sanity check + return authztypes.AcceptResponse{}, sdkerrors.ErrInvalidType.Wrap("limit result must not be nil") + case !result.Accepted: + // not applicable, continue with next grant + continue + } + + // then check permission set + ok, err := g.GetFilter().Accept(ctx, exec.GetMsg()) + switch { + case err != nil: + return authztypes.AcceptResponse{}, sdkerrors.Wrap(err, "filter") + case !ok: + // no limit update and continue with next grant + continue + } + + // finally do limit state updates in result + switch { + case result.DeleteLimit: + updatedGrants := append(grants[0:i], grants[i+1:]...) //nolint:gocritic + if len(updatedGrants) == 0 { // remove when empty + return authztypes.AcceptResponse{Accept: true, Delete: true}, nil + } + newAuthz := factory.NewAuthz(updatedGrants) + if err := newAuthz.ValidateBasic(); err != nil { // sanity check + return authztypes.AcceptResponse{}, ErrInvalid.Wrapf("new grant state: %s", err) + } + return authztypes.AcceptResponse{Accept: true, Updated: newAuthz}, nil + case result.UpdateLimit != nil: + obj, err := g.WithNewLimits(result.UpdateLimit) + if err != nil { + return authztypes.AcceptResponse{}, err + } + newAuthz := factory.NewAuthz(append(append(grants[0:i], *obj), grants[i+1:]...)) + if err := newAuthz.ValidateBasic(); err != nil { // sanity check + return authztypes.AcceptResponse{}, ErrInvalid.Wrapf("new grant state: %s", err) + } + return authztypes.AcceptResponse{Accept: true, Updated: newAuthz}, nil + default: // accepted without a limit state update + return authztypes.AcceptResponse{Accept: true}, nil + } + } + return authztypes.AcceptResponse{Accept: false}, nil +} + +// ContractAuthzLimitX define execution limits that are enforced and updated when the grant +// is applied. When the limit lapsed the grant is removed. +type ContractAuthzLimitX interface { + Accept(ctx sdk.Context, msg AuthzableWasmMsg) (*ContractAuthzLimitAcceptResult, error) + ValidateBasic() error +} + +// ContractAuthzLimitAcceptResult result of the ContractAuthzLimitX.Accept method +type ContractAuthzLimitAcceptResult struct { + // Accepted is true when limit applies + Accepted bool + // DeleteLimit when set it is the end of life for this limit. Grant is removed from persistent store + DeleteLimit bool + // UpdateLimit update persistent state with new value + UpdateLimit ContractAuthzLimitX +} + +// ContractAuthzFilterX define more fine-grained control on the message payload passed +// to the contract in the operation. When no filter applies on execution, the +// operation is prohibited. +type ContractAuthzFilterX interface { + // Accept returns applicable or error + Accept(ctx sdk.Context, msg RawContractMessage) (bool, error) + ValidateBasic() error +} + +var _ cdctypes.UnpackInterfacesMessage = &ContractGrant{} + +// NewContractGrant constructor +func NewContractGrant(contract sdk.AccAddress, limit ContractAuthzLimitX, filter ContractAuthzFilterX) (*ContractGrant, error) { + pFilter, ok := filter.(proto.Message) + if !ok { + return nil, sdkerrors.ErrInvalidType.Wrap("filter is not a proto type") + } + anyFilter, err := cdctypes.NewAnyWithValue(pFilter) + if err != nil { + return nil, sdkerrors.Wrap(err, "filter") + } + return ContractGrant{ + Contract: contract.String(), + Filter: anyFilter, + }.WithNewLimits(limit) +} + +// WithNewLimits factory method to create a new grant with given limit +func (g ContractGrant) WithNewLimits(limit ContractAuthzLimitX) (*ContractGrant, error) { + pLimit, ok := limit.(proto.Message) + if !ok { + return nil, sdkerrors.ErrInvalidType.Wrap("limit is not a proto type") + } + anyLimit, err := cdctypes.NewAnyWithValue(pLimit) + if err != nil { + return nil, sdkerrors.Wrap(err, "limit") + } + + return &ContractGrant{ + Contract: g.Contract, + Limit: anyLimit, + Filter: g.Filter, + }, nil +} + +// UnpackInterfaces implements UnpackInterfacesMessage.UnpackInterfaces +func (g ContractGrant) UnpackInterfaces(unpacker cdctypes.AnyUnpacker) error { + var f ContractAuthzFilterX + if err := unpacker.UnpackAny(g.Filter, &f); err != nil { + return sdkerrors.Wrap(err, "filter") + } + var l ContractAuthzLimitX + if err := unpacker.UnpackAny(g.Limit, &l); err != nil { + return sdkerrors.Wrap(err, "limit") + } + return nil +} + +// GetLimit returns the cached value from the ContractGrant.Limit if present. +func (g ContractGrant) GetLimit() ContractAuthzLimitX { + if g.Limit == nil { + return &UndefinedLimit{} + } + a, ok := g.Limit.GetCachedValue().(ContractAuthzLimitX) + if !ok { + return &UndefinedLimit{} + } + return a +} + +// GetFilter returns the cached value from the ContractGrant.Filter if present. +func (g ContractGrant) GetFilter() ContractAuthzFilterX { + if g.Filter == nil { + return &UndefinedFilter{} + } + a, ok := g.Filter.GetCachedValue().(ContractAuthzFilterX) + if !ok { + return &UndefinedFilter{} + } + return a +} + +// ValidateBasic validates the grant +func (g ContractGrant) ValidateBasic() error { + if _, err := sdk.AccAddressFromBech32(g.Contract); err != nil { + return sdkerrors.Wrap(err, "contract") + } + // execution limits + if err := g.GetLimit().ValidateBasic(); err != nil { + return sdkerrors.Wrap(err, "limit") + } + // filter + if err := g.GetFilter().ValidateBasic(); err != nil { + return sdkerrors.Wrap(err, "filter") + } + return nil +} + +// UndefinedFilter null object that is always rejected in execution +type UndefinedFilter struct{} + +// Accept always returns error +func (f *UndefinedFilter) Accept(ctx sdk.Context, msg RawContractMessage) (bool, error) { + return false, sdkerrors.ErrNotFound.Wrapf("undefined filter") +} + +// ValidateBasic always returns error +func (f UndefinedFilter) ValidateBasic() error { + return sdkerrors.ErrInvalidType.Wrapf("undefined filter") +} + +// NewAllowAllMessagesFilter constructor +func NewAllowAllMessagesFilter() *AllowAllMessagesFilter { + return &AllowAllMessagesFilter{} +} + +// Accept accepts any valid json message content. +func (f *AllowAllMessagesFilter) Accept(ctx sdk.Context, msg RawContractMessage) (bool, error) { + return true, msg.ValidateBasic() +} + +// ValidateBasic returns always nil +func (f AllowAllMessagesFilter) ValidateBasic() error { + return nil +} + +// NewAcceptedMessageKeysFilter constructor +func NewAcceptedMessageKeysFilter(acceptedKeys ...string) *AcceptedMessageKeysFilter { + return &AcceptedMessageKeysFilter{Keys: acceptedKeys} +} + +// Accept only payload messages which contain one of the accepted key names in the json object. +func (f *AcceptedMessageKeysFilter) Accept(ctx sdk.Context, msg RawContractMessage) (bool, error) { + gasForDeserialization := gasDeserializationCostPerByte * uint64(len(msg)) + ctx.GasMeter().ConsumeGas(gasForDeserialization, "contract authorization") + + ok, err := isJSONObjectWithTopLevelKey(msg, f.Keys) + if err != nil { + return false, sdkerrors.ErrUnauthorized.Wrapf("not an allowed msg: %s", err.Error()) + } + return ok, nil +} + +// ValidateBasic validates the filter +func (f AcceptedMessageKeysFilter) ValidateBasic() error { + if len(f.Keys) == 0 { + return ErrEmpty.Wrap("keys") + } + idx := make(map[string]struct{}, len(f.Keys)) + for _, m := range f.Keys { + if m == "" { + return ErrEmpty.Wrap("key") + } + if m != strings.TrimSpace(m) { + return ErrInvalid.Wrapf("key %q contains whitespaces", m) + } + if _, exists := idx[m]; exists { + return ErrDuplicate.Wrapf("key %q", m) + } + idx[m] = struct{}{} + } + return nil +} + +// NewAcceptedMessagesFilter constructor +func NewAcceptedMessagesFilter(msgs ...RawContractMessage) *AcceptedMessagesFilter { + return &AcceptedMessagesFilter{Messages: msgs} +} + +// Accept only payload messages which are equal to the granted one. +func (f *AcceptedMessagesFilter) Accept(ctx sdk.Context, msg RawContractMessage) (bool, error) { + for _, v := range f.Messages { + if v.Equal(msg) { + return true, nil + } + } + return false, nil +} + +// ValidateBasic validates the filter +func (f AcceptedMessagesFilter) ValidateBasic() error { + if len(f.Messages) == 0 { + return ErrEmpty.Wrap("messages") + } + idx := make(map[string]struct{}, len(f.Messages)) + for _, m := range f.Messages { + if len(m) == 0 { + return ErrEmpty.Wrap("message") + } + if err := m.ValidateBasic(); err != nil { + return err + } + if _, exists := idx[string(m)]; exists { + return ErrDuplicate.Wrap("message") + } + idx[string(m)] = struct{}{} + } + return nil +} + +var ( + _ ContractAuthzLimitX = &UndefinedLimit{} + _ ContractAuthzLimitX = &MaxCallsLimit{} + _ ContractAuthzLimitX = &MaxFundsLimit{} + _ ContractAuthzLimitX = &CombinedLimit{} +) + +// UndefinedLimit null object that is always rejected in execution +type UndefinedLimit struct{} + +// ValidateBasic always returns error +func (u UndefinedLimit) ValidateBasic() error { + return sdkerrors.ErrInvalidType.Wrapf("undefined limit") +} + +// Accept always returns error +func (u UndefinedLimit) Accept(ctx sdk.Context, msg AuthzableWasmMsg) (*ContractAuthzLimitAcceptResult, error) { + return nil, sdkerrors.ErrNotFound.Wrapf("undefined filter") +} + +// NewMaxCallsLimit constructor +func NewMaxCallsLimit(number uint64) *MaxCallsLimit { + return &MaxCallsLimit{Remaining: number} +} + +// Accept only the defined number of message calls. No token transfers to the contract allowed. +func (m MaxCallsLimit) Accept(_ sdk.Context, msg AuthzableWasmMsg) (*ContractAuthzLimitAcceptResult, error) { + if !msg.GetFunds().Empty() { + return &ContractAuthzLimitAcceptResult{Accepted: false}, nil + } + switch n := m.Remaining; n { + case 0: // sanity check + return nil, sdkerrors.ErrUnauthorized.Wrap("no calls left") + case 1: + return &ContractAuthzLimitAcceptResult{Accepted: true, DeleteLimit: true}, nil + default: + return &ContractAuthzLimitAcceptResult{Accepted: true, UpdateLimit: &MaxCallsLimit{Remaining: n - 1}}, nil + } +} + +// ValidateBasic validates the limit +func (m MaxCallsLimit) ValidateBasic() error { + if m.Remaining == 0 { + return ErrEmpty.Wrap("remaining calls") + } + return nil +} + +// NewMaxFundsLimit constructor +// A panic will occur if the coin set is not valid. +func NewMaxFundsLimit(max ...sdk.Coin) *MaxFundsLimit { + return &MaxFundsLimit{Amounts: sdk.NewCoins(max...)} +} + +// Accept until the defined budget for token transfers to the contract is spent +func (m MaxFundsLimit) Accept(_ sdk.Context, msg AuthzableWasmMsg) (*ContractAuthzLimitAcceptResult, error) { + if msg.GetFunds().Empty() { // no state changes required + return &ContractAuthzLimitAcceptResult{Accepted: true}, nil + } + if !msg.GetFunds().IsAllLTE(m.Amounts) { + return &ContractAuthzLimitAcceptResult{Accepted: false}, nil + } + newAmounts := m.Amounts.Sub(msg.GetFunds()) + if newAmounts.IsZero() { + return &ContractAuthzLimitAcceptResult{Accepted: true, DeleteLimit: true}, nil + } + return &ContractAuthzLimitAcceptResult{Accepted: true, UpdateLimit: &MaxFundsLimit{Amounts: newAmounts}}, nil +} + +// ValidateBasic validates the limit +func (m MaxFundsLimit) ValidateBasic() error { + if err := m.Amounts.Validate(); err != nil { + return err + } + if m.Amounts.IsZero() { + return ErrEmpty.Wrap("amounts") + } + return nil +} + +// NewCombinedLimit constructor +// A panic will occur if the coin set is not valid. +func NewCombinedLimit(maxCalls uint64, maxAmounts ...sdk.Coin) *CombinedLimit { + return &CombinedLimit{CallsRemaining: maxCalls, Amounts: sdk.NewCoins(maxAmounts...)} +} + +// Accept until the max calls is reached or the token budget is spent. +func (l CombinedLimit) Accept(_ sdk.Context, msg AuthzableWasmMsg) (*ContractAuthzLimitAcceptResult, error) { + transferFunds := msg.GetFunds() + if !transferFunds.IsAllLTE(l.Amounts) { + return &ContractAuthzLimitAcceptResult{Accepted: false}, nil // does not apply + } + switch n := l.CallsRemaining; n { + case 0: // sanity check + return nil, sdkerrors.ErrUnauthorized.Wrap("no calls left") + case 1: + return &ContractAuthzLimitAcceptResult{Accepted: true, DeleteLimit: true}, nil + default: + remainingAmounts := l.Amounts.Sub(transferFunds) + if remainingAmounts.IsZero() { + return &ContractAuthzLimitAcceptResult{Accepted: true, DeleteLimit: true}, nil + } + return &ContractAuthzLimitAcceptResult{ + Accepted: true, + UpdateLimit: NewCombinedLimit(n-1, remainingAmounts...), + }, nil + } +} + +// ValidateBasic validates the limit +func (l CombinedLimit) ValidateBasic() error { + if l.CallsRemaining == 0 { + return ErrEmpty.Wrap("remaining calls") + } + if l.Amounts.IsZero() { + return ErrEmpty.Wrap("amounts") + } + if err := l.Amounts.Validate(); err != nil { + return sdkerrors.Wrap(err, "amounts") + } + return nil +} diff --git a/x/wasm/types/authz.pb.go b/x/wasm/types/authz.pb.go new file mode 100644 index 0000000000..549b558aa1 --- /dev/null +++ b/x/wasm/types/authz.pb.go @@ -0,0 +1,1865 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: cosmwasm/wasm/v1/authz.proto + +package types + +import ( + fmt "fmt" + io "io" + math "math" + math_bits "math/bits" + + _ "github.com/cosmos/cosmos-proto" + types "github.com/cosmos/cosmos-sdk/codec/types" + github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" + types1 "github.com/cosmos/cosmos-sdk/types" + _ "github.com/cosmos/gogoproto/gogoproto" + proto "github.com/gogo/protobuf/proto" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal + +var ( + _ = fmt.Errorf + _ = math.Inf +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// ContractExecutionAuthorization defines authorization for wasm execute. +// Since: wasmd 0.30 +type ContractExecutionAuthorization struct { + // Grants for contract executions + Grants []ContractGrant `protobuf:"bytes,1,rep,name=grants,proto3" json:"grants"` +} + +func (m *ContractExecutionAuthorization) Reset() { *m = ContractExecutionAuthorization{} } +func (m *ContractExecutionAuthorization) String() string { return proto.CompactTextString(m) } +func (*ContractExecutionAuthorization) ProtoMessage() {} +func (*ContractExecutionAuthorization) Descriptor() ([]byte, []int) { + return fileDescriptor_36ff3a20cf32b258, []int{0} +} + +func (m *ContractExecutionAuthorization) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} + +func (m *ContractExecutionAuthorization) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ContractExecutionAuthorization.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} + +func (m *ContractExecutionAuthorization) XXX_Merge(src proto.Message) { + xxx_messageInfo_ContractExecutionAuthorization.Merge(m, src) +} + +func (m *ContractExecutionAuthorization) XXX_Size() int { + return m.Size() +} + +func (m *ContractExecutionAuthorization) XXX_DiscardUnknown() { + xxx_messageInfo_ContractExecutionAuthorization.DiscardUnknown(m) +} + +var xxx_messageInfo_ContractExecutionAuthorization proto.InternalMessageInfo + +// ContractMigrationAuthorization defines authorization for wasm contract +// migration. Since: wasmd 0.30 +type ContractMigrationAuthorization struct { + // Grants for contract migrations + Grants []ContractGrant `protobuf:"bytes,1,rep,name=grants,proto3" json:"grants"` +} + +func (m *ContractMigrationAuthorization) Reset() { *m = ContractMigrationAuthorization{} } +func (m *ContractMigrationAuthorization) String() string { return proto.CompactTextString(m) } +func (*ContractMigrationAuthorization) ProtoMessage() {} +func (*ContractMigrationAuthorization) Descriptor() ([]byte, []int) { + return fileDescriptor_36ff3a20cf32b258, []int{1} +} + +func (m *ContractMigrationAuthorization) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} + +func (m *ContractMigrationAuthorization) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ContractMigrationAuthorization.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} + +func (m *ContractMigrationAuthorization) XXX_Merge(src proto.Message) { + xxx_messageInfo_ContractMigrationAuthorization.Merge(m, src) +} + +func (m *ContractMigrationAuthorization) XXX_Size() int { + return m.Size() +} + +func (m *ContractMigrationAuthorization) XXX_DiscardUnknown() { + xxx_messageInfo_ContractMigrationAuthorization.DiscardUnknown(m) +} + +var xxx_messageInfo_ContractMigrationAuthorization proto.InternalMessageInfo + +// ContractGrant a granted permission for a single contract +// Since: wasmd 0.30 +type ContractGrant struct { + // Contract is the bech32 address of the smart contract + Contract string `protobuf:"bytes,1,opt,name=contract,proto3" json:"contract,omitempty"` + // Limit defines execution limits that are enforced and updated when the grant + // is applied. When the limit lapsed the grant is removed. + Limit *types.Any `protobuf:"bytes,2,opt,name=limit,proto3" json:"limit,omitempty"` + // Filter define more fine-grained control on the message payload passed + // to the contract in the operation. When no filter applies on execution, the + // operation is prohibited. + Filter *types.Any `protobuf:"bytes,3,opt,name=filter,proto3" json:"filter,omitempty"` +} + +func (m *ContractGrant) Reset() { *m = ContractGrant{} } +func (m *ContractGrant) String() string { return proto.CompactTextString(m) } +func (*ContractGrant) ProtoMessage() {} +func (*ContractGrant) Descriptor() ([]byte, []int) { + return fileDescriptor_36ff3a20cf32b258, []int{2} +} + +func (m *ContractGrant) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} + +func (m *ContractGrant) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ContractGrant.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} + +func (m *ContractGrant) XXX_Merge(src proto.Message) { + xxx_messageInfo_ContractGrant.Merge(m, src) +} + +func (m *ContractGrant) XXX_Size() int { + return m.Size() +} + +func (m *ContractGrant) XXX_DiscardUnknown() { + xxx_messageInfo_ContractGrant.DiscardUnknown(m) +} + +var xxx_messageInfo_ContractGrant proto.InternalMessageInfo + +// MaxCallsLimit limited number of calls to the contract. No funds transferable. +// Since: wasmd 0.30 +type MaxCallsLimit struct { + // Remaining number that is decremented on each execution + Remaining uint64 `protobuf:"varint,1,opt,name=remaining,proto3" json:"remaining,omitempty"` +} + +func (m *MaxCallsLimit) Reset() { *m = MaxCallsLimit{} } +func (m *MaxCallsLimit) String() string { return proto.CompactTextString(m) } +func (*MaxCallsLimit) ProtoMessage() {} +func (*MaxCallsLimit) Descriptor() ([]byte, []int) { + return fileDescriptor_36ff3a20cf32b258, []int{3} +} + +func (m *MaxCallsLimit) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} + +func (m *MaxCallsLimit) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MaxCallsLimit.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} + +func (m *MaxCallsLimit) XXX_Merge(src proto.Message) { + xxx_messageInfo_MaxCallsLimit.Merge(m, src) +} + +func (m *MaxCallsLimit) XXX_Size() int { + return m.Size() +} + +func (m *MaxCallsLimit) XXX_DiscardUnknown() { + xxx_messageInfo_MaxCallsLimit.DiscardUnknown(m) +} + +var xxx_messageInfo_MaxCallsLimit proto.InternalMessageInfo + +// MaxFundsLimit defines the maximal amounts that can be sent to the contract. +// Since: wasmd 0.30 +type MaxFundsLimit struct { + // Amounts is the maximal amount of tokens transferable to the contract. + Amounts github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,1,rep,name=amounts,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"amounts"` +} + +func (m *MaxFundsLimit) Reset() { *m = MaxFundsLimit{} } +func (m *MaxFundsLimit) String() string { return proto.CompactTextString(m) } +func (*MaxFundsLimit) ProtoMessage() {} +func (*MaxFundsLimit) Descriptor() ([]byte, []int) { + return fileDescriptor_36ff3a20cf32b258, []int{4} +} + +func (m *MaxFundsLimit) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} + +func (m *MaxFundsLimit) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MaxFundsLimit.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} + +func (m *MaxFundsLimit) XXX_Merge(src proto.Message) { + xxx_messageInfo_MaxFundsLimit.Merge(m, src) +} + +func (m *MaxFundsLimit) XXX_Size() int { + return m.Size() +} + +func (m *MaxFundsLimit) XXX_DiscardUnknown() { + xxx_messageInfo_MaxFundsLimit.DiscardUnknown(m) +} + +var xxx_messageInfo_MaxFundsLimit proto.InternalMessageInfo + +// CombinedLimit defines the maximal amounts that can be sent to a contract and +// the maximal number of calls executable. Both need to remain >0 to be valid. +// Since: wasmd 0.30 +type CombinedLimit struct { + // Remaining number that is decremented on each execution + CallsRemaining uint64 `protobuf:"varint,1,opt,name=calls_remaining,json=callsRemaining,proto3" json:"calls_remaining,omitempty"` + // Amounts is the maximal amount of tokens transferable to the contract. + Amounts github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,2,rep,name=amounts,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"amounts"` +} + +func (m *CombinedLimit) Reset() { *m = CombinedLimit{} } +func (m *CombinedLimit) String() string { return proto.CompactTextString(m) } +func (*CombinedLimit) ProtoMessage() {} +func (*CombinedLimit) Descriptor() ([]byte, []int) { + return fileDescriptor_36ff3a20cf32b258, []int{5} +} + +func (m *CombinedLimit) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} + +func (m *CombinedLimit) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_CombinedLimit.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} + +func (m *CombinedLimit) XXX_Merge(src proto.Message) { + xxx_messageInfo_CombinedLimit.Merge(m, src) +} + +func (m *CombinedLimit) XXX_Size() int { + return m.Size() +} + +func (m *CombinedLimit) XXX_DiscardUnknown() { + xxx_messageInfo_CombinedLimit.DiscardUnknown(m) +} + +var xxx_messageInfo_CombinedLimit proto.InternalMessageInfo + +// AllowAllMessagesFilter is a wildcard to allow any type of contract payload +// message. +// Since: wasmd 0.30 +type AllowAllMessagesFilter struct{} + +func (m *AllowAllMessagesFilter) Reset() { *m = AllowAllMessagesFilter{} } +func (m *AllowAllMessagesFilter) String() string { return proto.CompactTextString(m) } +func (*AllowAllMessagesFilter) ProtoMessage() {} +func (*AllowAllMessagesFilter) Descriptor() ([]byte, []int) { + return fileDescriptor_36ff3a20cf32b258, []int{6} +} + +func (m *AllowAllMessagesFilter) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} + +func (m *AllowAllMessagesFilter) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_AllowAllMessagesFilter.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} + +func (m *AllowAllMessagesFilter) XXX_Merge(src proto.Message) { + xxx_messageInfo_AllowAllMessagesFilter.Merge(m, src) +} + +func (m *AllowAllMessagesFilter) XXX_Size() int { + return m.Size() +} + +func (m *AllowAllMessagesFilter) XXX_DiscardUnknown() { + xxx_messageInfo_AllowAllMessagesFilter.DiscardUnknown(m) +} + +var xxx_messageInfo_AllowAllMessagesFilter proto.InternalMessageInfo + +// AcceptedMessageKeysFilter accept only the specific contract message keys in +// the json object to be executed. +// Since: wasmd 0.30 +type AcceptedMessageKeysFilter struct { + // Messages is the list of unique keys + Keys []string `protobuf:"bytes,1,rep,name=keys,proto3" json:"keys,omitempty"` +} + +func (m *AcceptedMessageKeysFilter) Reset() { *m = AcceptedMessageKeysFilter{} } +func (m *AcceptedMessageKeysFilter) String() string { return proto.CompactTextString(m) } +func (*AcceptedMessageKeysFilter) ProtoMessage() {} +func (*AcceptedMessageKeysFilter) Descriptor() ([]byte, []int) { + return fileDescriptor_36ff3a20cf32b258, []int{7} +} + +func (m *AcceptedMessageKeysFilter) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} + +func (m *AcceptedMessageKeysFilter) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_AcceptedMessageKeysFilter.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} + +func (m *AcceptedMessageKeysFilter) XXX_Merge(src proto.Message) { + xxx_messageInfo_AcceptedMessageKeysFilter.Merge(m, src) +} + +func (m *AcceptedMessageKeysFilter) XXX_Size() int { + return m.Size() +} + +func (m *AcceptedMessageKeysFilter) XXX_DiscardUnknown() { + xxx_messageInfo_AcceptedMessageKeysFilter.DiscardUnknown(m) +} + +var xxx_messageInfo_AcceptedMessageKeysFilter proto.InternalMessageInfo + +// AcceptedMessagesFilter accept only the specific raw contract messages to be +// executed. +// Since: wasmd 0.30 +type AcceptedMessagesFilter struct { + // Messages is the list of raw contract messages + Messages []RawContractMessage `protobuf:"bytes,1,rep,name=messages,proto3,casttype=RawContractMessage" json:"messages,omitempty"` +} + +func (m *AcceptedMessagesFilter) Reset() { *m = AcceptedMessagesFilter{} } +func (m *AcceptedMessagesFilter) String() string { return proto.CompactTextString(m) } +func (*AcceptedMessagesFilter) ProtoMessage() {} +func (*AcceptedMessagesFilter) Descriptor() ([]byte, []int) { + return fileDescriptor_36ff3a20cf32b258, []int{8} +} + +func (m *AcceptedMessagesFilter) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} + +func (m *AcceptedMessagesFilter) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_AcceptedMessagesFilter.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} + +func (m *AcceptedMessagesFilter) XXX_Merge(src proto.Message) { + xxx_messageInfo_AcceptedMessagesFilter.Merge(m, src) +} + +func (m *AcceptedMessagesFilter) XXX_Size() int { + return m.Size() +} + +func (m *AcceptedMessagesFilter) XXX_DiscardUnknown() { + xxx_messageInfo_AcceptedMessagesFilter.DiscardUnknown(m) +} + +var xxx_messageInfo_AcceptedMessagesFilter proto.InternalMessageInfo + +func init() { + proto.RegisterType((*ContractExecutionAuthorization)(nil), "cosmwasm.wasm.v1.ContractExecutionAuthorization") + proto.RegisterType((*ContractMigrationAuthorization)(nil), "cosmwasm.wasm.v1.ContractMigrationAuthorization") + proto.RegisterType((*ContractGrant)(nil), "cosmwasm.wasm.v1.ContractGrant") + proto.RegisterType((*MaxCallsLimit)(nil), "cosmwasm.wasm.v1.MaxCallsLimit") + proto.RegisterType((*MaxFundsLimit)(nil), "cosmwasm.wasm.v1.MaxFundsLimit") + proto.RegisterType((*CombinedLimit)(nil), "cosmwasm.wasm.v1.CombinedLimit") + proto.RegisterType((*AllowAllMessagesFilter)(nil), "cosmwasm.wasm.v1.AllowAllMessagesFilter") + proto.RegisterType((*AcceptedMessageKeysFilter)(nil), "cosmwasm.wasm.v1.AcceptedMessageKeysFilter") + proto.RegisterType((*AcceptedMessagesFilter)(nil), "cosmwasm.wasm.v1.AcceptedMessagesFilter") +} + +func init() { proto.RegisterFile("cosmwasm/wasm/v1/authz.proto", fileDescriptor_36ff3a20cf32b258) } + +var fileDescriptor_36ff3a20cf32b258 = []byte{ + // 578 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x54, 0x4d, 0x8f, 0xd2, 0x40, + 0x18, 0xa6, 0xbb, 0x2b, 0x2e, 0xb3, 0xe2, 0x47, 0x25, 0x08, 0x64, 0x53, 0x08, 0x07, 0xe5, 0x42, + 0x2b, 0x78, 0x23, 0xf1, 0x00, 0x28, 0xc6, 0x28, 0x97, 0x5e, 0xdc, 0x78, 0xd9, 0x4c, 0xcb, 0x50, + 0x26, 0xdb, 0x76, 0x48, 0x67, 0xca, 0xd7, 0x9f, 0xd0, 0xdf, 0xe1, 0x99, 0x83, 0x3f, 0x81, 0x70, + 0xda, 0xa3, 0xa7, 0x55, 0xe1, 0x5f, 0x78, 0x32, 0x9d, 0x99, 0xb2, 0x40, 0xc2, 0x1e, 0xf5, 0x52, + 0xe6, 0xfd, 0x78, 0x9e, 0xf7, 0x99, 0xf7, 0x7d, 0x19, 0x70, 0x6e, 0x13, 0xea, 0x8d, 0x21, 0xf5, + 0x0c, 0xfe, 0x19, 0xd5, 0x0c, 0x18, 0xb2, 0xc1, 0x4c, 0x1f, 0x06, 0x84, 0x11, 0xf5, 0x71, 0x1c, + 0xd5, 0xf9, 0x67, 0x54, 0x2b, 0x64, 0x1c, 0xe2, 0x10, 0x1e, 0x34, 0xa2, 0x93, 0xc8, 0x2b, 0xe4, + 0xa3, 0x3c, 0x42, 0x2f, 0x45, 0x40, 0x18, 0x32, 0xa4, 0x09, 0xcb, 0xb0, 0x20, 0x45, 0xc6, 0xa8, + 0x66, 0x21, 0x06, 0x6b, 0x86, 0x4d, 0xb0, 0x1f, 0x43, 0x1d, 0x42, 0x1c, 0x17, 0x19, 0xdc, 0xb2, + 0xc2, 0xbe, 0x01, 0xfd, 0xa9, 0x08, 0x95, 0x03, 0xa0, 0xb5, 0x89, 0xcf, 0x02, 0x68, 0xb3, 0xb7, + 0x13, 0x64, 0x87, 0x0c, 0x13, 0xbf, 0x19, 0xb2, 0x01, 0x09, 0xf0, 0x0c, 0x46, 0x86, 0xfa, 0x1a, + 0x24, 0x9d, 0x00, 0xfa, 0x8c, 0xe6, 0x94, 0xd2, 0x71, 0xe5, 0xac, 0x5e, 0xd4, 0xf7, 0x05, 0xeb, + 0x31, 0xc3, 0xbb, 0x28, 0xaf, 0x75, 0xb2, 0xb8, 0x29, 0x26, 0x4c, 0x09, 0x6a, 0x3c, 0x59, 0xce, + 0xab, 0xe9, 0x1d, 0xc6, 0xed, 0x9a, 0x5d, 0xec, 0x04, 0xf0, 0x5f, 0xd4, 0xfc, 0xae, 0x80, 0xf4, + 0x0e, 0x44, 0x2d, 0x80, 0x53, 0x5b, 0x3a, 0x72, 0x4a, 0x49, 0xa9, 0xa4, 0xcc, 0x8d, 0xad, 0xb6, + 0xc1, 0x3d, 0x17, 0x7b, 0x98, 0xe5, 0x8e, 0x4a, 0x4a, 0xe5, 0xac, 0x9e, 0xd1, 0x45, 0x03, 0xf5, + 0xb8, 0x81, 0x7a, 0xd3, 0x9f, 0xb6, 0x9e, 0x2d, 0xe7, 0xd5, 0xa7, 0x31, 0x67, 0x54, 0x6d, 0xf6, + 0x31, 0xc2, 0x5c, 0x98, 0x02, 0xab, 0x76, 0x40, 0xb2, 0x8f, 0x5d, 0x86, 0x82, 0xdc, 0xf1, 0x1d, + 0x2c, 0xb9, 0xe5, 0xbc, 0x9a, 0xd9, 0x61, 0xe9, 0x70, 0xd0, 0x85, 0x29, 0xd1, 0xe5, 0x0e, 0x48, + 0x77, 0xe1, 0xa4, 0x0d, 0x5d, 0x97, 0xf2, 0x02, 0xea, 0x39, 0x48, 0x05, 0xc8, 0x83, 0xd8, 0xc7, + 0xbe, 0xc3, 0xa5, 0x9f, 0x98, 0xb7, 0x8e, 0xc6, 0x21, 0x59, 0xe5, 0x2f, 0x0a, 0x27, 0xea, 0x84, + 0x7e, 0x4f, 0x12, 0x21, 0x70, 0x1f, 0x7a, 0x24, 0xbc, 0xed, 0x73, 0x5e, 0x97, 0x7b, 0x15, 0x6d, + 0x92, 0x2e, 0x37, 0x49, 0x6f, 0x13, 0xec, 0xb7, 0x5e, 0x46, 0x1d, 0xfe, 0xf6, 0xb3, 0x58, 0x71, + 0x30, 0x1b, 0x84, 0x96, 0x6e, 0x13, 0x4f, 0x2e, 0xa1, 0xfc, 0xa9, 0xd2, 0xde, 0x95, 0xc1, 0xa6, + 0x43, 0x44, 0x39, 0x80, 0x9a, 0x31, 0xf7, 0x61, 0x45, 0x62, 0x28, 0x9e, 0x85, 0x7d, 0xd4, 0x13, + 0x8a, 0x5e, 0x80, 0x47, 0x76, 0x74, 0xd1, 0xcb, 0xfd, 0x0b, 0x3e, 0xe4, 0x6e, 0x33, 0xf6, 0x6e, + 0x4b, 0x3f, 0xfa, 0x1f, 0xd2, 0xeb, 0x20, 0xdb, 0x74, 0x5d, 0x32, 0x6e, 0xba, 0x6e, 0x17, 0x51, + 0x0a, 0x1d, 0x44, 0xc5, 0xdc, 0x1a, 0x07, 0x07, 0x5a, 0x7e, 0x0f, 0xf2, 0x4d, 0xdb, 0x46, 0x43, + 0x86, 0x7a, 0x12, 0xf3, 0x01, 0x4d, 0x25, 0x4c, 0x55, 0xc1, 0xc9, 0x15, 0x9a, 0x8a, 0x41, 0xa4, + 0x4c, 0x7e, 0xbe, 0x83, 0xaa, 0x0f, 0xb2, 0x7b, 0x54, 0x31, 0x4f, 0x1d, 0x9c, 0x7a, 0xd2, 0xc3, + 0xb9, 0x1e, 0xb4, 0xb2, 0x7f, 0x6e, 0x8a, 0xaa, 0x09, 0xc7, 0x9b, 0xff, 0x9c, 0x08, 0x9b, 0x9b, + 0xbc, 0xc3, 0x75, 0x5a, 0x6f, 0x16, 0xbf, 0xb5, 0xc4, 0x62, 0xa5, 0x29, 0xd7, 0x2b, 0x4d, 0xf9, + 0xb5, 0xd2, 0x94, 0xaf, 0x6b, 0x2d, 0x71, 0xbd, 0xd6, 0x12, 0x3f, 0xd6, 0x5a, 0xe2, 0xf3, 0xf3, + 0xad, 0x86, 0xb6, 0x09, 0xf5, 0x3e, 0xc5, 0x6f, 0x5c, 0xcf, 0x98, 0x88, 0xb7, 0x8e, 0x37, 0xd5, + 0x4a, 0xf2, 0x8d, 0x7f, 0xf5, 0x37, 0x00, 0x00, 0xff, 0xff, 0x13, 0xc8, 0x1d, 0x99, 0x09, 0x05, + 0x00, 0x00, +} + +func (m *ContractExecutionAuthorization) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ContractExecutionAuthorization) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ContractExecutionAuthorization) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Grants) > 0 { + for iNdEx := len(m.Grants) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Grants[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintAuthz(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *ContractMigrationAuthorization) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ContractMigrationAuthorization) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ContractMigrationAuthorization) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Grants) > 0 { + for iNdEx := len(m.Grants) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Grants[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintAuthz(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *ContractGrant) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ContractGrant) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ContractGrant) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Filter != nil { + { + size, err := m.Filter.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintAuthz(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + if m.Limit != nil { + { + size, err := m.Limit.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintAuthz(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + if len(m.Contract) > 0 { + i -= len(m.Contract) + copy(dAtA[i:], m.Contract) + i = encodeVarintAuthz(dAtA, i, uint64(len(m.Contract))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MaxCallsLimit) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MaxCallsLimit) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MaxCallsLimit) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Remaining != 0 { + i = encodeVarintAuthz(dAtA, i, uint64(m.Remaining)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *MaxFundsLimit) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MaxFundsLimit) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MaxFundsLimit) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Amounts) > 0 { + for iNdEx := len(m.Amounts) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Amounts[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintAuthz(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *CombinedLimit) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *CombinedLimit) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *CombinedLimit) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Amounts) > 0 { + for iNdEx := len(m.Amounts) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Amounts[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintAuthz(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + if m.CallsRemaining != 0 { + i = encodeVarintAuthz(dAtA, i, uint64(m.CallsRemaining)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *AllowAllMessagesFilter) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *AllowAllMessagesFilter) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *AllowAllMessagesFilter) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *AcceptedMessageKeysFilter) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *AcceptedMessageKeysFilter) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *AcceptedMessageKeysFilter) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Keys) > 0 { + for iNdEx := len(m.Keys) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Keys[iNdEx]) + copy(dAtA[i:], m.Keys[iNdEx]) + i = encodeVarintAuthz(dAtA, i, uint64(len(m.Keys[iNdEx]))) + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *AcceptedMessagesFilter) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *AcceptedMessagesFilter) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *AcceptedMessagesFilter) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Messages) > 0 { + for iNdEx := len(m.Messages) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Messages[iNdEx]) + copy(dAtA[i:], m.Messages[iNdEx]) + i = encodeVarintAuthz(dAtA, i, uint64(len(m.Messages[iNdEx]))) + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func encodeVarintAuthz(dAtA []byte, offset int, v uint64) int { + offset -= sovAuthz(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} + +func (m *ContractExecutionAuthorization) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Grants) > 0 { + for _, e := range m.Grants { + l = e.Size() + n += 1 + l + sovAuthz(uint64(l)) + } + } + return n +} + +func (m *ContractMigrationAuthorization) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Grants) > 0 { + for _, e := range m.Grants { + l = e.Size() + n += 1 + l + sovAuthz(uint64(l)) + } + } + return n +} + +func (m *ContractGrant) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Contract) + if l > 0 { + n += 1 + l + sovAuthz(uint64(l)) + } + if m.Limit != nil { + l = m.Limit.Size() + n += 1 + l + sovAuthz(uint64(l)) + } + if m.Filter != nil { + l = m.Filter.Size() + n += 1 + l + sovAuthz(uint64(l)) + } + return n +} + +func (m *MaxCallsLimit) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Remaining != 0 { + n += 1 + sovAuthz(uint64(m.Remaining)) + } + return n +} + +func (m *MaxFundsLimit) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Amounts) > 0 { + for _, e := range m.Amounts { + l = e.Size() + n += 1 + l + sovAuthz(uint64(l)) + } + } + return n +} + +func (m *CombinedLimit) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.CallsRemaining != 0 { + n += 1 + sovAuthz(uint64(m.CallsRemaining)) + } + if len(m.Amounts) > 0 { + for _, e := range m.Amounts { + l = e.Size() + n += 1 + l + sovAuthz(uint64(l)) + } + } + return n +} + +func (m *AllowAllMessagesFilter) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *AcceptedMessageKeysFilter) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Keys) > 0 { + for _, s := range m.Keys { + l = len(s) + n += 1 + l + sovAuthz(uint64(l)) + } + } + return n +} + +func (m *AcceptedMessagesFilter) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Messages) > 0 { + for _, b := range m.Messages { + l = len(b) + n += 1 + l + sovAuthz(uint64(l)) + } + } + return n +} + +func sovAuthz(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} + +func sozAuthz(x uint64) (n int) { + return sovAuthz(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} + +func (m *ContractExecutionAuthorization) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthz + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ContractExecutionAuthorization: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ContractExecutionAuthorization: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Grants", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthz + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthAuthz + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthAuthz + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Grants = append(m.Grants, ContractGrant{}) + if err := m.Grants[len(m.Grants)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipAuthz(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthAuthz + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} + +func (m *ContractMigrationAuthorization) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthz + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ContractMigrationAuthorization: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ContractMigrationAuthorization: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Grants", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthz + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthAuthz + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthAuthz + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Grants = append(m.Grants, ContractGrant{}) + if err := m.Grants[len(m.Grants)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipAuthz(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthAuthz + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} + +func (m *ContractGrant) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthz + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ContractGrant: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ContractGrant: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Contract", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthz + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthAuthz + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthAuthz + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Contract = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Limit", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthz + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthAuthz + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthAuthz + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Limit == nil { + m.Limit = &types.Any{} + } + if err := m.Limit.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Filter", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthz + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthAuthz + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthAuthz + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Filter == nil { + m.Filter = &types.Any{} + } + if err := m.Filter.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipAuthz(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthAuthz + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} + +func (m *MaxCallsLimit) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthz + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MaxCallsLimit: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MaxCallsLimit: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Remaining", wireType) + } + m.Remaining = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthz + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Remaining |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipAuthz(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthAuthz + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} + +func (m *MaxFundsLimit) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthz + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MaxFundsLimit: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MaxFundsLimit: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Amounts", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthz + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthAuthz + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthAuthz + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Amounts = append(m.Amounts, types1.Coin{}) + if err := m.Amounts[len(m.Amounts)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipAuthz(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthAuthz + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} + +func (m *CombinedLimit) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthz + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: CombinedLimit: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: CombinedLimit: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field CallsRemaining", wireType) + } + m.CallsRemaining = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthz + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.CallsRemaining |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Amounts", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthz + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthAuthz + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthAuthz + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Amounts = append(m.Amounts, types1.Coin{}) + if err := m.Amounts[len(m.Amounts)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipAuthz(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthAuthz + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} + +func (m *AllowAllMessagesFilter) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthz + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: AllowAllMessagesFilter: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: AllowAllMessagesFilter: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipAuthz(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthAuthz + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} + +func (m *AcceptedMessageKeysFilter) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthz + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: AcceptedMessageKeysFilter: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: AcceptedMessageKeysFilter: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Keys", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthz + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthAuthz + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthAuthz + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Keys = append(m.Keys, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipAuthz(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthAuthz + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} + +func (m *AcceptedMessagesFilter) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthz + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: AcceptedMessagesFilter: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: AcceptedMessagesFilter: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Messages", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthz + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthAuthz + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthAuthz + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Messages = append(m.Messages, make([]byte, postIndex-iNdEx)) + copy(m.Messages[len(m.Messages)-1], dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipAuthz(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthAuthz + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} + +func skipAuthz(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowAuthz + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowAuthz + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowAuthz + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthAuthz + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupAuthz + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthAuthz + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthAuthz = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowAuthz = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupAuthz = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/wasm/types/authz_test.go b/x/wasm/types/authz_test.go new file mode 100644 index 0000000000..06747693fc --- /dev/null +++ b/x/wasm/types/authz_test.go @@ -0,0 +1,728 @@ +package types + +import ( + "math" + "testing" + + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + authztypes "github.com/cosmos/cosmos-sdk/x/authz" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestContractAuthzFilterValidate(t *testing.T) { + specs := map[string]struct { + src ContractAuthzFilterX + expErr bool + }{ + "allow all": { + src: &AllowAllMessagesFilter{}, + }, + "allow keys - single": { + src: NewAcceptedMessageKeysFilter("foo"), + }, + "allow keys - multi": { + src: NewAcceptedMessageKeysFilter("foo", "bar"), + }, + "allow keys - empty": { + src: NewAcceptedMessageKeysFilter(), + expErr: true, + }, + "allow keys - duplicates": { + src: NewAcceptedMessageKeysFilter("foo", "foo"), + expErr: true, + }, + "allow keys - whitespaces": { + src: NewAcceptedMessageKeysFilter(" foo"), + expErr: true, + }, + "allow keys - empty key": { + src: NewAcceptedMessageKeysFilter("", "bar"), + expErr: true, + }, + "allow keys - whitespace key": { + src: NewAcceptedMessageKeysFilter(" ", "bar"), + expErr: true, + }, + "allow message - single": { + src: NewAcceptedMessagesFilter([]byte(`{}`)), + }, + "allow message - multiple": { + src: NewAcceptedMessagesFilter([]byte(`{}`), []byte(`{"foo":"bar"}`)), + }, + "allow message - multiple with empty": { + src: NewAcceptedMessagesFilter([]byte(`{}`), nil), + expErr: true, + }, + "allow message - duplicate": { + src: NewAcceptedMessagesFilter([]byte(`{}`), []byte(`{}`)), + expErr: true, + }, + "allow message - non json": { + src: NewAcceptedMessagesFilter([]byte("non-json")), + expErr: true, + }, + "allow message - empty": { + src: NewAcceptedMessagesFilter(), + expErr: true, + }, + "allow all message - always valid": { + src: NewAllowAllMessagesFilter(), + }, + "undefined - always invalid": { + src: &UndefinedFilter{}, + expErr: true, + }, + } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + gotErr := spec.src.ValidateBasic() + if spec.expErr { + require.Error(t, gotErr) + return + } + require.NoError(t, gotErr) + }) + } +} + +func TestContractAuthzFilterAccept(t *testing.T) { + specs := map[string]struct { + filter ContractAuthzFilterX + src RawContractMessage + exp bool + expGasConsumed sdk.Gas + expErr bool + }{ + "allow all - accepts json obj": { + filter: &AllowAllMessagesFilter{}, + src: []byte(`{}`), + exp: true, + }, + "allow all - accepts json array": { + filter: &AllowAllMessagesFilter{}, + src: []byte(`[{},{}]`), + exp: true, + }, + "allow all - rejects non json msg": { + filter: &AllowAllMessagesFilter{}, + src: []byte(``), + expErr: true, + }, + "allowed key - single": { + filter: NewAcceptedMessageKeysFilter("foo"), + src: []byte(`{"foo": "bar"}`), + exp: true, + expGasConsumed: sdk.Gas(len(`{"foo": "bar"}`)), + }, + "allowed key - multiple": { + filter: NewAcceptedMessageKeysFilter("foo", "other"), + src: []byte(`{"other": "value"}`), + exp: true, + expGasConsumed: sdk.Gas(len(`{"other": "value"}`)), + }, + "allowed key - non accepted key": { + filter: NewAcceptedMessageKeysFilter("foo"), + src: []byte(`{"bar": "value"}`), + exp: false, + expGasConsumed: sdk.Gas(len(`{"bar": "value"}`)), + }, + "allowed key - unsupported array msg": { + filter: NewAcceptedMessageKeysFilter("foo", "other"), + src: []byte(`[{"foo":"bar"}]`), + expErr: false, + expGasConsumed: sdk.Gas(len(`[{"foo":"bar"}]`)), + }, + "allowed key - invalid msg": { + filter: NewAcceptedMessageKeysFilter("foo", "other"), + src: []byte(`not a json msg`), + expErr: true, + }, + "allow message - single": { + filter: NewAcceptedMessagesFilter([]byte(`{}`)), + src: []byte(`{}`), + exp: true, + }, + "allow message - multiple": { + filter: NewAcceptedMessagesFilter([]byte(`[{"foo":"bar"}]`), []byte(`{"other":"value"}`)), + src: []byte(`[{"foo":"bar"}]`), + exp: true, + }, + "allow message - no match": { + filter: NewAcceptedMessagesFilter([]byte(`{"foo":"bar"}`)), + src: []byte(`{"other":"value"}`), + exp: false, + }, + "allow all message - always accept valid": { + filter: NewAllowAllMessagesFilter(), + src: []byte(`{"other":"value"}`), + exp: true, + }, + "allow all message - always reject invalid json": { + filter: NewAllowAllMessagesFilter(), + src: []byte(`not json`), + expErr: true, + }, + "undefined - always errors": { + filter: &UndefinedFilter{}, + src: []byte(`{"foo":"bar"}`), + expErr: true, + }, + } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + gm := sdk.NewGasMeter(1_000_000) + allowed, gotErr := spec.filter.Accept(sdk.Context{}.WithGasMeter(gm), spec.src) + + // then + if spec.expErr { + require.Error(t, gotErr) + return + } + require.NoError(t, gotErr) + assert.Equal(t, spec.exp, allowed) + assert.Equal(t, spec.expGasConsumed, gm.GasConsumed()) + }) + } +} + +func TestContractAuthzLimitValidate(t *testing.T) { + oneToken := sdk.NewCoin(sdk.DefaultBondDenom, sdk.OneInt()) + specs := map[string]struct { + src ContractAuthzLimitX + expErr bool + }{ + "max calls": { + src: NewMaxCallsLimit(1), + }, + "max calls - max uint64": { + src: NewMaxCallsLimit(math.MaxUint64), + }, + "max calls - empty": { + src: NewMaxCallsLimit(0), + expErr: true, + }, + "max funds": { + src: NewMaxFundsLimit(oneToken), + }, + "max funds - empty coins": { + src: NewMaxFundsLimit(), + expErr: true, + }, + "max funds - duplicates": { + src: &MaxFundsLimit{Amounts: sdk.Coins{oneToken, oneToken}}, + expErr: true, + }, + "max funds - contains empty value": { + src: &MaxFundsLimit{Amounts: sdk.Coins{oneToken, sdk.NewCoin("other", sdk.ZeroInt())}.Sort()}, + expErr: true, + }, + "max funds - unsorted": { + src: &MaxFundsLimit{Amounts: sdk.Coins{oneToken, sdk.NewCoin("other", sdk.OneInt())}}, + expErr: true, + }, + "combined": { + src: NewCombinedLimit(1, oneToken), + }, + "combined - empty calls": { + src: NewCombinedLimit(0, oneToken), + expErr: true, + }, + "combined - empty amounts": { + src: NewCombinedLimit(1), + expErr: true, + }, + "combined - invalid amounts": { + src: &CombinedLimit{CallsRemaining: 1, Amounts: sdk.Coins{oneToken, oneToken}}, + expErr: true, + }, + "undefined": { + src: &UndefinedLimit{}, + expErr: true, + }, + } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + gotErr := spec.src.ValidateBasic() + if spec.expErr { + require.Error(t, gotErr) + return + } + require.NoError(t, gotErr) + }) + } +} + +func TestContractAuthzLimitAccept(t *testing.T) { + oneToken := sdk.NewCoin(sdk.DefaultBondDenom, sdk.OneInt()) + otherToken := sdk.NewCoin("other", sdk.OneInt()) + specs := map[string]struct { + limit ContractAuthzLimitX + src AuthzableWasmMsg + exp *ContractAuthzLimitAcceptResult + expErr bool + }{ + "max calls - updated": { + limit: NewMaxCallsLimit(2), + src: &MsgExecuteContract{}, + exp: &ContractAuthzLimitAcceptResult{Accepted: true, UpdateLimit: NewMaxCallsLimit(1)}, + }, + "max calls - removed": { + limit: NewMaxCallsLimit(1), + src: &MsgExecuteContract{}, + exp: &ContractAuthzLimitAcceptResult{Accepted: true, DeleteLimit: true}, + }, + "max calls - accepted with zero fund set": { + limit: NewMaxCallsLimit(1), + src: &MsgExecuteContract{Funds: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.ZeroInt()))}, + exp: &ContractAuthzLimitAcceptResult{Accepted: true, DeleteLimit: true}, + }, + "max calls - rejected with some fund transfer": { + limit: NewMaxCallsLimit(1), + src: &MsgExecuteContract{Funds: sdk.NewCoins(oneToken)}, + exp: &ContractAuthzLimitAcceptResult{Accepted: false}, + }, + "max calls - invalid": { + limit: &MaxCallsLimit{}, + src: &MsgExecuteContract{}, + expErr: true, + }, + "max funds - single updated": { + limit: NewMaxFundsLimit(oneToken.Add(oneToken)), + src: &MsgExecuteContract{Funds: sdk.NewCoins(oneToken)}, + exp: &ContractAuthzLimitAcceptResult{Accepted: true, UpdateLimit: NewMaxFundsLimit(oneToken)}, + }, + "max funds - single removed": { + limit: NewMaxFundsLimit(oneToken), + src: &MsgExecuteContract{Funds: sdk.NewCoins(oneToken)}, + exp: &ContractAuthzLimitAcceptResult{Accepted: true, DeleteLimit: true}, + }, + "max funds - single with unknown token": { + limit: NewMaxFundsLimit(oneToken), + src: &MsgExecuteContract{Funds: sdk.NewCoins(otherToken)}, + exp: &ContractAuthzLimitAcceptResult{Accepted: false}, + }, + "max funds - single exceeds limit": { + limit: NewMaxFundsLimit(oneToken), + src: &MsgExecuteContract{Funds: sdk.NewCoins(oneToken.Add(oneToken))}, + exp: &ContractAuthzLimitAcceptResult{Accepted: false}, + }, + "max funds - single with additional token send": { + limit: NewMaxFundsLimit(oneToken), + src: &MsgExecuteContract{Funds: sdk.NewCoins(oneToken, otherToken)}, + exp: &ContractAuthzLimitAcceptResult{Accepted: false}, + }, + "max funds - multi with other left": { + limit: NewMaxFundsLimit(oneToken, otherToken), + src: &MsgExecuteContract{Funds: sdk.NewCoins(oneToken)}, + exp: &ContractAuthzLimitAcceptResult{Accepted: true, UpdateLimit: NewMaxFundsLimit(otherToken)}, + }, + "max funds - multi with all used": { + limit: NewMaxFundsLimit(oneToken, otherToken), + src: &MsgExecuteContract{Funds: sdk.NewCoins(oneToken, otherToken)}, + exp: &ContractAuthzLimitAcceptResult{Accepted: true, DeleteLimit: true}, + }, + "max funds - multi with no tokens sent": { + limit: NewMaxFundsLimit(oneToken, otherToken), + src: &MsgExecuteContract{}, + exp: &ContractAuthzLimitAcceptResult{Accepted: true}, + }, + "max funds - multi with other exceeds limit": { + limit: NewMaxFundsLimit(oneToken, otherToken), + src: &MsgExecuteContract{Funds: sdk.NewCoins(oneToken, otherToken.Add(otherToken))}, + exp: &ContractAuthzLimitAcceptResult{Accepted: false}, + }, + "max combined - multi amounts one consumed": { + limit: NewCombinedLimit(2, oneToken, otherToken), + src: &MsgExecuteContract{Funds: sdk.NewCoins(oneToken)}, + exp: &ContractAuthzLimitAcceptResult{Accepted: true, UpdateLimit: NewCombinedLimit(1, otherToken)}, + }, + "max combined - multi amounts none consumed": { + limit: NewCombinedLimit(2, oneToken, otherToken), + src: &MsgExecuteContract{}, + exp: &ContractAuthzLimitAcceptResult{Accepted: true, UpdateLimit: NewCombinedLimit(1, oneToken, otherToken)}, + }, + "max combined - removed on last execution": { + limit: NewCombinedLimit(1, oneToken, otherToken), + src: &MsgExecuteContract{Funds: sdk.NewCoins(oneToken)}, + exp: &ContractAuthzLimitAcceptResult{Accepted: true, DeleteLimit: true}, + }, + "max combined - removed on last token": { + limit: NewCombinedLimit(2, oneToken), + src: &MsgExecuteContract{Funds: sdk.NewCoins(oneToken)}, + exp: &ContractAuthzLimitAcceptResult{Accepted: true, DeleteLimit: true}, + }, + "max combined - update with token and calls remaining": { + limit: NewCombinedLimit(2, oneToken, otherToken), + src: &MsgExecuteContract{Funds: sdk.NewCoins(oneToken)}, + exp: &ContractAuthzLimitAcceptResult{Accepted: true, UpdateLimit: NewCombinedLimit(1, otherToken)}, + }, + "max combined - multi with other exceeds limit": { + limit: NewCombinedLimit(2, oneToken, otherToken), + src: &MsgExecuteContract{Funds: sdk.NewCoins(oneToken, otherToken.Add(otherToken))}, + exp: &ContractAuthzLimitAcceptResult{Accepted: false}, + }, + "max combined - with unknown token": { + limit: NewCombinedLimit(2, oneToken), + src: &MsgExecuteContract{Funds: sdk.NewCoins(otherToken)}, + exp: &ContractAuthzLimitAcceptResult{Accepted: false}, + }, + "undefined": { + limit: &UndefinedLimit{}, + expErr: true, + }, + } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + gotResult, gotErr := spec.limit.Accept(sdk.Context{}, spec.src) + // then + if spec.expErr { + require.Error(t, gotErr) + return + } + require.NoError(t, gotErr) + assert.Equal(t, spec.exp, gotResult) + }) + } +} + +func TestValidateContractGrant(t *testing.T) { + specs := map[string]struct { + setup func(t *testing.T) ContractGrant + expErr bool + }{ + "all good": { + setup: func(t *testing.T) ContractGrant { + return mustGrant(randBytes(ContractAddrLen), NewMaxCallsLimit(1), NewAllowAllMessagesFilter()) + }, + }, + "invalid address": { + setup: func(t *testing.T) ContractGrant { + return mustGrant([]byte{}, NewMaxCallsLimit(1), NewAllowAllMessagesFilter()) + }, + expErr: true, + }, + "invalid limit": { + setup: func(t *testing.T) ContractGrant { + return mustGrant(randBytes(ContractAddrLen), NewMaxCallsLimit(0), NewAllowAllMessagesFilter()) + }, + expErr: true, + }, + + "invalid filter ": { + setup: func(t *testing.T) ContractGrant { + return mustGrant(randBytes(ContractAddrLen), NewMaxCallsLimit(1), NewAcceptedMessageKeysFilter()) + }, + expErr: true, + }, + "empty limit": { + setup: func(t *testing.T) ContractGrant { + r := mustGrant(randBytes(ContractAddrLen), NewMaxCallsLimit(0), NewAllowAllMessagesFilter()) + r.Limit = nil + return r + }, + expErr: true, + }, + + "empty filter ": { + setup: func(t *testing.T) ContractGrant { + r := mustGrant(randBytes(ContractAddrLen), NewMaxCallsLimit(1), NewAcceptedMessageKeysFilter()) + r.Filter = nil + return r + }, + expErr: true, + }, + "wrong limit type": { + setup: func(t *testing.T) ContractGrant { + r := mustGrant(randBytes(ContractAddrLen), NewMaxCallsLimit(0), NewAllowAllMessagesFilter()) + r.Limit = r.Filter + return r + }, + expErr: true, + }, + + "wrong filter type": { + setup: func(t *testing.T) ContractGrant { + r := mustGrant(randBytes(ContractAddrLen), NewMaxCallsLimit(1), NewAcceptedMessageKeysFilter()) + r.Filter = r.Limit + return r + }, + expErr: true, + }, + } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + gotErr := spec.setup(t).ValidateBasic() + if spec.expErr { + require.Error(t, gotErr) + return + } + require.NoError(t, gotErr) + }) + } +} + +func TestValidateContractAuthorization(t *testing.T) { + validGrant, err := NewContractGrant(randBytes(SDKAddrLen), NewMaxCallsLimit(1), NewAllowAllMessagesFilter()) + require.NoError(t, err) + invalidGrant, err := NewContractGrant(randBytes(SDKAddrLen), NewMaxCallsLimit(1), NewAllowAllMessagesFilter()) + require.NoError(t, err) + invalidGrant.Limit = nil + + specs := map[string]struct { + setup func(t *testing.T) validatable + expErr bool + }{ + "contract execution": { + setup: func(t *testing.T) validatable { + return NewContractMigrationAuthorization(*validGrant) + }, + }, + "contract execution - duplicate grants": { + setup: func(t *testing.T) validatable { + return NewContractMigrationAuthorization(*validGrant, *validGrant) + }, + }, + "contract execution - invalid grant": { + setup: func(t *testing.T) validatable { + return NewContractMigrationAuthorization(*validGrant, *invalidGrant) + }, + expErr: true, + }, + "contract execution - empty grants": { + setup: func(t *testing.T) validatable { + return NewContractMigrationAuthorization() + }, + expErr: true, + }, + "contract migration": { + setup: func(t *testing.T) validatable { + return NewContractMigrationAuthorization(*validGrant) + }, + }, + "contract migration - duplicate grants": { + setup: func(t *testing.T) validatable { + return NewContractMigrationAuthorization(*validGrant, *validGrant) + }, + }, + "contract migration - invalid grant": { + setup: func(t *testing.T) validatable { + return NewContractMigrationAuthorization(*validGrant, *invalidGrant) + }, + expErr: true, + }, + "contract migration - empty grant": { + setup: func(t *testing.T) validatable { + return NewContractMigrationAuthorization() + }, + expErr: true, + }, + } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + gotErr := spec.setup(t).ValidateBasic() + if spec.expErr { + require.Error(t, gotErr) + return + } + require.NoError(t, gotErr) + }) + } +} + +func TestAcceptGrantedMessage(t *testing.T) { + myContractAddr := sdk.AccAddress(randBytes(SDKAddrLen)) + otherContractAddr := sdk.AccAddress(randBytes(SDKAddrLen)) + specs := map[string]struct { + auth authztypes.Authorization + msg sdk.Msg + expResult authztypes.AcceptResponse + expErr *sdkerrors.Error + }{ + "accepted and updated - contract execution": { + auth: NewContractExecutionAuthorization(mustGrant(myContractAddr, NewMaxCallsLimit(2), NewAllowAllMessagesFilter())), + msg: &MsgExecuteContract{ + Sender: sdk.AccAddress(randBytes(SDKAddrLen)).String(), + Contract: myContractAddr.String(), + Msg: []byte(`{"foo":"bar"}`), + }, + expResult: authztypes.AcceptResponse{ + Accept: true, + Updated: NewContractExecutionAuthorization(mustGrant(myContractAddr, NewMaxCallsLimit(1), NewAllowAllMessagesFilter())), + }, + }, + "accepted and not updated - limit not touched": { + auth: NewContractExecutionAuthorization(mustGrant(myContractAddr, NewMaxFundsLimit(sdk.NewCoin(sdk.DefaultBondDenom, sdk.OneInt())), NewAllowAllMessagesFilter())), + msg: &MsgExecuteContract{ + Sender: sdk.AccAddress(randBytes(SDKAddrLen)).String(), + Contract: myContractAddr.String(), + Msg: []byte(`{"foo":"bar"}`), + }, + expResult: authztypes.AcceptResponse{Accept: true}, + }, + "accepted and removed - single": { + auth: NewContractExecutionAuthorization(mustGrant(myContractAddr, NewMaxCallsLimit(1), NewAllowAllMessagesFilter())), + msg: &MsgExecuteContract{ + Sender: sdk.AccAddress(randBytes(SDKAddrLen)).String(), + Contract: myContractAddr.String(), + Msg: []byte(`{"foo":"bar"}`), + }, + expResult: authztypes.AcceptResponse{Accept: true, Delete: true}, + }, + "accepted and updated - multi, one removed": { + auth: NewContractExecutionAuthorization( + mustGrant(myContractAddr, NewMaxCallsLimit(1), NewAllowAllMessagesFilter()), + mustGrant(myContractAddr, NewMaxCallsLimit(1), NewAllowAllMessagesFilter()), + ), + msg: &MsgExecuteContract{ + Sender: sdk.AccAddress(randBytes(SDKAddrLen)).String(), + Contract: myContractAddr.String(), + Msg: []byte(`{"foo":"bar"}`), + }, + expResult: authztypes.AcceptResponse{ + Accept: true, + Updated: NewContractExecutionAuthorization(mustGrant(myContractAddr, NewMaxCallsLimit(1), NewAllowAllMessagesFilter())), + }, + }, + "accepted and updated - multi, one updated": { + auth: NewContractExecutionAuthorization( + mustGrant(otherContractAddr, NewMaxCallsLimit(1), NewAllowAllMessagesFilter()), + mustGrant(myContractAddr, NewMaxFundsLimit(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(2))), NewAcceptedMessageKeysFilter("bar")), + mustGrant(myContractAddr, NewCombinedLimit(2, sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(2))), NewAcceptedMessageKeysFilter("foo")), + ), + msg: &MsgExecuteContract{ + Sender: sdk.AccAddress(randBytes(SDKAddrLen)).String(), + Contract: myContractAddr.String(), + Msg: []byte(`{"foo":"bar"}`), + Funds: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.OneInt())), + }, + expResult: authztypes.AcceptResponse{ + Accept: true, + Updated: NewContractExecutionAuthorization( + mustGrant(otherContractAddr, NewMaxCallsLimit(1), NewAllowAllMessagesFilter()), + mustGrant(myContractAddr, NewMaxFundsLimit(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(2))), NewAcceptedMessageKeysFilter("bar")), + mustGrant(myContractAddr, NewCombinedLimit(1, sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(1))), NewAcceptedMessageKeysFilter("foo")), + ), + }, + }, + "not accepted - no matching contract address": { + auth: NewContractExecutionAuthorization(mustGrant(myContractAddr, NewMaxCallsLimit(1), NewAllowAllMessagesFilter())), + msg: &MsgExecuteContract{ + Sender: sdk.AccAddress(randBytes(SDKAddrLen)).String(), + Contract: sdk.AccAddress(randBytes(SDKAddrLen)).String(), + Msg: []byte(`{"foo":"bar"}`), + }, + expResult: authztypes.AcceptResponse{Accept: false}, + }, + "not accepted - max calls but tokens": { + auth: NewContractExecutionAuthorization(mustGrant(myContractAddr, NewMaxCallsLimit(1), NewAllowAllMessagesFilter())), + msg: &MsgExecuteContract{ + Sender: sdk.AccAddress(randBytes(SDKAddrLen)).String(), + Contract: myContractAddr.String(), + Msg: []byte(`{"foo":"bar"}`), + Funds: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.OneInt())), + }, + expResult: authztypes.AcceptResponse{Accept: false}, + }, + "not accepted - funds exceeds limit": { + auth: NewContractExecutionAuthorization(mustGrant(myContractAddr, NewMaxFundsLimit(sdk.NewCoin(sdk.DefaultBondDenom, sdk.OneInt())), NewAllowAllMessagesFilter())), + msg: &MsgExecuteContract{ + Sender: sdk.AccAddress(randBytes(SDKAddrLen)).String(), + Contract: myContractAddr.String(), + Msg: []byte(`{"foo":"bar"}`), + Funds: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(2))), + }, + expResult: authztypes.AcceptResponse{Accept: false}, + }, + "not accepted - no matching filter": { + auth: NewContractExecutionAuthorization(mustGrant(myContractAddr, NewMaxCallsLimit(1), NewAcceptedMessageKeysFilter("other"))), + msg: &MsgExecuteContract{ + Sender: sdk.AccAddress(randBytes(SDKAddrLen)).String(), + Contract: myContractAddr.String(), + Msg: []byte(`{"foo":"bar"}`), + Funds: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.OneInt())), + }, + expResult: authztypes.AcceptResponse{Accept: false}, + }, + "invalid msg type - contract execution": { + auth: NewContractExecutionAuthorization(mustGrant(myContractAddr, NewMaxCallsLimit(1), NewAllowAllMessagesFilter())), + msg: &MsgMigrateContract{ + Sender: sdk.AccAddress(randBytes(SDKAddrLen)).String(), + Contract: myContractAddr.String(), + CodeID: 1, + Msg: []byte(`{"foo":"bar"}`), + }, + expErr: sdkerrors.ErrInvalidType, + }, + "payload is empty": { + auth: NewContractExecutionAuthorization(mustGrant(myContractAddr, NewMaxCallsLimit(1), NewAllowAllMessagesFilter())), + msg: &MsgExecuteContract{ + Sender: sdk.AccAddress(randBytes(SDKAddrLen)).String(), + Contract: myContractAddr.String(), + }, + expErr: sdkerrors.ErrInvalidType, + }, + "payload is invalid": { + auth: NewContractExecutionAuthorization(mustGrant(myContractAddr, NewMaxCallsLimit(1), NewAllowAllMessagesFilter())), + msg: &MsgExecuteContract{ + Sender: sdk.AccAddress(randBytes(SDKAddrLen)).String(), + Contract: myContractAddr.String(), + Msg: []byte(`not json`), + }, + expErr: ErrInvalid, + }, + "invalid grant": { + auth: NewContractExecutionAuthorization(ContractGrant{Contract: myContractAddr.String()}), + msg: &MsgExecuteContract{ + Sender: sdk.AccAddress(randBytes(SDKAddrLen)).String(), + Contract: myContractAddr.String(), + Msg: []byte(`{"foo":"bar"}`), + }, + expErr: sdkerrors.ErrNotFound, + }, + "invalid msg type - contract migration": { + auth: NewContractMigrationAuthorization(mustGrant(myContractAddr, NewMaxCallsLimit(1), NewAllowAllMessagesFilter())), + msg: &MsgExecuteContract{ + Sender: sdk.AccAddress(randBytes(SDKAddrLen)).String(), + Contract: myContractAddr.String(), + Msg: []byte(`{"foo":"bar"}`), + }, + expErr: sdkerrors.ErrInvalidType, + }, + "accepted and updated - contract migration": { + auth: NewContractMigrationAuthorization(mustGrant(myContractAddr, NewMaxCallsLimit(2), NewAllowAllMessagesFilter())), + msg: &MsgMigrateContract{ + Sender: sdk.AccAddress(randBytes(SDKAddrLen)).String(), + Contract: myContractAddr.String(), + CodeID: 1, + Msg: []byte(`{"foo":"bar"}`), + }, + expResult: authztypes.AcceptResponse{ + Accept: true, + Updated: NewContractMigrationAuthorization(mustGrant(myContractAddr, NewMaxCallsLimit(1), NewAllowAllMessagesFilter())), + }, + }, + } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + ctx := sdk.Context{}.WithGasMeter(sdk.NewInfiniteGasMeter()) + gotResult, gotErr := spec.auth.Accept(ctx, spec.msg) + if spec.expErr != nil { + require.ErrorIs(t, gotErr, spec.expErr) + return + } + require.NoError(t, gotErr) + assert.Equal(t, spec.expResult, gotResult) + }) + } +} + +func mustGrant(contract sdk.AccAddress, limit ContractAuthzLimitX, filter ContractAuthzFilterX) ContractGrant { + g, err := NewContractGrant(contract, limit, filter) + if err != nil { + panic(err) + } + return *g +} diff --git a/x/wasm/types/codec.go b/x/wasm/types/codec.go index f1cd6f557f..5148da1346 100644 --- a/x/wasm/types/codec.go +++ b/x/wasm/types/codec.go @@ -6,6 +6,7 @@ import ( cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/msgservice" + "github.com/cosmos/cosmos-sdk/x/authz" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" ) @@ -29,6 +30,21 @@ func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { //nolint:staticcheck cdc.RegisterConcrete(&UpdateAdminProposal{}, "wasm/UpdateAdminProposal", nil) cdc.RegisterConcrete(&ClearAdminProposal{}, "wasm/ClearAdminProposal", nil) cdc.RegisterConcrete(&UpdateInstantiateConfigProposal{}, "wasm/UpdateInstantiateConfigProposal", nil) + + cdc.RegisterInterface((*ContractInfoExtension)(nil), nil) + + cdc.RegisterInterface((*ContractAuthzFilterX)(nil), nil) + cdc.RegisterConcrete(&AllowAllMessagesFilter{}, "wasm/AllowAllMessagesFilter", nil) + cdc.RegisterConcrete(&AcceptedMessageKeysFilter{}, "wasm/AcceptedMessageKeysFilter", nil) + cdc.RegisterConcrete(&AcceptedMessagesFilter{}, "wasm/AcceptedMessagesFilter", nil) + + cdc.RegisterInterface((*ContractAuthzLimitX)(nil), nil) + cdc.RegisterConcrete(&MaxCallsLimit{}, "wasm/MaxCallsLimit", nil) + cdc.RegisterConcrete(&MaxFundsLimit{}, "wasm/MaxFundsLimit", nil) + cdc.RegisterConcrete(&CombinedLimit{}, "wasm/CombinedLimit", nil) + + cdc.RegisterConcrete(&ContractExecutionAuthorization{}, "wasm/ContractExecutionAuthorization", nil) + cdc.RegisterConcrete(&ContractMigrationAuthorization{}, "wasm/ContractMigrationAuthorization", nil) } func RegisterInterfaces(registry types.InterfaceRegistry) { @@ -60,6 +76,28 @@ func RegisterInterfaces(registry types.InterfaceRegistry) { registry.RegisterInterface("ContractInfoExtension", (*ContractInfoExtension)(nil)) + registry.RegisterInterface("ContractAuthzFilterX", (*ContractAuthzFilterX)(nil)) + registry.RegisterImplementations( + (*ContractAuthzFilterX)(nil), + &AllowAllMessagesFilter{}, + &AcceptedMessageKeysFilter{}, + &AcceptedMessagesFilter{}, + ) + + registry.RegisterInterface("ContractAuthzLimitX", (*ContractAuthzLimitX)(nil)) + registry.RegisterImplementations( + (*ContractAuthzLimitX)(nil), + &MaxCallsLimit{}, + &MaxFundsLimit{}, + &CombinedLimit{}, + ) + + registry.RegisterImplementations( + (*authz.Authorization)(nil), + &ContractExecutionAuthorization{}, + &ContractMigrationAuthorization{}, + ) + msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc) } diff --git a/x/wasm/types/errors.go b/x/wasm/types/errors.go index 7accd72bcb..a7e0464612 100644 --- a/x/wasm/types/errors.go +++ b/x/wasm/types/errors.go @@ -73,17 +73,7 @@ var ( // error if an address does not belong to a contract (just for registration) _ = sdkErrors.Register(DefaultCodespace, 22, "no such contract") - // ErrNotAJSONObject error if given data is not a JSON object - ErrNotAJSONObject = sdkErrors.Register(DefaultCodespace, 23, "not a JSON object") - - // ErrNoTopLevelKey error if a JSON object has no top-level key - ErrNoTopLevelKey = sdkErrors.Register(DefaultCodespace, 24, "no top-level key") - - // ErrMultipleTopLevelKeys error if a JSON object has more than one top-level key - ErrMultipleTopLevelKeys = sdkErrors.Register(DefaultCodespace, 25, "multiple top-level keys") - - // ErrTopKevelKeyNotAllowed error if a JSON object has a top-level key that is not allowed - ErrTopKevelKeyNotAllowed = sdkErrors.Register(DefaultCodespace, 26, "top-level key is not allowed") + // code 23 -26 were used for json parser // ErrExceedMaxQueryStackSize error if max query stack size is exceeded ErrExceedMaxQueryStackSize = sdkErrors.Register(DefaultCodespace, 27, "max query stack size exceeded") diff --git a/x/wasm/types/json_matching.go b/x/wasm/types/json_matching.go index cfa8522650..34ff76d35d 100644 --- a/x/wasm/types/json_matching.go +++ b/x/wasm/types/json_matching.go @@ -2,34 +2,32 @@ package types import ( "encoding/json" - - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) -// IsJSONObjectWithTopLevelKey checks if the given bytes are a valid JSON object +// isJSONObjectWithTopLevelKey returns true if the given bytes are a valid JSON object // with exactly one top-level key that is contained in the list of allowed keys. -func IsJSONObjectWithTopLevelKey(jsonBytes []byte, allowedKeys []string) error { - document := map[string]interface{}{} - if err := json.Unmarshal(jsonBytes, &document); err != nil { - return sdkerrors.Wrap(ErrNotAJSONObject, "failed to unmarshal JSON to map") +func isJSONObjectWithTopLevelKey(jsonBytes RawContractMessage, allowedKeys []string) (bool, error) { + if err := jsonBytes.ValidateBasic(); err != nil { + return false, err } - if len(document) == 0 { - return sdkerrors.Wrap(ErrNoTopLevelKey, "JSON object has no top-level key") + document := map[string]interface{}{} + if err := json.Unmarshal(jsonBytes, &document); err != nil { + return false, nil // not a map } - if len(document) > 1 { - return sdkerrors.Wrap(ErrMultipleTopLevelKeys, "JSON object has multiple top-level keys") + if len(document) != 1 { + return false, nil // unsupported type } // Loop is executed exactly once for topLevelKey := range document { for _, allowedKey := range allowedKeys { if allowedKey == topLevelKey { - return nil + return true, nil } } - return sdkerrors.Wrapf(ErrTopKevelKeyNotAllowed, "JSON object has a top-level key which is not allowed: '%s'", topLevelKey) + return false, nil } panic("Reached unreachable code. This is a bug.") diff --git a/x/wasm/types/json_matching_test.go b/x/wasm/types/json_matching_test.go index 17f7684872..01d2d3efd3 100644 --- a/x/wasm/types/json_matching_test.go +++ b/x/wasm/types/json_matching_test.go @@ -1,8 +1,11 @@ package types import ( + "encoding/json" "testing" + "github.com/stretchr/testify/assert" + // sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/stretchr/testify/require" ) @@ -11,105 +14,121 @@ func TestIsJSONObjectWithTopLevelKey(t *testing.T) { specs := map[string]struct { src []byte allowedKeys []string - exp error + expResult bool + expErr error }{ "happy": { src: []byte(`{"msg": {"foo":"bar"}}`), allowedKeys: []string{"msg"}, - exp: nil, + expResult: true, }, "happy with many allowed keys 1": { src: []byte(`{"claim": {"foo":"bar"}}`), allowedKeys: []string{"claim", "swap", "burn", "mint"}, - exp: nil, + expResult: true, }, "happy with many allowed keys 2": { src: []byte(`{"burn": {"foo":"bar"}}`), allowedKeys: []string{"claim", "swap", "burn", "mint"}, - exp: nil, + expResult: true, }, "happy with many allowed keys 3": { src: []byte(`{"mint": {"foo":"bar"}}`), allowedKeys: []string{"claim", "swap", "burn", "mint"}, - exp: nil, + expResult: true, }, "happy with number": { src: []byte(`{"msg": 123}`), allowedKeys: []string{"msg"}, - exp: nil, + expResult: true, }, "happy with array": { src: []byte(`{"msg": [1, 2, 3, 4]}`), allowedKeys: []string{"msg"}, - exp: nil, + expResult: true, }, "happy with null": { src: []byte(`{"msg": null}`), allowedKeys: []string{"msg"}, - exp: nil, + expResult: true, }, "happy with whitespace": { src: []byte(`{ "msg": null }`), allowedKeys: []string{"msg"}, - exp: nil, + expResult: true, }, - "happy with excaped key": { + "happy with escaped key": { src: []byte(`{"event\u2468thing": {"foo":"bar"}}`), allowedKeys: []string{"event⑨thing"}, - exp: nil, + expResult: true, }, // Invalid JSON object "errors for bytes that are no JSON": { src: []byte(`nope`), allowedKeys: []string{"claim"}, - exp: ErrNotAJSONObject, + expErr: ErrInvalid, }, - "errors for valid JSON (string)": { + "false for valid JSON (string)": { src: []byte(`"nope"`), allowedKeys: []string{"claim"}, - exp: ErrNotAJSONObject, + expResult: false, }, - "errors for valid JSON (array)": { + "false for valid JSON (array)": { src: []byte(`[1, 2, 3]`), allowedKeys: []string{"claim"}, - exp: ErrNotAJSONObject, - }, + expResult: false, + }, + // not supported: https://github.com/golang/go/issues/24415 + //"errors for duplicate key": { + // src: []byte(`{"claim": "foo", "claim":"bar"}`), + // allowedKeys: []string{"claim"}, + // expErr: ErrNotAJSONObject, + //}, // Not one top-level key - "errors for no top-level key": { + "false for no top-level key": { src: []byte(`{}`), allowedKeys: []string{"claim"}, - exp: ErrNoTopLevelKey, + expResult: false, }, - "errors for multiple top-level keys": { + "false for multiple top-level keys": { src: []byte(`{"claim": {}, "and_swap": {}}`), allowedKeys: []string{"claim"}, - exp: ErrMultipleTopLevelKeys, + expResult: false, }, // Wrong top-level key - "errors for wrong top-level key 1": { + "wrong top-level key 1": { src: []byte(`{"claim": {}}`), allowedKeys: []string{""}, - exp: ErrTopKevelKeyNotAllowed, + expResult: false, }, - "errors for wrong top-level key 2": { + "wrong top-level key 2": { src: []byte(`{"claim": {}}`), allowedKeys: []string{"swap", "burn", "mint"}, - exp: ErrTopKevelKeyNotAllowed, + expResult: false, }, } for name, spec := range specs { t.Run(name, func(t *testing.T) { - result := IsJSONObjectWithTopLevelKey(spec.src, spec.allowedKeys) - if spec.exp == nil { - require.NoError(t, result) - } else { - require.Error(t, result) - require.Contains(t, result.Error(), spec.exp.Error()) + exists, gotErr := isJSONObjectWithTopLevelKey(spec.src, spec.allowedKeys) + if spec.expErr != nil { + assert.ErrorIs(t, gotErr, spec.expErr) + return } + require.NoError(t, gotErr) + assert.Equal(t, spec.expResult, exists) }) } } + +func TestDuplicateKeyGivesSameResult(t *testing.T) { + jsonBytes := []byte(`{"event⑨thing": "foo", "event⑨thing":"bar"}`) + for i := 0; i < 10000; i++ { + document := map[string]interface{}{} + require.NoError(t, json.Unmarshal(jsonBytes, &document)) + assert.Equal(t, "bar", document["event⑨thing"]) + } +} diff --git a/x/wasm/types/query.pb.go b/x/wasm/types/query.pb.go index bb08b7571c..68b15e39fa 100644 --- a/x/wasm/types/query.pb.go +++ b/x/wasm/types/query.pb.go @@ -1288,8 +1288,10 @@ func (this *QueryCodeResponse) Equal(that interface{}) bool { } // Reference imports to suppress errors if they are not otherwise used. -var _ context.Context -var _ grpc.ClientConn +var ( + _ context.Context + _ grpc.ClientConn +) // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. diff --git a/x/wasm/types/tx.go b/x/wasm/types/tx.go index 9630777f29..dd6f6284cd 100644 --- a/x/wasm/types/tx.go +++ b/x/wasm/types/tx.go @@ -1,6 +1,7 @@ package types import ( + "bytes" "encoding/json" "errors" "strings" @@ -41,6 +42,11 @@ func (r RawContractMessage) Bytes() []byte { return r } +// Equal content is equal json. Byte equal but this can change in the future. +func (r RawContractMessage) Equal(o RawContractMessage) bool { + return bytes.Equal(r.Bytes(), o.Bytes()) +} + func (msg MsgStoreCode) Route() string { return RouterKey } @@ -163,6 +169,21 @@ func (msg MsgExecuteContract) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{senderAddr} } +// GetMsg returns the payload message send to the contract +func (msg MsgExecuteContract) GetMsg() RawContractMessage { + return msg.Msg +} + +// GetFunds returns tokens send to the contract +func (msg MsgExecuteContract) GetFunds() sdk.Coins { + return msg.Funds +} + +// GetContract returns the bech32 address of the contract +func (msg MsgExecuteContract) GetContract() string { + return msg.Contract +} + func (msg MsgMigrateContract) Route() string { return RouterKey } @@ -201,6 +222,21 @@ func (msg MsgMigrateContract) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{senderAddr} } +// GetMsg returns the payload message send to the contract +func (msg MsgMigrateContract) GetMsg() RawContractMessage { + return msg.Msg +} + +// GetFunds returns tokens send to the contract +func (msg MsgMigrateContract) GetFunds() sdk.Coins { + return sdk.NewCoins() +} + +// GetContract returns the bech32 address of the contract +func (msg MsgMigrateContract) GetContract() string { + return msg.Contract +} + func (msg MsgUpdateAdmin) Route() string { return RouterKey } diff --git a/x/wasm/types/tx.pb.go b/x/wasm/types/tx.pb.go index f81b1106e0..4670ba2b0b 100644 --- a/x/wasm/types/tx.pb.go +++ b/x/wasm/types/tx.pb.go @@ -778,8 +778,10 @@ var fileDescriptor_4f74d82755520264 = []byte{ } // Reference imports to suppress errors if they are not otherwise used. -var _ context.Context -var _ grpc.ClientConn +var ( + _ context.Context + _ grpc.ClientConn +) // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against.