diff --git a/contrib/local/02-contracts.sh b/contrib/local/02-contracts.sh
index ecbadf31..c445d948 100755
--- a/contrib/local/02-contracts.sh
+++ b/contrib/local/02-contracts.sh
@@ -1,5 +1,5 @@
#!/bin/bash
-set -o errexit -o nounset -o pipefail
+set -o errexit -o nounset -o pipefail -x
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"
@@ -9,7 +9,10 @@ RESP=$(wasmd tx wasm store "$DIR/../../x/wasm/keeper/testdata/hackatom.wasm" \
--from validator --gas 1500000 -y --chain-id=testing --node=http://localhost:26657 -b block -o json)
CODE_ID=$(echo "$RESP" | jq -r '.logs[0].events[1].attributes[-1].value')
+CODE_HASH=$(echo "$RESP" | jq -r '.logs[0].events[1].attributes[-2].value')
echo "* Code id: $CODE_ID"
+echo "* Code checksum: $CODE_HASH"
+
echo "* Download code"
TMPDIR=$(mktemp -t wasmdXXXXXX)
wasmd q wasm code "$CODE_ID" "$TMPDIR"
@@ -27,6 +30,17 @@ wasmd tx wasm instantiate "$CODE_ID" "$INIT" --admin="$(wasmd keys show validato
CONTRACT=$(wasmd query wasm list-contract-by-code "$CODE_ID" -o json | jq -r '.contracts[-1]')
echo "* Contract address: $CONTRACT"
+
+echo "## Create new contract instance with predictable address"
+wasmd tx wasm instantiate2 "$CODE_ID" "$INIT" $(echo -n "testing" | xxd -ps) \
+ --admin="$(wasmd keys show validator -a)" \
+ --from validator --amount="100ustake" --label "local0.1.0" \
+ --fix-msg \
+ --gas 1000000 -y --chain-id=testing -b block -o json | jq
+
+predictedAdress=$(wasmd q wasm build-address "$CODE_HASH" $(wasmd keys show validator -a) $(echo -n "testing" | xxd -ps) "$INIT")
+wasmd q wasm contract "$predictedAdress" -o json | jq
+
echo "### Query all"
RESP=$(wasmd query wasm contract-state all "$CONTRACT" -o json)
echo "$RESP" | jq
diff --git a/docs/proto/proto-docs.md b/docs/proto/proto-docs.md
index 584398a7..add638f0 100644
--- a/docs/proto/proto-docs.md
+++ b/docs/proto/proto-docs.md
@@ -23,6 +23,8 @@
- [MsgExecuteContract](#cosmwasm.wasm.v1.MsgExecuteContract)
- [MsgExecuteContractResponse](#cosmwasm.wasm.v1.MsgExecuteContractResponse)
- [MsgInstantiateContract](#cosmwasm.wasm.v1.MsgInstantiateContract)
+ - [MsgInstantiateContract2](#cosmwasm.wasm.v1.MsgInstantiateContract2)
+ - [MsgInstantiateContract2Response](#cosmwasm.wasm.v1.MsgInstantiateContract2Response)
- [MsgInstantiateContractResponse](#cosmwasm.wasm.v1.MsgInstantiateContractResponse)
- [MsgMigrateContract](#cosmwasm.wasm.v1.MsgMigrateContract)
- [MsgMigrateContractResponse](#cosmwasm.wasm.v1.MsgMigrateContractResponse)
@@ -327,7 +329,7 @@ MsgExecuteContractResponse returns execution result data.
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
-| `data` | [bytes](#bytes) | | Data contains base64-encoded bytes to returned from the contract |
+| `data` | [bytes](#bytes) | | Data contains bytes to returned from the contract |
@@ -355,6 +357,45 @@ code id.
+
+
+### MsgInstantiateContract2
+MsgInstantiateContract2 create a new smart contract instance for the given
+code id with a predicable address.
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| `sender` | [string](#string) | | Sender is the that actor that signed the messages |
+| `admin` | [string](#string) | | Admin is an optional address that can execute migrations |
+| `code_id` | [uint64](#uint64) | | CodeID is the reference to the stored WASM code |
+| `label` | [string](#string) | | Label is optional metadata to be stored with a contract instance. |
+| `msg` | [bytes](#bytes) | | Msg json encoded message to be passed to the contract on instantiation |
+| `funds` | [cosmos.base.v1beta1.Coin](#cosmos.base.v1beta1.Coin) | repeated | Funds coins that are transferred to the contract on instantiation |
+| `salt` | [bytes](#bytes) | | Salt is an arbitrary value provided by the sender. Size can be 1 to 64. |
+| `fix_msg` | [bool](#bool) | | FixMsg include the msg value into the hash for the predictable address. Default is false |
+
+
+
+
+
+
+
+
+### MsgInstantiateContract2Response
+MsgInstantiateContract2Response return instantiation result data
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| `address` | [string](#string) | | Address is the bech32 address of the new contract instance. |
+| `data` | [bytes](#bytes) | | Data contains bytes to returned from the contract |
+
+
+
+
+
+
### MsgInstantiateContractResponse
@@ -364,7 +405,7 @@ MsgInstantiateContractResponse return instantiation result data
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `address` | [string](#string) | | Address is the bech32 address of the new contract instance. |
-| `data` | [bytes](#bytes) | | Data contains base64-encoded bytes to returned from the contract |
+| `data` | [bytes](#bytes) | | Data contains bytes to returned from the contract |
@@ -478,7 +519,8 @@ Msg defines the wasm Msg service.
| Method Name | Request Type | Response Type | Description | HTTP Verb | Endpoint |
| ----------- | ------------ | ------------- | ------------| ------- | -------- |
| `StoreCode` | [MsgStoreCode](#cosmwasm.wasm.v1.MsgStoreCode) | [MsgStoreCodeResponse](#cosmwasm.wasm.v1.MsgStoreCodeResponse) | StoreCode to submit Wasm code to the system | |
-| `InstantiateContract` | [MsgInstantiateContract](#cosmwasm.wasm.v1.MsgInstantiateContract) | [MsgInstantiateContractResponse](#cosmwasm.wasm.v1.MsgInstantiateContractResponse) | Instantiate creates a new smart contract instance for the given code id. | |
+| `InstantiateContract` | [MsgInstantiateContract](#cosmwasm.wasm.v1.MsgInstantiateContract) | [MsgInstantiateContractResponse](#cosmwasm.wasm.v1.MsgInstantiateContractResponse) | InstantiateContract creates a new smart contract instance for the given code id. | |
+| `InstantiateContract2` | [MsgInstantiateContract2](#cosmwasm.wasm.v1.MsgInstantiateContract2) | [MsgInstantiateContract2Response](#cosmwasm.wasm.v1.MsgInstantiateContract2Response) | InstantiateContract2 creates a new smart contract instance for the given code id with a predictable address | |
| `ExecuteContract` | [MsgExecuteContract](#cosmwasm.wasm.v1.MsgExecuteContract) | [MsgExecuteContractResponse](#cosmwasm.wasm.v1.MsgExecuteContractResponse) | Execute submits the given message data to a smart contract | |
| `MigrateContract` | [MsgMigrateContract](#cosmwasm.wasm.v1.MsgMigrateContract) | [MsgMigrateContractResponse](#cosmwasm.wasm.v1.MsgMigrateContractResponse) | Migrate runs a code upgrade/ downgrade for a smart contract | |
| `UpdateAdmin` | [MsgUpdateAdmin](#cosmwasm.wasm.v1.MsgUpdateAdmin) | [MsgUpdateAdminResponse](#cosmwasm.wasm.v1.MsgUpdateAdminResponse) | UpdateAdmin sets a new admin for a smart contract | |
@@ -560,7 +602,7 @@ order. The intention is to have more human readable data that is auditable.
| ----- | ---- | ----- | ----------- |
| `store_code` | [MsgStoreCode](#cosmwasm.wasm.v1.MsgStoreCode) | | |
| `instantiate_contract` | [MsgInstantiateContract](#cosmwasm.wasm.v1.MsgInstantiateContract) | | |
-| `execute_contract` | [MsgExecuteContract](#cosmwasm.wasm.v1.MsgExecuteContract) | | |
+| `execute_contract` | [MsgExecuteContract](#cosmwasm.wasm.v1.MsgExecuteContract) | | MsgInstantiateContract2 intentionally not supported see https://github.com/CosmWasm/wasmd/issues/987 |
diff --git a/proto/cosmwasm/wasm/v1/genesis.proto b/proto/cosmwasm/wasm/v1/genesis.proto
index f02f3307..87373e18 100644
--- a/proto/cosmwasm/wasm/v1/genesis.proto
+++ b/proto/cosmwasm/wasm/v1/genesis.proto
@@ -33,6 +33,8 @@ message GenesisState {
MsgStoreCode store_code = 1;
MsgInstantiateContract instantiate_contract = 2;
MsgExecuteContract execute_contract = 3;
+ // MsgInstantiateContract2 intentionally not supported
+ // see https://github.com/CosmWasm/wasmd/issues/987
}
}
}
diff --git a/proto/cosmwasm/wasm/v1/tx.proto b/proto/cosmwasm/wasm/v1/tx.proto
index f1eb8fec..04acc8ef 100644
--- a/proto/cosmwasm/wasm/v1/tx.proto
+++ b/proto/cosmwasm/wasm/v1/tx.proto
@@ -12,9 +12,14 @@ option (gogoproto.goproto_getters_all) = false;
service Msg {
// StoreCode to submit Wasm code to the system
rpc StoreCode(MsgStoreCode) returns (MsgStoreCodeResponse);
- // Instantiate creates a new smart contract instance for the given code id.
+ // InstantiateContract creates a new smart contract instance for the given
+ // code id.
rpc InstantiateContract(MsgInstantiateContract)
returns (MsgInstantiateContractResponse);
+ // InstantiateContract2 creates a new smart contract instance for the given
+ // code id with a predictable address
+ rpc InstantiateContract2(MsgInstantiateContract2)
+ returns (MsgInstantiateContract2Response);
// Execute submits the given message data to a smart contract
rpc ExecuteContract(MsgExecuteContract) returns (MsgExecuteContractResponse);
// Migrate runs a code upgrade/ downgrade for a smart contract
@@ -64,11 +69,45 @@ message MsgInstantiateContract {
(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"
];
}
+
+// MsgInstantiateContract2 create a new smart contract instance for the given
+// code id with a predicable address.
+message MsgInstantiateContract2 {
+ // Sender is the that actor that signed the messages
+ string sender = 1;
+ // Admin is an optional address that can execute migrations
+ string admin = 2;
+ // CodeID is the reference to the stored WASM code
+ uint64 code_id = 3 [ (gogoproto.customname) = "CodeID" ];
+ // Label is optional metadata to be stored with a contract instance.
+ string label = 4;
+ // Msg json encoded message to be passed to the contract on instantiation
+ bytes msg = 5 [ (gogoproto.casttype) = "RawContractMessage" ];
+ // Funds coins that are transferred to the contract on instantiation
+ repeated cosmos.base.v1beta1.Coin funds = 6 [
+ (gogoproto.nullable) = false,
+ (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"
+ ];
+ // Salt is an arbitrary value provided by the sender. Size can be 1 to 64.
+ bytes salt = 7;
+ // FixMsg include the msg value into the hash for the predictable address.
+ // Default is false
+ bool fix_msg = 8;
+}
+
// MsgInstantiateContractResponse return instantiation result data
message MsgInstantiateContractResponse {
// Address is the bech32 address of the new contract instance.
string address = 1;
- // Data contains base64-encoded bytes to returned from the contract
+ // Data contains bytes to returned from the contract
+ bytes data = 2;
+}
+
+// MsgInstantiateContract2Response return instantiation result data
+message MsgInstantiateContract2Response {
+ // Address is the bech32 address of the new contract instance.
+ string address = 1;
+ // Data contains bytes to returned from the contract
bytes data = 2;
}
@@ -89,7 +128,7 @@ message MsgExecuteContract {
// MsgExecuteContractResponse returns execution result data.
message MsgExecuteContractResponse {
- // Data contains base64-encoded bytes to returned from the contract
+ // Data contains bytes to returned from the contract
bytes data = 1;
}
diff --git a/x/wasm/alias.go b/x/wasm/alias.go
index 09f0e7af..a64de37b 100644
--- a/x/wasm/alias.go
+++ b/x/wasm/alias.go
@@ -86,6 +86,7 @@ var (
ErrQueryFailed = types.ErrQueryFailed
ErrInvalidMsg = types.ErrInvalidMsg
KeyLastCodeID = types.KeyLastCodeID
+ KeyLastInstanceID = types.KeyLastInstanceID
CodeKeyPrefix = types.CodeKeyPrefix
ContractKeyPrefix = types.ContractKeyPrefix
ContractStorePrefix = types.ContractStorePrefix
@@ -101,6 +102,7 @@ type (
MsgStoreCode = types.MsgStoreCode
MsgStoreCodeResponse = types.MsgStoreCodeResponse
MsgInstantiateContract = types.MsgInstantiateContract
+ MsgInstantiateContract2 = types.MsgInstantiateContract2
MsgInstantiateContractResponse = types.MsgInstantiateContractResponse
MsgExecuteContract = types.MsgExecuteContract
MsgExecuteContractResponse = types.MsgExecuteContractResponse
diff --git a/x/wasm/client/cli/genesis_msg.go b/x/wasm/client/cli/genesis_msg.go
index 0859b032..8aedae35 100644
--- a/x/wasm/client/cli/genesis_msg.go
+++ b/x/wasm/client/cli/genesis_msg.go
@@ -8,10 +8,6 @@ import (
"errors"
"fmt"
- "github.com/CosmWasm/wasmd/x/wasm/ioutils"
-
- "github.com/CosmWasm/wasmd/x/wasm/keeper"
-
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
@@ -24,6 +20,8 @@ import (
"github.com/spf13/cobra"
tmtypes "github.com/tendermint/tendermint/types"
+ "github.com/CosmWasm/wasmd/x/wasm/ioutils"
+ "github.com/CosmWasm/wasmd/x/wasm/keeper"
"github.com/CosmWasm/wasmd/x/wasm/types"
)
@@ -133,7 +131,7 @@ func GenesisInstantiateContractCmd(defaultNodeHome string, genesisMutator Genesi
return fmt.Errorf("permissions were not granted for %s", senderAddr)
}
state.GenMsgs = append(state.GenMsgs, types.GenesisState_GenMsgs{
- Sum: &types.GenesisState_GenMsgs_InstantiateContract{InstantiateContract: &msg},
+ Sum: &types.GenesisState_GenMsgs_InstantiateContract{InstantiateContract: msg},
})
return nil
})
@@ -238,10 +236,7 @@ func GenesisListContractsCmd(defaultNodeHome string, genReader GenesisReader) *c
return err
}
state := g.WasmModuleState
- all, err := GetAllContracts(state)
- if err != nil {
- return err
- }
+ all := GetAllContracts(state)
return printJSONOutput(cmd, all)
},
}
@@ -313,18 +308,7 @@ type ContractMeta struct {
Info types.ContractInfo `json:"info"`
}
-// returns nil when not found
-func codeHashByID(state *types.GenesisState, codeID uint64) []byte {
- codes := GetAllCodes(state)
- for _, v := range codes {
- if v.CodeID == codeID {
- return v.Info.CodeHash
- }
- }
- return nil
-}
-
-func GetAllContracts(state *types.GenesisState) ([]ContractMeta, error) {
+func GetAllContracts(state *types.GenesisState) []ContractMeta {
all := make([]ContractMeta, len(state.Contracts))
for i, c := range state.Contracts {
all[i] = ContractMeta{
@@ -333,18 +317,11 @@ func GetAllContracts(state *types.GenesisState) ([]ContractMeta, error) {
}
}
// add inflight
+ seq := contractSeqValue(state)
for _, m := range state.GenMsgs {
if msg := m.GetInstantiateContract(); msg != nil {
- senderAddr, err := sdk.AccAddressFromBech32(msg.Sender)
- if err != nil {
- panic(fmt.Sprintf("unsupported address %q: %s", msg.Sender, err))
- }
- codeHash := codeHashByID(state, msg.CodeID)
- if codeHash == nil {
- return nil, types.ErrNotFound.Wrapf("hash for code-id: %d", msg.CodeID)
- }
all = append(all, ContractMeta{
- ContractAddress: keeper.BuildContractAddress(codeHash, senderAddr, msg.Label).String(),
+ ContractAddress: keeper.BuildContractAddressClassic(msg.CodeID, seq).String(),
Info: types.ContractInfo{
CodeID: msg.CodeID,
Creator: msg.Sender,
@@ -352,9 +329,10 @@ func GetAllContracts(state *types.GenesisState) ([]ContractMeta, error) {
Label: msg.Label,
},
})
+ seq++
}
}
- return all, nil
+ return all
}
func hasAccountBalance(cmd *cobra.Command, appState map[string]json.RawMessage, sender sdk.AccAddress, coins sdk.Coins) (bool, error) {
@@ -381,19 +359,13 @@ func hasContract(state *types.GenesisState, contractAddr string) bool {
return true
}
}
+ seq := contractSeqValue(state)
for _, m := range state.GenMsgs {
if msg := m.GetInstantiateContract(); msg != nil {
- senderAddr, err := sdk.AccAddressFromBech32(msg.Sender)
- if err != nil {
- panic(fmt.Sprintf("unsupported address %q: %s", msg.Sender, err))
- }
- hash := codeHashByID(state, msg.CodeID)
- if hash == nil {
- panic(fmt.Sprintf("unknown code id: %d", msg.CodeID))
- }
- if keeper.BuildContractAddress(hash, senderAddr, msg.Label).String() == contractAddr {
+ if keeper.BuildContractAddressClassic(msg.CodeID, seq).String() == contractAddr {
return true
}
+ seq++
}
}
return false
@@ -486,6 +458,19 @@ func (x DefaultGenesisIO) AlterWasmModuleState(cmd *cobra.Command, callback func
return genutil.ExportGenesisFile(g.GenDoc, g.GenesisFile)
}
+// contractSeqValue reads the contract sequence from the genesis or
+// returns default start value used in the keeper
+func contractSeqValue(state *types.GenesisState) uint64 {
+ var seq uint64 = 1
+ for _, s := range state.Sequences {
+ if bytes.Equal(s.IDKey, types.KeyLastInstanceID) {
+ seq = s.Value
+ break
+ }
+ }
+ return seq
+}
+
// codeSeqValue reads the code sequence from the genesis or
// returns default start value used in the keeper
func codeSeqValue(state *types.GenesisState) uint64 {
diff --git a/x/wasm/client/cli/genesis_msg_test.go b/x/wasm/client/cli/genesis_msg_test.go
index 6b67aa49..a1d24f29 100644
--- a/x/wasm/client/cli/genesis_msg_test.go
+++ b/x/wasm/client/cli/genesis_msg_test.go
@@ -1,15 +1,12 @@
package cli
import (
- "bytes"
"context"
"encoding/json"
"os"
"path"
"testing"
- "github.com/cosmos/cosmos-sdk/types/address"
-
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/crypto/hd"
@@ -366,8 +363,7 @@ func TestInstantiateContractCmd(t *testing.T) {
}
func TestExecuteContractCmd(t *testing.T) {
- mySenderAddr := sdk.AccAddress(bytes.Repeat([]byte{1}, address.Len))
- myFirstContractAddress := keeper.BuildContractAddress([]byte("myCodeHash"), mySenderAddr, "my").String()
+ const firstContractAddress = "cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr"
minimalWasmGenesis := types.GenesisState{
Params: types.DefaultParams(),
}
@@ -394,7 +390,7 @@ func TestExecuteContractCmd(t *testing.T) {
},
Contracts: []types.Contract{
{
- ContractAddress: myFirstContractAddress,
+ ContractAddress: firstContractAddress,
ContractInfo: types.ContractInfoFixture(func(info *types.ContractInfo) {
info.Created = nil
}),
@@ -403,34 +399,53 @@ func TestExecuteContractCmd(t *testing.T) {
},
},
mutator: func(cmd *cobra.Command) {
- cmd.SetArgs([]string{myFirstContractAddress, `{}`})
+ cmd.SetArgs([]string{firstContractAddress, `{}`})
flagSet := cmd.Flags()
flagSet.Set("run-as", myWellFundedAccount)
},
expMsgCount: 1,
},
- "all good with contract from genesis store messages": {
+ "all good with contract from genesis store messages without initial sequence": {
srcGenesis: types.GenesisState{
Params: types.DefaultParams(),
Codes: []types.Code{
{
- CodeID: 1,
- CodeInfo: types.CodeInfoFixture(func(info *types.CodeInfo) {
- info.CodeHash = []byte("myCodeHash")
- }),
+ CodeID: 1,
+ CodeInfo: types.CodeInfoFixture(),
CodeBytes: wasmIdent,
},
},
GenMsgs: []types.GenesisState_GenMsgs{
- {Sum: &types.GenesisState_GenMsgs_InstantiateContract{InstantiateContract: types.MsgInstantiateContractFixture(
- func(m *types.MsgInstantiateContract) {
- m.Sender = mySenderAddr.String()
- m.Label = "my"
- })}},
+ {Sum: &types.GenesisState_GenMsgs_InstantiateContract{InstantiateContract: types.MsgInstantiateContractFixture()}},
},
},
mutator: func(cmd *cobra.Command) {
- cmd.SetArgs([]string{myFirstContractAddress, `{}`})
+ cmd.SetArgs([]string{firstContractAddress, `{}`})
+ flagSet := cmd.Flags()
+ flagSet.Set("run-as", myWellFundedAccount)
+ },
+ expMsgCount: 2,
+ },
+ "all good with contract from genesis store messages and contract sequence set": {
+ srcGenesis: types.GenesisState{
+ Params: types.DefaultParams(),
+ Codes: []types.Code{
+ {
+ CodeID: 1,
+ CodeInfo: types.CodeInfoFixture(),
+ CodeBytes: wasmIdent,
+ },
+ },
+ GenMsgs: []types.GenesisState_GenMsgs{
+ {Sum: &types.GenesisState_GenMsgs_InstantiateContract{InstantiateContract: types.MsgInstantiateContractFixture()}},
+ },
+ Sequences: []types.Sequence{
+ {IDKey: types.KeyLastInstanceID, Value: 100},
+ },
+ },
+ mutator: func(cmd *cobra.Command) {
+ // See TestBuildContractAddress in keeper_test.go
+ cmd.SetArgs([]string{"cosmos1mujpjkwhut9yjw4xueyugc02evfv46y0dtmnz4lh8xxkkdapym9stu5qm8", `{}`})
flagSet := cmd.Flags()
flagSet.Set("run-as", myWellFundedAccount)
},
@@ -457,7 +472,7 @@ func TestExecuteContractCmd(t *testing.T) {
},
Contracts: []types.Contract{
{
- ContractAddress: myFirstContractAddress,
+ ContractAddress: firstContractAddress,
ContractInfo: types.ContractInfoFixture(func(info *types.ContractInfo) {
info.Created = nil
}),
@@ -466,7 +481,7 @@ func TestExecuteContractCmd(t *testing.T) {
},
},
mutator: func(cmd *cobra.Command) {
- cmd.SetArgs([]string{myFirstContractAddress, `{}`})
+ cmd.SetArgs([]string{firstContractAddress, `{}`})
flagSet := cmd.Flags()
flagSet.Set("run-as", keeper.RandomBech32AccountAddress(t))
},
@@ -484,7 +499,7 @@ func TestExecuteContractCmd(t *testing.T) {
},
Contracts: []types.Contract{
{
- ContractAddress: myFirstContractAddress,
+ ContractAddress: firstContractAddress,
ContractInfo: types.ContractInfoFixture(func(info *types.ContractInfo) {
info.Created = nil
}),
@@ -493,7 +508,7 @@ func TestExecuteContractCmd(t *testing.T) {
},
},
mutator: func(cmd *cobra.Command) {
- cmd.SetArgs([]string{myFirstContractAddress, `{}`})
+ cmd.SetArgs([]string{firstContractAddress, `{}`})
flagSet := cmd.Flags()
flagSet.Set("run-as", myWellFundedAccount)
flagSet.Set("amount", "100stake")
@@ -512,7 +527,7 @@ func TestExecuteContractCmd(t *testing.T) {
},
Contracts: []types.Contract{
{
- ContractAddress: myFirstContractAddress,
+ ContractAddress: firstContractAddress,
ContractInfo: types.ContractInfoFixture(func(info *types.ContractInfo) {
info.Created = nil
}),
@@ -521,7 +536,7 @@ func TestExecuteContractCmd(t *testing.T) {
},
},
mutator: func(cmd *cobra.Command) {
- cmd.SetArgs([]string{myFirstContractAddress, `{}`})
+ cmd.SetArgs([]string{firstContractAddress, `{}`})
flagSet := cmd.Flags()
flagSet.Set("run-as", keeper.RandomBech32AccountAddress(t))
flagSet.Set("amount", "10stake")
@@ -550,9 +565,6 @@ func TestExecuteContractCmd(t *testing.T) {
}
func TestGetAllContracts(t *testing.T) {
- creatorAddr1 := sdk.AccAddress(bytes.Repeat([]byte{1}, address.Len))
- creatorAddr2 := sdk.AccAddress(bytes.Repeat([]byte{2}, address.Len))
-
specs := map[string]struct {
src types.GenesisState
exp []ContractMeta
@@ -583,55 +595,68 @@ func TestGetAllContracts(t *testing.T) {
},
"read from message state": {
src: types.GenesisState{
- Codes: []types.Code{{CodeID: 1, CodeInfo: types.CodeInfo{CodeHash: []byte("firstCodeHash")}}},
GenMsgs: []types.GenesisState_GenMsgs{
- {Sum: &types.GenesisState_GenMsgs_InstantiateContract{InstantiateContract: &types.MsgInstantiateContract{Sender: creatorAddr1.String(), Label: "first", CodeID: 1}}},
- {Sum: &types.GenesisState_GenMsgs_InstantiateContract{InstantiateContract: &types.MsgInstantiateContract{Sender: creatorAddr2.String(), Label: "second", CodeID: 1}}},
+ {Sum: &types.GenesisState_GenMsgs_InstantiateContract{InstantiateContract: &types.MsgInstantiateContract{Label: "first"}}},
+ {Sum: &types.GenesisState_GenMsgs_InstantiateContract{InstantiateContract: &types.MsgInstantiateContract{Label: "second"}}},
},
},
exp: []ContractMeta{
{
- ContractAddress: keeper.BuildContractAddress([]byte("firstCodeHash"), creatorAddr1, "first").String(),
- Info: types.ContractInfo{Creator: creatorAddr1.String(), Label: "first", CodeID: 1},
+ ContractAddress: keeper.BuildContractAddressClassic(0, 1).String(),
+ Info: types.ContractInfo{Label: "first"},
},
{
- ContractAddress: keeper.BuildContractAddress([]byte("firstCodeHash"), creatorAddr2, "second").String(),
- Info: types.ContractInfo{Creator: creatorAddr2.String(), Label: "second", CodeID: 1},
+ ContractAddress: keeper.BuildContractAddressClassic(0, 2).String(),
+ Info: types.ContractInfo{Label: "second"},
+ },
+ },
+ },
+ "read from message state with contract sequence": {
+ src: types.GenesisState{
+ Sequences: []types.Sequence{
+ {IDKey: types.KeyLastInstanceID, Value: 100},
+ },
+ GenMsgs: []types.GenesisState_GenMsgs{
+ {Sum: &types.GenesisState_GenMsgs_InstantiateContract{InstantiateContract: &types.MsgInstantiateContract{Label: "hundred"}}},
+ },
+ },
+ exp: []ContractMeta{
+ {
+ ContractAddress: keeper.BuildContractAddressClassic(0, 100).String(),
+ Info: types.ContractInfo{Label: "hundred"},
},
},
},
"read from contract and message state with contract sequence": {
src: types.GenesisState{
- Codes: []types.Code{
- {CodeID: 1, CodeInfo: types.CodeInfo{CodeHash: []byte("firstCodeHash")}},
- {CodeID: 100, CodeInfo: types.CodeInfo{CodeHash: []byte("otherCodeHash")}},
- },
Contracts: []types.Contract{
{
- ContractAddress: keeper.BuildContractAddress([]byte("firstCodeHash"), creatorAddr1, "first").String(),
- ContractInfo: types.ContractInfo{Label: "first", CodeID: 1},
+ ContractAddress: "first-contract",
+ ContractInfo: types.ContractInfo{Label: "first"},
},
},
+ Sequences: []types.Sequence{
+ {IDKey: types.KeyLastInstanceID, Value: 100},
+ },
GenMsgs: []types.GenesisState_GenMsgs{
- {Sum: &types.GenesisState_GenMsgs_InstantiateContract{InstantiateContract: &types.MsgInstantiateContract{Sender: creatorAddr1.String(), Label: "hundred", CodeID: 100}}},
+ {Sum: &types.GenesisState_GenMsgs_InstantiateContract{InstantiateContract: &types.MsgInstantiateContract{Label: "hundred"}}},
},
},
exp: []ContractMeta{
{
- ContractAddress: keeper.BuildContractAddress([]byte("firstCodeHash"), creatorAddr1, "first").String(),
- Info: types.ContractInfo{Label: "first", CodeID: 1},
+ ContractAddress: "first-contract",
+ Info: types.ContractInfo{Label: "first"},
},
{
- ContractAddress: keeper.BuildContractAddress([]byte("otherCodeHash"), creatorAddr1, "hundred").String(),
- Info: types.ContractInfo{Creator: creatorAddr1.String(), Label: "hundred", CodeID: 100},
+ ContractAddress: keeper.BuildContractAddressClassic(0, 100).String(),
+ Info: types.ContractInfo{Label: "hundred"},
},
},
},
}
for msg, spec := range specs {
t.Run(msg, func(t *testing.T) {
- got, err := GetAllContracts(&spec.src)
- require.NoError(t, err)
+ got := GetAllContracts(&spec.src)
assert.Equal(t, spec.exp, got)
})
}
diff --git a/x/wasm/client/cli/query.go b/x/wasm/client/cli/query.go
index f399bfd7..b847b3d8 100644
--- a/x/wasm/client/cli/query.go
+++ b/x/wasm/client/cli/query.go
@@ -67,11 +67,12 @@ func GetCmdLibVersion() *cobra.Command {
// GetCmdBuildAddress build a contract address
func GetCmdBuildAddress() *cobra.Command {
+ decoder := newArgDecoder(hex.DecodeString)
cmd := &cobra.Command{
- Use: "build-address [code-hash] [creator-address] [label]",
+ Use: "build-address [code-hash] [creator-address] [salt-hex-encoded] [json_encoded_init_args (required when set as fixed)]",
Short: "build contract address",
Aliases: []string{"address"},
- Args: cobra.ExactArgs(3),
+ Args: cobra.RangeArgs(3, 4),
RunE: func(cmd *cobra.Command, args []string) error {
codeHash, err := hex.DecodeString(args[0])
if err != nil {
@@ -81,14 +82,27 @@ func GetCmdBuildAddress() *cobra.Command {
if err != nil {
return fmt.Errorf("creator: %s", err)
}
- label := args[2]
- if err := types.ValidateLabel(label); err != nil {
- return fmt.Errorf("label: %s", err)
+ salt, err := hex.DecodeString(args[2])
+ switch {
+ case err != nil:
+ return fmt.Errorf("salt: %s", err)
+ case len(salt) == 0:
+ return errors.New("empty salt")
}
- cmd.Println(keeper.BuildContractAddress(codeHash, creator, label).String())
+
+ if len(args) == 3 {
+ cmd.Println(keeper.BuildContractAddressPredictable(codeHash, creator, salt, []byte{}).String())
+ return nil
+ }
+ msg := types.RawContractMessage(args[3])
+ if err := msg.ValidateBasic(); err != nil {
+ return fmt.Errorf("init message: %s", err)
+ }
+ cmd.Println(keeper.BuildContractAddressPredictable(codeHash, creator, salt, msg).String())
return nil
},
}
+ decoder.RegisterFlags(cmd.PersistentFlags(), "salt")
return cmd
}
@@ -526,7 +540,7 @@ func newArgDecoder(def func(string) ([]byte, error)) *argumentDecoder {
func (a *argumentDecoder) RegisterFlags(f *flag.FlagSet, argName string) {
f.BoolVar(&a.asciiF, "ascii", false, "ascii encoded "+argName)
- f.BoolVar(&a.hexF, "hex", false, "hex encoded "+argName)
+ f.BoolVar(&a.hexF, "hex", false, "hex encoded "+argName)
f.BoolVar(&a.b64F, "b64", false, "base64 encoded "+argName)
}
diff --git a/x/wasm/client/cli/tx.go b/x/wasm/client/cli/tx.go
index c4dfa473..d65e45c2 100644
--- a/x/wasm/client/cli/tx.go
+++ b/x/wasm/client/cli/tx.go
@@ -1,6 +1,7 @@
package cli
import (
+ "encoding/hex"
"errors"
"fmt"
"os"
@@ -11,6 +12,7 @@ import (
"github.com/cosmos/cosmos-sdk/client/tx"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
+ "github.com/cosmos/cosmos-sdk/version"
"github.com/spf13/cobra"
flag "github.com/spf13/pflag"
@@ -23,6 +25,7 @@ const (
flagLabel = "label"
flagAdmin = "admin"
flagNoAdmin = "no-admin"
+ flagFixMsg = "fix-msg"
flagRunAs = "run-as"
flagInstantiateByEverybody = "instantiate-everybody"
flagInstantiateNobody = "instantiate-nobody"
@@ -43,6 +46,7 @@ func GetTxCmd() *cobra.Command {
txCmd.AddCommand(
StoreCodeCmd(),
InstantiateContractCmd(),
+ InstantiateContract2Cmd(),
ExecuteContractCmd(),
MigrateContractCmd(),
UpdateContractAdminCmd(),
@@ -174,8 +178,14 @@ func parseAccessConfigFlags(flags *flag.FlagSet) (*types.AccessConfig, error) {
// InstantiateContractCmd will instantiate a contract from previously uploaded code.
func InstantiateContractCmd() *cobra.Command {
cmd := &cobra.Command{
- Use: "instantiate [code_id_int64] [json_encoded_init_args] --label [text] --admin [address,optional] --amount [coins,optional]",
- Short: "Instantiate a wasm contract",
+ Use: "instantiate [code_id_int64] [json_encoded_init_args] --label [text] --admin [address,optional] --amount [coins,optional] ",
+ Short: "Instantiate a wasm contract",
+ Long: fmt.Sprintf(`Creates a new instance of an uploaded wasm code with the given 'constructor' message.
+Each contract instance has a unique address assigned.
+Example:
+$ %s wasmd tx wasm instantiate 1 '{"foo":"bar"}' --admin="$(%s keys show mykey -a)" \
+ --from mykey --amount="100ustake" --label "local0.1.0"
+`, version.AppName, version.AppName),
Aliases: []string{"start", "init", "inst", "i"},
Args: cobra.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) error {
@@ -183,7 +193,6 @@ func InstantiateContractCmd() *cobra.Command {
if err != nil {
return err
}
-
msg, err := parseInstantiateArgs(args[0], args[1], clientCtx.GetFromAddress(), cmd.Flags())
if err != nil {
return err
@@ -191,7 +200,7 @@ func InstantiateContractCmd() *cobra.Command {
if err := msg.ValidateBasic(); err != nil {
return err
}
- return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), &msg)
+ return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
},
}
@@ -203,43 +212,105 @@ func InstantiateContractCmd() *cobra.Command {
return cmd
}
-func parseInstantiateArgs(rawCodeID, initMsg string, sender sdk.AccAddress, flags *flag.FlagSet) (types.MsgInstantiateContract, error) {
+// InstantiateContract2Cmd will instantiate a contract from previously uploaded code with predicable address generated
+func InstantiateContract2Cmd() *cobra.Command {
+ decoder := newArgDecoder(hex.DecodeString)
+ cmd := &cobra.Command{
+ Use: "instantiate2 [code_id_int64] [json_encoded_init_args] [salt] --label [text] --admin [address,optional] --amount [coins,optional] " +
+ "--fix-msg [bool,optional]",
+ Short: "Instantiate a wasm contract with predictable address",
+ Long: fmt.Sprintf(`Creates a new instance of an uploaded wasm code with the given 'constructor' message.
+Each contract instance has a unique address assigned. They are assigned automatically but in order to have predictable addresses
+for special use cases, the given 'salt' argument and '--fix-msg' parameters can be used to generate a custom address.
+
+Predictable address example (also see '%s query wasm build-address -h'):
+$ %s wasmd tx wasm instantiate2 1 '{"foo":"bar"}' $(echo -n "testing" | xxd -ps) --admin="$(%s keys show mykey -a)" \
+ --from mykey --amount="100ustake" --label "local0.1.0" \
+ --fix-msg
+`, version.AppName, version.AppName, version.AppName),
+ Aliases: []string{"start", "init", "inst", "i"},
+ Args: cobra.ExactArgs(3),
+ RunE: func(cmd *cobra.Command, args []string) error {
+ clientCtx, err := client.GetClientTxContext(cmd)
+ if err != nil {
+ return err
+ }
+ salt, err := decoder.DecodeString(args[2])
+ if err != nil {
+ return fmt.Errorf("salt: %w", err)
+ }
+ fixMsg, err := cmd.Flags().GetBool(flagFixMsg)
+ if err != nil {
+ return fmt.Errorf("fix msg: %w", err)
+ }
+ data, err := parseInstantiateArgs(args[0], args[1], clientCtx.GetFromAddress(), cmd.Flags())
+ if err != nil {
+ return err
+ }
+ msg := &types.MsgInstantiateContract2{
+ Sender: data.Sender,
+ Admin: data.Admin,
+ CodeID: data.CodeID,
+ Label: data.Label,
+ Msg: data.Msg,
+ Funds: data.Funds,
+ Salt: salt,
+ FixMsg: fixMsg,
+ }
+ if err := msg.ValidateBasic(); err != nil {
+ return err
+ }
+ return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
+ },
+ }
+
+ cmd.Flags().String(flagAmount, "", "Coins to send to the contract during instantiation")
+ cmd.Flags().String(flagLabel, "", "A human-readable name for this contract in lists")
+ cmd.Flags().String(flagAdmin, "", "Address of an admin")
+ cmd.Flags().Bool(flagNoAdmin, false, "You must set this explicitly if you don't want an admin")
+ cmd.Flags().Bool(flagFixMsg, false, "An optional flag to include the json_encoded_init_args for the predictable address generation mode")
+ decoder.RegisterFlags(cmd.PersistentFlags(), "salt")
+ flags.AddTxFlagsToCmd(cmd)
+ return cmd
+}
+
+func parseInstantiateArgs(rawCodeID, initMsg string, sender sdk.AccAddress, flags *flag.FlagSet) (*types.MsgInstantiateContract, error) {
// get the id of the code to instantiate
codeID, err := strconv.ParseUint(rawCodeID, 10, 64)
if err != nil {
- return types.MsgInstantiateContract{}, err
+ return nil, err
}
amountStr, err := flags.GetString(flagAmount)
if err != nil {
- return types.MsgInstantiateContract{}, fmt.Errorf("amount: %s", err)
+ return nil, fmt.Errorf("amount: %s", err)
}
amount, err := sdk.ParseCoinsNormalized(amountStr)
if err != nil {
- return types.MsgInstantiateContract{}, fmt.Errorf("amount: %s", err)
+ return nil, fmt.Errorf("amount: %s", err)
}
label, err := flags.GetString(flagLabel)
if err != nil {
- return types.MsgInstantiateContract{}, fmt.Errorf("label: %s", err)
+ return nil, fmt.Errorf("label: %s", err)
}
if label == "" {
- return types.MsgInstantiateContract{}, errors.New("label is required on all contracts")
+ return nil, errors.New("label is required on all contracts")
}
adminStr, err := flags.GetString(flagAdmin)
if err != nil {
- return types.MsgInstantiateContract{}, fmt.Errorf("admin: %s", err)
+ return nil, fmt.Errorf("admin: %s", err)
}
noAdmin, err := flags.GetBool(flagNoAdmin)
if err != nil {
- return types.MsgInstantiateContract{}, fmt.Errorf("no-admin: %s", err)
+ return nil, fmt.Errorf("no-admin: %s", err)
}
// ensure sensible admin is set (or explicitly immutable)
if adminStr == "" && !noAdmin {
- return types.MsgInstantiateContract{}, fmt.Errorf("you must set an admin or explicitly pass --no-admin to make it immutible (wasmd issue #719)")
+ return nil, fmt.Errorf("you must set an admin or explicitly pass --no-admin to make it immutible (wasmd issue #719)")
}
if adminStr != "" && noAdmin {
- return types.MsgInstantiateContract{}, fmt.Errorf("you set an admin and passed --no-admin, those cannot both be true")
+ return nil, fmt.Errorf("you set an admin and passed --no-admin, those cannot both be true")
}
// build and sign the transaction, then broadcast to Tendermint
@@ -251,7 +322,7 @@ func parseInstantiateArgs(rawCodeID, initMsg string, sender sdk.AccAddress, flag
Msg: []byte(initMsg),
Admin: adminStr,
}
- return msg, nil
+ return &msg, nil
}
// ExecuteContractCmd will instantiate a contract from previously uploaded code.
diff --git a/x/wasm/handler.go b/x/wasm/handler.go
index e6004cd7..c7f27b75 100644
--- a/x/wasm/handler.go
+++ b/x/wasm/handler.go
@@ -29,6 +29,8 @@ func NewHandler(k types.ContractOpsKeeper) sdk.Handler {
res, err = msgServer.StoreCode(sdk.WrapSDKContext(ctx), msg)
case *MsgInstantiateContract:
res, err = msgServer.InstantiateContract(sdk.WrapSDKContext(ctx), msg)
+ case *MsgInstantiateContract2:
+ res, err = msgServer.InstantiateContract2(sdk.WrapSDKContext(ctx), msg)
case *MsgExecuteContract:
res, err = msgServer.ExecuteContract(sdk.WrapSDKContext(ctx), msg)
case *MsgMigrateContract:
diff --git a/x/wasm/keeper/addresses.go b/x/wasm/keeper/addresses.go
new file mode 100644
index 00000000..67eabb44
--- /dev/null
+++ b/x/wasm/keeper/addresses.go
@@ -0,0 +1,76 @@
+package keeper
+
+import (
+ "encoding/binary"
+ "fmt"
+
+ sdk "github.com/cosmos/cosmos-sdk/types"
+ "github.com/cosmos/cosmos-sdk/types/address"
+
+ "github.com/CosmWasm/wasmd/x/wasm/types"
+)
+
+// AddressGenerator abstract address generator to be used for a single contract address
+type AddressGenerator func(ctx sdk.Context, codeID uint64, checksum []byte) sdk.AccAddress
+
+// ClassicAddressGenerator generates a contract address using codeID and instanceID sequence
+func (k Keeper) ClassicAddressGenerator() AddressGenerator {
+ return func(ctx sdk.Context, codeID uint64, _ []byte) sdk.AccAddress {
+ instanceID := k.autoIncrementID(ctx, types.KeyLastInstanceID)
+ return BuildContractAddressClassic(codeID, instanceID)
+ }
+}
+
+// PredicableAddressGenerator generates a predictable contract address
+func PredicableAddressGenerator(creator sdk.AccAddress, salt []byte, msg []byte, fixMsg bool) AddressGenerator {
+ return func(ctx sdk.Context, _ uint64, checksum []byte) sdk.AccAddress {
+ if !fixMsg { // clear msg to not be included in the address generation
+ msg = []byte{}
+ }
+ return BuildContractAddressPredictable(checksum, creator, salt, msg)
+ }
+}
+
+// BuildContractAddressClassic builds an sdk account address for a contract.
+func BuildContractAddressClassic(codeID, instanceID uint64) sdk.AccAddress {
+ contractID := make([]byte, 16)
+ binary.BigEndian.PutUint64(contractID[:8], codeID)
+ binary.BigEndian.PutUint64(contractID[8:], instanceID)
+ return address.Module(types.ModuleName, contractID)[:types.ContractAddrLen]
+}
+
+// BuildContractAddressPredictable generates a contract address for the wasm module with len = types.ContractAddrLen using the
+// Cosmos SDK address.Module function.
+// Internally a key is built containing:
+// (len(checksum) | checksum | len(sender_address) | sender_address | len(salt) | salt| len(initMsg) | initMsg).
+//
+// All method parameter values must be valid and not nil.
+func BuildContractAddressPredictable(checksum []byte, creator sdk.AccAddress, salt, initMsg types.RawContractMessage) sdk.AccAddress {
+ if len(checksum) != 32 {
+ panic("invalid checksum")
+ }
+ if err := sdk.VerifyAddressFormat(creator); err != nil {
+ panic(fmt.Sprintf("creator: %s", err))
+ }
+ if err := types.ValidateSalt(salt); err != nil {
+ panic(fmt.Sprintf("salt: %s", err))
+ }
+ if err := initMsg.ValidateBasic(); len(initMsg) != 0 && err != nil {
+ panic(fmt.Sprintf("initMsg: %s", err))
+ }
+ checksum = UInt64LengthPrefix(checksum)
+ creator = UInt64LengthPrefix(creator)
+ salt = UInt64LengthPrefix(salt)
+ initMsg = UInt64LengthPrefix(initMsg)
+ key := make([]byte, len(checksum)+len(creator)+len(salt)+len(initMsg))
+ copy(key[0:], checksum)
+ copy(key[len(checksum):], creator)
+ copy(key[len(checksum)+len(creator):], salt)
+ copy(key[len(checksum)+len(creator)+len(salt):], initMsg)
+ return address.Module(types.ModuleName, key)[:types.ContractAddrLen]
+}
+
+// UInt64LengthPrefix prepend big endian encoded byte length
+func UInt64LengthPrefix(bz []byte) []byte {
+ return append(sdk.Uint64ToBigEndian(uint64(len(bz))), bz...)
+}
diff --git a/x/wasm/keeper/addresses_test.go b/x/wasm/keeper/addresses_test.go
new file mode 100644
index 00000000..fbcc607f
--- /dev/null
+++ b/x/wasm/keeper/addresses_test.go
@@ -0,0 +1,432 @@
+package keeper
+
+import (
+ "encoding/json"
+ "fmt"
+ "testing"
+
+ sdk "github.com/cosmos/cosmos-sdk/types"
+ "github.com/stretchr/testify/require"
+ tmbytes "github.com/tendermint/tendermint/libs/bytes"
+)
+
+func TestBuildContractAddress(t *testing.T) {
+ x, y := sdk.GetConfig().GetBech32AccountAddrPrefix(), sdk.GetConfig().GetBech32AccountPubPrefix()
+ t.Cleanup(func() {
+ sdk.GetConfig().SetBech32PrefixForAccount(x, y)
+ })
+ sdk.GetConfig().SetBech32PrefixForAccount("purple", "purple")
+
+ // test vectors generated via cosmjs: https://github.com/cosmos/cosmjs/pull/1253/files
+ type Spec struct {
+ In struct {
+ Checksum tmbytes.HexBytes `json:"checksum"`
+ Creator sdk.AccAddress `json:"creator"`
+ Salt tmbytes.HexBytes `json:"salt"`
+ Msg string `json:"msg"`
+ } `json:"in"`
+ Out struct {
+ Address sdk.AccAddress `json:"address"`
+ } `json:"out"`
+ }
+ var specs []Spec
+ require.NoError(t, json.Unmarshal([]byte(goldenMasterPredictableContractAddr), &specs))
+ require.NotEmpty(t, specs)
+ for i, spec := range specs {
+ t.Run(fmt.Sprintf("case %d", i), func(t *testing.T) {
+ // when
+ gotAddr := BuildContractAddressPredictable(spec.In.Checksum, spec.In.Creator, spec.In.Salt.Bytes(), []byte(spec.In.Msg))
+
+ require.Equal(t, spec.Out.Address.String(), gotAddr.String())
+ require.NoError(t, sdk.VerifyAddressFormat(gotAddr))
+ })
+ }
+}
+
+const goldenMasterPredictableContractAddr = `[
+ {
+ "in": {
+ "checksum": "13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a5",
+ "creator": "purple1nxvenxve42424242hwamhwamenxvenxvhxf2py",
+ "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbcccccccccc",
+ "salt": "61",
+ "msg": null
+ },
+ "intermediate": {
+ "key": "7761736d00000000000000002013a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a500000000000000149999999999aaaaaaaaaabbbbbbbbbbcccccccccc0000000000000001610000000000000000",
+ "addressData": "5e865d3e45ad3e961f77fd77d46543417ced44d924dc3e079b5415ff6775f847"
+ },
+ "out": {
+ "address": "purple1t6r960j945lfv8mhl4mage2rg97w63xeynwrupum2s2l7em4lprs9ce5hk"
+ }
+ },
+ {
+ "in": {
+ "checksum": "13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a5",
+ "creator": "purple1nxvenxve42424242hwamhwamenxvenxvhxf2py",
+ "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbcccccccccc",
+ "salt": "61",
+ "msg": "{}"
+ },
+ "intermediate": {
+ "key": "7761736d00000000000000002013a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a500000000000000149999999999aaaaaaaaaabbbbbbbbbbcccccccccc00000000000000016100000000000000027b7d",
+ "addressData": "0995499608947a5281e2c7ebd71bdb26a1ad981946dad57f6c4d3ee35de77835"
+ },
+ "out": {
+ "address": "purple1px25n9sgj3a99q0zcl4awx7my6s6mxqegmdd2lmvf5lwxh080q6suttktr"
+ }
+ },
+ {
+ "in": {
+ "checksum": "13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a5",
+ "creator": "purple1nxvenxve42424242hwamhwamenxvenxvhxf2py",
+ "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbcccccccccc",
+ "salt": "61",
+ "msg": "{\"some\":123,\"structure\":{\"nested\":[\"ok\",true]}}"
+ },
+ "intermediate": {
+ "key": "7761736d00000000000000002013a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a500000000000000149999999999aaaaaaaaaabbbbbbbbbbcccccccccc000000000000000161000000000000002f7b22736f6d65223a3132332c22737472756374757265223a7b226e6573746564223a5b226f6b222c747275655d7d7d",
+ "addressData": "83326e554723b15bac664ceabc8a5887e27003abe9fbd992af8c7bcea4745167"
+ },
+ "out": {
+ "address": "purple1svexu428ywc4htrxfn4tezjcsl38qqata8aany4033auafr529ns4v254c"
+ }
+ },
+ {
+ "in": {
+ "checksum": "13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a5",
+ "creator": "purple1nxvenxve42424242hwamhwamenxvenxvhxf2py",
+ "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbcccccccccc",
+ "salt": "aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae",
+ "msg": null
+ },
+ "intermediate": {
+ "key": "7761736d00000000000000002013a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a500000000000000149999999999aaaaaaaaaabbbbbbbbbbcccccccccc0000000000000040aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae0000000000000000",
+ "addressData": "9384c6248c0bb171e306fd7da0993ec1e20eba006452a3a9e078883eb3594564"
+ },
+ "out": {
+ "address": "purple1jwzvvfyvpwchrccxl476pxf7c83qawsqv3f2820q0zyrav6eg4jqdcq7gc"
+ }
+ },
+ {
+ "in": {
+ "checksum": "13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a5",
+ "creator": "purple1nxvenxve42424242hwamhwamenxvenxvhxf2py",
+ "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbcccccccccc",
+ "salt": "aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae",
+ "msg": "{}"
+ },
+ "intermediate": {
+ "key": "7761736d00000000000000002013a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a500000000000000149999999999aaaaaaaaaabbbbbbbbbbcccccccccc0000000000000040aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae00000000000000027b7d",
+ "addressData": "9a8d5f98fb186825401a26206158e7a1213311a9b6a87944469913655af52ffb"
+ },
+ "out": {
+ "address": "purple1n2x4lx8mrp5z2sq6ycsxzk885ysnxydfk658j3zxnyfk2kh49lasesxf6j"
+ }
+ },
+ {
+ "in": {
+ "checksum": "13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a5",
+ "creator": "purple1nxvenxve42424242hwamhwamenxvenxvhxf2py",
+ "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbcccccccccc",
+ "salt": "aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae",
+ "msg": "{\"some\":123,\"structure\":{\"nested\":[\"ok\",true]}}"
+ },
+ "intermediate": {
+ "key": "7761736d00000000000000002013a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a500000000000000149999999999aaaaaaaaaabbbbbbbbbbcccccccccc0000000000000040aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae000000000000002f7b22736f6d65223a3132332c22737472756374757265223a7b226e6573746564223a5b226f6b222c747275655d7d7d",
+ "addressData": "932f07bc53f7d0b0b43cb5a54ac3e245b205e6ae6f7c1d991dc6af4a2ff9ac18"
+ },
+ "out": {
+ "address": "purple1jvhs00zn7lgtpdpukkj54slzgkeqte4wda7pmxgac6h55tle4svq8cmp60"
+ }
+ },
+ {
+ "in": {
+ "checksum": "13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a5",
+ "creator": "purple1nxvenxve42424242hwamhwamenxvenxvmhwamhwaamhwamhwlllsatsy6m",
+ "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff",
+ "salt": "61",
+ "msg": null
+ },
+ "intermediate": {
+ "key": "7761736d00000000000000002013a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a500000000000000209999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff0000000000000001610000000000000000",
+ "addressData": "9725e94f528d8b78d33c25f3dfcd60e6142d8be60ab36f6a5b59036fd51560db"
+ },
+ "out": {
+ "address": "purple1juj7jn6j3k9h35euyhealntquc2zmzlxp2ek76jmtypkl4g4vrdsfwmwxk"
+ }
+ },
+ {
+ "in": {
+ "checksum": "13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a5",
+ "creator": "purple1nxvenxve42424242hwamhwamenxvenxvmhwamhwaamhwamhwlllsatsy6m",
+ "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff",
+ "salt": "61",
+ "msg": "{}"
+ },
+ "intermediate": {
+ "key": "7761736d00000000000000002013a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a500000000000000209999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff00000000000000016100000000000000027b7d",
+ "addressData": "b056e539bbaf447ba18f3f13b792970111fc78933eb6700f4d227b5216d63658"
+ },
+ "out": {
+ "address": "purple1kptw2wdm4az8hgv08ufm0y5hqyglc7yn86m8qr6dyfa4y9kkxevqmkm9q3"
+ }
+ },
+ {
+ "in": {
+ "checksum": "13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a5",
+ "creator": "purple1nxvenxve42424242hwamhwamenxvenxvmhwamhwaamhwamhwlllsatsy6m",
+ "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff",
+ "salt": "61",
+ "msg": "{\"some\":123,\"structure\":{\"nested\":[\"ok\",true]}}"
+ },
+ "intermediate": {
+ "key": "7761736d00000000000000002013a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a500000000000000209999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff000000000000000161000000000000002f7b22736f6d65223a3132332c22737472756374757265223a7b226e6573746564223a5b226f6b222c747275655d7d7d",
+ "addressData": "6c98434180f052294ff89fb6d2dae34f9f4468b0b8e6e7c002b2a44adee39abd"
+ },
+ "out": {
+ "address": "purple1djvyxsvq7pfzjnlcn7md9khrf705g69shrnw0sqzk2jy4hhrn27sjh2ysy"
+ }
+ },
+ {
+ "in": {
+ "checksum": "13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a5",
+ "creator": "purple1nxvenxve42424242hwamhwamenxvenxvmhwamhwaamhwamhwlllsatsy6m",
+ "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff",
+ "salt": "aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae",
+ "msg": null
+ },
+ "intermediate": {
+ "key": "7761736d00000000000000002013a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a500000000000000209999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff0000000000000040aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae0000000000000000",
+ "addressData": "0aaf1c31c5d529d21d898775bc35b3416f47bfd99188c334c6c716102cbd3101"
+ },
+ "out": {
+ "address": "purple1p2h3cvw9655ay8vfsa6mcddng9h5007ejxyvxdxxcutpqt9axyqsagmmay"
+ }
+ },
+ {
+ "in": {
+ "checksum": "13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a5",
+ "creator": "purple1nxvenxve42424242hwamhwamenxvenxvmhwamhwaamhwamhwlllsatsy6m",
+ "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff",
+ "salt": "aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae",
+ "msg": "{}"
+ },
+ "intermediate": {
+ "key": "7761736d00000000000000002013a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a500000000000000209999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff0000000000000040aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae00000000000000027b7d",
+ "addressData": "36fe6ab732187cdfed46290b448b32eb7f4798e7a4968b0537de8a842cbf030e"
+ },
+ "out": {
+ "address": "purple1xmlx4dejrp7dlm2x9y95fzejadl50x885jtgkpfhm69ggt9lqv8qk3vn4f"
+ }
+ },
+ {
+ "in": {
+ "checksum": "13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a5",
+ "creator": "purple1nxvenxve42424242hwamhwamenxvenxvmhwamhwaamhwamhwlllsatsy6m",
+ "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff",
+ "salt": "aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae",
+ "msg": "{\"some\":123,\"structure\":{\"nested\":[\"ok\",true]}}"
+ },
+ "intermediate": {
+ "key": "7761736d00000000000000002013a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a500000000000000209999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff0000000000000040aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae000000000000002f7b22736f6d65223a3132332c22737472756374757265223a7b226e6573746564223a5b226f6b222c747275655d7d7d",
+ "addressData": "a0d0c942adac6f3e5e7c23116c4c42a24e96e0ab75f53690ec2d3de16067c751"
+ },
+ "out": {
+ "address": "purple15rgvjs4d43hnuhnuyvgkcnzz5f8fdc9twh6ndy8v9577zcr8cags40l9dt"
+ }
+ },
+ {
+ "in": {
+ "checksum": "1da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b",
+ "creator": "purple1nxvenxve42424242hwamhwamenxvenxvhxf2py",
+ "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbcccccccccc",
+ "salt": "61",
+ "msg": null
+ },
+ "intermediate": {
+ "key": "7761736d0000000000000000201da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b00000000000000149999999999aaaaaaaaaabbbbbbbbbbcccccccccc0000000000000001610000000000000000",
+ "addressData": "b95c467218d408a0f93046f227b6ece7fe18133ff30113db4d2a7becdfeca141"
+ },
+ "out": {
+ "address": "purple1h9wyvusc6sy2p7fsgmez0dhvullpsyel7vq38k6d9fa7ehlv59qsvnyh36"
+ }
+ },
+ {
+ "in": {
+ "checksum": "1da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b",
+ "creator": "purple1nxvenxve42424242hwamhwamenxvenxvhxf2py",
+ "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbcccccccccc",
+ "salt": "61",
+ "msg": "{}"
+ },
+ "intermediate": {
+ "key": "7761736d0000000000000000201da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b00000000000000149999999999aaaaaaaaaabbbbbbbbbbcccccccccc00000000000000016100000000000000027b7d",
+ "addressData": "23fe45dbbd45dc6cd25244a74b6e99e7a65bf0bac2f2842a05049d37555a3ae6"
+ },
+ "out": {
+ "address": "purple1y0lytkaaghwxe5jjgjn5km5eu7n9hu96ctegg2s9qjwnw4268tnqxhg60a"
+ }
+ },
+ {
+ "in": {
+ "checksum": "1da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b",
+ "creator": "purple1nxvenxve42424242hwamhwamenxvenxvhxf2py",
+ "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbcccccccccc",
+ "salt": "61",
+ "msg": "{\"some\":123,\"structure\":{\"nested\":[\"ok\",true]}}"
+ },
+ "intermediate": {
+ "key": "7761736d0000000000000000201da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b00000000000000149999999999aaaaaaaaaabbbbbbbbbbcccccccccc000000000000000161000000000000002f7b22736f6d65223a3132332c22737472756374757265223a7b226e6573746564223a5b226f6b222c747275655d7d7d",
+ "addressData": "6faea261ed63baa65b05726269e83b217fa6205dc7d9fb74f9667d004a69c082"
+ },
+ "out": {
+ "address": "purple1d7h2yc0dvwa2vkc9wf3xn6pmy9l6vgzaclvlka8eve7sqjnfczpqqsdnwu"
+ }
+ },
+ {
+ "in": {
+ "checksum": "1da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b",
+ "creator": "purple1nxvenxve42424242hwamhwamenxvenxvhxf2py",
+ "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbcccccccccc",
+ "salt": "aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae",
+ "msg": null
+ },
+ "intermediate": {
+ "key": "7761736d0000000000000000201da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b00000000000000149999999999aaaaaaaaaabbbbbbbbbbcccccccccc0000000000000040aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae0000000000000000",
+ "addressData": "67a3ab6384729925fdb144574628ce96836fe098d2c6be4e84ac106b2728d96c"
+ },
+ "out": {
+ "address": "purple1v736kcuyw2vjtld3g3t5v2xwj6pklcyc6trtun5y4sgxkfegm9kq7vgpnt"
+ }
+ },
+ {
+ "in": {
+ "checksum": "1da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b",
+ "creator": "purple1nxvenxve42424242hwamhwamenxvenxvhxf2py",
+ "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbcccccccccc",
+ "salt": "aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae",
+ "msg": "{}"
+ },
+ "intermediate": {
+ "key": "7761736d0000000000000000201da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b00000000000000149999999999aaaaaaaaaabbbbbbbbbbcccccccccc0000000000000040aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae00000000000000027b7d",
+ "addressData": "23a121263bfce05c144f4af86f3d8a9f87dc56f9dc48dbcffc8c5a614da4c661"
+ },
+ "out": {
+ "address": "purple1ywsjzf3mlns9c9z0ftux70v2n7rac4hem3ydhnlu33dxzndycesssc7x2m"
+ }
+ },
+ {
+ "in": {
+ "checksum": "1da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b",
+ "creator": "purple1nxvenxve42424242hwamhwamenxvenxvhxf2py",
+ "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbcccccccccc",
+ "salt": "aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae",
+ "msg": "{\"some\":123,\"structure\":{\"nested\":[\"ok\",true]}}"
+ },
+ "intermediate": {
+ "key": "7761736d0000000000000000201da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b00000000000000149999999999aaaaaaaaaabbbbbbbbbbcccccccccc0000000000000040aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae000000000000002f7b22736f6d65223a3132332c22737472756374757265223a7b226e6573746564223a5b226f6b222c747275655d7d7d",
+ "addressData": "dd90dba6d6fcd5fb9c9c8f536314eb1bb29cb5aa084b633c5806b926a5636b58"
+ },
+ "out": {
+ "address": "purple1mkgdhfkkln2lh8yu3afkx98trwefedd2pp9kx0zcq6ujdftrddvq50esay"
+ }
+ },
+ {
+ "in": {
+ "checksum": "1da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b",
+ "creator": "purple1nxvenxve42424242hwamhwamenxvenxvmhwamhwaamhwamhwlllsatsy6m",
+ "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff",
+ "salt": "61",
+ "msg": null
+ },
+ "intermediate": {
+ "key": "7761736d0000000000000000201da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b00000000000000209999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff0000000000000001610000000000000000",
+ "addressData": "547a743022f4f1af05b102f57bf1c1c7d7ee81bae427dc20d36b2c4ec57612ae"
+ },
+ "out": {
+ "address": "purple123a8gvpz7nc67pd3qt6hhuwpclt7aqd6usnacgxndvkya3tkz2hq5hz38f"
+ }
+ },
+ {
+ "in": {
+ "checksum": "1da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b",
+ "creator": "purple1nxvenxve42424242hwamhwamenxvenxvmhwamhwaamhwamhwlllsatsy6m",
+ "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff",
+ "salt": "61",
+ "msg": "{}"
+ },
+ "intermediate": {
+ "key": "7761736d0000000000000000201da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b00000000000000209999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff00000000000000016100000000000000027b7d",
+ "addressData": "416e169110e4b411bc53162d7503b2bbf14d6b36b1413a4f4c9af622696e9665"
+ },
+ "out": {
+ "address": "purple1g9hpdygsuj6pr0znzckh2qajh0c566ekk9qn5n6vntmzy6twjejsrl9alk"
+ }
+ },
+ {
+ "in": {
+ "checksum": "1da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b",
+ "creator": "purple1nxvenxve42424242hwamhwamenxvenxvmhwamhwaamhwamhwlllsatsy6m",
+ "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff",
+ "salt": "61",
+ "msg": "{\"some\":123,\"structure\":{\"nested\":[\"ok\",true]}}"
+ },
+ "intermediate": {
+ "key": "7761736d0000000000000000201da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b00000000000000209999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff000000000000000161000000000000002f7b22736f6d65223a3132332c22737472756374757265223a7b226e6573746564223a5b226f6b222c747275655d7d7d",
+ "addressData": "619a0988b92d8796cea91dea63cbb1f1aefa4a6b6ee5c5d1e937007252697220"
+ },
+ "out": {
+ "address": "purple1vxdqnz9e9kredn4frh4x8ja37xh05jntdmjut50fxuq8y5nfwgsquu9mxh"
+ }
+ },
+ {
+ "in": {
+ "checksum": "1da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b",
+ "creator": "purple1nxvenxve42424242hwamhwamenxvenxvmhwamhwaamhwamhwlllsatsy6m",
+ "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff",
+ "salt": "aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae",
+ "msg": null
+ },
+ "intermediate": {
+ "key": "7761736d0000000000000000201da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b00000000000000209999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff0000000000000040aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae0000000000000000",
+ "addressData": "d8af856a6a04852d19b647ad6d4336eb26e077f740aef1a0331db34d299a885a"
+ },
+ "out": {
+ "address": "purple1mzhc26n2qjzj6xdkg7kk6sekavnwqalhgzh0rgpnrke562v63pdq8grp8q"
+ }
+ },
+ {
+ "in": {
+ "checksum": "1da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b",
+ "creator": "purple1nxvenxve42424242hwamhwamenxvenxvmhwamhwaamhwamhwlllsatsy6m",
+ "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff",
+ "salt": "aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae",
+ "msg": "{}"
+ },
+ "intermediate": {
+ "key": "7761736d0000000000000000201da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b00000000000000209999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff0000000000000040aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae00000000000000027b7d",
+ "addressData": "c7fb7bea96daab23e416c4fcf328215303005e1d0d5424257335568e5381e33c"
+ },
+ "out": {
+ "address": "purple1clahh65km24j8eqkcn70x2pp2vpsqhsap42zgftnx4tgu5upuv7q9ywjws"
+ }
+ },
+ {
+ "in": {
+ "checksum": "1da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b",
+ "creator": "purple1nxvenxve42424242hwamhwamenxvenxvmhwamhwaamhwamhwlllsatsy6m",
+ "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff",
+ "salt": "aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae",
+ "msg": "{\"some\":123,\"structure\":{\"nested\":[\"ok\",true]}}"
+ },
+ "intermediate": {
+ "key": "7761736d0000000000000000201da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b00000000000000209999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff0000000000000040aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae000000000000002f7b22736f6d65223a3132332c22737472756374757265223a7b226e6573746564223a5b226f6b222c747275655d7d7d",
+ "addressData": "ccdf9dea141a6c2475870529ab38fae9dec30df28e005894fe6578b66133ab4a"
+ },
+ "out": {
+ "address": "purple1en0em6s5rfkzgav8q556kw86a80vxr0j3cq93987v4utvcfn4d9q0tql4w"
+ }
+ }
+]
+`
diff --git a/x/wasm/keeper/contract_keeper.go b/x/wasm/keeper/contract_keeper.go
index 6e1195db..564adc55 100644
--- a/x/wasm/keeper/contract_keeper.go
+++ b/x/wasm/keeper/contract_keeper.go
@@ -11,7 +11,18 @@ var _ types.ContractOpsKeeper = PermissionedKeeper{}
// decoratedKeeper contains a subset of the wasm keeper that are already or can be guarded by an authorization policy in the future
type decoratedKeeper interface {
create(ctx sdk.Context, creator sdk.AccAddress, wasmCode []byte, instantiateAccess *types.AccessConfig, authZ AuthorizationPolicy) (codeID uint64, checksum []byte, err error)
- instantiate(ctx sdk.Context, codeID uint64, creator, admin sdk.AccAddress, initMsg []byte, label string, deposit sdk.Coins, authZ AuthorizationPolicy) (sdk.AccAddress, []byte, error)
+
+ instantiate(
+ ctx sdk.Context,
+ codeID uint64,
+ creator, admin sdk.AccAddress,
+ initMsg []byte,
+ label string,
+ deposit sdk.Coins,
+ addressGenerator AddressGenerator,
+ authZ AuthorizationPolicy,
+ ) (sdk.AccAddress, []byte, error)
+
migrate(ctx sdk.Context, contractAddress sdk.AccAddress, caller sdk.AccAddress, newCodeID uint64, msg []byte, authZ AuthorizationPolicy) ([]byte, error)
setContractAdmin(ctx sdk.Context, contractAddress, caller, newAdmin sdk.AccAddress, authZ AuthorizationPolicy) error
pinCode(ctx sdk.Context, codeID uint64) error
@@ -20,6 +31,7 @@ type decoratedKeeper interface {
Sudo(ctx sdk.Context, contractAddress sdk.AccAddress, msg []byte) ([]byte, error)
setContractInfoExtension(ctx sdk.Context, contract sdk.AccAddress, extra types.ContractInfoExtension) error
setAccessConfig(ctx sdk.Context, codeID uint64, caller sdk.AccAddress, newConfig types.AccessConfig, autz AuthorizationPolicy) error
+ ClassicAddressGenerator() AddressGenerator
}
type PermissionedKeeper struct {
@@ -43,8 +55,40 @@ func (p PermissionedKeeper) Create(ctx sdk.Context, creator sdk.AccAddress, wasm
return p.nested.create(ctx, creator, wasmCode, instantiateAccess, p.authZPolicy)
}
-func (p PermissionedKeeper) Instantiate(ctx sdk.Context, codeID uint64, creator, admin sdk.AccAddress, initMsg []byte, label string, deposit sdk.Coins) (sdk.AccAddress, []byte, error) {
- return p.nested.instantiate(ctx, codeID, creator, admin, initMsg, label, deposit, p.authZPolicy)
+// Instantiate creates an instance of a WASM contract using the classic sequence based address generator
+func (p PermissionedKeeper) Instantiate(
+ ctx sdk.Context,
+ codeID uint64,
+ creator, admin sdk.AccAddress,
+ initMsg []byte,
+ label string,
+ deposit sdk.Coins,
+) (sdk.AccAddress, []byte, error) {
+ return p.nested.instantiate(ctx, codeID, creator, admin, initMsg, label, deposit, p.nested.ClassicAddressGenerator(), p.authZPolicy)
+}
+
+// Instantiate2 creates an instance of a WASM contract using the predictable address generator
+func (p PermissionedKeeper) Instantiate2(
+ ctx sdk.Context,
+ codeID uint64,
+ creator, admin sdk.AccAddress,
+ initMsg []byte,
+ label string,
+ deposit sdk.Coins,
+ salt []byte,
+ fixMsg bool,
+) (sdk.AccAddress, []byte, error) {
+ return p.nested.instantiate(
+ ctx,
+ codeID,
+ creator,
+ admin,
+ initMsg,
+ label,
+ deposit,
+ PredicableAddressGenerator(creator, salt, initMsg, fixMsg),
+ p.authZPolicy,
+ )
}
func (p PermissionedKeeper) Execute(ctx sdk.Context, contractAddress sdk.AccAddress, caller sdk.AccAddress, msg []byte, coins sdk.Coins) ([]byte, error) {
diff --git a/x/wasm/keeper/contract_keeper_test.go b/x/wasm/keeper/contract_keeper_test.go
new file mode 100644
index 00000000..0a8bd1e2
--- /dev/null
+++ b/x/wasm/keeper/contract_keeper_test.go
@@ -0,0 +1,168 @@
+package keeper
+
+import (
+ "encoding/json"
+ "fmt"
+ "math"
+ "strings"
+ "testing"
+
+ "github.com/CosmWasm/wasmd/x/wasm/keeper/wasmtesting"
+
+ sdk "github.com/cosmos/cosmos-sdk/types"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+
+ "github.com/CosmWasm/wasmd/x/wasm/types"
+)
+
+func TestInstantiate2(t *testing.T) {
+ parentCtx, keepers := CreateTestInput(t, false, AvailableCapabilities)
+ example := StoreHackatomExampleContract(t, parentCtx, keepers)
+ otherExample := StoreReflectContract(t, parentCtx, keepers)
+ mock := &wasmtesting.MockWasmer{}
+ wasmtesting.MakeInstantiable(mock)
+ keepers.WasmKeeper.wasmVM = mock // set mock to not fail on contract init message
+
+ verifierAddr := RandomAccountAddress(t)
+ beneficiaryAddr := RandomAccountAddress(t)
+ initMsg := mustMarshal(t, HackatomExampleInitMsg{Verifier: verifierAddr, Beneficiary: beneficiaryAddr})
+
+ otherAddr := keepers.Faucet.NewFundedRandomAccount(parentCtx, sdk.NewInt64Coin("denom", 1_000_000_000))
+
+ const (
+ mySalt = "my salt"
+ myLabel = "my label"
+ )
+ // create instances for duplicate checks
+ exampleContract := func(t *testing.T, ctx sdk.Context, fixMsg bool) {
+ _, _, err := keepers.ContractKeeper.Instantiate2(
+ ctx,
+ example.CodeID,
+ example.CreatorAddr,
+ nil,
+ initMsg,
+ myLabel,
+ sdk.NewCoins(sdk.NewInt64Coin("denom", 1)),
+ []byte(mySalt),
+ fixMsg,
+ )
+ require.NoError(t, err)
+ }
+ exampleWithFixMsg := func(t *testing.T, ctx sdk.Context) {
+ exampleContract(t, ctx, true)
+ }
+ exampleWithoutFixMsg := func(t *testing.T, ctx sdk.Context) {
+ exampleContract(t, ctx, false)
+ }
+ specs := map[string]struct {
+ setup func(t *testing.T, ctx sdk.Context)
+ codeID uint64
+ sender sdk.AccAddress
+ salt []byte
+ initMsg json.RawMessage
+ fixMsg bool
+ expErr error
+ }{
+ "fix msg - generates different address than without fixMsg": {
+ setup: exampleWithoutFixMsg,
+ codeID: example.CodeID,
+ sender: example.CreatorAddr,
+ salt: []byte(mySalt),
+ initMsg: initMsg,
+ fixMsg: true,
+ },
+ "fix msg - different sender": {
+ setup: exampleWithFixMsg,
+ codeID: example.CodeID,
+ sender: otherAddr,
+ salt: []byte(mySalt),
+ initMsg: initMsg,
+ fixMsg: true,
+ },
+ "fix msg - different code": {
+ setup: exampleWithFixMsg,
+ codeID: otherExample.CodeID,
+ sender: example.CreatorAddr,
+ salt: []byte(mySalt),
+ initMsg: []byte(`{}`),
+ fixMsg: true,
+ },
+ "fix msg - different salt": {
+ setup: exampleWithFixMsg,
+ codeID: example.CodeID,
+ sender: example.CreatorAddr,
+ salt: []byte("other salt"),
+ initMsg: initMsg,
+ fixMsg: true,
+ },
+ "fix msg - different init msg": {
+ setup: exampleWithFixMsg,
+ codeID: example.CodeID,
+ sender: example.CreatorAddr,
+ salt: []byte(mySalt),
+ initMsg: mustMarshal(t, HackatomExampleInitMsg{Verifier: otherAddr, Beneficiary: beneficiaryAddr}),
+ fixMsg: true,
+ },
+ "different sender": {
+ setup: exampleWithoutFixMsg,
+ codeID: example.CodeID,
+ sender: otherAddr,
+ salt: []byte(mySalt),
+ initMsg: initMsg,
+ },
+ "different code": {
+ setup: exampleWithoutFixMsg,
+ codeID: otherExample.CodeID,
+ sender: example.CreatorAddr,
+ salt: []byte(mySalt),
+ initMsg: []byte(`{}`),
+ },
+ "different salt": {
+ setup: exampleWithoutFixMsg,
+ codeID: example.CodeID,
+ sender: example.CreatorAddr,
+ salt: []byte(`other salt`),
+ initMsg: initMsg,
+ },
+ "different init msg - reject same address": {
+ setup: exampleWithoutFixMsg,
+ codeID: example.CodeID,
+ sender: example.CreatorAddr,
+ salt: []byte(mySalt),
+ initMsg: mustMarshal(t, HackatomExampleInitMsg{Verifier: otherAddr, Beneficiary: beneficiaryAddr}),
+ expErr: types.ErrDuplicate,
+ },
+ "fix msg - long msg": {
+ setup: exampleWithFixMsg,
+ codeID: example.CodeID,
+ sender: otherAddr,
+ salt: []byte(mySalt),
+ initMsg: []byte(fmt.Sprintf(`{"foo":%q}`, strings.Repeat("b", math.MaxInt16+1))), // too long kills CI
+ fixMsg: true,
+ },
+ }
+ for name, spec := range specs {
+ t.Run(name, func(t *testing.T) {
+ ctx, _ := parentCtx.CacheContext()
+ spec.setup(t, ctx)
+ gotAddr, _, gotErr := keepers.ContractKeeper.Instantiate2(
+ ctx,
+ spec.codeID,
+ spec.sender,
+ nil,
+ spec.initMsg,
+ myLabel,
+ sdk.NewCoins(sdk.NewInt64Coin("denom", 2)),
+ spec.salt,
+ spec.fixMsg,
+ )
+ if spec.expErr != nil {
+ assert.ErrorIs(t, gotErr, spec.expErr)
+ return
+ }
+ require.NoError(t, gotErr)
+ assert.NotEmpty(t, gotAddr)
+ })
+ }
+}
diff --git a/x/wasm/keeper/genesis.go b/x/wasm/keeper/genesis.go
index d81750b7..7fa5280b 100644
--- a/x/wasm/keeper/genesis.go
+++ b/x/wasm/keeper/genesis.go
@@ -35,6 +35,7 @@ func InitGenesis(ctx sdk.Context, keeper *Keeper, data types.GenesisState, staki
}
}
+ var maxContractID int
for i, contract := range data.Contracts {
contractAddr, err := sdk.AccAddressFromBech32(contract.ContractAddress)
if err != nil {
@@ -44,6 +45,7 @@ func InitGenesis(ctx sdk.Context, keeper *Keeper, data types.GenesisState, staki
if err != nil {
return nil, sdkerrors.Wrapf(err, "contract number %d", i)
}
+ maxContractID = i + 1 // not ideal but max(contractID) is not persisted otherwise
}
for i, seq := range data.Sequences {
@@ -58,6 +60,10 @@ func InitGenesis(ctx sdk.Context, keeper *Keeper, data types.GenesisState, staki
if seqVal <= maxCodeID {
return nil, sdkerrors.Wrapf(types.ErrInvalid, "seq %s with value: %d must be greater than: %d ", string(types.KeyLastCodeID), seqVal, maxCodeID)
}
+ seqVal = keeper.PeekAutoIncrementID(ctx, types.KeyLastInstanceID)
+ if seqVal <= uint64(maxContractID) {
+ return nil, sdkerrors.Wrapf(types.ErrInvalid, "seq %s with value: %d must be greater than: %d ", string(types.KeyLastInstanceID), seqVal, maxContractID)
+ }
if len(data.GenMsgs) == 0 {
return nil, nil
@@ -111,7 +117,7 @@ func ExportGenesis(ctx sdk.Context, keeper *Keeper) *types.GenesisState {
return false
})
- for _, k := range [][]byte{types.KeyLastCodeID} {
+ for _, k := range [][]byte{types.KeyLastCodeID, types.KeyLastInstanceID} {
genState.Sequences = append(genState.Sequences, types.Sequence{
IDKey: k,
Value: keeper.PeekAutoIncrementID(ctx, k),
diff --git a/x/wasm/keeper/genesis_test.go b/x/wasm/keeper/genesis_test.go
index 4b65f82e..aee7ad00 100644
--- a/x/wasm/keeper/genesis_test.go
+++ b/x/wasm/keeper/genesis_test.go
@@ -11,14 +11,11 @@ import (
"testing"
"time"
- bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper"
-
- "github.com/cosmos/cosmos-sdk/types/address"
-
"github.com/cosmos/cosmos-sdk/store"
"github.com/cosmos/cosmos-sdk/store/prefix"
sdk "github.com/cosmos/cosmos-sdk/types"
authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper"
+ bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper"
distributionkeeper "github.com/cosmos/cosmos-sdk/x/distribution/keeper"
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
paramskeeper "github.com/cosmos/cosmos-sdk/x/params/keeper"
@@ -69,7 +66,7 @@ func TestGenesisExportImport(t *testing.T) {
creatorAddr, err := sdk.AccAddressFromBech32(codeInfo.Creator)
require.NoError(t, err)
- codeID, checksum, err := contractKeeper.Create(srcCtx, creatorAddr, wasmCode, &codeInfo.InstantiateConfig)
+ codeID, _, err := contractKeeper.Create(srcCtx, creatorAddr, wasmCode, &codeInfo.InstantiateConfig)
require.NoError(t, err)
if pinned {
contractKeeper.PinCode(srcCtx, codeID)
@@ -84,7 +81,7 @@ func TestGenesisExportImport(t *testing.T) {
}
contract.CodeID = codeID
- contractAddr := BuildContractAddress(checksum, creatorAddr, "testing")
+ contractAddr := wasmKeeper.ClassicAddressGenerator()(srcCtx, codeID, nil)
wasmKeeper.storeContractInfo(srcCtx, contractAddr, &contract)
wasmKeeper.appendToContractHistory(srcCtx, contractAddr, history...)
wasmKeeper.importContractState(srcCtx, contractAddr, stateModels)
@@ -160,16 +157,6 @@ func TestGenesisInit(t *testing.T) {
require.NoError(t, err)
myCodeInfo := wasmTypes.CodeInfoFixture(wasmTypes.WithSHA256CodeHash(wasmCode))
- mySenderAddr := sdk.AccAddress(bytes.Repeat([]byte{1}, address.Len))
- myLabel := "testing"
- myContractInfoFixture := func(mutators ...func(*types.ContractInfo)) types.ContractInfo {
- return types.ContractInfoFixture(func(c *wasmTypes.ContractInfo) {
- c.CodeID = 1
- c.Creator = mySenderAddr.String()
- c.Label = myLabel
- }, types.OnlyGenesisFields)
- }
-
specs := map[string]struct {
src types.GenesisState
stakingMock StakingKeeperMock
@@ -185,6 +172,7 @@ func TestGenesisInit(t *testing.T) {
}},
Sequences: []types.Sequence{
{IDKey: types.KeyLastCodeID, Value: 2},
+ {IDKey: types.KeyLastInstanceID, Value: 1},
},
Params: types.DefaultParams(),
},
@@ -203,6 +191,7 @@ func TestGenesisInit(t *testing.T) {
}},
Sequences: []types.Sequence{
{IDKey: types.KeyLastCodeID, Value: 10},
+ {IDKey: types.KeyLastInstanceID, Value: 1},
},
Params: types.DefaultParams(),
},
@@ -222,6 +211,7 @@ func TestGenesisInit(t *testing.T) {
Contracts: nil,
Sequences: []types.Sequence{
{IDKey: types.KeyLastCodeID, Value: 3},
+ {IDKey: types.KeyLastInstanceID, Value: 1},
},
Params: types.DefaultParams(),
},
@@ -278,12 +268,13 @@ func TestGenesisInit(t *testing.T) {
}},
Contracts: []types.Contract{
{
- ContractAddress: BuildContractAddress(myCodeInfo.CodeHash, mySenderAddr, myLabel).String(),
- ContractInfo: myContractInfoFixture(),
+ ContractAddress: BuildContractAddressClassic(1, 1).String(),
+ ContractInfo: types.ContractInfoFixture(func(c *wasmTypes.ContractInfo) { c.CodeID = 1 }, types.OnlyGenesisFields),
},
},
Sequences: []types.Sequence{
{IDKey: types.KeyLastCodeID, Value: 2},
+ {IDKey: types.KeyLastInstanceID, Value: 2},
},
Params: types.DefaultParams(),
},
@@ -298,17 +289,16 @@ func TestGenesisInit(t *testing.T) {
}},
Contracts: []types.Contract{
{
- ContractAddress: BuildContractAddress(myCodeInfo.CodeHash, mySenderAddr, myLabel).String(),
- ContractInfo: myContractInfoFixture(),
+ ContractAddress: BuildContractAddressClassic(1, 1).String(),
+ ContractInfo: types.ContractInfoFixture(func(c *wasmTypes.ContractInfo) { c.CodeID = 1 }, types.OnlyGenesisFields),
}, {
- ContractAddress: BuildContractAddress(myCodeInfo.CodeHash, mySenderAddr, "other-label").String(),
- ContractInfo: myContractInfoFixture(func(i *wasmTypes.ContractInfo) {
- i.Label = "other-label"
- }),
+ ContractAddress: BuildContractAddressClassic(1, 2).String(),
+ ContractInfo: types.ContractInfoFixture(func(c *wasmTypes.ContractInfo) { c.CodeID = 1 }, types.OnlyGenesisFields),
},
},
Sequences: []types.Sequence{
{IDKey: types.KeyLastCodeID, Value: 2},
+ {IDKey: types.KeyLastInstanceID, Value: 3},
},
Params: types.DefaultParams(),
},
@@ -318,8 +308,8 @@ func TestGenesisInit(t *testing.T) {
src: types.GenesisState{
Contracts: []types.Contract{
{
- ContractAddress: BuildContractAddress(myCodeInfo.CodeHash, mySenderAddr, myLabel).String(),
- ContractInfo: myContractInfoFixture(),
+ ContractAddress: BuildContractAddressClassic(1, 1).String(),
+ ContractInfo: types.ContractInfoFixture(func(c *wasmTypes.ContractInfo) { c.CodeID = 1 }, types.OnlyGenesisFields),
},
},
Params: types.DefaultParams(),
@@ -334,11 +324,11 @@ func TestGenesisInit(t *testing.T) {
}},
Contracts: []types.Contract{
{
- ContractAddress: BuildContractAddress(myCodeInfo.CodeHash, mySenderAddr, myLabel).String(),
- ContractInfo: myContractInfoFixture(),
+ ContractAddress: BuildContractAddressClassic(1, 1).String(),
+ ContractInfo: types.ContractInfoFixture(func(c *wasmTypes.ContractInfo) { c.CodeID = 1 }, types.OnlyGenesisFields),
}, {
- ContractAddress: BuildContractAddress(myCodeInfo.CodeHash, mySenderAddr, myLabel).String(),
- ContractInfo: myContractInfoFixture(),
+ ContractAddress: BuildContractAddressClassic(1, 1).String(),
+ ContractInfo: types.ContractInfoFixture(func(c *wasmTypes.ContractInfo) { c.CodeID = 1 }, types.OnlyGenesisFields),
},
},
Params: types.DefaultParams(),
@@ -353,8 +343,8 @@ func TestGenesisInit(t *testing.T) {
}},
Contracts: []types.Contract{
{
- ContractAddress: BuildContractAddress(myCodeInfo.CodeHash, mySenderAddr, myLabel).String(),
- ContractInfo: myContractInfoFixture(),
+ ContractAddress: BuildContractAddressClassic(1, 1).String(),
+ ContractInfo: types.ContractInfoFixture(func(c *wasmTypes.ContractInfo) { c.CodeID = 1 }, types.OnlyGenesisFields),
ContractState: []types.Model{
{
Key: []byte{0x1},
@@ -392,6 +382,26 @@ func TestGenesisInit(t *testing.T) {
Params: types.DefaultParams(),
},
},
+ "prevent contract id seq init value == count contracts": {
+ src: types.GenesisState{
+ Codes: []types.Code{{
+ CodeID: firstCodeID,
+ CodeInfo: myCodeInfo,
+ CodeBytes: wasmCode,
+ }},
+ Contracts: []types.Contract{
+ {
+ ContractAddress: BuildContractAddressClassic(1, 1).String(),
+ ContractInfo: types.ContractInfoFixture(func(c *wasmTypes.ContractInfo) { c.CodeID = 1 }, types.OnlyGenesisFields),
+ },
+ },
+ Sequences: []types.Sequence{
+ {IDKey: types.KeyLastCodeID, Value: 2},
+ {IDKey: types.KeyLastInstanceID, Value: 1},
+ },
+ Params: types.DefaultParams(),
+ },
+ },
"validator set update called for any genesis messages": {
src: wasmTypes.GenesisState{
GenMsgs: []types.GenesisState_GenMsgs{
@@ -550,17 +560,16 @@ func TestImportContractWithCodeHistoryReset(t *testing.T) {
}
assert.Equal(t, expHistory, keeper.GetContractHistory(ctx, contractAddr))
assert.Equal(t, uint64(2), keeper.PeekAutoIncrementID(ctx, types.KeyLastCodeID))
+ assert.Equal(t, uint64(3), keeper.PeekAutoIncrementID(ctx, types.KeyLastInstanceID))
}
func TestSupportedGenMsgTypes(t *testing.T) {
wasmCode, err := os.ReadFile("./testdata/hackatom.wasm")
require.NoError(t, err)
- wasmHash := sha256.Sum256(wasmCode)
var (
myAddress sdk.AccAddress = bytes.Repeat([]byte{1}, types.ContractAddrLen)
verifierAddress sdk.AccAddress = bytes.Repeat([]byte{2}, types.ContractAddrLen)
beneficiaryAddress sdk.AccAddress = bytes.Repeat([]byte{3}, types.ContractAddrLen)
- contractAddr = BuildContractAddress(wasmHash[:], myAddress, "testing")
)
const denom = "stake"
importState := types.GenesisState{
@@ -592,7 +601,7 @@ func TestSupportedGenMsgTypes(t *testing.T) {
Sum: &types.GenesisState_GenMsgs_ExecuteContract{
ExecuteContract: &types.MsgExecuteContract{
Sender: verifierAddress.String(),
- Contract: contractAddr.String(),
+ Contract: BuildContractAddressClassic(1, 1).String(),
Msg: []byte(`{"release":{}}`),
},
},
@@ -617,7 +626,7 @@ func TestSupportedGenMsgTypes(t *testing.T) {
require.NotNil(t, codeInfo)
// verify contract instantiated
- cInfo := keeper.GetContractInfo(ctx, contractAddr)
+ cInfo := keeper.GetContractInfo(ctx, BuildContractAddressClassic(1, 1))
require.NotNil(t, cInfo)
// verify contract executed
diff --git a/x/wasm/keeper/ibc_test.go b/x/wasm/keeper/ibc_test.go
index bdbab1a3..063dfb7f 100644
--- a/x/wasm/keeper/ibc_test.go
+++ b/x/wasm/keeper/ibc_test.go
@@ -4,8 +4,6 @@ import (
"fmt"
"testing"
- "github.com/tendermint/tendermint/libs/rand"
-
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/stretchr/testify/assert"
@@ -43,7 +41,7 @@ func TestBindingPortForIBCContractOnInstantiate(t *testing.T) {
}
func TestContractFromPortID(t *testing.T) {
- contractAddr := BuildContractAddress(rand.Bytes(32), RandomAccountAddress(t), "testing")
+ contractAddr := BuildContractAddressClassic(1, 100)
specs := map[string]struct {
srcPort string
expAddr sdk.AccAddress
diff --git a/x/wasm/keeper/keeper.go b/x/wasm/keeper/keeper.go
index c3496036..f29f6e18 100644
--- a/x/wasm/keeper/keeper.go
+++ b/x/wasm/keeper/keeper.go
@@ -19,7 +19,6 @@ import (
"github.com/cosmos/cosmos-sdk/store/prefix"
"github.com/cosmos/cosmos-sdk/telemetry"
sdk "github.com/cosmos/cosmos-sdk/types"
- "github.com/cosmos/cosmos-sdk/types/address"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
vestingexported "github.com/cosmos/cosmos-sdk/x/auth/vesting/exported"
@@ -224,8 +223,8 @@ func (k Keeper) create(ctx sdk.Context, creator sdk.AccAddress, wasmCode []byte,
evt := sdk.NewEvent(
types.EventTypeStoreCode,
- sdk.NewAttribute(types.AttributeKeyCodeID, strconv.FormatUint(codeID, 10)),
sdk.NewAttribute(types.AttributeKeyChecksum, hex.EncodeToString(checksum)),
+ sdk.NewAttribute(types.AttributeKeyCodeID, strconv.FormatUint(codeID, 10)), // last element to be compatible with scripts
)
for _, f := range strings.Split(report.RequiredCapabilities, ",") {
evt.AppendAttributes(sdk.NewAttribute(types.AttributeKeyRequiredCapability, strings.TrimSpace(f)))
@@ -267,7 +266,16 @@ func (k Keeper) importCode(ctx sdk.Context, codeID uint64, codeInfo types.CodeIn
return nil
}
-func (k Keeper) instantiate(ctx sdk.Context, codeID uint64, creator, admin sdk.AccAddress, initMsg []byte, label string, deposit sdk.Coins, authPolicy AuthorizationPolicy) (sdk.AccAddress, []byte, error) {
+func (k Keeper) instantiate(
+ ctx sdk.Context,
+ codeID uint64,
+ creator, admin sdk.AccAddress,
+ initMsg []byte,
+ label string,
+ deposit sdk.Coins,
+ addressGenerator AddressGenerator,
+ authPolicy AuthorizationPolicy,
+) (sdk.AccAddress, []byte, error) {
defer telemetry.MeasureSince(time.Now(), "wasm", "contract", "instantiate")
if creator == nil {
@@ -277,19 +285,15 @@ func (k Keeper) instantiate(ctx sdk.Context, codeID uint64, creator, admin sdk.A
ctx.GasMeter().ConsumeGas(instanceCosts, "Loading CosmWasm module: instantiate")
// get contact info
- store := ctx.KVStore(k.storeKey)
- bz := store.Get(types.GetCodeKey(codeID))
- if bz == nil {
+ codeInfo := k.GetCodeInfo(ctx, codeID)
+ if codeInfo == nil {
return nil, nil, sdkerrors.Wrap(types.ErrNotFound, "code")
}
- var codeInfo types.CodeInfo
- k.cdc.MustUnmarshal(bz, &codeInfo)
-
if !authPolicy.CanInstantiateContract(codeInfo.InstantiateConfig, creator) {
return nil, nil, sdkerrors.Wrap(sdkerrors.ErrUnauthorized, "can not instantiate")
}
- contractAddress := BuildContractAddress(codeInfo.CodeHash, creator, label)
+ contractAddress := addressGenerator(ctx, codeID, codeInfo.CodeHash)
if k.HasContractInfo(ctx, contractAddress) {
return nil, nil, types.ErrDuplicate.Wrap("instance with this code id, sender and label exists: try a different label")
}
@@ -338,7 +342,7 @@ func (k Keeper) instantiate(ctx sdk.Context, codeID uint64, creator, admin sdk.A
info := types.NewInfo(creator, deposit)
// create prefixed data store
- // 0x03 | BuildContractAddress (sdk.AccAddress)
+ // 0x03 | BuildContractAddressClassic (sdk.AccAddress)
prefixStoreKey := types.GetContractStorePrefix(contractAddress)
prefixStore := prefix.NewStore(ctx.KVStore(k.storeKey), prefixStoreKey)
@@ -1006,21 +1010,6 @@ func (k Keeper) consumeRuntimeGas(ctx sdk.Context, gas uint64) {
}
}
-// BuildContractAddress generates a contract address for the wasm module with len = types.ContractAddrLen using the
-// Cosmos SDK address.Module function.
-// Internally a key is built containing (len(checksum) | checksum | len(sender_address) | sender_address | len(label) | label).
-// All method parameter values must be valid and not be empty or nil.
-func BuildContractAddress(checksum []byte, creator sdk.AccAddress, label string) sdk.AccAddress {
- checksum = address.MustLengthPrefix(checksum)
- creator = address.MustLengthPrefix(creator)
- labelBz := address.MustLengthPrefix([]byte(label))
- key := make([]byte, len(checksum)+len(creator)+len(labelBz))
- copy(key[0:], checksum)
- copy(key[len(checksum):], creator)
- copy(key[len(checksum)+len(creator):], labelBz)
- return address.Module(types.ModuleName, key)[:types.ContractAddrLen]
-}
-
func (k Keeper) autoIncrementID(ctx sdk.Context, lastIDKey []byte) uint64 {
store := ctx.KVStore(k.storeKey)
bz := store.Get(lastIDKey)
diff --git a/x/wasm/keeper/keeper_test.go b/x/wasm/keeper/keeper_test.go
index 5235141f..947edd27 100644
--- a/x/wasm/keeper/keeper_test.go
+++ b/x/wasm/keeper/keeper_test.go
@@ -3,12 +3,10 @@ package keeper
import (
"bytes"
_ "embed"
- "encoding/hex"
"encoding/json"
"errors"
"fmt"
"os"
- "strings"
"testing"
"time"
@@ -62,7 +60,7 @@ func TestCreateSuccess(t *testing.T) {
require.Equal(t, hackatomWasm, storedCode)
// and events emitted
codeHash := "13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a5"
- exp := sdk.Events{sdk.NewEvent("store_code", sdk.NewAttribute("code_id", "1"), sdk.NewAttribute("code_checksum", codeHash))}
+ exp := sdk.Events{sdk.NewEvent("store_code", sdk.NewAttribute("code_checksum", codeHash), sdk.NewAttribute("code_id", "1"))}
assert.Equal(t, exp, em.Events())
}
@@ -398,11 +396,11 @@ func TestInstantiate(t *testing.T) {
// create with no balance is also legal
gotContractAddr, _, err := keepers.ContractKeeper.Instantiate(ctx.WithEventManager(em), example.CodeID, creator, nil, initMsgBz, "demo contract 1", nil)
require.NoError(t, err)
- require.Equal(t, "cosmos1xaq0tcwz9fsqmtxlpzwjn2zr8gw66ljjr079ltfc5pelepcs7sjsk28n5n", gotContractAddr.String())
+ require.Equal(t, "cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr", gotContractAddr.String())
gasAfter := ctx.GasMeter().GasConsumed()
if types.EnableGasVerification {
- require.Equal(t, uint64(0x187b8), gasAfter-gasBefore)
+ require.Equal(t, uint64(0x1964f), gasAfter-gasBefore)
}
// ensure it is stored properly
@@ -541,65 +539,6 @@ func TestInstantiateWithPermissions(t *testing.T) {
}
}
-func TestInstantiateWithUniqueContractAddress(t *testing.T) {
- parentCtx, keepers := CreateTestInput(t, false, AvailableCapabilities)
- example := InstantiateHackatomExampleContract(t, parentCtx, keepers)
- otherExample := InstantiateReflectExampleContract(t, parentCtx, keepers)
- initMsg := mustMarshal(t, HackatomExampleInitMsg{Verifier: example.VerifierAddr, Beneficiary: example.BeneficiaryAddr})
-
- otherAddress := DeterministicAccountAddress(t, 1)
- keepers.Faucet.Fund(parentCtx, otherAddress, sdk.NewInt64Coin("denom", 100000000))
- used := make(map[string]struct{})
- specs := map[string]struct {
- codeID uint64
- sender sdk.AccAddress
- label string
- initMsg json.RawMessage
- expErr error
- }{
- "reject duplicate which generates the same address": {
- codeID: example.CodeID,
- sender: example.CreatorAddr,
- label: example.Label,
- initMsg: initMsg,
- expErr: types.ErrDuplicate,
- },
- "different sender": {
- codeID: example.CodeID,
- sender: otherAddress,
- label: example.Label,
- initMsg: initMsg,
- },
- "different code": {
- codeID: otherExample.CodeID,
- sender: example.CreatorAddr,
- label: example.Label,
- initMsg: []byte(`{}`),
- },
- "different label": {
- codeID: example.CodeID,
- sender: example.CreatorAddr,
- label: "other label",
- initMsg: initMsg,
- },
- }
- for name, spec := range specs {
- t.Run(name, func(t *testing.T) {
- ctx, _ := parentCtx.CacheContext()
- gotAddr, _, gotErr := keepers.ContractKeeper.Instantiate(ctx, spec.codeID, spec.sender, nil, spec.initMsg, spec.label, example.Deposit)
- if spec.expErr != nil {
- assert.ErrorIs(t, gotErr, spec.expErr)
- return
- }
- require.NoError(t, gotErr)
- expAddr := BuildContractAddress(keepers.WasmKeeper.GetCodeInfo(ctx, spec.codeID).CodeHash, spec.sender, spec.label)
- assert.Equal(t, expAddr.String(), gotAddr.String())
- require.NotContains(t, used, gotAddr.String())
- used[gotAddr.String()] = struct{}{}
- })
- }
-}
-
func TestInstantiateWithAccounts(t *testing.T) {
parentCtx, keepers := CreateTestInput(t, false, AvailableCapabilities)
example := StoreHackatomExampleContract(t, parentCtx, keepers)
@@ -609,12 +548,13 @@ func TestInstantiateWithAccounts(t *testing.T) {
senderAddr := DeterministicAccountAddress(t, 1)
keepers.Faucet.Fund(parentCtx, senderAddr, sdk.NewInt64Coin("denom", 100000000))
const myLabel = "testing"
- contractAddr := BuildContractAddress(example.Checksum, senderAddr, myLabel)
+ mySalt := []byte(`my salt`)
+ contractAddr := BuildContractAddressPredictable(example.Checksum, senderAddr, mySalt, []byte{})
lastAccountNumber := keepers.AccountKeeper.GetAccount(parentCtx, senderAddr).GetAccountNumber()
specs := map[string]struct {
- acceptList Option
+ option Option
account authtypes.AccountI
initBalance sdk.Coin
deposit sdk.Coins
@@ -679,7 +619,7 @@ func TestInstantiateWithAccounts(t *testing.T) {
expErr: types.ErrAccountExists,
},
"with option used to set non default type to accept list": {
- acceptList: WithAcceptedAccountTypesOnContractInstantiation(&vestingtypes.DelayedVestingAccount{}),
+ option: WithAcceptedAccountTypesOnContractInstantiation(&vestingtypes.DelayedVestingAccount{}),
account: vestingtypes.NewDelayedVestingAccount(
authtypes.NewBaseAccount(contractAddr, nil, 0, 0),
sdk.NewCoins(sdk.NewCoin("denom", sdk.NewInt(1_000))), time.Now().Add(30*time.Hour).Unix()),
@@ -689,6 +629,15 @@ func TestInstantiateWithAccounts(t *testing.T) {
sdk.NewCoins(sdk.NewCoin("denom", sdk.NewInt(1_000))), time.Now().Add(30*time.Hour).Unix()),
expBalance: sdk.NewCoins(sdk.NewCoin("denom", sdk.NewInt(1_001))),
},
+ "pruning account fails": {
+ option: WithAccountPruner(wasmtesting.AccountPrunerMock{CleanupExistingAccountFn: func(ctx sdk.Context, existingAccount authtypes.AccountI) (handled bool, err error) {
+ return false, types.ErrUnsupportedForContract.Wrap("testing")
+ }}),
+ account: vestingtypes.NewDelayedVestingAccount(
+ authtypes.NewBaseAccount(contractAddr, nil, 0, 0),
+ sdk.NewCoins(sdk.NewCoin("denom", sdk.NewInt(1_000))), time.Now().Add(30*time.Hour).Unix()),
+ expErr: types.ErrUnsupportedForContract,
+ },
}
for name, spec := range specs {
t.Run(name, func(t *testing.T) {
@@ -699,16 +648,17 @@ func TestInstantiateWithAccounts(t *testing.T) {
if !spec.initBalance.IsNil() {
keepers.Faucet.Fund(ctx, spec.account.GetAddress(), spec.initBalance)
}
- if spec.acceptList != nil {
- spec.acceptList.apply(keepers.WasmKeeper)
+ if spec.option != nil {
+ spec.option.apply(keepers.WasmKeeper)
}
defer func() {
- if spec.acceptList != nil { // reset
+ if spec.option != nil { // reset
WithAcceptedAccountTypesOnContractInstantiation(&authtypes.BaseAccount{}).apply(keepers.WasmKeeper)
+ WithAccountPruner(NewVestingCoinBurner(keepers.BankKeeper)).apply(keepers.WasmKeeper)
}
}()
// when
- gotAddr, _, gotErr := keepers.ContractKeeper.Instantiate(ctx, 1, senderAddr, nil, initMsg, myLabel, spec.deposit)
+ gotAddr, _, gotErr := keepers.ContractKeeper.Instantiate2(ctx, 1, senderAddr, nil, initMsg, myLabel, spec.deposit, mySalt, false)
if spec.expErr != nil {
assert.ErrorIs(t, gotErr, spec.expErr)
return
@@ -857,8 +807,7 @@ func TestExecute(t *testing.T) {
addr, _, err := keepers.ContractKeeper.Instantiate(ctx, contractID, creator, nil, initMsgBz, "demo contract 3", deposit)
require.NoError(t, err)
- // cosmos1eycfqpgtcp4gc9g24cvg6useyncxspq8qurv2z7cs0wzcgvmffaquzwe2e build with code-id 1, DeterministicAccountAddress(t, 1) and label `demo contract 3`
- require.Equal(t, "cosmos1eycfqpgtcp4gc9g24cvg6useyncxspq8qurv2z7cs0wzcgvmffaquzwe2e", addr.String())
+ require.Equal(t, "cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr", addr.String())
// ensure bob doesn't exist
bobAcct := accKeeper.GetAccount(ctx, bob)
@@ -1562,7 +1511,7 @@ func TestSudo(t *testing.T) {
require.NoError(t, err)
addr, _, err := keepers.ContractKeeper.Instantiate(ctx, contractID, creator, nil, initMsgBz, "demo contract 3", deposit)
require.NoError(t, err)
- require.Equal(t, "cosmos1eycfqpgtcp4gc9g24cvg6useyncxspq8qurv2z7cs0wzcgvmffaquzwe2e", addr.String())
+ require.Equal(t, "cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr", addr.String())
// the community is broke
_, _, community := keyPubAddr()
@@ -2077,104 +2026,6 @@ func TestQueryIsolation(t *testing.T) {
assert.Nil(t, ctx.KVStore(k.storeKey).Get([]byte(`set_in_query`)))
}
-func TestBuildContractAddress(t *testing.T) {
- x, y := sdk.GetConfig().GetBech32AccountAddrPrefix(), sdk.GetConfig().GetBech32AccountPubPrefix()
- t.Cleanup(func() {
- sdk.GetConfig().SetBech32PrefixForAccount(x, y)
- })
- sdk.GetConfig().SetBech32PrefixForAccount("purple", "purple")
-
- // test vectors from https://gist.github.com/webmaster128/e4d401d414bd0e7e6f70482f11877fbe
- specs := map[string]struct {
- checksum []byte
- label string
- creator string
- expAddress string
- }{
- "initial account addr example": {
- checksum: fromHex("13A1FC994CC6D1C81B746EE0C0FF6F90043875E0BF1D9BE6B7D779FC978DC2A5"),
- label: "instance 1",
- creator: "purple1nxvenxve42424242hwamhwamenxvenxvhxf2py",
- expAddress: "purple1jukvumwqfxapueg6un6rtmafxktcluzv70xc3edz2m5t3slgw49qrmhc03",
- },
- "account addr with different label": {
- checksum: fromHex("13A1FC994CC6D1C81B746EE0C0FF6F90043875E0BF1D9BE6B7D779FC978DC2A5"),
- label: "instance 2",
- creator: "purple1nxvenxve42424242hwamhwamenxvenxvhxf2py",
- expAddress: "purple1jpc2w2vu2t6k7u09p6v8e3w28ptnzvvt2snu5rytlj8qya27dq5sjkwm06",
- },
- "initial contract addr example": {
- checksum: fromHex("13A1FC994CC6D1C81B746EE0C0FF6F90043875E0BF1D9BE6B7D779FC978DC2A5"),
- label: "instance 1",
- creator: "purple1nxvenxve42424242hwamhwamenxvenxvmhwamhwaamhwamhwlllsatsy6m",
- expAddress: "purple1wde5zlcveuh79w37w5g244qu9xja3hgfulyfkjvkxvwvjzgd5l3qfraz3c",
- },
- "contract addr with different label": {
- checksum: fromHex("13A1FC994CC6D1C81B746EE0C0FF6F90043875E0BF1D9BE6B7D779FC978DC2A5"),
- label: "instance 2",
- creator: "purple1nxvenxve42424242hwamhwamenxvenxvmhwamhwaamhwamhwlllsatsy6m",
- expAddress: "purple1vae2kf0r3ehtq5q2jmfkg7wp4ckxwrw8dv4pvazz5nlzzu05lxzq878fa9",
- },
- "account addr with different checksum": {
- checksum: fromHex("1DA6C16DE2CBAF7AD8CBB66F0925BA33F5C278CB2491762D04658C1480EA229B"),
- label: "instance 1",
- creator: "purple1nxvenxve42424242hwamhwamenxvenxvhxf2py",
- expAddress: "purple1gmgvt9levtn52mpfal3gl5tv60f47zez3wgczrh5c9352sfm9crs47zt0k",
- },
- "account addr with different checksum and label": {
- checksum: fromHex("1DA6C16DE2CBAF7AD8CBB66F0925BA33F5C278CB2491762D04658C1480EA229B"),
- label: "instance 2",
- creator: "purple1nxvenxve42424242hwamhwamenxvenxvhxf2py",
- expAddress: "purple13jrcqxknt05rhdxmegjzjel666yay6fj3xvfp6445k7a9q2km4wqa7ss34",
- },
- "contract addr with different checksum": {
- checksum: fromHex("1DA6C16DE2CBAF7AD8CBB66F0925BA33F5C278CB2491762D04658C1480EA229B"),
- label: "instance 1",
- creator: "purple1nxvenxve42424242hwamhwamenxvenxvmhwamhwaamhwamhwlllsatsy6m",
- expAddress: "purple1lu0lf6wmqeuwtrx93ptzvf4l0dyyz2vz6s8h5y9cj42fvhsmracq49pww9",
- },
- "contract addr with different checksum and label": {
- checksum: fromHex("1DA6C16DE2CBAF7AD8CBB66F0925BA33F5C278CB2491762D04658C1480EA229B"),
- label: "instance 2",
- creator: "purple1nxvenxve42424242hwamhwamenxvenxvmhwamhwaamhwamhwlllsatsy6m",
- expAddress: "purple1zmerc8a9ml2au29rq3knuu35fktef3akceurckr6pf370n0wku7sw3c9mj",
- },
- // regression tests
- "min label size": {
- checksum: fromHex("13A1FC994CC6D1C81B746EE0C0FF6F90043875E0BF1D9BE6B7D779FC978DC2A5"),
- label: "x",
- creator: "purple1nxvenxve42424242hwamhwamenxvenxvhxf2py",
- expAddress: "purple16pc8gt824lmp3dh2sxvttj0ykcs02n5p3ldswhv3j7y853gghlfq7mqeh9",
- },
- "max label size": {
- checksum: fromHex("13A1FC994CC6D1C81B746EE0C0FF6F90043875E0BF1D9BE6B7D779FC978DC2A5"),
- label: strings.Repeat("x", types.MaxLabelSize),
- creator: "purple1nxvenxve42424242hwamhwamenxvenxvhxf2py",
- expAddress: "purple1prkdvjmvv4s3tnppfxmlpj259v9cplf3wws4qq9qd7w3s4yqzqeqem4759",
- },
- }
- for name, spec := range specs {
- t.Run(name, func(t *testing.T) {
- creatorAddr, err := sdk.AccAddressFromBech32(spec.creator)
- require.NoError(t, err)
-
- // when
- gotAddr := BuildContractAddress(spec.checksum, creatorAddr, spec.label)
-
- require.Equal(t, spec.expAddress, gotAddr.String())
- require.NoError(t, sdk.VerifyAddressFormat(gotAddr))
- })
- }
-}
-
-func fromHex(s string) []byte {
- r, err := hex.DecodeString(s)
- if err != nil {
- panic(err)
- }
- return r
-}
-
func TestSetAccessConfig(t *testing.T) {
parentCtx, keepers := CreateTestInput(t, false, AvailableCapabilities)
k := keepers.WasmKeeper
diff --git a/x/wasm/keeper/migrations.go b/x/wasm/keeper/migrations.go
deleted file mode 100644
index 4d218d50..00000000
--- a/x/wasm/keeper/migrations.go
+++ /dev/null
@@ -1,27 +0,0 @@
-package keeper
-
-import (
- sdk "github.com/cosmos/cosmos-sdk/types"
-
- "github.com/CosmWasm/wasmd/x/wasm/types"
-)
-
-// Migrator is a struct for handling in-place store migrations.
-type Migrator struct {
- keeper *Keeper
-}
-
-// NewMigrator returns a new Migrator.
-func NewMigrator(keeper *Keeper) Migrator {
- return Migrator{keeper: keeper}
-}
-
-var keyLastInstanceID = append(types.SequenceKeyPrefix, []byte("lastContractId")...)
-
-// Migrate1to2 migrates from version 1 to 2.
-// Remove the unused sequence for address generation
-func (m Migrator) Migrate1to2(ctx sdk.Context) error {
- store := ctx.KVStore(m.keeper.storeKey)
- store.Delete(keyLastInstanceID)
- return nil
-}
diff --git a/x/wasm/keeper/migrations_test.go b/x/wasm/keeper/migrations_test.go
deleted file mode 100644
index bc9110a3..00000000
--- a/x/wasm/keeper/migrations_test.go
+++ /dev/null
@@ -1,20 +0,0 @@
-package keeper
-
-import (
- "testing"
-
- sdk "github.com/cosmos/cosmos-sdk/types"
- "github.com/stretchr/testify/assert"
-)
-
-func TestMigrateV1ToV2(t *testing.T) {
- ctx, keepers := CreateTestInput(t, false, AvailableCapabilities)
- store := ctx.KVStore(keepers.WasmKeeper.storeKey)
- store.Set(keyLastInstanceID, sdk.Uint64ToBigEndian(100))
-
- // when
- NewMigrator(keepers.WasmKeeper).Migrate1to2(ctx)
-
- // then
- assert.False(t, store.Has(keyLastInstanceID))
-}
diff --git a/x/wasm/keeper/msg_server.go b/x/wasm/keeper/msg_server.go
index 8c2a592e..d3051f43 100644
--- a/x/wasm/keeper/msg_server.go
+++ b/x/wasm/keeper/msg_server.go
@@ -43,6 +43,7 @@ func (m msgServer) StoreCode(goCtx context.Context, msg *types.MsgStoreCode) (*t
}, nil
}
+// InstantiateContract instantiate a new contract with classic sequence based address generation
func (m msgServer) InstantiateContract(goCtx context.Context, msg *types.MsgInstantiateContract) (*types.MsgInstantiateContractResponse, error) {
ctx := sdk.UnwrapSDKContext(goCtx)
@@ -74,6 +75,37 @@ func (m msgServer) InstantiateContract(goCtx context.Context, msg *types.MsgInst
}, nil
}
+// InstantiateContract2 instantiate a new contract with predicatable address generated
+func (m msgServer) InstantiateContract2(goCtx context.Context, msg *types.MsgInstantiateContract2) (*types.MsgInstantiateContract2Response, error) {
+ ctx := sdk.UnwrapSDKContext(goCtx)
+
+ senderAddr, err := sdk.AccAddressFromBech32(msg.Sender)
+ if err != nil {
+ return nil, sdkerrors.Wrap(err, "sender")
+ }
+ var adminAddr sdk.AccAddress
+ if msg.Admin != "" {
+ if adminAddr, err = sdk.AccAddressFromBech32(msg.Admin); err != nil {
+ return nil, sdkerrors.Wrap(err, "admin")
+ }
+ }
+
+ ctx.EventManager().EmitEvent(sdk.NewEvent(
+ sdk.EventTypeMessage,
+ sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName),
+ sdk.NewAttribute(sdk.AttributeKeySender, msg.Sender),
+ ))
+ contractAddr, data, err := m.keeper.Instantiate2(ctx, msg.CodeID, senderAddr, adminAddr, msg.Msg, msg.Label, msg.Funds, msg.Salt, msg.FixMsg)
+ if err != nil {
+ return nil, err
+ }
+
+ return &types.MsgInstantiateContract2Response{
+ Address: contractAddr.String(),
+ Data: data,
+ }, nil
+}
+
func (m msgServer) ExecuteContract(goCtx context.Context, msg *types.MsgExecuteContract) (*types.MsgExecuteContractResponse, error) {
ctx := sdk.UnwrapSDKContext(goCtx)
senderAddr, err := sdk.AccAddressFromBech32(msg.Sender)
diff --git a/x/wasm/keeper/proposal_integration_test.go b/x/wasm/keeper/proposal_integration_test.go
index ace55269..5a0305a4 100644
--- a/x/wasm/keeper/proposal_integration_test.go
+++ b/x/wasm/keeper/proposal_integration_test.go
@@ -2,25 +2,21 @@ package keeper
import (
"bytes"
- "crypto/sha256"
"encoding/hex"
"encoding/json"
"errors"
"os"
"testing"
- "github.com/cosmos/cosmos-sdk/x/params/client/utils"
-
wasmvm "github.com/CosmWasm/wasmvm"
-
- "github.com/CosmWasm/wasmd/x/wasm/keeper/wasmtesting"
-
sdk "github.com/cosmos/cosmos-sdk/types"
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
+ "github.com/cosmos/cosmos-sdk/x/params/client/utils"
"github.com/cosmos/cosmos-sdk/x/params/types/proposal"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
+ "github.com/CosmWasm/wasmd/x/wasm/keeper/wasmtesting"
"github.com/CosmWasm/wasmd/x/wasm/types"
)
@@ -117,8 +113,9 @@ func TestInstantiateProposal(t *testing.T) {
require.NoError(t, err)
// then
- codeHash := keepers.WasmKeeper.GetCodeInfo(ctx, 1).CodeHash
- contractAddr := BuildContractAddress(codeHash, oneAddress, "testing")
+ contractAddr, err := sdk.AccAddressFromBech32("cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr")
+ require.NoError(t, err)
+
cInfo := wasmKeeper.GetContractInfo(ctx, contractAddr)
require.NotNil(t, cInfo)
assert.Equal(t, uint64(1), cInfo.CodeID)
@@ -188,8 +185,9 @@ func TestInstantiateProposal_NoAdmin(t *testing.T) {
require.NoError(t, err)
// then
- codeHash := keepers.WasmKeeper.GetCodeInfo(ctx, 1).CodeHash
- contractAddr := BuildContractAddress(codeHash, oneAddress, "testing")
+ contractAddr, err := sdk.AccAddressFromBech32("cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr")
+ require.NoError(t, err)
+
cInfo := wasmKeeper.GetContractInfo(ctx, contractAddr)
require.NotNil(t, cInfo)
assert.Equal(t, uint64(1), cInfo.CodeID)
@@ -230,7 +228,7 @@ func TestMigrateProposal(t *testing.T) {
var (
anyAddress = DeterministicAccountAddress(t, 1)
otherAddress = DeterministicAccountAddress(t, 2)
- contractAddr = BuildContractAddress(codeInfoFixture.CodeHash, RandomAccountAddress(t), "")
+ contractAddr = BuildContractAddressClassic(1, 1)
)
contractInfoFixture := types.ContractInfoFixture(func(c *types.ContractInfo) {
@@ -407,13 +405,12 @@ func TestSudoProposal(t *testing.T) {
}
func TestAdminProposals(t *testing.T) {
+ var (
+ otherAddress sdk.AccAddress = bytes.Repeat([]byte{0x2}, types.ContractAddrLen)
+ contractAddr = BuildContractAddressClassic(1, 1)
+ )
wasmCode, err := os.ReadFile("./testdata/hackatom.wasm")
require.NoError(t, err)
- var (
- otherAddress = DeterministicAccountAddress(t, 2)
- codeHash = sha256.Sum256(wasmCode)
- contractAddr = BuildContractAddress(codeHash[:], RandomAccountAddress(t), "")
- )
specs := map[string]struct {
state types.ContractInfo
diff --git a/x/wasm/keeper/querier_test.go b/x/wasm/keeper/querier_test.go
index 115eeb84..f4341d16 100644
--- a/x/wasm/keeper/querier_test.go
+++ b/x/wasm/keeper/querier_test.go
@@ -158,9 +158,8 @@ func TestQuerySmartContractState(t *testing.T) {
func TestQuerySmartContractPanics(t *testing.T) {
ctx, keepers := CreateTestInput(t, false, AvailableCapabilities)
- creator := RandomAccountAddress(t)
- contractAddr := BuildContractAddress([]byte("myCodeHash"), creator, "testing")
- keepers.WasmKeeper.storeCodeInfo(ctx, 1, types.CodeInfo{CodeHash: []byte("myCodeHash")})
+ contractAddr := BuildContractAddressClassic(1, 1)
+ keepers.WasmKeeper.storeCodeInfo(ctx, 1, types.CodeInfo{})
keepers.WasmKeeper.storeContractInfo(ctx, contractAddr, &types.ContractInfo{
CodeID: 1,
Created: types.NewAbsoluteTxPosition(ctx),
diff --git a/x/wasm/keeper/test_common.go b/x/wasm/keeper/test_common.go
index fff90af3..721a3278 100644
--- a/x/wasm/keeper/test_common.go
+++ b/x/wasm/keeper/test_common.go
@@ -9,20 +9,18 @@ import (
"testing"
"time"
- "github.com/cosmos/cosmos-sdk/x/auth/vesting"
-
- "github.com/cosmos/cosmos-sdk/types/address"
-
"github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/std"
"github.com/cosmos/cosmos-sdk/store"
sdk "github.com/cosmos/cosmos-sdk/types"
+ "github.com/cosmos/cosmos-sdk/types/address"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/types/module"
"github.com/cosmos/cosmos-sdk/x/auth"
authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
+ "github.com/cosmos/cosmos-sdk/x/auth/vesting"
authzkeeper "github.com/cosmos/cosmos-sdk/x/authz/keeper"
"github.com/cosmos/cosmos-sdk/x/bank"
bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper"
@@ -72,7 +70,6 @@ import (
dbm "github.com/tendermint/tm-db"
wasmappparams "github.com/CosmWasm/wasmd/app/params"
-
"github.com/CosmWasm/wasmd/x/wasm/keeper/wasmtesting"
"github.com/CosmWasm/wasmd/x/wasm/types"
)
diff --git a/x/wasm/keeper/wasmtesting/coin_transferrer.go b/x/wasm/keeper/wasmtesting/coin_transferrer.go
deleted file mode 100644
index 497ecc74..00000000
--- a/x/wasm/keeper/wasmtesting/coin_transferrer.go
+++ /dev/null
@@ -1,14 +0,0 @@
-package wasmtesting
-
-import sdk "github.com/cosmos/cosmos-sdk/types"
-
-type MockCoinTransferrer struct {
- TransferCoinsFn func(ctx sdk.Context, fromAddr sdk.AccAddress, toAddr sdk.AccAddress, amt sdk.Coins) error
-}
-
-func (m *MockCoinTransferrer) TransferCoins(ctx sdk.Context, fromAddr sdk.AccAddress, toAddr sdk.AccAddress, amt sdk.Coins) error {
- if m.TransferCoinsFn == nil {
- panic("not expected to be called")
- }
- return m.TransferCoinsFn(ctx, fromAddr, toAddr, amt)
-}
diff --git a/x/wasm/keeper/wasmtesting/extension_mocks.go b/x/wasm/keeper/wasmtesting/extension_mocks.go
new file mode 100644
index 00000000..562d9e74
--- /dev/null
+++ b/x/wasm/keeper/wasmtesting/extension_mocks.go
@@ -0,0 +1,28 @@
+package wasmtesting
+
+import (
+ sdk "github.com/cosmos/cosmos-sdk/types"
+ authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
+)
+
+type MockCoinTransferrer struct {
+ TransferCoinsFn func(ctx sdk.Context, fromAddr sdk.AccAddress, toAddr sdk.AccAddress, amt sdk.Coins) error
+}
+
+func (m *MockCoinTransferrer) TransferCoins(ctx sdk.Context, fromAddr sdk.AccAddress, toAddr sdk.AccAddress, amt sdk.Coins) error {
+ if m.TransferCoinsFn == nil {
+ panic("not expected to be called")
+ }
+ return m.TransferCoinsFn(ctx, fromAddr, toAddr, amt)
+}
+
+type AccountPrunerMock struct {
+ CleanupExistingAccountFn func(ctx sdk.Context, existingAccount authtypes.AccountI) (handled bool, err error)
+}
+
+func (m AccountPrunerMock) CleanupExistingAccount(ctx sdk.Context, existingAccount authtypes.AccountI) (handled bool, err error) {
+ if m.CleanupExistingAccountFn == nil {
+ panic("not expected to be called")
+ }
+ return m.CleanupExistingAccountFn(ctx, existingAccount)
+}
diff --git a/x/wasm/module.go b/x/wasm/module.go
index 2433fe02..c7ea6339 100644
--- a/x/wasm/module.go
+++ b/x/wasm/module.go
@@ -134,11 +134,6 @@ func NewAppModule(
func (am AppModule) RegisterServices(cfg module.Configurator) {
types.RegisterMsgServer(cfg.MsgServer(), keeper.NewMsgServerImpl(keeper.NewDefaultPermissionKeeper(am.keeper)))
types.RegisterQueryServer(cfg.QueryServer(), NewQuerier(am.keeper))
-
- m := keeper.NewMigrator(am.keeper)
- if err := cfg.RegisterMigration(types.ModuleName, 1, m.Migrate1to2); err != nil {
- panic(err)
- }
}
func (am AppModule) LegacyQuerierHandler(amino *codec.LegacyAmino) sdk.Querier { //nolint:staticcheck
diff --git a/x/wasm/module_test.go b/x/wasm/module_test.go
index d3530e5a..66591aba 100644
--- a/x/wasm/module_test.go
+++ b/x/wasm/module_test.go
@@ -7,11 +7,8 @@ import (
"os"
"testing"
- "github.com/cosmos/cosmos-sdk/types/address"
-
- "github.com/CosmWasm/wasmd/x/wasm/keeper/testdata"
-
sdk "github.com/cosmos/cosmos-sdk/types"
+ "github.com/cosmos/cosmos-sdk/types/address"
"github.com/cosmos/cosmos-sdk/types/module"
authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper"
bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper"
@@ -24,6 +21,7 @@ import (
"github.com/tendermint/tendermint/crypto/ed25519"
"github.com/CosmWasm/wasmd/x/wasm/keeper"
+ "github.com/CosmWasm/wasmd/x/wasm/keeper/testdata"
"github.com/CosmWasm/wasmd/x/wasm/types"
)
@@ -148,8 +146,7 @@ type state struct {
func TestHandleInstantiate(t *testing.T) {
data := setupTest(t)
- creator := sdk.AccAddress(bytes.Repeat([]byte{1}, address.Len))
- data.faucet.Fund(data.ctx, creator, sdk.NewInt64Coin("denom", 100000))
+ creator := data.faucet.NewFundedRandomAccount(data.ctx, sdk.NewInt64Coin("denom", 100000))
h := data.module.Route().Handler()
q := data.module.LegacyQuerierHandler(nil)
@@ -183,7 +180,7 @@ func TestHandleInstantiate(t *testing.T) {
require.NoError(t, err)
contractBech32Addr := parseInitResponse(t, res.Data)
- require.Equal(t, "cosmos1400ax8h2dxe8ch64sus5sczqdhwv28hpjkkaphpa83he4fhz6k4qcm9kul", contractBech32Addr)
+ require.Equal(t, "cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr", contractBech32Addr)
// this should be standard x/wasm init event, nothing from contract
require.Equal(t, 3, len(res.Events), prettyEvents(res.Events))
require.Equal(t, "message", res.Events[0].Type)
@@ -210,9 +207,7 @@ func TestHandleExecute(t *testing.T) {
deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000))
topUp := sdk.NewCoins(sdk.NewInt64Coin("denom", 5000))
- creator := sdk.AccAddress(bytes.Repeat([]byte{1}, address.Len))
- data.faucet.Fund(data.ctx, creator, sdk.NewInt64Coin("denom", 100000*2))
-
+ creator := data.faucet.NewFundedRandomAccount(data.ctx, deposit.Add(deposit...)...)
fred := data.faucet.NewFundedRandomAccount(data.ctx, topUp...)
h := data.module.Route().Handler()
@@ -244,7 +239,7 @@ func TestHandleExecute(t *testing.T) {
require.NoError(t, err)
contractBech32Addr := parseInitResponse(t, res.Data)
- require.Equal(t, "cosmos1400ax8h2dxe8ch64sus5sczqdhwv28hpjkkaphpa83he4fhz6k4qcm9kul", contractBech32Addr)
+ require.Equal(t, "cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr", contractBech32Addr)
// this should be standard x/wasm message event, init event, plus a bank send event (2), with no custom contract events
require.Equal(t, 6, len(res.Events), prettyEvents(res.Events))
require.Equal(t, "message", res.Events[0].Type)
@@ -377,7 +372,7 @@ func TestHandleExecuteEscrow(t *testing.T) {
res, err = h(data.ctx, &initCmd)
require.NoError(t, err)
contractBech32Addr := parseInitResponse(t, res.Data)
- require.Equal(t, "cosmos1400ax8h2dxe8ch64sus5sczqdhwv28hpjkkaphpa83he4fhz6k4qcm9kul", contractBech32Addr)
+ require.Equal(t, "cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr", contractBech32Addr)
handleMsg := map[string]interface{}{
"release": map[string]interface{}{},
diff --git a/x/wasm/types/codec.go b/x/wasm/types/codec.go
index e7e578b7..f1cd6f55 100644
--- a/x/wasm/types/codec.go
+++ b/x/wasm/types/codec.go
@@ -13,6 +13,7 @@ import (
func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { //nolint:staticcheck
cdc.RegisterConcrete(&MsgStoreCode{}, "wasm/MsgStoreCode", nil)
cdc.RegisterConcrete(&MsgInstantiateContract{}, "wasm/MsgInstantiateContract", nil)
+ cdc.RegisterConcrete(&MsgInstantiateContract2{}, "wasm/MsgInstantiateContract2", nil)
cdc.RegisterConcrete(&MsgExecuteContract{}, "wasm/MsgExecuteContract", nil)
cdc.RegisterConcrete(&MsgMigrateContract{}, "wasm/MsgMigrateContract", nil)
cdc.RegisterConcrete(&MsgUpdateAdmin{}, "wasm/MsgUpdateAdmin", nil)
@@ -35,6 +36,7 @@ func RegisterInterfaces(registry types.InterfaceRegistry) {
(*sdk.Msg)(nil),
&MsgStoreCode{},
&MsgInstantiateContract{},
+ &MsgInstantiateContract2{},
&MsgExecuteContract{},
&MsgMigrateContract{},
&MsgUpdateAdmin{},
diff --git a/x/wasm/types/exported_keepers.go b/x/wasm/types/exported_keepers.go
index df099579..e68df8ee 100644
--- a/x/wasm/types/exported_keepers.go
+++ b/x/wasm/types/exported_keepers.go
@@ -28,8 +28,27 @@ type ContractOpsKeeper interface {
// Create uploads and compiles a WASM contract, returning a short identifier for the contract
Create(ctx sdk.Context, creator sdk.AccAddress, wasmCode []byte, instantiateAccess *AccessConfig) (codeID uint64, checksum []byte, err error)
- // Instantiate creates an instance of a WASM contract
- Instantiate(ctx sdk.Context, codeID uint64, creator, admin sdk.AccAddress, initMsg []byte, label string, deposit sdk.Coins) (sdk.AccAddress, []byte, error)
+ // Instantiate creates an instance of a WASM contract using the classic sequence based address generator
+ Instantiate(
+ ctx sdk.Context,
+ codeID uint64,
+ creator, admin sdk.AccAddress,
+ initMsg []byte,
+ label string,
+ deposit sdk.Coins,
+ ) (sdk.AccAddress, []byte, error)
+
+ // Instantiate2 creates an instance of a WASM contract using the predictable address generator
+ Instantiate2(
+ ctx sdk.Context,
+ codeID uint64,
+ creator, admin sdk.AccAddress,
+ initMsg []byte,
+ label string,
+ deposit sdk.Coins,
+ salt []byte,
+ fixMsg bool,
+ ) (sdk.AccAddress, []byte, error)
// Execute executes the contract instance
Execute(ctx sdk.Context, contractAddress sdk.AccAddress, caller sdk.AccAddress, msg []byte, coins sdk.Coins) ([]byte, error)
diff --git a/x/wasm/types/keys.go b/x/wasm/types/keys.go
index 9660360c..fb636ef4 100644
--- a/x/wasm/types/keys.go
+++ b/x/wasm/types/keys.go
@@ -32,7 +32,8 @@ var (
PinnedCodeIndexPrefix = []byte{0x07}
TXCounterPrefix = []byte{0x08}
- KeyLastCodeID = append(SequenceKeyPrefix, []byte("lastCodeId")...)
+ KeyLastCodeID = append(SequenceKeyPrefix, []byte("lastCodeId")...)
+ KeyLastInstanceID = append(SequenceKeyPrefix, []byte("lastContractId")...)
)
// GetCodeKey constructs the key for retreiving the ID for the WASM code
diff --git a/x/wasm/types/tx.go b/x/wasm/types/tx.go
index 0c83018d..9630777f 100644
--- a/x/wasm/types/tx.go
+++ b/x/wasm/types/tx.go
@@ -306,3 +306,56 @@ func (msg MsgIBCCloseChannel) GetSignBytes() []byte {
func (msg MsgIBCCloseChannel) GetSigners() []sdk.AccAddress {
return nil
}
+
+var _ sdk.Msg = &MsgInstantiateContract2{}
+
+func (msg MsgInstantiateContract2) Route() string {
+ return RouterKey
+}
+
+func (msg MsgInstantiateContract2) Type() string {
+ return "instantiate2"
+}
+
+func (msg MsgInstantiateContract2) ValidateBasic() error {
+ if _, err := sdk.AccAddressFromBech32(msg.Sender); err != nil {
+ return sdkerrors.Wrap(err, "sender")
+ }
+
+ if msg.CodeID == 0 {
+ return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "code id is required")
+ }
+
+ if err := ValidateLabel(msg.Label); err != nil {
+ return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "label is required")
+ }
+
+ if !msg.Funds.IsValid() {
+ return sdkerrors.ErrInvalidCoins
+ }
+
+ if len(msg.Admin) != 0 {
+ if _, err := sdk.AccAddressFromBech32(msg.Admin); err != nil {
+ return sdkerrors.Wrap(err, "admin")
+ }
+ }
+ if err := msg.Msg.ValidateBasic(); err != nil {
+ return sdkerrors.Wrap(err, "payload msg")
+ }
+ if err := ValidateSalt(msg.Salt); err != nil {
+ return sdkerrors.Wrap(err, "salt")
+ }
+ return nil
+}
+
+func (msg MsgInstantiateContract2) GetSignBytes() []byte {
+ return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(&msg))
+}
+
+func (msg MsgInstantiateContract2) GetSigners() []sdk.AccAddress {
+ senderAddr, err := sdk.AccAddressFromBech32(msg.Sender)
+ if err != nil { // should never happen as valid basic rejects invalid addresses
+ panic(err.Error())
+ }
+ return []sdk.AccAddress{senderAddr}
+}
diff --git a/x/wasm/types/tx.pb.go b/x/wasm/types/tx.pb.go
index 52d5098d..cf90465b 100644
--- a/x/wasm/types/tx.pb.go
+++ b/x/wasm/types/tx.pb.go
@@ -184,11 +184,71 @@ func (m *MsgInstantiateContract) XXX_DiscardUnknown() {
var xxx_messageInfo_MsgInstantiateContract proto.InternalMessageInfo
+// MsgInstantiateContract2 create a new smart contract instance for the given
+// code id with a predicable address.
+type MsgInstantiateContract2 struct {
+ // Sender is the that actor that signed the messages
+ Sender string `protobuf:"bytes,1,opt,name=sender,proto3" json:"sender,omitempty"`
+ // Admin is an optional address that can execute migrations
+ Admin string `protobuf:"bytes,2,opt,name=admin,proto3" json:"admin,omitempty"`
+ // CodeID is the reference to the stored WASM code
+ CodeID uint64 `protobuf:"varint,3,opt,name=code_id,json=codeId,proto3" json:"code_id,omitempty"`
+ // Label is optional metadata to be stored with a contract instance.
+ Label string `protobuf:"bytes,4,opt,name=label,proto3" json:"label,omitempty"`
+ // Msg json encoded message to be passed to the contract on instantiation
+ Msg RawContractMessage `protobuf:"bytes,5,opt,name=msg,proto3,casttype=RawContractMessage" json:"msg,omitempty"`
+ // Funds coins that are transferred to the contract on instantiation
+ Funds github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,6,rep,name=funds,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"funds"`
+ // Salt is an arbitrary value provided by the sender. Size can be 1 to 64.
+ Salt []byte `protobuf:"bytes,7,opt,name=salt,proto3" json:"salt,omitempty"`
+ // FixMsg include the msg value into the hash for the predictable address.
+ // Default is false
+ FixMsg bool `protobuf:"varint,8,opt,name=fix_msg,json=fixMsg,proto3" json:"fix_msg,omitempty"`
+}
+
+func (m *MsgInstantiateContract2) Reset() { *m = MsgInstantiateContract2{} }
+func (m *MsgInstantiateContract2) String() string { return proto.CompactTextString(m) }
+func (*MsgInstantiateContract2) ProtoMessage() {}
+func (*MsgInstantiateContract2) Descriptor() ([]byte, []int) {
+ return fileDescriptor_4f74d82755520264, []int{3}
+}
+
+func (m *MsgInstantiateContract2) XXX_Unmarshal(b []byte) error {
+ return m.Unmarshal(b)
+}
+
+func (m *MsgInstantiateContract2) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ if deterministic {
+ return xxx_messageInfo_MsgInstantiateContract2.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 *MsgInstantiateContract2) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_MsgInstantiateContract2.Merge(m, src)
+}
+
+func (m *MsgInstantiateContract2) XXX_Size() int {
+ return m.Size()
+}
+
+func (m *MsgInstantiateContract2) XXX_DiscardUnknown() {
+ xxx_messageInfo_MsgInstantiateContract2.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_MsgInstantiateContract2 proto.InternalMessageInfo
+
// MsgInstantiateContractResponse return instantiation result data
type MsgInstantiateContractResponse struct {
// Address is the bech32 address of the new contract instance.
Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"`
- // Data contains base64-encoded bytes to returned from the contract
+ // Data contains bytes to returned from the contract
Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"`
}
@@ -196,7 +256,7 @@ func (m *MsgInstantiateContractResponse) Reset() { *m = MsgInstantiateCo
func (m *MsgInstantiateContractResponse) String() string { return proto.CompactTextString(m) }
func (*MsgInstantiateContractResponse) ProtoMessage() {}
func (*MsgInstantiateContractResponse) Descriptor() ([]byte, []int) {
- return fileDescriptor_4f74d82755520264, []int{3}
+ return fileDescriptor_4f74d82755520264, []int{4}
}
func (m *MsgInstantiateContractResponse) XXX_Unmarshal(b []byte) error {
@@ -230,6 +290,52 @@ func (m *MsgInstantiateContractResponse) XXX_DiscardUnknown() {
var xxx_messageInfo_MsgInstantiateContractResponse proto.InternalMessageInfo
+// MsgInstantiateContract2Response return instantiation result data
+type MsgInstantiateContract2Response struct {
+ // Address is the bech32 address of the new contract instance.
+ Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"`
+ // Data contains bytes to returned from the contract
+ Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"`
+}
+
+func (m *MsgInstantiateContract2Response) Reset() { *m = MsgInstantiateContract2Response{} }
+func (m *MsgInstantiateContract2Response) String() string { return proto.CompactTextString(m) }
+func (*MsgInstantiateContract2Response) ProtoMessage() {}
+func (*MsgInstantiateContract2Response) Descriptor() ([]byte, []int) {
+ return fileDescriptor_4f74d82755520264, []int{5}
+}
+
+func (m *MsgInstantiateContract2Response) XXX_Unmarshal(b []byte) error {
+ return m.Unmarshal(b)
+}
+
+func (m *MsgInstantiateContract2Response) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ if deterministic {
+ return xxx_messageInfo_MsgInstantiateContract2Response.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 *MsgInstantiateContract2Response) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_MsgInstantiateContract2Response.Merge(m, src)
+}
+
+func (m *MsgInstantiateContract2Response) XXX_Size() int {
+ return m.Size()
+}
+
+func (m *MsgInstantiateContract2Response) XXX_DiscardUnknown() {
+ xxx_messageInfo_MsgInstantiateContract2Response.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_MsgInstantiateContract2Response proto.InternalMessageInfo
+
// MsgExecuteContract submits the given message data to a smart contract
type MsgExecuteContract struct {
// Sender is the that actor that signed the messages
@@ -246,7 +352,7 @@ func (m *MsgExecuteContract) Reset() { *m = MsgExecuteContract{} }
func (m *MsgExecuteContract) String() string { return proto.CompactTextString(m) }
func (*MsgExecuteContract) ProtoMessage() {}
func (*MsgExecuteContract) Descriptor() ([]byte, []int) {
- return fileDescriptor_4f74d82755520264, []int{4}
+ return fileDescriptor_4f74d82755520264, []int{6}
}
func (m *MsgExecuteContract) XXX_Unmarshal(b []byte) error {
@@ -282,7 +388,7 @@ var xxx_messageInfo_MsgExecuteContract proto.InternalMessageInfo
// MsgExecuteContractResponse returns execution result data.
type MsgExecuteContractResponse struct {
- // Data contains base64-encoded bytes to returned from the contract
+ // Data contains bytes to returned from the contract
Data []byte `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"`
}
@@ -290,7 +396,7 @@ func (m *MsgExecuteContractResponse) Reset() { *m = MsgExecuteContractRe
func (m *MsgExecuteContractResponse) String() string { return proto.CompactTextString(m) }
func (*MsgExecuteContractResponse) ProtoMessage() {}
func (*MsgExecuteContractResponse) Descriptor() ([]byte, []int) {
- return fileDescriptor_4f74d82755520264, []int{5}
+ return fileDescriptor_4f74d82755520264, []int{7}
}
func (m *MsgExecuteContractResponse) XXX_Unmarshal(b []byte) error {
@@ -340,7 +446,7 @@ func (m *MsgMigrateContract) Reset() { *m = MsgMigrateContract{} }
func (m *MsgMigrateContract) String() string { return proto.CompactTextString(m) }
func (*MsgMigrateContract) ProtoMessage() {}
func (*MsgMigrateContract) Descriptor() ([]byte, []int) {
- return fileDescriptor_4f74d82755520264, []int{6}
+ return fileDescriptor_4f74d82755520264, []int{8}
}
func (m *MsgMigrateContract) XXX_Unmarshal(b []byte) error {
@@ -385,7 +491,7 @@ func (m *MsgMigrateContractResponse) Reset() { *m = MsgMigrateContractRe
func (m *MsgMigrateContractResponse) String() string { return proto.CompactTextString(m) }
func (*MsgMigrateContractResponse) ProtoMessage() {}
func (*MsgMigrateContractResponse) Descriptor() ([]byte, []int) {
- return fileDescriptor_4f74d82755520264, []int{7}
+ return fileDescriptor_4f74d82755520264, []int{9}
}
func (m *MsgMigrateContractResponse) XXX_Unmarshal(b []byte) error {
@@ -433,7 +539,7 @@ func (m *MsgUpdateAdmin) Reset() { *m = MsgUpdateAdmin{} }
func (m *MsgUpdateAdmin) String() string { return proto.CompactTextString(m) }
func (*MsgUpdateAdmin) ProtoMessage() {}
func (*MsgUpdateAdmin) Descriptor() ([]byte, []int) {
- return fileDescriptor_4f74d82755520264, []int{8}
+ return fileDescriptor_4f74d82755520264, []int{10}
}
func (m *MsgUpdateAdmin) XXX_Unmarshal(b []byte) error {
@@ -474,7 +580,7 @@ func (m *MsgUpdateAdminResponse) Reset() { *m = MsgUpdateAdminResponse{}
func (m *MsgUpdateAdminResponse) String() string { return proto.CompactTextString(m) }
func (*MsgUpdateAdminResponse) ProtoMessage() {}
func (*MsgUpdateAdminResponse) Descriptor() ([]byte, []int) {
- return fileDescriptor_4f74d82755520264, []int{9}
+ return fileDescriptor_4f74d82755520264, []int{11}
}
func (m *MsgUpdateAdminResponse) XXX_Unmarshal(b []byte) error {
@@ -520,7 +626,7 @@ func (m *MsgClearAdmin) Reset() { *m = MsgClearAdmin{} }
func (m *MsgClearAdmin) String() string { return proto.CompactTextString(m) }
func (*MsgClearAdmin) ProtoMessage() {}
func (*MsgClearAdmin) Descriptor() ([]byte, []int) {
- return fileDescriptor_4f74d82755520264, []int{10}
+ return fileDescriptor_4f74d82755520264, []int{12}
}
func (m *MsgClearAdmin) XXX_Unmarshal(b []byte) error {
@@ -561,7 +667,7 @@ func (m *MsgClearAdminResponse) Reset() { *m = MsgClearAdminResponse{} }
func (m *MsgClearAdminResponse) String() string { return proto.CompactTextString(m) }
func (*MsgClearAdminResponse) ProtoMessage() {}
func (*MsgClearAdminResponse) Descriptor() ([]byte, []int) {
- return fileDescriptor_4f74d82755520264, []int{11}
+ return fileDescriptor_4f74d82755520264, []int{13}
}
func (m *MsgClearAdminResponse) XXX_Unmarshal(b []byte) error {
@@ -599,7 +705,9 @@ func init() {
proto.RegisterType((*MsgStoreCode)(nil), "cosmwasm.wasm.v1.MsgStoreCode")
proto.RegisterType((*MsgStoreCodeResponse)(nil), "cosmwasm.wasm.v1.MsgStoreCodeResponse")
proto.RegisterType((*MsgInstantiateContract)(nil), "cosmwasm.wasm.v1.MsgInstantiateContract")
+ proto.RegisterType((*MsgInstantiateContract2)(nil), "cosmwasm.wasm.v1.MsgInstantiateContract2")
proto.RegisterType((*MsgInstantiateContractResponse)(nil), "cosmwasm.wasm.v1.MsgInstantiateContractResponse")
+ proto.RegisterType((*MsgInstantiateContract2Response)(nil), "cosmwasm.wasm.v1.MsgInstantiateContract2Response")
proto.RegisterType((*MsgExecuteContract)(nil), "cosmwasm.wasm.v1.MsgExecuteContract")
proto.RegisterType((*MsgExecuteContractResponse)(nil), "cosmwasm.wasm.v1.MsgExecuteContractResponse")
proto.RegisterType((*MsgMigrateContract)(nil), "cosmwasm.wasm.v1.MsgMigrateContract")
@@ -613,55 +721,60 @@ func init() {
func init() { proto.RegisterFile("cosmwasm/wasm/v1/tx.proto", fileDescriptor_4f74d82755520264) }
var fileDescriptor_4f74d82755520264 = []byte{
- // 766 bytes of a gzipped FileDescriptorProto
- 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x55, 0xcb, 0x6e, 0xd3, 0x40,
- 0x14, 0x8d, 0x1b, 0x27, 0x4d, 0x6e, 0x43, 0x89, 0x4c, 0x1a, 0x52, 0x83, 0x9c, 0x28, 0xa0, 0xe2,
- 0x05, 0xd8, 0x4d, 0x91, 0xd8, 0x37, 0x29, 0x8b, 0x56, 0x32, 0x42, 0xae, 0x4a, 0x05, 0x9b, 0x68,
- 0x62, 0x4f, 0x5d, 0xab, 0xb5, 0x27, 0x78, 0x9c, 0xa6, 0xfd, 0x09, 0xc4, 0x8e, 0x7f, 0xe0, 0x2f,
- 0xd8, 0x75, 0x85, 0xba, 0x41, 0x62, 0x15, 0x20, 0xfd, 0x0b, 0x56, 0xc8, 0xcf, 0xba, 0xa9, 0x93,
- 0x06, 0x21, 0x36, 0xce, 0xdc, 0x99, 0x73, 0x5f, 0x27, 0x67, 0xee, 0xc0, 0xaa, 0x46, 0xa8, 0x35,
- 0x44, 0xd4, 0x92, 0xfd, 0xcf, 0x49, 0x4b, 0x76, 0x4f, 0xa5, 0xbe, 0x43, 0x5c, 0xc2, 0x95, 0xa3,
- 0x23, 0xc9, 0xff, 0x9c, 0xb4, 0x78, 0xc1, 0xdb, 0x21, 0x54, 0xee, 0x21, 0x8a, 0xe5, 0x93, 0x56,
- 0x0f, 0xbb, 0xa8, 0x25, 0x6b, 0xc4, 0xb4, 0x03, 0x0f, 0xbe, 0x62, 0x10, 0x83, 0xf8, 0x4b, 0xd9,
- 0x5b, 0x85, 0xbb, 0x0f, 0x6f, 0xa6, 0x38, 0xeb, 0x63, 0x1a, 0x9c, 0x36, 0xbf, 0x30, 0x50, 0x52,
- 0xa8, 0xb1, 0xeb, 0x12, 0x07, 0x77, 0x88, 0x8e, 0xb9, 0x2a, 0xe4, 0x29, 0xb6, 0x75, 0xec, 0xd4,
- 0x98, 0x06, 0x23, 0x16, 0xd5, 0xd0, 0xe2, 0x5e, 0xc0, 0xb2, 0xe7, 0xdf, 0xed, 0x9d, 0xb9, 0xb8,
- 0xab, 0x11, 0x1d, 0xd7, 0x16, 0x1a, 0x8c, 0x58, 0x6a, 0x97, 0xc7, 0xa3, 0x7a, 0x69, 0x7f, 0x73,
- 0x57, 0x69, 0x9f, 0xb9, 0x7e, 0x04, 0xb5, 0xe4, 0xe1, 0x22, 0x8b, 0xdb, 0x83, 0xaa, 0x69, 0x53,
- 0x17, 0xd9, 0xae, 0x89, 0x5c, 0xdc, 0xed, 0x63, 0xc7, 0x32, 0x29, 0x35, 0x89, 0x5d, 0xcb, 0x35,
- 0x18, 0x71, 0x69, 0x43, 0x90, 0x26, 0xfb, 0x94, 0x36, 0x35, 0x0d, 0x53, 0xda, 0x21, 0xf6, 0x81,
- 0x69, 0xa8, 0x2b, 0x09, 0xef, 0xd7, 0xb1, 0xf3, 0x0e, 0x5b, 0xc8, 0x96, 0xd9, 0x1d, 0xb6, 0xc0,
- 0x96, 0x73, 0xcd, 0x7d, 0xa8, 0x24, 0x5b, 0x50, 0x31, 0xed, 0x13, 0x9b, 0x62, 0xee, 0x11, 0x2c,
- 0x7a, 0x85, 0x76, 0x4d, 0xdd, 0xef, 0x85, 0x6d, 0xc3, 0x78, 0x54, 0xcf, 0x7b, 0x90, 0xed, 0x2d,
- 0x35, 0xef, 0x1d, 0x6d, 0xeb, 0x1c, 0x0f, 0x05, 0xed, 0x10, 0x6b, 0x47, 0x74, 0x60, 0x05, 0x1d,
- 0xa9, 0xb1, 0xdd, 0xfc, 0xb0, 0x00, 0x55, 0x85, 0x1a, 0xdb, 0x57, 0x15, 0x74, 0x88, 0xed, 0x3a,
- 0x48, 0x73, 0xa7, 0xd2, 0x54, 0x81, 0x1c, 0xd2, 0x2d, 0xd3, 0xf6, 0x63, 0x15, 0xd5, 0xc0, 0x48,
- 0x56, 0x92, 0x9d, 0x5a, 0x49, 0x05, 0x72, 0xc7, 0xa8, 0x87, 0x8f, 0x6b, 0x6c, 0xe0, 0xea, 0x1b,
- 0x9c, 0x08, 0x59, 0x8b, 0x1a, 0x3e, 0x59, 0xa5, 0x76, 0xf5, 0xf7, 0xa8, 0xce, 0xa9, 0x68, 0x18,
- 0x95, 0xa1, 0x60, 0x4a, 0x91, 0x81, 0x55, 0x0f, 0xc2, 0x21, 0xc8, 0x1d, 0x0c, 0x6c, 0x9d, 0xd6,
- 0xf2, 0x8d, 0xac, 0xb8, 0xb4, 0xb1, 0x2a, 0x05, 0x72, 0x91, 0x3c, 0xb9, 0x48, 0xa1, 0x5c, 0xa4,
- 0x0e, 0x31, 0xed, 0xf6, 0xfa, 0xf9, 0xa8, 0x9e, 0xf9, 0xfc, 0xa3, 0x2e, 0x1a, 0xa6, 0x7b, 0x38,
- 0xe8, 0x49, 0x1a, 0xb1, 0xe4, 0x50, 0x5b, 0xc1, 0xcf, 0x33, 0xaa, 0x1f, 0x85, 0x32, 0xf1, 0x1c,
- 0xa8, 0x1a, 0x44, 0x6e, 0xbe, 0x02, 0x21, 0x9d, 0x8f, 0x98, 0xf3, 0x1a, 0x2c, 0x22, 0x5d, 0x77,
- 0x30, 0xa5, 0x21, 0x31, 0x91, 0xc9, 0x71, 0xc0, 0xea, 0xc8, 0x45, 0x21, 0xc9, 0xfe, 0xba, 0xf9,
- 0x8d, 0x01, 0x4e, 0xa1, 0xc6, 0xcb, 0x53, 0xac, 0x0d, 0xe6, 0x20, 0xd7, 0xfb, 0xaf, 0x42, 0x4c,
- 0xc8, 0x6f, 0x6c, 0x47, 0x3c, 0x65, 0xff, 0x82, 0xa7, 0xdc, 0x7f, 0xe3, 0x69, 0x1d, 0xf8, 0x9b,
- 0x6d, 0xc5, 0x1c, 0x45, 0x4c, 0x30, 0x09, 0x26, 0x3e, 0x05, 0x4c, 0x28, 0xa6, 0xe1, 0xa0, 0x7f,
- 0x64, 0x62, 0x2e, 0xb1, 0x85, 0x74, 0xb1, 0xb7, 0xd2, 0x15, 0xf6, 0x32, 0x51, 0xd8, 0xcc, 0x5e,
- 0x10, 0x2c, 0x2b, 0xd4, 0xd8, 0xeb, 0xeb, 0xc8, 0xc5, 0x9b, 0xbe, 0xfe, 0xa7, 0xb5, 0xf1, 0x00,
- 0x8a, 0x36, 0x1e, 0x76, 0x93, 0x37, 0xa6, 0x60, 0xe3, 0x61, 0xe0, 0x94, 0xec, 0x31, 0x7b, 0xbd,
- 0xc7, 0x66, 0xcd, 0xbf, 0x98, 0x89, 0x14, 0x51, 0x41, 0xcd, 0x0e, 0xdc, 0x51, 0xa8, 0xd1, 0x39,
- 0xc6, 0xc8, 0x99, 0x9d, 0x7b, 0x56, 0xf8, 0xfb, 0xb0, 0x72, 0x2d, 0x48, 0x14, 0x7d, 0xe3, 0x2b,
- 0x0b, 0x59, 0x85, 0x1a, 0xdc, 0x2e, 0x14, 0xaf, 0x46, 0x66, 0xca, 0x08, 0x4b, 0xce, 0x23, 0x7e,
- 0x6d, 0xf6, 0x79, 0xcc, 0xe5, 0x7b, 0xb8, 0x97, 0x36, 0x6a, 0xc4, 0x54, 0xf7, 0x14, 0x24, 0xbf,
- 0x3e, 0x2f, 0x32, 0x4e, 0x89, 0xe1, 0xee, 0xe4, 0xe5, 0x7b, 0x9c, 0x1a, 0x64, 0x02, 0xc5, 0x3f,
- 0x9d, 0x07, 0x95, 0x4c, 0x33, 0xa9, 0xec, 0xf4, 0x34, 0x13, 0xa8, 0x29, 0x69, 0xa6, 0x89, 0xf1,
- 0x2d, 0x2c, 0x25, 0x55, 0xd7, 0x48, 0x75, 0x4e, 0x20, 0x78, 0xf1, 0x36, 0x44, 0x1c, 0xfa, 0x0d,
- 0x40, 0x42, 0x53, 0xf5, 0x54, 0xbf, 0x2b, 0x00, 0xff, 0xe4, 0x16, 0x40, 0x14, 0xb7, 0xbd, 0x75,
- 0xfe, 0x4b, 0xc8, 0x9c, 0x8f, 0x05, 0xe6, 0x62, 0x2c, 0x30, 0x3f, 0xc7, 0x02, 0xf3, 0xf1, 0x52,
- 0xc8, 0x5c, 0x5c, 0x0a, 0x99, 0xef, 0x97, 0x42, 0xe6, 0xdd, 0x5a, 0x62, 0xf0, 0x74, 0x08, 0xb5,
- 0xf6, 0xa3, 0x67, 0x5c, 0x97, 0x4f, 0x83, 0xe7, 0xdc, 0x1f, 0x3e, 0xbd, 0xbc, 0xff, 0x98, 0x3f,
- 0xff, 0x13, 0x00, 0x00, 0xff, 0xff, 0xef, 0x6b, 0xa0, 0xa3, 0x4f, 0x08, 0x00, 0x00,
+ // 840 bytes of a gzipped FileDescriptorProto
+ 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe4, 0x56, 0x4d, 0x6f, 0xe3, 0x44,
+ 0x18, 0x8e, 0x1b, 0xe7, 0xeb, 0x6d, 0x58, 0x22, 0x93, 0x4d, 0xbd, 0x06, 0x39, 0x91, 0x41, 0x8b,
+ 0x91, 0xc0, 0x6e, 0x82, 0xc4, 0xbd, 0xc9, 0x72, 0xe8, 0x4a, 0x06, 0xe4, 0x6a, 0xa9, 0xe0, 0x12,
+ 0x4d, 0xec, 0x89, 0xd7, 0xda, 0xd8, 0x13, 0x3c, 0x93, 0x26, 0xfd, 0x13, 0x88, 0x1b, 0xff, 0x81,
+ 0xdf, 0xc0, 0x05, 0x89, 0x43, 0x8f, 0x7b, 0x41, 0xe2, 0x14, 0x20, 0xfd, 0x17, 0x9c, 0x90, 0x3f,
+ 0xeb, 0xcd, 0x3a, 0x69, 0x00, 0x71, 0xe2, 0x92, 0xcc, 0xeb, 0x79, 0xde, 0xaf, 0x67, 0x9e, 0x77,
+ 0x6c, 0x78, 0x64, 0x11, 0xea, 0x2d, 0x11, 0xf5, 0xf4, 0xe8, 0xe7, 0xaa, 0xaf, 0xb3, 0x95, 0x36,
+ 0x0f, 0x08, 0x23, 0x42, 0x2b, 0xdd, 0xd2, 0xa2, 0x9f, 0xab, 0xbe, 0x24, 0x87, 0x4f, 0x08, 0xd5,
+ 0x27, 0x88, 0x62, 0xfd, 0xaa, 0x3f, 0xc1, 0x0c, 0xf5, 0x75, 0x8b, 0xb8, 0x7e, 0xec, 0x21, 0xb5,
+ 0x1d, 0xe2, 0x90, 0x68, 0xa9, 0x87, 0xab, 0xe4, 0xe9, 0x3b, 0xaf, 0xa7, 0xb8, 0x9e, 0x63, 0x1a,
+ 0xef, 0x2a, 0x3f, 0x71, 0xd0, 0x34, 0xa8, 0x73, 0xc1, 0x48, 0x80, 0x47, 0xc4, 0xc6, 0x42, 0x07,
+ 0xaa, 0x14, 0xfb, 0x36, 0x0e, 0x44, 0xae, 0xc7, 0xa9, 0x0d, 0x33, 0xb1, 0x84, 0x4f, 0xe0, 0x41,
+ 0xe8, 0x3f, 0x9e, 0x5c, 0x33, 0x3c, 0xb6, 0x88, 0x8d, 0xc5, 0xa3, 0x1e, 0xa7, 0x36, 0x87, 0xad,
+ 0xcd, 0xba, 0xdb, 0xbc, 0x3c, 0xbb, 0x30, 0x86, 0xd7, 0x2c, 0x8a, 0x60, 0x36, 0x43, 0x5c, 0x6a,
+ 0x09, 0xcf, 0xa0, 0xe3, 0xfa, 0x94, 0x21, 0x9f, 0xb9, 0x88, 0xe1, 0xf1, 0x1c, 0x07, 0x9e, 0x4b,
+ 0xa9, 0x4b, 0x7c, 0xb1, 0xd2, 0xe3, 0xd4, 0xe3, 0x81, 0xac, 0x6d, 0xf7, 0xa9, 0x9d, 0x59, 0x16,
+ 0xa6, 0x74, 0x44, 0xfc, 0xa9, 0xeb, 0x98, 0x0f, 0x73, 0xde, 0x5f, 0x64, 0xce, 0x4f, 0xf9, 0x7a,
+ 0xb9, 0xc5, 0x3f, 0xe5, 0xeb, 0x7c, 0xab, 0xa2, 0x5c, 0x42, 0x3b, 0xdf, 0x82, 0x89, 0xe9, 0x9c,
+ 0xf8, 0x14, 0x0b, 0xef, 0x42, 0x2d, 0x2c, 0x74, 0xec, 0xda, 0x51, 0x2f, 0xfc, 0x10, 0x36, 0xeb,
+ 0x6e, 0x35, 0x84, 0x9c, 0x3f, 0x31, 0xab, 0xe1, 0xd6, 0xb9, 0x2d, 0x48, 0x50, 0xb7, 0x9e, 0x63,
+ 0xeb, 0x05, 0x5d, 0x78, 0x71, 0x47, 0x66, 0x66, 0x2b, 0xdf, 0x1e, 0x41, 0xc7, 0xa0, 0xce, 0xf9,
+ 0x5d, 0x05, 0x23, 0xe2, 0xb3, 0x00, 0x59, 0x6c, 0x27, 0x4d, 0x6d, 0xa8, 0x20, 0xdb, 0x73, 0xfd,
+ 0x28, 0x56, 0xc3, 0x8c, 0x8d, 0x7c, 0x25, 0xe5, 0x9d, 0x95, 0xb4, 0xa1, 0x32, 0x43, 0x13, 0x3c,
+ 0x13, 0xf9, 0xd8, 0x35, 0x32, 0x04, 0x15, 0xca, 0x1e, 0x75, 0x22, 0xb2, 0x9a, 0xc3, 0xce, 0x9f,
+ 0xeb, 0xae, 0x60, 0xa2, 0x65, 0x5a, 0x86, 0x81, 0x29, 0x45, 0x0e, 0x36, 0x43, 0x88, 0x80, 0xa0,
+ 0x32, 0x5d, 0xf8, 0x36, 0x15, 0xab, 0xbd, 0xb2, 0x7a, 0x3c, 0x78, 0xa4, 0xc5, 0x72, 0xd1, 0x42,
+ 0xb9, 0x68, 0x89, 0x5c, 0xb4, 0x11, 0x71, 0xfd, 0xe1, 0xe9, 0xcd, 0xba, 0x5b, 0xfa, 0xe1, 0xb7,
+ 0xae, 0xea, 0xb8, 0xec, 0xf9, 0x62, 0xa2, 0x59, 0xc4, 0xd3, 0x13, 0x6d, 0xc5, 0x7f, 0x1f, 0x51,
+ 0xfb, 0x45, 0x22, 0x93, 0xd0, 0x81, 0x9a, 0x71, 0x64, 0xe5, 0xc7, 0x23, 0x38, 0x29, 0x26, 0x64,
+ 0xf0, 0xff, 0x64, 0x44, 0x10, 0x80, 0xa7, 0x68, 0xc6, 0xc4, 0x5a, 0x24, 0x9d, 0x68, 0x2d, 0x9c,
+ 0x40, 0x6d, 0xea, 0xae, 0xc6, 0x61, 0x91, 0xf5, 0x1e, 0xa7, 0xd6, 0xcd, 0xea, 0xd4, 0x5d, 0x19,
+ 0xd4, 0x51, 0x3e, 0x03, 0xb9, 0x98, 0xbd, 0x4c, 0xb2, 0x22, 0xd4, 0x90, 0x6d, 0x07, 0x98, 0xd2,
+ 0x84, 0xc5, 0xd4, 0x0c, 0x13, 0xd9, 0x88, 0xa1, 0x44, 0xa3, 0xd1, 0x5a, 0xf9, 0x1c, 0xba, 0x3b,
+ 0x4e, 0xe3, 0x1f, 0x06, 0xfc, 0x85, 0x03, 0xc1, 0xa0, 0xce, 0xa7, 0x2b, 0x6c, 0x2d, 0x0e, 0x10,
+ 0x7b, 0x38, 0x3b, 0x09, 0x26, 0x39, 0xdd, 0xcc, 0x4e, 0x4f, 0xa9, 0xfc, 0x37, 0x4e, 0xa9, 0xf2,
+ 0x9f, 0xe9, 0xf6, 0x14, 0xa4, 0xd7, 0xdb, 0xca, 0x38, 0x4a, 0x99, 0xe0, 0x72, 0x4c, 0x7c, 0x1f,
+ 0x33, 0x61, 0xb8, 0x4e, 0x80, 0xfe, 0x25, 0x13, 0x07, 0x49, 0x3d, 0xa1, 0x8b, 0xbf, 0x97, 0xae,
+ 0xa4, 0x97, 0xad, 0xc2, 0xf6, 0xf6, 0x82, 0xe0, 0x81, 0x41, 0x9d, 0x67, 0x73, 0x1b, 0x31, 0x7c,
+ 0x16, 0x4d, 0xdf, 0xae, 0x36, 0xde, 0x86, 0x86, 0x8f, 0x97, 0xe3, 0xfc, 0xbc, 0xd6, 0x7d, 0xbc,
+ 0x8c, 0x9d, 0xf2, 0x3d, 0x96, 0x5f, 0xed, 0x51, 0x11, 0xa3, 0x8b, 0x32, 0x97, 0x22, 0x2d, 0x48,
+ 0x19, 0xc1, 0x1b, 0x06, 0x75, 0x46, 0x33, 0x8c, 0x82, 0xfd, 0xb9, 0xf7, 0x85, 0x3f, 0x81, 0x87,
+ 0xaf, 0x04, 0x49, 0xa3, 0x0f, 0x7e, 0xae, 0x40, 0xd9, 0xa0, 0x8e, 0x70, 0x01, 0x8d, 0xbb, 0x57,
+ 0x58, 0xc1, 0x2b, 0x25, 0xff, 0x7e, 0x90, 0x1e, 0xef, 0xdf, 0xcf, 0xb8, 0xfc, 0x06, 0xde, 0x2a,
+ 0xba, 0xfa, 0xd5, 0x42, 0xf7, 0x02, 0xa4, 0x74, 0x7a, 0x28, 0x32, 0x4b, 0xc9, 0xa0, 0x5d, 0x78,
+ 0xb9, 0x7e, 0x70, 0x68, 0xa4, 0x81, 0xd4, 0x3f, 0x18, 0x9a, 0x65, 0xc5, 0xf0, 0xe6, 0xf6, 0xc8,
+ 0xbf, 0x57, 0x18, 0x65, 0x0b, 0x25, 0x7d, 0x78, 0x08, 0x2a, 0x9f, 0x66, 0x7b, 0x9e, 0x8a, 0xd3,
+ 0x6c, 0xa1, 0x76, 0xa4, 0xd9, 0x35, 0x02, 0x5f, 0xc1, 0x71, 0x5e, 0xeb, 0xbd, 0x42, 0xe7, 0x1c,
+ 0x42, 0x52, 0xef, 0x43, 0x64, 0xa1, 0xbf, 0x04, 0xc8, 0x29, 0xb9, 0x5b, 0xe8, 0x77, 0x07, 0x90,
+ 0xde, 0xbf, 0x07, 0x90, 0xc6, 0x1d, 0x3e, 0xb9, 0xf9, 0x43, 0x2e, 0xdd, 0x6c, 0x64, 0xee, 0xe5,
+ 0x46, 0xe6, 0x7e, 0xdf, 0xc8, 0xdc, 0x77, 0xb7, 0x72, 0xe9, 0xe5, 0xad, 0x5c, 0xfa, 0xf5, 0x56,
+ 0x2e, 0x7d, 0xfd, 0x38, 0x77, 0xdd, 0x8d, 0x08, 0xf5, 0x2e, 0xd3, 0x8f, 0x39, 0x5b, 0x5f, 0xc5,
+ 0x1f, 0x75, 0xd1, 0x95, 0x37, 0xa9, 0x46, 0x9f, 0x74, 0x1f, 0xff, 0x15, 0x00, 0x00, 0xff, 0xff,
+ 0x1a, 0x2c, 0xa2, 0xcd, 0x55, 0x0a, 0x00, 0x00,
}
// Reference imports to suppress errors if they are not otherwise used.
@@ -678,8 +791,12 @@ const _ = grpc.SupportPackageIsVersion4
type MsgClient interface {
// StoreCode to submit Wasm code to the system
StoreCode(ctx context.Context, in *MsgStoreCode, opts ...grpc.CallOption) (*MsgStoreCodeResponse, error)
- // Instantiate creates a new smart contract instance for the given code id.
+ // InstantiateContract creates a new smart contract instance for the given
+ // code id.
InstantiateContract(ctx context.Context, in *MsgInstantiateContract, opts ...grpc.CallOption) (*MsgInstantiateContractResponse, error)
+ // InstantiateContract2 creates a new smart contract instance for the given
+ // code id with a predictable address
+ InstantiateContract2(ctx context.Context, in *MsgInstantiateContract2, opts ...grpc.CallOption) (*MsgInstantiateContract2Response, error)
// Execute submits the given message data to a smart contract
ExecuteContract(ctx context.Context, in *MsgExecuteContract, opts ...grpc.CallOption) (*MsgExecuteContractResponse, error)
// Migrate runs a code upgrade/ downgrade for a smart contract
@@ -716,6 +833,15 @@ func (c *msgClient) InstantiateContract(ctx context.Context, in *MsgInstantiateC
return out, nil
}
+func (c *msgClient) InstantiateContract2(ctx context.Context, in *MsgInstantiateContract2, opts ...grpc.CallOption) (*MsgInstantiateContract2Response, error) {
+ out := new(MsgInstantiateContract2Response)
+ err := c.cc.Invoke(ctx, "/cosmwasm.wasm.v1.Msg/InstantiateContract2", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
func (c *msgClient) ExecuteContract(ctx context.Context, in *MsgExecuteContract, opts ...grpc.CallOption) (*MsgExecuteContractResponse, error) {
out := new(MsgExecuteContractResponse)
err := c.cc.Invoke(ctx, "/cosmwasm.wasm.v1.Msg/ExecuteContract", in, out, opts...)
@@ -756,8 +882,12 @@ func (c *msgClient) ClearAdmin(ctx context.Context, in *MsgClearAdmin, opts ...g
type MsgServer interface {
// StoreCode to submit Wasm code to the system
StoreCode(context.Context, *MsgStoreCode) (*MsgStoreCodeResponse, error)
- // Instantiate creates a new smart contract instance for the given code id.
+ // InstantiateContract creates a new smart contract instance for the given
+ // code id.
InstantiateContract(context.Context, *MsgInstantiateContract) (*MsgInstantiateContractResponse, error)
+ // InstantiateContract2 creates a new smart contract instance for the given
+ // code id with a predictable address
+ InstantiateContract2(context.Context, *MsgInstantiateContract2) (*MsgInstantiateContract2Response, error)
// Execute submits the given message data to a smart contract
ExecuteContract(context.Context, *MsgExecuteContract) (*MsgExecuteContractResponse, error)
// Migrate runs a code upgrade/ downgrade for a smart contract
@@ -779,6 +909,10 @@ func (*UnimplementedMsgServer) InstantiateContract(ctx context.Context, req *Msg
return nil, status.Errorf(codes.Unimplemented, "method InstantiateContract not implemented")
}
+func (*UnimplementedMsgServer) InstantiateContract2(ctx context.Context, req *MsgInstantiateContract2) (*MsgInstantiateContract2Response, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method InstantiateContract2 not implemented")
+}
+
func (*UnimplementedMsgServer) ExecuteContract(ctx context.Context, req *MsgExecuteContract) (*MsgExecuteContractResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method ExecuteContract not implemented")
}
@@ -835,6 +969,24 @@ func _Msg_InstantiateContract_Handler(srv interface{}, ctx context.Context, dec
return interceptor(ctx, in, info, handler)
}
+func _Msg_InstantiateContract2_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(MsgInstantiateContract2)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(MsgServer).InstantiateContract2(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/cosmwasm.wasm.v1.Msg/InstantiateContract2",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(MsgServer).InstantiateContract2(ctx, req.(*MsgInstantiateContract2))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
func _Msg_ExecuteContract_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(MsgExecuteContract)
if err := dec(in); err != nil {
@@ -919,6 +1071,10 @@ var _Msg_serviceDesc = grpc.ServiceDesc{
MethodName: "InstantiateContract",
Handler: _Msg_InstantiateContract_Handler,
},
+ {
+ MethodName: "InstantiateContract2",
+ Handler: _Msg_InstantiateContract2_Handler,
+ },
{
MethodName: "ExecuteContract",
Handler: _Msg_ExecuteContract_Handler,
@@ -1094,6 +1250,93 @@ func (m *MsgInstantiateContract) MarshalToSizedBuffer(dAtA []byte) (int, error)
return len(dAtA) - i, nil
}
+func (m *MsgInstantiateContract2) 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 *MsgInstantiateContract2) MarshalTo(dAtA []byte) (int, error) {
+ size := m.Size()
+ return m.MarshalToSizedBuffer(dAtA[:size])
+}
+
+func (m *MsgInstantiateContract2) MarshalToSizedBuffer(dAtA []byte) (int, error) {
+ i := len(dAtA)
+ _ = i
+ var l int
+ _ = l
+ if m.FixMsg {
+ i--
+ if m.FixMsg {
+ dAtA[i] = 1
+ } else {
+ dAtA[i] = 0
+ }
+ i--
+ dAtA[i] = 0x40
+ }
+ if len(m.Salt) > 0 {
+ i -= len(m.Salt)
+ copy(dAtA[i:], m.Salt)
+ i = encodeVarintTx(dAtA, i, uint64(len(m.Salt)))
+ i--
+ dAtA[i] = 0x3a
+ }
+ if len(m.Funds) > 0 {
+ for iNdEx := len(m.Funds) - 1; iNdEx >= 0; iNdEx-- {
+ {
+ size, err := m.Funds[iNdEx].MarshalToSizedBuffer(dAtA[:i])
+ if err != nil {
+ return 0, err
+ }
+ i -= size
+ i = encodeVarintTx(dAtA, i, uint64(size))
+ }
+ i--
+ dAtA[i] = 0x32
+ }
+ }
+ if len(m.Msg) > 0 {
+ i -= len(m.Msg)
+ copy(dAtA[i:], m.Msg)
+ i = encodeVarintTx(dAtA, i, uint64(len(m.Msg)))
+ i--
+ dAtA[i] = 0x2a
+ }
+ if len(m.Label) > 0 {
+ i -= len(m.Label)
+ copy(dAtA[i:], m.Label)
+ i = encodeVarintTx(dAtA, i, uint64(len(m.Label)))
+ i--
+ dAtA[i] = 0x22
+ }
+ if m.CodeID != 0 {
+ i = encodeVarintTx(dAtA, i, uint64(m.CodeID))
+ i--
+ dAtA[i] = 0x18
+ }
+ if len(m.Admin) > 0 {
+ i -= len(m.Admin)
+ copy(dAtA[i:], m.Admin)
+ i = encodeVarintTx(dAtA, i, uint64(len(m.Admin)))
+ i--
+ dAtA[i] = 0x12
+ }
+ if len(m.Sender) > 0 {
+ i -= len(m.Sender)
+ copy(dAtA[i:], m.Sender)
+ i = encodeVarintTx(dAtA, i, uint64(len(m.Sender)))
+ i--
+ dAtA[i] = 0xa
+ }
+ return len(dAtA) - i, nil
+}
+
func (m *MsgInstantiateContractResponse) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
@@ -1131,6 +1374,43 @@ func (m *MsgInstantiateContractResponse) MarshalToSizedBuffer(dAtA []byte) (int,
return len(dAtA) - i, nil
}
+func (m *MsgInstantiateContract2Response) 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 *MsgInstantiateContract2Response) MarshalTo(dAtA []byte) (int, error) {
+ size := m.Size()
+ return m.MarshalToSizedBuffer(dAtA[:size])
+}
+
+func (m *MsgInstantiateContract2Response) MarshalToSizedBuffer(dAtA []byte) (int, error) {
+ i := len(dAtA)
+ _ = i
+ var l int
+ _ = l
+ if len(m.Data) > 0 {
+ i -= len(m.Data)
+ copy(dAtA[i:], m.Data)
+ i = encodeVarintTx(dAtA, i, uint64(len(m.Data)))
+ i--
+ dAtA[i] = 0x12
+ }
+ if len(m.Address) > 0 {
+ i -= len(m.Address)
+ copy(dAtA[i:], m.Address)
+ i = encodeVarintTx(dAtA, i, uint64(len(m.Address)))
+ i--
+ dAtA[i] = 0xa
+ }
+ return len(dAtA) - i, nil
+}
+
func (m *MsgExecuteContract) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
@@ -1508,6 +1788,47 @@ func (m *MsgInstantiateContract) Size() (n int) {
return n
}
+func (m *MsgInstantiateContract2) Size() (n int) {
+ if m == nil {
+ return 0
+ }
+ var l int
+ _ = l
+ l = len(m.Sender)
+ if l > 0 {
+ n += 1 + l + sovTx(uint64(l))
+ }
+ l = len(m.Admin)
+ if l > 0 {
+ n += 1 + l + sovTx(uint64(l))
+ }
+ if m.CodeID != 0 {
+ n += 1 + sovTx(uint64(m.CodeID))
+ }
+ l = len(m.Label)
+ if l > 0 {
+ n += 1 + l + sovTx(uint64(l))
+ }
+ l = len(m.Msg)
+ if l > 0 {
+ n += 1 + l + sovTx(uint64(l))
+ }
+ if len(m.Funds) > 0 {
+ for _, e := range m.Funds {
+ l = e.Size()
+ n += 1 + l + sovTx(uint64(l))
+ }
+ }
+ l = len(m.Salt)
+ if l > 0 {
+ n += 1 + l + sovTx(uint64(l))
+ }
+ if m.FixMsg {
+ n += 2
+ }
+ return n
+}
+
func (m *MsgInstantiateContractResponse) Size() (n int) {
if m == nil {
return 0
@@ -1525,6 +1846,23 @@ func (m *MsgInstantiateContractResponse) Size() (n int) {
return n
}
+func (m *MsgInstantiateContract2Response) Size() (n int) {
+ if m == nil {
+ return 0
+ }
+ var l int
+ _ = l
+ l = len(m.Address)
+ if l > 0 {
+ n += 1 + l + sovTx(uint64(l))
+ }
+ l = len(m.Data)
+ if l > 0 {
+ n += 1 + l + sovTx(uint64(l))
+ }
+ return n
+}
+
func (m *MsgExecuteContract) Size() (n int) {
if m == nil {
return 0
@@ -2157,6 +2495,294 @@ func (m *MsgInstantiateContract) Unmarshal(dAtA []byte) error {
return nil
}
+func (m *MsgInstantiateContract2) 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 ErrIntOverflowTx
+ }
+ 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: MsgInstantiateContract2: wiretype end group for non-group")
+ }
+ if fieldNum <= 0 {
+ return fmt.Errorf("proto: MsgInstantiateContract2: illegal tag %d (wire type %d)", fieldNum, wire)
+ }
+ switch fieldNum {
+ case 1:
+ if wireType != 2 {
+ return fmt.Errorf("proto: wrong wireType = %d for field Sender", wireType)
+ }
+ var stringLen uint64
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowTx
+ }
+ 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 ErrInvalidLengthTx
+ }
+ postIndex := iNdEx + intStringLen
+ if postIndex < 0 {
+ return ErrInvalidLengthTx
+ }
+ if postIndex > l {
+ return io.ErrUnexpectedEOF
+ }
+ m.Sender = string(dAtA[iNdEx:postIndex])
+ iNdEx = postIndex
+ case 2:
+ if wireType != 2 {
+ return fmt.Errorf("proto: wrong wireType = %d for field Admin", wireType)
+ }
+ var stringLen uint64
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowTx
+ }
+ 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 ErrInvalidLengthTx
+ }
+ postIndex := iNdEx + intStringLen
+ if postIndex < 0 {
+ return ErrInvalidLengthTx
+ }
+ if postIndex > l {
+ return io.ErrUnexpectedEOF
+ }
+ m.Admin = string(dAtA[iNdEx:postIndex])
+ iNdEx = postIndex
+ case 3:
+ if wireType != 0 {
+ return fmt.Errorf("proto: wrong wireType = %d for field CodeID", wireType)
+ }
+ m.CodeID = 0
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowTx
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ m.CodeID |= uint64(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ case 4:
+ if wireType != 2 {
+ return fmt.Errorf("proto: wrong wireType = %d for field Label", wireType)
+ }
+ var stringLen uint64
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowTx
+ }
+ 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 ErrInvalidLengthTx
+ }
+ postIndex := iNdEx + intStringLen
+ if postIndex < 0 {
+ return ErrInvalidLengthTx
+ }
+ if postIndex > l {
+ return io.ErrUnexpectedEOF
+ }
+ m.Label = string(dAtA[iNdEx:postIndex])
+ iNdEx = postIndex
+ case 5:
+ if wireType != 2 {
+ return fmt.Errorf("proto: wrong wireType = %d for field Msg", wireType)
+ }
+ var byteLen int
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowTx
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ byteLen |= int(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ if byteLen < 0 {
+ return ErrInvalidLengthTx
+ }
+ postIndex := iNdEx + byteLen
+ if postIndex < 0 {
+ return ErrInvalidLengthTx
+ }
+ if postIndex > l {
+ return io.ErrUnexpectedEOF
+ }
+ m.Msg = append(m.Msg[:0], dAtA[iNdEx:postIndex]...)
+ if m.Msg == nil {
+ m.Msg = []byte{}
+ }
+ iNdEx = postIndex
+ case 6:
+ if wireType != 2 {
+ return fmt.Errorf("proto: wrong wireType = %d for field Funds", wireType)
+ }
+ var msglen int
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowTx
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ msglen |= int(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ if msglen < 0 {
+ return ErrInvalidLengthTx
+ }
+ postIndex := iNdEx + msglen
+ if postIndex < 0 {
+ return ErrInvalidLengthTx
+ }
+ if postIndex > l {
+ return io.ErrUnexpectedEOF
+ }
+ m.Funds = append(m.Funds, types.Coin{})
+ if err := m.Funds[len(m.Funds)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
+ return err
+ }
+ iNdEx = postIndex
+ case 7:
+ if wireType != 2 {
+ return fmt.Errorf("proto: wrong wireType = %d for field Salt", wireType)
+ }
+ var byteLen int
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowTx
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ byteLen |= int(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ if byteLen < 0 {
+ return ErrInvalidLengthTx
+ }
+ postIndex := iNdEx + byteLen
+ if postIndex < 0 {
+ return ErrInvalidLengthTx
+ }
+ if postIndex > l {
+ return io.ErrUnexpectedEOF
+ }
+ m.Salt = append(m.Salt[:0], dAtA[iNdEx:postIndex]...)
+ if m.Salt == nil {
+ m.Salt = []byte{}
+ }
+ iNdEx = postIndex
+ case 8:
+ if wireType != 0 {
+ return fmt.Errorf("proto: wrong wireType = %d for field FixMsg", wireType)
+ }
+ var v int
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowTx
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ v |= int(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ m.FixMsg = bool(v != 0)
+ default:
+ iNdEx = preIndex
+ skippy, err := skipTx(dAtA[iNdEx:])
+ if err != nil {
+ return err
+ }
+ if (skippy < 0) || (iNdEx+skippy) < 0 {
+ return ErrInvalidLengthTx
+ }
+ if (iNdEx + skippy) > l {
+ return io.ErrUnexpectedEOF
+ }
+ iNdEx += skippy
+ }
+ }
+
+ if iNdEx > l {
+ return io.ErrUnexpectedEOF
+ }
+ return nil
+}
+
func (m *MsgInstantiateContractResponse) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
@@ -2274,6 +2900,123 @@ func (m *MsgInstantiateContractResponse) Unmarshal(dAtA []byte) error {
return nil
}
+func (m *MsgInstantiateContract2Response) 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 ErrIntOverflowTx
+ }
+ 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: MsgInstantiateContract2Response: wiretype end group for non-group")
+ }
+ if fieldNum <= 0 {
+ return fmt.Errorf("proto: MsgInstantiateContract2Response: illegal tag %d (wire type %d)", fieldNum, wire)
+ }
+ switch fieldNum {
+ case 1:
+ if wireType != 2 {
+ return fmt.Errorf("proto: wrong wireType = %d for field Address", wireType)
+ }
+ var stringLen uint64
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowTx
+ }
+ 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 ErrInvalidLengthTx
+ }
+ postIndex := iNdEx + intStringLen
+ if postIndex < 0 {
+ return ErrInvalidLengthTx
+ }
+ if postIndex > l {
+ return io.ErrUnexpectedEOF
+ }
+ m.Address = string(dAtA[iNdEx:postIndex])
+ iNdEx = postIndex
+ case 2:
+ if wireType != 2 {
+ return fmt.Errorf("proto: wrong wireType = %d for field Data", wireType)
+ }
+ var byteLen int
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowTx
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ byteLen |= int(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ if byteLen < 0 {
+ return ErrInvalidLengthTx
+ }
+ postIndex := iNdEx + byteLen
+ if postIndex < 0 {
+ return ErrInvalidLengthTx
+ }
+ if postIndex > l {
+ return io.ErrUnexpectedEOF
+ }
+ m.Data = append(m.Data[:0], dAtA[iNdEx:postIndex]...)
+ if m.Data == nil {
+ m.Data = []byte{}
+ }
+ iNdEx = postIndex
+ default:
+ iNdEx = preIndex
+ skippy, err := skipTx(dAtA[iNdEx:])
+ if err != nil {
+ return err
+ }
+ if (skippy < 0) || (iNdEx+skippy) < 0 {
+ return ErrInvalidLengthTx
+ }
+ if (iNdEx + skippy) > l {
+ return io.ErrUnexpectedEOF
+ }
+ iNdEx += skippy
+ }
+ }
+
+ if iNdEx > l {
+ return io.ErrUnexpectedEOF
+ }
+ return nil
+}
+
func (m *MsgExecuteContract) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
diff --git a/x/wasm/types/tx_test.go b/x/wasm/types/tx_test.go
index b59ad7ce..a3c29b4f 100644
--- a/x/wasm/types/tx_test.go
+++ b/x/wasm/types/tx_test.go
@@ -186,6 +186,142 @@ func TestInstantiateContractValidation(t *testing.T) {
}
}
+func TestInstantiateContract2Validation(t *testing.T) {
+ bad, err := sdk.AccAddressFromHex("012345")
+ require.NoError(t, err)
+ badAddress := bad.String()
+ // proper address size
+ goodAddress := sdk.AccAddress(make([]byte, 20)).String()
+ sdk.GetConfig().SetAddressVerifier(VerifyAddressLen())
+
+ cases := map[string]struct {
+ msg MsgInstantiateContract2
+ valid bool
+ }{
+ "empty": {
+ msg: MsgInstantiateContract2{},
+ valid: false,
+ },
+ "correct minimal": {
+ msg: MsgInstantiateContract2{
+ Sender: goodAddress,
+ CodeID: firstCodeID,
+ Label: "foo",
+ Msg: []byte("{}"),
+ Salt: []byte{0},
+ },
+ valid: true,
+ },
+ "missing code": {
+ msg: MsgInstantiateContract2{
+ Sender: goodAddress,
+ Label: "foo",
+ Msg: []byte("{}"),
+ Salt: []byte{0},
+ },
+ valid: false,
+ },
+ "missing label": {
+ msg: MsgInstantiateContract2{
+ Sender: goodAddress,
+ Msg: []byte("{}"),
+ Salt: []byte{0},
+ },
+ valid: false,
+ },
+ "label too long": {
+ msg: MsgInstantiateContract2{
+ Sender: goodAddress,
+ Label: strings.Repeat("food", 33),
+ Salt: []byte{0},
+ },
+ valid: false,
+ },
+ "bad sender minimal": {
+ msg: MsgInstantiateContract2{
+ Sender: badAddress,
+ CodeID: firstCodeID,
+ Label: "foo",
+ Msg: []byte("{}"),
+ Salt: []byte{0},
+ },
+ valid: false,
+ },
+ "correct maximal": {
+ msg: MsgInstantiateContract2{
+ Sender: goodAddress,
+ CodeID: firstCodeID,
+ Label: strings.Repeat("a", MaxLabelSize),
+ Msg: []byte(`{"some": "data"}`),
+ Funds: sdk.Coins{sdk.Coin{Denom: "foobar", Amount: sdk.NewInt(200)}},
+ Salt: bytes.Repeat([]byte{0}, MaxSaltSize),
+ FixMsg: true,
+ },
+ valid: true,
+ },
+ "negative funds": {
+ msg: MsgInstantiateContract2{
+ Sender: goodAddress,
+ CodeID: firstCodeID,
+ Label: "foo",
+ Msg: []byte(`{"some": "data"}`),
+ // we cannot use sdk.NewCoin() constructors as they panic on creating invalid data (before we can test)
+ Funds: sdk.Coins{sdk.Coin{Denom: "foobar", Amount: sdk.NewInt(-200)}},
+ Salt: []byte{0},
+ },
+ valid: false,
+ },
+ "non json init msg": {
+ msg: MsgInstantiateContract2{
+ Sender: goodAddress,
+ CodeID: firstCodeID,
+ Label: "foo",
+ Msg: []byte("invalid-json"),
+ Salt: []byte{0},
+ },
+ valid: false,
+ },
+ "empty init msg": {
+ msg: MsgInstantiateContract2{
+ Sender: goodAddress,
+ CodeID: firstCodeID,
+ Label: "foo",
+ Salt: []byte{0},
+ },
+ valid: false,
+ },
+ "empty salt": {
+ msg: MsgInstantiateContract2{
+ Sender: goodAddress,
+ CodeID: firstCodeID,
+ Label: "foo",
+ Msg: []byte(`{"some": "data"}`),
+ },
+ valid: false,
+ },
+ "salt too long": {
+ msg: MsgInstantiateContract2{
+ Sender: goodAddress,
+ CodeID: firstCodeID,
+ Label: "foo",
+ Msg: []byte(`{"some": "data"}`),
+ Salt: bytes.Repeat([]byte{0}, 65),
+ },
+ valid: false,
+ },
+ }
+ for name, tc := range cases {
+ t.Run(name, func(t *testing.T) {
+ err := tc.msg.ValidateBasic()
+ if tc.valid {
+ assert.NoError(t, err)
+ } else {
+ assert.Error(t, err)
+ }
+ })
+ }
+}
+
func TestExecuteContractValidation(t *testing.T) {
bad, err := sdk.AccAddressFromHex("012345")
require.NoError(t, err)
diff --git a/x/wasm/types/validation.go b/x/wasm/types/validation.go
index 0619c7f0..908c5255 100644
--- a/x/wasm/types/validation.go
+++ b/x/wasm/types/validation.go
@@ -4,8 +4,11 @@ import (
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
)
+// MaxSaltSize is the longest salt that can be used when instantiating a contract
+const MaxSaltSize = 64
+
var (
- // MaxLabelSize is the longest label that can be used when Instantiating a contract
+ // MaxLabelSize is the longest label that can be used when instantiating a contract
MaxLabelSize = 128 // extension point for chains to customize via compile flag.
// MaxWasmSize is the largest a compiled contract code can be when storing code on chain
@@ -28,7 +31,18 @@ func ValidateLabel(label string) error {
return sdkerrors.Wrap(ErrEmpty, "is required")
}
if len(label) > MaxLabelSize {
- return sdkerrors.Wrap(ErrLimit, "cannot be longer than 128 characters")
+ return ErrLimit.Wrapf("cannot be longer than %d characters", MaxLabelSize)
+ }
+ return nil
+}
+
+// ValidateSalt ensure salt constraints
+func ValidateSalt(salt []byte) error {
+ switch n := len(salt); {
+ case n == 0:
+ return sdkerrors.Wrap(ErrEmpty, "is required")
+ case n > MaxSaltSize:
+ return ErrLimit.Wrapf("cannot be longer than %d characters", MaxSaltSize)
}
return nil
}