diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 766f7c2dc..189f85ee3 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -221,7 +221,7 @@ jobs: echo "not_a_key" > ias_keys/develop/spid.txt echo "not_a_key" > ias_keys/develop/api_key.txt LOG_LEVEL=ERROR go test -v ./x/compute/client/... - LOG_LEVEL=ERROR go test -p 1 -timeout 20m -v ./x/compute/internal/... + LOG_LEVEL=ERROR go test -p 1 -timeout 40m -v ./x/compute/internal/... Clippy: runs-on: ubuntu-20.04 @@ -294,15 +294,21 @@ jobs: runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v2 - - name: Build docker testnet + - name: Build LocalSecret run: | echo not_a_key | tee {api_key,spid}.txt DOCKER_TAG=v0.0.0 make build-localsecret + - name: Run integration tests + run: | + cd integration-tests + yarn + docker run -d -p 9091:9091 --name localsecret ghcr.io/scrtlabs/localsecret:v0.0.0 + sleep 30 + docker logs localsecret + yarn test - name: Run secret.js tests run: | git clone --depth 1 https://github.com/scrtlabs/secret.js - # Copy v1 contract to tests directory - cp ./target/wasm32-unknown-unknown/release/v1_sanity_contract.wasm ./secret.js/test/test_contract_v1.wasm cd secret.js # Use the docker images that we built just a few steps above perl -i -pe 's/localsecret:.+?"/localsecret:v0.0.0"/' ./test/* diff --git a/.vscode/launch.json b/.vscode/launch.json index cf316bbde..17ec80ded 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -10,6 +10,7 @@ "request": "launch", "mode": "debug", "program": "${file}", + "cwd": "${workspaceFolder}/x/compute/internal/keeper", "env": { "SGX_MODE": "SW", "RUST_BACKTRACE": "1" }, "args": [ "test", diff --git a/.vscode/settings.json b/.vscode/settings.json index 0b900924e..8318189d7 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,9 +1,13 @@ { "rust-analyzer.linkedProjects": [ - "./cosmwasm/Cargo.toml", - "./cosmwasm/enclaves/Cargo.toml", - "./x/compute/internal/keeper/testdata/v1-sanity-contract/Cargo.toml", - "./x/compute/internal/keeper/testdata/test-contract/Cargo.toml" + "cosmwasm/Cargo.toml", + "cosmwasm/enclaves/Cargo.toml", + "x/compute/internal/keeper/testdata/v1-sanity-contract/Cargo.toml", + "x/compute/internal/keeper/testdata/test-contract/Cargo.toml", + "./x/compute/internal/keeper/testdata/ibc/Cargo.toml", + "integration-tests/contract-v1/Cargo.toml", + "integration-tests/contract-v0.10/Cargo.toml", + "go-cosmwasm/Cargo.toml" ], "rust-analyzer.diagnostics.experimental.enable": true, "rust-analyzer.rustfmt.rangeFormatting.enable": true, @@ -20,7 +24,6 @@ "go.useLanguageServer": true, "go.lintTool": "golangci-lint", "go.lintOnSave": "workspace", - "go.buildTags": "secretcli", "gopls": { "formatting.gofumpt": true }, diff --git a/Makefile b/Makefile index 364e9b530..b90dcc8c3 100644 --- a/Makefile +++ b/Makefile @@ -348,6 +348,7 @@ build-test-contract: # sudo apt install -y binaryen $(MAKE) -C ./x/compute/internal/keeper/testdata/test-contract $(MAKE) -C ./x/compute/internal/keeper/testdata/v1-sanity-contract + $(MAKE) -C ./x/compute/internal/keeper/testdata/ibc prep-go-tests: build-test-contract @@ -361,7 +362,7 @@ go-tests: build-test-contract cp ./cosmwasm/enclaves/execute/librust_cosmwasm_enclave.signed.so ./x/compute/internal/keeper rm -rf ./x/compute/internal/keeper/.sgx_secrets mkdir -p ./x/compute/internal/keeper/.sgx_secrets - GOMAXPROCS=8 SGX_MODE=SW SCRT_SGX_STORAGE='./' go test -failfast -timeout 2400s -v ./x/compute/internal/... $(GO_TEST_ARGS) + GOMAXPROCS=8 SGX_MODE=SW SCRT_SGX_STORAGE='./' go test -failfast -timeout 40m -v ./x/compute/internal/... $(GO_TEST_ARGS) go-tests-hw: build-test-contract # empty BUILD_PROFILE means debug mode which compiles faster diff --git a/app/app.go b/app/app.go index 5a97f9a86..9363a2ac1 100644 --- a/app/app.go +++ b/app/app.go @@ -399,7 +399,6 @@ func NewSecretNetworkApp( AddRoute(ibcclienttypes.RouterKey, ibcclient.NewClientProposalHandler(app.ibcKeeper.ClientKeeper)) // Just re-use the full router - do we want to limit this more? - computeRouter := app.Router() regRouter := app.Router() // Replace with bootstrap flag when we figure out how to test properly and everything works @@ -419,7 +418,7 @@ func NewSecretNetworkApp( // The last arguments can contain custom message handlers, and custom query handlers, // if we want to allow any custom callbacks - supportedFeatures := "staking" + supportedFeatures := "staking,stargate,ibc3" app.computeKeeper = compute.NewKeeper( appCodec, @@ -435,7 +434,9 @@ func NewSecretNetworkApp( app.ibcKeeper.PortKeeper, app.transferKeeper, app.ibcKeeper.ChannelKeeper, - computeRouter, + app.Router(), + app.MsgServiceRouter(), + app.GRPCQueryRouter(), computeDir, computeConfig, supportedFeatures, diff --git a/cmd/secretd/attestation.go b/cmd/secretd/attestation.go index dabc4b482..f64cdfbbd 100644 --- a/cmd/secretd/attestation.go +++ b/cmd/secretd/attestation.go @@ -17,7 +17,6 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/server" "github.com/cosmos/cosmos-sdk/x/genutil" genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" @@ -124,8 +123,7 @@ blockchain. Writes the certificate in DER format to ~/attestation_cert Args: cobra.MaximumNArgs(2), RunE: func(cmd *cobra.Command, args []string) error { clientCtx := client.GetClientContextFromCmd(cmd) - depCdc := clientCtx.Codec - cdc := depCdc.(codec.Codec) + cdc := clientCtx.Codec serverCtx := server.GetServerContextFromCmd(cmd) config := serverCtx.Config @@ -175,8 +173,8 @@ blockchain. Writes the certificate in DER format to ~/attestation_cert return err } - fmt.Println(fmt.Sprintf("%s", hex.EncodeToString(pubkey))) - fmt.Println(fmt.Sprintf("%s", hex.EncodeToString(masterKey))) + fmt.Printf("%s\n", hex.EncodeToString(pubkey)) + fmt.Printf("%s\n", hex.EncodeToString(masterKey)) // sanity check - make sure the certificate we're using matches the generated key if hex.EncodeToString(pubkey) != hex.EncodeToString(masterKey) { @@ -239,7 +237,7 @@ func ParseCert() *cobra.Command { return err } - fmt.Println(fmt.Sprintf("0x%s", hex.EncodeToString(pubkey))) + fmt.Printf("0x%s\n", hex.EncodeToString(pubkey)) return nil }, } @@ -313,7 +311,7 @@ func HealthCheck() *cobra.Command { return fmt.Errorf("failed to start enclave. Enclave returned: %s", err) } - fmt.Println(fmt.Sprintf("SGX enclave health status: %s", res)) + fmt.Printf("SGX enclave health status: %s\n", res) return nil }, } @@ -491,7 +489,11 @@ Please report any issues with this command "certificate": "%s" }`, base64.StdEncoding.EncodeToString(cert))) - resp, err := http.Post(fmt.Sprintf(`%s`, regUrl), "application/json", bytes.NewBuffer(data)) + resp, err := http.Post(regUrl, "application/json", bytes.NewBuffer(data)) + if err != nil { + log.Fatalln(err) + } + defer resp.Body.Close() body, err := io.ReadAll(resp.Body) @@ -515,7 +517,7 @@ Please report any issues with this command } seed := details.Details.Value - log.Printf(fmt.Sprintf(`seed: %s`, seed)) + log.Printf(`seed: %s\n`, seed) if len(seed) > 2 { seed = seed[2:] diff --git a/cmd/secretd/genaccounts.go b/cmd/secretd/genaccounts.go index e4bf9b8c7..3ed771043 100644 --- a/cmd/secretd/genaccounts.go +++ b/cmd/secretd/genaccounts.go @@ -14,7 +14,6 @@ import ( "github.com/spf13/cobra" "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/server" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/genutil" @@ -42,8 +41,7 @@ contain valid denominations. Accounts may optionally be supplied with vesting pa Args: cobra.ExactArgs(2), RunE: func(cmd *cobra.Command, args []string) error { clientCtx := client.GetClientContextFromCmd(cmd) - depCdc := clientCtx.Codec - cdc := depCdc.(codec.Codec) + cdc := clientCtx.Codec serverCtx := server.GetServerContextFromCmd(cmd) config := serverCtx.Config @@ -161,7 +159,7 @@ contain valid denominations. Accounts may optionally be supplied with vesting pa appState[authtypes.ModuleName] = authGenStateBz - bankGenState := banktypes.GetGenesisStateFromAppState(depCdc, appState) + bankGenState := banktypes.GetGenesisStateFromAppState(cdc, appState) bankGenState.Balances = append(bankGenState.Balances, balances) bankGenState.Balances = banktypes.SanitizeGenesisBalances(bankGenState.Balances) diff --git a/cosmwasm/enclaves/Cargo.lock b/cosmwasm/enclaves/Cargo.lock index 26a972389..096506845 100644 --- a/cosmwasm/enclaves/Cargo.lock +++ b/cosmwasm/enclaves/Cargo.lock @@ -79,6 +79,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "base64" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" + [[package]] name = "base64" version = "0.13.0" @@ -250,7 +256,7 @@ checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" [[package]] name = "cosmos_proto" -version = "1.2.4" +version = "1.4.0" dependencies = [ "dirs", "protobuf", @@ -315,6 +321,51 @@ dependencies = [ "zeroize", ] +[[package]] +name = "cw_types_generic" +version = "0.1.0" +dependencies = [ + "base64 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cw_types_v010", + "cw_types_v1", + "enclave-ffi-types", + "hex", + "log", + "serde 1.0.118", + "serde_json 1.0.60", +] + +[[package]] +name = "cw_types_v010" +version = "1.4.0" +dependencies = [ + "base64 0.13.0 (git+https://github.com/mesalock-linux/rust-base64-sgx?rev=dc7389e10817b078f289386b3b6a852ab6c4c021)", + "bech32", + "derive_more", + "enclave-ffi-types", + "log", + "serde 1.0.118", + "serde_json 1.0.60", + "sgx_tstd 1.1.3 (git+https://github.com/apache/teaclave-sgx-sdk.git?rev=a37ffb9449ba6d5b6e4a9d586bbab864ae732269)", +] + +[[package]] +name = "cw_types_v1" +version = "1.4.0" +dependencies = [ + "base64 0.13.0 (git+https://github.com/mesalock-linux/rust-base64-sgx?rev=dc7389e10817b078f289386b3b6a852ab6c4c021)", + "bech32", + "cw_types_v010", + "derive_more", + "enclave-ffi-types", + "log", + "serde 1.0.118", + "serde_json 1.0.60", + "sgx_tstd 1.1.3 (git+https://github.com/apache/teaclave-sgx-sdk.git?rev=a37ffb9449ba6d5b6e4a9d586bbab864ae732269)", + "thiserror", + "uint", +] + [[package]] name = "dbl" version = "0.3.2" @@ -411,17 +462,18 @@ dependencies = [ [[package]] name = "enclave_contract_engine" -version = "1.2.4" +version = "1.4.0" dependencies = [ "base64 0.13.0 (git+https://github.com/mesalock-linux/rust-base64-sgx?rev=dc7389e10817b078f289386b3b6a852ab6c4c021)", "bech32", "cosmos_proto", + "cw_types_generic", + "cw_types_v010", + "cw_types_v1", "derive_more", "ed25519-zebra", "enclave-ffi-types", "enclave_cosmos_types", - "enclave_cosmwasm_v010_types", - "enclave_cosmwasm_v1_types", "enclave_crypto", "enclave_utils", "hex", @@ -444,12 +496,12 @@ dependencies = [ [[package]] name = "enclave_cosmos_types" -version = "1.2.4" +version = "1.4.0" dependencies = [ "cosmos_proto", + "cw_types_v010", "derive_more", "enclave-ffi-types", - "enclave_cosmwasm_v010_types", "enclave_crypto", "log", "num_enum", @@ -460,42 +512,12 @@ dependencies = [ "sha2 0.8.2", ] -[[package]] -name = "enclave_cosmwasm_v010_types" -version = "1.2.4" -dependencies = [ - "base64 0.13.0 (git+https://github.com/mesalock-linux/rust-base64-sgx?rev=dc7389e10817b078f289386b3b6a852ab6c4c021)", - "bech32", - "derive_more", - "enclave-ffi-types", - "log", - "serde 1.0.118", - "serde_json 1.0.60", - "sgx_tstd 1.1.3 (git+https://github.com/apache/teaclave-sgx-sdk.git?rev=a37ffb9449ba6d5b6e4a9d586bbab864ae732269)", -] - -[[package]] -name = "enclave_cosmwasm_v1_types" -version = "1.2.4" -dependencies = [ - "base64 0.13.0 (git+https://github.com/mesalock-linux/rust-base64-sgx?rev=dc7389e10817b078f289386b3b6a852ab6c4c021)", - "bech32", - "derive_more", - "enclave-ffi-types", - "enclave_cosmwasm_v010_types", - "log", - "serde 1.0.118", - "serde_json 1.0.60", - "sgx_tstd 1.1.3 (git+https://github.com/apache/teaclave-sgx-sdk.git?rev=a37ffb9449ba6d5b6e4a9d586bbab864ae732269)", - "thiserror", - "uint", -] - [[package]] name = "enclave_crypto" -version = "1.2.4" +version = "1.4.0" dependencies = [ "aes-siv", + "cosmos_proto", "derive_more", "enclave-ffi-types", "hex", @@ -508,12 +530,13 @@ dependencies = [ "sgx_tstd 1.1.3 (git+https://github.com/apache/teaclave-sgx-sdk.git?rev=a37ffb9449ba6d5b6e4a9d586bbab864ae732269)", "sgx_types 1.1.3 (git+https://github.com/apache/teaclave-sgx-sdk.git?rev=a37ffb9449ba6d5b6e4a9d586bbab864ae732269)", "sha2 0.8.2", + "sha3", "x25519-dalek", ] [[package]] name = "enclave_utils" -version = "1.2.4" +version = "1.4.0" dependencies = [ "enclave-ffi-types", "lazy_static", @@ -642,6 +665,12 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" +[[package]] +name = "keccak" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9b7d56ba4a8344d6be9729995e6b06f928af29998cdf79fe390cbf6b1fee838" + [[package]] name = "lazy_static" version = "1.4.0" @@ -1010,7 +1039,7 @@ dependencies = [ [[package]] name = "secret-enclave" -version = "1.2.4" +version = "1.4.0" dependencies = [ "base64 0.13.0 (git+https://github.com/mesalock-linux/rust-base64-sgx?rev=dc7389e10817b078f289386b3b6a852ab6c4c021)", "bit-vec", @@ -1047,7 +1076,7 @@ dependencies = [ [[package]] name = "secret-query-enclave" -version = "1.2.4" +version = "1.4.0" dependencies = [ "ctor", "enclave_contract_engine", @@ -1342,6 +1371,19 @@ dependencies = [ "opaque-debug 0.3.0", ] +[[package]] +name = "sha3" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd26bc0e7a2e3a7c959bc494caf58b72ee0c71d67704e9520f736ca7e4853ecf" +dependencies = [ + "block-buffer 0.7.3", + "byte-tools", + "digest 0.8.1", + "keccak", + "opaque-debug 0.2.3", +] + [[package]] name = "spin" version = "0.5.2" diff --git a/cosmwasm/enclaves/Cargo.toml b/cosmwasm/enclaves/Cargo.toml index c812d3ad2..d818d4c6d 100644 --- a/cosmwasm/enclaves/Cargo.toml +++ b/cosmwasm/enclaves/Cargo.toml @@ -1,5 +1,17 @@ [workspace] -members = ["ffi-types", "execute", "query", "shared/*"] +members = [ + "ffi-types", + "execute", + "query", + "shared/contract-engine", + "shared/cosmos-proto", + "shared/cosmos-types", + "shared/crypto", + "shared/utils", + "shared/cosmwasm-types/v1.0", + "shared/cosmwasm-types/v0.10", + "shared/cosmwasm-types/generic" +] exclude = ["test"] [profile.release] diff --git a/cosmwasm/enclaves/execute/Cargo.toml b/cosmwasm/enclaves/execute/Cargo.toml index 9c551b242..da0c296d6 100644 --- a/cosmwasm/enclaves/execute/Cargo.toml +++ b/cosmwasm/enclaves/execute/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "secret-enclave" -version = "1.2.4" +version = "1.4.0" authors = ["SCRT Labs "] edition = "2018" description = "An enclave running wasmi, to be used by cosmwasm-sgx-vm" diff --git a/cosmwasm/enclaves/query/Cargo.toml b/cosmwasm/enclaves/query/Cargo.toml index fb897856c..861f82881 100644 --- a/cosmwasm/enclaves/query/Cargo.toml +++ b/cosmwasm/enclaves/query/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "secret-query-enclave" -version = "1.2.4" +version = "1.4.0" authors = ["SCRT Labs "] edition = "2018" description = "An enclave running wasmi, to be used by cosmwasm-sgx-vm" diff --git a/cosmwasm/enclaves/shared/contract-engine/Cargo.toml b/cosmwasm/enclaves/shared/contract-engine/Cargo.toml index 972de3966..04fcec99e 100644 --- a/cosmwasm/enclaves/shared/contract-engine/Cargo.toml +++ b/cosmwasm/enclaves/shared/contract-engine/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "enclave_contract_engine" -version = "1.2.4" +version = "1.4.0" authors = ["Cashmaney "] edition = "2018" @@ -23,8 +23,9 @@ enclave-ffi-types = { path = "../../ffi-types" } cosmos_proto = { path = "../cosmos-proto" } enclave_crypto = { path = "../crypto" } enclave_cosmos_types = { path = "../cosmos-types" } -enclave_cosmwasm_v010_types = { path = "../cosmwasm-v010-types" } -enclave_cosmwasm_v1_types = { path = "../cosmwasm-v1-types" } +cw_types_v010 = { path = "../cosmwasm-types/v0.10" } +cw_types_v1 = { path = "../cosmwasm-types/v1.0" } +cw_types_generic = {path = "../cosmwasm-types/generic"} enclave_utils = { path = "../utils" } serde = { git = "https://github.com/mesalock-linux/serde-sgx", features = [ "derive" diff --git a/cosmwasm/enclaves/shared/contract-engine/src/contract_operations.rs b/cosmwasm/enclaves/shared/contract-engine/src/contract_operations.rs index 7e0381f44..195bf917c 100644 --- a/cosmwasm/enclaves/shared/contract-engine/src/contract_operations.rs +++ b/cosmwasm/enclaves/shared/contract-engine/src/contract_operations.rs @@ -1,36 +1,30 @@ -use log::*; +use cw_types_generic::{BaseAddr, BaseEnv}; + +use cw_types_v010::encoding::Binary; +use cw_types_v010::types::CanonicalAddr; +use enclave_cosmos_types::types::{ContractCode, HandleType, SigInfo}; +use enclave_crypto::Ed25519PublicKey; use enclave_ffi_types::{Ctx, EnclaveError}; +use enclave_utils::coalesce; +use log::*; use crate::contract_validation::{ReplyParams, ValidatedMessage}; use crate::external::results::{HandleSuccess, InitSuccess, QuerySuccess}; -use crate::wasm::CosmWasmApiVersion; -use cosmos_proto::tx::signing::SignMode; -use cosmwasm_v010_types::types::CanonicalAddr; -use enclave_cosmos_types::types::{ContractCode, HandleType, SigInfo}; -use enclave_cosmwasm_v010_types as cosmwasm_v010_types; -use enclave_cosmwasm_v010_types::encoding::Binary; -use enclave_cosmwasm_v1_types::addresses::Addr; -use enclave_cosmwasm_v1_types::results::{ - DecryptedReply, Event, Reply, SubMsgResponse, SubMsgResult, -}; -use enclave_cosmwasm_v1_types::timestamp::Timestamp; - -use enclave_crypto::{Ed25519PublicKey, HASH_SIZE}; -use enclave_utils::coalesce; +use crate::message::{is_ibc_msg, parse_message, ParsedMessage}; use super::contract_validation::{ - extract_contract_key, generate_encryption_key, validate_contract_key, validate_msg, - verify_params, ContractKey, + generate_encryption_key, validate_contract_key, validate_msg, verify_params, ContractKey, }; use super::gas::WasmCosts; -use super::io::encrypt_output; +use super::io::{ + encrypt_output, finalize_raw_output, manipulate_callback_sig_for_plaintext, + set_all_logs_to_plaintext, +}; use super::module_cache::create_module_instance; use super::types::{IoNonce, SecretMessage}; use super::wasm::{ContractInstance, ContractOperation, Engine}; -const HEX_ENCODED_HASH_SIZE: usize = HASH_SIZE * 2; - /* Each contract is compiled with these functions already implemented in wasm: fn cosmwasm_api_0_6() -> i32; // Seems unused, but we should support it anyways @@ -55,69 +49,44 @@ pub fn init( msg: &[u8], // probably function call and args sig_info: &[u8], // info about signature verification ) -> Result { + trace!("Starting init"); + let contract_code = ContractCode::new(contract); + let contract_hash = contract_code.hash(); - let mut env_v010: cosmwasm_v010_types::types::Env = - serde_json::from_slice(env).map_err(|err| { - warn!( - "init got an error while trying to deserialize env input bytes into json {:?}: {}", - String::from_utf8_lossy(&env), - err - ); - EnclaveError::FailedToDeserialize - })?; - env_v010.contract_code_hash = hex::encode(contract_code.hash()); + let base_env: BaseEnv = extract_base_env(env)?; - let canonical_contract_address = CanonicalAddr::from_human(&env_v010.contract.address).map_err(|err| { - warn!( - "init got an error while trying to deserialize env_v010.contract.address from bech32 string to bytes {:?}: {}", - env_v010.contract.address, err - ); - EnclaveError::FailedToDeserialize - })?; + let (sender, contract_address, block_height, sent_funds) = base_env.get_verification_params(); - trace!("init env_v010: {:?}", env_v010); + let canonical_contract_address = to_canonical(contract_address)?; - let canonical_sender_address = CanonicalAddr::from_human(&env_v010.message.sender).map_err(|err| { - warn!( - "init got an error while trying to deserialize env_v010.message.sender from bech32 string to bytes {:?}: {}", - env_v010.message.sender, err - ); - EnclaveError::FailedToDeserialize - })?; + let canonical_sender_address = to_canonical(sender)?; let contract_key = generate_encryption_key( - &env_v010, - contract_code.hash(), - &(canonical_contract_address.0).0, + &canonical_sender_address, + &block_height, + &contract_hash, + &canonical_contract_address, )?; - trace!("init contract key: {:?}", hex::encode(contract_key)); - let parsed_sig_info: SigInfo = serde_json::from_slice(sig_info).map_err(|err| { - warn!( - "init got an error while trying to deserialize env input bytes into json {:?}: {}", - String::from_utf8_lossy(&sig_info), - err - ); - EnclaveError::FailedToDeserialize - })?; + let parsed_sig_info: SigInfo = extract_sig_info(sig_info)?; - trace!("init input before decryption: {:?}", base64::encode(&msg)); let secret_msg = SecretMessage::from_slice(msg)?; - verify_params(&parsed_sig_info, &env_v010, &secret_msg)?; + verify_params( + &parsed_sig_info, + &sent_funds, + &canonical_sender_address, + &contract_address, + &secret_msg, + )?; let decrypted_msg = secret_msg.decrypt()?; let ValidatedMessage { validated_msg, reply_params, - } = validate_msg(&decrypted_msg, contract_code.hash(), None)?; - - trace!( - "init input after decryption: {:?}", - String::from_utf8_lossy(&validated_msg) - ); + } = validate_msg(&decrypted_msg, &contract_hash, None, None)?; let mut engine = start_engine( context, @@ -129,11 +98,15 @@ pub fn init( secret_msg.user_public_key, )?; - let (contract_env_bytes, contract_msg_info_bytes) = - env_to_env_msg_info_bytes(&engine, &mut env_v010)?; + let mut versioned_env = + base_env.into_versioned_env(&engine.contract_instance.cosmwasm_api_version); + + versioned_env.set_contract_hash(&contract_hash); + + let (env_bytes, msg_info_bytes) = versioned_env.get_wasm_ptrs()?; - let env_ptr = engine.write_to_memory(&contract_env_bytes)?; - let msg_info_ptr = engine.write_to_memory(&contract_msg_info_bytes)?; + let env_ptr = engine.write_to_memory(&env_bytes)?; + let msg_info_ptr = engine.write_to_memory(&msg_info_bytes)?; let msg_ptr = engine.write_to_memory(&validated_msg)?; // This wrapper is used to coalesce all errors in this block to one object @@ -141,17 +114,15 @@ pub fn init( let output = coalesce!(EnclaveError, { let vec_ptr = engine.init(env_ptr, msg_info_ptr, msg_ptr)?; let output = engine.extract_vector(vec_ptr)?; - // TODO: copy cosmwasm's structures to enclave - // TODO: ref: https://github.com/CosmWasm/cosmwasm/blob/b971c037a773bf6a5f5d08a88485113d9b9e8e7b/packages/std/src/init_handle.rs#L129 - // TODO: ref: https://github.com/CosmWasm/cosmwasm/blob/b971c037a773bf6a5f5d08a88485113d9b9e8e7b/packages/std/src/query.rs#L13 let output = encrypt_output( output, &secret_msg, &canonical_contract_address, - &env_v010.contract_code_hash, + versioned_env.get_contract_hash(), reply_params, &canonical_sender_address, false, + false, )?; Ok(output) @@ -170,344 +141,14 @@ pub fn init( }) } -pub struct ParsedMessage { - pub should_validate_sig_info: bool, - pub was_msg_encrypted: bool, - pub secret_msg: SecretMessage, - pub decrypted_msg: Vec, - pub contract_hash_for_validation: Option>, -} - -pub fn redact_custom_events(reply: &mut Reply) { - reply.result = match &reply.result { - SubMsgResult::Ok(r) => { - let mut events: Vec = Default::default(); - - let filtered_attributes = vec!["contract_address".to_string(), "code_id".to_string()]; - for ev in r.events.iter() { - if !ev.ty.starts_with("wasm") { - continue; - } - - let mut new_ev = Event { - ty: ev.ty.clone(), - attributes: vec![], - }; - - for attr in &ev.attributes { - if !filtered_attributes.contains(&attr.key) { - new_ev.attributes.push(attr.clone()); - } - } - - if new_ev.attributes.len() > 0 { - events.push(new_ev); - } - } - - SubMsgResult::Ok(SubMsgResponse { - events, - data: r.data.clone(), - }) - } - SubMsgResult::Err(_) => reply.result.clone(), - }; -} - -// Parse the message that was passed to handle (Based on the assumption that it might be a reply or IBC as well) -pub fn parse_message( - message: &[u8], - sig_info: &SigInfo, - handle_type: &HandleType, -) -> Result { - let orig_secret_msg = SecretMessage::from_slice(message)?; - - return match handle_type { - HandleType::HANDLE_TYPE_EXECUTE => { - trace!( - "handle input before decryption: {:?}", - base64::encode(&message) - ); - let decrypted_msg = orig_secret_msg.decrypt()?; - Ok(ParsedMessage { - should_validate_sig_info: true, - was_msg_encrypted: true, - secret_msg: orig_secret_msg, - decrypted_msg, - contract_hash_for_validation: None, - }) - } - - HandleType::HANDLE_TYPE_REPLY => { - if sig_info.sign_mode == SignMode::SIGN_MODE_UNSPECIFIED { - trace!("reply input is not encrypted"); - let decrypted_msg = orig_secret_msg.msg.clone(); - let mut reply: Reply = serde_json::from_slice(&decrypted_msg) - .map_err(|err| { - warn!( - "reply got an error while trying to deserialize decrypted reply bytes into json {:?}: {}", - String::from_utf8_lossy(&decrypted_msg), - err - ); - EnclaveError::FailedToDeserialize - })?; - - let msg_id = String::from_utf8(reply.id.as_slice().to_vec()).map_err(|err| { - warn!( - "Failed to parse message id as string {:?}: {}", - reply.id.as_slice().to_vec(), - err - ); - EnclaveError::FailedToDeserialize - })?; - - let msg_id_as_num = match msg_id.parse::() { - Ok(m) => m, - Err(err) => { - warn!("Failed to parse message id as number {}: {}", msg_id, err); - return Err(EnclaveError::FailedToDeserialize); - } - }; - - let decrypted_reply = DecryptedReply { - id: msg_id_as_num, - result: reply.result.clone(), - }; - - redact_custom_events(&mut reply); - let serialized_encrypted_reply : Vec = serde_json::to_vec(&reply).map_err(|err| { - warn!( - "got an error while trying to serialize encrypted reply into bytes {:?}: {}", - reply, err - ); - EnclaveError::FailedToSerialize - })?; - - let reply_secret_msg = SecretMessage { - nonce: orig_secret_msg.nonce, - user_public_key: orig_secret_msg.user_public_key, - msg: serialized_encrypted_reply, - }; - - let serialized_reply: Vec = serde_json::to_vec(&decrypted_reply).map_err(|err| { - warn!( - "got an error while trying to serialize decrypted reply into bytes {:?}: {}", - decrypted_reply, err - ); - EnclaveError::FailedToSerialize - })?; - - return Ok(ParsedMessage { - should_validate_sig_info: false, - was_msg_encrypted: false, - secret_msg: reply_secret_msg, - decrypted_msg: serialized_reply, - contract_hash_for_validation: None, - }); - } - - // Here we are sure the reply is OK because only OK is encrypted - trace!( - "reply input before decryption: {:?}", - base64::encode(&message) - ); - let mut parsed_encrypted_reply: Reply = serde_json::from_slice( - &orig_secret_msg.msg.as_slice().to_vec(), - ) - .map_err(|err| { - warn!( - "reply got an error while trying to deserialize msg input bytes into json {:?}: {}", - String::from_utf8_lossy(&orig_secret_msg.msg), - err - ); - EnclaveError::FailedToDeserialize - })?; - - match parsed_encrypted_reply.result.clone() { - SubMsgResult::Ok(response) => { - let decrypted_msg_data = match response.data { - Some(data) => { - let tmp_secret_msg_data = SecretMessage { - nonce: orig_secret_msg.nonce, - user_public_key: orig_secret_msg.user_public_key, - msg: data.as_slice().to_vec(), - }; - - Some(Binary( - tmp_secret_msg_data.decrypt()?[HEX_ENCODED_HASH_SIZE..].to_vec(), - )) - } - None => None, - }; - - let tmp_secret_msg_id = SecretMessage { - nonce: orig_secret_msg.nonce, - user_public_key: orig_secret_msg.user_public_key, - msg: parsed_encrypted_reply.id.as_slice().to_vec(), - }; - - let tmp_decrypted_msg_id = tmp_secret_msg_id.decrypt()?; - - // Now we need to create synthetic SecretMessage to fit the API in "handle" - let result = SubMsgResult::Ok(SubMsgResponse { - events: response.events, - data: decrypted_msg_data, - }); - - let msg_id = - String::from_utf8(tmp_decrypted_msg_id[HEX_ENCODED_HASH_SIZE..].to_vec()) - .map_err(|err| { - warn!( - "Failed to parse message id as string {:?}: {}", - tmp_decrypted_msg_id[HEX_ENCODED_HASH_SIZE..].to_vec(), - err - ); - EnclaveError::FailedToDeserialize - })?; - - let msg_id_as_num = match msg_id.parse::() { - Ok(m) => m, - Err(err) => { - warn!("Failed to parse message id as number {}: {}", msg_id, err); - return Err(EnclaveError::FailedToDeserialize); - } - }; - - let decrypted_reply = DecryptedReply { - id: msg_id_as_num, - result, - }; - - let decrypted_reply_as_vec = - serde_json::to_vec(&decrypted_reply).map_err(|err| { - warn!( - "got an error while trying to serialize reply into bytes {:?}: {}", - decrypted_reply, err - ); - EnclaveError::FailedToSerialize - })?; - - redact_custom_events(&mut parsed_encrypted_reply); - let serialized_encrypted_reply : Vec = serde_json::to_vec(&parsed_encrypted_reply).map_err(|err| { - warn!( - "got an error while trying to serialize encrypted reply into bytes {:?}: {}", - parsed_encrypted_reply, err - ); - EnclaveError::FailedToSerialize - })?; - - let reply_secret_msg = SecretMessage { - nonce: orig_secret_msg.nonce, - user_public_key: orig_secret_msg.user_public_key, - msg: serialized_encrypted_reply, - }; - - Ok(ParsedMessage { - should_validate_sig_info: true, - was_msg_encrypted: true, - secret_msg: reply_secret_msg, - decrypted_msg: decrypted_reply_as_vec, - contract_hash_for_validation: Some( - tmp_decrypted_msg_id[..HEX_ENCODED_HASH_SIZE].to_vec(), - ), - }) - } - SubMsgResult::Err(response) => { - let secret_msg = SecretMessage { - nonce: orig_secret_msg.nonce, - user_public_key: orig_secret_msg.user_public_key, - msg: base64::decode(response.clone()).map_err(|err| { - warn!( - "got an error while trying to serialize err reply from base64 {:?}: {}", - response, err - ); - EnclaveError::FailedToSerialize - })? - }; - - let decrypted_error = secret_msg.decrypt()?; - - let tmp_secret_msg_id = SecretMessage { - nonce: orig_secret_msg.nonce, - user_public_key: orig_secret_msg.user_public_key, - msg: parsed_encrypted_reply.id.as_slice().to_vec(), - }; - - let tmp_decrypted_msg_id = tmp_secret_msg_id.decrypt()?; - - // Now we need to create synthetic SecretMessage to fit the API in "handle" - let result = SubMsgResult::Err( - String::from_utf8(decrypted_error[HEX_ENCODED_HASH_SIZE..].to_vec()) - .map_err(|err| { - warn!( - "Failed to parse error as string {:?}: {}", - decrypted_error[HEX_ENCODED_HASH_SIZE..].to_vec(), - err - ); - EnclaveError::FailedToDeserialize - })?, - ); - - let msg_id = - String::from_utf8(tmp_decrypted_msg_id[HEX_ENCODED_HASH_SIZE..].to_vec()) - .map_err(|err| { - warn!( - "Failed to parse message id as string {:?}: {}", - tmp_decrypted_msg_id[HEX_ENCODED_HASH_SIZE..].to_vec(), - err - ); - EnclaveError::FailedToDeserialize - })?; - - let msg_id_as_num = match msg_id.parse::() { - Ok(m) => m, - Err(err) => { - warn!("Failed to parse message id as number {}: {}", msg_id, err); - return Err(EnclaveError::FailedToDeserialize); - } - }; - - let decrypted_reply = DecryptedReply { - id: msg_id_as_num, - result, - }; - - let decrypted_reply_as_vec = - serde_json::to_vec(&decrypted_reply).map_err(|err| { - warn!( - "got an error while trying to serialize reply into bytes {:?}: {}", - decrypted_reply, err - ); - EnclaveError::FailedToSerialize - })?; - - let serialized_encrypted_reply : Vec = serde_json::to_vec(&parsed_encrypted_reply).map_err(|err| { - warn!( - "got an error while trying to serialize encrypted reply into bytes {:?}: {}", - parsed_encrypted_reply, err - ); - EnclaveError::FailedToSerialize - })?; - - let reply_secret_msg = SecretMessage { - nonce: orig_secret_msg.nonce, - user_public_key: orig_secret_msg.user_public_key, - msg: serialized_encrypted_reply, - }; - - Ok(ParsedMessage { - should_validate_sig_info: true, - was_msg_encrypted: true, - secret_msg: reply_secret_msg, - decrypted_msg: decrypted_reply_as_vec, - contract_hash_for_validation: Some( - tmp_decrypted_msg_id[..HEX_ENCODED_HASH_SIZE].to_vec(), - ), - }) - } - } - } - }; +fn to_canonical(contract_address: &BaseAddr) -> Result { + CanonicalAddr::from_human(contract_address).map_err(|err| { + warn!( + "error while trying to deserialize address from bech32 string to bytes {:?}: {}", + contract_address, err + ); + EnclaveError::FailedToDeserialize + }) } #[cfg_attr(feature = "cargo-clippy", allow(clippy::too_many_arguments))] @@ -521,51 +162,22 @@ pub fn handle( sig_info: &[u8], handle_type: u8, ) -> Result { + trace!("Starting handle"); + let contract_code = ContractCode::new(contract); + let contract_hash = contract_code.hash(); - let mut env_v010: cosmwasm_v010_types::types::Env = - serde_json::from_slice(env).map_err(|err| { - warn!( - "handle got an error while trying to deserialize env input bytes into json {:?}: {}", - env, err - ); - EnclaveError::FailedToDeserialize - })?; - env_v010.contract_code_hash = hex::encode(contract_code.hash()); + let base_env: BaseEnv = extract_base_env(env)?; - trace!("handle env_v010: {:?}", env_v010); + let (sender, contract_address, _, sent_funds) = base_env.get_verification_params(); - let canonical_contract_address = CanonicalAddr::from_human(&env_v010.contract.address).map_err(|err| { - warn!( - "got an error while trying to deserialize env_v010.contract.address from bech32 string to bytes {:?}: {}", - env_v010.contract.address, err - ); - EnclaveError::FailedToDeserialize - })?; + let canonical_contract_address = to_canonical(contract_address)?; - let canonical_sender_address = CanonicalAddr::from_human(&env_v010.message.sender).map_err(|err| { - warn!( - "init got an error while trying to deserialize env_v010.message.sender from bech32 string to bytes {:?}: {}", - env_v010.message.sender, err - ); - EnclaveError::FailedToDeserialize - })?; + let contract_key = base_env.get_contract_key()?; - let contract_key = extract_contract_key(&env_v010)?; + validate_contract_key(&contract_key, &canonical_contract_address, &contract_code)?; - if !validate_contract_key(&contract_key, &canonical_contract_address, &contract_code) { - warn!("got an error while trying to deserialize output bytes"); - return Err(EnclaveError::FailedContractAuthentication); - } - - let parsed_sig_info: SigInfo = serde_json::from_slice(sig_info).map_err(|err| { - warn!( - "handle got an error while trying to deserialize sig info input bytes into json {:?}: {}", - String::from_utf8_lossy(&sig_info), - err - ); - EnclaveError::FailedToDeserialize - })?; + let parsed_sig_info: SigInfo = extract_sig_info(sig_info)?; // The flow of handle is now used for multiple messages (such ash Handle, Reply) // When the message is handle, we expect it always to be encrypted while in Reply for example it might be plaintext @@ -574,18 +186,31 @@ pub fn handle( let ParsedMessage { should_validate_sig_info, was_msg_encrypted, + should_encrypt_output, secret_msg, decrypted_msg, contract_hash_for_validation, } = parse_message(msg, &parsed_sig_info, &parsed_handle_type)?; + let canonical_sender_address = match to_canonical(sender) { + Ok(can) => can, + Err(_) => CanonicalAddr::from_vec(vec![]), + }; + // There is no signature to verify when the input isn't signed. // Receiving unsigned messages is only possible in Handle. (Init tx are always signed) // All of these functions go through handle but the data isn't signed: // Reply (that is not WASM reply) if should_validate_sig_info { // Verify env parameters against the signed tx - verify_params(&parsed_sig_info, &env_v010, &secret_msg)?; + + verify_params( + &parsed_sig_info, + sent_funds, + &canonical_sender_address, + contract_address, + &secret_msg, + )?; } let mut validated_msg = decrypted_msg.clone(); @@ -593,22 +218,14 @@ pub fn handle( if was_msg_encrypted { let x = validate_msg( &decrypted_msg, - contract_code.hash(), + &contract_hash, contract_hash_for_validation, + Some(parsed_handle_type.clone()), )?; validated_msg = x.validated_msg; reply_params = x.reply_params; } - trace!( - "handle input afer decryption: {:?}", - String::from_utf8_lossy(&validated_msg) - ); - - trace!("Successfully authenticated the contract!"); - - trace!("Handle: Contract Key: {:?}", hex::encode(contract_key)); - // Although the operation here is not always handle it is irrelevant in this case // because it only helps to decide whether to check floating points or not // In this case we want to do the same as in Handle both for Reply and for others so we can always pass "Handle". @@ -622,34 +239,61 @@ pub fn handle( secret_msg.user_public_key, )?; - let (contract_env_bytes, contract_msg_info_bytes) = - env_to_env_msg_info_bytes(&engine, &mut env_v010)?; + let mut versioned_env = base_env + .clone() + .into_versioned_env(&engine.contract_instance.cosmwasm_api_version); + + versioned_env.set_contract_hash(&contract_hash); - let env_ptr = engine.write_to_memory(&contract_env_bytes)?; - let msg_info_ptr = engine.write_to_memory(&contract_msg_info_bytes)?; + let (env_bytes, msg_info_bytes) = versioned_env.get_wasm_ptrs()?; + + let env_ptr = engine.write_to_memory(&env_bytes)?; + let msg_info_ptr = engine.write_to_memory(&msg_info_bytes)?; let msg_ptr = engine.write_to_memory(&validated_msg)?; // This wrapper is used to coalesce all errors in this block to one object // so we can `.map_err()` in one place for all of them let output = coalesce!(EnclaveError, { - let vec_ptr = engine.handle(env_ptr, msg_info_ptr, msg_ptr, parsed_handle_type)?; + let vec_ptr = engine.handle(env_ptr, msg_info_ptr, msg_ptr, parsed_handle_type.clone())?; - let output = engine.extract_vector(vec_ptr)?; + let mut output = engine.extract_vector(vec_ptr)?; debug!( "(2) nonce just before encrypt_output: nonce = {:?} pubkey = {:?}", secret_msg.nonce, secret_msg.user_public_key ); - let output = encrypt_output( - output, - &secret_msg, - &canonical_contract_address, - &env_v010.contract_code_hash, - reply_params, - &canonical_sender_address, - false, - )?; + if should_encrypt_output { + output = encrypt_output( + output, + &secret_msg, + &canonical_contract_address, + versioned_env.get_contract_hash(), + reply_params, + &canonical_sender_address, + false, + is_ibc_msg(parsed_handle_type.clone()), + )?; + } else { + let mut raw_output = manipulate_callback_sig_for_plaintext(output)?; + set_all_logs_to_plaintext(&mut raw_output); + + let finalized_output = + finalize_raw_output(raw_output, false, is_ibc_msg(parsed_handle_type), false); + trace!( + "Wasm output for plaintext message is: {:?}", + finalized_output + ); + + output = serde_json::to_vec(&finalized_output).map_err(|err| { + debug!( + "got an error while trying to serialize output json into bytes {:?}: {}", + finalized_output, err + ); + EnclaveError::FailedToSerialize + })?; + } + Ok(output) }) .map_err(|err| { @@ -661,6 +305,17 @@ pub fn handle( Ok(HandleSuccess { output }) } +fn extract_sig_info(sig_info: &[u8]) -> Result { + serde_json::from_slice(sig_info).map_err(|err| { + warn!( + "handle got an error while trying to deserialize sig info input bytes into json {:?}: {}", + String::from_utf8_lossy(&sig_info), + err + ); + EnclaveError::FailedToDeserialize + }) +} + pub fn query( context: Ctx, gas_limit: u64, @@ -669,47 +324,26 @@ pub fn query( env: &[u8], msg: &[u8], ) -> Result { + trace!("Entered query"); + let contract_code = ContractCode::new(contract); + let contract_hash = contract_code.hash(); - let mut env_v010: cosmwasm_v010_types::types::Env = - serde_json::from_slice(env).map_err(|err| { - warn!( - "query got an error while trying to deserialize env input bytes into json {:?}: {}", - env, err - ); - EnclaveError::FailedToDeserialize - })?; - env_v010.contract_code_hash = hex::encode(contract_code.hash()); + let base_env: BaseEnv = extract_base_env(env)?; - trace!("query env_v010: {:?}", env_v010); + let (_, contract_address, _, _) = base_env.get_verification_params(); - let canonical_contract_address = CanonicalAddr::from_human(&env_v010.contract.address).map_err(|err| { - warn!( - "got an error while trying to deserialize env_v010.contract.address from bech32 string to bytes {:?}: {}", - env_v010.contract.address, err - ); - EnclaveError::FailedToDeserialize - })?; - - let contract_key = extract_contract_key(&env_v010)?; + let canonical_contract_address = to_canonical(contract_address)?; - if !validate_contract_key(&contract_key, &canonical_contract_address, &contract_code) { - warn!("query got an error while trying to validate contract key"); - return Err(EnclaveError::FailedContractAuthentication); - } + let contract_key = base_env.get_contract_key()?; - trace!("successfully authenticated the contract!"); - trace!("query contract key: {:?}", hex::encode(contract_key)); + validate_contract_key(&contract_key, &canonical_contract_address, &contract_code)?; - trace!("query input before decryption: {:?}", base64::encode(&msg)); let secret_msg = SecretMessage::from_slice(msg)?; let decrypted_msg = secret_msg.decrypt()?; - trace!( - "query input afer decryption: {:?}", - String::from_utf8_lossy(&decrypted_msg) - ); + let ValidatedMessage { validated_msg, .. } = - validate_msg(&decrypted_msg, contract_code.hash(), None)?; + validate_msg(&decrypted_msg, &contract_hash, None, None)?; let mut engine = start_engine( context, @@ -721,10 +355,14 @@ pub fn query( secret_msg.user_public_key, )?; - let (contract_env_bytes, _ /* no msg_info in query */) = - env_to_env_msg_info_bytes(&engine, &mut env_v010)?; + let mut versioned_env = + base_env.into_versioned_env(&engine.contract_instance.cosmwasm_api_version); + + versioned_env.set_contract_hash(&contract_hash); - let env_ptr = engine.write_to_memory(&contract_env_bytes)?; + let (env_bytes, _) = versioned_env.get_wasm_ptrs()?; + + let env_ptr = engine.write_to_memory(&env_bytes)?; let msg_ptr = engine.write_to_memory(&validated_msg)?; // This wrapper is used to coalesce all errors in this block to one object @@ -742,6 +380,7 @@ pub fn query( None, // Not used for queries (Query response is not replied to the caller), &CanonicalAddr(Binary(Vec::new())), // Not used for queries (used only for replies) true, + false, )?; Ok(output) }) @@ -782,80 +421,18 @@ fn start_engine( Ok(Engine::new(contract_instance, module)) } -fn env_to_env_msg_info_bytes( - engine: &Engine, - env_v010: &mut cosmwasm_v010_types::types::Env, -) -> Result<(Vec, Vec), EnclaveError> { - match engine.contract_instance.cosmwasm_api_version { - CosmWasmApiVersion::V010 => { - // Assaf: contract_key is irrelevant inside the contract, - // but existing v0.10 contracts might expect it to be populated :facepalm:, - // therefore we are going to leave it populated :shrug:. - // env_v010.contract_key = None; - - // in v0.10 the timestamp passed from Go was unix time in seconds - // 10.16 time is unix time in nanoseconds, so now Go passes here unix time in nanoseconds - // but v0.10 contracts still expect time to be in unix seconds, - // so we need to convert it from nanoseconds to seconds - env_v010.block.time = Timestamp::from_nanos(env_v010.block.time).seconds(); - - let env_v010_bytes = serde_json::to_vec(env_v010).map_err(|err| { - warn!( - "got an error while trying to serialize env_v010 (cosmwasm v0.10) into bytes {:?}: {}", - env_v010, err - ); - EnclaveError::FailedToSerialize - })?; - - let msg_info_v010_bytes: Vec = vec![]; // in v0.10 msg_info is inside env - - Ok((env_v010_bytes, msg_info_v010_bytes)) - } - CosmWasmApiVersion::V1 => { - let env_v1 = enclave_cosmwasm_v1_types::types::Env { - block: enclave_cosmwasm_v1_types::types::BlockInfo { - height: env_v010.block.height, - time: Timestamp::from_nanos(env_v010.block.time), - chain_id: env_v010.block.chain_id.clone(), - }, - contract: enclave_cosmwasm_v1_types::types::ContractInfo { - address: Addr(env_v010.contract.address.0.clone()), - code_hash: env_v010.contract_code_hash.clone(), - }, - }; - - let env_v1_bytes = serde_json::to_vec(&env_v1).map_err(|err| { - warn!( - "got an error while trying to serialize env_v1 (CosmWasm v1) into bytes {:?}: {}", - env_v1, err - ); - EnclaveError::FailedToSerialize - })?; - - let msg_info_v1 = enclave_cosmwasm_v1_types::types::MessageInfo { - sender: Addr(env_v010.message.sender.0.clone()), - funds: env_v010 - .message - .sent_funds - .iter() - .map(|coin| { - enclave_cosmwasm_v1_types::coins::Coin::new( - coin.amount.u128(), - coin.denom.clone(), - ) - }) - .collect::>(), - }; - - let msg_info_v1_bytes = serde_json::to_vec(&msg_info_v1).map_err(|err| { - warn!( - "got an error while trying to serialize msg_info_v1 (CosmWasm v1) into bytes {:?}: {}", - msg_info_v1, err - ); - EnclaveError::FailedToSerialize - })?; - - Ok((env_v1_bytes, msg_info_v1_bytes)) - } - } +fn extract_base_env(env: &[u8]) -> Result { + serde_json::from_slice(env) + .map_err(|err| { + warn!( + "error while deserializing env into json {:?}: {}", + String::from_utf8_lossy(&env), + err + ); + EnclaveError::FailedToDeserialize + }) + .map(|base_env| { + trace!("base env: {:?}", base_env); + base_env + }) } diff --git a/cosmwasm/enclaves/shared/contract-engine/src/contract_validation.rs b/cosmwasm/enclaves/shared/contract-engine/src/contract_validation.rs index 4faf8d350..b2fe47d8f 100644 --- a/cosmwasm/enclaves/shared/contract-engine/src/contract_validation.rs +++ b/cosmwasm/enclaves/shared/contract-engine/src/contract_validation.rs @@ -1,17 +1,18 @@ -use enclave_cosmwasm_v1_types::results::REPLY_ENCRYPTION_MAGIC_BYTES; +use cw_types_v1::ibc::IbcPacketReceiveMsg; +use cw_types_v1::results::REPLY_ENCRYPTION_MAGIC_BYTES; use log::*; -use enclave_ffi_types::EnclaveError; - +use cw_types_v010::types::{CanonicalAddr, Coin, HumanAddr}; use enclave_cosmos_types::traits::CosmosAminoPubkey; use enclave_cosmos_types::types::{ - ContractCode, CosmWasmMsg, CosmosPubKey, SigInfo, SignDoc, StdSignDoc, + ContractCode, CosmWasmMsg, CosmosPubKey, HandleType, SigInfo, SignDoc, StdSignDoc, }; -use enclave_cosmwasm_v010_types::types::{CanonicalAddr, Coin, Env, HumanAddr}; use enclave_crypto::traits::VerifyingKey; use enclave_crypto::{sha_256, AESKey, Hmac, Kdf, HASH_SIZE, KEY_MANAGER}; +use enclave_ffi_types::EnclaveError; use crate::io::create_callback_signature; +use crate::message::is_ibc_msg; use crate::types::SecretMessage; pub type ContractKey = [u8; CONTRACT_KEY_LENGTH]; @@ -22,66 +23,33 @@ const HEX_ENCODED_HASH_SIZE: usize = HASH_SIZE * 2; const SIZE_OF_U64: usize = 8; pub fn generate_encryption_key( - env: &Env, - contract_hash: [u8; HASH_SIZE], - contract_address: &[u8], + sender: &CanonicalAddr, + block_height: &u64, + contract_hash: &[u8; HASH_SIZE], + contract_address: &CanonicalAddr, ) -> Result<[u8; CONTRACT_KEY_LENGTH], EnclaveError> { let consensus_state_ikm = KEY_MANAGER.get_consensus_state_ikm().unwrap(); - let (_, sender_address_u5) = bech32::decode(env.message.sender.as_str()).map_err(|err| { - warn!( - "got an error while trying to deserialize env.message.sender from bech32 string to bytes {:?}: {}", - env.message.sender, err - ); - EnclaveError::FailedToDeserialize - })?; - let snder_address: Vec = sender_address_u5.iter().map(|x| x.to_u8()).collect(); - - let sender_id = generate_sender_id(&snder_address, env.block.height as u64); + let sender_id = generate_sender_id(&(sender.0).0, block_height); let mut encryption_key = [0u8; 64]; let authenticated_contract_id = generate_contract_id( &consensus_state_ikm, &sender_id, - &contract_hash, - contract_address, + contract_hash, + &(contract_address.0).0, ); encryption_key[0..32].copy_from_slice(&sender_id); encryption_key[32..].copy_from_slice(&authenticated_contract_id); - Ok(encryption_key) -} - -pub fn extract_contract_key(env: &Env) -> Result<[u8; CONTRACT_KEY_LENGTH], EnclaveError> { - if env.contract_key.is_none() { - warn!("Contract execute with empty contract key"); - return Err(EnclaveError::FailedContractAuthentication); - } - - let contract_key = - base64::decode(env.contract_key.as_ref().unwrap().as_bytes()).map_err(|err| { - warn!( - "got an error while trying to deserialize output bytes into json {:?}: {}", - env, err - ); - EnclaveError::FailedContractAuthentication - })?; - - if contract_key.len() != CONTRACT_KEY_LENGTH { - warn!("Contract execute with empty contract key"); - return Err(EnclaveError::FailedContractAuthentication); - } - - let mut key_as_bytes = [0u8; CONTRACT_KEY_LENGTH]; + trace!("contract key: {:?}", hex::encode(encryption_key)); - key_as_bytes.copy_from_slice(&contract_key); - - Ok(key_as_bytes) + Ok(encryption_key) } -pub fn generate_sender_id(msg_sender: &[u8], block_height: u64) -> [u8; HASH_SIZE] { +pub fn generate_sender_id(msg_sender: &[u8], block_height: &u64) -> [u8; HASH_SIZE] { let mut input_data = msg_sender.to_vec(); input_data.extend_from_slice(&block_height.to_be_bytes()); sha_256(&input_data) @@ -105,7 +73,7 @@ pub fn validate_contract_key( contract_key: &[u8; CONTRACT_KEY_LENGTH], contract_address: &CanonicalAddr, contract_code: &ContractCode, -) -> bool { +) -> Result<(), EnclaveError> { // parse contract key -> < signer_id || authentication_code > let mut signer_id: [u8; HASH_SIZE] = [0u8; HASH_SIZE]; signer_id.copy_from_slice(&contract_key[0..HASH_SIZE]); @@ -130,7 +98,13 @@ pub fn validate_contract_key( contract_address.as_slice(), ); - calculated_authentication_id == expected_authentication_id + if calculated_authentication_id == expected_authentication_id { + trace!("Successfully authenticated the contract!"); + Ok(()) + } else { + warn!("got an error while trying to deserialize output bytes"); + Err(EnclaveError::FailedContractAuthentication) + } } pub struct ValidatedMessage { @@ -146,7 +120,65 @@ pub struct ReplyParams { /// Validate that the message sent to the enclave (after decryption) was actually addressed to this contract. pub fn validate_msg( msg: &[u8], - contract_hash: [u8; HASH_SIZE], + contract_hash: &[u8; HASH_SIZE], + contract_hash_for_validation: Option>, + handle_type: Option, +) -> Result { + match handle_type { + None => validate_basic_msg(msg, contract_hash, contract_hash_for_validation), + Some(h) => match is_ibc_msg(h.clone()) { + false => validate_basic_msg(msg, contract_hash, contract_hash_for_validation), + true => validate_ibc_msg(msg, contract_hash, contract_hash_for_validation, h), + }, + } +} + +pub fn validate_ibc_msg( + msg: &[u8], + contract_hash: &[u8; HASH_SIZE], + contract_hash_for_validation: Option>, + handle_type: HandleType, +) -> Result { + match handle_type { + HandleType::HANDLE_TYPE_IBC_PACKET_RECEIVE => { + let mut parsed_ibc_packet: IbcPacketReceiveMsg = + serde_json::from_slice(&msg.to_vec()).map_err(|err| { + warn!( + "IbcPacketReceive msg got an error while trying to deserialize msg input bytes into json {:?}: {}", + String::from_utf8_lossy(&msg), + err + ); + EnclaveError::FailedToDeserialize + })?; + + let validated_msg = validate_basic_msg( + parsed_ibc_packet.packet.data.as_slice(), + contract_hash, + contract_hash_for_validation, + )?; + parsed_ibc_packet.packet.data = validated_msg.validated_msg.as_slice().into(); + + Ok(ValidatedMessage{ + validated_msg: serde_json::to_vec(&parsed_ibc_packet).map_err(|err| { + warn!( + "got an error while trying to serialize parsed_ibc_packet msg into bytes {:?}: {}", + parsed_ibc_packet, err + ); + EnclaveError::FailedToSerialize + })?, + reply_params: validated_msg.reply_params, + }) + } + _ => { + warn!("Malformed message - in IBC, only packet receive message can be encrypted"); + Err(EnclaveError::ValidationFailure) + } + } +} + +pub fn validate_basic_msg( + msg: &[u8], + contract_hash: &[u8; HASH_SIZE], contract_hash_for_validation: Option>, ) -> Result { if contract_hash_for_validation.is_none() && msg.len() < HEX_ENCODED_HASH_SIZE { @@ -210,19 +242,16 @@ pub fn validate_msg( /// Verify all the parameters sent to the enclave match up, and were signed by the right account. pub fn verify_params( sig_info: &SigInfo, - env: &Env, + sent_funds: &[Coin], + sender: &CanonicalAddr, + contract_address: &HumanAddr, msg: &SecretMessage, ) -> Result<(), EnclaveError> { info!("Verifying message signatures for: {:?}", sig_info); // If there's no callback signature - it's not a callback and there has to be a tx signer + signature if let Some(callback_sig) = &sig_info.callback_sig { - return verify_callback_sig( - callback_sig.as_slice(), - &env.message.sender, - msg, - &env.message.sent_funds, - ); + return verify_callback_sig(callback_sig.as_slice(), sender, msg, sent_funds); } trace!( @@ -230,7 +259,7 @@ pub fn verify_params( String::from_utf8_lossy(sig_info.sign_bytes.as_slice()) ); - let (sender_public_key, messages) = get_signer_and_messages(sig_info, env)?; + let (sender_public_key, messages) = get_signer_and_messages(sig_info, sender)?; trace!( "sender canonical address is: {:?}", @@ -243,13 +272,21 @@ pub fn verify_params( .verify_bytes( sig_info.sign_bytes.as_slice(), sig_info.signature.as_slice(), + sig_info.sign_mode, ) .map_err(|err| { warn!("Signature verification failed: {:?}", err); EnclaveError::FailedTxVerification })?; - if verify_message_params(&messages, env, &sender_public_key, msg) { + if verify_message_params( + &messages, + sender, + sent_funds, + contract_address, + &sender_public_key, + msg, + ) { info!("Parameters verified successfully"); return Ok(()); } @@ -261,7 +298,7 @@ pub fn verify_params( fn get_signer_and_messages( sign_info: &SigInfo, - env: &Env, + sender: &CanonicalAddr, ) -> Result<(CosmosPubKey, Vec), EnclaveError> { use cosmos_proto::tx::signing::SignMode::*; match sign_info.sign_mode { @@ -269,15 +306,6 @@ fn get_signer_and_messages( let sign_doc = SignDoc::from_bytes(sign_info.sign_bytes.as_slice())?; trace!("sign doc: {:?}", sign_doc); - let sender = CanonicalAddr::from_human(&env.message.sender).map_err(|err| { - warn!( - "failed to canonicalize message sender: {} {}", - env.message.sender, err - ); - EnclaveError::FailedTxVerification - })?; - trace!("sender canonical address is: {:?}", sender.0.0); - // This verifies that signatures and sign bytes are self consistent let sender_public_key = sign_doc @@ -290,7 +318,7 @@ fn get_signer_and_messages( Ok((sender_public_key.clone(), sign_doc.body.messages)) } - SIGN_MODE_LEGACY_AMINO_JSON => { + SIGN_MODE_LEGACY_AMINO_JSON | SIGN_MODE_EIP_191 => { use protobuf::well_known_types::Any as AnyProto; use protobuf::Message; @@ -327,16 +355,11 @@ fn get_signer_and_messages( ///This is used when contracts send callbacks to each other. fn verify_callback_sig( callback_signature: &[u8], - sender: &HumanAddr, + sender: &CanonicalAddr, msg: &SecretMessage, sent_funds: &[Coin], ) -> Result<(), EnclaveError> { - if verify_callback_sig_impl( - callback_signature, - &CanonicalAddr::from_human(sender).or(Err(EnclaveError::FailedToSerialize))?, - msg, - sent_funds, - ) { + if verify_callback_sig_impl(callback_signature, sender, msg, sent_funds) { info!("Message verified! msg.sender is the calling contract"); return Ok(()); } @@ -387,16 +410,16 @@ fn get_verified_msg<'sd>( } /// Check that the contract listed in the cosmwasm message matches the one in env -fn verify_contract(msg: &CosmWasmMsg, env: &Env) -> bool { +fn verify_contract(msg: &CosmWasmMsg, contract_address: &HumanAddr) -> bool { // Contract address is relevant only to execute, since during sending an instantiate message the contract address is not yet known match msg { CosmWasmMsg::Execute { contract, .. } => { info!("Verifying contract address.."); - let is_verified = env.contract.address == *contract; + let is_verified = contract_address == contract; if !is_verified { trace!( "Contract address sent to enclave {:?} is not the same as the signed one {:?}", - env.contract.address, + contract_address, *contract ); } @@ -408,36 +431,38 @@ fn verify_contract(msg: &CosmWasmMsg, env: &Env) -> bool { } /// Check that the funds listed in the cosmwasm message matches the ones in env -fn verify_funds(msg: &CosmWasmMsg, env: &Env) -> bool { +fn verify_funds(msg: &CosmWasmMsg, sent_funds_msg: &[Coin]) -> bool { match msg { CosmWasmMsg::Execute { sent_funds, .. } | CosmWasmMsg::Instantiate { init_funds: sent_funds, .. - } => &env.message.sent_funds == sent_funds, + } => sent_funds_msg == sent_funds, CosmWasmMsg::Other => false, } } fn verify_message_params( messages: &[CosmWasmMsg], - env: &Env, + sender: &CanonicalAddr, + sent_funds: &[Coin], + contract_address: &HumanAddr, signer_public_key: &CosmosPubKey, sent_msg: &SecretMessage, ) -> bool { info!("Verifying sender.."); - let msg_sender = match CanonicalAddr::from_human(&env.message.sender) { - Ok(msg_sender) => msg_sender, - _ => return false, - }; + // let msg_sender = match CanonicalAddr::from_human(&env.message.sender) { + // Ok(msg_sender) => msg_sender, + // _ => return false, + // }; let signer_addr = signer_public_key.get_address(); - if signer_addr != msg_sender { + if &signer_addr != sender { warn!("Sender verification failed!"); trace!( "Message sender {:?} does not match with the message signer {:?}", - msg_sender, + sender, signer_addr ); return false; @@ -446,13 +471,13 @@ fn verify_message_params( info!("Verifying message.."); // If msg is not found (is None) then it means message verification failed, // since it didn't find a matching signed message - let msg = get_verified_msg(messages, &msg_sender, sent_msg); + let msg = get_verified_msg(messages, sender, sent_msg); if msg.is_none() { warn!("Message verification failed!"); trace!( "Message sent to contract {:?} by {:?} does not match any signed messages {:?}", sent_msg.to_vec(), - msg_sender, + sender, messages ); return false; @@ -467,13 +492,13 @@ fn verify_message_params( return false; } - if !verify_contract(msg, env) { + if !verify_contract(msg, contract_address) { warn!("Contract address verification failed!"); return false; } info!("Verifying funds.."); - if !verify_funds(msg, env) { + if !verify_funds(msg, sent_funds) { warn!("Funds verification failed!"); return false; } diff --git a/cosmwasm/enclaves/shared/contract-engine/src/db.rs b/cosmwasm/enclaves/shared/contract-engine/src/db.rs index fad8a47b6..e5764ba2c 100644 --- a/cosmwasm/enclaves/shared/contract-engine/src/db.rs +++ b/cosmwasm/enclaves/shared/contract-engine/src/db.rs @@ -22,7 +22,7 @@ pub fn write_encrypted_key( let scrambled_field_name = field_name_digest(key, contract_key); - info!( + trace!( "Writing to scrambled field name: {:?}", scrambled_field_name ); @@ -53,7 +53,7 @@ pub fn read_encrypted_key( ) -> Result<(Option>, u64), WasmEngineError> { let scrambled_field_name = field_name_digest(key, contract_key); - info!( + trace!( "Reading from scrambled field name: {:?}", scrambled_field_name ); @@ -82,7 +82,7 @@ pub fn remove_encrypted_key( ) -> Result { let scrambled_field_name = field_name_digest(key, contract_key); - info!("Removing scrambled field name: {:?}", scrambled_field_name); + trace!("Removing scrambled field name: {:?}", scrambled_field_name); // Call remove_db (this bubbles up to Tendermint via ocalls and FFI to Go code) // fn remove_db(context: Ctx, key: &[u8]) { diff --git a/cosmwasm/enclaves/shared/contract-engine/src/io.rs b/cosmwasm/enclaves/shared/contract-engine/src/io.rs index 4ddcc6e8f..f0c284535 100644 --- a/cosmwasm/enclaves/shared/contract-engine/src/io.rs +++ b/cosmwasm/enclaves/shared/contract-engine/src/io.rs @@ -5,9 +5,9 @@ use crate::contract_validation::ReplyParams; /// that is unique to the user and the enclave /// use super::types::{IoNonce, SecretMessage}; -use enclave_cosmwasm_v010_types::encoding::Binary; -use enclave_cosmwasm_v010_types::types::{CanonicalAddr, Coin}; -use enclave_cosmwasm_v1_types::results::{Event, Reply, ReplyOn, SubMsgResponse, SubMsgResult}; +use cw_types_v010::encoding::Binary; +use cw_types_v010::types::{CanonicalAddr, Coin, LogAttribute}; +use cw_types_v1::results::{Event, Reply, ReplyOn, SubMsgResponse, SubMsgResult}; use enclave_ffi_types::EnclaveError; @@ -25,7 +25,7 @@ use sha2::Digest; /// b. Authenticate the reply. #[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] #[serde(untagged)] -enum RawWasmOutput { +pub enum RawWasmOutput { Err { #[serde(rename = "Err")] err: Value, @@ -42,36 +42,68 @@ enum RawWasmOutput { }, OkV010 { #[serde(rename = "Ok")] - ok: enclave_cosmwasm_v010_types::types::ContractResult, + ok: cw_types_v010::types::ContractResult, internal_reply_enclave_sig: Option, internal_msg_id: Option, }, OkV1 { #[serde(rename = "Ok")] - ok: enclave_cosmwasm_v1_types::results::Response, + ok: cw_types_v1::results::Response, internal_reply_enclave_sig: Option, internal_msg_id: Option, }, + OkIBCPacketReceive { + #[serde(rename = "Ok")] + ok: cw_types_v1::ibc::IbcReceiveResponse, + }, + OkIBCOpenChannel { + #[serde(rename = "Ok")] + ok: cw_types_v1::ibc::IbcChannelOpenResponse, + }, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] -struct V010WasmOutput { +pub struct V010WasmOutput { #[serde(rename = "Ok")] - pub ok: Option, + pub ok: Option, #[serde(rename = "Err")] pub err: Option, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] -struct V1WasmOutput { +pub struct V1WasmOutput { #[serde(rename = "Ok")] - pub ok: Option, + pub ok: Option, #[serde(rename = "Err")] pub err: Option, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] -struct QueryOutput { +pub struct IBCOutput { + #[serde(rename = "ok")] + pub ok: Option, + #[serde(rename = "Err")] + pub err: Option, +} + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] +pub struct IBCReceiveOutput { + #[serde(rename = "ok")] + pub ok: Option, + #[serde(rename = "Err")] + pub err: Option, +} + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] +pub struct IBCOpenChannelOutput { + #[serde(rename = "ok")] + pub ok: Option, + #[serde(rename = "Err")] + pub err: Option, +} + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] +pub struct QueryOutput { #[serde(rename = "Ok")] pub ok: Option, #[serde(rename = "Err")] @@ -79,9 +111,12 @@ struct QueryOutput { } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] -struct WasmOutput { +pub struct WasmOutput { pub v010: Option, pub v1: Option, + pub ibc_basic: Option, + pub ibc_packet_receive: Option, + pub ibc_open_channel: Option, pub query: Option, pub internal_reply_enclave_sig: Option, pub internal_msg_id: Option, @@ -154,6 +189,213 @@ fn b64_encode(data: &[u8]) -> String { base64::encode(data) } +pub fn finalize_raw_output( + raw_output: RawWasmOutput, + is_query_output: bool, + is_ibc: bool, + is_msg_encrypted: bool, +) -> WasmOutput { + return match raw_output { + RawWasmOutput::Err { + err, + internal_msg_id, + internal_reply_enclave_sig, + } => { + if is_query_output { + WasmOutput { + v010: None, + v1: None, + ibc_basic: None, + ibc_packet_receive: None, + ibc_open_channel: None, + query: Some(QueryOutput { + ok: None, + err: Some(err), + }), + internal_reply_enclave_sig: None, + internal_msg_id: None, + } + } else { + WasmOutput { + v010: Some(V010WasmOutput { + err: match is_msg_encrypted { + true => Some(err), + false => Some(json!({"generic_err":{"msg":err}})), + }, + ok: None, + }), + v1: None, + ibc_basic: None, + ibc_packet_receive: None, + ibc_open_channel: None, + query: None, + internal_reply_enclave_sig, + internal_msg_id, + } + } + } + RawWasmOutput::OkV010 { + ok, + internal_reply_enclave_sig, + internal_msg_id, + } => WasmOutput { + v010: Some(V010WasmOutput { + err: None, + ok: Some(ok), + }), + v1: None, + ibc_basic: None, + ibc_packet_receive: None, + ibc_open_channel: None, + query: None, + internal_reply_enclave_sig, + internal_msg_id, + }, + RawWasmOutput::OkV1 { + ok, + internal_reply_enclave_sig, + internal_msg_id, + } => match is_ibc { + false => WasmOutput { + v010: None, + v1: Some(V1WasmOutput { + err: None, + ok: Some(ok), + }), + ibc_basic: None, + ibc_packet_receive: None, + ibc_open_channel: None, + query: None, + internal_reply_enclave_sig, + internal_msg_id, + }, + true => WasmOutput { + v010: None, + v1: None, + ibc_basic: Some(IBCOutput { + err: None, + ok: Some(cw_types_v1::ibc::IbcBasicResponse::new( + ok.messages, + ok.attributes, + ok.events, + )), + }), + ibc_packet_receive: None, + ibc_open_channel: None, + query: None, + internal_reply_enclave_sig, + internal_msg_id, + }, + }, + RawWasmOutput::QueryOkV010 { ok } | RawWasmOutput::QueryOkV1 { ok } => WasmOutput { + v010: None, + v1: None, + ibc_basic: None, + ibc_packet_receive: None, + ibc_open_channel: None, + query: Some(QueryOutput { + ok: Some(ok), + err: None, + }), + internal_reply_enclave_sig: None, + internal_msg_id: None, + }, + RawWasmOutput::OkIBCPacketReceive { ok } => WasmOutput { + v010: None, + v1: None, + ibc_basic: None, + ibc_packet_receive: Some(IBCReceiveOutput { + err: None, + ok: Some(ok), + }), + ibc_open_channel: None, + query: None, + internal_reply_enclave_sig: None, + internal_msg_id: None, + }, + RawWasmOutput::OkIBCOpenChannel { ok } => WasmOutput { + v010: None, + v1: None, + ibc_basic: None, + ibc_packet_receive: None, + ibc_open_channel: Some(IBCOpenChannelOutput { + err: None, + ok: match ok { + Some(o) => Some(o.version), + None => Some("".to_string()), + }, + }), + query: None, + internal_reply_enclave_sig: None, + internal_msg_id: None, + }, + }; +} + +pub fn manipulate_callback_sig_for_plaintext( + output: Vec, +) -> Result { + let mut raw_output: RawWasmOutput = serde_json::from_slice(&output).map_err(|err| { + warn!("got an error while trying to deserialize output bytes into json"); + trace!("output: {:?} error: {:?}", output, err); + EnclaveError::FailedToDeserialize + })?; + + match &mut raw_output { + RawWasmOutput::OkV1 { ok, .. } => { + for sub_msg in &mut ok.messages { + if let cw_types_v1::results::CosmosMsg::Wasm(wasm_msg) = &mut sub_msg.msg { + match wasm_msg { + cw_types_v1::results::WasmMsg::Execute { callback_sig, .. } + | cw_types_v1::results::WasmMsg::Instantiate { callback_sig, .. } => { + *callback_sig = Some(vec![]) + } + } + } + } + } + RawWasmOutput::OkIBCPacketReceive { ok } => { + for sub_msg in &mut ok.messages { + if let cw_types_v1::results::CosmosMsg::Wasm(wasm_msg) = &mut sub_msg.msg { + match wasm_msg { + cw_types_v1::results::WasmMsg::Execute { callback_sig, .. } + | cw_types_v1::results::WasmMsg::Instantiate { callback_sig, .. } => { + *callback_sig = Some(vec![]) + } + } + } + } + } + _ => {} + } + + Ok(raw_output) +} + +pub fn set_attributes_to_plaintext(attributes: &mut Vec) { + for attr in attributes { + attr.encrypted = false; + } +} + +pub fn set_all_logs_to_plaintext(raw_output: &mut RawWasmOutput) { + match raw_output { + RawWasmOutput::OkV1 { ok, .. } => { + set_attributes_to_plaintext(&mut ok.attributes); + for ev in &mut ok.events { + set_attributes_to_plaintext(&mut ev.attributes); + } + } + RawWasmOutput::OkIBCPacketReceive { ok } => { + set_attributes_to_plaintext(&mut ok.attributes); + for ev in &mut ok.events { + set_attributes_to_plaintext(&mut ev.attributes); + } + } + _ => {} + } +} + pub fn encrypt_output( output: Vec, secret_msg: &SecretMessage, @@ -162,14 +404,17 @@ pub fn encrypt_output( reply_params: Option, sender_addr: &CanonicalAddr, is_query_output: bool, + is_ibc_output: bool, ) -> Result, EnclaveError> { // When encrypting an output we might encrypt an output that is a reply to a caller contract (Via "Reply" endpoint). // Therefore if reply_recipient_contract_hash is not "None" we append it to any encrypted data besided submessages that are irrelevant for replies. // More info in: https://github.com/CosmWasm/cosmwasm/blob/v1.0.0/packages/std/src/results/submessages.rs#L192-L198 let encryption_key = calc_encryption_key(&secret_msg.nonce, &secret_msg.user_public_key); trace!( - "Output before encryption: {:?}", - String::from_utf8_lossy(&output) + "Output before encryption: {:?} {:?} {:?}", + String::from_utf8_lossy(&output), + secret_msg.nonce, + secret_msg.user_public_key ); let mut output: RawWasmOutput = serde_json::from_slice(&output).map_err(|err| { @@ -185,10 +430,7 @@ pub fn encrypt_output( internal_msg_id, } => { let encrypted_err = encrypt_serializable(&encryption_key, err, &reply_params)?; - - // Putting the error inside a 'generic_err' envelope, so we can encrypt the error itself *err = json!({"generic_err":{"msg":encrypted_err}}); - let msg_id = match reply_params { Some(ref r) => { let encrypted_id = Binary::from_base64(&encrypt_preserialized_string( @@ -209,6 +451,7 @@ pub fn encrypt_output( let reply = Reply { id: msg_id.unwrap(), result: SubMsgResult::Err(encrypted_err), + was_msg_encrypted: true, }; let reply_as_vec = serde_json::to_vec(&reply).map_err(|err| { warn!( @@ -242,7 +485,7 @@ pub fn encrypt_output( internal_msg_id, } => { for msg in &mut ok.messages { - if let enclave_cosmwasm_v010_types::types::CosmosMsg::Wasm(wasm_msg) = msg { + if let cw_types_v010::types::CosmosMsg::Wasm(wasm_msg) = msg { encrypt_v010_wasm_msg( wasm_msg, secret_msg.nonce, @@ -285,10 +528,14 @@ pub fn encrypt_output( Some(_) => { let events = match ok.log.len() { 0 => vec![], - _ => vec![Event { - ty: "wasm".to_string(), - attributes: ok.log.clone(), - }], + _ => { + let mut logs = ok.log.clone(); + logs.sort_by(|a, b| a.key.cmp(&b.key)); + vec![Event { + ty: "wasm".to_string(), + attributes: logs, + }] + } }; let reply = Reply { @@ -297,6 +544,7 @@ pub fn encrypt_output( events, data: ok.data.clone(), }), + was_msg_encrypted: true, }; let reply_as_vec = serde_json::to_vec(&reply).map_err(|err| { @@ -325,9 +573,7 @@ pub fn encrypt_output( internal_msg_id, } => { for sub_msg in &mut ok.messages { - if let enclave_cosmwasm_v1_types::results::CosmosMsg::Wasm(wasm_msg) = - &mut sub_msg.msg - { + if let cw_types_v1::results::CosmosMsg::Wasm(wasm_msg) = &mut sub_msg.msg { encrypt_v1_wasm_msg( wasm_msg, &sub_msg.reply_on, @@ -342,6 +588,8 @@ pub fn encrypt_output( // We don't encrypt it here to remain with the same type (u64) sub_msg.id = 0; } + + sub_msg.was_msg_encrypted = true; } // v1: The attributes that will be emitted as part of a "wasm" event. @@ -359,6 +607,11 @@ pub fn encrypt_output( } if let Some(data) = &mut ok.data { + if is_ibc_output { + warn!("IBC output should not contain any data"); + return Err(EnclaveError::InternalError); + } + *data = Binary::from_base64(&encrypt_serializable( &encryption_key, data, @@ -385,7 +638,7 @@ pub fn encrypt_output( Some(_) => { let mut events: Vec = vec![]; - if ok.attributes.len() > 0 { + if !ok.attributes.is_empty() { events.push(Event { ty: "wasm".to_string(), attributes: ok.attributes.clone(), @@ -398,6 +651,8 @@ pub fn encrypt_output( if event.ty != "wasm" { event.ty = custom_contract_event_prefix.clone() + event.ty.as_str(); } + + event.attributes.sort_by(|a, b| a.key.cmp(&b.key)); } let reply = Reply { @@ -406,6 +661,7 @@ pub fn encrypt_output( events, data: ok.data.clone(), }), + was_msg_encrypted: true, }; let reply_as_vec = serde_json::to_vec(&reply).map_err(|err| { @@ -429,78 +685,51 @@ pub fn encrypt_output( None => None, // Not a reply, we don't need enclave sig } } - }; + RawWasmOutput::OkIBCPacketReceive { ok } => { + for sub_msg in &mut ok.messages { + if let cw_types_v1::results::CosmosMsg::Wasm(wasm_msg) = &mut sub_msg.msg { + encrypt_v1_wasm_msg( + wasm_msg, + &sub_msg.reply_on, + sub_msg.id, + secret_msg.nonce, + secret_msg.user_public_key, + contract_addr, + contract_hash, + )?; - let final_output: WasmOutput = match output { - RawWasmOutput::Err { - err, - internal_msg_id, - internal_reply_enclave_sig, - } => { - if is_query_output { - WasmOutput { - v010: None, - v1: None, - query: Some(QueryOutput { - ok: None, - err: Some(err), - }), - internal_reply_enclave_sig: None, - internal_msg_id: None, + // The ID can be extracted from the encrypted wasm msg + // We don't encrypt it here to remain with the same type (u64) + sub_msg.id = 0; } - } else { - WasmOutput { - v010: Some(V010WasmOutput { - err: Some(err), - ok: None, - }), - v1: None, - query: None, - internal_reply_enclave_sig, - internal_msg_id, + + sub_msg.was_msg_encrypted = true; + } + + // v1: The attributes that will be emitted as part of a "wasm" event. + for attr in ok.attributes.iter_mut().filter(|attr| attr.encrypted) { + attr.key = encrypt_preserialized_string(&encryption_key, &attr.key, &None)?; + attr.value = encrypt_preserialized_string(&encryption_key, &attr.value, &None)?; + } + + // v1: Extra, custom events separate from the main wasm one. These will have "wasm-"" prepended to the type. + for event in ok.events.iter_mut() { + for attr in event.attributes.iter_mut().filter(|attr| attr.encrypted) { + attr.key = encrypt_preserialized_string(&encryption_key, &attr.key, &None)?; + attr.value = encrypt_preserialized_string(&encryption_key, &attr.value, &None)?; } } + + ok.acknowledgement = Binary::from_base64(&encrypt_serializable( + &encryption_key, + &ok.acknowledgement, + &reply_params, + )?)?; } - RawWasmOutput::OkV010 { - ok, - internal_reply_enclave_sig, - internal_msg_id, - } => WasmOutput { - v010: Some(V010WasmOutput { - err: None, - ok: Some(ok), - }), - v1: None, - query: None, - internal_reply_enclave_sig, - internal_msg_id, - }, - RawWasmOutput::OkV1 { - ok, - internal_reply_enclave_sig, - internal_msg_id, - } => WasmOutput { - v010: None, - v1: Some(V1WasmOutput { - err: None, - ok: Some(ok), - }), - query: None, - internal_reply_enclave_sig, - internal_msg_id, - }, - RawWasmOutput::QueryOkV010 { ok } | RawWasmOutput::QueryOkV1 { ok } => WasmOutput { - v010: None, - v1: None, - query: Some(QueryOutput { - ok: Some(ok), - err: None, - }), - internal_reply_enclave_sig: None, - internal_msg_id: None, - }, + RawWasmOutput::OkIBCOpenChannel { ok: _ } => {} }; + let final_output = finalize_raw_output(output, is_query_output, is_ibc_output, true); trace!("WasmOutput: {:?}", final_output); let encrypted_output = serde_json::to_vec(&final_output).map_err(|err| { @@ -515,20 +744,20 @@ pub fn encrypt_output( } fn encrypt_v010_wasm_msg( - wasm_msg: &mut enclave_cosmwasm_v010_types::types::WasmMsg, + wasm_msg: &mut cw_types_v010::types::WasmMsg, nonce: IoNonce, user_public_key: Ed25519PublicKey, contract_addr: &CanonicalAddr, ) -> Result<(), EnclaveError> { match wasm_msg { - enclave_cosmwasm_v010_types::types::WasmMsg::Execute { + cw_types_v010::types::WasmMsg::Execute { msg, callback_code_hash, callback_sig, send, .. } - | enclave_cosmwasm_v010_types::types::WasmMsg::Instantiate { + | cw_types_v010::types::WasmMsg::Instantiate { msg, callback_code_hash, callback_sig, @@ -555,7 +784,7 @@ fn encrypt_v010_wasm_msg( } fn encrypt_v1_wasm_msg( - wasm_msg: &mut enclave_cosmwasm_v1_types::results::WasmMsg, + wasm_msg: &mut cw_types_v1::results::WasmMsg, reply_on: &ReplyOn, msg_id: u64, // In every submessage there is a field called "id", currently used only by "reply". nonce: IoNonce, @@ -564,14 +793,14 @@ fn encrypt_v1_wasm_msg( reply_recipient_contract_hash: &str, ) -> Result<(), EnclaveError> { match wasm_msg { - enclave_cosmwasm_v1_types::results::WasmMsg::Execute { + cw_types_v1::results::WasmMsg::Execute { msg, code_hash, callback_sig, funds, .. } - | enclave_cosmwasm_v1_types::results::WasmMsg::Instantiate { + | cw_types_v1::results::WasmMsg::Instantiate { msg, code_hash, callback_sig, @@ -586,9 +815,8 @@ fn encrypt_v1_wasm_msg( // it will treat the next 64 bytes as a recipient code-hash and prepend this code-hash to its output. let mut hash_appended_msg = code_hash.as_bytes().to_vec(); if *reply_on != ReplyOn::Never { - hash_appended_msg.extend_from_slice( - enclave_cosmwasm_v1_types::results::REPLY_ENCRYPTION_MAGIC_BYTES, - ); + hash_appended_msg + .extend_from_slice(cw_types_v1::results::REPLY_ENCRYPTION_MAGIC_BYTES); hash_appended_msg.extend_from_slice(&msg_id.to_be_bytes()); hash_appended_msg.extend_from_slice(reply_recipient_contract_hash.as_bytes()); } @@ -609,11 +837,11 @@ fn encrypt_v1_wasm_msg( &msg_to_pass, &funds .iter() - .map(|coin| enclave_cosmwasm_v010_types::types::Coin { + .map(|coin| cw_types_v010::types::Coin { denom: coin.denom.clone(), - amount: enclave_cosmwasm_v010_types::math::Uint128(coin.amount.u128()), + amount: cw_types_v010::math::Uint128(coin.amount.u128()), }) - .collect::>()[..], + .collect::>()[..], )); } } diff --git a/cosmwasm/enclaves/shared/contract-engine/src/lib.rs b/cosmwasm/enclaves/shared/contract-engine/src/lib.rs index 5fab47759..49e83256a 100644 --- a/cosmwasm/enclaves/shared/contract-engine/src/lib.rs +++ b/cosmwasm/enclaves/shared/contract-engine/src/lib.rs @@ -2,6 +2,7 @@ #[cfg(not(target_env = "sgx"))] extern crate sgx_tstd as std; +extern crate core; extern crate sgx_types; mod contract_operations; @@ -12,6 +13,7 @@ pub mod external; mod gas; mod io; mod memory; +mod message; pub(crate) mod module_cache; mod query_chain; pub(crate) mod types; diff --git a/cosmwasm/enclaves/shared/contract-engine/src/message.rs b/cosmwasm/enclaves/shared/contract-engine/src/message.rs new file mode 100644 index 000000000..d5bbf98fb --- /dev/null +++ b/cosmwasm/enclaves/shared/contract-engine/src/message.rs @@ -0,0 +1,505 @@ +use log::{trace, warn}; + +use cosmos_proto::tx::signing::SignMode; +use cw_types_v010::encoding::Binary; +use cw_types_v1::ibc::IbcPacketReceiveMsg; +use cw_types_v1::results::{DecryptedReply, Event, Reply, SubMsgResponse, SubMsgResult}; +use enclave_cosmos_types::types::{HandleType, SigInfo}; +use enclave_ffi_types::EnclaveError; + +use crate::types::SecretMessage; + +const HEX_ENCODED_HASH_SIZE: usize = 64; + +pub struct ParsedMessage { + pub should_validate_sig_info: bool, + pub was_msg_encrypted: bool, + pub should_encrypt_output: bool, + pub secret_msg: SecretMessage, + pub decrypted_msg: Vec, + pub contract_hash_for_validation: Option>, +} + +pub struct DecryptedSecretMessage { + pub secret_msg: SecretMessage, + pub decrypted_msg: Vec, +} + +pub fn redact_custom_events(reply: &mut Reply) { + reply.result = match &reply.result { + SubMsgResult::Ok(r) => { + let mut events: Vec = Default::default(); + + let filtered_attributes = vec!["contract_address".to_string(), "code_id".to_string()]; + for ev in r.events.iter() { + if !ev.ty.starts_with("wasm") { + continue; + } + + let mut new_ev = Event { + ty: ev.ty.clone(), + attributes: vec![], + }; + + for attr in &ev.attributes { + if !filtered_attributes.contains(&attr.key) { + new_ev.attributes.push(attr.clone()); + } + } + + if !new_ev.attributes.is_empty() { + events.push(new_ev); + } + } + + SubMsgResult::Ok(SubMsgResponse { + events, + data: r.data.clone(), + }) + } + SubMsgResult::Err(_) => reply.result.clone(), + }; +} + +pub fn get_secret_msg(message: &[u8]) -> SecretMessage { + match SecretMessage::from_slice(message) { + Ok(orig_secret_msg) => orig_secret_msg, + Err(_) => { + trace!( + "Msg is not SecretMessage (probably plaintext): {:?}", + base64::encode(&message) + ); + + return SecretMessage { + nonce: [0; 32], + user_public_key: [0; 32], + msg: message.into(), + }; + } + } +} + +pub fn try_get_decrypted_secret_msg(message: &[u8]) -> Option { + let secret_msg = get_secret_msg(message); + match secret_msg.decrypt() { + Ok(decrypted_msg) => Some(DecryptedSecretMessage { + secret_msg, + decrypted_msg, + }), + Err(_) => None, + } +} + +// Parse the message that was passed to handle (Based on the assumption that it might be a reply or IBC as well) +pub fn parse_message( + message: &[u8], + sig_info: &SigInfo, + handle_type: &HandleType, +) -> Result { + return match handle_type { + HandleType::HANDLE_TYPE_EXECUTE => match try_get_decrypted_secret_msg(message) { + Some(decrypted_secret_msg) => { + trace!( + "execute input before decryption: {:?}", + base64::encode(&message) + ); + + Ok(ParsedMessage { + should_validate_sig_info: true, + was_msg_encrypted: true, + should_encrypt_output: true, + secret_msg: decrypted_secret_msg.secret_msg, + decrypted_msg: decrypted_secret_msg.decrypted_msg, + contract_hash_for_validation: None, + }) + } + None => { + trace!( + "execute input was plaintext: {:?}", + base64::encode(&message) + ); + + let secret_msg = get_secret_msg(message); + let decrypted_msg = secret_msg.msg.clone(); + + Ok(ParsedMessage { + should_validate_sig_info: false, + was_msg_encrypted: false, + should_encrypt_output: false, + secret_msg, + decrypted_msg, + contract_hash_for_validation: None, + }) + } + }, + HandleType::HANDLE_TYPE_REPLY => { + let orig_secret_msg = SecretMessage::from_slice(message)?; + + if sig_info.sign_mode == SignMode::SIGN_MODE_UNSPECIFIED { + trace!( + "reply input is not encrypted: {:?}", + base64::encode(&message) + ); + let decrypted_msg = orig_secret_msg.msg.clone(); + let mut reply: Reply = serde_json::from_slice(&decrypted_msg) + .map_err(|err| { + warn!( + "reply got an error while trying to deserialize decrypted reply bytes into json {:?}: {}", + String::from_utf8_lossy(&decrypted_msg), + err + ); + EnclaveError::FailedToDeserialize + })?; + + let msg_id = String::from_utf8(reply.id.as_slice().to_vec()).map_err(|err| { + warn!( + "Failed to parse message id as string {:?}: {}", + reply.id.as_slice().to_vec(), + err + ); + EnclaveError::FailedToDeserialize + })?; + + let msg_id_as_num = match msg_id.parse::() { + Ok(m) => m, + Err(err) => { + warn!("Failed to parse message id as number {}: {}", msg_id, err); + return Err(EnclaveError::FailedToDeserialize); + } + }; + + let decrypted_reply = DecryptedReply { + id: msg_id_as_num, + result: reply.result.clone(), + }; + + redact_custom_events(&mut reply); + let serialized_encrypted_reply : Vec = serde_json::to_vec(&reply).map_err(|err| { + warn!( + "got an error while trying to serialize encrypted reply into bytes {:?}: {}", + reply, err + ); + EnclaveError::FailedToSerialize + })?; + + let reply_secret_msg = SecretMessage { + nonce: orig_secret_msg.nonce, + user_public_key: orig_secret_msg.user_public_key, + msg: serialized_encrypted_reply, + }; + + let serialized_reply: Vec = serde_json::to_vec(&decrypted_reply).map_err(|err| { + warn!( + "got an error while trying to serialize decrypted reply into bytes {:?}: {}", + decrypted_reply, err + ); + EnclaveError::FailedToSerialize + })?; + + return Ok(ParsedMessage { + should_validate_sig_info: false, + was_msg_encrypted: false, + should_encrypt_output: reply.was_msg_encrypted, + secret_msg: reply_secret_msg, + decrypted_msg: serialized_reply, + contract_hash_for_validation: None, + }); + } + + trace!( + "reply input before decryption: {:?}", + base64::encode(&message) + ); + let mut parsed_encrypted_reply: Reply = serde_json::from_slice( + &orig_secret_msg.msg.as_slice().to_vec(), + ) + .map_err(|err| { + warn!( + "reply got an error while trying to deserialize msg input bytes into json {:?}: {}", + String::from_utf8_lossy(&orig_secret_msg.msg), + err + ); + EnclaveError::FailedToDeserialize + })?; + + match parsed_encrypted_reply.result.clone() { + SubMsgResult::Ok(response) => { + let decrypted_msg_data = match response.data { + Some(data) => { + let tmp_secret_msg_data = SecretMessage { + nonce: orig_secret_msg.nonce, + user_public_key: orig_secret_msg.user_public_key, + msg: data.as_slice().to_vec(), + }; + + Some(Binary( + tmp_secret_msg_data.decrypt()?[HEX_ENCODED_HASH_SIZE..].to_vec(), + )) + } + None => None, + }; + + let tmp_secret_msg_id = SecretMessage { + nonce: orig_secret_msg.nonce, + user_public_key: orig_secret_msg.user_public_key, + msg: parsed_encrypted_reply.id.as_slice().to_vec(), + }; + + let tmp_decrypted_msg_id = tmp_secret_msg_id.decrypt()?; + + // Now we need to create synthetic SecretMessage to fit the API in "handle" + let result = SubMsgResult::Ok(SubMsgResponse { + events: response.events, + data: decrypted_msg_data, + }); + + let msg_id = + String::from_utf8(tmp_decrypted_msg_id[HEX_ENCODED_HASH_SIZE..].to_vec()) + .map_err(|err| { + warn!( + "Failed to parse message id as string {:?}: {}", + tmp_decrypted_msg_id[HEX_ENCODED_HASH_SIZE..].to_vec(), + err + ); + EnclaveError::FailedToDeserialize + })?; + + let msg_id_as_num = match msg_id.parse::() { + Ok(m) => m, + Err(err) => { + warn!("Failed to parse message id as number {}: {}", msg_id, err); + return Err(EnclaveError::FailedToDeserialize); + } + }; + + let decrypted_reply = DecryptedReply { + id: msg_id_as_num, + result, + }; + + let decrypted_reply_as_vec = + serde_json::to_vec(&decrypted_reply).map_err(|err| { + warn!( + "got an error while trying to serialize reply into bytes {:?}: {}", + decrypted_reply, err + ); + EnclaveError::FailedToSerialize + })?; + + redact_custom_events(&mut parsed_encrypted_reply); + let serialized_encrypted_reply : Vec = serde_json::to_vec(&parsed_encrypted_reply).map_err(|err| { + warn!( + "got an error while trying to serialize encrypted reply into bytes {:?}: {}", + parsed_encrypted_reply, err + ); + EnclaveError::FailedToSerialize + })?; + + let reply_secret_msg = SecretMessage { + nonce: orig_secret_msg.nonce, + user_public_key: orig_secret_msg.user_public_key, + msg: serialized_encrypted_reply, + }; + + Ok(ParsedMessage { + should_validate_sig_info: true, + was_msg_encrypted: true, + should_encrypt_output: true, + secret_msg: reply_secret_msg, + decrypted_msg: decrypted_reply_as_vec, + contract_hash_for_validation: Some( + tmp_decrypted_msg_id[..HEX_ENCODED_HASH_SIZE].to_vec(), + ), + }) + } + SubMsgResult::Err(response) => { + let secret_msg = SecretMessage { + nonce: orig_secret_msg.nonce, + user_public_key: orig_secret_msg.user_public_key, + msg: base64::decode(response.clone()).map_err(|err| { + warn!( + "got an error while trying to serialize err reply from base64 {:?}: {}", + response, err + ); + EnclaveError::FailedToSerialize + })? + }; + + let decrypted_error = secret_msg.decrypt()?; + + let tmp_secret_msg_id = SecretMessage { + nonce: orig_secret_msg.nonce, + user_public_key: orig_secret_msg.user_public_key, + msg: parsed_encrypted_reply.id.as_slice().to_vec(), + }; + + let tmp_decrypted_msg_id = tmp_secret_msg_id.decrypt()?; + + // Now we need to create synthetic SecretMessage to fit the API in "handle" + let result = SubMsgResult::Err( + String::from_utf8(decrypted_error[HEX_ENCODED_HASH_SIZE..].to_vec()) + .map_err(|err| { + warn!( + "Failed to parse error as string {:?}: {}", + decrypted_error[HEX_ENCODED_HASH_SIZE..].to_vec(), + err + ); + EnclaveError::FailedToDeserialize + })?, + ); + + let msg_id = + String::from_utf8(tmp_decrypted_msg_id[HEX_ENCODED_HASH_SIZE..].to_vec()) + .map_err(|err| { + warn!( + "Failed to parse message id as string {:?}: {}", + tmp_decrypted_msg_id[HEX_ENCODED_HASH_SIZE..].to_vec(), + err + ); + EnclaveError::FailedToDeserialize + })?; + + let msg_id_as_num = match msg_id.parse::() { + Ok(m) => m, + Err(err) => { + warn!("Failed to parse message id as number {}: {}", msg_id, err); + return Err(EnclaveError::FailedToDeserialize); + } + }; + + let decrypted_reply = DecryptedReply { + id: msg_id_as_num, + result, + }; + + let decrypted_reply_as_vec = + serde_json::to_vec(&decrypted_reply).map_err(|err| { + warn!( + "got an error while trying to serialize reply into bytes {:?}: {}", + decrypted_reply, err + ); + EnclaveError::FailedToSerialize + })?; + + let serialized_encrypted_reply : Vec = serde_json::to_vec(&parsed_encrypted_reply).map_err(|err| { + warn!( + "got an error while trying to serialize encrypted reply into bytes {:?}: {}", + parsed_encrypted_reply, err + ); + EnclaveError::FailedToSerialize + })?; + + let reply_secret_msg = SecretMessage { + nonce: orig_secret_msg.nonce, + user_public_key: orig_secret_msg.user_public_key, + msg: serialized_encrypted_reply, + }; + + Ok(ParsedMessage { + should_validate_sig_info: true, + was_msg_encrypted: true, + should_encrypt_output: true, + secret_msg: reply_secret_msg, + decrypted_msg: decrypted_reply_as_vec, + contract_hash_for_validation: Some( + tmp_decrypted_msg_id[..HEX_ENCODED_HASH_SIZE].to_vec(), + ), + }) + } + } + } + HandleType::HANDLE_TYPE_IBC_CHANNEL_OPEN + | HandleType::HANDLE_TYPE_IBC_CHANNEL_CONNECT + | HandleType::HANDLE_TYPE_IBC_CHANNEL_CLOSE + | HandleType::HANDLE_TYPE_IBC_PACKET_ACK + | HandleType::HANDLE_TYPE_IBC_PACKET_TIMEOUT => { + trace!( + "parsing {} msg (Should always be plaintext): {:?}", + HandleType::to_export_name(&handle_type), + base64::encode(&message) + ); + + let scrt_msg = SecretMessage { + nonce: [0; 32], + user_public_key: [0; 32], + msg: message.into(), + }; + + let decrypted_msg = scrt_msg.msg.clone(); + + Ok(ParsedMessage { + should_validate_sig_info: false, + was_msg_encrypted: false, + should_encrypt_output: false, + secret_msg: scrt_msg, + decrypted_msg, + contract_hash_for_validation: None, + }) + } + HandleType::HANDLE_TYPE_IBC_PACKET_RECEIVE => { + // TODO: Maybe mark whether the message was encrypted or not. + let mut parsed_encrypted_ibc_packet: IbcPacketReceiveMsg = + serde_json::from_slice(&message.to_vec()).map_err(|err| { + warn!( + "Got an error while trying to deserialize input bytes msg into IbcPacketReceiveMsg message {:?}: {}", + String::from_utf8_lossy(&message), + err + ); + EnclaveError::FailedToDeserialize + })?; + + let tmp_secret_data = + get_secret_msg(parsed_encrypted_ibc_packet.packet.data.as_slice()); + let mut was_msg_encrypted = false; + let orig_secret_msg = tmp_secret_data; + + match orig_secret_msg.decrypt() { + Ok(decrypted_msg) => { + // IBC packet was encrypted + + trace!( + "ibc_packet_receive data before decryption: {:?}", + base64::encode(&message) + ); + + parsed_encrypted_ibc_packet.packet.data = decrypted_msg.as_slice().into(); + was_msg_encrypted = true; + } + Err(_) => { + // assume data is not encrypted + + trace!( + "ibc_packet_receive data was plaintext: {:?}", + base64::encode(&message) + ); + } + } + Ok(ParsedMessage { + should_validate_sig_info: false, + was_msg_encrypted, + should_encrypt_output: was_msg_encrypted, + secret_msg: orig_secret_msg, + decrypted_msg: serde_json::to_vec(&parsed_encrypted_ibc_packet).map_err(|err| { + warn!( + "got an error while trying to serialize IbcPacketReceive msg into bytes {:?}: {}", + parsed_encrypted_ibc_packet, err + ); + EnclaveError::FailedToSerialize + })?, + contract_hash_for_validation: None, + }) + } + }; +} + +pub fn is_ibc_msg(handle_type: HandleType) -> bool { + match handle_type { + HandleType::HANDLE_TYPE_EXECUTE | HandleType::HANDLE_TYPE_REPLY => false, + HandleType::HANDLE_TYPE_IBC_CHANNEL_OPEN + | HandleType::HANDLE_TYPE_IBC_CHANNEL_CONNECT + | HandleType::HANDLE_TYPE_IBC_CHANNEL_CLOSE + | HandleType::HANDLE_TYPE_IBC_PACKET_RECEIVE + | HandleType::HANDLE_TYPE_IBC_PACKET_ACK + | HandleType::HANDLE_TYPE_IBC_PACKET_TIMEOUT => true, + } +} diff --git a/cosmwasm/enclaves/shared/contract-engine/src/query_chain.rs b/cosmwasm/enclaves/shared/contract-engine/src/query_chain.rs index eec21d0bc..a99eb0bdc 100644 --- a/cosmwasm/enclaves/shared/contract-engine/src/query_chain.rs +++ b/cosmwasm/enclaves/shared/contract-engine/src/query_chain.rs @@ -11,7 +11,7 @@ use super::errors::WasmEngineError; use crate::external::{ecalls, ocalls}; use crate::types::{IoNonce, SecretMessage}; -use enclave_cosmwasm_v010_types::{ +use cw_types_v010::{ encoding::Binary, query::{QueryRequest, WasmQuery}, std_error::{StdError, StdResult}, diff --git a/cosmwasm/enclaves/shared/contract-engine/src/types.rs b/cosmwasm/enclaves/shared/contract-engine/src/types.rs index 07e2ff7c9..0fe611b12 100644 --- a/cosmwasm/enclaves/shared/contract-engine/src/types.rs +++ b/cosmwasm/enclaves/shared/contract-engine/src/types.rs @@ -28,6 +28,7 @@ impl SecretMessage { } pub fn decrypt(&self) -> Result, EnclaveError> { + trace!("input before decryption: {:?}", base64::encode(&self.msg)); let key = self.encryption_key(); // pass @@ -36,6 +37,11 @@ impl SecretMessage { EnclaveError::DecryptionError })?; + trace!( + "input after decryption: {:?}", + String::from_utf8_lossy(&msg) + ); + Ok(msg) } diff --git a/cosmwasm/enclaves/shared/contract-engine/src/wasm/contract.rs b/cosmwasm/enclaves/shared/contract-engine/src/wasm/contract.rs index efcd11a53..95ecf74f8 100644 --- a/cosmwasm/enclaves/shared/contract-engine/src/wasm/contract.rs +++ b/cosmwasm/enclaves/shared/contract-engine/src/wasm/contract.rs @@ -9,7 +9,9 @@ use wasmi::{Error as InterpreterError, MemoryInstance, MemoryRef, ModuleRef, Run use enclave_ffi_types::{Ctx, EnclaveError}; -use enclave_cosmwasm_v010_types::consts::BECH32_PREFIX_ACC_ADDR; +use cw_types_generic::CosmWasmApiVersion; +use cw_types_v010::consts::BECH32_PREFIX_ACC_ADDR; + use enclave_crypto::{sha_256, Ed25519PublicKey, WasmApiCryptoError}; use crate::contract_validation::ContractKey; @@ -29,14 +31,6 @@ mod api_marker { pub const V1: &str = "interface_version_8"; } -/// CosmwasmApiVersion is used to decide how to handle contract inputs and outputs -pub enum CosmWasmApiVersion { - /// CosmWasm v0.10 API - V010, - /// CosmWasm v1 API - V1, -} - /// Right now ContractOperation is used to detect queris and prevent state changes #[derive(Clone, Copy, Debug)] pub enum ContractOperation { diff --git a/cosmwasm/enclaves/shared/contract-engine/src/wasm/engine.rs b/cosmwasm/enclaves/shared/contract-engine/src/wasm/engine.rs index 880cb9970..773ea982a 100644 --- a/cosmwasm/enclaves/shared/contract-engine/src/wasm/engine.rs +++ b/cosmwasm/enclaves/shared/contract-engine/src/wasm/engine.rs @@ -4,7 +4,9 @@ use wasmi::{ModuleRef, RuntimeValue}; use enclave_ffi_types::EnclaveError; -use super::contract::{ContractInstance, CosmWasmApiVersion}; +use cw_types_generic::CosmWasmApiVersion; + +use super::contract::ContractInstance; use crate::errors::{wasmi_error_to_enclave_error, WasmEngineError}; use enclave_cosmos_types::types::HandleType; @@ -146,6 +148,48 @@ impl Engine { RuntimeValue::I32(msg_ptr as i32), ], ), + HandleType::HANDLE_TYPE_IBC_CHANNEL_OPEN => ( + "ibc_channel_open", + vec![ + RuntimeValue::I32(env_ptr as i32), + RuntimeValue::I32(msg_ptr as i32), + ], + ), + HandleType::HANDLE_TYPE_IBC_CHANNEL_CONNECT => ( + "ibc_channel_connect", + vec![ + RuntimeValue::I32(env_ptr as i32), + RuntimeValue::I32(msg_ptr as i32), + ], + ), + HandleType::HANDLE_TYPE_IBC_CHANNEL_CLOSE => ( + "ibc_channel_close", + vec![ + RuntimeValue::I32(env_ptr as i32), + RuntimeValue::I32(msg_ptr as i32), + ], + ), + HandleType::HANDLE_TYPE_IBC_PACKET_RECEIVE => ( + "ibc_packet_receive", + vec![ + RuntimeValue::I32(env_ptr as i32), + RuntimeValue::I32(msg_ptr as i32), + ], + ), + HandleType::HANDLE_TYPE_IBC_PACKET_ACK => ( + "ibc_packet_ack", + vec![ + RuntimeValue::I32(env_ptr as i32), + RuntimeValue::I32(msg_ptr as i32), + ], + ), + HandleType::HANDLE_TYPE_IBC_PACKET_TIMEOUT => ( + "ibc_packet_timeout", + vec![ + RuntimeValue::I32(env_ptr as i32), + RuntimeValue::I32(msg_ptr as i32), + ], + ), }, }; diff --git a/cosmwasm/enclaves/shared/contract-engine/src/wasm/mod.rs b/cosmwasm/enclaves/shared/contract-engine/src/wasm/mod.rs index a9883a7a1..43ed153d9 100644 --- a/cosmwasm/enclaves/shared/contract-engine/src/wasm/mod.rs +++ b/cosmwasm/enclaves/shared/contract-engine/src/wasm/mod.rs @@ -4,6 +4,7 @@ mod externals; mod import_resolver; pub mod traits; -pub use contract::{ContractInstance, ContractOperation, CosmWasmApiVersion}; +pub use contract::{ContractInstance, ContractOperation}; +pub use cw_types_generic::CosmWasmApiVersion; pub use engine::Engine; pub use import_resolver::{create_builder, WasmiImportResolver}; diff --git a/cosmwasm/enclaves/shared/cosmos-proto/Cargo.toml b/cosmwasm/enclaves/shared/cosmos-proto/Cargo.toml index 30b15d02f..b12275afc 100644 --- a/cosmwasm/enclaves/shared/cosmos-proto/Cargo.toml +++ b/cosmwasm/enclaves/shared/cosmos-proto/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cosmos_proto" -version = "1.2.4" +version = "1.4.0" authors = ["bob"] edition = "2018" diff --git a/cosmwasm/enclaves/shared/cosmos-proto/src/tx/signing.rs b/cosmwasm/enclaves/shared/cosmos-proto/src/tx/signing.rs index d73a38f55..35ace061c 100644 --- a/cosmwasm/enclaves/shared/cosmos-proto/src/tx/signing.rs +++ b/cosmwasm/enclaves/shared/cosmos-proto/src/tx/signing.rs @@ -1156,6 +1156,7 @@ pub enum SignMode { SIGN_MODE_DIRECT = 1, SIGN_MODE_TEXTUAL = 2, SIGN_MODE_LEGACY_AMINO_JSON = 127, + SIGN_MODE_EIP_191 = 191 } impl ::protobuf::ProtobufEnum for SignMode { @@ -1169,6 +1170,7 @@ impl ::protobuf::ProtobufEnum for SignMode { 1 => ::std::option::Option::Some(SignMode::SIGN_MODE_DIRECT), 2 => ::std::option::Option::Some(SignMode::SIGN_MODE_TEXTUAL), 127 => ::std::option::Option::Some(SignMode::SIGN_MODE_LEGACY_AMINO_JSON), + 191 => ::std::option::Option::Some(SignMode::SIGN_MODE_EIP_191), _ => ::std::option::Option::None } } @@ -1179,6 +1181,7 @@ impl ::protobuf::ProtobufEnum for SignMode { SignMode::SIGN_MODE_DIRECT, SignMode::SIGN_MODE_TEXTUAL, SignMode::SIGN_MODE_LEGACY_AMINO_JSON, + SignMode::SIGN_MODE_EIP_191, ]; values } diff --git a/cosmwasm/enclaves/shared/cosmos-types/Cargo.toml b/cosmwasm/enclaves/shared/cosmos-types/Cargo.toml index fa2c3417f..e9c5ece00 100644 --- a/cosmwasm/enclaves/shared/cosmos-types/Cargo.toml +++ b/cosmwasm/enclaves/shared/cosmos-types/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "enclave_cosmos_types" -version = "1.2.4" +version = "1.4.0" authors = ["Cashmaney "] edition = "2018" @@ -19,7 +19,7 @@ sgx_tstd = { rev = "a37ffb9449ba6d5b6e4a9d586bbab864ae732269", git = "https://gi cosmos_proto = { path = "../cosmos-proto" } enclave-ffi-types = { path = "../../ffi-types" } enclave_crypto = { path = "../crypto" } -enclave_cosmwasm_v010_types = { path = "../cosmwasm-v010-types" } +cw_types_v010 = { path = "../cosmwasm-types/v0.10" } log = "0.4.14" serde = { git = "https://github.com/mesalock-linux/serde-sgx", features = [ "derive" diff --git a/cosmwasm/enclaves/shared/cosmos-types/src/multisig.rs b/cosmwasm/enclaves/shared/cosmos-types/src/multisig.rs index daff4798b..994216f87 100644 --- a/cosmwasm/enclaves/shared/cosmos-types/src/multisig.rs +++ b/cosmwasm/enclaves/shared/cosmos-types/src/multisig.rs @@ -6,11 +6,11 @@ use crate::types::CosmosPubKey; use enclave_crypto::traits::VerifyingKey; -use cosmos_proto::crypto::multisig::multisig::MultiSignature; +use cosmos_proto::{crypto::multisig::multisig::MultiSignature, tx::signing::SignMode}; use super::traits::CosmosAminoPubkey; -use enclave_cosmwasm_v010_types::types::CanonicalAddr; +use cw_types_v010::types::CanonicalAddr; use enclave_crypto::CryptoError; use protobuf::Message; @@ -94,7 +94,12 @@ impl CosmosAminoPubkey for MultisigThresholdPubKey { } impl VerifyingKey for MultisigThresholdPubKey { - fn verify_bytes(&self, bytes: &[u8], sig: &[u8]) -> Result<(), CryptoError> { + fn verify_bytes( + &self, + bytes: &[u8], + sig: &[u8], + sign_mode: SignMode, + ) -> Result<(), CryptoError> { debug!("verifying multisig"); trace!("Sign bytes are: {:?}", bytes); let signatures = decode_multisig_signature(sig)?; @@ -122,7 +127,7 @@ impl VerifyingKey for MultisigThresholdPubKey { for (i, current_signer) in signers.iter().enumerate() { trace!("Checking pubkey: {:?}", current_signer); // This technically support that one of the multisig signers is a multisig itself - let result = current_signer.verify_bytes(bytes, current_sig); + let result = current_signer.verify_bytes(bytes, current_sig, sign_mode); if result.is_ok() { signer_pos = Some(i); diff --git a/cosmwasm/enclaves/shared/cosmos-types/src/single_address.rs b/cosmwasm/enclaves/shared/cosmos-types/src/single_address.rs index 7cdf08d6a..d739c3b23 100644 --- a/cosmwasm/enclaves/shared/cosmos-types/src/single_address.rs +++ b/cosmwasm/enclaves/shared/cosmos-types/src/single_address.rs @@ -2,7 +2,7 @@ use enclave_crypto::secp256k1::{Secp256k1PubKey, SECP256K1_PREFIX}; use log::warn; use super::traits::CosmosAminoPubkey; -use enclave_cosmwasm_v010_types::types::CanonicalAddr; +use cw_types_v010::types::CanonicalAddr; use enclave_crypto::hash::ripemd::ripemd160; use enclave_crypto::hash::sha::sha_256; diff --git a/cosmwasm/enclaves/shared/cosmos-types/src/traits.rs b/cosmwasm/enclaves/shared/cosmos-types/src/traits.rs index 97952c457..ec4dfff37 100644 --- a/cosmwasm/enclaves/shared/cosmos-types/src/traits.rs +++ b/cosmwasm/enclaves/shared/cosmos-types/src/traits.rs @@ -1,4 +1,4 @@ -use enclave_cosmwasm_v010_types::types::CanonicalAddr; +use cw_types_v010::types::CanonicalAddr; // https://github.com/tendermint/tendermint/blob/v0.33.3/crypto/crypto.go#L22 pub trait CosmosAminoPubkey: PartialEq { diff --git a/cosmwasm/enclaves/shared/cosmos-types/src/types.rs b/cosmwasm/enclaves/shared/cosmos-types/src/types.rs index 873a80733..531f1c22b 100644 --- a/cosmwasm/enclaves/shared/cosmos-types/src/types.rs +++ b/cosmwasm/enclaves/shared/cosmos-types/src/types.rs @@ -1,6 +1,7 @@ use log::*; use enclave_ffi_types::EnclaveError; +use proto::tx::signing::SignMode; use protobuf::Message; use serde::{Deserialize, Serialize}; @@ -12,7 +13,7 @@ use enclave_crypto::{ use cosmos_proto as proto; -use enclave_cosmwasm_v010_types::{ +use cw_types_v010::{ coins::Coin, encoding::Binary, math::Uint128, @@ -120,10 +121,15 @@ impl CosmosAminoPubkey for CosmosPubKey { } impl VerifyingKey for CosmosPubKey { - fn verify_bytes(&self, bytes: &[u8], sig: &[u8]) -> Result<(), CryptoError> { + fn verify_bytes( + &self, + bytes: &[u8], + sig: &[u8], + sign_mode: SignMode, + ) -> Result<(), CryptoError> { match self { - CosmosPubKey::Secp256k1(pubkey) => pubkey.verify_bytes(bytes, sig), - CosmosPubKey::Multisig(pubkey) => pubkey.verify_bytes(bytes, sig), + CosmosPubKey::Secp256k1(pubkey) => pubkey.verify_bytes(bytes, sig, sign_mode), + CosmosPubKey::Multisig(pubkey) => pubkey.verify_bytes(bytes, sig, sign_mode), } } } @@ -139,6 +145,7 @@ pub enum SignModeDef { SIGN_MODE_DIRECT = 1, SIGN_MODE_TEXTUAL = 2, SIGN_MODE_LEGACY_AMINO_JSON = 127, + SIGN_MODE_EIP_191 = 191, } #[allow(non_camel_case_types)] @@ -146,6 +153,12 @@ pub enum SignModeDef { pub enum HandleType { HANDLE_TYPE_EXECUTE = 0, HANDLE_TYPE_REPLY = 1, + HANDLE_TYPE_IBC_CHANNEL_OPEN = 2, + HANDLE_TYPE_IBC_CHANNEL_CONNECT = 3, + HANDLE_TYPE_IBC_CHANNEL_CLOSE = 4, + HANDLE_TYPE_IBC_PACKET_RECEIVE = 5, + HANDLE_TYPE_IBC_PACKET_ACK = 6, + HANDLE_TYPE_IBC_PACKET_TIMEOUT = 7, } impl HandleType { @@ -153,12 +166,31 @@ impl HandleType { match value { 0 => Ok(HandleType::HANDLE_TYPE_EXECUTE), 1 => Ok(HandleType::HANDLE_TYPE_REPLY), + 2 => Ok(HandleType::HANDLE_TYPE_IBC_CHANNEL_OPEN), + 3 => Ok(HandleType::HANDLE_TYPE_IBC_CHANNEL_CONNECT), + 4 => Ok(HandleType::HANDLE_TYPE_IBC_CHANNEL_CLOSE), + 5 => Ok(HandleType::HANDLE_TYPE_IBC_PACKET_RECEIVE), + 6 => Ok(HandleType::HANDLE_TYPE_IBC_PACKET_ACK), + 7 => Ok(HandleType::HANDLE_TYPE_IBC_PACKET_TIMEOUT), _ => { error!("unrecognized handle type: {}", value); Err(EnclaveError::FailedToDeserialize) } } } + + pub fn to_export_name(h: &HandleType) -> String { + match h { + HandleType::HANDLE_TYPE_EXECUTE => "execute".to_string(), + HandleType::HANDLE_TYPE_REPLY => "reply".to_string(), + HandleType::HANDLE_TYPE_IBC_CHANNEL_OPEN => "ibc_channel_open".to_string(), + HandleType::HANDLE_TYPE_IBC_CHANNEL_CONNECT => "ibc_channel_connect".to_string(), + HandleType::HANDLE_TYPE_IBC_CHANNEL_CLOSE => "ibc_channel_close".to_string(), + HandleType::HANDLE_TYPE_IBC_PACKET_RECEIVE => "ibc_packet_receive".to_string(), + HandleType::HANDLE_TYPE_IBC_PACKET_ACK => "ibc_packet_ack".to_string(), + HandleType::HANDLE_TYPE_IBC_PACKET_TIMEOUT => "ibc_packet_timeout".to_string(), + } + } } // This is called `VerificationInfo` on the Go side diff --git a/cosmwasm/enclaves/shared/cosmwasm-types/generic/Cargo.toml b/cosmwasm/enclaves/shared/cosmwasm-types/generic/Cargo.toml new file mode 100644 index 000000000..dd13cedf3 --- /dev/null +++ b/cosmwasm/enclaves/shared/cosmwasm-types/generic/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "cw_types_generic" +version = "0.1.0" +authors = ["bob"] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +serde = { git = "https://github.com/mesalock-linux/serde-sgx", features = [ + "derive" +] } +serde_json = { git = "https://github.com/mesalock-linux/serde-json-sgx" } +enclave-ffi-types = { path = "../../../ffi-types" } + +cw_types_v010 = { path = "../v0.10" } +cw_types_v1 = { path = "../v1.0" } + +log = "0.4.14" +hex = "0.4.2" +base64 = "0.13.0" diff --git a/cosmwasm/enclaves/shared/cosmwasm-types/generic/src/lib.rs b/cosmwasm/enclaves/shared/cosmwasm-types/generic/src/lib.rs new file mode 100644 index 000000000..a34bb7897 --- /dev/null +++ b/cosmwasm/enclaves/shared/cosmwasm-types/generic/src/lib.rs @@ -0,0 +1,175 @@ +use log::warn; +use serde::{Deserialize, Serialize}; + +use cw_types_v010::types::{Env as V010Env, HumanAddr}; +use cw_types_v1::types::Env as V1Env; +use cw_types_v1::types::MessageInfo as V1MessageInfo; + +use cw_types_v010::types as v010types; +use cw_types_v1::types as v1types; + +use enclave_ffi_types::EnclaveError; + +pub const CONTRACT_KEY_LENGTH: usize = 64; + +/// CosmwasmApiVersion is used to decide how to handle contract inputs and outputs +pub enum CosmWasmApiVersion { + /// CosmWasm v0.10 API + V010, + /// CosmWasm v1 API + V1, +} + +pub type BaseAddr = HumanAddr; +pub type BaseCoin = v010types::Coin; +pub type BaseCanoncalAddr = v010types::CanonicalAddr; + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] +#[serde(rename_all = "snake_case")] +pub struct BaseEnv(pub V010Env); + +impl BaseEnv { + + pub fn get_contract_key(&self) -> Result<[u8; CONTRACT_KEY_LENGTH], EnclaveError> { + + let contract_key = if let Some(b64_key) = &self.0.contract_key { + base64::decode(b64_key).map_err(|err| { + warn!( + "got an error while trying to decode contract key {:?}: {}", + b64_key, err + ); + EnclaveError::FailedContractAuthentication + })? + } else { + warn!("Contract execute with empty contract key"); + return Err(EnclaveError::FailedContractAuthentication); + }; + + if contract_key.len() != CONTRACT_KEY_LENGTH { + warn!("Contract execute with empty contract key"); + return Err(EnclaveError::FailedContractAuthentication); + } + + let mut key_as_bytes = [0u8; CONTRACT_KEY_LENGTH]; + key_as_bytes.copy_from_slice(&contract_key); + + Ok(key_as_bytes) + } + + pub fn get_verification_params(&self) -> (&BaseAddr, &BaseAddr, u64, &Vec) { + ( + &self.0.message.sender, + &self.0.contract.address, + self.0.block.height, + &self.0.message.sent_funds, + ) + } + + pub fn into_versioned_env(self, api_version: &CosmWasmApiVersion) -> CwEnv { + match api_version { + CosmWasmApiVersion::V010 => self.into_v010(), + CosmWasmApiVersion::V1 => self.into_v1(), + } + } + + fn into_v010(self) -> CwEnv { + CwEnv::V010Env { env: self.0 } + } + + /// This is the conversion function from the base to the new env. We assume that if there are + /// any API changes that are necessary on the base level we will have to update this as well + fn into_v1(self) -> CwEnv { + CwEnv::V1Env { + env: V1Env { + block: v1types::BlockInfo { + height: self.0.block.height, + time: v1types::Timestamp::from_nanos(self.0.block.time), + chain_id: self.0.block.chain_id.clone(), + }, + contract: v1types::ContractInfo { + address: v1types::Addr::unchecked(self.0.contract.address.0), + code_hash: self.0.contract_code_hash, + }, + }, + msg_info: v1types::MessageInfo { + sender: v1types::Addr::unchecked(self.0.message.sender.0), + funds: self + .0 + .message + .sent_funds + .into_iter() + .map(|x| x.into()) + .collect(), + }, + } + } +} + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] +#[serde(rename_all = "snake_case")] +pub enum CwEnv { + V010Env { env: V010Env }, + V1Env { env: V1Env, msg_info: V1MessageInfo }, +} + +impl CwEnv { + pub fn get_contract_hash(&self) -> &String { + match self { + CwEnv::V010Env { env } => &env.contract_code_hash, + CwEnv::V1Env { env, .. } => &env.contract.code_hash, + } + } + + pub fn set_contract_hash(&mut self, contract_hash: &[u8; 32]) { + match self { + CwEnv::V010Env { env } => { + env.contract_code_hash = hex::encode(contract_hash); + } + CwEnv::V1Env { env, .. } => { + env.contract.code_hash = hex::encode(contract_hash); + } + } + } + + pub fn get_wasm_ptrs(&self) -> Result<(Vec, Vec), EnclaveError> { + match self { + CwEnv::V010Env { env } => { + let env_bytes = serde_json::to_vec(env).map_err(|err| { + warn!( + "got an error while trying to serialize env_v010 (cosmwasm v0.10) into bytes {:?}: {}", + env, err + ); + EnclaveError::FailedToSerialize + })?; + + Ok((env_bytes, vec![])) + } + CwEnv::V1Env { env, msg_info } => { + let env_bytes = serde_json::to_vec(env).map_err(|err| { + warn!( + "got an error while trying to serialize env_v010 (cosmwasm v0.10) into bytes {:?}: {}", + env, err + ); + EnclaveError::FailedToSerialize + })?; + let msg_bytes = serde_json::to_vec(msg_info).map_err(|err| { + warn!( + "got an error while trying to serialize env_v010 (cosmwasm v0.10) into bytes {:?}: {}", + msg_info, err + ); + EnclaveError::FailedToSerialize + })?; + + Ok((env_bytes, msg_bytes)) + } + } + } +} + +#[cfg(test)] +mod tests { + #[test] + fn it_works() { + assert_eq!(2 + 2, 4); + } +} diff --git a/cosmwasm/enclaves/shared/cosmwasm-v010-types/Cargo.toml b/cosmwasm/enclaves/shared/cosmwasm-types/v0.10/Cargo.toml similarity index 89% rename from cosmwasm/enclaves/shared/cosmwasm-v010-types/Cargo.toml rename to cosmwasm/enclaves/shared/cosmwasm-types/v0.10/Cargo.toml index 75c2e4b16..ecbde79fe 100644 --- a/cosmwasm/enclaves/shared/cosmwasm-v010-types/Cargo.toml +++ b/cosmwasm/enclaves/shared/cosmwasm-types/v0.10/Cargo.toml @@ -1,6 +1,6 @@ [package] -name = "enclave_cosmwasm_v010_types" -version = "1.2.4" +name = "cw_types_v010" +version = "1.4.0" authors = ["Cashmaney "] edition = "2018" @@ -13,7 +13,7 @@ sgx_tstd = { rev = "a37ffb9449ba6d5b6e4a9d586bbab864ae732269", git = "https://gi ] } [dependencies] -enclave-ffi-types = { path = "../../ffi-types" } +enclave-ffi-types = { path = "../../../ffi-types" } log = "0.4.8" serde = { git = "https://github.com/mesalock-linux/serde-sgx", features = [ "derive" diff --git a/cosmwasm/enclaves/shared/cosmwasm-v1-types/Makefile b/cosmwasm/enclaves/shared/cosmwasm-types/v0.10/Makefile similarity index 89% rename from cosmwasm/enclaves/shared/cosmwasm-v1-types/Makefile rename to cosmwasm/enclaves/shared/cosmwasm-types/v0.10/Makefile index ad94f0548..165f1ac7a 100644 --- a/cosmwasm/enclaves/shared/cosmwasm-v1-types/Makefile +++ b/cosmwasm/enclaves/shared/cosmwasm-types/v0.10/Makefile @@ -6,7 +6,7 @@ else Rust_Flags := "-Z force-unstable-if-unmarked -C target-cpu=skylake" endif -Rust_Target_Path = "$(CURDIR)/../../xargo" +Rust_Target_Path = "$(CURDIR)/../../../xargo" .PHONY: check check: diff --git a/cosmwasm/enclaves/shared/cosmwasm-v010-types/src/coins.rs b/cosmwasm/enclaves/shared/cosmwasm-types/v0.10/src/coins.rs similarity index 100% rename from cosmwasm/enclaves/shared/cosmwasm-v010-types/src/coins.rs rename to cosmwasm/enclaves/shared/cosmwasm-types/v0.10/src/coins.rs diff --git a/cosmwasm/enclaves/shared/cosmwasm-v010-types/src/consts.rs b/cosmwasm/enclaves/shared/cosmwasm-types/v0.10/src/consts.rs similarity index 100% rename from cosmwasm/enclaves/shared/cosmwasm-v010-types/src/consts.rs rename to cosmwasm/enclaves/shared/cosmwasm-types/v0.10/src/consts.rs diff --git a/cosmwasm/enclaves/shared/cosmwasm-v010-types/src/encoding.rs b/cosmwasm/enclaves/shared/cosmwasm-types/v0.10/src/encoding.rs similarity index 100% rename from cosmwasm/enclaves/shared/cosmwasm-v010-types/src/encoding.rs rename to cosmwasm/enclaves/shared/cosmwasm-types/v0.10/src/encoding.rs diff --git a/cosmwasm/enclaves/shared/cosmwasm-v010-types/src/lib.rs b/cosmwasm/enclaves/shared/cosmwasm-types/v0.10/src/lib.rs similarity index 100% rename from cosmwasm/enclaves/shared/cosmwasm-v010-types/src/lib.rs rename to cosmwasm/enclaves/shared/cosmwasm-types/v0.10/src/lib.rs diff --git a/cosmwasm/enclaves/shared/cosmwasm-v010-types/src/math.rs b/cosmwasm/enclaves/shared/cosmwasm-types/v0.10/src/math.rs similarity index 100% rename from cosmwasm/enclaves/shared/cosmwasm-v010-types/src/math.rs rename to cosmwasm/enclaves/shared/cosmwasm-types/v0.10/src/math.rs diff --git a/cosmwasm/enclaves/shared/cosmwasm-v010-types/src/query.rs b/cosmwasm/enclaves/shared/cosmwasm-types/v0.10/src/query.rs similarity index 82% rename from cosmwasm/enclaves/shared/cosmwasm-v010-types/src/query.rs rename to cosmwasm/enclaves/shared/cosmwasm-types/v0.10/src/query.rs index 5154ddb15..51b800cba 100644 --- a/cosmwasm/enclaves/shared/cosmwasm-v010-types/src/query.rs +++ b/cosmwasm/enclaves/shared/cosmwasm-types/v0.10/src/query.rs @@ -17,6 +17,34 @@ pub enum QueryRequest { Dist(DistQuery), Mint(MintQuery), Gov(GovQuery), + Ibc(IbcQuery), + Stargate { path: String, data: Binary }, +} + +/// These are queries to the various IBC modules to see the state of the contract's +/// IBC connection. These will return errors if the contract is not "ibc enabled" +#[non_exhaustive] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] +#[serde(rename_all = "snake_case")] +pub enum IbcQuery { + /// Gets the Port ID the current contract is bound to. + /// + /// Returns a `PortIdResponse`. + PortId {}, + /// Lists all channels that are bound to a given port. + /// If `port_id` is omitted, this list all channels bound to the contract's port. + /// + /// Returns a `ListChannelsResponse`. + ListChannels { port_id: Option }, + /// Lists all information for a (portID, channelID) pair. + /// If port_id is omitted, it will default to the contract's own channel. + /// (To save a PortId{} call) + /// + /// Returns a `ChannelResponse`. + Channel { + channel_id: String, + port_id: Option, + }, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] @@ -97,6 +125,8 @@ pub enum WasmQuery { /// Key is the raw key used in the contracts Storage key: Binary, }, + /// returns a ContractInfoResponse with metadata on the contract from the runtime + ContractInfo { contract_addr: String }, } impl From for QueryRequest { @@ -153,6 +183,19 @@ pub enum StakingQuery { Validators {}, /// Returns all the unbonding delegations by the delegator UnbondingDelegations { delegator: HumanAddr }, + + /// Returns all validators in the currently active validator set. + /// + /// The query response type is `AllValidatorsResponse`. + AllValidators {}, + /// Returns the validator at the given address. Returns None if the validator is + /// not part of the currently active validator set. + /// + /// The query response type is `ValidatorResponse`. + Validator { + /// The validator's address (e.g. (e.g. cosmosvaloper1...)) + address: String, + }, } /// Delegation is basic (cheap to query) data about a delegation diff --git a/cosmwasm/enclaves/shared/cosmwasm-v010-types/src/std_error.rs b/cosmwasm/enclaves/shared/cosmwasm-types/v0.10/src/std_error.rs similarity index 100% rename from cosmwasm/enclaves/shared/cosmwasm-v010-types/src/std_error.rs rename to cosmwasm/enclaves/shared/cosmwasm-types/v0.10/src/std_error.rs diff --git a/cosmwasm/enclaves/shared/cosmwasm-v010-types/src/system_error.rs b/cosmwasm/enclaves/shared/cosmwasm-types/v0.10/src/system_error.rs similarity index 100% rename from cosmwasm/enclaves/shared/cosmwasm-v010-types/src/system_error.rs rename to cosmwasm/enclaves/shared/cosmwasm-types/v0.10/src/system_error.rs diff --git a/cosmwasm/enclaves/shared/cosmwasm-v010-types/src/types.rs b/cosmwasm/enclaves/shared/cosmwasm-types/v0.10/src/types.rs similarity index 99% rename from cosmwasm/enclaves/shared/cosmwasm-v010-types/src/types.rs rename to cosmwasm/enclaves/shared/cosmwasm-types/v0.10/src/types.rs index 54bb82dde..e0d828335 100644 --- a/cosmwasm/enclaves/shared/cosmwasm-v010-types/src/types.rs +++ b/cosmwasm/enclaves/shared/cosmwasm-types/v0.10/src/types.rs @@ -133,6 +133,7 @@ pub struct ContractInfo { // This should be in correlation with cosmwasm-std/init_handle's InitResponse and HandleResponse #[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] +#[serde(deny_unknown_fields)] pub struct ContractResult { pub messages: Vec, pub log: Vec, diff --git a/cosmwasm/enclaves/shared/cosmwasm-v1-types/Cargo.toml b/cosmwasm/enclaves/shared/cosmwasm-types/v1.0/Cargo.toml similarity index 84% rename from cosmwasm/enclaves/shared/cosmwasm-v1-types/Cargo.toml rename to cosmwasm/enclaves/shared/cosmwasm-types/v1.0/Cargo.toml index 2fcbdc5a6..10794b5b2 100644 --- a/cosmwasm/enclaves/shared/cosmwasm-v1-types/Cargo.toml +++ b/cosmwasm/enclaves/shared/cosmwasm-types/v1.0/Cargo.toml @@ -1,6 +1,6 @@ [package] -name = "enclave_cosmwasm_v1_types" -version = "1.2.4" +name = "cw_types_v1" +version = "1.4.0" authors = ["Cashmaney "] edition = "2018" @@ -13,8 +13,8 @@ sgx_tstd = { rev = "a37ffb9449ba6d5b6e4a9d586bbab864ae732269", git = "https://gi ] } [dependencies] -enclave-ffi-types = { path = "../../ffi-types" } -enclave_cosmwasm_v010_types = { path = "../cosmwasm-v010-types" } +enclave-ffi-types = { path = "../../../ffi-types" } +cw_types_v010 = { path = "../v0.10" } log = "0.4.8" serde = { git = "https://github.com/mesalock-linux/serde-sgx", features = [ "derive" diff --git a/cosmwasm/enclaves/shared/cosmwasm-v010-types/Makefile b/cosmwasm/enclaves/shared/cosmwasm-types/v1.0/Makefile similarity index 89% rename from cosmwasm/enclaves/shared/cosmwasm-v010-types/Makefile rename to cosmwasm/enclaves/shared/cosmwasm-types/v1.0/Makefile index ad94f0548..165f1ac7a 100644 --- a/cosmwasm/enclaves/shared/cosmwasm-v010-types/Makefile +++ b/cosmwasm/enclaves/shared/cosmwasm-types/v1.0/Makefile @@ -6,7 +6,7 @@ else Rust_Flags := "-Z force-unstable-if-unmarked -C target-cpu=skylake" endif -Rust_Target_Path = "$(CURDIR)/../../xargo" +Rust_Target_Path = "$(CURDIR)/../../../xargo" .PHONY: check check: diff --git a/cosmwasm/enclaves/shared/cosmwasm-v1-types/src/addresses.rs b/cosmwasm/enclaves/shared/cosmwasm-types/v1.0/src/addresses.rs similarity index 100% rename from cosmwasm/enclaves/shared/cosmwasm-v1-types/src/addresses.rs rename to cosmwasm/enclaves/shared/cosmwasm-types/v1.0/src/addresses.rs diff --git a/cosmwasm/enclaves/shared/cosmwasm-v1-types/src/coins.rs b/cosmwasm/enclaves/shared/cosmwasm-types/v1.0/src/coins.rs similarity index 79% rename from cosmwasm/enclaves/shared/cosmwasm-v1-types/src/coins.rs rename to cosmwasm/enclaves/shared/cosmwasm-types/v1.0/src/coins.rs index 0a54f1959..e923772a0 100644 --- a/cosmwasm/enclaves/shared/cosmwasm-v1-types/src/coins.rs +++ b/cosmwasm/enclaves/shared/cosmwasm-types/v1.0/src/coins.rs @@ -1,6 +1,8 @@ use serde::{Deserialize, Serialize}; use std::fmt; +use cw_types_v010::coins::Coin as V010Coin; + use super::math::Uint128; #[derive(Serialize, Deserialize, Clone, Default, Debug, PartialEq)] @@ -27,3 +29,12 @@ impl fmt::Display for Coin { write!(f, "{}{}", self.amount, self.denom) } } + +impl From for Coin { + fn from(other: V010Coin) -> Self { + Coin { + amount: other.amount.into(), + denom: other.denom, + } + } +} diff --git a/cosmwasm/enclaves/shared/cosmwasm-v1-types/src/errors/crypto_error.rs b/cosmwasm/enclaves/shared/cosmwasm-types/v1.0/src/errors/crypto_error.rs similarity index 100% rename from cosmwasm/enclaves/shared/cosmwasm-v1-types/src/errors/crypto_error.rs rename to cosmwasm/enclaves/shared/cosmwasm-types/v1.0/src/errors/crypto_error.rs diff --git a/cosmwasm/enclaves/shared/cosmwasm-v1-types/src/errors/mod.rs b/cosmwasm/enclaves/shared/cosmwasm-types/v1.0/src/errors/mod.rs similarity index 100% rename from cosmwasm/enclaves/shared/cosmwasm-v1-types/src/errors/mod.rs rename to cosmwasm/enclaves/shared/cosmwasm-types/v1.0/src/errors/mod.rs diff --git a/cosmwasm/enclaves/shared/cosmwasm-v1-types/src/errors/recover_pubkey_error.rs b/cosmwasm/enclaves/shared/cosmwasm-types/v1.0/src/errors/recover_pubkey_error.rs similarity index 100% rename from cosmwasm/enclaves/shared/cosmwasm-v1-types/src/errors/recover_pubkey_error.rs rename to cosmwasm/enclaves/shared/cosmwasm-types/v1.0/src/errors/recover_pubkey_error.rs diff --git a/cosmwasm/enclaves/shared/cosmwasm-v1-types/src/errors/std_error.rs b/cosmwasm/enclaves/shared/cosmwasm-types/v1.0/src/errors/std_error.rs similarity index 100% rename from cosmwasm/enclaves/shared/cosmwasm-v1-types/src/errors/std_error.rs rename to cosmwasm/enclaves/shared/cosmwasm-types/v1.0/src/errors/std_error.rs diff --git a/cosmwasm/enclaves/shared/cosmwasm-v1-types/src/errors/verification_error.rs b/cosmwasm/enclaves/shared/cosmwasm-types/v1.0/src/errors/verification_error.rs similarity index 100% rename from cosmwasm/enclaves/shared/cosmwasm-v1-types/src/errors/verification_error.rs rename to cosmwasm/enclaves/shared/cosmwasm-types/v1.0/src/errors/verification_error.rs diff --git a/cosmwasm/enclaves/shared/cosmwasm-types/v1.0/src/ibc.rs b/cosmwasm/enclaves/shared/cosmwasm-types/v1.0/src/ibc.rs new file mode 100644 index 000000000..6c620e915 --- /dev/null +++ b/cosmwasm/enclaves/shared/cosmwasm-types/v1.0/src/ibc.rs @@ -0,0 +1,297 @@ +use crate::addresses::Addr; +use crate::results::{Event, SubMsg}; +use crate::timestamp::Timestamp; +use cw_types_v010::{encoding::Binary, types::Empty, types::LogAttribute}; +use serde::{Deserialize, Serialize}; +use std::fmt; + +/// The message that is passed into `ibc_channel_open` +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] +#[serde(rename_all = "snake_case")] +pub enum IbcChannelOpenMsg { + /// The ChanOpenInit step from https://github.com/cosmos/ibc/tree/master/spec/core/ics-004-channel-and-packet-semantics#channel-lifecycle-management + OpenInit { channel: IbcChannel }, + /// The ChanOpenTry step from https://github.com/cosmos/ibc/tree/master/spec/core/ics-004-channel-and-packet-semantics#channel-lifecycle-management + OpenTry { + channel: IbcChannel, + counterparty_version: String, + }, +} + +/// IbcChannel defines all information on a channel. +/// This is generally used in the hand-shake process, but can be queried directly. +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] +pub struct IbcChannel { + pub endpoint: IbcEndpoint, + pub counterparty_endpoint: IbcEndpoint, + pub order: IbcOrder, + /// Note: in ibcv3 this may be "", in the IbcOpenChannel handshake messages + pub version: String, + /// The connection upon which this channel was created. If this is a multi-hop + /// channel, we only expose the first hop. + pub connection_id: String, +} + +/// This serializes either as "null" or a JSON object. +pub type IbcChannelOpenResponse = Option; + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] +pub struct Ibc3ChannelOpenResponse { + /// We can set the channel version to a different one than we were called with + pub version: String, +} + +/// This is the return value for the majority of the ibc handlers. +/// That are able to dispatch messages / events on their own, +/// but have no meaningful return value to the calling code. +/// +/// Callbacks that have return values (like receive_packet) +/// or that cannot redispatch messages (like the handshake callbacks) +/// will use other Response types +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] +#[non_exhaustive] +pub struct IbcBasicResponse +where + T: Clone + fmt::Debug + PartialEq, +{ + /// Optional list of messages to pass. These will be executed in order. + /// If the ReplyOn member is set, they will invoke this contract's `reply` entry point + /// after execution. Otherwise, they act like "fire and forget". + /// Use `SubMsg::new` to create messages with the older "fire and forget" semantics. + pub messages: Vec>, + /// The attributes that will be emitted as part of a `wasm` event. + /// + /// More info about events (and their attributes) can be found in [*Cosmos SDK* docs]. + /// + /// [*Cosmos SDK* docs]: https://docs.cosmos.network/v0.42/core/events.html + pub attributes: Vec, + /// Extra, custom events separate from the main `wasm` one. These will have + /// `wasm-` prepended to the type. + /// + /// More info about events can be found in [*Cosmos SDK* docs]. + /// + /// [*Cosmos SDK* docs]: https://docs.cosmos.network/v0.42/core/events.html + pub events: Vec, +} + +impl IbcBasicResponse { + pub fn new( + messages: Vec>, + attributes: Vec, + events: Vec, + ) -> Self { + IbcBasicResponse { + messages, + attributes, + events, + } + } +} + +// This defines the return value on packet response processing. +// This "success" case should be returned even in application-level errors, +// Where the acknowledgement bytes contain an encoded error message to be returned to +// the calling chain. (Returning ContractResult::Err will abort processing of this packet +// and not inform the calling chain). +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] +#[serde(deny_unknown_fields)] +#[non_exhaustive] +pub struct IbcReceiveResponse +where + T: Clone + fmt::Debug + PartialEq, +{ + /// The bytes we return to the contract that sent the packet. + /// This may represent a success or error of exection + pub acknowledgement: Binary, + /// Optional list of messages to pass. These will be executed in order. + /// If the ReplyOn member is set, they will invoke this contract's `reply` entry point + /// after execution. Otherwise, they act like "fire and forget". + /// Use `call` or `msg.into()` to create messages with the older "fire and forget" semantics. + pub messages: Vec>, + /// The attributes that will be emitted as part of a "wasm" event. + /// + /// More info about events (and their attributes) can be found in [*Cosmos SDK* docs]. + /// + /// [*Cosmos SDK* docs]: https://docs.cosmos.network/v0.42/core/events.html + pub attributes: Vec, + /// Extra, custom events separate from the main `wasm` one. These will have + /// `wasm-` prepended to the type. + /// + /// More info about events can be found in [*Cosmos SDK* docs]. + /// + /// [*Cosmos SDK* docs]: https://docs.cosmos.network/v0.42/core/events.html + pub events: Vec, +} + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] +pub struct IbcEndpoint { + pub port_id: String, + pub channel_id: String, +} + +impl IbcEndpoint { + pub fn default() -> Self { + IbcEndpoint { + port_id: String::default(), + channel_id: String::default(), + } + } +} + +/// IbcOrder defines if a channel is ORDERED or UNORDERED +/// Values come from https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/ibc/core/channel/v1/channel.proto#L69-L80 +/// Naming comes from the protobuf files and go translations. +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] +pub enum IbcOrder { + #[serde(rename = "ORDER_UNORDERED")] + Unordered, + #[serde(rename = "ORDER_ORDERED")] + Ordered, +} + +/// The message that is passed into `ibc_channel_connect` +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] +#[serde(rename_all = "snake_case")] +pub enum IbcChannelConnectMsg { + /// The ChanOpenAck step from https://github.com/cosmos/ibc/tree/master/spec/core/ics-004-channel-and-packet-semantics#channel-lifecycle-management + OpenAck { + channel: IbcChannel, + counterparty_version: String, + }, + /// The ChanOpenConfirm step from https://github.com/cosmos/ibc/tree/master/spec/core/ics-004-channel-and-packet-semantics#channel-lifecycle-management + OpenConfirm { channel: IbcChannel }, +} + +/// The message that is passed into `ibc_channel_close` +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] +#[serde(rename_all = "snake_case")] +pub enum IbcChannelCloseMsg { + /// The ChanCloseInit step from https://github.com/cosmos/ibc/tree/master/spec/core/ics-004-channel-and-packet-semantics#channel-lifecycle-management + CloseInit { channel: IbcChannel }, + /// The ChanCloseConfirm step from https://github.com/cosmos/ibc/tree/master/spec/core/ics-004-channel-and-packet-semantics#channel-lifecycle-management + CloseConfirm { channel: IbcChannel }, // pub channel: IbcChannel, +} + +/// The message that is passed into `ibc_packet_receive` +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] +pub struct IbcPacketReceiveMsg { + pub packet: IbcPacket, + pub relayer: Addr, +} + +impl IbcPacketReceiveMsg { + pub fn default() -> Self { + Self { + packet: IbcPacket::default(), + relayer: Addr::unchecked("".to_string()), + } + } +} + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] +pub struct IbcPacket { + /// The raw data sent from the other side in the packet + pub data: Binary, + /// identifies the channel and port on the sending chain. + pub src: IbcEndpoint, + /// identifies the channel and port on the receiving chain. + pub dest: IbcEndpoint, + /// The sequence number of the packet on the given channel + pub sequence: u64, + pub timeout: IbcTimeout, +} + +impl IbcPacket { + pub fn default() -> Self { + Self { + data: vec![].as_slice().into(), + src: IbcEndpoint::default(), + dest: IbcEndpoint::default(), + sequence: 0, + timeout: IbcTimeout::default(), + } + } +} + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] +#[non_exhaustive] +pub struct IbcAcknowledgement { + pub data: Binary, +} + +impl IbcAcknowledgement { + pub fn default() -> Self { + Self { + data: vec![].as_slice().into(), + } + } +} + +/// In IBC each package must set at least one type of timeout: +/// the timestamp or the block height. Using this rather complex enum instead of +/// two timeout fields we ensure that at least one timeout is set. +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] +#[serde(rename_all = "snake_case")] +pub struct IbcTimeout { + // use private fields to enforce the use of constructors, which ensure that at least one is set + block: Option, + timestamp: Option, +} + +impl IbcTimeout { + pub fn default() -> Self { + Self { + block: None, + timestamp: None, + } + } +} + +/// IBCTimeoutHeight Height is a monotonically increasing data type +/// that can be compared against another Height for the purposes of updating and +/// freezing clients. +/// Ordering is (revision_number, timeout_height) +#[derive(Serialize, Deserialize, Copy, Clone, Debug, PartialEq, Eq)] +pub struct IbcTimeoutBlock { + /// the version that the client is currently on + /// (eg. after reseting the chain this could increment 1 as height drops to 0) + pub revision: u64, + /// block height after which the packet times out. + /// the height within the given revision + pub height: u64, +} + +/// The message that is passed into `ibc_packet_ack` +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] +pub struct IbcPacketAckMsg { + pub acknowledgement: IbcAcknowledgement, + pub original_packet: IbcPacket, + pub relayer: Addr, +} + +impl IbcPacketAckMsg { + pub fn default() -> Self { + Self { + acknowledgement: IbcAcknowledgement::default(), + original_packet: IbcPacket::default(), + relayer: Addr::unchecked("".to_string()), + } + } +} + +/// The message that is passed into `ibc_packet_timeout` +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] +#[non_exhaustive] +pub struct IbcPacketTimeoutMsg { + pub packet: IbcPacket, + pub relayer: Addr, +} + +impl IbcPacketTimeoutMsg { + pub fn default() -> Self { + Self { + packet: IbcPacket::default(), + relayer: Addr::unchecked("".to_string()), + } + } +} diff --git a/cosmwasm/enclaves/shared/cosmwasm-v1-types/src/lib.rs b/cosmwasm/enclaves/shared/cosmwasm-types/v1.0/src/lib.rs similarity index 91% rename from cosmwasm/enclaves/shared/cosmwasm-v1-types/src/lib.rs rename to cosmwasm/enclaves/shared/cosmwasm-types/v1.0/src/lib.rs index 310434644..62f52dc66 100644 --- a/cosmwasm/enclaves/shared/cosmwasm-v1-types/src/lib.rs +++ b/cosmwasm/enclaves/shared/cosmwasm-types/v1.0/src/lib.rs @@ -2,6 +2,7 @@ pub mod addresses; pub mod coins; pub mod errors; +pub mod ibc; pub mod math; pub mod results; pub mod timestamp; diff --git a/cosmwasm/enclaves/shared/cosmwasm-v1-types/src/math/mod.rs b/cosmwasm/enclaves/shared/cosmwasm-types/v1.0/src/math/mod.rs similarity index 100% rename from cosmwasm/enclaves/shared/cosmwasm-v1-types/src/math/mod.rs rename to cosmwasm/enclaves/shared/cosmwasm-types/v1.0/src/math/mod.rs diff --git a/cosmwasm/enclaves/shared/cosmwasm-v1-types/src/math/uint128.rs b/cosmwasm/enclaves/shared/cosmwasm-types/v1.0/src/math/uint128.rs similarity index 98% rename from cosmwasm/enclaves/shared/cosmwasm-v1-types/src/math/uint128.rs rename to cosmwasm/enclaves/shared/cosmwasm-types/v1.0/src/math/uint128.rs index 919804442..46c1df620 100644 --- a/cosmwasm/enclaves/shared/cosmwasm-v1-types/src/math/uint128.rs +++ b/cosmwasm/enclaves/shared/cosmwasm-types/v1.0/src/math/uint128.rs @@ -6,6 +6,8 @@ use std::ops; use crate::errors::{DivideByZeroError, OverflowError, OverflowOperation, StdError}; +use cw_types_v010::math::Uint128 as V010Uint128; + /// A thin wrapper around u128 that is using strings for JSON encoding/decoding, /// such that the full u128 range can be used for clients that convert JSON numbers to floats, /// like JavaScript and jq. @@ -321,6 +323,12 @@ impl<'a> Sum<&'a Uint128> for Uint128 { } } +impl From for Uint128 { + fn from(other: V010Uint128) -> Self { + Uint128(other.0) + } +} + /// This module is purely a workaround that lets us ignore lints for all the code /// the `construct_uint!` macro generates. #[allow(clippy::all)] diff --git a/cosmwasm/enclaves/shared/cosmwasm-v1-types/src/math/uint64.rs b/cosmwasm/enclaves/shared/cosmwasm-types/v1.0/src/math/uint64.rs similarity index 100% rename from cosmwasm/enclaves/shared/cosmwasm-v1-types/src/math/uint64.rs rename to cosmwasm/enclaves/shared/cosmwasm-types/v1.0/src/math/uint64.rs diff --git a/cosmwasm/enclaves/shared/cosmwasm-v1-types/src/results/contract_result.rs b/cosmwasm/enclaves/shared/cosmwasm-types/v1.0/src/results/contract_result.rs similarity index 100% rename from cosmwasm/enclaves/shared/cosmwasm-v1-types/src/results/contract_result.rs rename to cosmwasm/enclaves/shared/cosmwasm-types/v1.0/src/results/contract_result.rs diff --git a/cosmwasm/enclaves/shared/cosmwasm-v1-types/src/results/cosmos_msg.rs b/cosmwasm/enclaves/shared/cosmwasm-types/v1.0/src/results/cosmos_msg.rs similarity index 80% rename from cosmwasm/enclaves/shared/cosmwasm-v1-types/src/results/cosmos_msg.rs rename to cosmwasm/enclaves/shared/cosmwasm-types/v1.0/src/results/cosmos_msg.rs index f141bff5f..dfe5d4f76 100644 --- a/cosmwasm/enclaves/shared/cosmwasm-v1-types/src/results/cosmos_msg.rs +++ b/cosmwasm/enclaves/shared/cosmwasm-types/v1.0/src/results/cosmos_msg.rs @@ -1,10 +1,9 @@ use serde::{Deserialize, Serialize}; use std::fmt; -use crate::coins::Coin; -#[cfg(feature = "stargate")] -use crate::ibc::IbcMsg; -use enclave_cosmwasm_v010_types::encoding::Binary; +use crate::{coins::Coin, ibc::IbcTimeout}; + +use cw_types_v010::encoding::Binary; use super::Empty; @@ -19,21 +18,16 @@ where // by default we use RawMsg, but a contract can override that // to call into more app-specific code (whatever they define) Custom(T), - #[cfg(feature = "staking")] Staking(StakingMsg), - #[cfg(feature = "staking")] Distribution(DistributionMsg), /// A Stargate message encoded the same way as a protobuf [Any](https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/any.proto). /// This is the same structure as messages in `TxBody` from [ADR-020](https://github.com/cosmos/cosmos-sdk/blob/master/docs/architecture/adr-020-protobuf-transaction-encoding.md) - #[cfg(feature = "stargate")] Stargate { type_url: String, value: Binary, }, - #[cfg(feature = "stargate")] Ibc(IbcMsg), Wasm(WasmMsg), - #[cfg(feature = "stargate")] Gov(GovMsg), } @@ -57,12 +51,47 @@ pub enum BankMsg { Burn { amount: Vec }, } +/// These are messages in the IBC lifecycle. Only usable by IBC-enabled contracts +/// (contracts that directly speak the IBC protocol via 6 entry points) +#[non_exhaustive] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] +#[serde(rename_all = "snake_case")] +pub enum IbcMsg { + /// Sends bank tokens owned by the contract to the given address on another chain. + /// The channel must already be established between the ibctransfer module on this chain + /// and a matching module on the remote chain. + /// We cannot select the port_id, this is whatever the local chain has bound the ibctransfer + /// module to. + Transfer { + /// exisiting channel to send the tokens over + channel_id: String, + /// address on the remote chain to receive these tokens + to_address: String, + /// packet data only supports one coin + /// https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/ibc/applications/transfer/v1/transfer.proto#L11-L20 + amount: Coin, + /// when packet times out, measured on remote chain + timeout: IbcTimeout, + }, + /// Sends an IBC packet with given data over the existing channel. + /// Data should be encoded in a format defined by the channel version, + /// and the module on the other side should know how to parse this. + SendPacket { + channel_id: String, + data: Binary, + /// when packet times out, measured on remote chain + timeout: IbcTimeout, + }, + /// This will close an existing channel that is owned by this contract. + /// Port is auto-assigned to the contract's IBC port + CloseChannel { channel_id: String }, +} + pub const REPLY_ENCRYPTION_MAGIC_BYTES: &[u8] = b"REPLY01"; /// The message types of the staking module. /// /// See https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto -#[cfg(feature = "staking")] #[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] #[serde(rename_all = "snake_case")] pub enum StakingMsg { @@ -84,7 +113,6 @@ pub enum StakingMsg { /// The message types of the distribution module. /// /// See https://github.com/cosmos/cosmos-sdk/blob/v0.42.4/proto/cosmos/distribution/v1beta1/tx.proto -#[cfg(feature = "staking")] #[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] #[serde(rename_all = "snake_case")] pub enum DistributionMsg { @@ -147,7 +175,6 @@ pub enum WasmMsg { }, } -#[cfg(feature = "stargate")] #[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] #[serde(rename_all = "snake_case")] pub enum GovMsg { @@ -155,7 +182,6 @@ pub enum GovMsg { Vote { proposal_id: u64, vote: VoteOption }, } -#[cfg(feature = "stargate")] #[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] #[serde(rename_all = "snake_case")] pub enum VoteOption { @@ -164,61 +190,3 @@ pub enum VoteOption { Abstain, NoWithVeto, } - -impl From for CosmosMsg -where - T: Clone + fmt::Debug + PartialEq, -{ - fn from(msg: BankMsg) -> Self { - CosmosMsg::Bank(msg) - } -} - -#[cfg(feature = "staking")] -impl From for CosmosMsg -where - T: Clone + fmt::Debug + PartialEq, -{ - fn from(msg: StakingMsg) -> Self { - CosmosMsg::Staking(msg) - } -} - -#[cfg(feature = "staking")] -impl From for CosmosMsg -where - T: Clone + fmt::Debug + PartialEq, -{ - fn from(msg: DistributionMsg) -> Self { - CosmosMsg::Distribution(msg) - } -} - -impl From for CosmosMsg -where - T: Clone + fmt::Debug + PartialEq, -{ - fn from(msg: WasmMsg) -> Self { - CosmosMsg::Wasm(msg) - } -} - -#[cfg(feature = "stargate")] -impl From for CosmosMsg -where - T: Clone + fmt::Debug + PartialEq, -{ - fn from(msg: IbcMsg) -> Self { - CosmosMsg::Ibc(msg) - } -} - -#[cfg(feature = "stargate")] -impl From for CosmosMsg -where - T: Clone + fmt::Debug + PartialEq, -{ - fn from(msg: GovMsg) -> Self { - CosmosMsg::Gov(msg) - } -} diff --git a/cosmwasm/enclaves/shared/cosmwasm-v1-types/src/results/empty.rs b/cosmwasm/enclaves/shared/cosmwasm-types/v1.0/src/results/empty.rs similarity index 100% rename from cosmwasm/enclaves/shared/cosmwasm-v1-types/src/results/empty.rs rename to cosmwasm/enclaves/shared/cosmwasm-types/v1.0/src/results/empty.rs diff --git a/cosmwasm/enclaves/shared/cosmwasm-v1-types/src/results/events.rs b/cosmwasm/enclaves/shared/cosmwasm-types/v1.0/src/results/events.rs similarity index 94% rename from cosmwasm/enclaves/shared/cosmwasm-v1-types/src/results/events.rs rename to cosmwasm/enclaves/shared/cosmwasm-types/v1.0/src/results/events.rs index 34e5e8450..caa8bb305 100644 --- a/cosmwasm/enclaves/shared/cosmwasm-v1-types/src/results/events.rs +++ b/cosmwasm/enclaves/shared/cosmwasm-types/v1.0/src/results/events.rs @@ -1,4 +1,4 @@ -use enclave_cosmwasm_v010_types::types::LogAttribute; +use cw_types_v010::types::LogAttribute; use serde::{Deserialize, Serialize}; /// A full [*Cosmos SDK* event]. /// diff --git a/cosmwasm/enclaves/shared/cosmwasm-types/v1.0/src/results/mod.rs b/cosmwasm/enclaves/shared/cosmwasm-types/v1.0/src/results/mod.rs new file mode 100644 index 000000000..2476e5bf6 --- /dev/null +++ b/cosmwasm/enclaves/shared/cosmwasm-types/v1.0/src/results/mod.rs @@ -0,0 +1,15 @@ +//! This module contains the messages that are sent from the contract to the VM as an execution result + +mod contract_result; +mod cosmos_msg; +mod empty; +mod events; +mod response; +mod submessages; + +pub use contract_result::*; +pub use cosmos_msg::*; +pub use empty::*; +pub use events::*; +pub use response::*; +pub use submessages::*; diff --git a/cosmwasm/enclaves/shared/cosmwasm-v1-types/src/results/response.rs b/cosmwasm/enclaves/shared/cosmwasm-types/v1.0/src/results/response.rs similarity index 96% rename from cosmwasm/enclaves/shared/cosmwasm-v1-types/src/results/response.rs rename to cosmwasm/enclaves/shared/cosmwasm-types/v1.0/src/results/response.rs index 1a6054a0c..06a90890f 100644 --- a/cosmwasm/enclaves/shared/cosmwasm-v1-types/src/results/response.rs +++ b/cosmwasm/enclaves/shared/cosmwasm-types/v1.0/src/results/response.rs @@ -1,9 +1,9 @@ use serde::{Deserialize, Serialize}; use std::fmt; -use enclave_cosmwasm_v010_types::{encoding::Binary, types::LogAttribute}; +use cw_types_v010::{encoding::Binary, types::Empty, types::LogAttribute}; -use super::{Empty, Event, SubMsg}; +use super::{Event, SubMsg}; /// A response of a contract entry point, such as `instantiate` or `execute`. /// @@ -60,6 +60,7 @@ use super::{Empty, Event, SubMsg}; /// } /// ``` #[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] +#[serde(deny_unknown_fields)] pub struct Response where T: Clone + fmt::Debug + PartialEq, diff --git a/cosmwasm/enclaves/shared/cosmwasm-v1-types/src/results/submessages.rs b/cosmwasm/enclaves/shared/cosmwasm-types/v1.0/src/results/submessages.rs similarity index 87% rename from cosmwasm/enclaves/shared/cosmwasm-v1-types/src/results/submessages.rs rename to cosmwasm/enclaves/shared/cosmwasm-types/v1.0/src/results/submessages.rs index b408467ff..4a0f08412 100644 --- a/cosmwasm/enclaves/shared/cosmwasm-v1-types/src/results/submessages.rs +++ b/cosmwasm/enclaves/shared/cosmwasm-types/v1.0/src/results/submessages.rs @@ -1,7 +1,7 @@ use serde::{Deserialize, Serialize}; use std::fmt; -use enclave_cosmwasm_v010_types::encoding::Binary; +use cw_types_v010::encoding::Binary; use super::{CosmosMsg, Empty, Event}; @@ -21,6 +21,10 @@ pub enum ReplyOn { Never, } +fn bool_false() -> bool { + false +} + /// A submessage that will guarantee a `reply` call on success or error, depending on /// the `reply_on` setting. If you do not need to process the result, use regular messages instead. /// @@ -38,6 +42,11 @@ where pub msg: CosmosMsg, pub gas_limit: Option, pub reply_on: ReplyOn, + // An indication that will be passed to the reply that will indicate wether the original message, + // which is the one who create the submessages, was encrypted or not. + // Plaintext replies will be encrypted only if the original message was. + #[serde(default = "bool_false")] + pub was_msg_encrypted: bool, } /// The information we get back from a successful sub message execution, @@ -65,6 +74,7 @@ pub struct Reply { /// Use this to identify which submessage triggered the `reply`. pub id: Binary, pub result: SubMsgResult, + pub was_msg_encrypted: bool, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] pub struct DecryptedReply { diff --git a/cosmwasm/enclaves/shared/cosmwasm-v1-types/src/timestamp.rs b/cosmwasm/enclaves/shared/cosmwasm-types/v1.0/src/timestamp.rs similarity index 100% rename from cosmwasm/enclaves/shared/cosmwasm-v1-types/src/timestamp.rs rename to cosmwasm/enclaves/shared/cosmwasm-types/v1.0/src/timestamp.rs diff --git a/cosmwasm/enclaves/shared/cosmwasm-v1-types/src/types.rs b/cosmwasm/enclaves/shared/cosmwasm-types/v1.0/src/types.rs similarity index 97% rename from cosmwasm/enclaves/shared/cosmwasm-v1-types/src/types.rs rename to cosmwasm/enclaves/shared/cosmwasm-types/v1.0/src/types.rs index e78d3e21b..537a05af8 100644 --- a/cosmwasm/enclaves/shared/cosmwasm-v1-types/src/types.rs +++ b/cosmwasm/enclaves/shared/cosmwasm-types/v1.0/src/types.rs @@ -1,8 +1,8 @@ use serde::{Deserialize, Serialize}; -use super::addresses::Addr; -use super::coins::Coin; -use super::timestamp::Timestamp; +pub use super::addresses::Addr; +pub use super::coins::Coin; +pub use super::timestamp::Timestamp; #[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] pub struct Env { diff --git a/cosmwasm/enclaves/shared/cosmwasm-v1-types/src/results/mod.rs b/cosmwasm/enclaves/shared/cosmwasm-v1-types/src/results/mod.rs deleted file mode 100644 index 21b5d7b74..000000000 --- a/cosmwasm/enclaves/shared/cosmwasm-v1-types/src/results/mod.rs +++ /dev/null @@ -1,19 +0,0 @@ -//! This module contains the messages that are sent from the contract to the VM as an execution result - -mod contract_result; -mod cosmos_msg; -mod empty; -mod events; -mod response; -mod submessages; - -pub use contract_result::ContractResult; -pub use cosmos_msg::{BankMsg, CosmosMsg, WasmMsg, REPLY_ENCRYPTION_MAGIC_BYTES}; -#[cfg(feature = "staking")] -pub use cosmos_msg::{DistributionMsg, StakingMsg}; -#[cfg(feature = "stargate")] -pub use cosmos_msg::{GovMsg, VoteOption}; -pub use empty::Empty; -pub use events::Event; -pub use response::Response; -pub use submessages::{DecryptedReply, Reply, SubMsgResponse, SubMsgResult, ReplyOn, SubMsg, SubMsgExecutionResponse}; diff --git a/cosmwasm/enclaves/shared/crypto/Cargo.toml b/cosmwasm/enclaves/shared/crypto/Cargo.toml index 1760b23ff..8730879cf 100644 --- a/cosmwasm/enclaves/shared/crypto/Cargo.toml +++ b/cosmwasm/enclaves/shared/crypto/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "enclave_crypto" -version = "1.2.4" +version = "1.4.0" authors = ["Cashmaney "] edition = "2018" @@ -19,19 +19,18 @@ sgx_types = { rev = "a37ffb9449ba6d5b6e4a9d586bbab864ae732269", git = "https://g [dependencies] sgx_trts = { rev = "a37ffb9449ba6d5b6e4a9d586bbab864ae732269", git = "https://github.com/apache/teaclave-sgx-sdk.git" } - enclave-ffi-types = { path = "../../ffi-types" } - log = "0.4.8" derive_more = "0.99" lazy_static = "1.4" hex = "0.4.2" - ring = { git = "https://github.com/mesalock-linux/ring-sgx", tag = "v0.16.5" } sha2 = "0.8.1" +sha3 = "0.8.1" ripemd160 = "0.9.1" secp256k1 = "0.21.3" aes-siv = "=0.6.2" x25519-dalek = { version = "=1.2.0", default-features = false, features = [ "u64_backend" ] } +cosmos_proto = { path = "../cosmos-proto" } diff --git a/cosmwasm/enclaves/shared/crypto/src/secp256k1.rs b/cosmwasm/enclaves/shared/crypto/src/secp256k1.rs index aab3e37cf..074e26b85 100644 --- a/cosmwasm/enclaves/shared/crypto/src/secp256k1.rs +++ b/cosmwasm/enclaves/shared/crypto/src/secp256k1.rs @@ -2,8 +2,10 @@ use log::*; use crate::traits::VerifyingKey; use crate::CryptoError; +use cosmos_proto::tx::signing::SignMode; use secp256k1::Secp256k1; use sha2::{Digest as Sha2Digest, Sha256}; +use sha3::Keccak256; pub const SECP256K1_PREFIX: [u8; 4] = [235, 90, 233, 135]; @@ -17,9 +19,18 @@ impl Secp256k1PubKey { } impl VerifyingKey for Secp256k1PubKey { - fn verify_bytes(&self, bytes: &[u8], sig: &[u8]) -> Result<(), CryptoError> { + fn verify_bytes( + &self, + bytes: &[u8], + sig: &[u8], + sign_mode: SignMode, + ) -> Result<(), CryptoError> { // Signing ref: https://docs.cosmos.network/master/spec/_ics/ics-030-signed-messages.html#preliminary - let sign_bytes_hash = Sha256::digest(bytes); + let sign_bytes_hash = if sign_mode == SignMode::SIGN_MODE_EIP_191 { + Keccak256::digest(bytes) + } else { + Sha256::digest(bytes) + }; let msg = secp256k1::Message::from_slice(sign_bytes_hash.as_slice()).map_err(|err| { warn!("Failed to create a secp256k1 message from tx: {:?}", err); CryptoError::VerificationError diff --git a/cosmwasm/enclaves/shared/crypto/src/traits.rs b/cosmwasm/enclaves/shared/crypto/src/traits.rs index fe058203a..3e0651857 100644 --- a/cosmwasm/enclaves/shared/crypto/src/traits.rs +++ b/cosmwasm/enclaves/shared/crypto/src/traits.rs @@ -1,3 +1,4 @@ +use cosmos_proto::tx::signing::SignMode; use enclave_ffi_types::EnclaveError; use crate::errors::CryptoError; @@ -44,5 +45,10 @@ pub trait ExportECKey { // https://github.com/tendermint/tendermint/blob/v0.33.3/crypto/crypto.go#L22 pub trait VerifyingKey: PartialEq { /// Verify that `sig` was generated by this public key, for the content in `bytes` - fn verify_bytes(&self, bytes: &[u8], sig: &[u8]) -> Result<(), CryptoError>; + fn verify_bytes( + &self, + bytes: &[u8], + sig: &[u8], + sign_mode: SignMode, + ) -> Result<(), CryptoError>; } diff --git a/cosmwasm/enclaves/shared/utils/Cargo.toml b/cosmwasm/enclaves/shared/utils/Cargo.toml index 78d74d86a..cb451b52b 100644 --- a/cosmwasm/enclaves/shared/utils/Cargo.toml +++ b/cosmwasm/enclaves/shared/utils/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "enclave_utils" -version = "1.2.4" +version = "1.4.0" authors = ["Cashmaney "] edition = "2018" diff --git a/cosmwasm/packages/sgx-vm/src/errors/vm_error.rs b/cosmwasm/packages/sgx-vm/src/errors/vm_error.rs index 7fca9f045..e72b445dc 100644 --- a/cosmwasm/packages/sgx-vm/src/errors/vm_error.rs +++ b/cosmwasm/packages/sgx-vm/src/errors/vm_error.rs @@ -1,5 +1,5 @@ use snafu::Snafu; -use std::fmt::{Debug, Display}; +use std::fmt::Debug; use super::communication_error::CommunicationError; // use crate::backends::InsufficientGasLeft; @@ -7,6 +7,8 @@ use crate::ffi::FfiError; use super::EnclaveError; +const MAX_ERR_LEN: usize = 4096; + #[derive(Debug, Snafu)] #[non_exhaustive] pub enum VmError { @@ -105,11 +107,17 @@ pub enum VmError { #[allow(unused)] impl VmError { pub(crate) fn cache_err>(msg: S) -> Self { - CacheErr { msg: msg.into() }.build() + CacheErr { + msg: &Self::truncate_input(msg), + } + .build() } pub(crate) fn compile_err>(msg: S) -> Self { - CompileErr { msg: msg.into() }.build() + CompileErr { + msg: &Self::truncate_input(msg), + } + .build() } pub(crate) fn conversion_err, T: Into, U: Into>( @@ -118,19 +126,25 @@ impl VmError { input: U, ) -> Self { ConversionErr { - from_type: from_type.into(), - to_type: to_type.into(), - input: input.into(), + from_type: &Self::truncate_input(from_type), + to_type: &Self::truncate_input(to_type), + input: &Self::truncate_input(input), } .build() } pub(crate) fn generic_err>(msg: S) -> Self { - GenericErr { msg: msg.into() }.build() + GenericErr { + msg: &Self::truncate_input(msg), + } + .build() } pub(crate) fn instantiation_err>(msg: S) -> Self { - InstantiationErr { msg: msg.into() }.build() + InstantiationErr { + msg: &Self::truncate_input(msg), + } + .build() } pub(crate) fn integrity_err() -> Self { @@ -142,36 +156,57 @@ impl VmError { IteratorDoesNotExist { id: iterator_id }.build() } - pub(crate) fn parse_err, M: Display>(target: T, msg: M) -> Self { + pub(crate) fn parse_err, M: Into>(target: T, msg: M) -> Self { ParseErr { - target: target.into(), - msg: msg.to_string(), + target: &Self::truncate_input(target), + msg: &Self::truncate_input(msg), } .build() } - pub(crate) fn serialize_err, M: Display>(source: S, msg: M) -> Self { + pub(crate) fn serialize_err, M: Into>(source: S, msg: M) -> Self { SerializeErr { - source: source.into(), - msg: msg.to_string(), + source: &Self::truncate_input(source), + msg: &Self::truncate_input(msg), } .build() } pub(crate) fn resolve_err>(msg: S) -> Self { - ResolveErr { msg: msg.into() }.build() + ResolveErr { + msg: &Self::truncate_input(msg), + } + .build() } pub(crate) fn runtime_err>(msg: S) -> Self { - RuntimeErr { msg: msg.into() }.build() + RuntimeErr { + msg: &Self::truncate_input(msg), + } + .build() } pub(crate) fn static_validation_err>(msg: S) -> Self { - StaticValidationErr { msg: msg.into() }.build() + StaticValidationErr { + msg: &Self::truncate_input(msg), + } + .build() } pub(crate) fn uninitialized_context_data>(kind: S) -> Self { - UninitializedContextData { kind: kind.into() }.build() + UninitializedContextData { + kind: &Self::truncate_input(kind), + } + .build() + } + + // this is not super ideal, as we don't want super long strings to be copied and moved around + // but it'll at least limit the shit that gets thrown on-chain + fn truncate_input>(msg: S) -> String { + let mut s: String = msg.into(); + + s.truncate(MAX_ERR_LEN); + s } pub(crate) fn write_access_denied() -> Self { @@ -196,57 +231,6 @@ impl From for VmError { } } -/* -impl From for VmError { - fn from(original: wasmer_runtime_core::cache::Error) -> Self { - VmError::cache_err(format!("Wasmer cache error: {:?}", original)) - } -} - -impl From for VmError { - fn from(original: wasmer_runtime_core::error::CompileError) -> Self { - VmError::compile_err(format!("Wasmer compile error: {:?}", original)) - } -} - -impl From for VmError { - fn from(original: wasmer_runtime_core::error::ResolveError) -> Self { - VmError::resolve_err(format!("Wasmer resolve error: {:?}", original)) - } -} - -impl From for VmError { - fn from(original: wasmer_runtime_core::error::RuntimeError) -> Self { - use wasmer_runtime_core::error::{InvokeError, RuntimeError}; - - fn runtime_error(err: RuntimeError) -> VmError { - VmError::runtime_err(format!("Wasmer runtime error: {:?}", err)) - } - - match original { - // TODO: fix the issue described below: - // `InvokeError::FailedWithNoError` happens when running out of gas in singlepass v0.17 - // but it's supposed to indicate bugs in Wasmer... - // https://github.com/wasmerio/wasmer/issues/1452 - // https://github.com/CosmWasm/cosmwasm/issues/375 - RuntimeError::InvokeError(InvokeError::FailedWithNoError) => VmError::GasDepletion, - // This variant contains the error we return from imports. - RuntimeError::User(err) => match err.downcast::() { - Ok(err) => *err, - Err(err) => runtime_error(RuntimeError::User(err)), - }, - _ => runtime_error(original), - } - } -} - -impl From for VmError { - fn from(_original: InsufficientGasLeft) -> Self { - VmError::GasDepletion - } -} -*/ - #[cfg(test)] mod test { use super::*; @@ -301,6 +285,18 @@ mod test { } } + #[test] + fn truncation_of_error_works() { + let long_string = String::from_utf8(vec![b'X'; 4096]).unwrap(); + let error = VmError::generic_err(format!("{} should not be here", long_string)); + match error { + VmError::GenericErr { msg, .. } => { + assert_eq!(msg, long_string); + } + e => panic!("Unexpected error: {:?}", e), + } + } + #[test] fn instantiation_err_works() { let error = VmError::instantiation_err("something went wrong"); diff --git a/cosmwasm/packages/sgx-vm/src/serde.rs b/cosmwasm/packages/sgx-vm/src/serde.rs index 8e1640028..c4a00a2e0 100644 --- a/cosmwasm/packages/sgx-vm/src/serde.rs +++ b/cosmwasm/packages/sgx-vm/src/serde.rs @@ -11,12 +11,12 @@ pub fn from_slice<'a, T>(value: &'a [u8]) -> VmResult where T: Deserialize<'a>, { - serde_json::from_slice(value).map_err(|e| VmError::parse_err(type_name::(), e)) + serde_json::from_slice(value).map_err(|e| VmError::parse_err(type_name::(), e.to_string())) } pub fn to_vec(data: &T) -> VmResult> where T: Serialize + ?Sized, { - serde_json::to_vec(data).map_err(|e| VmError::serialize_err(type_name::(), e)) + serde_json::to_vec(data).map_err(|e| VmError::serialize_err(type_name::(), e.to_string())) } diff --git a/deployment/docker/devimage/bootstrap_init_no_stop.sh b/deployment/docker/devimage/bootstrap_init_no_stop.sh index 486a1d4ff..318da5e3a 100755 --- a/deployment/docker/devimage/bootstrap_init_no_stop.sh +++ b/deployment/docker/devimage/bootstrap_init_no_stop.sh @@ -8,6 +8,7 @@ then rm -rf /opt/secret/.sgx_secrets/* chain_id=${CHAINID:-secretdev-1} + LOG_LEVEL=${LOG_LEVEL:-INFO} mkdir -p ./.sgx_secrets secretd config chain-id "$chain_id" @@ -67,5 +68,5 @@ setsid node faucet_server.js & # Setup secretcli cp $(which secretd) $(dirname $(which secretd))/secretcli -source /opt/sgxsdk/environment && RUST_BACKTRACE=1 LOG_LEVEL=INFO secretd start --rpc.laddr tcp://0.0.0.0:26657 --bootstrap +source /opt/sgxsdk/environment && RUST_BACKTRACE=1 LOG_LEVEL="$LOG_LEVEL" secretd start --rpc.laddr tcp://0.0.0.0:26657 --bootstrap diff --git a/go-cosmwasm/cmd/main.go b/go-cosmwasm/cmd/main.go index 20237995a..a2137d132 100644 --- a/go-cosmwasm/cmd/main.go +++ b/go-cosmwasm/cmd/main.go @@ -22,7 +22,7 @@ func main() { panic(err) } - wasmer, err := wasm.NewWasmer("tmp", "staking", 0, 15) + wasmer, err := wasm.NewWasmer("tmp", "staking,stargate,ibc3", 0, 15) if err != nil { panic(err) } diff --git a/go-cosmwasm/lib.go b/go-cosmwasm/lib.go index 4cdfdcd95..bf83e12a5 100644 --- a/go-cosmwasm/lib.go +++ b/go-cosmwasm/lib.go @@ -85,11 +85,14 @@ func (w *Wasmer) GetCode(code CodeID) (WasmCode, error) { } // This struct helps us to distinguish between v0.10 contract response and v1 contract response -type V010orV1ContractExecResponse struct { - V1 *V1ContractExecResponse `json:"v1,omitempty"` - V010 *V010ContractExecResponse `json:"v010,omitempty"` - InternaReplyEnclaveSig []byte `json:"internal_reply_enclave_sig"` - InternalMsgId []byte `json:"internal_msg_id"` +type ContractExecResponse struct { + V1 *V1ContractExecResponse `json:"v1,omitempty"` + V010 *V010ContractExecResponse `json:"v010,omitempty"` + InternaReplyEnclaveSig []byte `json:"internal_reply_enclave_sig"` + InternalMsgId []byte `json:"internal_msg_id"` + IBCBasic *v1types.IBCBasicResult `json:"ibc_basic,omitempty"` + IBCPacketReceive *v1types.IBCReceiveResult `json:"ibc_packet_receive,omitempty"` + IBCChannelOpen *v1types.IBCOpenChannelResult `json:"ibc_open_channel,omitempty"` } type V010ContractExecResponse struct { @@ -205,7 +208,7 @@ func (w *Wasmer) Instantiate( if isOutputAddressedToReply { respV010orV1.V1.Ok.Data, err = AppendReplyInternalDataToData(respV010orV1.V1.Ok.Data, respV010orV1.InternaReplyEnclaveSig, respV010orV1.InternalMsgId) if err != nil { - return nil, nil, gasUsed, fmt.Errorf("cannot serialize v1 DataWithInternalReplyInfo into binary : %w", err) + return nil, nil, gasUsed, fmt.Errorf("cannot serialize v1 DataWithInternalReplyInfo into binary: %w", err) } } else { respV010orV1.V1.Ok.Data = nil @@ -260,55 +263,86 @@ func (w *Wasmer) Execute( return nil, gasUsed, err } - var respV010orV1 V010orV1ContractExecResponse - err = json.Unmarshal(data, &respV010orV1) + var resp ContractExecResponse + err = json.Unmarshal(data, &resp) if err != nil { // unidentified response 🤷 return nil, gasUsed, fmt.Errorf("handle: cannot parse response from json: %w", err) } - isOutputAddressedToReply := (len(respV010orV1.InternaReplyEnclaveSig) > 0 && len(respV010orV1.InternalMsgId) > 0) + isOutputAddressedToReply := (len(resp.InternaReplyEnclaveSig) > 0 && len(resp.InternalMsgId) > 0) // handle v0.10 response - if respV010orV1.V010 != nil { - if respV010orV1.V010.Err != nil { + if resp.V010 != nil { + if resp.V010.Err != nil { return v1types.DataWithInternalReplyInfo{ - InternalMsgId: respV010orV1.InternalMsgId, - InternaReplyEnclaveSig: respV010orV1.InternaReplyEnclaveSig, - Data: []byte(respV010orV1.V010.Err.GenericErr.Msg), - }, gasUsed, fmt.Errorf("%+v", respV010orV1.V010.Err) - } - - if respV010orV1.V010.Ok != nil { + InternalMsgId: resp.InternalMsgId, + InternaReplyEnclaveSig: resp.InternaReplyEnclaveSig, + Data: []byte(resp.V010.Err.GenericErr.Msg), + }, gasUsed, fmt.Errorf("%+v", resp.V010.Err) + } else if resp.V010.Ok != nil { if isOutputAddressedToReply { - respV010orV1.V010.Ok.Data, err = AppendReplyInternalDataToData(respV010orV1.V010.Ok.Data, respV010orV1.InternaReplyEnclaveSig, respV010orV1.InternalMsgId) + resp.V010.Ok.Data, err = AppendReplyInternalDataToData(resp.V010.Ok.Data, resp.InternaReplyEnclaveSig, resp.InternalMsgId) if err != nil { - return nil, gasUsed, fmt.Errorf("cannot serialize v010 DataWithInternalReplyInfo into binary : %w", err) + return nil, gasUsed, fmt.Errorf("cannot serialize v0.10 DataWithInternalReplyInfo into binary : %w", err) } } - return respV010orV1.V010.Ok, gasUsed, nil + return resp.V010.Ok, gasUsed, nil + } else { + return nil, gasUsed, fmt.Errorf("cannot parse v0.10 handle response: %+v", resp) } } // handle v1 response - if respV010orV1.V1 != nil { - if respV010orV1.V1.Err != nil { + if resp.V1 != nil { + if resp.V1.Err != nil { return v1types.DataWithInternalReplyInfo{ - InternalMsgId: respV010orV1.InternalMsgId, - InternaReplyEnclaveSig: respV010orV1.InternaReplyEnclaveSig, - Data: []byte(respV010orV1.V1.Err.GenericErr.Msg), - }, gasUsed, fmt.Errorf("%+v", respV010orV1.V1.Err) - } - - if respV010orV1.V1.Ok != nil { + InternalMsgId: resp.InternalMsgId, + InternaReplyEnclaveSig: resp.InternaReplyEnclaveSig, + Data: []byte(resp.V1.Err.GenericErr.Msg), + }, gasUsed, fmt.Errorf("%+v", resp.V1.Err) + } else if resp.V1.Ok != nil { if isOutputAddressedToReply { - respV010orV1.V1.Ok.Data, err = AppendReplyInternalDataToData(respV010orV1.V1.Ok.Data, respV010orV1.InternaReplyEnclaveSig, respV010orV1.InternalMsgId) + resp.V1.Ok.Data, err = AppendReplyInternalDataToData(resp.V1.Ok.Data, resp.InternaReplyEnclaveSig, resp.InternalMsgId) if err != nil { - return nil, gasUsed, fmt.Errorf("cannot serialize v1 DataWithInternalReplyInfo into binary : %w", err) + return nil, gasUsed, fmt.Errorf("cannot serialize v1 DataWithInternalReplyInfo into binary: %w", err) } } - return respV010orV1.V1.Ok, gasUsed, nil + return resp.V1.Ok, gasUsed, nil + } else { + return nil, gasUsed, fmt.Errorf("cannot parse v1 handle response: %+v", resp) + } + } + + if resp.IBCBasic != nil { + if resp.IBCBasic.Err != nil { + return nil, gasUsed, fmt.Errorf("%+v", resp.IBCBasic.Err) + } else if resp.IBCBasic.Ok != nil { + return resp.IBCBasic.Ok, gasUsed, nil + } else { + return nil, gasUsed, fmt.Errorf("cannot parse IBCBasic response: %+v", resp) + } + } + + if resp.IBCPacketReceive != nil { + if resp.IBCPacketReceive.Err != nil { + return nil, gasUsed, fmt.Errorf("%+v", resp.IBCPacketReceive.Err) + } else if resp.IBCPacketReceive.Ok != nil { + return resp.IBCPacketReceive.Ok, gasUsed, nil + } else { + return nil, gasUsed, fmt.Errorf("cannot parse IBCPacketReceive response: %+v", resp) + } + } + + if resp.IBCChannelOpen != nil { + if resp.IBCChannelOpen.Err != nil { + return nil, gasUsed, fmt.Errorf("%+v", resp.IBCChannelOpen.Err) + } else if resp.IBCChannelOpen.Ok != nil { + // ibc_channel_open actually returns no data + return resp.IBCChannelOpen.Ok, gasUsed, nil + } else { + return nil, gasUsed, fmt.Errorf("cannot parse IBCChannelOpen response: %+v", resp) } } diff --git a/go-cosmwasm/types/env.go b/go-cosmwasm/types/env.go index 6afd3d27d..ac93d8067 100644 --- a/go-cosmwasm/types/env.go +++ b/go-cosmwasm/types/env.go @@ -15,6 +15,10 @@ type Env struct { Recursive bool `json:"recursive"` } +type BaseEnv[T Env] struct { + First T +} + type ContractKey string type BlockInfo struct { diff --git a/go-cosmwasm/types/queries.go b/go-cosmwasm/types/queries.go index 9fa681c72..65d8f4e24 100644 --- a/go-cosmwasm/types/queries.go +++ b/go-cosmwasm/types/queries.go @@ -64,13 +64,15 @@ func ToQuerierResult(response []byte, err error) QuerierResult { // QueryRequest is an rust enum and only (exactly) one of the fields should be set // Should we do a cleaner approach in Go? (type/data?) type QueryRequest struct { - Bank *BankQuery `json:"bank,omitempty"` - Custom json.RawMessage `json:"custom,omitempty"` - Staking *StakingQuery `json:"staking,omitempty"` - Wasm *WasmQuery `json:"wasm,omitempty"` - Dist *DistQuery `json:"dist,omitempty"` - Mint *MintQuery `json:"mint,omitempty"` - Gov *GovQuery `json:"gov,omitempty"` + Bank *BankQuery `json:"bank,omitempty"` + Custom json.RawMessage `json:"custom,omitempty"` + Staking *StakingQuery `json:"staking,omitempty"` + Wasm *WasmQuery `json:"wasm,omitempty"` + Dist *DistQuery `json:"dist,omitempty"` + Mint *MintQuery `json:"mint,omitempty"` + Gov *GovQuery `json:"gov,omitempty"` + IBC *IBCQuery `json:"ibc,omitempty"` + Stargate *StargateQuery `json:"stargate,omitempty"` } type BankQuery struct { @@ -103,6 +105,25 @@ type StakingQuery struct { Delegation *DelegationQuery `json:"delegation,omitempty"` UnBondingDelegations *UnbondingDeletionsQuery `json:"unbonding_delegations,omitempty"` BondedDenom *struct{} `json:"bonded_denom,omitempty"` + AllValidators *AllValidatorsQuery `json:"all_validators,omitempty"` + Validator *ValidatorQuery `json:"validator,omitempty"` +} + +type AllValidatorsQuery struct{} + +// AllValidatorsResponse is the expected response to AllValidatorsQuery +type AllValidatorsResponse struct { + Validators Validators `json:"validators"` +} + +type ValidatorQuery struct { + /// Address is the validator's address (e.g. cosmosvaloper1...) + Address string `json:"address"` +} + +// ValidatorResponse is the expected response to ValidatorQuery +type ValidatorResponse struct { + Validator *Validator `json:"validator"` // serializes to `null` when unset which matches Rust's Option::None serialization } type UnbondingDeletionsQuery struct { @@ -219,22 +240,40 @@ type BondedDenomResponse struct { } type WasmQuery struct { - Smart *SmartQuery `json:"smart,omitempty"` - Raw *RawQuery `json:"raw,omitempty"` + Smart *SmartQuery `json:"smart,omitempty"` + Raw *RawQuery `json:"raw,omitempty"` + ContractInfo *ContractInfoQuery `json:"contract_info,omitempty"` } // SmartQuery response is raw bytes ([]byte) type SmartQuery struct { + // Bech32 encoded sdk.AccAddress of the contract ContractAddr string `json:"contract_addr"` Msg []byte `json:"msg"` } // RawQuery response is raw bytes ([]byte) type RawQuery struct { + // Bech32 encoded sdk.AccAddress of the contract ContractAddr string `json:"contract_addr"` Key []byte `json:"key"` } +type ContractInfoQuery struct { + // Bech32 encoded sdk.AccAddress of the contract + ContractAddr string `json:"contract_addr"` +} + +type ContractInfoResponse struct { + CodeID uint64 `json:"code_id"` + Creator string `json:"creator"` + // Set to the admin who can migrate contract, if any + Admin string `json:"admin,omitempty"` + Pinned bool `json:"pinned"` + // Set if the contract is IBC enabled + IBCPort string `json:"ibc_port,omitempty"` +} + type DistQuery struct { Rewards *RewardsQuery `json:"rewards,omitempty"` } @@ -242,6 +281,157 @@ type DistQuery struct { type GovQuery struct { Proposals *ProposalsQuery `json:"proposals,omitempty"` } + +// StargateQuery is encoded the same way as abci_query, with path and protobuf encoded request data. +// The format is defined in [ADR-21](https://github.com/cosmos/cosmos-sdk/blob/master/docs/architecture/adr-021-protobuf-query-encoding.md). +// The response is protobuf encoded data directly without a JSON response wrapper. +// The caller is responsible for compiling the proper protobuf definitions for both requests and responses. +type StargateQuery struct { + // this is the fully qualified service path used for routing, + // eg. custom/cosmos_sdk.x.bank.v1.Query/QueryBalance + Path string `json:"path"` + // this is the expected protobuf message type (not any), binary encoded + Data []byte `json:"data"` +} + +// IBCQuery defines a query request from the contract into the chain. +// This is the counterpart of [IbcQuery](https://github.com/CosmWasm/cosmwasm/blob/v0.14.0-beta1/packages/std/src/ibc.rs#L61-L83). +type IBCQuery struct { + PortID *PortIDQuery `json:"port_id,omitempty"` + ListChannels *ListChannelsQuery `json:"list_channels,omitempty"` + Channel *ChannelQuery `json:"channel,omitempty"` +} + +type PortIDQuery struct{} + +type PortIDResponse struct { + PortID string `json:"port_id"` +} + +// ListChannelsQuery is an IBCQuery that lists all channels that are bound to a given port. +// If `PortID` is unset, this list all channels bound to the contract's port. +// Returns a `ListChannelsResponse`. +// This is the counterpart of [IbcQuery::ListChannels](https://github.com/CosmWasm/cosmwasm/blob/v0.14.0-beta1/packages/std/src/ibc.rs#L70-L73). +type ListChannelsQuery struct { + // optional argument + PortID string `json:"port_id,omitempty"` +} + +type ListChannelsResponse struct { + Channels IBCChannels `json:"channels"` +} + +type IBCEndpoint struct { + PortID string `json:"port_id"` + ChannelID string `json:"channel_id"` +} + +// TODO: test what the sdk Order.String() represents and how to parse back +// Proto files: https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/ibc/core/channel/v1/channel.proto#L69-L80 +// Auto-gen code: https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/x/ibc/core/04-channel/types/channel.pb.go#L70-L101 +type IBCOrder = string + +// These are the only two valid values for IbcOrder +const Unordered = "ORDER_UNORDERED" +const Ordered = "ORDER_ORDERED" + +type IBCChannel struct { + Endpoint IBCEndpoint `json:"endpoint"` + CounterpartyEndpoint IBCEndpoint `json:"counterparty_endpoint"` + Order IBCOrder `json:"order"` + Version string `json:"version"` + ConnectionID string `json:"connection_id"` +} + +type IBCOpenInit struct { + Channel IBCChannel `json:"channel"` +} + +func (m *IBCOpenInit) ToMsg() IBCChannelOpenMsg { + return IBCChannelOpenMsg{ + OpenInit: m, + } +} + +type IBCOpenTry struct { + Channel IBCChannel `json:"channel"` + CounterpartyVersion string `json:"counterparty_version"` +} + +func (m *IBCOpenTry) ToMsg() IBCChannelOpenMsg { + return IBCChannelOpenMsg{ + OpenTry: m, + } +} + +type IBCChannelOpenMsg struct { + OpenInit *IBCOpenInit `json:"open_init,omitempty"` + OpenTry *IBCOpenTry `json:"open_try,omitempty"` +} + +// IBCChannels must JSON encode empty array as [] (not null) for consistency with Rust parser +type IBCChannels []IBCChannel + +// MarshalJSON ensures that we get [] for empty arrays +func (e IBCChannels) MarshalJSON() ([]byte, error) { + if len(e) == 0 { + return []byte("[]"), nil + } + var raw []IBCChannel = e + return json.Marshal(raw) +} + +// UnmarshalJSON ensures that we get [] for empty arrays +func (e *IBCChannels) UnmarshalJSON(data []byte) error { + // make sure we deserialize [] back to null + if string(data) == "[]" || string(data) == "null" { + return nil + } + var raw []IBCChannel + if err := json.Unmarshal(data, &raw); err != nil { + return err + } + *e = raw + return nil +} + +// IBCEndpoints must JSON encode empty array as [] (not null) for consistency with Rust parser +type IBCEndpoints []IBCEndpoint + +// MarshalJSON ensures that we get [] for empty arrays +func (e IBCEndpoints) MarshalJSON() ([]byte, error) { + if len(e) == 0 { + return []byte("[]"), nil + } + var raw []IBCEndpoint = e + return json.Marshal(raw) +} + +// UnmarshalJSON ensures that we get [] for empty arrays +func (e *IBCEndpoints) UnmarshalJSON(data []byte) error { + // make sure we deserialize [] back to null + if string(data) == "[]" || string(data) == "null" { + return nil + } + var raw []IBCEndpoint + if err := json.Unmarshal(data, &raw); err != nil { + return err + } + *e = raw + return nil +} + +type ChannelQuery struct { + // optional argument + PortID string `json:"port_id,omitempty"` + ChannelID string `json:"channel_id"` +} + +type ChannelResponse struct { + // may be empty if there is no matching channel + Channel *IBCChannel `json:"channel,omitempty"` +} + type MintQuery struct { Inflation *MintingInflationQuery `json:"inflation,omitempty"` BondedRatio *MintingBondedRatioQuery `json:"bonded_ratio,omitempty"` diff --git a/go-cosmwasm/types/types.go b/go-cosmwasm/types/types.go index 9c8713186..83d166bb4 100644 --- a/go-cosmwasm/types/types.go +++ b/go-cosmwasm/types/types.go @@ -72,6 +72,12 @@ type HandleType int const ( HandleTypeExecute HandleType = iota HandleTypeReply + HandleTypeIbcChannelOpen + HandleTypeIbcChannelConnect + HandleTypeIbcChannelClose + HandleTypeIbcPacketReceive + HandleTypeIbcPacketAck + HandleTypeIbcPacketTimeout ) type CosmosMsgVersion int diff --git a/go-cosmwasm/types/v1/ibc.go b/go-cosmwasm/types/v1/ibc.go index 87b60a361..78099b298 100644 --- a/go-cosmwasm/types/v1/ibc.go +++ b/go-cosmwasm/types/v1/ibc.go @@ -1,7 +1,8 @@ package v1types import ( - abci "github.com/tendermint/tendermint/abci/types" + types "github.com/enigmampc/SecretNetwork/go-cosmwasm/types" + v010msgtypes "github.com/enigmampc/SecretNetwork/go-cosmwasm/types/v010" ) type IBCEndpoint struct { @@ -137,16 +138,19 @@ func (m *IBCCloseConfirm) ToMsg() IBCChannelCloseMsg { } type IBCPacketReceiveMsg struct { - Packet IBCPacket `json:"packet"` + Packet IBCPacket `json:"packet"` + Relayer string `json:"relayer"` } type IBCPacketAckMsg struct { Acknowledgement IBCAcknowledgement `json:"acknowledgement"` OriginalPacket IBCPacket `json:"original_packet"` + Relayer string `json:"relayer"` } type IBCPacketTimeoutMsg struct { - Packet IBCPacket `json:"packet"` + Packet IBCPacket `json:"packet"` + Relayer string `json:"relayer"` } // TODO: test what the sdk Order.String() represents and how to parse back @@ -196,10 +200,17 @@ type IBCPacket struct { // IBCChannelOpenResult is the raw response from the ibc_channel_open call. // This is mirrors Rust's ContractResult<()>. -// We just check if Err == "" to see if this is success (no other data on success) +// Check if Err == "" to see if this is success +// On Success, IBCV3ChannelOpenResponse *may* be set if the contract is ibcv3 compatible and wishes to +// define a custom version in the handshake. type IBCChannelOpenResult struct { - Ok *struct{} `json:"ok,omitempty"` - Err string `json:"error,omitempty"` + Ok *IBC3ChannelOpenResponse `json:"ok,omitempty"` + Err string `json:"error,omitempty"` +} + +// IBC3ChannelOpenResponse is version negotiation data for the handshake +type IBC3ChannelOpenResponse struct { + Version string `json:"version"` } // This is the return value for the majority of the ibc handlers. @@ -211,7 +222,7 @@ type IBCChannelOpenResult struct { // will use other Response types type IBCBasicResult struct { Ok *IBCBasicResponse `json:"ok,omitempty"` - Err string `json:"error,omitempty"` + Err *types.StdError `json:"Err,omitempty"` } // IBCBasicResponse defines the return value on a successful processing. @@ -223,7 +234,7 @@ type IBCBasicResponse struct { // "fire and forget". Messages []SubMsg `json:"messages"` // attributes for a log event to return over abci interface - Attributes []abci.EventAttribute `json:"attributes"` + Attributes []v010msgtypes.LogAttribute `json:"attributes"` // custom events (separate from the main one that contains the attributes // above) Events []Event `json:"events"` @@ -238,7 +249,12 @@ type IBCBasicResponse struct { // will use other Response types type IBCReceiveResult struct { Ok *IBCReceiveResponse `json:"ok,omitempty"` - Err string `json:"error,omitempty"` + Err *types.StdError `json:"Err,omitempty"` +} + +type IBCOpenChannelResult struct { + Ok *string `json:"ok,omitempty"` + Err *types.StdError `json:"Err,omitempty"` } // IBCReceiveResponse defines the return value on packet response processing. @@ -254,8 +270,8 @@ type IBCReceiveResponse struct { // If the ReplyOn value matches the result, the runtime will invoke this // contract's `reply` entry point after execution. Otherwise, this is all // "fire and forget". - Messages []SubMsg `json:"messages"` - Attributes []abci.EventAttribute `json:"attributes"` + Messages []SubMsg `json:"messages"` + Attributes []v010msgtypes.LogAttribute `json:"attributes"` // custom events (separate from the main one that contains the attributes // above) Events []Event `json:"events"` diff --git a/go-cosmwasm/types/v1/subcall.go b/go-cosmwasm/types/v1/subcall.go index 0be755b38..7732e600a 100644 --- a/go-cosmwasm/types/v1/subcall.go +++ b/go-cosmwasm/types/v1/subcall.go @@ -66,15 +66,17 @@ type SubMsgResult struct { // SubMsg wraps a CosmosMsg with some metadata for handling replies (ID) and optionally // limiting the gas usage (GasLimit) type SubMsg struct { - ID uint64 `json:"id"` - Msg CosmosMsg `json:"msg"` - GasLimit *uint64 `json:"gas_limit,omitempty"` - ReplyOn replyOn `json:"reply_on"` + ID uint64 `json:"id"` + Msg CosmosMsg `json:"msg"` + GasLimit *uint64 `json:"gas_limit,omitempty"` + ReplyOn replyOn `json:"reply_on"` + WasMsgEncrypted bool `json:"was_msg_encrypted"` } type Reply struct { - ID []byte `json:"id"` - Result SubMsgResult `json:"result"` + ID []byte `json:"id"` + Result SubMsgResult `json:"result"` + WasMsgEncrypted bool `json:"was_msg_encrypted"` } // SubcallResult is the raw response we return from the sdk -> reply after executing a SubMsg. diff --git a/integration-tests/Makefile b/integration-tests/Makefile new file mode 100644 index 000000000..0774137ce --- /dev/null +++ b/integration-tests/Makefile @@ -0,0 +1,6 @@ +all: + $(MAKE) -C contract-v1 + $(MAKE) -C contract-v0.10 + +run-localsecret: + docker run --rm -it -p 9091:9091 --name localsecret ghcr.io/scrtlabs/localsecret:"$(TAG)" \ No newline at end of file diff --git a/integration-tests/contract-v0.10/.gitignore b/integration-tests/contract-v0.10/.gitignore new file mode 100644 index 000000000..0e24e33d5 --- /dev/null +++ b/integration-tests/contract-v0.10/.gitignore @@ -0,0 +1,13 @@ +# Build results +/target +*.wasm + +# Text file backups +**/*.rs.bk + +# macOS +.DS_Store + +# IDEs +*.iml +.idea diff --git a/integration-tests/contract-v0.10/Cargo.lock b/integration-tests/contract-v0.10/Cargo.lock new file mode 100644 index 000000000..ff55b2b42 --- /dev/null +++ b/integration-tests/contract-v0.10/Cargo.lock @@ -0,0 +1,276 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "addr2line" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "backtrace" +version = "0.3.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cab84319d616cfb654d03394f38ab7e6f0919e181b1b57e1fd15e7fb4077d9a7" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "base64" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7" + +[[package]] +name = "cc" +version = "1.0.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "contract-v010" +version = "0.0.1" +dependencies = [ + "schemars", + "secret-cosmwasm-std", + "secret-cosmwasm-storage", + "serde", + "serde-json-wasm", +] + +[[package]] +name = "doc-comment" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" + +[[package]] +name = "gimli" +version = "0.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4" + +[[package]] +name = "itoa" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" + +[[package]] +name = "libc" +version = "0.2.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "miniz_oxide" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f5c75688da582b8ffc1f1799e9db273f32133c49e048f614d22ec3256773ccc" +dependencies = [ + "adler", +] + +[[package]] +name = "object" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53" +dependencies = [ + "memchr", +] + +[[package]] +name = "proc-macro2" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" + +[[package]] +name = "ryu" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695" + +[[package]] +name = "schemars" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be77ed66abed6954aabf6a3e31a84706bedbf93750d267e92ef4a6d90bbd6a61" +dependencies = [ + "schemars_derive", + "serde", + "serde_json", +] + +[[package]] +name = "schemars_derive" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11af7a475c9ee266cfaa9e303a47c830ebe072bf3101ab907a7b7b9d816fa01d" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals", + "syn", +] + +[[package]] +name = "secret-cosmwasm-std" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5d4b8fed972d924458d9c3c0e6c9fbf6c4c5e30655571e3d2b78be056d316e9" +dependencies = [ + "base64", + "schemars", + "serde", + "serde-json-wasm", + "snafu", +] + +[[package]] +name = "secret-cosmwasm-storage" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffee3243bb13c02ddcdc15458526288d36ec23422ec43681ac5d48e7325d8327" +dependencies = [ + "secret-cosmwasm-std", + "serde", +] + +[[package]] +name = "serde" +version = "1.0.138" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1578c6245786b9d168c5447eeacfb96856573ca56c9d68fdcf394be134882a47" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde-json-wasm" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "120bad73306616e91acd7ceed522ba96032a51cffeef3cc813de7f367df71e37" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.138" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "023e9b1467aef8a10fb88f25611870ada9800ef7e22afce356bb0d2387b6f27c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_derive_internals" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dbab34ca63057a1f15280bdf3c39f2b1eb1b54c17e98360e511637aef7418c6" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82c2c1fdcd807d1098552c5b9a36e425e42e9fbd7c6a37a8425f390f781f7fa7" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "snafu" +version = "0.6.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eab12d3c261b2308b0d80c26fffb58d17eba81a4be97890101f416b478c79ca7" +dependencies = [ + "backtrace", + "doc-comment", + "snafu-derive", +] + +[[package]] +name = "snafu-derive" +version = "0.6.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1508efa03c362e23817f96cde18abed596a25219a8b2c66e8db33c03543d315b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "syn" +version = "1.0.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c" diff --git a/integration-tests/contract-v0.10/Cargo.toml b/integration-tests/contract-v0.10/Cargo.toml new file mode 100644 index 000000000..d74eb335b --- /dev/null +++ b/integration-tests/contract-v0.10/Cargo.toml @@ -0,0 +1,42 @@ +[package] +name = "contract-v010" +version = "0.0.1" +authors = ["Enigma "] +edition = "2018" +description = "A test contract intended to use in integration tests for the Secret Netowrk" +license = "MIT" +exclude = [ + # Those files are cosmwasm-opt artifacts. You might want to commit them for convenience but they should not be part of the source code publication. + "contract.wasm", + "hash.txt", +] + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[lib] +crate-type = ["cdylib", "rlib"] + +[profile.release] +opt-level = 3 +debug = false +rpath = false +lto = true +debug-assertions = false +codegen-units = 1 +panic = 'abort' +incremental = false +overflow-checks = true + +[features] +default = ["backtraces"] +backtraces = ["cosmwasm-std/backtraces"] +with_floats = [] + +[dependencies] +cosmwasm-std = { package = "secret-cosmwasm-std", version = "0.10.1" } +cosmwasm-storage = { package = "secret-cosmwasm-storage", version = "0.10.0" } +schemars = "0.7" +serde = { version = "1.0.114", default-features = false, features = [ + "derive", + "alloc" +] } +serde-json-wasm = "0.2.1" diff --git a/integration-tests/contract-v0.10/Makefile b/integration-tests/contract-v0.10/Makefile new file mode 100644 index 000000000..a253e86d4 --- /dev/null +++ b/integration-tests/contract-v0.10/Makefile @@ -0,0 +1,8 @@ +all: src/contract.rs src/lib.rs Cargo.toml Cargo.lock + rustup target add wasm32-unknown-unknown + RUSTFLAGS='-C link-arg=-s' cargo build --release --target wasm32-unknown-unknown + cp ./target/wasm32-unknown-unknown/release/contract_v010.wasm ./contract.wasm + +clean: + cargo clean + -rm -f ./contract.wasm \ No newline at end of file diff --git a/integration-tests/contract-v0.10/README.md b/integration-tests/contract-v0.10/README.md new file mode 100644 index 000000000..6f604781c --- /dev/null +++ b/integration-tests/contract-v0.10/README.md @@ -0,0 +1 @@ +Just `make`. :rainbow: diff --git a/integration-tests/contract-v0.10/rust-toolchain b/integration-tests/contract-v0.10/rust-toolchain new file mode 100644 index 000000000..6cb4a6feb --- /dev/null +++ b/integration-tests/contract-v0.10/rust-toolchain @@ -0,0 +1 @@ +1.63 \ No newline at end of file diff --git a/integration-tests/contract-v0.10/src/contract.rs b/integration-tests/contract-v0.10/src/contract.rs new file mode 100644 index 000000000..5e1cd82e4 --- /dev/null +++ b/integration-tests/contract-v0.10/src/contract.rs @@ -0,0 +1,119 @@ +use cosmwasm_std::{to_binary, Api, BalanceResponse, BankQuery, Binary, Coin, Env, Extern, HandleResponse, HandleResult, HumanAddr, InitResponse, InitResult, Querier, QueryRequest, QueryResult, Storage, VoteOption, CosmosMsg, BankMsg}; + +/////////////////////////////// Messages /////////////////////////////// + +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[serde(rename_all = "snake_case")] +pub enum Msg { + Nop {}, + BankMsgSend { + to_address: HumanAddr, + amount: Vec, + }, + StargateMsg { + type_url: String, + value: Binary, + }, + StakingMsgDelegate { + validator: String, + amount: Coin, + }, + StakingMsgUndelegate { + validator: String, + amount: Coin, + }, + StakingMsgRedelegate { + src_validator: String, + dst_validator: String, + amount: Coin, + }, + GovVote { + proposal_id: u64, + vote: VoteOption, + }, + DistributionMsgSetWithdrawAddress { + address: String, + }, + DistributionMsgWithdrawDelegatorReward { + validator: String, + }, + + WasmMsgInstantiate { + code_id: u64, + code_hash: String, + msg: Binary, + funds: Vec, + label: String, + }, + WasmMsgExecute { + contract_addr: String, + code_hash: String, + msg: Binary, + funds: Vec, + }, +} + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[serde(rename_all = "snake_case")] +pub enum QueryMsg { + BankBalance { address: HumanAddr, denom: String }, +} + +/////////////////////////////// Init /////////////////////////////// + +pub fn init( + _deps: &mut Extern, + _env: Env, + _msg: Msg, +) -> InitResult { + return Ok(InitResponse { + messages: vec![], + log: vec![], + }); +} + +/////////////////////////////// Handle /////////////////////////////// + +pub fn handle( + _deps: &mut Extern, + env: Env, + msg: Msg, +) -> HandleResult { + match msg { + Msg::BankMsgSend { to_address, amount } => Ok( + HandleResponse { + messages: vec![ + CosmosMsg::Bank(BankMsg::Send { from_address: env.contract.address, to_address, amount }) + ], + log: vec![], + data: None, + } + ), + _ => Ok( + HandleResponse { + messages: vec![], + log: vec![], + data: None, + } + ), + } +} + +/////////////////////////////// Query /////////////////////////////// + +pub fn query(deps: &Extern, msg: QueryMsg) -> QueryResult { + match msg { + QueryMsg::BankBalance { address, denom } => { + let res = + deps.querier + .query::(&QueryRequest::Bank(BankQuery::Balance { + address, + denom, + }))?; + return Ok(to_binary(&res)?); + } + } +} diff --git a/integration-tests/contract-v0.10/src/lib.rs b/integration-tests/contract-v0.10/src/lib.rs new file mode 100644 index 000000000..4d128dcb3 --- /dev/null +++ b/integration-tests/contract-v0.10/src/lib.rs @@ -0,0 +1,38 @@ +pub mod contract; + +#[cfg(target_arch = "wasm32")] +mod wasm { + use super::contract; + use cosmwasm_std::{ + do_handle, do_init, do_query, ExternalApi, ExternalQuerier, ExternalStorage, + }; + + #[no_mangle] + extern "C" fn init(env_ptr: u32, msg_ptr: u32) -> u32 { + do_init( + &contract::init::, + env_ptr, + msg_ptr, + ) + } + + #[no_mangle] + extern "C" fn handle(env_ptr: u32, msg_ptr: u32) -> u32 { + do_handle( + &contract::handle::, + env_ptr, + msg_ptr, + ) + } + + #[no_mangle] + extern "C" fn query(msg_ptr: u32) -> u32 { + do_query( + &contract::query::, + msg_ptr, + ) + } + + // Other C externs like cosmwasm_vm_version_1, allocate, deallocate are available + // automatically because we `use cosmwasm_std`. +} diff --git a/integration-tests/contract-v1/.gitignore b/integration-tests/contract-v1/.gitignore new file mode 100644 index 000000000..0e24e33d5 --- /dev/null +++ b/integration-tests/contract-v1/.gitignore @@ -0,0 +1,13 @@ +# Build results +/target +*.wasm + +# Text file backups +**/*.rs.bk + +# macOS +.DS_Store + +# IDEs +*.iml +.idea diff --git a/integration-tests/contract-v1/Cargo.lock b/integration-tests/contract-v1/Cargo.lock new file mode 100644 index 000000000..283ca7e5e --- /dev/null +++ b/integration-tests/contract-v1/Cargo.lock @@ -0,0 +1,614 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "base16ct" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce" + +[[package]] +name = "base64" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" + +[[package]] +name = "base64ct" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bdca834647821e0b13d9539a8634eb62d3501b6b6c2cec1722786ee6671b851" + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array", +] + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "const-oid" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4c78c047431fee22c1a7bb92e00ad095a02a983affe4d8a72e2a2c62c1b94f3" + +[[package]] +name = "contract-v1" +version = "0.0.1" +dependencies = [ + "cosmwasm-std", + "cosmwasm-storage", + "schemars", + "serde", + "serde-json-wasm 0.2.3", +] + +[[package]] +name = "cosmwasm-crypto" +version = "1.0.0" +source = "git+https://github.com/scrtlabs/cosmwasm?branch=secret#e69869a8565e4e2318bdbfd3711fd1ceda0db209" +dependencies = [ + "digest", + "ed25519-zebra", + "k256", + "rand_core 0.6.3", + "thiserror", +] + +[[package]] +name = "cosmwasm-derive" +version = "1.0.0" +source = "git+https://github.com/scrtlabs/cosmwasm?branch=secret#e69869a8565e4e2318bdbfd3711fd1ceda0db209" +dependencies = [ + "syn", +] + +[[package]] +name = "cosmwasm-std" +version = "1.0.0" +source = "git+https://github.com/scrtlabs/cosmwasm?branch=secret#e69869a8565e4e2318bdbfd3711fd1ceda0db209" +dependencies = [ + "base64", + "cosmwasm-crypto", + "cosmwasm-derive", + "forward_ref", + "schemars", + "serde", + "serde-json-wasm 0.4.1", + "thiserror", + "uint", +] + +[[package]] +name = "cosmwasm-storage" +version = "1.0.0" +source = "git+https://github.com/scrtlabs/cosmwasm?branch=secret#e69869a8565e4e2318bdbfd3711fd1ceda0db209" +dependencies = [ + "cosmwasm-std", + "serde", +] + +[[package]] +name = "cpufeatures" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59a6001667ab124aebae2a495118e11d30984c3a653e99d86d58971708cf5e4b" +dependencies = [ + "libc", +] + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "crypto-bigint" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03c6a1d5fa1de37e071642dfa44ec552ca5b299adb128fab16138e24b548fd21" +dependencies = [ + "generic-array", + "rand_core 0.6.3", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-mac" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714" +dependencies = [ + "generic-array", + "subtle", +] + +[[package]] +name = "curve25519-dalek" +version = "3.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90f9d052967f590a76e62eb387bd0bbb1b000182c3cefe5364db6b7211651bc0" +dependencies = [ + "byteorder", + "digest", + "rand_core 0.5.1", + "subtle", + "zeroize", +] + +[[package]] +name = "der" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6919815d73839e7ad218de758883aae3a257ba6759ce7a9992501efbb53d705c" +dependencies = [ + "const-oid", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + +[[package]] +name = "dyn-clone" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d07a982d1fb29db01e5a59b1918e03da4df7297eaeee7686ac45542fd4e59c8" + +[[package]] +name = "ecdsa" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0d69ae62e0ce582d56380743515fefaf1a8c70cec685d9677636d7e30ae9dc9" +dependencies = [ + "der", + "elliptic-curve", + "rfc6979", + "signature", +] + +[[package]] +name = "ed25519-zebra" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "403ef3e961ab98f0ba902771d29f842058578bb1ce7e3c59dad5a6a93e784c69" +dependencies = [ + "curve25519-dalek", + "hex", + "rand_core 0.6.3", + "serde", + "sha2", + "thiserror", + "zeroize", +] + +[[package]] +name = "elliptic-curve" +version = "0.11.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25b477563c2bfed38a3b7a60964c49e058b2510ad3f12ba3483fd8f62c2306d6" +dependencies = [ + "base16ct", + "crypto-bigint", + "der", + "ff", + "generic-array", + "group", + "rand_core 0.6.3", + "sec1", + "subtle", + "zeroize", +] + +[[package]] +name = "ff" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "131655483be284720a17d74ff97592b8e76576dc25563148601df2d7c9080924" +dependencies = [ + "rand_core 0.6.3", + "subtle", +] + +[[package]] +name = "forward_ref" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8cbd1169bd7b4a0a20d92b9af7a7e0422888bd38a6f5ec29c1fd8c1558a272e" + +[[package]] +name = "generic-array" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", +] + +[[package]] +name = "group" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc5ac374b108929de78460075f3dc439fa66df9d8fc77e8f12caa5165fcf0c89" +dependencies = [ + "ff", + "rand_core 0.6.3", + "subtle", +] + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hmac" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" +dependencies = [ + "crypto-mac", + "digest", +] + +[[package]] +name = "itoa" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" + +[[package]] +name = "k256" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19c3a5e0a0b8450278feda242592512e09f61c72e018b8cd5c859482802daf2d" +dependencies = [ + "cfg-if", + "ecdsa", + "elliptic-curve", + "sec1", + "sha2", +] + +[[package]] +name = "libc" +version = "0.2.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" + +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + +[[package]] +name = "pkcs8" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cabda3fb821068a9a4fab19a683eac3af12edf0f34b94a8be53c4972b8149d0" +dependencies = [ + "der", + "spki", + "zeroize", +] + +[[package]] +name = "proc-macro2" +version = "1.0.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c278e965f1d8cf32d6e0e96de3d3e79712178ae67986d9cf9151f51e95aac89b" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom 0.1.16", +] + +[[package]] +name = "rand_core" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" +dependencies = [ + "getrandom 0.2.7", +] + +[[package]] +name = "rfc6979" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96ef608575f6392792f9ecf7890c00086591d29a83910939d430753f7c050525" +dependencies = [ + "crypto-bigint", + "hmac", + "zeroize", +] + +[[package]] +name = "ryu" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695" + +[[package]] +name = "schemars" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1847b767a3d62d95cbf3d8a9f0e421cf57a0d8aa4f411d4b16525afb0284d4ed" +dependencies = [ + "dyn-clone", + "schemars_derive", + "serde", + "serde_json", +] + +[[package]] +name = "schemars_derive" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af4d7e1b012cb3d9129567661a63755ea4b8a7386d339dc945ae187e403c6743" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals", + "syn", +] + +[[package]] +name = "sec1" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08da66b8b0965a5555b6bd6639e68ccba85e1e2506f5fbb089e93f8a04e1a2d1" +dependencies = [ + "der", + "generic-array", + "pkcs8", + "subtle", + "zeroize", +] + +[[package]] +name = "serde" +version = "1.0.140" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc855a42c7967b7c369eb5860f7164ef1f6f81c20c7cc1141f2a604e18723b03" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde-json-wasm" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "120bad73306616e91acd7ceed522ba96032a51cffeef3cc813de7f367df71e37" +dependencies = [ + "serde", +] + +[[package]] +name = "serde-json-wasm" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479b4dbc401ca13ee8ce902851b834893251404c4f3c65370a49e047a6be09a5" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.140" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f2122636b9fe3b81f1cb25099fcf2d3f542cdb1d45940d56c713158884a05da" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_derive_internals" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85bf8229e7920a9f636479437026331ce11aa132b4dde37d121944a44d6e5f3c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82c2c1fdcd807d1098552c5b9a36e425e42e9fbd7c6a37a8425f390f781f7fa7" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer", + "cfg-if", + "cpufeatures", + "digest", + "opaque-debug", +] + +[[package]] +name = "signature" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02658e48d89f2bec991f9a78e69cfa4c316f8d6a6c4ec12fae1aeb263d486788" +dependencies = [ + "digest", + "rand_core 0.6.3", +] + +[[package]] +name = "spki" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d01ac02a6ccf3e07db148d2be087da624fea0221a16152ed01f0496a6b0a27" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "subtle" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" + +[[package]] +name = "syn" +version = "1.0.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "1.0.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "typenum" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" + +[[package]] +name = "uint" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12f03af7ccf01dd611cc450a0d10dbc9b745770d096473e2faf0ca6e2d66d1e0" +dependencies = [ + "byteorder", + "crunchy", + "hex", + "static_assertions", +] + +[[package]] +name = "unicode-ident" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15c61ba63f9235225a22310255a29b806b907c9b8c964bcbd0a2c70f3f2deea7" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "zeroize" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4756f7db3f7b5574938c3eb1c117038b8e07f95ee6718c0efad4ac21508f1efd" diff --git a/integration-tests/contract-v1/Cargo.toml b/integration-tests/contract-v1/Cargo.toml new file mode 100644 index 000000000..c25108483 --- /dev/null +++ b/integration-tests/contract-v1/Cargo.toml @@ -0,0 +1,41 @@ +[package] +name = "contract-v1" +version = "0.0.1" +authors = ["SCRT Labs "] +edition = "2018" +description = "A Test contract intended to use in integration tests for the Secret Netowrk" +license = "MIT" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[lib] +crate-type = ["cdylib", "rlib"] + +[profile.release] +opt-level = 3 +debug = false +rpath = false +lto = true +debug-assertions = false +codegen-units = 1 +panic = 'abort' +incremental = false +overflow-checks = true + +[features] +default = [] +backtraces = ["cosmwasm-std/backtraces"] +with_floats = [] + +[dependencies] +cosmwasm-std = { git = "https://github.com/scrtlabs/cosmwasm", branch = "secret", features = [ + "stargate", + "staking", + "ibc3" +] } +cosmwasm-storage = { git = "https://github.com/scrtlabs/cosmwasm", branch = "secret" } +schemars = "0.8.1" +serde = { version = "1.0.114", default-features = false, features = [ + "derive", + "alloc" +] } +serde-json-wasm = "0.2.1" diff --git a/integration-tests/contract-v1/Makefile b/integration-tests/contract-v1/Makefile new file mode 100644 index 000000000..61a463623 --- /dev/null +++ b/integration-tests/contract-v1/Makefile @@ -0,0 +1,8 @@ +all: src/contract.rs src/lib.rs src/msg.rs Cargo.toml Cargo.lock + rustup target add wasm32-unknown-unknown + RUSTFLAGS='-C link-arg=-s' cargo build --release --target wasm32-unknown-unknown + cp ./target/wasm32-unknown-unknown/release/contract_v1.wasm ./contract.wasm + +clean: + cargo clean + -rm -f ./contract.wasm \ No newline at end of file diff --git a/integration-tests/contract-v1/rust-toolchain b/integration-tests/contract-v1/rust-toolchain new file mode 100644 index 000000000..6cb4a6feb --- /dev/null +++ b/integration-tests/contract-v1/rust-toolchain @@ -0,0 +1 @@ +1.63 \ No newline at end of file diff --git a/integration-tests/contract-v1/src/contract.rs b/integration-tests/contract-v1/src/contract.rs new file mode 100644 index 000000000..f98b32cdc --- /dev/null +++ b/integration-tests/contract-v1/src/contract.rs @@ -0,0 +1,246 @@ +use cosmwasm_std::{ + entry_point, to_binary, to_vec, AllBalanceResponse, AllDelegationsResponse, + AllValidatorsResponse, BalanceResponse, BankMsg, BankQuery, Binary, BondedDenomResponse, + ChannelResponse, ContractInfoResponse, ContractResult, CosmosMsg, DelegationResponse, Deps, + DepsMut, DistributionMsg, Empty, Env, GovMsg, IbcMsg, IbcQuery, ListChannelsResponse, + MessageInfo, PortIdResponse, QueryRequest, Response, StakingMsg, StakingQuery, StdError, + StdResult, ValidatorResponse, WasmMsg, WasmQuery, +}; + +use crate::msg::{Msg, QueryMsg}; + +#[entry_point] +pub fn instantiate(deps: DepsMut, env: Env, info: MessageInfo, msg: Msg) -> StdResult { + return handle_msg(deps, env, info, msg); +} + +#[entry_point] +pub fn execute(deps: DepsMut, env: Env, info: MessageInfo, msg: Msg) -> StdResult { + return handle_msg(deps, env, info, msg); +} + +fn handle_msg(_deps: DepsMut, _env: Env, _info: MessageInfo, msg: Msg) -> StdResult { + match msg { + Msg::Nop {} => { + return Ok(Response::new()); + } + Msg::BankMsgSend { to_address, amount } => { + return Ok( + Response::new().add_message(CosmosMsg::Bank(BankMsg::Send { to_address, amount })) + ); + } + Msg::StargateMsg { type_url, value } => { + return Ok(Response::new().add_message(CosmosMsg::Stargate { type_url, value })); + } + Msg::StakingMsgDelegate { validator, amount } => { + return Ok( + Response::new().add_message(CosmosMsg::Staking(StakingMsg::Delegate { + validator, + amount, + })), + ); + } + Msg::StakingMsgUndelegate { validator, amount } => { + return Ok( + Response::new().add_message(CosmosMsg::Staking(StakingMsg::Undelegate { + validator, + amount, + })), + ); + } + Msg::StakingMsgRedelegate { + src_validator, + dst_validator, + amount, + } => { + return Ok( + Response::new().add_message(CosmosMsg::Staking(StakingMsg::Redelegate { + src_validator, + dst_validator, + amount, + })), + ); + } + Msg::GovVote { proposal_id, vote } => { + return Ok( + Response::new().add_message(CosmosMsg::Gov(GovMsg::Vote { proposal_id, vote })) + ); + } + Msg::DistributionMsgSetWithdrawAddress { address } => { + return Ok(Response::new().add_message(CosmosMsg::Distribution( + DistributionMsg::SetWithdrawAddress { address }, + ))); + } + Msg::DistributionMsgWithdrawDelegatorReward { validator } => { + return Ok(Response::new().add_message(CosmosMsg::Distribution( + DistributionMsg::WithdrawDelegatorReward { validator }, + ))); + } + Msg::IbcMsgTransfer { + channel_id, + to_address, + amount, + timeout, + } => { + return Ok( + Response::new().add_message(CosmosMsg::Ibc(IbcMsg::Transfer { + channel_id, + to_address, + amount, + timeout, + })), + ); + } + Msg::IbcMsgSendPacket { + channel_id, + data, + timeout, + } => { + return Ok( + Response::new().add_message(CosmosMsg::Ibc(IbcMsg::SendPacket { + channel_id, + data, + timeout, + })), + ); + } + Msg::IbcMsgCloseChannel { channel_id } => { + return Ok( + Response::new().add_message(CosmosMsg::Ibc(IbcMsg::CloseChannel { channel_id })) + ); + } + Msg::WasmMsgInstantiate { + code_id, + code_hash, + msg, + funds, + label, + } => { + return Ok( + Response::new().add_message(CosmosMsg::Wasm(WasmMsg::Instantiate { + code_id, + code_hash, + msg, + funds, + label, + })), + ); + } + Msg::WasmMsgExecute { + contract_addr, + code_hash, + msg, + funds, + } => { + return Ok( + Response::new().add_message(CosmosMsg::Wasm(WasmMsg::Execute { + contract_addr, + code_hash, + msg, + funds, + })), + ); + } + } +} + +#[entry_point] +pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult { + match msg { + QueryMsg::Stargate { path, data } => { + return Ok(to_binary( + &deps + .querier + .raw_query(&to_vec(&QueryRequest::::Stargate { path, data })?) + .unwrap() + .unwrap(), + )?); + } + QueryMsg::BankBalance { address, denom } => { + return Ok(to_binary(&deps.querier.query::( + &QueryRequest::Bank(BankQuery::Balance { address, denom }), + )?)?); + } + QueryMsg::BankAllBalances { address } => { + return Ok(to_binary(&deps.querier.query::( + &QueryRequest::Bank(BankQuery::AllBalances { address }), + )?)?); + } + QueryMsg::StakingBondedDenom {} => { + return Ok(to_binary(&deps.querier.query::( + &QueryRequest::Staking(StakingQuery::BondedDenom {}), + )?)?); + } + QueryMsg::StakingAllDelegations { delegator } => { + return Ok(to_binary(&deps.querier.query::( + &QueryRequest::Staking(StakingQuery::AllDelegations { delegator }), + )?)?); + } + QueryMsg::StakingDelegation { + delegator, + validator, + } => { + return Ok(to_binary(&deps.querier.query::( + &QueryRequest::Staking(StakingQuery::Delegation { + delegator, + validator, + }), + )?)?); + } + QueryMsg::StakingAllValidators {} => { + return Ok(to_binary(&deps.querier.query::( + &QueryRequest::Staking(StakingQuery::AllValidators {}), + )?)?); + } + QueryMsg::StakingValidator { address } => { + return Ok(to_binary(&deps.querier.query::( + &QueryRequest::Staking(StakingQuery::Validator { address }), + )?)?); + } + QueryMsg::IbcPortId {} => { + return Ok(to_binary(&deps.querier.query::( + &QueryRequest::Ibc(IbcQuery::PortId {}), + )?)?); + } + QueryMsg::IbcListChannels { port_id } => { + return Ok(to_binary(&deps.querier.query::( + &QueryRequest::Ibc(IbcQuery::ListChannels { port_id }), + )?)?); + } + QueryMsg::IbcChannel { + channel_id, + port_id, + } => { + return Ok(to_binary(&deps.querier.query::( + &QueryRequest::Ibc(IbcQuery::Channel { + channel_id, + port_id, + }), + )?)?); + } + QueryMsg::WasmSmart { + contract_addr, + code_hash, + msg, + } => { + let result = &deps + .querier + .raw_query(&to_vec(&QueryRequest::Wasm::(WasmQuery::Smart { + contract_addr, + code_hash, + msg, + }))?) + .unwrap(); + + match result { + ContractResult::Ok(ok) => Ok(Binary(ok.0.to_vec())), + ContractResult::Err(err) => Err(StdError::generic_err(err)), + } + } + QueryMsg::WasmContractInfo { contract_addr } => { + return Ok(to_binary(&deps.querier.query::( + &QueryRequest::Wasm(WasmQuery::ContractInfo { contract_addr }), + )?)?); + } + } +} diff --git a/integration-tests/contract-v1/src/lib.rs b/integration-tests/contract-v1/src/lib.rs new file mode 100644 index 000000000..112ecadc8 --- /dev/null +++ b/integration-tests/contract-v1/src/lib.rs @@ -0,0 +1,2 @@ +pub mod contract; +pub mod msg; diff --git a/integration-tests/contract-v1/src/msg.rs b/integration-tests/contract-v1/src/msg.rs new file mode 100644 index 000000000..8721720a7 --- /dev/null +++ b/integration-tests/contract-v1/src/msg.rs @@ -0,0 +1,112 @@ +use cosmwasm_std::{Binary, Coin, IbcTimeout, VoteOption}; +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] +#[serde(rename_all = "snake_case")] +pub enum Msg { + Nop {}, + BankMsgSend { + to_address: String, + amount: Vec, + }, + StargateMsg { + type_url: String, + value: Binary, + }, + StakingMsgDelegate { + validator: String, + amount: Coin, + }, + StakingMsgUndelegate { + validator: String, + amount: Coin, + }, + StakingMsgRedelegate { + src_validator: String, + dst_validator: String, + amount: Coin, + }, + GovVote { + proposal_id: u64, + vote: VoteOption, + }, + DistributionMsgSetWithdrawAddress { + address: String, + }, + DistributionMsgWithdrawDelegatorReward { + validator: String, + }, + + IbcMsgTransfer { + channel_id: String, + to_address: String, + amount: Coin, + timeout: IbcTimeout, + }, + IbcMsgSendPacket { + channel_id: String, + data: Binary, + timeout: IbcTimeout, + }, + IbcMsgCloseChannel { + channel_id: String, + }, + WasmMsgInstantiate { + code_id: u64, + code_hash: String, + msg: Binary, + funds: Vec, + label: String, + }, + WasmMsgExecute { + contract_addr: String, + code_hash: String, + msg: Binary, + funds: Vec, + }, +} + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[serde(rename_all = "snake_case")] +pub enum QueryMsg { + BankBalance { + address: String, + denom: String, + }, + BankAllBalances { + address: String, + }, + StakingBondedDenom {}, + StakingAllDelegations { + delegator: String, + }, + StakingDelegation { + delegator: String, + validator: String, + }, + StakingAllValidators {}, + StakingValidator { + address: String, + }, + Stargate { + path: String, + data: Binary, + }, + IbcPortId {}, + IbcListChannels { + port_id: Option, + }, + IbcChannel { + channel_id: String, + port_id: Option, + }, + WasmSmart { + contract_addr: String, + code_hash: String, + msg: Binary, + }, + WasmContractInfo { + contract_addr: String, + }, +} diff --git a/integration-tests/jest.config.js b/integration-tests/jest.config.js new file mode 100644 index 000000000..877497a25 --- /dev/null +++ b/integration-tests/jest.config.js @@ -0,0 +1,13 @@ +/** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */ +module.exports = { + preset: "ts-jest", + testEnvironment: "node", + testTimeout: 60_000, + // modulePathIgnorePatterns: ["dist", "scripts"], + // globalSetup: "/test/globalSetup.ts", + // globalTeardown: "/test/globalTeardown.js", + // setupFilesAfterEnv: ["/test/setup.ts"], + globals: { + TEST_ACCOUNTS: {}, + }, +}; diff --git a/integration-tests/package.json b/integration-tests/package.json new file mode 100644 index 000000000..b06e6fc36 --- /dev/null +++ b/integration-tests/package.json @@ -0,0 +1,19 @@ +{ + "name": "integration-tests", + "version": "1.4.0", + "license": "MIT", + "scripts": { + "test": "make && jest" + }, + "devDependencies": { + "@noble/hashes": "1.1.2", + "@types/jest": "28.1.7", + "@types/node": "18.7.9", + "jest": "28.1.3", + "prettier": "2.7.1", + "secretjs": "1.3.0-beta.23", + "ts-jest": "28.0.8", + "ts-node": "10.9.1", + "typescript": "4.7.4" + } +} diff --git a/integration-tests/test.ts b/integration-tests/test.ts new file mode 100644 index 000000000..924d73f9a --- /dev/null +++ b/integration-tests/test.ts @@ -0,0 +1,399 @@ +import { + fromBase64, + MsgInstantiateContract, + MsgStoreCode, + SecretNetworkClient, + toBase64, + toHex, + Wallet, +} from "secretjs"; +import { MsgSend } from "secretjs/dist/protobuf_stuff/cosmos/bank/v1beta1/tx"; +import { + QueryBalanceRequest, + QueryBalanceResponse, +} from "secretjs//dist/protobuf_stuff/cosmos/bank/v1beta1/query"; +import { sha256 } from "@noble/hashes/sha256"; +import * as fs from "fs"; + +// @ts-ignore +const accounts: { + a: SecretNetworkClient; + b: SecretNetworkClient; + c: SecretNetworkClient; + d: SecretNetworkClient; +} = {}; + +let v1CodeID: number; +let v1Address: string; +let v1CodeHash: string; + +let v010CodeID: number; +let v010Address: string; +let v010CodeHash: string; + +beforeAll(async () => { + accounts.a = await SecretNetworkClient.create({ + chainId: "secretdev-1", + grpcWebUrl: "http://localhost:9091", + wallet: new Wallet( + "grant rice replace explain federal release fix clever romance raise often wild taxi quarter soccer fiber love must tape steak together observe swap guitar" + ), + walletAddress: "secret1ap26qrlp8mcq2pg6r47w43l0y8zkqm8a450s03", + }); + + accounts.b = await SecretNetworkClient.create({ + chainId: "secretdev-1", + grpcWebUrl: "http://localhost:9091", + wallet: new Wallet( + "jelly shadow frog dirt dragon use armed praise universe win jungle close inmate rain oil canvas beauty pioneer chef soccer icon dizzy thunder meadow" + ), + walletAddress: "secret1fc3fzy78ttp0lwuujw7e52rhspxn8uj52zfyne", + }); + + accounts.c = await SecretNetworkClient.create({ + chainId: "secretdev-1", + grpcWebUrl: "http://localhost:9091", + wallet: new Wallet( + "chair love bleak wonder skirt permit say assist aunt credit roast size obtain minute throw sand usual age smart exact enough room shadow charge" + ), + walletAddress: "secret1ajz54hz8azwuy34qwy9fkjnfcrvf0dzswy0lqq", + }); + + accounts.d = await SecretNetworkClient.create({ + chainId: "secretdev-1", + grpcWebUrl: "http://localhost:9091", + wallet: new Wallet( + "word twist toast cloth movie predict advance crumble escape whale sail such angry muffin balcony keen move employ cook valve hurt glimpse breeze brick" + ), + walletAddress: "secret1ldjxljw7v4vk6zhyduywh04hpj0jdwxsmrlatf", + }); + + console.log("Waiting for LocalSecret to start..."); + await waitForBlocks(); + + const v1Wasm = fs.readFileSync( + `${__dirname}/contract-v1/contract.wasm` + ) as Uint8Array; + v1CodeHash = toHex(sha256(v1Wasm)); + + const v010Wasm = fs.readFileSync( + `${__dirname}/contract-v0.10/contract.wasm` + ) as Uint8Array; + v010CodeHash = toHex(sha256(v010Wasm)); + + let tx = await accounts.a.tx.broadcast( + [ + new MsgStoreCode({ + sender: accounts.a.address, + wasmByteCode: v1Wasm, + source: "", + builder: "", + }), + new MsgStoreCode({ + sender: accounts.a.address, + wasmByteCode: v010Wasm, + source: "", + builder: "", + }), + ], + { gasLimit: 5_000_000 } + ); + if (tx.code !== 0) { + console.error(tx.rawLog); + } + expect(tx.code).toBe(0); + + v1CodeID = Number(tx.arrayLog.find((x) => x.key === "code_id").value); + v010CodeID = Number( + tx.arrayLog.reverse().find((x) => x.key === "code_id").value + ); + + tx = await accounts.a.tx.broadcast( + [ + new MsgInstantiateContract({ + sender: accounts.a.address, + codeId: v1CodeID, + codeHash: v1CodeHash, + initMsg: { nop: {} }, + label: `v1-${Math.random()}`, + }), + new MsgInstantiateContract({ + sender: accounts.a.address, + codeId: v010CodeID, + codeHash: v010CodeHash, + initMsg: { nop: {} }, + label: `v010-${Math.random()}`, + }), + ], + { gasLimit: 200_000 } + ); + if (tx.code !== 0) { + console.error(tx.rawLog); + } + expect(tx.code).toBe(0); + + v1Address = tx.arrayLog.find((x) => x.key === "contract_address").value; + v010Address = tx.arrayLog + .reverse() + .find((x) => x.key === "contract_address").value; +}); + +async function sleep(ms: number) { + return new Promise((resolve) => setTimeout(resolve, ms)); +} +async function waitForBlocks() { + while (true) { + const secretjs = await SecretNetworkClient.create({ + grpcWebUrl: "http://localhost:9091", + chainId: "secretdev-1", + }); + + try { + const { block } = await secretjs.query.tendermint.getLatestBlock({}); + + if (Number(block?.header?.height) >= 1) { + console.log("blocks are running, current block:", JSON.stringify(block.header.height)); + break; + } + } catch (e) { + console.error("block error:", e); + } + await sleep(100); + } +} + +describe("Bank::MsgSend", () => { + test("v1", async () => { + const tx = await accounts.a.tx.compute.executeContract( + { + sender: accounts.a.address, + contractAddress: v1Address, + codeHash: v1CodeHash, + msg: { + bank_msg_send: { + to_address: accounts.b.address, + amount: [{ amount: "1", denom: "uscrt" }], + }, + }, + sentFunds: [{ amount: "1", denom: "uscrt" }], + }, + { gasLimit: 250_000 } + ); + if (tx.code !== 0) { + console.error(tx.rawLog); + } + expect(tx.code).toBe(0); + expect(tx.arrayLog.filter((x) => x.type === "coin_spent")).toStrictEqual([ + { + key: "spender", + msg: 0, + type: "coin_spent", + value: accounts.a.address, + }, + { key: "amount", msg: 0, type: "coin_spent", value: "1uscrt" }, + { + key: "spender", + msg: 0, + type: "coin_spent", + value: v1Address, + }, + { key: "amount", msg: 0, type: "coin_spent", value: "1uscrt" }, + ]); + expect(tx.arrayLog.filter((x) => x.type === "coin_received")).toStrictEqual( + [ + { + key: "receiver", + msg: 0, + type: "coin_received", + value: v1Address, + }, + { key: "amount", msg: 0, type: "coin_received", value: "1uscrt" }, + { + key: "receiver", + msg: 0, + type: "coin_received", + value: accounts.b.address, + }, + { key: "amount", msg: 0, type: "coin_received", value: "1uscrt" }, + ] + ); + }); + + test("v0.10", async () => { + const tx = await accounts.a.tx.compute.executeContract( + { + sender: accounts.a.address, + contractAddress: v010Address, + codeHash: v010CodeHash, + msg: { + bank_msg_send: { + to_address: accounts.b.address, + amount: [{ amount: "1", denom: "uscrt" }], + }, + }, + sentFunds: [{ amount: "1", denom: "uscrt" }], + }, + { gasLimit: 250_000 } + ); + if (tx.code !== 0) { + console.error(tx.rawLog); + } + expect(tx.code).toBe(0); + expect(tx.arrayLog.filter((x) => x.type === "coin_spent")).toStrictEqual([ + { + key: "spender", + msg: 0, + type: "coin_spent", + value: accounts.a.address, + }, + { key: "amount", msg: 0, type: "coin_spent", value: "1uscrt" }, + { + key: "spender", + msg: 0, + type: "coin_spent", + value: v010Address, + }, + { key: "amount", msg: 0, type: "coin_spent", value: "1uscrt" }, + ]); + expect(tx.arrayLog.filter((x) => x.type === "coin_received")).toStrictEqual( + [ + { + key: "receiver", + msg: 0, + type: "coin_received", + value: v010Address, + }, + { key: "amount", msg: 0, type: "coin_received", value: "1uscrt" }, + { + key: "receiver", + msg: 0, + type: "coin_received", + value: accounts.b.address, + }, + { key: "amount", msg: 0, type: "coin_received", value: "1uscrt" }, + ] + ); + }); +}); + +describe("StargateMsg", () => { + test("v1", async () => { + const tx = await accounts.a.tx.compute.executeContract( + { + sender: accounts.a.address, + contractAddress: v1Address, + codeHash: v1CodeHash, + msg: { + stargate_msg: { + type_url: "/cosmos.bank.v1beta1.MsgSend", + value: toBase64( + MsgSend.encode({ + fromAddress: v1Address, + toAddress: accounts.b.address, + amount: [{ amount: "1", denom: "uscrt" }], + }).finish() + ), + }, + }, + sentFunds: [{ amount: "1", denom: "uscrt" }], + }, + { gasLimit: 250_000 } + ); + if (tx.code !== 0) { + console.error(tx.rawLog); + } + expect(tx.code).toBe(0); + expect(tx.arrayLog.filter((x) => x.type === "coin_spent")).toStrictEqual([ + { + key: "spender", + msg: 0, + type: "coin_spent", + value: accounts.a.address, + }, + { key: "amount", msg: 0, type: "coin_spent", value: "1uscrt" }, + { + key: "spender", + msg: 0, + type: "coin_spent", + value: v1Address, + }, + { key: "amount", msg: 0, type: "coin_spent", value: "1uscrt" }, + ]); + expect(tx.arrayLog.filter((x) => x.type === "coin_received")).toStrictEqual( + [ + { + key: "receiver", + msg: 0, + type: "coin_received", + value: v1Address, + }, + { key: "amount", msg: 0, type: "coin_received", value: "1uscrt" }, + { + key: "receiver", + msg: 0, + type: "coin_received", + value: accounts.b.address, + }, + { key: "amount", msg: 0, type: "coin_received", value: "1uscrt" }, + ] + ); + }); +}); + +describe("StargateQuery", () => { + test("v1", async () => { + const result: any = await accounts.a.query.compute.queryContract({ + contractAddress: v1Address, + codeHash: v1CodeHash, + query: { + stargate: { + path: "/cosmos.bank.v1beta1.Query/Balance", + data: toBase64( + QueryBalanceRequest.encode({ + address: accounts.a.address, + denom: "uscrt", + }).finish() + ), + }, + }, + }); + + const response = QueryBalanceResponse.decode(fromBase64(result)); + expect(response?.balance?.denom).toBe("uscrt"); + expect(Number(response?.balance?.amount)).toBeGreaterThanOrEqual(1); + }); +}); + +describe("BankQuery", () => { + describe("Balance", () => { + test("v1", async () => { + const result: any = await accounts.a.query.compute.queryContract({ + contractAddress: v1Address, + codeHash: v1CodeHash, + query: { + bank_balance: { + address: accounts.a.address, + denom: "uscrt", + }, + }, + }); + expect(result?.amount?.denom).toBe("uscrt"); + expect(Number(result?.amount?.amount)).toBeGreaterThanOrEqual(1); + }); + + test("v0.10", async () => { + const result: any = await accounts.a.query.compute.queryContract({ + contractAddress: v010Address, + codeHash: v010CodeHash, + query: { + bank_balance: { + address: accounts.a.address, + denom: "uscrt", + }, + }, + }); + expect(result?.amount?.denom).toBe("uscrt"); + expect(Number(result?.amount?.amount)).toBeGreaterThanOrEqual(1); + }); + }); +}); diff --git a/integration-tests/tsconfig.json b/integration-tests/tsconfig.json new file mode 100644 index 000000000..b6105b83d --- /dev/null +++ b/integration-tests/tsconfig.json @@ -0,0 +1,6 @@ +{ + "compilerOptions": { + "types": ["jest", "node"], + "esModuleInterop": true + } +} diff --git a/integration-tests/utils.ts b/integration-tests/utils.ts new file mode 100644 index 000000000..569cef2a7 --- /dev/null +++ b/integration-tests/utils.ts @@ -0,0 +1,68 @@ +const testInput = { + events: [ + { + type: "yes", + attributes: [ + { + key: { + "0": 115, + "1": 101, + "2": 110, + "3": 100, + "4": 101, + "5": 114 + }, + value: { + "0": 115, + "1": 101, + "2": 99, + "3": 114, + }, + index: true + } + ] + } + ], + "other": "value" +} + +interface BytesObj { + [key: string]: number +} + +const bytesToKv = (input: BytesObj) => { + let output = ""; + for (const v of Object.values(input)) { + output += String.fromCharCode(v); + } + + return output; +} + +const objToKv = (input) => { + // console.log("got object:", input); + const output = {}; + const key = bytesToKv(input.key); + output[key] = bytesToKv(input.value); + return output; +} + +export const cleanBytes = (tx) => { + // console.log("input:", JSON.stringify(testInput, null, 2), "\n\n"); + + const events = tx.events.map(e => { + return { + ...e, + attributes: e.attributes.map(i => objToKv(i)) + }; + } + ) + + const output = { + ...tx, + events, + txBytes: undefined, + }; + // console.log("output:", JSON.stringify(output, null, 2)); + return output; +} \ No newline at end of file diff --git a/integration-tests/yarn.lock b/integration-tests/yarn.lock new file mode 100644 index 000000000..eade28849 --- /dev/null +++ b/integration-tests/yarn.lock @@ -0,0 +1,2763 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@ampproject/remapping@^2.1.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.0.tgz#56c133824780de3174aed5ab6834f3026790154d" + integrity sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w== + dependencies: + "@jridgewell/gen-mapping" "^0.1.0" + "@jridgewell/trace-mapping" "^0.3.9" + +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.18.6.tgz#3b25d38c89600baa2dcc219edfa88a74eb2c427a" + integrity sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q== + dependencies: + "@babel/highlight" "^7.18.6" + +"@babel/compat-data@^7.18.8": + version "7.18.8" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.18.8.tgz#2483f565faca607b8535590e84e7de323f27764d" + integrity sha512-HSmX4WZPPK3FUxYp7g2T6EyO8j96HlZJlxmKPSh6KAcqwyDrfx7hKjXpAW/0FhFfTJsR0Yt4lAjLI2coMptIHQ== + +"@babel/core@^7.11.6", "@babel/core@^7.12.3": + version "7.18.10" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.18.10.tgz#39ad504991d77f1f3da91be0b8b949a5bc466fb8" + integrity sha512-JQM6k6ENcBFKVtWvLavlvi/mPcpYZ3+R+2EySDEMSMbp7Mn4FexlbbJVrx2R7Ijhr01T8gyqrOaABWIOgxeUyw== + dependencies: + "@ampproject/remapping" "^2.1.0" + "@babel/code-frame" "^7.18.6" + "@babel/generator" "^7.18.10" + "@babel/helper-compilation-targets" "^7.18.9" + "@babel/helper-module-transforms" "^7.18.9" + "@babel/helpers" "^7.18.9" + "@babel/parser" "^7.18.10" + "@babel/template" "^7.18.10" + "@babel/traverse" "^7.18.10" + "@babel/types" "^7.18.10" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.1" + semver "^6.3.0" + +"@babel/generator@^7.18.10", "@babel/generator@^7.7.2": + version "7.18.12" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.18.12.tgz#fa58daa303757bd6f5e4bbca91b342040463d9f4" + integrity sha512-dfQ8ebCN98SvyL7IxNMCUtZQSq5R7kxgN+r8qYTGDmmSion1hX2C0zq2yo1bsCDhXixokv1SAWTZUMYbO/V5zg== + dependencies: + "@babel/types" "^7.18.10" + "@jridgewell/gen-mapping" "^0.3.2" + jsesc "^2.5.1" + +"@babel/helper-compilation-targets@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.18.9.tgz#69e64f57b524cde3e5ff6cc5a9f4a387ee5563bf" + integrity sha512-tzLCyVmqUiFlcFoAPLA/gL9TeYrF61VLNtb+hvkuVaB5SUjW7jcfrglBIX1vUIoT7CLP3bBlIMeyEsIl2eFQNg== + dependencies: + "@babel/compat-data" "^7.18.8" + "@babel/helper-validator-option" "^7.18.6" + browserslist "^4.20.2" + semver "^6.3.0" + +"@babel/helper-environment-visitor@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz#0c0cee9b35d2ca190478756865bb3528422f51be" + integrity sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg== + +"@babel/helper-function-name@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.18.9.tgz#940e6084a55dee867d33b4e487da2676365e86b0" + integrity sha512-fJgWlZt7nxGksJS9a0XdSaI4XvpExnNIgRP+rVefWh5U7BL8pPuir6SJUmFKRfjWQ51OtWSzwOxhaH/EBWWc0A== + dependencies: + "@babel/template" "^7.18.6" + "@babel/types" "^7.18.9" + +"@babel/helper-hoist-variables@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz#d4d2c8fb4baeaa5c68b99cc8245c56554f926678" + integrity sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-module-imports@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz#1e3ebdbbd08aad1437b428c50204db13c5a3ca6e" + integrity sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-module-transforms@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.18.9.tgz#5a1079c005135ed627442df31a42887e80fcb712" + integrity sha512-KYNqY0ICwfv19b31XzvmI/mfcylOzbLtowkw+mfvGPAQ3kfCnMLYbED3YecL5tPd8nAYFQFAd6JHp2LxZk/J1g== + dependencies: + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-module-imports" "^7.18.6" + "@babel/helper-simple-access" "^7.18.6" + "@babel/helper-split-export-declaration" "^7.18.6" + "@babel/helper-validator-identifier" "^7.18.6" + "@babel/template" "^7.18.6" + "@babel/traverse" "^7.18.9" + "@babel/types" "^7.18.9" + +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.8.0": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.18.9.tgz#4b8aea3b069d8cb8a72cdfe28ddf5ceca695ef2f" + integrity sha512-aBXPT3bmtLryXaoJLyYPXPlSD4p1ld9aYeR+sJNOZjJJGiOpb+fKfh3NkcCu7J54nUJwCERPBExCCpyCOHnu/w== + +"@babel/helper-simple-access@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.18.6.tgz#d6d8f51f4ac2978068df934b569f08f29788c7ea" + integrity sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-split-export-declaration@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz#7367949bc75b20c6d5a5d4a97bba2824ae8ef075" + integrity sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-string-parser@^7.18.10": + version "7.18.10" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.18.10.tgz#181f22d28ebe1b3857fa575f5c290b1aaf659b56" + integrity sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw== + +"@babel/helper-validator-identifier@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz#9c97e30d31b2b8c72a1d08984f2ca9b574d7a076" + integrity sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g== + +"@babel/helper-validator-option@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz#bf0d2b5a509b1f336099e4ff36e1a63aa5db4db8" + integrity sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw== + +"@babel/helpers@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.18.9.tgz#4bef3b893f253a1eced04516824ede94dcfe7ff9" + integrity sha512-Jf5a+rbrLoR4eNdUmnFu8cN5eNJT6qdTdOg5IHIzq87WwyRw9PwguLFOWYgktN/60IP4fgDUawJvs7PjQIzELQ== + dependencies: + "@babel/template" "^7.18.6" + "@babel/traverse" "^7.18.9" + "@babel/types" "^7.18.9" + +"@babel/highlight@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.18.6.tgz#81158601e93e2563795adcbfbdf5d64be3f2ecdf" + integrity sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g== + dependencies: + "@babel/helper-validator-identifier" "^7.18.6" + chalk "^2.0.0" + js-tokens "^4.0.0" + +"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.18.10", "@babel/parser@^7.18.11": + version "7.18.11" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.18.11.tgz#68bb07ab3d380affa9a3f96728df07969645d2d9" + integrity sha512-9JKn5vN+hDt0Hdqn1PiJ2guflwP+B6Ga8qbDuoF0PzzVhrzsKIJo8yGqVk6CmMHiMei9w1C1Bp9IMJSIK+HPIQ== + +"@babel/plugin-syntax-async-generators@^7.8.4": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" + integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-bigint@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz#4c9a6f669f5d0cdf1b90a1671e9a146be5300cea" + integrity sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-class-properties@^7.8.3": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" + integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== + dependencies: + "@babel/helper-plugin-utils" "^7.12.13" + +"@babel/plugin-syntax-import-meta@^7.8.3": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51" + integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-json-strings@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" + integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-logical-assignment-operators@^7.8.3": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" + integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" + integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-numeric-separator@^7.8.3": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" + integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-object-rest-spread@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" + integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-catch-binding@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" + integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-chaining@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" + integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-top-level-await@^7.8.3": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" + integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-typescript@^7.7.2": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.18.6.tgz#1c09cd25795c7c2b8a4ba9ae49394576d4133285" + integrity sha512-mAWAuq4rvOepWCBid55JuRNvpTNf2UGVgoz4JV0fXEKolsVZDzsa4NqCef758WZJj/GDu0gVGItjKFiClTAmZA== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/runtime@^7.18.3": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.18.9.tgz#b4fcfce55db3d2e5e080d2490f608a3b9f407f4a" + integrity sha512-lkqXDcvlFT5rvEjiu6+QYO+1GXrEHRo2LOtS7E4GtX5ESIZOgepqsZBVIj6Pv+a6zqsya9VCgiK1KAK4BvJDAw== + dependencies: + regenerator-runtime "^0.13.4" + +"@babel/template@^7.18.10", "@babel/template@^7.18.6", "@babel/template@^7.3.3": + version "7.18.10" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.18.10.tgz#6f9134835970d1dbf0835c0d100c9f38de0c5e71" + integrity sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA== + dependencies: + "@babel/code-frame" "^7.18.6" + "@babel/parser" "^7.18.10" + "@babel/types" "^7.18.10" + +"@babel/traverse@^7.18.10", "@babel/traverse@^7.18.9", "@babel/traverse@^7.7.2": + version "7.18.11" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.18.11.tgz#3d51f2afbd83ecf9912bcbb5c4d94e3d2ddaa16f" + integrity sha512-TG9PiM2R/cWCAy6BPJKeHzNbu4lPzOSZpeMfeNErskGpTJx6trEvFaVCbDvpcxwy49BKWmEPwiW8mrysNiDvIQ== + dependencies: + "@babel/code-frame" "^7.18.6" + "@babel/generator" "^7.18.10" + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-function-name" "^7.18.9" + "@babel/helper-hoist-variables" "^7.18.6" + "@babel/helper-split-export-declaration" "^7.18.6" + "@babel/parser" "^7.18.11" + "@babel/types" "^7.18.10" + debug "^4.1.0" + globals "^11.1.0" + +"@babel/types@^7.0.0", "@babel/types@^7.18.10", "@babel/types@^7.18.6", "@babel/types@^7.18.9", "@babel/types@^7.3.0", "@babel/types@^7.3.3": + version "7.18.10" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.18.10.tgz#4908e81b6b339ca7c6b7a555a5fc29446f26dde6" + integrity sha512-MJvnbEiiNkpjo+LknnmRrqbY1GPUUggjv+wQVjetM/AONoupqRALB7I6jGqNUAZsKcRIEu2J6FRFvsczljjsaQ== + dependencies: + "@babel/helper-string-parser" "^7.18.10" + "@babel/helper-validator-identifier" "^7.18.6" + to-fast-properties "^2.0.0" + +"@bcoe/v8-coverage@^0.2.3": + version "0.2.3" + resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" + integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== + +"@cosmjs/encoding@0.27.1": + version "0.27.1" + resolved "https://registry.yarnpkg.com/@cosmjs/encoding/-/encoding-0.27.1.tgz#3cd5bc0af743485eb2578cdb08cfa84c86d610e1" + integrity sha512-rayLsA0ojHeniaRfWWcqSsrE/T1rl1gl0OXVNtXlPwLJifKBeLEefGbOUiAQaT0wgJ8VNGBazVtAZBpJidfDhw== + dependencies: + base64-js "^1.3.0" + bech32 "^1.1.4" + readonly-date "^1.0.0" + +"@cosmjs/math@0.27.1": + version "0.27.1" + resolved "https://registry.yarnpkg.com/@cosmjs/math/-/math-0.27.1.tgz#be78857b008ffc6b1ed6fecaa1c4cd5bc38c07d7" + integrity sha512-cHWVjmfIjtRc7f80n7x+J5k8pe+vTVTQ0lA82tIxUgqUvgS6rogPP/TmGtTiZ4+NxWxd11DUISY6gVpr18/VNQ== + dependencies: + bn.js "^5.2.0" + +"@cspotcode/source-map-support@^0.8.0": + version "0.8.1" + resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1" + integrity sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw== + dependencies: + "@jridgewell/trace-mapping" "0.3.9" + +"@improbable-eng/grpc-web-node-http-transport@0.15.0": + version "0.15.0" + resolved "https://registry.yarnpkg.com/@improbable-eng/grpc-web-node-http-transport/-/grpc-web-node-http-transport-0.15.0.tgz#5a064472ef43489cbd075a91fb831c2abeb09d68" + integrity sha512-HLgJfVolGGpjc9DWPhmMmXJx8YGzkek7jcCFO1YYkSOoO81MWRZentPOd/JiKiZuU08wtc4BG+WNuGzsQB5jZA== + +"@improbable-eng/grpc-web@0.15.0": + version "0.15.0" + resolved "https://registry.yarnpkg.com/@improbable-eng/grpc-web/-/grpc-web-0.15.0.tgz#3e47e9fdd90381a74abd4b7d26e67422a2a04bef" + integrity sha512-ERft9/0/8CmYalqOVnJnpdDry28q+j+nAlFFARdjyxXDJ+Mhgv9+F600QC8BR9ygOfrXRlAk6CvST2j+JCpQPg== + dependencies: + browser-headers "^0.4.1" + +"@istanbuljs/load-nyc-config@^1.0.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" + integrity sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ== + dependencies: + camelcase "^5.3.1" + find-up "^4.1.0" + get-package-type "^0.1.0" + js-yaml "^3.13.1" + resolve-from "^5.0.0" + +"@istanbuljs/schema@^0.1.2": + version "0.1.3" + resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" + integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== + +"@jest/console@^28.1.3": + version "28.1.3" + resolved "https://registry.yarnpkg.com/@jest/console/-/console-28.1.3.tgz#2030606ec03a18c31803b8a36382762e447655df" + integrity sha512-QPAkP5EwKdK/bxIr6C1I4Vs0rm2nHiANzj/Z5X2JQkrZo6IqvC4ldZ9K95tF0HdidhA8Bo6egxSzUFPYKcEXLw== + dependencies: + "@jest/types" "^28.1.3" + "@types/node" "*" + chalk "^4.0.0" + jest-message-util "^28.1.3" + jest-util "^28.1.3" + slash "^3.0.0" + +"@jest/core@^28.1.3": + version "28.1.3" + resolved "https://registry.yarnpkg.com/@jest/core/-/core-28.1.3.tgz#0ebf2bd39840f1233cd5f2d1e6fc8b71bd5a1ac7" + integrity sha512-CIKBrlaKOzA7YG19BEqCw3SLIsEwjZkeJzf5bdooVnW4bH5cktqe3JX+G2YV1aK5vP8N9na1IGWFzYaTp6k6NA== + dependencies: + "@jest/console" "^28.1.3" + "@jest/reporters" "^28.1.3" + "@jest/test-result" "^28.1.3" + "@jest/transform" "^28.1.3" + "@jest/types" "^28.1.3" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + ci-info "^3.2.0" + exit "^0.1.2" + graceful-fs "^4.2.9" + jest-changed-files "^28.1.3" + jest-config "^28.1.3" + jest-haste-map "^28.1.3" + jest-message-util "^28.1.3" + jest-regex-util "^28.0.2" + jest-resolve "^28.1.3" + jest-resolve-dependencies "^28.1.3" + jest-runner "^28.1.3" + jest-runtime "^28.1.3" + jest-snapshot "^28.1.3" + jest-util "^28.1.3" + jest-validate "^28.1.3" + jest-watcher "^28.1.3" + micromatch "^4.0.4" + pretty-format "^28.1.3" + rimraf "^3.0.0" + slash "^3.0.0" + strip-ansi "^6.0.0" + +"@jest/environment@^28.1.3": + version "28.1.3" + resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-28.1.3.tgz#abed43a6b040a4c24fdcb69eab1f97589b2d663e" + integrity sha512-1bf40cMFTEkKyEf585R9Iz1WayDjHoHqvts0XFYEqyKM3cFWDpeMoqKKTAF9LSYQModPUlh8FKptoM2YcMWAXA== + dependencies: + "@jest/fake-timers" "^28.1.3" + "@jest/types" "^28.1.3" + "@types/node" "*" + jest-mock "^28.1.3" + +"@jest/expect-utils@^28.1.3": + version "28.1.3" + resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-28.1.3.tgz#58561ce5db7cd253a7edddbc051fb39dda50f525" + integrity sha512-wvbi9LUrHJLn3NlDW6wF2hvIMtd4JUl2QNVrjq+IBSHirgfrR3o9RnVtxzdEGO2n9JyIWwHnLfby5KzqBGg2YA== + dependencies: + jest-get-type "^28.0.2" + +"@jest/expect@^28.1.3": + version "28.1.3" + resolved "https://registry.yarnpkg.com/@jest/expect/-/expect-28.1.3.tgz#9ac57e1d4491baca550f6bdbd232487177ad6a72" + integrity sha512-lzc8CpUbSoE4dqT0U+g1qODQjBRHPpCPXissXD4mS9+sWQdmmpeJ9zSH1rS1HEkrsMN0fb7nKrJ9giAR1d3wBw== + dependencies: + expect "^28.1.3" + jest-snapshot "^28.1.3" + +"@jest/fake-timers@^28.1.3": + version "28.1.3" + resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-28.1.3.tgz#230255b3ad0a3d4978f1d06f70685baea91c640e" + integrity sha512-D/wOkL2POHv52h+ok5Oj/1gOG9HSywdoPtFsRCUmlCILXNn5eIWmcnd3DIiWlJnpGvQtmajqBP95Ei0EimxfLw== + dependencies: + "@jest/types" "^28.1.3" + "@sinonjs/fake-timers" "^9.1.2" + "@types/node" "*" + jest-message-util "^28.1.3" + jest-mock "^28.1.3" + jest-util "^28.1.3" + +"@jest/globals@^28.1.3": + version "28.1.3" + resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-28.1.3.tgz#a601d78ddc5fdef542728309894895b4a42dc333" + integrity sha512-XFU4P4phyryCXu1pbcqMO0GSQcYe1IsalYCDzRNyhetyeyxMcIxa11qPNDpVNLeretItNqEmYYQn1UYz/5x1NA== + dependencies: + "@jest/environment" "^28.1.3" + "@jest/expect" "^28.1.3" + "@jest/types" "^28.1.3" + +"@jest/reporters@^28.1.3": + version "28.1.3" + resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-28.1.3.tgz#9adf6d265edafc5fc4a434cfb31e2df5a67a369a" + integrity sha512-JuAy7wkxQZVNU/V6g9xKzCGC5LVXx9FDcABKsSXp5MiKPEE2144a/vXTEDoyzjUpZKfVwp08Wqg5A4WfTMAzjg== + dependencies: + "@bcoe/v8-coverage" "^0.2.3" + "@jest/console" "^28.1.3" + "@jest/test-result" "^28.1.3" + "@jest/transform" "^28.1.3" + "@jest/types" "^28.1.3" + "@jridgewell/trace-mapping" "^0.3.13" + "@types/node" "*" + chalk "^4.0.0" + collect-v8-coverage "^1.0.0" + exit "^0.1.2" + glob "^7.1.3" + graceful-fs "^4.2.9" + istanbul-lib-coverage "^3.0.0" + istanbul-lib-instrument "^5.1.0" + istanbul-lib-report "^3.0.0" + istanbul-lib-source-maps "^4.0.0" + istanbul-reports "^3.1.3" + jest-message-util "^28.1.3" + jest-util "^28.1.3" + jest-worker "^28.1.3" + slash "^3.0.0" + string-length "^4.0.1" + strip-ansi "^6.0.0" + terminal-link "^2.0.0" + v8-to-istanbul "^9.0.1" + +"@jest/schemas@^28.1.3": + version "28.1.3" + resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-28.1.3.tgz#ad8b86a66f11f33619e3d7e1dcddd7f2d40ff905" + integrity sha512-/l/VWsdt/aBXgjshLWOFyFt3IVdYypu5y2Wn2rOO1un6nkqIn8SLXzgIMYXFyYsRWDyF5EthmKJMIdJvk08grg== + dependencies: + "@sinclair/typebox" "^0.24.1" + +"@jest/source-map@^28.1.2": + version "28.1.2" + resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-28.1.2.tgz#7fe832b172b497d6663cdff6c13b0a920e139e24" + integrity sha512-cV8Lx3BeStJb8ipPHnqVw/IM2VCMWO3crWZzYodSIkxXnRcXJipCdx1JCK0K5MsJJouZQTH73mzf4vgxRaH9ww== + dependencies: + "@jridgewell/trace-mapping" "^0.3.13" + callsites "^3.0.0" + graceful-fs "^4.2.9" + +"@jest/test-result@^28.1.3": + version "28.1.3" + resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-28.1.3.tgz#5eae945fd9f4b8fcfce74d239e6f725b6bf076c5" + integrity sha512-kZAkxnSE+FqE8YjW8gNuoVkkC9I7S1qmenl8sGcDOLropASP+BkcGKwhXoyqQuGOGeYY0y/ixjrd/iERpEXHNg== + dependencies: + "@jest/console" "^28.1.3" + "@jest/types" "^28.1.3" + "@types/istanbul-lib-coverage" "^2.0.0" + collect-v8-coverage "^1.0.0" + +"@jest/test-sequencer@^28.1.3": + version "28.1.3" + resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-28.1.3.tgz#9d0c283d906ac599c74bde464bc0d7e6a82886c3" + integrity sha512-NIMPEqqa59MWnDi1kvXXpYbqsfQmSJsIbnd85mdVGkiDfQ9WQQTXOLsvISUfonmnBT+w85WEgneCigEEdHDFxw== + dependencies: + "@jest/test-result" "^28.1.3" + graceful-fs "^4.2.9" + jest-haste-map "^28.1.3" + slash "^3.0.0" + +"@jest/transform@^28.1.3": + version "28.1.3" + resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-28.1.3.tgz#59d8098e50ab07950e0f2fc0fc7ec462371281b0" + integrity sha512-u5dT5di+oFI6hfcLOHGTAfmUxFRrjK+vnaP0kkVow9Md/M7V/MxqQMOz/VV25UZO8pzeA9PjfTpOu6BDuwSPQA== + dependencies: + "@babel/core" "^7.11.6" + "@jest/types" "^28.1.3" + "@jridgewell/trace-mapping" "^0.3.13" + babel-plugin-istanbul "^6.1.1" + chalk "^4.0.0" + convert-source-map "^1.4.0" + fast-json-stable-stringify "^2.0.0" + graceful-fs "^4.2.9" + jest-haste-map "^28.1.3" + jest-regex-util "^28.0.2" + jest-util "^28.1.3" + micromatch "^4.0.4" + pirates "^4.0.4" + slash "^3.0.0" + write-file-atomic "^4.0.1" + +"@jest/types@^28.1.3": + version "28.1.3" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-28.1.3.tgz#b05de80996ff12512bc5ceb1d208285a7d11748b" + integrity sha512-RyjiyMUZrKz/c+zlMFO1pm70DcIlST8AeWTkoUdZevew44wcNZQHsEVOiCVtgVnlFFD82FPaXycys58cf2muVQ== + dependencies: + "@jest/schemas" "^28.1.3" + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^3.0.0" + "@types/node" "*" + "@types/yargs" "^17.0.8" + chalk "^4.0.0" + +"@jridgewell/gen-mapping@^0.1.0": + version "0.1.1" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz#e5d2e450306a9491e3bd77e323e38d7aff315996" + integrity sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w== + dependencies: + "@jridgewell/set-array" "^1.0.0" + "@jridgewell/sourcemap-codec" "^1.4.10" + +"@jridgewell/gen-mapping@^0.3.2": + version "0.3.2" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz#c1aedc61e853f2bb9f5dfe6d4442d3b565b253b9" + integrity sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A== + dependencies: + "@jridgewell/set-array" "^1.0.1" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.9" + +"@jridgewell/resolve-uri@^3.0.3": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78" + integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w== + +"@jridgewell/set-array@^1.0.0", "@jridgewell/set-array@^1.0.1": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" + integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== + +"@jridgewell/sourcemap-codec@^1.4.10": + version "1.4.14" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24" + integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== + +"@jridgewell/trace-mapping@0.3.9": + version "0.3.9" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz#6534fd5933a53ba7cbf3a17615e273a0d1273ff9" + integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ== + dependencies: + "@jridgewell/resolve-uri" "^3.0.3" + "@jridgewell/sourcemap-codec" "^1.4.10" + +"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.13", "@jridgewell/trace-mapping@^0.3.9": + version "0.3.15" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.15.tgz#aba35c48a38d3fd84b37e66c9c0423f9744f9774" + integrity sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g== + dependencies: + "@jridgewell/resolve-uri" "^3.0.3" + "@jridgewell/sourcemap-codec" "^1.4.10" + +"@noble/hashes@1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.0.0.tgz#d5e38bfbdaba174805a4e649f13be9a9ed3351ae" + integrity sha512-DZVbtY62kc3kkBtMHqwCOfXrT/hnoORy5BJ4+HU1IR59X0KWAOqsfzQPcUl/lQLlG7qXbe/fZ3r/emxtAl+sqg== + +"@noble/hashes@1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.1.2.tgz#e9e035b9b166ca0af657a7848eb2718f0f22f183" + integrity sha512-KYRCASVTv6aeUi1tsF8/vpyR7zpfs3FUzy2Jqm+MU+LmUKhQ0y2FpfwqkCcxSg2ua4GALJd8k2R76WxwZGbQpA== + +"@noble/secp256k1@1.6.3": + version "1.6.3" + resolved "https://registry.yarnpkg.com/@noble/secp256k1/-/secp256k1-1.6.3.tgz#7eed12d9f4404b416999d0c87686836c4c5c9b94" + integrity sha512-T04e4iTurVy7I8Sw4+c5OSN9/RkPlo1uKxAomtxQNLq8j1uPAqnsqG1bqvY3Jv7c13gyr6dui0zmh/I3+f/JaQ== + +"@osmonauts/helpers@0.3.8": + version "0.3.8" + resolved "https://registry.yarnpkg.com/@osmonauts/helpers/-/helpers-0.3.8.tgz#77a57cdd20922cd477f21de9662a403620e2c848" + integrity sha512-6xM/DGjLctziRVT2DuR7/MQ/HqfHAcqOaGF4z77Jeh3RWQ78zWiaRVxBefRQdKaqrh5LhXL6VebUdiy9IGwTTA== + dependencies: + "@babel/runtime" "^7.18.3" + long "^5.2.0" + protobufjs "^6.11.3" + +"@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/aspromise/-/aspromise-1.1.2.tgz#9b8b0cc663d669a7d8f6f5d0893a14d348f30fbf" + integrity sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ== + +"@protobufjs/base64@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/base64/-/base64-1.1.2.tgz#4c85730e59b9a1f1f349047dbf24296034bb2735" + integrity sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg== + +"@protobufjs/codegen@^2.0.4": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@protobufjs/codegen/-/codegen-2.0.4.tgz#7ef37f0d010fb028ad1ad59722e506d9262815cb" + integrity sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg== + +"@protobufjs/eventemitter@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz#355cbc98bafad5978f9ed095f397621f1d066b70" + integrity sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q== + +"@protobufjs/fetch@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/fetch/-/fetch-1.1.0.tgz#ba99fb598614af65700c1619ff06d454b0d84c45" + integrity sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ== + dependencies: + "@protobufjs/aspromise" "^1.1.1" + "@protobufjs/inquire" "^1.1.0" + +"@protobufjs/float@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@protobufjs/float/-/float-1.0.2.tgz#5e9e1abdcb73fc0a7cb8b291df78c8cbd97b87d1" + integrity sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ== + +"@protobufjs/inquire@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/inquire/-/inquire-1.1.0.tgz#ff200e3e7cf2429e2dcafc1140828e8cc638f089" + integrity sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q== + +"@protobufjs/path@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/path/-/path-1.1.2.tgz#6cc2b20c5c9ad6ad0dccfd21ca7673d8d7fbf68d" + integrity sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA== + +"@protobufjs/pool@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/pool/-/pool-1.1.0.tgz#09fd15f2d6d3abfa9b65bc366506d6ad7846ff54" + integrity sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw== + +"@protobufjs/utf8@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570" + integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw== + +"@sinclair/typebox@^0.24.1": + version "0.24.28" + resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.24.28.tgz#15aa0b416f82c268b1573ab653e4413c965fe794" + integrity sha512-dgJd3HLOkLmz4Bw50eZx/zJwtBq65nms3N9VBYu5LTjJ883oBFkTyXRlCB/ZGGwqYpJJHA5zW2Ibhl5ngITfow== + +"@sinonjs/commons@^1.7.0": + version "1.8.3" + resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.3.tgz#3802ddd21a50a949b6721ddd72da36e67e7f1b2d" + integrity sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ== + dependencies: + type-detect "4.0.8" + +"@sinonjs/fake-timers@^9.1.2": + version "9.1.2" + resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz#4eaab737fab77332ab132d396a3c0d364bd0ea8c" + integrity sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw== + dependencies: + "@sinonjs/commons" "^1.7.0" + +"@tsconfig/node10@^1.0.7": + version "1.0.9" + resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.9.tgz#df4907fc07a886922637b15e02d4cebc4c0021b2" + integrity sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA== + +"@tsconfig/node12@^1.0.7": + version "1.0.11" + resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.11.tgz#ee3def1f27d9ed66dac6e46a295cffb0152e058d" + integrity sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag== + +"@tsconfig/node14@^1.0.0": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.3.tgz#e4386316284f00b98435bf40f72f75a09dabf6c1" + integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow== + +"@tsconfig/node16@^1.0.2": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.3.tgz#472eaab5f15c1ffdd7f8628bd4c4f753995ec79e" + integrity sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ== + +"@types/babel__core@^7.1.14": + version "7.1.19" + resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.19.tgz#7b497495b7d1b4812bdb9d02804d0576f43ee460" + integrity sha512-WEOTgRsbYkvA/KCsDwVEGkd7WAr1e3g31VHQ8zy5gul/V1qKullU/BU5I68X5v7V3GnB9eotmom4v5a5gjxorw== + dependencies: + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + "@types/babel__generator" "*" + "@types/babel__template" "*" + "@types/babel__traverse" "*" + +"@types/babel__generator@*": + version "7.6.4" + resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.4.tgz#1f20ce4c5b1990b37900b63f050182d28c2439b7" + integrity sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg== + dependencies: + "@babel/types" "^7.0.0" + +"@types/babel__template@*": + version "7.4.1" + resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.1.tgz#3d1a48fd9d6c0edfd56f2ff578daed48f36c8969" + integrity sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g== + dependencies: + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + +"@types/babel__traverse@*", "@types/babel__traverse@^7.0.6": + version "7.18.0" + resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.18.0.tgz#8134fd78cb39567465be65b9fdc16d378095f41f" + integrity sha512-v4Vwdko+pgymgS+A2UIaJru93zQd85vIGWObM5ekZNdXCKtDYqATlEYnWgfo86Q6I1Lh0oXnksDnMU1cwmlPDw== + dependencies: + "@babel/types" "^7.3.0" + +"@types/graceful-fs@^4.1.3": + version "4.1.5" + resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.5.tgz#21ffba0d98da4350db64891f92a9e5db3cdb4e15" + integrity sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw== + dependencies: + "@types/node" "*" + +"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz#8467d4b3c087805d63580480890791277ce35c44" + integrity sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g== + +"@types/istanbul-lib-report@*": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#c14c24f18ea8190c118ee7562b7ff99a36552686" + integrity sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg== + dependencies: + "@types/istanbul-lib-coverage" "*" + +"@types/istanbul-reports@^3.0.0": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz#9153fe98bba2bd565a63add9436d6f0d7f8468ff" + integrity sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw== + dependencies: + "@types/istanbul-lib-report" "*" + +"@types/jest@28.1.7": + version "28.1.7" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-28.1.7.tgz#a680c5d05b69634c2d54a63cb106d7fb1adaba16" + integrity sha512-acDN4VHD40V24tgu0iC44jchXavRNVFXQ/E6Z5XNsswgoSO/4NgsXoEYmPUGookKldlZQyIpmrEXsHI9cA3ZTA== + dependencies: + expect "^28.0.0" + pretty-format "^28.0.0" + +"@types/long@^4.0.1": + version "4.0.2" + resolved "https://registry.yarnpkg.com/@types/long/-/long-4.0.2.tgz#b74129719fc8d11c01868010082d483b7545591a" + integrity sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA== + +"@types/node@*", "@types/node@18.7.9", "@types/node@>=13.7.0": + version "18.7.9" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.7.9.tgz#180bfc495c91dc62573967edf047e15dbdce1491" + integrity sha512-0N5Y1XAdcl865nDdjbO0m3T6FdmQ4ijE89/urOHLREyTXbpMWbSafx9y7XIsgWGtwUP2iYTinLyyW3FatAxBLQ== + +"@types/node@10.12.18": + version "10.12.18" + resolved "https://registry.yarnpkg.com/@types/node/-/node-10.12.18.tgz#1d3ca764718915584fcd9f6344621b7672665c67" + integrity sha512-fh+pAqt4xRzPfqA6eh3Z2y6fyZavRIumvjhaCL753+TVkGKGhpPeyrJG2JftD0T9q4GF00KjefsQ+PQNDdWQaQ== + +"@types/node@11.11.6": + version "11.11.6" + resolved "https://registry.yarnpkg.com/@types/node/-/node-11.11.6.tgz#df929d1bb2eee5afdda598a41930fe50b43eaa6a" + integrity sha512-Exw4yUWMBXM3X+8oqzJNRqZSwUAaS4+7NdvHqQuFi/d+synz++xmX3QIf+BFqneW8N31R8Ky+sikfZUXq07ggQ== + +"@types/prettier@^2.1.5": + version "2.7.0" + resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.7.0.tgz#ea03e9f0376a4446f44797ca19d9c46c36e352dc" + integrity sha512-RI1L7N4JnW5gQw2spvL7Sllfuf1SaHdrZpCHiBlCXjIlufi1SMNnbu2teze3/QE67Fg2tBlH7W+mi4hVNk4p0A== + +"@types/stack-utils@^2.0.0": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c" + integrity sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw== + +"@types/yargs-parser@*": + version "21.0.0" + resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.0.tgz#0c60e537fa790f5f9472ed2776c2b71ec117351b" + integrity sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA== + +"@types/yargs@^17.0.8": + version "17.0.11" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.11.tgz#5e10ca33e219807c0eee0f08b5efcba9b6a42c06" + integrity sha512-aB4y9UDUXTSMxmM4MH+YnuR0g5Cph3FLQBoWoMB21DSvFVAxRVEHEMx3TLh+zUZYMCQtKiqazz0Q4Rre31f/OA== + dependencies: + "@types/yargs-parser" "*" + +acorn-walk@^8.1.1: + version "8.2.0" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1" + integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA== + +acorn@^8.4.1: + version "8.8.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.0.tgz#88c0187620435c7f6015803f5539dae05a9dbea8" + integrity sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w== + +ansi-escapes@^4.2.1: + version "4.3.2" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" + integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== + dependencies: + type-fest "^0.21.3" + +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +ansi-styles@^4.0.0, ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +ansi-styles@^5.0.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" + integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== + +anymatch@^3.0.3: + version "3.1.2" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" + integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +arg@^4.1.0: + version "4.1.3" + resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" + integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== + +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== + dependencies: + sprintf-js "~1.0.2" + +babel-jest@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-28.1.3.tgz#c1187258197c099072156a0a121c11ee1e3917d5" + integrity sha512-epUaPOEWMk3cWX0M/sPvCHHCe9fMFAa/9hXEgKP8nFfNl/jlGkE9ucq9NqkZGXLDduCJYS0UvSlPUwC0S+rH6Q== + dependencies: + "@jest/transform" "^28.1.3" + "@types/babel__core" "^7.1.14" + babel-plugin-istanbul "^6.1.1" + babel-preset-jest "^28.1.3" + chalk "^4.0.0" + graceful-fs "^4.2.9" + slash "^3.0.0" + +babel-plugin-istanbul@^6.1.1: + version "6.1.1" + resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz#fa88ec59232fd9b4e36dbbc540a8ec9a9b47da73" + integrity sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@istanbuljs/load-nyc-config" "^1.0.0" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-instrument "^5.0.4" + test-exclude "^6.0.0" + +babel-plugin-jest-hoist@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-28.1.3.tgz#1952c4d0ea50f2d6d794353762278d1d8cca3fbe" + integrity sha512-Ys3tUKAmfnkRUpPdpa98eYrAR0nV+sSFUZZEGuQ2EbFd1y4SOLtD5QDNHAq+bb9a+bbXvYQC4b+ID/THIMcU6Q== + dependencies: + "@babel/template" "^7.3.3" + "@babel/types" "^7.3.3" + "@types/babel__core" "^7.1.14" + "@types/babel__traverse" "^7.0.6" + +babel-preset-current-node-syntax@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz#b4399239b89b2a011f9ddbe3e4f401fc40cff73b" + integrity sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ== + dependencies: + "@babel/plugin-syntax-async-generators" "^7.8.4" + "@babel/plugin-syntax-bigint" "^7.8.3" + "@babel/plugin-syntax-class-properties" "^7.8.3" + "@babel/plugin-syntax-import-meta" "^7.8.3" + "@babel/plugin-syntax-json-strings" "^7.8.3" + "@babel/plugin-syntax-logical-assignment-operators" "^7.8.3" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + "@babel/plugin-syntax-numeric-separator" "^7.8.3" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + "@babel/plugin-syntax-top-level-await" "^7.8.3" + +babel-preset-jest@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-28.1.3.tgz#5dfc20b99abed5db994406c2b9ab94c73aaa419d" + integrity sha512-L+fupJvlWAHbQfn74coNX3zf60LXMJsezNvvx8eIh7iOR1luJ1poxYgQk1F8PYtNq/6QODDHCqsSnTFSWC491A== + dependencies: + babel-plugin-jest-hoist "^28.1.3" + babel-preset-current-node-syntax "^1.0.0" + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +base-x@^3.0.2: + version "3.0.9" + resolved "https://registry.yarnpkg.com/base-x/-/base-x-3.0.9.tgz#6349aaabb58526332de9f60995e548a53fe21320" + integrity sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ== + dependencies: + safe-buffer "^5.0.1" + +base64-js@^1.3.0: + version "1.5.1" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" + integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== + +bech32@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/bech32/-/bech32-2.0.0.tgz#078d3686535075c8c79709f054b1b226a133b355" + integrity sha512-LcknSilhIGatDAsY1ak2I8VtGaHNhgMSYVxFrGLXv+xLHytaKZKcaUJJUE7qmBr7h33o5YQwP55pMI0xmkpJwg== + +bech32@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/bech32/-/bech32-1.1.4.tgz#e38c9f37bf179b8eb16ae3a772b40c356d4832e9" + integrity sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ== + +bignumber.js@9.0.2: + version "9.0.2" + resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.0.2.tgz#71c6c6bed38de64e24a65ebe16cfcf23ae693673" + integrity sha512-GAcQvbpsM0pUb0zw1EI0KhQEZ+lRwR5fYaAp3vPOYuP7aDvGy6cVN6XHLauvF8SOga2y0dcLcjt3iQDTSEliyw== + +bindings@^1.3.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df" + integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ== + dependencies: + file-uri-to-path "1.0.0" + +bip32@2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/bip32/-/bip32-2.0.6.tgz#6a81d9f98c4cd57d05150c60d8f9e75121635134" + integrity sha512-HpV5OMLLGTjSVblmrtYRfFFKuQB+GArM0+XP8HGWfJ5vxYBqo+DesvJwOdC2WJ3bCkZShGf0QIfoIpeomVzVdA== + dependencies: + "@types/node" "10.12.18" + bs58check "^2.1.1" + create-hash "^1.2.0" + create-hmac "^1.1.7" + tiny-secp256k1 "^1.1.3" + typeforce "^1.11.5" + wif "^2.0.6" + +bip39@3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/bip39/-/bip39-3.0.4.tgz#5b11fed966840b5e1b8539f0f54ab6392969b2a0" + integrity sha512-YZKQlb752TrUWqHWj7XAwCSjYEgGAk+/Aas3V7NyjQeZYsztO8JnQUaCWhcnL4T+jL8nvB8typ2jRPzTlgugNw== + dependencies: + "@types/node" "11.11.6" + create-hash "^1.1.0" + pbkdf2 "^3.0.9" + randombytes "^2.0.1" + +bn.js@^4.11.8, bn.js@^4.11.9: + version "4.12.0" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" + integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== + +bn.js@^5.2.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.1.tgz#0bc527a6a0d18d0aa8d5b0538ce4a77dccfa7b70" + integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ== + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +braces@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + dependencies: + fill-range "^7.0.1" + +brorand@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" + integrity sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w== + +browser-headers@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/browser-headers/-/browser-headers-0.4.1.tgz#4308a7ad3b240f4203dbb45acedb38dc2d65dd02" + integrity sha512-CA9hsySZVo9371qEHjHZtYxV2cFtVj5Wj/ZHi8ooEsrtm4vOnl9Y9HmyYWk9q+05d7K3rdoAE0j3MVEFVvtQtg== + +browserslist@^4.20.2: + version "4.21.3" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.3.tgz#5df277694eb3c48bc5c4b05af3e8b7e09c5a6d1a" + integrity sha512-898rgRXLAyRkM1GryrrBHGkqA5hlpkV5MhtZwg9QXeiyLUYs2k00Un05aX5l2/yJIOObYKOpS2JNo8nJDE7fWQ== + dependencies: + caniuse-lite "^1.0.30001370" + electron-to-chromium "^1.4.202" + node-releases "^2.0.6" + update-browserslist-db "^1.0.5" + +bs-logger@0.x: + version "0.2.6" + resolved "https://registry.yarnpkg.com/bs-logger/-/bs-logger-0.2.6.tgz#eb7d365307a72cf974cc6cda76b68354ad336bd8" + integrity sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog== + dependencies: + fast-json-stable-stringify "2.x" + +bs58@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/bs58/-/bs58-4.0.1.tgz#be161e76c354f6f788ae4071f63f34e8c4f0a42a" + integrity sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw== + dependencies: + base-x "^3.0.2" + +bs58check@<3.0.0, bs58check@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/bs58check/-/bs58check-2.1.2.tgz#53b018291228d82a5aa08e7d796fdafda54aebfc" + integrity sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA== + dependencies: + bs58 "^4.0.0" + create-hash "^1.1.0" + safe-buffer "^5.1.2" + +bser@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05" + integrity sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ== + dependencies: + node-int64 "^0.4.0" + +buffer-from@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== + +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + +camelcase@^5.3.1: + version "5.3.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" + integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== + +camelcase@^6.2.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" + integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== + +caniuse-lite@^1.0.30001370: + version "1.0.30001381" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001381.tgz#e62955310e6e69cdf4b40bc5bc0895aa24bc4b8b" + integrity sha512-fEnkDOKpvp6qc+olg7+NzE1SqyfiyKf4uci7fAU38M3zxs0YOyKOxW/nMZ2l9sJbt7KZHcDIxUnbI0Iime7V4w== + +chalk@^2.0.0: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chalk@^4.0.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +char-regex@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" + integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== + +ci-info@^3.2.0: + version "3.3.2" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.3.2.tgz#6d2967ffa407466481c6c90b6e16b3098f080128" + integrity sha512-xmDt/QIAdeZ9+nfdPsaBCpMvHNLFiLdjj59qjqn+6iPe6YmHGQ35sBnQ8uslRBXFmXkiZQOJRjvQeoGppoTjjg== + +cipher-base@^1.0.1, cipher-base@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" + integrity sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q== + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +cjs-module-lexer@^1.0.0: + version "1.2.2" + resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz#9f84ba3244a512f3a54e5277e8eef4c489864e40" + integrity sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA== + +cliui@^7.0.2: + version "7.0.4" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" + integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.0" + wrap-ansi "^7.0.0" + +co@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + integrity sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ== + +collect-v8-coverage@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz#cc2c8e94fc18bbdffe64d6534570c8a673b27f59" + integrity sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg== + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + +convert-source-map@^1.4.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.8.0.tgz#f3373c32d21b4d780dd8004514684fb791ca4369" + integrity sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA== + dependencies: + safe-buffer "~5.1.1" + +create-hash@^1.1.0, create-hash@^1.1.2, create-hash@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" + integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg== + dependencies: + cipher-base "^1.0.1" + inherits "^2.0.1" + md5.js "^1.3.4" + ripemd160 "^2.0.1" + sha.js "^2.4.0" + +create-hmac@^1.1.4, create-hmac@^1.1.7: + version "1.1.7" + resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff" + integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg== + dependencies: + cipher-base "^1.0.3" + create-hash "^1.1.0" + inherits "^2.0.1" + ripemd160 "^2.0.0" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + +create-require@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" + integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== + +cross-spawn@^7.0.3: + version "7.0.3" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" + integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +curve25519-js@0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/curve25519-js/-/curve25519-js-0.0.4.tgz#e6ad967e8cd284590d657bbfc90d8b50e49ba060" + integrity sha512-axn2UMEnkhyDUPWOwVKBMVIzSQy2ejH2xRGy1wq81dqRwApXfIzfbE3hIX0ZRFBIihf/KDqK158DLwESu4AK1w== + +debug@^4.1.0, debug@^4.1.1: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + +dedent@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c" + integrity sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA== + +deepmerge@^4.2.2: + version "4.2.2" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955" + integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg== + +detect-newline@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" + integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== + +diff-sequences@^28.1.1: + version "28.1.1" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-28.1.1.tgz#9989dc731266dc2903457a70e996f3a041913ac6" + integrity sha512-FU0iFaH/E23a+a718l8Qa/19bF9p06kgE0KipMOMadwa3SjnaElKzPaUC0vnibs6/B/9ni97s61mcejk8W1fQw== + +diff@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" + integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== + +electron-to-chromium@^1.4.202: + version "1.4.225" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.225.tgz#3e27bdd157cbaf19768141f2e0f0f45071e52338" + integrity sha512-ICHvGaCIQR3P88uK8aRtx8gmejbVJyC6bB4LEC3anzBrIzdzC7aiZHY4iFfXhN4st6I7lMO0x4sgBHf/7kBvRw== + +elliptic@^6.4.0: + version "6.5.4" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb" + integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ== + dependencies: + bn.js "^4.11.9" + brorand "^1.1.0" + hash.js "^1.0.0" + hmac-drbg "^1.0.1" + inherits "^2.0.4" + minimalistic-assert "^1.0.1" + minimalistic-crypto-utils "^1.0.1" + +emittery@^0.10.2: + version "0.10.2" + resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.10.2.tgz#902eec8aedb8c41938c46e9385e9db7e03182933" + integrity sha512-aITqOwnLanpHLNXZJENbOgjUBeHocD+xsSJmNrjovKBW5HbSpW3d1pEls7GFQPUWXiwG9+0P4GtHfEqC/4M0Iw== + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +error-ex@^1.3.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" + integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== + dependencies: + is-arrayish "^0.2.1" + +escalade@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" + integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== + +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== + +escape-string-regexp@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" + integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== + +esprima@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + +execa@^5.0.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" + integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== + dependencies: + cross-spawn "^7.0.3" + get-stream "^6.0.0" + human-signals "^2.1.0" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^4.0.1" + onetime "^5.1.2" + signal-exit "^3.0.3" + strip-final-newline "^2.0.0" + +exit@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" + integrity sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ== + +expect@^28.0.0, expect@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/expect/-/expect-28.1.3.tgz#90a7c1a124f1824133dd4533cce2d2bdcb6603ec" + integrity sha512-eEh0xn8HlsuOBxFgIss+2mX85VAS4Qy3OSkjV7rlBWljtA4oWH37glVGyOZSZvErDT/yBywZdPGwCXuTvSG85g== + dependencies: + "@jest/expect-utils" "^28.1.3" + jest-get-type "^28.0.2" + jest-matcher-utils "^28.1.3" + jest-message-util "^28.1.3" + jest-util "^28.1.3" + +fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fb-watchman@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.1.tgz#fc84fb39d2709cf3ff6d743706157bb5708a8a85" + integrity sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg== + dependencies: + bser "2.1.1" + +file-uri-to-path@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" + integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== + +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== + dependencies: + to-regex-range "^5.0.1" + +find-up@^4.0.0, find-up@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" + integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== + dependencies: + locate-path "^5.0.0" + path-exists "^4.0.0" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + +fsevents@^2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" + integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== + +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + +gensync@^1.0.0-beta.2: + version "1.0.0-beta.2" + resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" + integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== + +get-caller-file@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + +get-package-type@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" + integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== + +get-stream@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" + integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== + +glob@^7.1.3, glob@^7.1.4: + version "7.2.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.1.1" + once "^1.3.0" + path-is-absolute "^1.0.0" + +globals@^11.1.0: + version "11.12.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== + +graceful-fs@^4.2.9: + version "4.2.10" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" + integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +has@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + +hash-base@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.1.0.tgz#55c381d9e06e1d2997a883b4a3fddfe7f0d3af33" + integrity sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA== + dependencies: + inherits "^2.0.4" + readable-stream "^3.6.0" + safe-buffer "^5.2.0" + +hash.js@^1.0.0, hash.js@^1.0.3: + version "1.1.7" + resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" + integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== + dependencies: + inherits "^2.0.3" + minimalistic-assert "^1.0.1" + +hmac-drbg@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" + integrity sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg== + dependencies: + hash.js "^1.0.3" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.1" + +html-escaper@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" + integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== + +human-signals@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" + integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== + +import-local@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.1.0.tgz#b4479df8a5fd44f6cdce24070675676063c95cb4" + integrity sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg== + dependencies: + pkg-dir "^4.2.0" + resolve-cwd "^3.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== + +is-core-module@^2.9.0: + version "2.10.0" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.10.0.tgz#9012ede0a91c69587e647514e1d5277019e728ed" + integrity sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg== + dependencies: + has "^1.0.3" + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-generator-fn@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" + integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== + +is-gzip@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-gzip/-/is-gzip-2.0.0.tgz#f4fed2bbd9f96bf2cb39e19262797fdb15aad933" + integrity sha512-jtO4Njg6q58zDo/Pu4027beSZ0VdsZlt8/5Moco6yAg+DIxb5BK/xUYqYG2+MD4+piKldXJNHxRkhEYI2fvrxA== + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-stream@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" + integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + +istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz#189e7909d0a39fa5a3dfad5b03f71947770191d3" + integrity sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw== + +istanbul-lib-instrument@^5.0.4, istanbul-lib-instrument@^5.1.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.0.tgz#31d18bdd127f825dd02ea7bfdfd906f8ab840e9f" + integrity sha512-6Lthe1hqXHBNsqvgDzGO6l03XNeu3CrG4RqQ1KM9+l5+jNGpEJfIELx1NS3SEHmJQA8np/u+E4EPRKRiu6m19A== + dependencies: + "@babel/core" "^7.12.3" + "@babel/parser" "^7.14.7" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-coverage "^3.2.0" + semver "^6.3.0" + +istanbul-lib-report@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#7518fe52ea44de372f460a76b5ecda9ffb73d8a6" + integrity sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw== + dependencies: + istanbul-lib-coverage "^3.0.0" + make-dir "^3.0.0" + supports-color "^7.1.0" + +istanbul-lib-source-maps@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz#895f3a709fcfba34c6de5a42939022f3e4358551" + integrity sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw== + dependencies: + debug "^4.1.1" + istanbul-lib-coverage "^3.0.0" + source-map "^0.6.1" + +istanbul-reports@^3.1.3: + version "3.1.5" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.5.tgz#cc9a6ab25cb25659810e4785ed9d9fb742578bae" + integrity sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w== + dependencies: + html-escaper "^2.0.0" + istanbul-lib-report "^3.0.0" + +jest-changed-files@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-28.1.3.tgz#d9aeee6792be3686c47cb988a8eaf82ff4238831" + integrity sha512-esaOfUWJXk2nfZt9SPyC8gA1kNfdKLkQWyzsMlqq8msYSlNKfmZxfRgZn4Cd4MGVUF+7v6dBs0d5TOAKa7iIiA== + dependencies: + execa "^5.0.0" + p-limit "^3.1.0" + +jest-circus@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-28.1.3.tgz#d14bd11cf8ee1a03d69902dc47b6bd4634ee00e4" + integrity sha512-cZ+eS5zc79MBwt+IhQhiEp0OeBddpc1n8MBo1nMB8A7oPMKEO+Sre+wHaLJexQUj9Ya/8NOBY0RESUgYjB6fow== + dependencies: + "@jest/environment" "^28.1.3" + "@jest/expect" "^28.1.3" + "@jest/test-result" "^28.1.3" + "@jest/types" "^28.1.3" + "@types/node" "*" + chalk "^4.0.0" + co "^4.6.0" + dedent "^0.7.0" + is-generator-fn "^2.0.0" + jest-each "^28.1.3" + jest-matcher-utils "^28.1.3" + jest-message-util "^28.1.3" + jest-runtime "^28.1.3" + jest-snapshot "^28.1.3" + jest-util "^28.1.3" + p-limit "^3.1.0" + pretty-format "^28.1.3" + slash "^3.0.0" + stack-utils "^2.0.3" + +jest-cli@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-28.1.3.tgz#558b33c577d06de55087b8448d373b9f654e46b2" + integrity sha512-roY3kvrv57Azn1yPgdTebPAXvdR2xfezaKKYzVxZ6It/5NCxzJym6tUI5P1zkdWhfUYkxEI9uZWcQdaFLo8mJQ== + dependencies: + "@jest/core" "^28.1.3" + "@jest/test-result" "^28.1.3" + "@jest/types" "^28.1.3" + chalk "^4.0.0" + exit "^0.1.2" + graceful-fs "^4.2.9" + import-local "^3.0.2" + jest-config "^28.1.3" + jest-util "^28.1.3" + jest-validate "^28.1.3" + prompts "^2.0.1" + yargs "^17.3.1" + +jest-config@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-28.1.3.tgz#e315e1f73df3cac31447eed8b8740a477392ec60" + integrity sha512-MG3INjByJ0J4AsNBm7T3hsuxKQqFIiRo/AUqb1q9LRKI5UU6Aar9JHbr9Ivn1TVwfUD9KirRoM/T6u8XlcQPHQ== + dependencies: + "@babel/core" "^7.11.6" + "@jest/test-sequencer" "^28.1.3" + "@jest/types" "^28.1.3" + babel-jest "^28.1.3" + chalk "^4.0.0" + ci-info "^3.2.0" + deepmerge "^4.2.2" + glob "^7.1.3" + graceful-fs "^4.2.9" + jest-circus "^28.1.3" + jest-environment-node "^28.1.3" + jest-get-type "^28.0.2" + jest-regex-util "^28.0.2" + jest-resolve "^28.1.3" + jest-runner "^28.1.3" + jest-util "^28.1.3" + jest-validate "^28.1.3" + micromatch "^4.0.4" + parse-json "^5.2.0" + pretty-format "^28.1.3" + slash "^3.0.0" + strip-json-comments "^3.1.1" + +jest-diff@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-28.1.3.tgz#948a192d86f4e7a64c5264ad4da4877133d8792f" + integrity sha512-8RqP1B/OXzjjTWkqMX67iqgwBVJRgCyKD3L9nq+6ZqJMdvjE8RgHktqZ6jNrkdMT+dJuYNI3rhQpxaz7drJHfw== + dependencies: + chalk "^4.0.0" + diff-sequences "^28.1.1" + jest-get-type "^28.0.2" + pretty-format "^28.1.3" + +jest-docblock@^28.1.1: + version "28.1.1" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-28.1.1.tgz#6f515c3bf841516d82ecd57a62eed9204c2f42a8" + integrity sha512-3wayBVNiOYx0cwAbl9rwm5kKFP8yHH3d/fkEaL02NPTkDojPtheGB7HZSFY4wzX+DxyrvhXz0KSCVksmCknCuA== + dependencies: + detect-newline "^3.0.0" + +jest-each@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-28.1.3.tgz#bdd1516edbe2b1f3569cfdad9acd543040028f81" + integrity sha512-arT1z4sg2yABU5uogObVPvSlSMQlDA48owx07BDPAiasW0yYpYHYOo4HHLz9q0BVzDVU4hILFjzJw0So9aCL/g== + dependencies: + "@jest/types" "^28.1.3" + chalk "^4.0.0" + jest-get-type "^28.0.2" + jest-util "^28.1.3" + pretty-format "^28.1.3" + +jest-environment-node@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-28.1.3.tgz#7e74fe40eb645b9d56c0c4b70ca4357faa349be5" + integrity sha512-ugP6XOhEpjAEhGYvp5Xj989ns5cB1K6ZdjBYuS30umT4CQEETaxSiPcZ/E1kFktX4GkrcM4qu07IIlDYX1gp+A== + dependencies: + "@jest/environment" "^28.1.3" + "@jest/fake-timers" "^28.1.3" + "@jest/types" "^28.1.3" + "@types/node" "*" + jest-mock "^28.1.3" + jest-util "^28.1.3" + +jest-get-type@^28.0.2: + version "28.0.2" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-28.0.2.tgz#34622e628e4fdcd793d46db8a242227901fcf203" + integrity sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA== + +jest-haste-map@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-28.1.3.tgz#abd5451129a38d9841049644f34b034308944e2b" + integrity sha512-3S+RQWDXccXDKSWnkHa/dPwt+2qwA8CJzR61w3FoYCvoo3Pn8tvGcysmMF0Bj0EX5RYvAI2EIvC57OmotfdtKA== + dependencies: + "@jest/types" "^28.1.3" + "@types/graceful-fs" "^4.1.3" + "@types/node" "*" + anymatch "^3.0.3" + fb-watchman "^2.0.0" + graceful-fs "^4.2.9" + jest-regex-util "^28.0.2" + jest-util "^28.1.3" + jest-worker "^28.1.3" + micromatch "^4.0.4" + walker "^1.0.8" + optionalDependencies: + fsevents "^2.3.2" + +jest-leak-detector@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-28.1.3.tgz#a6685d9b074be99e3adee816ce84fd30795e654d" + integrity sha512-WFVJhnQsiKtDEo5lG2mM0v40QWnBM+zMdHHyJs8AWZ7J0QZJS59MsyKeJHWhpBZBH32S48FOVvGyOFT1h0DlqA== + dependencies: + jest-get-type "^28.0.2" + pretty-format "^28.1.3" + +jest-matcher-utils@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-28.1.3.tgz#5a77f1c129dd5ba3b4d7fc20728806c78893146e" + integrity sha512-kQeJ7qHemKfbzKoGjHHrRKH6atgxMk8Enkk2iPQ3XwO6oE/KYD8lMYOziCkeSB9G4adPM4nR1DE8Tf5JeWH6Bw== + dependencies: + chalk "^4.0.0" + jest-diff "^28.1.3" + jest-get-type "^28.0.2" + pretty-format "^28.1.3" + +jest-message-util@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-28.1.3.tgz#232def7f2e333f1eecc90649b5b94b0055e7c43d" + integrity sha512-PFdn9Iewbt575zKPf1286Ht9EPoJmYT7P0kY+RibeYZ2XtOr53pDLEFoTWXbd1h4JiGiWpTBC84fc8xMXQMb7g== + dependencies: + "@babel/code-frame" "^7.12.13" + "@jest/types" "^28.1.3" + "@types/stack-utils" "^2.0.0" + chalk "^4.0.0" + graceful-fs "^4.2.9" + micromatch "^4.0.4" + pretty-format "^28.1.3" + slash "^3.0.0" + stack-utils "^2.0.3" + +jest-mock@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-28.1.3.tgz#d4e9b1fc838bea595c77ab73672ebf513ab249da" + integrity sha512-o3J2jr6dMMWYVH4Lh/NKmDXdosrsJgi4AviS8oXLujcjpCMBb1FMsblDnOXKZKfSiHLxYub1eS0IHuRXsio9eA== + dependencies: + "@jest/types" "^28.1.3" + "@types/node" "*" + +jest-pnp-resolver@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz#b704ac0ae028a89108a4d040b3f919dfddc8e33c" + integrity sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w== + +jest-regex-util@^28.0.2: + version "28.0.2" + resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-28.0.2.tgz#afdc377a3b25fb6e80825adcf76c854e5bf47ead" + integrity sha512-4s0IgyNIy0y9FK+cjoVYoxamT7Zeo7MhzqRGx7YDYmaQn1wucY9rotiGkBzzcMXTtjrCAP/f7f+E0F7+fxPNdw== + +jest-resolve-dependencies@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-28.1.3.tgz#8c65d7583460df7275c6ea2791901fa975c1fe66" + integrity sha512-qa0QO2Q0XzQoNPouMbCc7Bvtsem8eQgVPNkwn9LnS+R2n8DaVDPL/U1gngC0LTl1RYXJU0uJa2BMC2DbTfFrHA== + dependencies: + jest-regex-util "^28.0.2" + jest-snapshot "^28.1.3" + +jest-resolve@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-28.1.3.tgz#cfb36100341ddbb061ec781426b3c31eb51aa0a8" + integrity sha512-Z1W3tTjE6QaNI90qo/BJpfnvpxtaFTFw5CDgwpyE/Kz8U/06N1Hjf4ia9quUhCh39qIGWF1ZuxFiBiJQwSEYKQ== + dependencies: + chalk "^4.0.0" + graceful-fs "^4.2.9" + jest-haste-map "^28.1.3" + jest-pnp-resolver "^1.2.2" + jest-util "^28.1.3" + jest-validate "^28.1.3" + resolve "^1.20.0" + resolve.exports "^1.1.0" + slash "^3.0.0" + +jest-runner@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-28.1.3.tgz#5eee25febd730b4713a2cdfd76bdd5557840f9a1" + integrity sha512-GkMw4D/0USd62OVO0oEgjn23TM+YJa2U2Wu5zz9xsQB1MxWKDOlrnykPxnMsN0tnJllfLPinHTka61u0QhaxBA== + dependencies: + "@jest/console" "^28.1.3" + "@jest/environment" "^28.1.3" + "@jest/test-result" "^28.1.3" + "@jest/transform" "^28.1.3" + "@jest/types" "^28.1.3" + "@types/node" "*" + chalk "^4.0.0" + emittery "^0.10.2" + graceful-fs "^4.2.9" + jest-docblock "^28.1.1" + jest-environment-node "^28.1.3" + jest-haste-map "^28.1.3" + jest-leak-detector "^28.1.3" + jest-message-util "^28.1.3" + jest-resolve "^28.1.3" + jest-runtime "^28.1.3" + jest-util "^28.1.3" + jest-watcher "^28.1.3" + jest-worker "^28.1.3" + p-limit "^3.1.0" + source-map-support "0.5.13" + +jest-runtime@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-28.1.3.tgz#a57643458235aa53e8ec7821949e728960d0605f" + integrity sha512-NU+881ScBQQLc1JHG5eJGU7Ui3kLKrmwCPPtYsJtBykixrM2OhVQlpMmFWJjMyDfdkGgBMNjXCGB/ebzsgNGQw== + dependencies: + "@jest/environment" "^28.1.3" + "@jest/fake-timers" "^28.1.3" + "@jest/globals" "^28.1.3" + "@jest/source-map" "^28.1.2" + "@jest/test-result" "^28.1.3" + "@jest/transform" "^28.1.3" + "@jest/types" "^28.1.3" + chalk "^4.0.0" + cjs-module-lexer "^1.0.0" + collect-v8-coverage "^1.0.0" + execa "^5.0.0" + glob "^7.1.3" + graceful-fs "^4.2.9" + jest-haste-map "^28.1.3" + jest-message-util "^28.1.3" + jest-mock "^28.1.3" + jest-regex-util "^28.0.2" + jest-resolve "^28.1.3" + jest-snapshot "^28.1.3" + jest-util "^28.1.3" + slash "^3.0.0" + strip-bom "^4.0.0" + +jest-snapshot@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-28.1.3.tgz#17467b3ab8ddb81e2f605db05583d69388fc0668" + integrity sha512-4lzMgtiNlc3DU/8lZfmqxN3AYD6GGLbl+72rdBpXvcV+whX7mDrREzkPdp2RnmfIiWBg1YbuFSkXduF2JcafJg== + dependencies: + "@babel/core" "^7.11.6" + "@babel/generator" "^7.7.2" + "@babel/plugin-syntax-typescript" "^7.7.2" + "@babel/traverse" "^7.7.2" + "@babel/types" "^7.3.3" + "@jest/expect-utils" "^28.1.3" + "@jest/transform" "^28.1.3" + "@jest/types" "^28.1.3" + "@types/babel__traverse" "^7.0.6" + "@types/prettier" "^2.1.5" + babel-preset-current-node-syntax "^1.0.0" + chalk "^4.0.0" + expect "^28.1.3" + graceful-fs "^4.2.9" + jest-diff "^28.1.3" + jest-get-type "^28.0.2" + jest-haste-map "^28.1.3" + jest-matcher-utils "^28.1.3" + jest-message-util "^28.1.3" + jest-util "^28.1.3" + natural-compare "^1.4.0" + pretty-format "^28.1.3" + semver "^7.3.5" + +jest-util@^28.0.0, jest-util@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-28.1.3.tgz#f4f932aa0074f0679943220ff9cbba7e497028b0" + integrity sha512-XdqfpHwpcSRko/C35uLYFM2emRAltIIKZiJ9eAmhjsj0CqZMa0p1ib0R5fWIqGhn1a103DebTbpqIaP1qCQ6tQ== + dependencies: + "@jest/types" "^28.1.3" + "@types/node" "*" + chalk "^4.0.0" + ci-info "^3.2.0" + graceful-fs "^4.2.9" + picomatch "^2.2.3" + +jest-validate@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-28.1.3.tgz#e322267fd5e7c64cea4629612c357bbda96229df" + integrity sha512-SZbOGBWEsaTxBGCOpsRWlXlvNkvTkY0XxRfh7zYmvd8uL5Qzyg0CHAXiXKROflh801quA6+/DsT4ODDthOC/OA== + dependencies: + "@jest/types" "^28.1.3" + camelcase "^6.2.0" + chalk "^4.0.0" + jest-get-type "^28.0.2" + leven "^3.1.0" + pretty-format "^28.1.3" + +jest-watcher@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-28.1.3.tgz#c6023a59ba2255e3b4c57179fc94164b3e73abd4" + integrity sha512-t4qcqj9hze+jviFPUN3YAtAEeFnr/azITXQEMARf5cMwKY2SMBRnCQTXLixTl20OR6mLh9KLMrgVJgJISym+1g== + dependencies: + "@jest/test-result" "^28.1.3" + "@jest/types" "^28.1.3" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + emittery "^0.10.2" + jest-util "^28.1.3" + string-length "^4.0.1" + +jest-worker@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-28.1.3.tgz#7e3c4ce3fa23d1bb6accb169e7f396f98ed4bb98" + integrity sha512-CqRA220YV/6jCo8VWvAt1KKx6eek1VIHMPeLEbpcfSfkEeWyBNppynM/o6q+Wmw+sOhos2ml34wZbSX3G13//g== + dependencies: + "@types/node" "*" + merge-stream "^2.0.0" + supports-color "^8.0.0" + +jest@28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest/-/jest-28.1.3.tgz#e9c6a7eecdebe3548ca2b18894a50f45b36dfc6b" + integrity sha512-N4GT5on8UkZgH0O5LUavMRV1EDEhNTL0KEfRmDIeZHSV7p2XgLoY9t9VDUgL6o+yfdgYHVxuz81G8oB9VG5uyA== + dependencies: + "@jest/core" "^28.1.3" + "@jest/types" "^28.1.3" + import-local "^3.0.2" + jest-cli "^28.1.3" + +js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +js-yaml@^3.13.1: + version "3.14.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" + integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +jsesc@^2.5.1: + version "2.5.2" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" + integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== + +json-parse-even-better-errors@^2.3.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" + integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== + +json5@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.1.tgz#655d50ed1e6f95ad1a3caababd2b0efda10b395c" + integrity sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA== + +kleur@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" + integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== + +leven@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" + integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== + +lines-and-columns@^1.1.6: + version "1.2.4" + resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" + integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== + +locate-path@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" + integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== + dependencies: + p-locate "^4.1.0" + +lodash.memoize@4.x: + version "4.1.2" + resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" + integrity sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag== + +long@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/long/-/long-4.0.0.tgz#9a7b71cfb7d361a194ea555241c92f7468d5bf28" + integrity sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA== + +long@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/long/-/long-5.2.0.tgz#2696dadf4b4da2ce3f6f6b89186085d94d52fd61" + integrity sha512-9RTUNjK60eJbx3uz+TEGF7fUr29ZDxR5QzXcyDpeSfeH28S9ycINflOgOlppit5U+4kNTe83KQnMEerw7GmE8w== + +lru-cache@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" + integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== + dependencies: + yallist "^4.0.0" + +make-dir@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" + integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== + dependencies: + semver "^6.0.0" + +make-error@1.x, make-error@^1.1.1: + version "1.3.6" + resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" + integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== + +makeerror@1.0.12: + version "1.0.12" + resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.12.tgz#3e5dd2079a82e812e983cc6610c4a2cb0eaa801a" + integrity sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg== + dependencies: + tmpl "1.0.5" + +md5.js@^1.3.4: + version "1.3.5" + resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" + integrity sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg== + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + safe-buffer "^5.1.2" + +merge-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== + +micromatch@^4.0.4: + version "4.0.5" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" + integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== + dependencies: + braces "^3.0.2" + picomatch "^2.3.1" + +mimic-fn@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + +minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" + integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== + +minimalistic-crypto-utils@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" + integrity sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg== + +minimatch@^3.0.4, minimatch@^3.1.1: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +miscreant@0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/miscreant/-/miscreant-0.3.2.tgz#a91c046566cca70bd6b5e9fbdd3f67617fa85034" + integrity sha512-fL9KxsQz9BJB2KGPMHFrReioywkiomBiuaLk6EuChijK0BsJsIKJXdVomR+/bPj5mvbFD6wM0CM3bZio9g7OHA== + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +nan@^2.13.2: + version "2.16.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.16.0.tgz#664f43e45460fb98faf00edca0bb0d7b8dce7916" + integrity sha512-UdAqHyFngu7TfQKsCBgAA6pWDkT8MAO7d0jyOecVhN5354xbLqdn8mV9Tat9gepAupm0bt2DbeaSC8vS52MuFA== + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== + +node-int64@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" + integrity sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw== + +node-releases@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.6.tgz#8a7088c63a55e493845683ebf3c828d8c51c5503" + integrity sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg== + +normalize-path@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +npm-run-path@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" + integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== + dependencies: + path-key "^3.0.0" + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + +onetime@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" + integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== + dependencies: + mimic-fn "^2.1.0" + +p-limit@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== + dependencies: + p-try "^2.0.0" + +p-limit@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + +p-locate@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" + integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== + dependencies: + p-limit "^2.2.0" + +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + +pako@2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/pako/-/pako-2.0.4.tgz#6cebc4bbb0b6c73b0d5b8d7e8476e2b2fbea576d" + integrity sha512-v8tweI900AUkZN6heMU/4Uy4cXRc2AYNRggVmTR+dEncawDJgCdLMximOVA2p4qO57WMynangsfGRb5WD6L1Bg== + +parse-json@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" + integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== + dependencies: + "@babel/code-frame" "^7.0.0" + error-ex "^1.3.1" + json-parse-even-better-errors "^2.3.0" + lines-and-columns "^1.1.6" + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== + +path-key@^3.0.0, path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +path-parse@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +pbkdf2@^3.0.9: + version "3.1.2" + resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.1.2.tgz#dd822aa0887580e52f1a039dc3eda108efae3075" + integrity sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA== + dependencies: + create-hash "^1.1.2" + create-hmac "^1.1.4" + ripemd160 "^2.0.1" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + +picocolors@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" + integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== + +picomatch@^2.0.4, picomatch@^2.2.3, picomatch@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +pirates@^4.0.4: + version "4.0.5" + resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.5.tgz#feec352ea5c3268fb23a37c702ab1699f35a5f3b" + integrity sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ== + +pkg-dir@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" + integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== + dependencies: + find-up "^4.0.0" + +prettier@2.7.1: + version "2.7.1" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.7.1.tgz#e235806850d057f97bb08368a4f7d899f7760c64" + integrity sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g== + +pretty-format@^28.0.0, pretty-format@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-28.1.3.tgz#c9fba8cedf99ce50963a11b27d982a9ae90970d5" + integrity sha512-8gFb/To0OmxHR9+ZTb14Df2vNxdGCX8g1xWGUTqUw5TiZvcQf5sHKObd5UcPyLLyowNwDAMTF3XWOG1B6mxl1Q== + dependencies: + "@jest/schemas" "^28.1.3" + ansi-regex "^5.0.1" + ansi-styles "^5.0.0" + react-is "^18.0.0" + +prompts@^2.0.1: + version "2.4.2" + resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069" + integrity sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q== + dependencies: + kleur "^3.0.3" + sisteransi "^1.0.5" + +protobufjs@6.11.3, protobufjs@^6.11.3: + version "6.11.3" + resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-6.11.3.tgz#637a527205a35caa4f3e2a9a4a13ddffe0e7af74" + integrity sha512-xL96WDdCZYdU7Slin569tFX712BxsxslWwAfAhCYjQKGTq7dAU91Lomy6nLLhh/dyGhk/YH4TwTSRxTzhuHyZg== + dependencies: + "@protobufjs/aspromise" "^1.1.2" + "@protobufjs/base64" "^1.1.2" + "@protobufjs/codegen" "^2.0.4" + "@protobufjs/eventemitter" "^1.1.0" + "@protobufjs/fetch" "^1.1.0" + "@protobufjs/float" "^1.0.2" + "@protobufjs/inquire" "^1.1.0" + "@protobufjs/path" "^1.1.2" + "@protobufjs/pool" "^1.1.0" + "@protobufjs/utf8" "^1.1.0" + "@types/long" "^4.0.1" + "@types/node" ">=13.7.0" + long "^4.0.0" + +randombytes@^2.0.1: + version "2.1.0" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" + integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== + dependencies: + safe-buffer "^5.1.0" + +react-is@^18.0.0: + version "18.2.0" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b" + integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w== + +readable-stream@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" + integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +readonly-date@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/readonly-date/-/readonly-date-1.0.0.tgz#5af785464d8c7d7c40b9d738cbde8c646f97dcd9" + integrity sha512-tMKIV7hlk0h4mO3JTmmVuIlJVXjKk3Sep9Bf5OH0O+758ruuVkUy2J9SttDLm91IEX/WHlXPSpxMGjPj4beMIQ== + +regenerator-runtime@^0.13.4: + version "0.13.9" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52" + integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA== + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== + +resolve-cwd@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" + integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg== + dependencies: + resolve-from "^5.0.0" + +resolve-from@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" + integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== + +resolve.exports@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-1.1.0.tgz#5ce842b94b05146c0e03076985d1d0e7e48c90c9" + integrity sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ== + +resolve@^1.20.0: + version "1.22.1" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177" + integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw== + dependencies: + is-core-module "^2.9.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +rimraf@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + +ripemd160@^2.0.0, ripemd160@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" + integrity sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA== + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + +safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +secretjs@1.3.0-beta.23: + version "1.3.0-beta.23" + resolved "https://registry.yarnpkg.com/secretjs/-/secretjs-1.3.0-beta.23.tgz#b956d2479cc6b06c1fed3623ae19a8ba7c540f8a" + integrity sha512-zXL0t1h68it1+77+kobAq4JcIWV7EUtHfP2W2Vpc9MpAGLUeJ5XgfSNs6uO4IYq7viIEL7idTTls/7ljWBb8xw== + dependencies: + "@cosmjs/encoding" "0.27.1" + "@cosmjs/math" "0.27.1" + "@improbable-eng/grpc-web" "0.15.0" + "@improbable-eng/grpc-web-node-http-transport" "0.15.0" + "@noble/hashes" "1.0.0" + "@noble/secp256k1" "1.6.3" + "@osmonauts/helpers" "0.3.8" + bech32 "2.0.0" + bignumber.js "9.0.2" + bip32 "2.0.6" + bip39 "3.0.4" + curve25519-js "0.0.4" + is-gzip "2.0.0" + miscreant "0.3.2" + pako "2.0.4" + protobufjs "6.11.3" + secure-random "1.1.2" + +secure-random@1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/secure-random/-/secure-random-1.1.2.tgz#ed103b460a851632d420d46448b2a900a41e7f7c" + integrity sha512-H2bdSKERKdBV1SwoqYm6C0y+9EA94v6SUBOWO8kDndc4NoUih7Dv6Tsgma7zO1lv27wIvjlD0ZpMQk7um5dheQ== + +semver@7.x, semver@^7.3.5: + version "7.3.7" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.7.tgz#12c5b649afdbf9049707796e22a4028814ce523f" + integrity sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g== + dependencies: + lru-cache "^6.0.0" + +semver@^6.0.0, semver@^6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" + integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== + +sha.js@^2.4.0, sha.js@^2.4.8: + version "2.4.11" + resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" + integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ== + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +signal-exit@^3.0.3, signal-exit@^3.0.7: + version "3.0.7" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" + integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== + +sisteransi@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" + integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== + +slash@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== + +source-map-support@0.5.13: + version "0.5.13" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.13.tgz#31b24a9c2e73c2de85066c0feb7d44767ed52932" + integrity sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map@^0.6.0, source-map@^0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== + +stack-utils@^2.0.3: + version "2.0.5" + resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.5.tgz#d25265fca995154659dbbfba3b49254778d2fdd5" + integrity sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA== + dependencies: + escape-string-regexp "^2.0.0" + +string-length@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a" + integrity sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ== + dependencies: + char-regex "^1.0.2" + strip-ansi "^6.0.0" + +string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-bom@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878" + integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w== + +strip-final-newline@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" + integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== + +strip-json-comments@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +supports-color@^7.0.0, supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +supports-color@^8.0.0: + version "8.1.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + +supports-hyperlinks@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz#4f77b42488765891774b70c79babd87f9bd594bb" + integrity sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ== + dependencies: + has-flag "^4.0.0" + supports-color "^7.0.0" + +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== + +terminal-link@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/terminal-link/-/terminal-link-2.1.1.tgz#14a64a27ab3c0df933ea546fba55f2d078edc994" + integrity sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ== + dependencies: + ansi-escapes "^4.2.1" + supports-hyperlinks "^2.0.0" + +test-exclude@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" + integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w== + dependencies: + "@istanbuljs/schema" "^0.1.2" + glob "^7.1.4" + minimatch "^3.0.4" + +tiny-secp256k1@^1.1.3: + version "1.1.6" + resolved "https://registry.yarnpkg.com/tiny-secp256k1/-/tiny-secp256k1-1.1.6.tgz#7e224d2bee8ab8283f284e40e6b4acb74ffe047c" + integrity sha512-FmqJZGduTyvsr2cF3375fqGHUovSwDi/QytexX1Se4BPuPZpTE5Ftp5fg+EFSuEf3lhZqgCRjEG3ydUQ/aNiwA== + dependencies: + bindings "^1.3.0" + bn.js "^4.11.8" + create-hmac "^1.1.7" + elliptic "^6.4.0" + nan "^2.13.2" + +tmpl@1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" + integrity sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw== + +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +ts-jest@28.0.8: + version "28.0.8" + resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-28.0.8.tgz#cd204b8e7a2f78da32cf6c95c9a6165c5b99cc73" + integrity sha512-5FaG0lXmRPzApix8oFG8RKjAz4ehtm8yMKOTy5HX3fY6W8kmvOrmcY0hKDElW52FJov+clhUbrKAqofnj4mXTg== + dependencies: + bs-logger "0.x" + fast-json-stable-stringify "2.x" + jest-util "^28.0.0" + json5 "^2.2.1" + lodash.memoize "4.x" + make-error "1.x" + semver "7.x" + yargs-parser "^21.0.1" + +ts-node@10.9.1: + version "10.9.1" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.1.tgz#e73de9102958af9e1f0b168a6ff320e25adcff4b" + integrity sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw== + dependencies: + "@cspotcode/source-map-support" "^0.8.0" + "@tsconfig/node10" "^1.0.7" + "@tsconfig/node12" "^1.0.7" + "@tsconfig/node14" "^1.0.0" + "@tsconfig/node16" "^1.0.2" + acorn "^8.4.1" + acorn-walk "^8.1.1" + arg "^4.1.0" + create-require "^1.1.0" + diff "^4.0.1" + make-error "^1.1.1" + v8-compile-cache-lib "^3.0.1" + yn "3.1.1" + +type-detect@4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" + integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== + +type-fest@^0.21.3: + version "0.21.3" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" + integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== + +typeforce@^1.11.5: + version "1.18.0" + resolved "https://registry.yarnpkg.com/typeforce/-/typeforce-1.18.0.tgz#d7416a2c5845e085034d70fcc5b6cc4a90edbfdc" + integrity sha512-7uc1O8h1M1g0rArakJdf0uLRSSgFcYexrVoKo+bzJd32gd4gDy2L/Z+8/FjPnU9ydY3pEnVPtr9FyscYY60K1g== + +typescript@4.7.4: + version "4.7.4" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.7.4.tgz#1a88596d1cf47d59507a1bcdfb5b9dfe4d488235" + integrity sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ== + +update-browserslist-db@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.5.tgz#be06a5eedd62f107b7c19eb5bcefb194411abf38" + integrity sha512-dteFFpCyvuDdr9S/ff1ISkKt/9YZxKjI9WlRR99c180GaztJtRa/fn18FdxGVKVsnPY7/a/FDN68mcvUmP4U7Q== + dependencies: + escalade "^3.1.1" + picocolors "^1.0.0" + +util-deprecate@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== + +v8-compile-cache-lib@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" + integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== + +v8-to-istanbul@^9.0.1: + version "9.0.1" + resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-9.0.1.tgz#b6f994b0b5d4ef255e17a0d17dc444a9f5132fa4" + integrity sha512-74Y4LqY74kLE6IFyIjPtkSTWzUZmj8tdHT9Ii/26dvQ6K9Dl2NbEfj0XgU2sHCtKgt5VupqhlO/5aWuqS+IY1w== + dependencies: + "@jridgewell/trace-mapping" "^0.3.12" + "@types/istanbul-lib-coverage" "^2.0.1" + convert-source-map "^1.6.0" + +walker@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.8.tgz#bd498db477afe573dc04185f011d3ab8a8d7653f" + integrity sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ== + dependencies: + makeerror "1.0.12" + +which@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +wif@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/wif/-/wif-2.0.6.tgz#08d3f52056c66679299726fade0d432ae74b4704" + integrity sha512-HIanZn1zmduSF+BQhkE+YXIbEiH0xPr1012QbFEGB0xsKqJii0/SqJjyn8dFv6y36kOznMgMB+LGcbZTJ1xACQ== + dependencies: + bs58check "<3.0.0" + +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + +write-file-atomic@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-4.0.2.tgz#a9df01ae5b77858a027fd2e80768ee433555fcfd" + integrity sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg== + dependencies: + imurmurhash "^0.1.4" + signal-exit "^3.0.7" + +y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== + +yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== + +yargs-parser@^21.0.0, yargs-parser@^21.0.1: + version "21.1.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" + integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== + +yargs@^17.3.1: + version "17.5.1" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.5.1.tgz#e109900cab6fcb7fd44b1d8249166feb0b36e58e" + integrity sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA== + dependencies: + cliui "^7.0.2" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.3" + y18n "^5.0.5" + yargs-parser "^21.0.0" + +yn@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" + integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== diff --git a/proto/secret/compute/v1beta1/msg.proto b/proto/secret/compute/v1beta1/msg.proto index 417f7c2b1..c0f1f62f9 100644 --- a/proto/secret/compute/v1beta1/msg.proto +++ b/proto/secret/compute/v1beta1/msg.proto @@ -6,8 +6,16 @@ option go_package = "github.com/enigmampc/SecretNetwork/x/compute/internal/types import "gogoproto/gogo.proto"; import "cosmos/base/v1beta1/coin.proto"; -//import "x/compute/internal/types/types.proto"; +// Msg defines the wasm Msg service. +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. + rpc InstantiateContract(MsgInstantiateContract) returns (MsgInstantiateContractResponse); + // Execute submits the given message data to a smart contract + rpc ExecuteContract(MsgExecuteContract) returns (MsgExecuteContractResponse); +} message MsgStoreCode { option (gogoproto.goproto_getters) = false; @@ -19,8 +27,12 @@ message MsgStoreCode { string source = 3; // Builder is a valid docker image name with tag, optional string builder = 4; - // InstantiatePermission to apply on contract creation, optional -// AccessConfig InstantiatePermission = 5; +} + +// MsgStoreCodeResponse returns store result data. +message MsgStoreCodeResponse { + // CodeID is the reference to the stored WASM code + uint64 code_id = 1 [ (gogoproto.customname) = "CodeID" ]; } message MsgInstantiateContract { @@ -37,6 +49,14 @@ message MsgInstantiateContract { bytes callback_sig = 7 [(gogoproto.customname) = "CallbackSig"]; } +// 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 + bytes data = 2; +} + message MsgExecuteContract { option (gogoproto.goproto_getters) = false; @@ -48,70 +68,8 @@ message MsgExecuteContract { bytes callback_sig = 6 [(gogoproto.customname) = "CallbackSig"]; } -// Todo: keeping this here for future replacing of bytes -> string -//syntax = "proto3"; -//package secret.compute.v1beta1; -// -//option go_package = "github.com/enigmampc/SecretNetwork/x/compute/internal/types"; -// -//import "gogoproto/gogo.proto"; -//import "cosmos/base/v1beta1/coin.proto"; -// -////import "x/compute/internal/types/types.proto"; -// -// -//message MsgStoreCode { -// option (gogoproto.goproto_getters) = false; -// -// // -// string sender = 1 [(gogoproto.moretags) = "yaml:\"sender\""]; -// // WASMByteCode can be raw or gzip compressed -// bytes wasm_byte_code = 2 [(gogoproto.customname) = "WASMByteCode"]; -// // Source is a valid absolute HTTPS URI to the contract's source code, optional -// string source = 3 [(gogoproto.moretags) = "yaml:\"source\""]; -// // Builder is a valid docker image name with tag, optional -// string builder = 4 [(gogoproto.moretags) = "yaml:\"builder\""]; -//} -// -//message MsgInstantiateContract { -// option (gogoproto.goproto_getters) = false; -// -// // -// string sender = 1 [(gogoproto.moretags) = "yaml:\"sender\""]; -// // -// string callback_code_hash = 2 [(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"callback_code_hash\"" ]; -// // -// uint64 code_id = 3 [(gogoproto.customname) = "CodeID", (gogoproto.moretags) = "yaml:\"code_id\""]; -// // -// string label = 4 [(gogoproto.moretags) = "yaml:\"label\""]; -// // -// bytes init_msg = 5 [(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"init_msg\"" ]; -// // -// repeated cosmos.base.v1beta1.Coin init_funds = 6 [ -// (gogoproto.nullable) = false, -// (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins", -// (gogoproto.moretags) = "yaml:\"init_funds\"" -// ]; -// // -// bytes callback_sig = 7 [(gogoproto.customname) = "CallbackSig", (gogoproto.moretags) = "yaml:\"callback_sig\""]; -//} -// -//message MsgExecuteContract { -// option (gogoproto.goproto_getters) = false; -// // -// string sender = 1 [(gogoproto.moretags) = "yaml:\"sender\""]; -// // -// string contract = 2 [(gogoproto.moretags) = "yaml:\"contract\""]; -// // -// bytes msg = 3 [(gogoproto.moretags) = "yaml:\"msg\""]; -// // -// string callback_code_hash = 4 [(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"callback_code_hash\"" ]; -// // -// repeated cosmos.base.v1beta1.Coin sent_funds = 5 [ -// (gogoproto.nullable) = false, -// (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins", -// (gogoproto.moretags) = "yaml:\"sent_funds\"" -// ]; -// // -// bytes callback_sig = 6 [(gogoproto.customname) = "CallbackSig", (gogoproto.moretags) = "yaml:\"callback_sig\""]; -//} \ No newline at end of file +// MsgExecuteContractResponse returns execution result data. +message MsgExecuteContractResponse { + // Data contains base64-encoded bytes to returned from the contract + bytes data = 1; +} \ No newline at end of file diff --git a/x/compute/alias.go b/x/compute/alias.go index 857d93a70..ef4a5b04c 100644 --- a/x/compute/alias.go +++ b/x/compute/alias.go @@ -66,7 +66,7 @@ var ( EncodeStakingMsg = keeper.EncodeStakingMsg EncodeWasmMsg = keeper.EncodeWasmMsg NewKeeper = keeper.NewKeeper - NewQuerier = keeper.NewQuerier + NewQuerier = keeper.NewGrpcQuerier NewLegacyQuerier = keeper.NewLegacyQuerier DefaultQueryPlugins = keeper.DefaultQueryPlugins BankQuerier = keeper.BankQuerier @@ -116,7 +116,7 @@ type ( CreatedAt = types.AbsoluteTxPosition WasmConfig = types.WasmConfig CodeInfoResponse = types.CodeInfoResponse - MessageHandler = keeper.MessageHandler + MessageHandler = keeper.SDKMessageHandler BankEncoder = keeper.BankEncoder CustomEncoder = keeper.CustomEncoder StakingEncoder = keeper.StakingEncoder diff --git a/x/compute/client/cli/tx.go b/x/compute/client/cli/tx.go index 5df4d8528..2f07da7ab 100644 --- a/x/compute/client/cli/tx.go +++ b/x/compute/client/cli/tx.go @@ -31,7 +31,6 @@ const ( flagProposalType = "type" flagIoMasterKey = "enclave-key" flagCodeHash = "code-hash" - // flagAdmin = "admin" ) // GetTxCmd returns the transaction commands for this module @@ -47,10 +46,6 @@ func GetTxCmd() *cobra.Command { StoreCodeCmd(), InstantiateContractCmd(), ExecuteContractCmd(), - // Currently not supporting these commands - // MigrateContractCmd(cdc), - // UpdateContractAdminCmd(cdc), - // ClearContractAdminCmd(cdc), ) return txCmd } @@ -105,20 +100,6 @@ func parseStoreCodeArgs(args []string, cliCtx client.Context, flags *flag.FlagSe return types.MsgStoreCode{}, fmt.Errorf("invalid input file. Use wasm binary or gzip") } - /* - var perm *types.AccessConfig - if onlyAddrStr := viper.GetString(flagInstantiateByAddress); onlyAddrStr != "" { - allowedAddr, err := sdk.AccAddressFromBech32(onlyAddrStr) - if err != nil { - return types.MsgStoreCode{}, sdkerrors.Wrap(err, flagInstantiateByAddress) - } - x := types.OnlyAddress.With(allowedAddr) - perm = &x - } else if everybody := viper.GetBool(flagInstantiateByEverybody); everybody { - perm = &types.AllowEverybody - } - */ - source, err := flags.GetString(flagSource) if err != nil { return types.MsgStoreCode{}, fmt.Errorf("source: %s", err) @@ -134,7 +115,6 @@ func parseStoreCodeArgs(args []string, cliCtx client.Context, flags *flag.FlagSe WASMByteCode: wasm, Source: source, Builder: builder, - // InstantiatePermission: perm, } return msg, nil } @@ -142,7 +122,7 @@ func parseStoreCodeArgs(args []string, cliCtx client.Context, flags *flag.FlagSe // 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]", + Use: "instantiate [code_id_int64] [json_encoded_init_args] --label [text] --amount [coins,optional]", Short: "Instantiate a wasm contract", Args: cobra.ExactArgs(2), RunE: func(cmd *cobra.Command, args []string) error { diff --git a/x/compute/internal/keeper/gov_test.go b/x/compute/internal/keeper/gov_test.go index 05ffd17cd..9d8626200 100644 --- a/x/compute/internal/keeper/gov_test.go +++ b/x/compute/internal/keeper/gov_test.go @@ -104,8 +104,7 @@ func TestGovQueryProposals(t *testing.T) { // an active proposal and checking that there is 1 active func TestGovVote(t *testing.T) { encodingConfig := MakeEncodingConfig() - var transferPortSource wasmTypes.ICS20TransferPortSource - transferPortSource = MockIBCTransferKeeper{GetPortFn: func(ctx sdk.Context) string { + transferPortSource := MockIBCTransferKeeper{GetPortFn: func(ctx sdk.Context) string { return "myTransferPort" }} encoders := DefaultEncoders(transferPortSource, encodingConfig.Marshaler) diff --git a/x/compute/internal/keeper/handler_plugin.go b/x/compute/internal/keeper/handler_plugin.go index 31cdeacb8..66ac0b67c 100644 --- a/x/compute/internal/keeper/handler_plugin.go +++ b/x/compute/internal/keeper/handler_plugin.go @@ -6,6 +6,7 @@ import ( "fmt" codectypes "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/cosmos/cosmos-sdk/x/auth/legacy/legacytx" capabilitykeeper "github.com/cosmos/cosmos-sdk/x/capability/keeper" ibctransfertypes "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" ibcclienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" @@ -14,7 +15,6 @@ import ( host "github.com/cosmos/ibc-go/v3/modules/core/24-host" v1wasmTypes "github.com/enigmampc/SecretNetwork/go-cosmwasm/types/v1" - "github.com/cosmos/cosmos-sdk/x/auth/legacy/legacytx" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" @@ -34,15 +34,22 @@ type MessageHandlerChain struct { handlers []Messenger } -type MessageHandler struct { - router sdk.Router - encoders MessageEncoders +// SDKMessageHandler can handles messages that can be encoded into sdk.Message types and routed. +type SDKMessageHandler struct { + // router is used to route StargateMsg and any other msg except for MsgExecuteContract & MsgInstantiateContrat. + router MessageRouter + // legacyRouter is used to route MsgExecuteContract & MsgInstantiateContrat. + // the reason is those msgs use the data field internally for reply, which is + // truncated if the msg erred + legacyRouter sdk.Router + encoders MessageEncoders } -func NewSDKMessageHandler(router sdk.Router, encoders MessageEncoders) MessageHandler { - return MessageHandler{ - router: router, - encoders: encoders, +func NewSDKMessageHandler(router MessageRouter, legacyRouter sdk.Router, encoders MessageEncoders) SDKMessageHandler { + return SDKMessageHandler{ + router: router, + legacyRouter: legacyRouter, + encoders: encoders, } } @@ -67,7 +74,8 @@ func NewMessageHandlerChain(first Messenger, others ...Messenger) *MessageHandle } func NewMessageHandler( - router sdk.Router, + msgRouter MessageRouter, + legacyMsgRouter sdk.Router, customEncoders *MessageEncoders, channelKeeper channelkeeper.Keeper, capabilityKeeper capabilitykeeper.ScopedKeeper, @@ -76,7 +84,7 @@ func NewMessageHandler( ) Messenger { encoders := DefaultEncoders(portSource, unpacker).Merge(customEncoders) return NewMessageHandlerChain( - NewSDKMessageHandler(router, encoders), + NewSDKMessageHandler(msgRouter, legacyMsgRouter, encoders), NewIBCRawPacketHandler(channelKeeper, capabilityKeeper), ) } @@ -515,7 +523,7 @@ func EncodeWasmMsg(sender sdk.AccAddress, msg *v1wasmTypes.WasmMsg) ([]sdk.Msg, } } -func (h MessageHandler) DispatchMsg(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg v1wasmTypes.CosmosMsg, ogMessageVersion wasmTypes.CosmosMsgVersion) ([]sdk.Event, [][]byte, error) { +func (h SDKMessageHandler) DispatchMsg(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg v1wasmTypes.CosmosMsg, ogMessageVersion wasmTypes.CosmosMsgVersion) ([]sdk.Event, [][]byte, error) { sdkMsgs, err := h.encoders.Encode(ctx, contractAddr, contractIBCPortID, msg) if err != nil { return nil, nil, err @@ -526,81 +534,70 @@ func (h MessageHandler) DispatchMsg(ctx sdk.Context, contractAddr sdk.AccAddress data [][]byte ) for _, sdkMsg := range sdkMsgs { - sdkEvents, sdkData, err := h.handleSdkMessage(ctx, contractAddr, sdkMsg) + res, err := h.handleSdkMessage(ctx, contractAddr, sdkMsg) if err != nil { - data = append(data, sdkData) + if res != nil { + data = append(data, res.Data) + } return nil, data, err } // append data - data = append(data, sdkData) + data = append(data, res.Data) + + // append events + sdkEvents := make([]sdk.Event, len(res.Events)) + for i := range res.Events { + sdkEvents[i] = sdk.Event(res.Events[i]) + } events = append(events, sdkEvents...) } return events, data, nil - - // return nil, nil, sdkerrors.Wrap(types.ErrInvalidMsg, "Unknown variant of CosmosMsgVersion") } -func (h MessageHandler) handleSdkMessage(ctx sdk.Context, contractAddr sdk.Address, msg sdk.Msg) (sdk.Events, []byte, error) { +func (h SDKMessageHandler) handleSdkMessage(ctx sdk.Context, contractAddr sdk.Address, msg sdk.Msg) (*sdk.Result, error) { if err := msg.ValidateBasic(); err != nil { - return nil, nil, err + return nil, err } - // make sure this account can send it + // make sure the contract account is also the "signer" on the message for _, acct := range msg.GetSigners() { if !acct.Equals(contractAddr) { - return nil, nil, sdkerrors.Wrap(sdkerrors.ErrUnauthorized, "contract doesn't have permission") + return nil, sdkerrors.Wrap(sdkerrors.ErrUnauthorized, "contract doesn't have permission") } } - var res *sdk.Result - var err error - if legacyMsg, ok := msg.(legacytx.LegacyMsg); ok { - msgRoute := legacyMsg.Route() - handler := h.router.Route(ctx, msgRoute) - if handler == nil { - return nil, nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized message route: %s", msgRoute) - } + _, isMsgInitContract := msg.(*types.MsgInstantiateContract) + _, isMsgExecContract := msg.(*types.MsgExecuteContract) - res, err = handler(ctx, msg) - if err != nil { - var errData []byte - errData = nil - if res != nil { - errData = make([]byte, len(res.Data)) - copy(errData, res.Data) + if isMsgInitContract || isMsgExecContract { + // legacyMsgRouter logic (CosmWasm v0.10) + if legacyMsg, ok := msg.(legacytx.LegacyMsg); ok { + msgRoute := legacyMsg.Route() + handler := h.legacyRouter.Route(ctx, msgRoute) + if handler == nil { + return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "can't route message %+v", msg) } - return nil, errData, err + return handler(ctx, msg) + } else { + return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized legacy message route: %s", sdk.MsgTypeURL(msg)) } - } else { - return nil, nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized legacy message route: %s", sdk.MsgTypeURL(msg)) - - // todo: grpc routing - // handler := k.serviceRouter.Handler(msg) - // if handler == nil { - // return nil, nil, sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, sdk.MsgTypeURL(msg)) - //} - // res, err := handler(ctx, msg) - // if err != nil { - // return nil, nil, err - //} } - var events []sdk.Event - data := make([]byte, len(res.Data)) - copy(data, res.Data) - // - // convert Tendermint.Events to sdk.Event - sdkEvents := make(sdk.Events, len(res.Events)) - for i := range res.Events { - sdkEvents[i] = sdk.Event(res.Events[i]) - } + // msgRouter logic (CosmWasm v1) - // append message action attribute - events = append(events, sdkEvents...) + // find the handler and execute it + if handler := h.router.Handler(msg); handler != nil { + // ADR 031 request type routing + return handler(ctx, msg) + } - return events, data, nil + // Assuming that the app developer has migrated all their Msgs to + // proto messages and has registered all `Msg services`, then this + // path should never be called, because all those Msgs should be + // registered within the `msgServiceRouter` already. + return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "can't route message %+v", msg) } // convertWasmIBCTimeoutHeightToCosmosHeight converts a wasm type ibc timeout height to ibc module type height diff --git a/x/compute/internal/keeper/ibc.go b/x/compute/internal/keeper/ibc.go index 8df6fdecc..900927b82 100644 --- a/x/compute/internal/keeper/ibc.go +++ b/x/compute/internal/keeper/ibc.go @@ -37,3 +37,8 @@ func PortIDForContract(addr sdk.AccAddress) string { func (k Keeper) ClaimCapability(ctx sdk.Context, cap *capabilitytypes.Capability, name string) error { return k.capabilityKeeper.ClaimCapability(ctx, cap, name) } + +// AuthenticateCapability wraps the scopedKeeper's AuthenticateCapability function +func (k Keeper) AuthenticateCapability(ctx sdk.Context, cap *capabilitytypes.Capability, name string) bool { + return k.capabilityKeeper.AuthenticateCapability(ctx, cap, name) +} diff --git a/x/compute/internal/keeper/ibc_test.go b/x/compute/internal/keeper/ibc_test.go new file mode 100644 index 000000000..13548318a --- /dev/null +++ b/x/compute/internal/keeper/ibc_test.go @@ -0,0 +1,1102 @@ +package keeper + +import ( + "encoding/binary" + "encoding/hex" + "encoding/json" + "fmt" + "math" + "os" + "testing" + + crypto "github.com/cosmos/cosmos-sdk/crypto/types" + sdk "github.com/cosmos/cosmos-sdk/types" + cosmwasm "github.com/enigmampc/SecretNetwork/go-cosmwasm/types" + v010cosmwasm "github.com/enigmampc/SecretNetwork/go-cosmwasm/types/v010" + v1types "github.com/enigmampc/SecretNetwork/go-cosmwasm/types/v1" + "github.com/enigmampc/SecretNetwork/x/compute/internal/types" + "github.com/stretchr/testify/require" + "github.com/tendermint/tendermint/libs/log" +) + +func ibcChannelConnectHelper( + t *testing.T, keeper Keeper, ctx sdk.Context, + contractAddr sdk.AccAddress, creatorPrivKey crypto.PrivKey, + gas uint64, shouldSendOpenAck bool, channel v1types.IBCChannel, +) (sdk.Context, []ContractEvent, cosmwasm.StdError) { + // create new ctx with the same storage and a gas limit + // this is to reset the event manager, so we won't get + // events from past calls + gasMeter := &WasmCounterGasMeter{0, sdk.NewGasMeter(gas)} + ctx = sdk.NewContext( + ctx.MultiStore(), + ctx.BlockHeader(), + ctx.IsCheckTx(), + log.NewNopLogger(), + ).WithGasMeter(gasMeter) + + var ibcChannelConnectMsg v1types.IBCChannelConnectMsg + if shouldSendOpenAck { + ibcChannelConnectMsg = v1types.IBCChannelConnectMsg{ + OpenAck: &v1types.IBCOpenAck{ + Channel: channel, + CounterpartyVersion: "", + }, + OpenConfirm: nil, + } + } else { + ibcChannelConnectMsg = v1types.IBCChannelConnectMsg{ + OpenAck: nil, + OpenConfirm: &v1types.IBCOpenConfirm{ + Channel: channel, + }, + } + } + + err := keeper.OnConnectChannel(ctx, contractAddr, ibcChannelConnectMsg) + + require.NotZero(t, gasMeter.GetWasmCounter(), err) + + if err != nil { + return ctx, nil, cosmwasm.StdError{GenericErr: &cosmwasm.GenericErr{Msg: err.Error()}} + } + + // wasmEvents comes from all the callbacks as well + wasmEvents := tryDecryptWasmEvents(ctx, []byte{}, true) + + return ctx, wasmEvents, cosmwasm.StdError{} +} + +func ibcChannelOpenHelper( + t *testing.T, keeper Keeper, ctx sdk.Context, + contractAddr sdk.AccAddress, creatorPrivKey crypto.PrivKey, + gas uint64, shouldSendOpenTry bool, channel v1types.IBCChannel, +) (string, cosmwasm.StdError) { + // create new ctx with the same storage and a gas limit + // this is to reset the event manager, so we won't get + // events from past calls + gasMeter := &WasmCounterGasMeter{0, sdk.NewGasMeter(gas)} + ctx = sdk.NewContext( + ctx.MultiStore(), + ctx.BlockHeader(), + ctx.IsCheckTx(), + log.NewNopLogger(), + ).WithGasMeter(gasMeter) + + var ibcChannelOpenMsg v1types.IBCChannelOpenMsg + if shouldSendOpenTry { + ibcChannelOpenMsg = v1types.IBCChannelOpenMsg{ + OpenTry: &v1types.IBCOpenTry{ + Channel: channel, + CounterpartyVersion: "", + }, + OpenInit: nil, + } + } else { + ibcChannelOpenMsg = v1types.IBCChannelOpenMsg{ + OpenTry: nil, + OpenInit: &v1types.IBCOpenInit{ + Channel: channel, + }, + } + } + + res, err := keeper.OnOpenChannel(ctx, contractAddr, ibcChannelOpenMsg) + + require.NotZero(t, gasMeter.GetWasmCounter(), err) + + if err != nil { + return "", cosmwasm.StdError{GenericErr: &cosmwasm.GenericErr{Msg: err.Error()}} + } + + return res, cosmwasm.StdError{} +} + +func ibcChannelCloseHelper( + t *testing.T, keeper Keeper, ctx sdk.Context, + contractAddr sdk.AccAddress, creatorPrivKey crypto.PrivKey, + gas uint64, shouldSendCloseConfirn bool, channel v1types.IBCChannel, +) (sdk.Context, []ContractEvent, cosmwasm.StdError) { + // create new ctx with the same storage and a gas limit + // this is to reset the event manager, so we won't get + // events from past calls + gasMeter := &WasmCounterGasMeter{0, sdk.NewGasMeter(gas)} + ctx = sdk.NewContext( + ctx.MultiStore(), + ctx.BlockHeader(), + ctx.IsCheckTx(), + log.NewNopLogger(), + ).WithGasMeter(gasMeter) + + var ibcChannelCloseMsg v1types.IBCChannelCloseMsg + if shouldSendCloseConfirn { + ibcChannelCloseMsg = v1types.IBCChannelCloseMsg{ + CloseConfirm: &v1types.IBCCloseConfirm{ + Channel: channel, + }, + CloseInit: nil, + } + } else { + ibcChannelCloseMsg = v1types.IBCChannelCloseMsg{ + CloseConfirm: nil, + CloseInit: &v1types.IBCCloseInit{ + Channel: channel, + }, + } + } + + err := keeper.OnCloseChannel(ctx, contractAddr, ibcChannelCloseMsg) + + require.NotZero(t, gasMeter.GetWasmCounter(), err) + + if err != nil { + return ctx, nil, cosmwasm.StdError{GenericErr: &cosmwasm.GenericErr{Msg: err.Error()}} + } + + // wasmEvents comes from all the callbacks as well + wasmEvents := tryDecryptWasmEvents(ctx, []byte{}, true) + + return ctx, wasmEvents, cosmwasm.StdError{} +} + +func createIBCEndpoint(port string, channel string) v1types.IBCEndpoint { + return v1types.IBCEndpoint{ + PortID: port, + ChannelID: channel, + } +} + +func createIBCTimeout(timeout uint64) v1types.IBCTimeout { + return v1types.IBCTimeout{ + Block: nil, + Timestamp: timeout, + } +} + +func createIBCPacket(src v1types.IBCEndpoint, dest v1types.IBCEndpoint, sequence uint64, timeout v1types.IBCTimeout, data []byte) v1types.IBCPacket { + return v1types.IBCPacket{ + Data: data, + Src: src, + Dest: dest, + Sequence: sequence, + Timeout: timeout, + } +} + +func ibcPacketReceiveHelper( + t *testing.T, keeper Keeper, ctx sdk.Context, + contractAddr sdk.AccAddress, creatorPrivKey crypto.PrivKey, + shouldEncryptMsg bool, gas uint64, packet v1types.IBCPacket, +) (sdk.Context, []byte, []ContractEvent, []byte, cosmwasm.StdError) { + var nonce []byte + internalPacket := packet + + if shouldEncryptMsg { + contractHash, err := keeper.GetContractHash(ctx, contractAddr) + require.NoError(t, err) + hashStr := hex.EncodeToString(contractHash) + + msg := types.SecretMsg{ + CodeHash: []byte(hashStr), + Msg: packet.Data, + } + + dataBz, err := wasmCtx.Encrypt(msg.Serialize()) + require.NoError(t, err) + nonce = dataBz[0:32] + internalPacket.Data = dataBz + } + + // create new ctx with the same storage and a gas limit + // this is to reset the event manager, so we won't get + // events from past calls + gasMeter := &WasmCounterGasMeter{0, sdk.NewGasMeter(gas)} + ctx = sdk.NewContext( + ctx.MultiStore(), + ctx.BlockHeader(), + ctx.IsCheckTx(), + log.NewNopLogger(), + ).WithGasMeter(gasMeter) + + ibcPacketReceiveMsg := v1types.IBCPacketReceiveMsg{ + Packet: internalPacket, + Relayer: "relayer", + } + + res, err := keeper.OnRecvPacket(ctx, contractAddr, ibcPacketReceiveMsg) + + require.NotZero(t, gasMeter.GetWasmCounter(), err) + + // wasmEvents comes from all the callbacks as well + wasmEvents := tryDecryptWasmEvents(ctx, nonce, !shouldEncryptMsg) + + if err != nil { + if shouldEncryptMsg { + return ctx, nil, nil, nil, extractInnerError(t, err, nonce, true, true) + } + + return ctx, nil, nil, nil, cosmwasm.StdError{GenericErr: &cosmwasm.GenericErr{Msg: err.Error()}} + } + + data := res + if shouldEncryptMsg { + data = getDecryptedData(t, res, nonce) + } + + return ctx, nonce, wasmEvents, data, cosmwasm.StdError{} +} + +func ibcPacketAckHelper( + t *testing.T, keeper Keeper, ctx sdk.Context, + contractAddr sdk.AccAddress, creatorPrivKey crypto.PrivKey, gas uint64, originalPacket v1types.IBCPacket, ack []byte, +) (sdk.Context, []ContractEvent, cosmwasm.StdError) { + // create new ctx with the same storage and a gas limit + // this is to reset the event manager, so we won't get + // events from past calls + gasMeter := &WasmCounterGasMeter{0, sdk.NewGasMeter(gas)} + ctx = sdk.NewContext( + ctx.MultiStore(), + ctx.BlockHeader(), + ctx.IsCheckTx(), + log.NewNopLogger(), + ).WithGasMeter(gasMeter) + + ibcPacketAckMsg := v1types.IBCPacketAckMsg{ + Acknowledgement: v1types.IBCAcknowledgement{ + Data: ack, + }, + OriginalPacket: originalPacket, + Relayer: "relayer", + } + + err := keeper.OnAckPacket(ctx, contractAddr, ibcPacketAckMsg) + + require.NotZero(t, gasMeter.GetWasmCounter(), err) + + if err != nil { + return ctx, nil, cosmwasm.StdError{GenericErr: &cosmwasm.GenericErr{Msg: err.Error()}} + } + + // wasmEvents comes from all the callbacks as well + wasmEvents := tryDecryptWasmEvents(ctx, []byte{}, true) + + return ctx, wasmEvents, cosmwasm.StdError{} +} + +func ibcPacketTimeoutHelper( + t *testing.T, keeper Keeper, ctx sdk.Context, + contractAddr sdk.AccAddress, creatorPrivKey crypto.PrivKey, gas uint64, originalPacket v1types.IBCPacket, +) (sdk.Context, []ContractEvent, cosmwasm.StdError) { + // create new ctx with the same storage and a gas limit + // this is to reset the event manager, so we won't get + // events from past calls + gasMeter := &WasmCounterGasMeter{0, sdk.NewGasMeter(gas)} + ctx = sdk.NewContext( + ctx.MultiStore(), + ctx.BlockHeader(), + ctx.IsCheckTx(), + log.NewNopLogger(), + ).WithGasMeter(gasMeter) + + ibcPacketTimeoutMsg := v1types.IBCPacketTimeoutMsg{ + Packet: originalPacket, + Relayer: "relayer", + } + + err := keeper.OnTimeoutPacket(ctx, contractAddr, ibcPacketTimeoutMsg) + + require.NotZero(t, gasMeter.GetWasmCounter(), err) + + if err != nil { + return ctx, nil, cosmwasm.StdError{GenericErr: &cosmwasm.GenericErr{Msg: err.Error()}} + } + + // wasmEvents comes from all the callbacks as well + wasmEvents := tryDecryptWasmEvents(ctx, []byte{}, true) + + return ctx, wasmEvents, cosmwasm.StdError{} +} + +func TestIBCChannelOpen(t *testing.T) { + ctx, keeper, codeID, _, walletA, privKeyA, _, _ := setupTest(t, "./testdata/ibc/contract.wasm", sdk.NewCoins()) + + _, _, contractAddress, _, err := initHelper(t, keeper, ctx, codeID, walletA, privKeyA, `{"init":{}}`, true, true, defaultGasForTests) + require.Empty(t, err) + + ibcChannel := v1types.IBCChannel{ + Endpoint: createIBCEndpoint(PortIDForContract(contractAddress), "channel.0"), + CounterpartyEndpoint: createIBCEndpoint(PortIDForContract(contractAddress), "channel.1"), + Order: v1types.Unordered, + Version: "1", + ConnectionID: "1", + } + + version, err := ibcChannelOpenHelper(t, keeper, ctx, contractAddress, privKeyA, defaultGasForTests, false, ibcChannel) + require.Empty(t, err) + require.Equal(t, version, "ibc-v1") + + queryRes, err := queryHelper(t, keeper, ctx, contractAddress, `{"q":{}}`, true, true, math.MaxUint64) + require.Empty(t, err) + + require.Equal(t, "1", queryRes) +} + +func TestIBCChannelOpenTry(t *testing.T) { + ctx, keeper, codeID, _, walletA, privKeyA, _, _ := setupTest(t, "./testdata/ibc/contract.wasm", sdk.NewCoins()) + + _, _, contractAddress, _, err := initHelper(t, keeper, ctx, codeID, walletA, privKeyA, `{"init":{}}`, true, true, defaultGasForTests) + require.Empty(t, err) + + ibcChannel := v1types.IBCChannel{ + Endpoint: createIBCEndpoint(PortIDForContract(contractAddress), "channel.0"), + CounterpartyEndpoint: createIBCEndpoint(PortIDForContract(contractAddress), "channel.1"), + Order: v1types.Unordered, + Version: "1", + ConnectionID: "1", + } + + version, err := ibcChannelOpenHelper(t, keeper, ctx, contractAddress, privKeyA, defaultGasForTests, true, ibcChannel) + require.Empty(t, err) + require.Equal(t, version, "ibc-v1") + + queryRes, err := queryHelper(t, keeper, ctx, contractAddress, `{"q":{}}`, true, true, math.MaxUint64) + require.Empty(t, err) + + require.Equal(t, "2", queryRes) +} + +func TestIBCChannelConnect(t *testing.T) { + ctx, keeper, codeID, _, walletA, privKeyA, _, _ := setupTest(t, "./testdata/ibc/contract.wasm", sdk.NewCoins()) + + _, _, contractAddress, _, err := initHelper(t, keeper, ctx, codeID, walletA, privKeyA, `{"init":{}}`, true, true, defaultGasForTests) + require.Empty(t, err) + + for _, test := range []struct { + description string + connectionID string + output string + isSuccess bool + hasAttributes bool + hasEvents bool + }{ + { + description: "Default", + connectionID: "0", + output: "4", + isSuccess: true, + hasAttributes: false, + hasEvents: false, + }, + { + description: "SubmessageNoReply", + connectionID: "1", + output: "10", + isSuccess: true, + hasAttributes: false, + hasEvents: false, + }, + { + description: "SubmessageWithReply", + connectionID: "2", + output: "17", + isSuccess: true, + hasAttributes: false, + hasEvents: false, + }, + { + description: "Attributes", + connectionID: "3", + output: "7", + isSuccess: true, + hasAttributes: true, + hasEvents: false, + }, + { + description: "Events", + connectionID: "4", + output: "8", + isSuccess: true, + hasAttributes: false, + hasEvents: true, + }, + { + description: "Error", + connectionID: "5", + output: "", + isSuccess: false, + hasAttributes: false, + hasEvents: false, + }, + } { + t.Run(test.description, func(t *testing.T) { + ibcChannel := v1types.IBCChannel{ + Endpoint: createIBCEndpoint(PortIDForContract(contractAddress), "channel.0"), + CounterpartyEndpoint: createIBCEndpoint(PortIDForContract(contractAddress), "channel.1"), + Order: v1types.Unordered, + Version: "1", + ConnectionID: test.connectionID, + } + + ctx, events, err := ibcChannelConnectHelper(t, keeper, ctx, contractAddress, privKeyA, defaultGasForTests, false, ibcChannel) + + if !test.isSuccess { + require.Contains(t, fmt.Sprintf("%+v", err), "Intentional") + } else { + require.Empty(t, err) + if test.hasAttributes { + require.Equal(t, + []ContractEvent{ + { + {Key: "contract_address", Value: contractAddress.String()}, + {Key: "attr1", Value: "😗"}, + }, + }, + events, + ) + } + + if test.hasEvents { + hadCyber1 := false + evts := ctx.EventManager().Events() + for _, e := range evts { + if e.Type == "wasm-cyber1" { + require.False(t, hadCyber1) + attrs, err := parseAndDecryptAttributes(e.Attributes, []byte{}, false) + require.Empty(t, err) + + require.Equal(t, + []v010cosmwasm.LogAttribute{ + {Key: "contract_address", Value: contractAddress.String()}, + {Key: "attr1", Value: "🤯"}, + }, + attrs, + ) + + hadCyber1 = true + } + } + + require.True(t, hadCyber1) + } + + queryRes, err := queryHelper(t, keeper, ctx, contractAddress, `{"q":{}}`, true, true, math.MaxUint64) + + require.Empty(t, err) + + require.Equal(t, test.output, queryRes) + } + }) + } +} + +func TestIBCChannelConnectOpenAck(t *testing.T) { + ctx, keeper, codeID, _, walletA, privKeyA, _, _ := setupTest(t, "./testdata/ibc/contract.wasm", sdk.NewCoins()) + + _, _, contractAddress, _, err := initHelper(t, keeper, ctx, codeID, walletA, privKeyA, `{"init":{}}`, true, true, defaultGasForTests) + require.Empty(t, err) + + ibcChannel := v1types.IBCChannel{ + Endpoint: createIBCEndpoint(PortIDForContract(contractAddress), "channel.0"), + CounterpartyEndpoint: createIBCEndpoint(PortIDForContract(contractAddress), "channel.1"), + Order: v1types.Unordered, + Version: "1", + ConnectionID: "1", + } + + ctx, _, err = ibcChannelConnectHelper(t, keeper, ctx, contractAddress, privKeyA, defaultGasForTests, true, ibcChannel) + require.Empty(t, err) + + queryRes, err := queryHelper(t, keeper, ctx, contractAddress, `{"q":{}}`, true, true, math.MaxUint64) + require.Empty(t, err) + + require.Equal(t, "3", queryRes) +} + +func TestIBCChannelClose(t *testing.T) { + ctx, keeper, codeID, _, walletA, privKeyA, _, _ := setupTest(t, "./testdata/ibc/contract.wasm", sdk.NewCoins()) + + _, _, contractAddress, _, err := initHelper(t, keeper, ctx, codeID, walletA, privKeyA, `{"init":{}}`, true, true, defaultGasForTests) + require.Empty(t, err) + + for _, test := range []struct { + description string + connectionID string + output string + isSuccess bool + hasAttributes bool + hasEvents bool + }{ + { + description: "Default", + connectionID: "0", + output: "6", + isSuccess: true, + hasAttributes: false, + hasEvents: false, + }, + { + description: "SubmessageNoReply", + connectionID: "1", + output: "12", + isSuccess: true, + hasAttributes: false, + hasEvents: false, + }, + { + description: "SubmessageWithReply", + connectionID: "2", + output: "19", + isSuccess: true, + hasAttributes: false, + hasEvents: false, + }, + { + description: "Attributes", + connectionID: "3", + output: "9", + isSuccess: true, + hasAttributes: true, + hasEvents: false, + }, + { + description: "Events", + connectionID: "4", + output: "10", + isSuccess: true, + hasAttributes: false, + hasEvents: true, + }, + { + description: "Error", + connectionID: "5", + output: "", + isSuccess: false, + hasAttributes: false, + hasEvents: false, + }, + } { + t.Run(test.description, func(t *testing.T) { + ibcChannel := v1types.IBCChannel{ + Endpoint: createIBCEndpoint(PortIDForContract(contractAddress), "channel.0"), + CounterpartyEndpoint: createIBCEndpoint(PortIDForContract(contractAddress), "channel.1"), + Order: v1types.Unordered, + Version: "1", + ConnectionID: test.connectionID, + } + + ctx, events, err := ibcChannelCloseHelper(t, keeper, ctx, contractAddress, privKeyA, defaultGasForTests, true, ibcChannel) + + if !test.isSuccess { + require.Contains(t, fmt.Sprintf("%+v", err), "Intentional") + } else { + require.Empty(t, err) + if test.hasAttributes { + require.Equal(t, + []ContractEvent{ + { + {Key: "contract_address", Value: contractAddress.String()}, + {Key: "attr1", Value: "😗"}, + }, + }, + events, + ) + } + + if test.hasEvents { + hadCyber1 := false + evts := ctx.EventManager().Events() + for _, e := range evts { + if e.Type == "wasm-cyber1" { + require.False(t, hadCyber1) + attrs, err := parseAndDecryptAttributes(e.Attributes, []byte{}, false) + require.Empty(t, err) + + require.Equal(t, + []v010cosmwasm.LogAttribute{ + {Key: "contract_address", Value: contractAddress.String()}, + {Key: "attr1", Value: "🤯"}, + }, + attrs, + ) + + hadCyber1 = true + } + } + + require.True(t, hadCyber1) + } + + queryRes, err := queryHelper(t, keeper, ctx, contractAddress, `{"q":{}}`, true, true, math.MaxUint64) + + require.Empty(t, err) + + require.Equal(t, test.output, queryRes) + } + }) + } +} + +func TestIBCChannelCloseInit(t *testing.T) { + ctx, keeper, codeID, _, walletA, privKeyA, _, _ := setupTest(t, "./testdata/ibc/contract.wasm", sdk.NewCoins()) + + _, _, contractAddress, _, err := initHelper(t, keeper, ctx, codeID, walletA, privKeyA, `{"init":{}}`, true, true, defaultGasForTests) + require.Empty(t, err) + + ibcChannel := v1types.IBCChannel{ + Endpoint: createIBCEndpoint(PortIDForContract(contractAddress), "channel.0"), + CounterpartyEndpoint: createIBCEndpoint(PortIDForContract(contractAddress), "channel.1"), + Order: v1types.Unordered, + Version: "1", + ConnectionID: "1", + } + + ctx, _, err = ibcChannelCloseHelper(t, keeper, ctx, contractAddress, privKeyA, defaultGasForTests, false, ibcChannel) + require.Empty(t, err) + + queryRes, err := queryHelper(t, keeper, ctx, contractAddress, `{"q":{}}`, true, true, math.MaxUint64) + require.Empty(t, err) + + require.Equal(t, "5", queryRes) +} + +func TestIBCPacketReceive(t *testing.T) { + ctx, keeper, codeID, _, walletA, privKeyA, _, _ := setupTest(t, "./testdata/ibc/contract.wasm", sdk.NewCoins()) + + _, _, contractAddress, _, err := initHelper(t, keeper, ctx, codeID, walletA, privKeyA, `{"init":{}}`, true, true, defaultGasForTests) + require.Empty(t, err) + for _, isEncrypted := range []bool{false, true} { + for _, test := range []struct { + description string + sequence uint64 + output string + isSuccess bool + hasAttributes bool + hasEvents bool + }{ + { + description: "Default", + sequence: 0, + output: "7", + isSuccess: true, + hasAttributes: false, + hasEvents: false, + }, + { + description: "SubmessageNoReply", + sequence: 1, + output: "13", + isSuccess: true, + hasAttributes: false, + hasEvents: false, + }, + { + description: "SubmessageWithReply", + sequence: 2, + output: "20", + isSuccess: true, + hasAttributes: false, + hasEvents: false, + }, + { + description: "Attributes", + sequence: 3, + output: "10", + isSuccess: true, + hasAttributes: true, + hasEvents: false, + }, + { + description: "Events", + sequence: 4, + output: "11", + isSuccess: true, + hasAttributes: false, + hasEvents: true, + }, + { + description: "Error", + sequence: 5, + output: "", + isSuccess: false, + hasAttributes: false, + hasEvents: false, + }, + { + description: "SubmessageWithReplyThatCallsToSubmessage", + sequence: 6, + output: "35", + isSuccess: true, + hasAttributes: false, + hasEvents: false, + }, + } { + t.Run(fmt.Sprintf("%s-Encryption:%t", test.description, isEncrypted), func(t *testing.T) { + ibcPacket := createIBCPacket(createIBCEndpoint(PortIDForContract(contractAddress), "channel.1"), + createIBCEndpoint(PortIDForContract(contractAddress), "channel.0"), + test.sequence, + createIBCTimeout(math.MaxUint64), + []byte{}, + ) + ctx, nonce, events, data, err := ibcPacketReceiveHelper(t, keeper, ctx, contractAddress, privKeyA, isEncrypted, defaultGasForTests, ibcPacket) + + if !test.isSuccess { + require.Contains(t, fmt.Sprintf("%+v", err), "Intentional") + } else { + require.Empty(t, err) + require.Equal(t, "\"out\"", string(data)) + + if test.hasAttributes { + require.Equal(t, + []ContractEvent{ + { + {Key: "contract_address", Value: contractAddress.String()}, + {Key: "attr1", Value: "😗"}, + }, + }, + events, + ) + } + + if test.hasEvents { + hadCyber1 := false + evts := ctx.EventManager().Events() + for _, e := range evts { + if e.Type == "wasm-cyber1" { + require.False(t, hadCyber1) + attrs, err := parseAndDecryptAttributes(e.Attributes, nonce, isEncrypted) + require.Empty(t, err) + + require.Equal(t, + []v010cosmwasm.LogAttribute{ + {Key: "contract_address", Value: contractAddress.String()}, + {Key: "attr1", Value: "🤯"}, + }, + attrs, + ) + + hadCyber1 = true + } + } + + require.True(t, hadCyber1) + } + + queryRes, err := queryHelper(t, keeper, ctx, contractAddress, `{"q":{}}`, true, true, math.MaxUint64) + + require.Empty(t, err) + require.Equal(t, test.output, queryRes) + } + }) + } + } +} + +type ContractInfo struct { + Address string `json:"address"` + Hash string `json:"hash"` +} + +func TestIBCPacketReceiveCallsV010Contract(t *testing.T) { + ctx, keeper, codeID, _, walletA, privKeyA, _, _ := setupTest(t, "./testdata/ibc/contract.wasm", sdk.NewCoins()) + + wasmCode, err := os.ReadFile("./testdata/test-contract/contract.wasm") + require.NoError(t, err) + + v010CodeID, err := keeper.Create(ctx, walletA, wasmCode, "", "") + require.NoError(t, err) + + codeInfo, err := keeper.GetCodeInfo(ctx, v010CodeID) + require.NoError(t, err) + v010CodeHash := hex.EncodeToString(codeInfo.CodeHash) + + _, _, contractAddress, _, err := initHelper(t, keeper, ctx, codeID, walletA, privKeyA, `{"init":{}}`, true, true, defaultGasForTests) + require.Empty(t, err) + _, _, v010ContractAddress, _, err := initHelper(t, keeper, ctx, v010CodeID, walletA, privKeyA, `{"counter":{"counter":10}}`, true, false, defaultGasForTests) + require.Empty(t, err) + contractInfo := ContractInfo{ + Address: v010ContractAddress.String(), + Hash: v010CodeHash, + } + + contractInfoBz, err := json.Marshal(contractInfo) + require.NoError(t, err) + + ibcPacket := createIBCPacket(createIBCEndpoint(PortIDForContract(contractAddress), "channel.1"), + createIBCEndpoint(PortIDForContract(contractAddress), "channel.0"), + 7, + createIBCTimeout(math.MaxUint64), + contractInfoBz, + ) + + expected_v010_result := uint32(15) + + for _, isEncrypted := range []bool{true, true} { + t.Run(fmt.Sprintf("Encryption:%t", isEncrypted), func(t *testing.T) { + ctx, _, _, data, err := ibcPacketReceiveHelper(t, keeper, ctx, contractAddress, privKeyA, isEncrypted, defaultGasForTests, ibcPacket) + require.Empty(t, err) + require.Equal(t, "\"out\"", string(data)) + + queryRes, err := queryHelper(t, keeper, ctx, contractAddress, `{"q":{}}`, true, true, math.MaxUint64) + + require.Empty(t, err) + require.Equal(t, "20", queryRes) + + queryRes, qErr := queryHelper(t, keeper, ctx, v010ContractAddress, `{"get":{}}`, true, false, math.MaxUint64) + require.Empty(t, qErr) + + var resp v1QueryResponse + e := json.Unmarshal([]byte(queryRes), &resp) + require.NoError(t, e) + require.Equal(t, expected_v010_result, resp.Get.Count) + expected_v010_result += 5 + }) + } +} + +func TestIBCPacketAck(t *testing.T) { + ctx, keeper, codeID, _, walletA, privKeyA, _, _ := setupTest(t, "./testdata/ibc/contract.wasm", sdk.NewCoins()) + + _, _, contractAddress, _, err := initHelper(t, keeper, ctx, codeID, walletA, privKeyA, `{"init":{}}`, true, true, defaultGasForTests) + require.Empty(t, err) + + for _, test := range []struct { + description string + sequence uint64 + output string + isSuccess bool + hasAttributes bool + hasEvents bool + }{ + { + description: "Default", + sequence: 0, + output: "8", + isSuccess: true, + hasAttributes: false, + hasEvents: false, + }, + { + description: "SubmessageNoReply", + sequence: 1, + output: "14", + isSuccess: true, + hasAttributes: false, + hasEvents: false, + }, + { + description: "SubmessageWithReply", + sequence: 2, + output: "21", + isSuccess: true, + hasAttributes: false, + hasEvents: false, + }, + { + description: "Attributes", + sequence: 3, + output: "11", + isSuccess: true, + hasAttributes: true, + hasEvents: false, + }, + { + description: "Events", + sequence: 4, + output: "12", + isSuccess: true, + hasAttributes: false, + hasEvents: true, + }, + { + description: "Error", + sequence: 5, + output: "", + isSuccess: false, + hasAttributes: false, + hasEvents: false, + }, + } { + t.Run(test.description, func(t *testing.T) { + ibcPacket := createIBCPacket(createIBCEndpoint(PortIDForContract(contractAddress), "channel.1"), + createIBCEndpoint(PortIDForContract(contractAddress), "channel.0"), + test.sequence, + createIBCTimeout(math.MaxUint64), + []byte{}, + ) + ack := make([]byte, 8) + binary.LittleEndian.PutUint64(ack, uint64(test.sequence)) + + ctx, events, err := ibcPacketAckHelper(t, keeper, ctx, contractAddress, privKeyA, defaultGasForTests, ibcPacket, ack) + + if !test.isSuccess { + require.Contains(t, fmt.Sprintf("%+v", err), "Intentional") + } else { + require.Empty(t, err) + if test.hasAttributes { + require.Equal(t, + []ContractEvent{ + { + {Key: "contract_address", Value: contractAddress.String()}, + {Key: "attr1", Value: "😗"}, + }, + }, + events, + ) + } + + if test.hasEvents { + hadCyber1 := false + evts := ctx.EventManager().Events() + for _, e := range evts { + if e.Type == "wasm-cyber1" { + require.False(t, hadCyber1) + attrs, err := parseAndDecryptAttributes(e.Attributes, []byte{}, false) + require.Empty(t, err) + + require.Equal(t, + []v010cosmwasm.LogAttribute{ + {Key: "contract_address", Value: contractAddress.String()}, + {Key: "attr1", Value: "🤯"}, + }, + attrs, + ) + + hadCyber1 = true + } + } + + require.True(t, hadCyber1) + } + + queryRes, err := queryHelper(t, keeper, ctx, contractAddress, `{"q":{}}`, true, true, math.MaxUint64) + + require.Empty(t, err) + + require.Equal(t, test.output, queryRes) + } + }) + } +} + +func TestIBCPacketTimeout(t *testing.T) { + ctx, keeper, codeID, _, walletA, privKeyA, _, _ := setupTest(t, "./testdata/ibc/contract.wasm", sdk.NewCoins()) + + _, _, contractAddress, _, err := initHelper(t, keeper, ctx, codeID, walletA, privKeyA, `{"init":{}}`, true, true, defaultGasForTests) + require.Empty(t, err) + + for _, test := range []struct { + description string + sequence uint64 + output string + isSuccess bool + hasAttributes bool + hasEvents bool + }{ + { + description: "Default", + sequence: 0, + output: "9", + isSuccess: true, + hasAttributes: false, + hasEvents: false, + }, + { + description: "SubmessageNoReply", + sequence: 1, + output: "15", + isSuccess: true, + hasAttributes: false, + hasEvents: false, + }, + { + description: "SubmessageWithReply", + sequence: 2, + output: "22", + isSuccess: true, + hasAttributes: false, + hasEvents: false, + }, + { + description: "Attributes", + sequence: 3, + output: "12", + isSuccess: true, + hasAttributes: true, + hasEvents: false, + }, + { + description: "Events", + sequence: 4, + output: "13", + isSuccess: true, + hasAttributes: false, + hasEvents: true, + }, + { + description: "Error", + sequence: 5, + output: "", + isSuccess: false, + hasAttributes: false, + hasEvents: false, + }, + } { + t.Run(test.description, func(t *testing.T) { + ibcPacket := createIBCPacket(createIBCEndpoint(PortIDForContract(contractAddress), "channel.1"), + createIBCEndpoint(PortIDForContract(contractAddress), "channel.0"), + test.sequence, + createIBCTimeout(math.MaxUint64), + []byte{}, + ) + + ctx, events, err := ibcPacketTimeoutHelper(t, keeper, ctx, contractAddress, privKeyA, defaultGasForTests, ibcPacket) + + if !test.isSuccess { + require.Contains(t, fmt.Sprintf("%+v", err), "Intentional") + } else { + require.Empty(t, err) + if test.hasAttributes { + require.Equal(t, + []ContractEvent{ + { + {Key: "contract_address", Value: contractAddress.String()}, + {Key: "attr1", Value: "😗"}, + }, + }, + events, + ) + } + + if test.hasEvents { + hadCyber1 := false + evts := ctx.EventManager().Events() + for _, e := range evts { + if e.Type == "wasm-cyber1" { + require.False(t, hadCyber1) + attrs, err := parseAndDecryptAttributes(e.Attributes, []byte{}, false) + require.Empty(t, err) + + require.Equal(t, + []v010cosmwasm.LogAttribute{ + {Key: "contract_address", Value: contractAddress.String()}, + {Key: "attr1", Value: "🤯"}, + }, + attrs, + ) + + hadCyber1 = true + } + } + + require.True(t, hadCyber1) + } + + queryRes, err := queryHelper(t, keeper, ctx, contractAddress, `{"q":{}}`, true, true, math.MaxUint64) + + require.Empty(t, err) + + require.Equal(t, test.output, queryRes) + } + }) + } +} diff --git a/x/compute/internal/keeper/keeper.go b/x/compute/internal/keeper/keeper.go index 1c75ccc16..691658b49 100644 --- a/x/compute/internal/keeper/keeper.go +++ b/x/compute/internal/keeper/keeper.go @@ -72,20 +72,19 @@ type Keeper struct { messenger Messenger // queryGasLimit is the max wasm gas that can be spent on executing a query with a contract queryGasLimit uint64 - serviceRouter MsgServiceRouter // authZPolicy AuthorizationPolicy // paramSpace subspace.Subspace } -// MsgServiceRouter expected MsgServiceRouter interface -type MsgServiceRouter interface { - Handler(msg sdk.Msg) baseapp.MsgServiceHandler -} - func moduleLogger(ctx sdk.Context) log.Logger { return ctx.Logger().With("module", fmt.Sprintf("x/%s", types.ModuleName)) } +// MessageRouter ADR 031 request type routing +type MessageRouter interface { + Handler(msg sdk.Msg) baseapp.MsgServiceHandler +} + func NewKeeper( cdc codec.Codec, legacyAmino codec.LegacyAmino, @@ -100,7 +99,9 @@ func NewKeeper( portKeeper portkeeper.Keeper, portSource types.ICS20TransferPortSource, channelKeeper channelkeeper.Keeper, - router sdk.Router, + legacyMsgRouter sdk.Router, + msgRouter MessageRouter, + queryRouter GRPCQueryRouter, homeDir string, wasmConfig *types.WasmConfig, supportedFeatures string, @@ -112,13 +113,6 @@ func NewKeeper( panic(err) } - /* - // set KeyTable if it has not already been set - if !paramSpace.HasKeyTable() { - paramSpace = paramSpace.WithKeyTable(types.ParamKeyTable()) - } - */ - keeper := Keeper{ storeKey: storeKey, cdc: cdc, @@ -128,50 +122,16 @@ func NewKeeper( bankKeeper: bankKeeper, portKeeper: portKeeper, capabilityKeeper: capabilityKeeper, - messenger: NewMessageHandler(router, customEncoders, channelKeeper, capabilityKeeper, portSource, cdc), + messenger: NewMessageHandler(msgRouter, legacyMsgRouter, customEncoders, channelKeeper, capabilityKeeper, portSource, cdc), queryGasLimit: wasmConfig.SmartQueryGasLimit, } - keeper.queryPlugins = DefaultQueryPlugins(govKeeper, distKeeper, mintKeeper, bankKeeper, stakingKeeper, &keeper).Merge(customPlugins) + keeper.queryPlugins = DefaultQueryPlugins(govKeeper, distKeeper, mintKeeper, bankKeeper, stakingKeeper, queryRouter, &keeper, channelKeeper).Merge(customPlugins) return keeper } -/* -func (k Keeper) getUploadAccessConfig(ctx sdk.Context) types.AccessConfig { - var a types.AccessConfig - k.paramSpace.Get(ctx, types.ParamStoreKeyUploadAccess, &a) - return a -} - -func (k Keeper) getInstantiateAccessConfig(ctx sdk.Context) types.AccessType { - var a types.AccessType - k.paramSpace.Get(ctx, types.ParamStoreKeyInstantiateAccess, &a) - return a -} - -// GetParams returns the total set of wasm parameters. -func (k Keeper) GetParams(ctx sdk.Context) types.Params { - var params types.Params - k.paramSpace.GetParamSet(ctx, ¶ms) - return params -} - -func (k Keeper) setParams(ctx sdk.Context, ps types.Params) { - k.paramSpace.SetParamSet(ctx, &ps) -} -*/ - // Create uploads and compiles a WASM contract, returning a short identifier for the contract func (k Keeper) Create(ctx sdk.Context, creator sdk.AccAddress, wasmCode []byte, source string, builder string) (codeID uint64, err error) { - /* - return k.create(ctx, creator, wasmCode, source, builder, &types.AccessConfig{Type: types.Everybody} , k.authZPolicy ) - } - - func (k Keeper) create(ctx sdk.Context, creator sdk.AccAddress, wasmCode []byte, source string, builder string, instantiateAccess *types.AccessConfig ) (codeID uint64, err error) { - if !authZ.CanCreateCode(k.getUploadAccessConfig(ctx), creator) { - return 0, sdkerrors.Wrap(sdkerrors.ErrUnauthorized, "can not create code") - } - */ wasmCode, err = uncompress(wasmCode) if err != nil { return 0, sdkerrors.Wrap(types.ErrCreateFailed, err.Error()) @@ -180,18 +140,12 @@ func (k Keeper) Create(ctx sdk.Context, creator sdk.AccAddress, wasmCode []byte, codeHash, err := k.wasmer.Create(wasmCode) if err != nil { - // return 0, sdkerrors.Wrap(err, "cosmwasm create") return 0, sdkerrors.Wrap(types.ErrCreateFailed, err.Error()) } store := ctx.KVStore(k.storeKey) codeID = k.autoIncrementID(ctx, types.KeyLastCodeID) - /* - if instantiateAccess == nil { - defaultAccessConfig := k.getInstantiateAccessConfig(ctx).With(creator) - instantiateAccess = &defaultAccessConfig - } - */ - codeInfo := types.NewCodeInfo(codeHash, creator, source, builder /* , *instantiateAccess */) + + codeInfo := types.NewCodeInfo(codeHash, creator, source, builder) // 0x01 | codeID (uint64) -> ContractInfo store.Set(types.GetCodeKey(codeID), k.cdc.MustMarshal(&codeInfo)) @@ -421,10 +375,6 @@ func (k Keeper) Instantiate(ctx sdk.Context, codeID uint64, creator sdk.AccAddre var codeInfo types.CodeInfo k.cdc.MustUnmarshal(bz, &codeInfo) - // if !authZ.CanInstantiateContract(codeInfo.InstantiateConfig, creator) { - // return nil, sdkerrors.Wrap(sdkerrors.ErrUnauthorized, "can not instantiate") - // } - // prepare env for contract instantiate call env := types.NewEnv(ctx, creator, deposit, contractAddress, nil) @@ -437,12 +387,14 @@ func (k Keeper) Instantiate(ctx sdk.Context, codeID uint64, creator sdk.AccAddre querier := QueryHandler{ Ctx: ctx, Plugins: k.queryPlugins, + Caller: contractAddress, } // instantiate wasm contract gas := gasForContract(ctx) response, key, gasUsed, err := k.wasmer.Instantiate(codeInfo.CodeHash, env, initMsg, prefixStore, cosmwasmAPI, querier, ctx.GasMeter(), gas, verificationInfo, contractAddress) consumeGas(ctx, gasUsed) + if err != nil { switch res := response.(type) { case v1wasmTypes.DataWithInternalReplyInfo: @@ -466,8 +418,6 @@ func (k Keeper) Instantiate(ctx sdk.Context, codeID uint64, creator sdk.AccAddre contractInfo := types.NewContractInfo(codeID, creator, label, createdAt) store.Set(types.GetContractAddressKey(contractAddress), k.cdc.MustMarshal(&contractInfo)) - // fmt.Printf("Storing key: %v for account %s\n", key, contractAddress) - store.Set(types.GetContractEnclaveKey(contractAddress), key) store.Set(types.GetContractLabelPrefix(label), contractAddress) @@ -573,6 +523,7 @@ func (k Keeper) Execute(ctx sdk.Context, contractAddress sdk.AccAddress, caller querier := QueryHandler{ Ctx: ctx, Plugins: k.queryPlugins, + Caller: contractAddress, } gas := gasForContract(ctx) @@ -580,93 +531,14 @@ func (k Keeper) Execute(ctx sdk.Context, contractAddress sdk.AccAddress, caller consumeGas(ctx, gasUsed) if execErr != nil { - return nil, sdkerrors.Wrap(types.ErrExecuteFailed, execErr.Error()) - } - - // var res wasmTypes.CosmosResponse - // err = json.Unmarshal(res, &res) - // if err != nil { - // return sdk.Result{}, err - //} - - // emit all events from this contract itself - events := types.ParseEvents(res.Log, contractAddress) - ctx.EventManager().EmitEvents(events) - - // TODO: capture events here as well - err = k.dispatchMessages(ctx, contractAddress, res.Messages) - if err != nil { - return nil, err - } - - return &sdk.Result{ - Data: res.Data, - }, nil -} - -/* -// We don't use this function currently. It's here for upstream compatibility -// Migrate allows to upgrade a contract to a new code with data migration. -func (k Keeper) Migrate(ctx sdk.Context, contractAddress sdk.AccAddress, caller sdk.AccAddress, newCodeID uint64, msg []byte) (*sdk.Result, error) { - return k.migrate(ctx, contractAddress, caller, newCodeID, msg, k.authZPolicy) -} - -func (k Keeper) migrate(ctx sdk.Context, contractAddress sdk.AccAddress, caller sdk.AccAddress, newCodeID uint64, msg []byte, authZ AuthorizationPolicy) (*sdk.Result, error) { - ctx.GasMeter().ConsumeGas(InstanceCost, "Loading CosmWasm module: migrate") - _ = authtypes.StdSignature{ - PubKey: secp256k1.PubKeySecp256k1{}, - Signature: []byte{}, - } - _ = []byte{} - - tx := authtypes.StdTx{} - txBytes := ctx.TxBytes() - err := k.cdc.UnmarshalBinaryLengthPrefixed(txBytes, &tx) - if err != nil { - return &sdk.Result{}, sdkerrors.Wrap(types.ErrInstantiateFailed, fmt.Sprintf("Unable to decode transaction from bytes: %s", err.Error())) - } - - contractInfo := k.GetContractInfo(ctx, contractAddress) - if contractInfo == nil { - return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "unknown contract") - } - if !authZ.CanModifyContract(contractInfo.Admin, caller) { - return nil, sdkerrors.Wrap(sdkerrors.ErrUnauthorized, "can not migrate") - } - - newCodeInfo := k.GetCodeInfo(ctx, newCodeID) - if newCodeInfo == nil { - return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "unknown code") - } - - store := ctx.KVStore(k.storeKey) - contractKey := store.Get(types.GetContractEnclaveKey(contractAddress)) - - var noDeposit sdk.Coins - params := types.NewEnv(ctx, caller, noDeposit, contractAddress, contractKey) - - // prepare querier - querier := QueryHandler{ - Ctx: ctx, - Plugins: k.queryPlugins, - } - - prefixStoreKey := types.GetContractStorePrefixKey(contractAddress) - prefixStore := prefix.NewStore(ctx.KVStore(k.storeKey), prefixStoreKey) - gas := gasForContract(ctx) - res, gasUsed, err := k.wasmer.Migrate(newCodeInfo.CodeHash, params, msg, &prefixStore, cosmwasmAPI, &querier, gasMeter(ctx), gas) - consumeGas(ctx, gasUsed) - if err != nil { - return nil, sdkerrors.Wrap(types.ErrMigrationFailed, err.Error()) - } - - // emit all events from this contract itself - events := types.ParseEvents(res.Log, contractAddress) - ctx.EventManager().EmitEvents(events) - - historyEntry := contractInfo.AddMigration(ctx, newCodeID, msg) - k.appendToContractHistory(ctx, contractAddress, historyEntry) - k.setContractInfo(ctx, contractAddress, contractInfo) + var result sdk.Result + switch res := response.(type) { + case v1wasmTypes.DataWithInternalReplyInfo: + result.Data, err = json.Marshal(res) + if err != nil { + return nil, sdkerrors.Wrap(err, "couldn't marshal internal reply info") + } + } return &result, sdkerrors.Wrap(types.ErrExecuteFailed, execErr.Error()) } @@ -715,7 +587,7 @@ func (k Keeper) querySmartRecursive(ctx sdk.Context, contractAddr sdk.AccAddress return k.querySmartImpl(ctx, contractAddr, req, useDefaultGasLimit, true) } -func (k Keeper) querySmartImpl(ctx sdk.Context, contractAddr sdk.AccAddress, req []byte, useDefaultGasLimit bool, recursive bool) ([]byte, error) { +func (k Keeper) querySmartImpl(ctx sdk.Context, contractAddress sdk.AccAddress, req []byte, useDefaultGasLimit bool, recursive bool) ([]byte, error) { defer telemetry.MeasureSince(time.Now(), "compute", "keeper", "query") if useDefaultGasLimit { @@ -724,7 +596,7 @@ func (k Keeper) querySmartImpl(ctx sdk.Context, contractAddr sdk.AccAddress, req ctx.GasMeter().ConsumeGas(types.InstanceCost, "Loading CosmWasm module: query") - _, codeInfo, prefixStore, err := k.contractInstance(ctx, contractAddr) + _, codeInfo, prefixStore, err := k.contractInstance(ctx, contractAddress) if err != nil { return nil, err } @@ -733,16 +605,17 @@ func (k Keeper) querySmartImpl(ctx sdk.Context, contractAddr sdk.AccAddress, req querier := QueryHandler{ Ctx: ctx, Plugins: k.queryPlugins, + Caller: contractAddress, } store := ctx.KVStore(k.storeKey) // 0x01 | codeID (uint64) -> ContractInfo - contractKey := store.Get(types.GetContractEnclaveKey(contractAddr)) + contractKey := store.Get(types.GetContractEnclaveKey(contractAddress)) params := types.NewEnv( ctx, sdk.AccAddress{}, /* empty because it's unused in queries */ - []sdk.Coin{}, /* empty because it's unused in queries */ - contractAddr, + sdk.NewCoins(), /* empty because it's unused in queries */ + contractAddress, contractKey, ) params.Recursive = recursive @@ -750,7 +623,7 @@ func (k Keeper) querySmartImpl(ctx sdk.Context, contractAddr sdk.AccAddress, req queryResult, gasUsed, qErr := k.wasmer.Query(codeInfo.CodeHash, params, req, prefixStore, cosmwasmAPI, querier, gasMeter(ctx), gasForContract(ctx)) consumeGas(ctx, gasUsed) - telemetry.SetGauge(float32(gasUsed), "compute", "keeper", "query", contractAddr.String(), "gasUsed") + telemetry.SetGauge(float32(gasUsed), "compute", "keeper", "query", contractAddress.String(), "gasUsed") if qErr != nil { return nil, sdkerrors.Wrap(types.ErrQueryFailed, qErr.Error()) @@ -814,12 +687,21 @@ func (k Keeper) GetContractAddress(ctx sdk.Context, label string) sdk.AccAddress return contractAddress } -func (k Keeper) GetContractHash(ctx sdk.Context, contractAddress sdk.AccAddress) []byte { - codeId := k.GetContractInfo(ctx, contractAddress).CodeID +func (k Keeper) GetContractHash(ctx sdk.Context, contractAddress sdk.AccAddress) ([]byte, error) { + contractInfo := k.GetContractInfo(ctx, contractAddress) + + if contractInfo == nil { + return nil, fmt.Errorf("failed to get contract info for the following address: %s", contractAddress.String()) + } + + codeId := contractInfo.CodeID - hash := k.GetCodeInfo(ctx, codeId).CodeHash + codeInfo, err := k.GetCodeInfo(ctx, codeId) + if err != nil { + return nil, err + } - return hash + return codeInfo.CodeHash, nil } func (k Keeper) GetContractInfo(ctx sdk.Context, contractAddress sdk.AccAddress) *types.ContractInfo { @@ -897,39 +779,15 @@ func (k Keeper) importContractState(ctx sdk.Context, contractAddress sdk.AccAddr return nil } -func (k Keeper) fixContractState(ctx sdk.Context, contractAddress sdk.AccAddress, models []types.Model) error { - prefixStoreKey := types.GetContractStorePrefixKey(contractAddress) - prefixStore := prefix.NewStore(ctx.KVStore(k.storeKey), prefixStoreKey) - for _, model := range models { - if model.Value == nil { - model.Value = []byte{} - } - - if !prefixStore.Has(model.Key) { - prefixStore.Set(model.Key, model.Value) - continue - } - - existingValue := prefixStore.Get(model.Key) - if bytes.Equal(existingValue, model.Value) { - continue - } else { - prefixStore.Set(model.Key, model.Value) - } - - } - return nil -} - -func (k Keeper) GetCodeInfo(ctx sdk.Context, codeID uint64) *types.CodeInfo { +func (k Keeper) GetCodeInfo(ctx sdk.Context, codeID uint64) (types.CodeInfo, error) { store := ctx.KVStore(k.storeKey) var codeInfo types.CodeInfo codeInfoBz := store.Get(types.GetCodeKey(codeID)) if codeInfoBz == nil { - return nil + return types.CodeInfo{}, fmt.Errorf("failed to get code info for code id %d", codeID) } k.cdc.MustUnmarshal(codeInfoBz, &codeInfo) - return &codeInfo + return codeInfo, nil } func (k Keeper) containsCodeInfo(ctx sdk.Context, codeID uint64) bool { @@ -978,6 +836,7 @@ func (k *Keeper) handleContractResponse( ogCosmosMessageVersion wasmTypes.CosmosMsgVersion, ) ([]byte, error) { events := types.ContractLogsToSdkEvents(logs, contractAddr) + ctx.EventManager().EmitEvents(events) if len(evts) > 0 { @@ -1078,8 +937,6 @@ func (k Keeper) importContract(ctx sdk.Context, contractAddr sdk.AccAddress, cus return sdkerrors.Wrapf(types.ErrDuplicate, "contract: %s", contractAddr) } - // historyEntry := c.ResetFromGenesis(ctx) - // k.appendToContractHistory(ctx, contractAddr, historyEntry) k.setContractCustomInfo(ctx, contractAddr, customInfo) k.setContractInfo(ctx, contractAddr, c) return k.importContractState(ctx, contractAddr, state) @@ -1155,6 +1012,7 @@ func (k Keeper) reply(ctx sdk.Context, contractAddress sdk.AccAddress, reply v1w querier := QueryHandler{ Ctx: ctx, Plugins: k.queryPlugins, + Caller: contractAddress, } // instantiate wasm contract @@ -1177,6 +1035,8 @@ func (k Keeper) reply(ctx sdk.Context, contractAddress sdk.AccAddress, reply v1w case *v010wasmTypes.HandleResponse: return nil, sdkerrors.Wrap(types.ErrReplyFailed, fmt.Sprintf("response of reply should always be a CosmWasm v1 response type: %+v", res)) case *v1wasmTypes.Response: + consumeGas(ctx, gasUsed) + ctx.EventManager().EmitEvent(sdk.NewEvent( types.EventTypeReply, sdk.NewAttribute(types.AttributeKeyContractAddr, contractAddress.String()), diff --git a/x/compute/internal/keeper/keeper_test.go b/x/compute/internal/keeper/keeper_test.go index f00880d69..d72c2f8d4 100644 --- a/x/compute/internal/keeper/keeper_test.go +++ b/x/compute/internal/keeper/keeper_test.go @@ -22,7 +22,7 @@ import ( reg "github.com/enigmampc/SecretNetwork/x/registration" ) -const SupportedFeatures = "staking" +const SupportedFeatures = "staking,stargate,ibc3" var wasmCtx = wasmUtils.WASMContext{ TestKeyPairPath: "/tmp/id_tx_io.json", @@ -89,104 +89,6 @@ func TestCreate(t *testing.T) { require.Equal(t, wasmCode, storedCode) } -/* -func TestCreateStoresInstantiatePermission(t *testing.T) { - wasmCode, err := os.ReadFile("./testdata/contract.wasm") - require.NoError(t, err) - var ( - deposit = sdk.NewCoins(sdk.NewInt64Coin("denom", 100000)) - myAddr = bytes.Repeat([]byte{1}, sdk.AddrLen) - ) - - specs := map[string]struct { - srcPermission types.AccessType - expInstConf types.AccessConfig - }{ - "default": { - srcPermission: types.DefaultParams().DefaultInstantiatePermission, - expInstConf: types.AllowEverybody, - }, - "everybody": { - srcPermission: types.Everybody, - expInstConf: types.AllowEverybody, - }, - "nobody": { - srcPermission: types.Nobody, - expInstConf: types.AllowNobody, - }, - "onlyAddress with matching address": { - srcPermission: types.OnlyAddress, - expInstConf: types.AccessConfig{Type: types.OnlyAddress, Address: myAddr}, - }, - } - for msg, spec := range specs { - t.Run(msg, func(t *testing.T) { - tempDir, err := os.MkdirTemp("", "wasm") - require.NoError(t, err) - defer os.RemoveAll(tempDir) - - ctx, keepers := CreateTestInput(t, false, tempDir, SupportedFeatures, nil, nil) - accKeeper, keeper := keepers.AccountKeeper, keepers.WasmKeeper - fundAccounts(ctx, accKeeper, myAddr, deposit) - - codeID, err := keeper.Create(ctx, myAddr, wasmCode, "https://github.com/CosmWasm/wasmd/blob/master/x/wasm/testdata/escrow.wasm", "any/builder:tag") - require.NoError(t, err) - - codeInfo := keeper.GetCodeInfo(ctx, codeID) - require.NotNil(t, codeInfo) - assert.True(t, spec.expInstConf.Equals(codeInfo.InstantiateConfig), "got %#v", codeInfo.InstantiateConfig) - }) - } -} - -func TestCreateWithParamPermissions(t *testing.T) { - tempDir, err := os.MkdirTemp("", "wasm") - require.NoError(t, err) - defer os.RemoveAll(tempDir) - ctx, keepers := CreateTestInput(t, false, tempDir, SupportedFeatures, nil, nil) - accKeeper, keeper := keepers.AccountKeeper, keepers.WasmKeeper - - deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000)) - creator := CreateFakeFundedAccount(ctx, accKeeper, deposit) - otherAddr := CreateFakeFundedAccount(ctx, accKeeper, deposit) - - wasmCode, err := os.ReadFile("./testdata/contract.wasm") - require.NoError(t, err) - - specs := map[string]struct { - srcPermission types.AccessConfig - expError *sdkerrors.Error - }{ - "default": { - srcPermission: types.DefaultUploadAccess, - }, - "everybody": { - srcPermission: types.AllowEverybody, - }, - "nobody": { - srcPermission: types.AllowNobody, - expError: sdkerrors.ErrUnauthorized, - }, - "onlyAddress with matching address": { - srcPermission: types.OnlyAddress.With(creator), - }, - "onlyAddress with non matching address": { - srcPermission: types.OnlyAddress.With(otherAddr), - expError: sdkerrors.ErrUnauthorized, - }, - } - for msg, spec := range specs { - t.Run(msg, func(t *testing.T) { - _, err := keeper.Create(ctx, creator, wasmCode, "https://github.com/CosmWasm/wasmd/blob/master/x/wasm/testdata/escrow.wasm", "any/builder:tag") - require.True(t, spec.expError.Is(err), err) - if spec.expError != nil { - return - } - }) - } -} -*/ - func TestCreateDuplicate(t *testing.T) { encodingConfig := MakeEncodingConfig() var transferPortSource types.ICS20TransferPortSource @@ -340,7 +242,10 @@ func TestInstantiate(t *testing.T) { initMsgBz, err := json.Marshal(initMsg) require.NoError(t, err) - key := keeper.GetCodeInfo(ctx, contractID).CodeHash + codeInfo, err := keeper.GetCodeInfo(ctx, contractID) + require.NoError(t, err) + + key := codeInfo.CodeHash msg := types.SecretMsg{ CodeHash: []byte(hex.EncodeToString(key)), @@ -530,8 +435,10 @@ func TestExecute(t *testing.T) { } initMsgBz, err := json.Marshal(initMsg) - key := keeper.GetCodeInfo(ctx, contractID).CodeHash - // keyStr := hex.EncodeToString(key) + codeInfo, err := keeper.GetCodeInfo(ctx, contractID) + require.NoError(t, err) + + key := codeInfo.CodeHash msg := types.SecretMsg{ CodeHash: []byte(hex.EncodeToString(key)), @@ -586,8 +493,7 @@ func TestExecute(t *testing.T) { initMsgBz = []byte(`{"release":{}}`) - key = keeper.GetCodeInfo(ctx, contractID).CodeHash - // keyStr := hex.EncodeToString(key) + require.NoError(t, err) msg = types.SecretMsg{ CodeHash: []byte(hex.EncodeToString(key)), @@ -815,7 +721,10 @@ func TestExecuteWithCpuLoop(t *testing.T) { initMsgBz, err := json.Marshal(initMsg) require.NoError(t, err) - hash := keeper.GetCodeInfo(ctx, contractID).CodeHash + codeInfo, err := keeper.GetCodeInfo(ctx, contractID) + require.NoError(t, err) + + hash := codeInfo.CodeHash msg := types.SecretMsg{ CodeHash: []byte(hex.EncodeToString(hash)), @@ -851,7 +760,9 @@ func TestExecuteWithCpuLoop(t *testing.T) { ctx = ctx.WithGasMeter(sdk.NewGasMeter(gasLimit)) require.Equal(t, uint64(0), ctx.GasMeter().GasConsumed()) - codeHash := keeper.GetContractHash(ctx, addr) + codeHash, err := keeper.GetContractHash(ctx, addr) + require.NoError(t, err) + codeHashStr := hex.EncodeToString(codeHash) msg2 := types.SecretMsg{ @@ -937,7 +848,9 @@ func TestExecuteWithStorageLoop(t *testing.T) { require.True(t, ok, "%+v", r) }() - codeHash := keeper.GetContractHash(ctx, addr) + codeHash, err := keeper.GetContractHash(ctx, addr) + require.NoError(t, err) + codeHashStr := hex.EncodeToString(codeHash) msg := types.SecretMsg{ diff --git a/x/compute/internal/keeper/msg_dispatcher.go b/x/compute/internal/keeper/msg_dispatcher.go index 2117d5222..234c90532 100644 --- a/x/compute/internal/keeper/msg_dispatcher.go +++ b/x/compute/internal/keeper/msg_dispatcher.go @@ -141,7 +141,19 @@ func (e UnsupportedRequest) Error() string { // Reply is encrypted only when it is a contract reply func isReplyEncrypted(msg v1wasmTypes.CosmosMsg, reply v1wasmTypes.Reply) bool { - return (msg.Wasm != nil) + if msg.Wasm == nil { + return false + } + + if msg.Wasm.Execute != nil { + return len(msg.Wasm.Execute.CallbackSignature) != 0 + } + + if msg.Wasm.Instantiate != nil { + return len(msg.Wasm.Instantiate.CallbackSignature) != 0 + } + + return true } // Issue #759 - we don't return error string for worries of non-determinism @@ -179,7 +191,7 @@ func (d MessageDispatcher) DispatchSubmessages(ctx sdk.Context, contractAddr sdk switch msg.ReplyOn { case v1wasmTypes.ReplySuccess, v1wasmTypes.ReplyError, v1wasmTypes.ReplyAlways, v1wasmTypes.ReplyNever: default: - return nil, sdkerrors.Wrap(types.ErrInvalid, "replyOn value") + return nil, sdkerrors.Wrap(types.ErrInvalid, "ReplyOn value") } // first, we build a sub-context which we can use inside the submessages @@ -243,7 +255,6 @@ func (d MessageDispatcher) DispatchSubmessages(ctx sdk.Context, contractAddr sdk if len(data) > 0 { responseData = data[0] } - result = v1wasmTypes.SubMsgResult{ // Copy first 64 bytes of the OG message in order to preserve the pubkey. Ok: &v1wasmTypes.SubMsgResponse{ @@ -263,8 +274,9 @@ func (d MessageDispatcher) DispatchSubmessages(ctx sdk.Context, contractAddr sdk msg_id := []byte(fmt.Sprint(msg.ID)) // now handle the reply, we use the parent context, and abort on error reply := v1wasmTypes.Reply{ - ID: msg_id, - Result: result, + ID: msg_id, + Result: result, + WasMsgEncrypted: msg.WasMsgEncrypted, } // we can ignore any result returned as there is nothing to do with the data @@ -292,14 +304,14 @@ func (d MessageDispatcher) DispatchSubmessages(ctx sdk.Context, contractAddr sdk if reply.Result.Ok != nil { err = json.Unmarshal(reply.Result.Ok.Data, &dataWithInternalReplyInfo) if err != nil { - return nil, fmt.Errorf("cannot serialize v1 DataWithInternalReplyInfo into json : %w", err) + return nil, fmt.Errorf("cannot serialize v1 DataWithInternalReplyInfo into json: %w", err) } reply.Result.Ok.Data = dataWithInternalReplyInfo.Data } else { err = json.Unmarshal(data[0], &dataWithInternalReplyInfo) if err != nil { - return nil, fmt.Errorf("cannot serialize v1 DataWithInternalReplyInfo into json : %w", err) + return nil, fmt.Errorf("cannot serialize v1 DataWithInternalReplyInfo into json: %w", err) } } @@ -310,7 +322,6 @@ func (d MessageDispatcher) DispatchSubmessages(ctx sdk.Context, contractAddr sdk replySigInfo = ogSigInfo reply.ID = dataWithInternalReplyInfo.InternalMsgId replySigInfo.CallbackSignature = dataWithInternalReplyInfo.InternaReplyEnclaveSig - } rspData, err := d.keeper.reply(ctx, contractAddr, reply, ogTx, replySigInfo) diff --git a/x/compute/internal/keeper/msg_server.go b/x/compute/internal/keeper/msg_server.go new file mode 100644 index 000000000..f5b73d4df --- /dev/null +++ b/x/compute/internal/keeper/msg_server.go @@ -0,0 +1,77 @@ +package keeper + +import ( + "context" + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/enigmampc/SecretNetwork/x/compute/internal/types" +) + +var _ types.MsgServer = msgServer{} + +type msgServer struct { + keeper Keeper +} + +func NewMsgServerImpl(k Keeper) types.MsgServer { + return &msgServer{keeper: k} +} + +func (m msgServer) StoreCode(goCtx context.Context, msg *types.MsgStoreCode) (*types.MsgStoreCodeResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + codeID, err := m.keeper.Create(ctx, msg.Sender, msg.WASMByteCode, msg.Source, msg.Builder) + + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), + sdk.NewAttribute(types.AttributeKeySigner, msg.Sender.String()), + sdk.NewAttribute(sdk.AttributeKeySender, msg.Sender.String()), + sdk.NewAttribute(types.AttributeKeyCodeID, fmt.Sprintf("%d", codeID)), + ), + }) + + return &types.MsgStoreCodeResponse{ + CodeID: codeID, + }, err +} + +func (m msgServer) InstantiateContract(goCtx context.Context, msg *types.MsgInstantiateContract) (*types.MsgInstantiateContractResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + ctx.EventManager().EmitEvent(sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), + sdk.NewAttribute(sdk.AttributeKeySender, msg.Sender.String()), + )) + + contractAddr, data, err := m.keeper.Instantiate(ctx, msg.CodeID, msg.Sender, msg.InitMsg, msg.Label, msg.InitFunds, msg.CallbackSig) + + // we always return data (internally used in reply) + // note: even if contractAddr == nil then contractAddr.String() is ok + // \o/🤷🤷‍♂️🤷‍♀️🤦🤦‍♂️🤦‍♀️ + return &types.MsgInstantiateContractResponse{ + Address: contractAddr.String(), + Data: data, + }, err +} + +func (m msgServer) ExecuteContract(goCtx context.Context, msg *types.MsgExecuteContract) (*types.MsgExecuteContractResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + ctx.EventManager().EmitEvent(sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), + sdk.NewAttribute(sdk.AttributeKeySender, msg.Sender.String()), + )) + + data, err := m.keeper.Execute(ctx, msg.Contract, msg.Sender, msg.Msg, msg.SentFunds, msg.CallbackSig) + + // we always return data (internally used in reply) + return &types.MsgExecuteContractResponse{ + Data: data.Data, + }, err +} diff --git a/x/compute/internal/keeper/param_verification_test.go b/x/compute/internal/keeper/param_verification_test.go deleted file mode 100644 index 266f2d58d..000000000 --- a/x/compute/internal/keeper/param_verification_test.go +++ /dev/null @@ -1,1031 +0,0 @@ -package keeper - -import ( - "fmt" - "testing" - - "github.com/stretchr/testify/require" - - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" - multisigkeys "github.com/cosmos/cosmos-sdk/crypto/keys/multisig" - crypto "github.com/cosmos/cosmos-sdk/crypto/types" - "github.com/cosmos/cosmos-sdk/crypto/types/multisig" - sdk "github.com/cosmos/cosmos-sdk/types" - sdksigning "github.com/cosmos/cosmos-sdk/types/tx/signing" - authante "github.com/cosmos/cosmos-sdk/x/auth/ante" - authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing" - authtx "github.com/cosmos/cosmos-sdk/x/auth/tx" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - - "github.com/enigmampc/SecretNetwork/x/compute/internal/types" -) - -func getSignBytes( - t *testing.T, signModeHandler authsigning.SignModeHandler, builder client.TxBuilder, multisigAccount Account, signer Account, -) []byte { - sig := sdksigning.SignatureV2{ - PubKey: signer.public, - Sequence: multisigAccount.acct.GetSequence(), - Data: &sdksigning.SingleSignatureData{ - SignMode: sdksigning.SignMode_SIGN_MODE_LEGACY_AMINO_JSON, - Signature: nil, - }, - } - err := builder.SetSignatures(sig) - require.NoError(t, err) - signerData := authsigning.SignerData{ - ChainID: "", - AccountNumber: signer.acct.GetAccountNumber(), - Sequence: signer.acct.GetSequence(), - } - bytesToSign, err := signModeHandler.GetSignBytes(sdksigning.SignMode_SIGN_MODE_LEGACY_AMINO_JSON, signerData, builder.GetTx()) - require.NoError(t, err) - - return bytesToSign -} - -func generateSignatures( - t *testing.T, signModeHandler authsigning.SignModeHandler, - builder client.TxBuilder, multisigAccount Account, signers []Account, actualSigners int, -) *sdksigning.MultiSignatureData { - multiSig := multisig.NewMultisig(len(signers)) - - for i := 0; i < len(signers); i++ { - signBytes := getSignBytes(t, signModeHandler, builder, multisigAccount, signers[i]) - var signature []byte - if i < actualSigners { - signature, _ = signers[i].private.Sign(signBytes) - } - signatureData := sdksigning.SingleSignatureData{ - SignMode: sdksigning.SignMode_SIGN_MODE_LEGACY_AMINO_JSON, - Signature: signature, - } - - err := multisig.AddSignatureFromPubKey(multiSig, &signatureData, signers[i].public, Accounts(signers).pubKeys()) - require.NoError(t, err) - } - - fmt.Printf("Multisig is %+v\n", multiSig) - - return multiSig -} - -func multisigTxCreator( - t *testing.T, ctx *sdk.Context, keeper Keeper, n int, threshold int, actualSigners int, sdkMsg sdk.Msg, -) (authsigning.SignModeHandler, []Account, Account) { - signers, multisigAccount := generateMultisigAccount(*ctx, keeper, n, threshold) - signModeHandler := multisigTxCreatorForExisting(t, ctx, multisigAccount, signers, actualSigners, sdkMsg) - return signModeHandler, signers, multisigAccount -} - -func multisigTxCreatorForExisting( - t *testing.T, ctx *sdk.Context, multisigAccount Account, signers []Account, actualSigners int, sdkMsg sdk.Msg, -) authsigning.SignModeHandler { - switch msg := sdkMsg.(type) { - case *types.MsgInstantiateContract: - msg.Sender = multisigAccount.address - case *types.MsgExecuteContract: - msg.Sender = multisigAccount.address - } - - txConfig := authtx.NewTxConfig(nil, authtx.DefaultSignModes) - signmodeHandler := txConfig.SignModeHandler() - builder := txConfig.NewTxBuilder() - builder.SetFeeAmount(nil) - builder.SetGasLimit(0) - builder.SetTimeoutHeight(0) - - _ = builder.SetMsgs(sdkMsg) - - multiSignature := generateSignatures(t, signmodeHandler, builder, multisigAccount, signers, actualSigners) - signature := sdksigning.SignatureV2{ - PubKey: multisigAccount.public, - Sequence: multisigAccount.acct.GetSequence(), - Data: multiSignature, - } - err := builder.SetSignatures(signature) - require.NoError(t, err) - - tx := builder.(protoTxProvider) - txbytes, err := tx.GetProtoTx().Marshal() - require.NoError(t, err) - *ctx = ctx.WithTxBytes(txbytes) - - return signmodeHandler -} - -type Account struct { - acct authtypes.AccountI - address sdk.AccAddress - public crypto.PubKey - private crypto.PrivKey -} - -func newAccount(ctx sdk.Context, keeper Keeper, private crypto.PrivKey) Account { - public := private.PubKey() - address := sdk.AccAddress(public.Address()) - acct, err := authante.GetSignerAcc(ctx, keeper.accountKeeper, address) - if err != nil { - panic(fmt.Sprintf("failed to get signer account %v", address)) - } - return Account{ - acct, - address, - public, - private, - } -} - -type Accounts []Account - -func (accts Accounts) pubKeys() []crypto.PubKey { - var pubKeys []crypto.PubKey - for _, acct := range accts { - pubKeys = append(pubKeys, acct.public) - } - return pubKeys -} - -func generateMultisigAccount(ctx sdk.Context, keeper Keeper, n int, threshold int) ([]Account, Account) { - accounts := make([]Account, n) - - for i := 0; i < n; i++ { - deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000)) - _, privKey := CreateFakeFundedAccount(ctx, keeper.accountKeeper, keeper.bankKeeper, deposit.Add(deposit...)) - accounts[i] = newAccount(ctx, keeper, privKey) - } - - multisigAccount := generateMultisigAccountFromPublicKeys(ctx, keeper, Accounts(accounts).pubKeys(), threshold) - - return accounts, multisigAccount -} - -func generateMultisigAccountFromPublicKeys(ctx sdk.Context, keeper Keeper, pubKeys []crypto.PubKey, threshold int) Account { - multisigPubkey := multisigkeys.NewLegacyAminoPubKey(threshold, pubKeys) - - // Register to keeper - addr := multisigPubkey.Address().Bytes() - baseAcct := authtypes.NewBaseAccountWithAddress(addr) - coins := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000)) - _ = baseAcct.SetPubKey(multisigPubkey) - keeper.accountKeeper.SetAccount(ctx, baseAcct) - - if err := keeper.bankKeeper.MintCoins(ctx, faucetAccountName, coins); err != nil { - panic(err) - } - - _ = keeper.bankKeeper.SendCoinsFromModuleToAccount(ctx, faucetAccountName, addr, coins) - - return Account{ - acct: baseAcct, - address: addr, - public: multisigPubkey, - private: nil, - } -} - -func prepareInitSignedTxMultipleMsgs( - t *testing.T, keeper Keeper, ctx sdk.Context, - creators []sdk.AccAddress, privKeys []crypto.PrivKey, initMsgs []sdk.Msg, codeID uint64, -) sdk.Context { - t.SkipNow() // skipping till multisig is fixed - accounts := make([]authtypes.AccountI, len(creators)) - for i, acc := range creators { - account, err := authante.GetSignerAcc(ctx, keeper.accountKeeper, acc) - require.NoError(t, err) - accounts[i] = account - } - - tx := NewTestTxMultiple(initMsgs, accounts, privKeys) - txBytes, err := tx.Marshal() - require.NoError(t, err) - - return ctx.WithTxBytes(txBytes) -} - -func TestMultipleSigners(t *testing.T) { - // - t.SkipNow() // skipping till multisig is fixed - ctx, keeper, codeID, codeHash, walletA, privKeyA, walletB, privKeyB := setupTest(t, "./testdata/test-contract/contract.wasm", sdk.NewCoins()) - - initMsg := `{"nop":{}}` - - msg := types.SecretMsg{ - CodeHash: []byte(codeHash), - Msg: []byte(initMsg), - } - - initMsgBz, err := wasmCtx.Encrypt(msg.Serialize()) - require.NoError(t, err) - nonce := initMsgBz[0:32] - - sdkMsgA := types.MsgInstantiateContract{ - Sender: walletA, - // Admin: nil, - CodeID: codeID, - Label: "demo contract 1", - InitMsg: initMsgBz, - InitFunds: nil, - } - sdkMsgB := types.MsgInstantiateContract{ - Sender: walletB, - // Admin: nil, - CodeID: codeID, - Label: "demo contract 2", - InitMsg: initMsgBz, - InitFunds: nil, - } - - ctx = prepareInitSignedTxMultipleMsgs( - t, keeper, ctx, - []sdk.AccAddress{walletA, walletB}, []crypto.PrivKey{privKeyA, privKeyB}, []sdk.Msg{&sdkMsgA, &sdkMsgB}, codeID, - ) - - contractAddressA, _, err := keeper.Instantiate(ctx, codeID, walletA /* nil,*/, initMsgBz, "demo contract 1", sdk.NewCoins(sdk.NewInt64Coin("denom", 0)), nil) - if err != nil { - err = extractInnerError(t, err, nonce, true, false) - } - require.NoError(t, err) - - wasmEvents := getDecryptedWasmEvents(t, ctx, nonce) - - require.Equal(t, - []ContractEvent{ - { - {Key: "contract_address", Value: contractAddressA.String()}, - {Key: "init", Value: "🌈"}, - }, - }, - wasmEvents, - ) - - contractAddressB, _, err := keeper.Instantiate(ctx, codeID, walletB /* nil,*/, initMsgBz, "demo contract 2", sdk.NewCoins(sdk.NewInt64Coin("denom", 0)), nil) - if err != nil { - err = extractInnerError(t, err, nonce, false, false) - } - require.NoError(t, err) - - wasmEvents = getDecryptedWasmEvents(t, ctx, nonce) - - require.Equal(t, - []ContractEvent{ - { - {Key: "contract_address", Value: contractAddressA.String()}, - {Key: "init", Value: "🌈"}, - }, - { - {Key: "contract_address", Value: contractAddressB.String()}, - {Key: "init", Value: "🌈"}, - }, - }, - wasmEvents, - ) -} - -func TestWrongSigner(t *testing.T) { - t.SkipNow() // skipping till multisig is fixed - ctx, keeper, codeID, _, walletA, _, walletB, privKeyB := setupTest(t, "./testdata/test-contract/contract.wasm", sdk.NewCoins()) - - initMsg := `{"nop":{}}` - - initMsgBz, err := wasmCtx.Encrypt([]byte(initMsg)) - require.NoError(t, err) - nonce := initMsgBz[0:32] - - sdkMsgA := types.MsgInstantiateContract{ - Sender: walletB, - // Admin: nil, - CodeID: codeID, - Label: "demo contract 1", - InitMsg: initMsgBz, - InitFunds: nil, - } - - ctx = prepareInitSignedTxMultipleMsgs(t, keeper, ctx, []sdk.AccAddress{walletB}, []crypto.PrivKey{privKeyB}, []sdk.Msg{&sdkMsgA}, codeID) - - _, _, err = keeper.Instantiate(ctx, codeID, walletA /* nil,*/, initMsgBz, "some label", sdk.NewCoins(sdk.NewInt64Coin("denom", 0)), nil) - if err != nil { - err = extractInnerError(t, err, nonce, false, false) - } - require.Contains(t, err.Error(), "is not found in the tx signer set") -} - -func TestMultiSig(t *testing.T) { - t.SkipNow() // skipping till multisig is fixed - ctx, keeper, codeID, codeHash, _, _, _, _ := setupTest(t, "./testdata/test-contract/contract.wasm", sdk.NewCoins()) - - initMsg := `{"nop":{}}` - msg := types.NewSecretMsg([]byte(codeHash), []byte(initMsg)) - - initMsgBz, err := wasmCtx.Encrypt(msg.Serialize()) - require.NoError(t, err) - nonce := initMsgBz[0:32] - - for i := 0; i < 5; i++ { - for j := 0; j <= i; j++ { - label := fmt.Sprintf("demo contract %d %d", i, j) - sdkMsg := types.MsgInstantiateContract{ - // Admin: nil, - CodeID: codeID, - Label: label, - InitMsg: initMsgBz, - InitFunds: sdk.NewCoins(sdk.NewInt64Coin("denom", 0)), - } - - _, _, multisigAddr := multisigTxCreator(t, &ctx, keeper, i+1, j+1, i+1, &sdkMsg) - - contractAddressA, _, err := keeper.Instantiate(ctx, codeID, multisigAddr.address /* nil, */, initMsgBz, label, sdk.NewCoins(sdk.NewInt64Coin("denom", 0)), nil) - if err != nil { - err = extractInnerError(t, err, nonce, true, false) - } - require.NoError(t, err) - - wasmEvents := getDecryptedWasmEvents(t, ctx, nonce) - - require.Equal(t, - []ContractEvent{ - { - {Key: "contract_address", Value: contractAddressA.String()}, - {Key: "init", Value: "🌈"}, - }, - }, - wasmEvents, - ) - - // Reset wasm events - ctx, keeper, codeID, codeHash, _, _, _, _ = setupTest(t, "./testdata/test-contract/contract.wasm", sdk.NewCoins()) - } - } -} - -func TestMultiSigThreshold(t *testing.T) { - t.SkipNow() // skipping till multisig is fixed - ctx, keeper, codeID, codeHash, _, _, _, _ := setupTest(t, "./testdata/test-contract/contract.wasm", sdk.NewCoins()) - - initMsg := `{"nop":{}}` - - msg := types.SecretMsg{ - CodeHash: []byte(codeHash), - Msg: []byte(initMsg), - } - - initMsgBz, err := wasmCtx.Encrypt(msg.Serialize()) - require.NoError(t, err) - nonce := initMsgBz[0:32] - - for i := 0; i < 5; i++ { - for j := 0; j <= i; j++ { - label := fmt.Sprintf("demo contract %d %d", i+1, j+1) - sdkMsg := types.MsgInstantiateContract{ - // Admin: nil, - CodeID: codeID, - Label: label, - InitMsg: initMsgBz, - InitFunds: sdk.NewCoins(sdk.NewInt64Coin("denom", 0)), - } - - _, _, multisigAddr := multisigTxCreator(t, &ctx, keeper, i+1, j+1, j+1, &sdkMsg) - - contractAddressA, _, err := keeper.Instantiate(ctx, codeID, multisigAddr.address /* nil,*/, initMsgBz, label, sdk.NewCoins(sdk.NewInt64Coin("denom", 0)), nil) - if err != nil { - err = extractInnerError(t, err, nonce, true, false) - } - require.NoError(t, err) - - wasmEvents := getDecryptedWasmEvents(t, ctx, nonce) - - require.Equal(t, - []ContractEvent{ - { - {Key: "contract_address", Value: contractAddressA.String()}, - {Key: "init", Value: "🌈"}, - }, - }, - wasmEvents, - ) - - // Reset wasm events - ctx, keeper, codeID, _, _, _, _, _ = setupTest(t, "./testdata/test-contract/contract.wasm", sdk.NewCoins()) - } - } -} - -func TestMultiSigThresholdNotMet(t *testing.T) { - t.SkipNow() // skipping till multisig is fixed - ctx, keeper, codeID, codeHash, _, _, _, _ := setupTest(t, "./testdata/test-contract/contract.wasm", sdk.NewCoins()) - - initMsg := `{"nop":{}}` - - msg := types.SecretMsg{ - CodeHash: []byte(codeHash), - Msg: []byte(initMsg), - } - - initMsgBz, err := wasmCtx.Encrypt(msg.Serialize()) - require.NoError(t, err) - nonce := initMsgBz[0:32] - - sdkMsg := types.MsgInstantiateContract{ - // Admin: nil, - CodeID: codeID, - Label: "demo contract 1", - InitMsg: initMsgBz, - InitFunds: sdk.NewCoins(sdk.NewInt64Coin("denom", 0)), - } - - _, _, multisigAddr := multisigTxCreator(t, &ctx, keeper, 3, 2, 1, &sdkMsg) - - _, _, err = keeper.Instantiate(ctx, codeID, multisigAddr.address /* nil,*/, initMsgBz, "demo contract 1", sdk.NewCoins(sdk.NewInt64Coin("denom", 0)), nil) - if err != nil { - err = extractInnerError(t, err, nonce, false, false) - } - require.Contains(t, err.Error(), "failed to verify transaction signature") -} - -func TestMultiSigExecute(t *testing.T) { - t.SkipNow() // skipping till multisig is fixed - ctx, keeper, codeID, codeHash, _, _, walletB, privKeyB := setupTest(t, "./testdata/erc20.wasm", sdk.NewCoins()) - - accounts, multisigAccount := generateMultisigAccount(ctx, keeper, 5, 4) - - initMsg := fmt.Sprintf( - `{"decimals":10,"initial_balances":[{"address":"%s","amount":"108"},{"address":"%s","amount":"53"}],"name":"ReuvenPersonalRustCoin","symbol":"RPRC"}`, - multisigAccount.address, walletB.String(), - ) - - _, _, contractAddress, _, error := initHelper(t, keeper, ctx, codeID, walletB, privKeyB, initMsg, true, false, defaultGasForTests) - require.Empty(t, error) - - execMsg := fmt.Sprintf(`{"transfer":{"amount":"10","recipient":"%s"}}`, walletB.String()) - - msg := types.SecretMsg{ - CodeHash: []byte(codeHash), - Msg: []byte(execMsg), - } - - execMsgBz, err := wasmCtx.Encrypt(msg.Serialize()) - require.NoError(t, err) - nonce := execMsgBz[0:32] - - funds := sdk.NewCoins(sdk.NewInt64Coin("denom", 0)) - sdkMsg := types.MsgExecuteContract{ - Contract: contractAddress, - Msg: execMsgBz, - SentFunds: funds, - CallbackSig: nil, - } - - _ = multisigTxCreatorForExisting(t, &ctx, multisigAccount, accounts, 4, &sdkMsg) - - execRes, err := keeper.Execute(ctx, contractAddress, multisigAccount.address, execMsgBz, funds, nil) - if err != nil { - err = extractInnerError(t, err, nonce, true, false) - } - require.NoError(t, err) - - data := getDecryptedData(t, execRes.Data, nonce) - wasmEvents := getDecryptedWasmEvents(t, ctx, nonce) - require.Empty(t, data) - require.Equal(t, - []ContractEvent{ - { - {Key: "contract_address", Value: contractAddress.String()}, - {Key: "action", Value: "transfer"}, - {Key: "sender", Value: multisigAccount.address.String()}, - {Key: "recipient", Value: walletB.String()}, - }, - }, - wasmEvents, - ) -} - -func TestMultiSigCallbacks(t *testing.T) { - t.SkipNow() // skipping till multisig is fixed - ctx, keeper, codeID, codeHash, walletA, privKeyA, _, _ := setupTest(t, "./testdata/test-contract/contract.wasm", sdk.NewCoins()) - - // init - _, _, contractAddress, initEvents, error := initHelper(t, keeper, ctx, codeID, walletA, privKeyA, `{"nop":{}}`, true, false, defaultGasForTests) - require.Empty(t, error) - - require.Equal(t, - []ContractEvent{ - { - {Key: "contract_address", Value: contractAddress.String()}, - {Key: "init", Value: "🌈"}, - }, - }, - initEvents, - ) - - execMsg := fmt.Sprintf(`{"a":{"contract_addr":"%s","code_hash":"%s","x":2,"y":3}}`, contractAddress.String(), codeHash) - - msg := types.SecretMsg{ - CodeHash: []byte(codeHash), - Msg: []byte(execMsg), - } - - execMsgBz, err := wasmCtx.Encrypt(msg.Serialize()) - require.NoError(t, err) - nonce := execMsgBz[0:32] - - sdkMsg := types.MsgExecuteContract{ - Contract: contractAddress, - Msg: execMsgBz, - SentFunds: sdk.NewCoins(sdk.NewInt64Coin("denom", 0)), - CallbackSig: nil, - } - - _, _, multisigAddr := multisigTxCreator(t, &ctx, keeper, 3, 2, 2, &sdkMsg) - - execRes, err := keeper.Execute(ctx, contractAddress, multisigAddr.address, execMsgBz, sdk.NewCoins(sdk.NewInt64Coin("denom", 0)), nil) - if err != nil { - err = extractInnerError(t, err, nonce, true, false) - } - data := getDecryptedData(t, execRes.Data, nonce) - execEvents := getDecryptedWasmEvents(t, ctx, nonce) - - require.Empty(t, err) - require.Equal(t, - []ContractEvent{ - { - {Key: "contract_address", Value: contractAddress.String()}, - {Key: "banana", Value: "🍌"}, - }, - { - {Key: "contract_address", Value: contractAddress.String()}, - {Key: "kiwi", Value: "🥝"}, - }, - { - {Key: "contract_address", Value: contractAddress.String()}, - {Key: "watermelon", Value: "🍉"}, - }, - }, - execEvents, - ) - require.Equal(t, []byte{2, 3}, data) -} - -func TestMultiSigInMultiSig(t *testing.T) { - t.SkipNow() // skipping till multisig is fixed - ctx, keeper, codeID, codeHash, _, privKeyA, _, privKeyB := setupTest(t, "./testdata/test-contract/contract.wasm", sdk.NewCoins()) - - accounts, multisigAccount := generateMultisigAccount(ctx, keeper, 5, 3) - multiSigPubKeys := []crypto.PubKey{multisigAccount.public, privKeyA.PubKey(), privKeyB.PubKey()} - multimultisigAccount := generateMultisigAccountFromPublicKeys(ctx, keeper, multiSigPubKeys, 2) - - initMsg := `{"nop":{}}` - - msg := types.SecretMsg{ - CodeHash: []byte(codeHash), - Msg: []byte(initMsg), - } - - initMsgBz, err := wasmCtx.Encrypt(msg.Serialize()) - require.NoError(t, err) - nonce := initMsgBz[0:32] - - sdkMsg := types.MsgInstantiateContract{ - Sender: multimultisigAccount.address, - // Admin: nil, - CodeID: codeID, - Label: "demo contract 1", - InitMsg: initMsgBz, - InitFunds: sdk.NewCoins(sdk.NewInt64Coin("denom", 0)), - } - - txConfig := authtx.NewTxConfig(nil, authtx.DefaultSignModes) - signModeHandler := txConfig.SignModeHandler() - builder := txConfig.NewTxBuilder() - builder.SetFeeAmount(nil) - builder.SetGasLimit(0) - builder.SetTimeoutHeight(0) - - _ = builder.SetMsgs(&sdkMsg) - multimultiSignBytes := getSignBytes(t, signModeHandler, builder, multimultisigAccount, multisigAccount) - multimultiSig := multisig.NewMultisig(3) - - // Sign by multisig - multiSignature := generateSignatures(t, signModeHandler, builder, multisigAccount, accounts, 3) - fmt.Printf("multisig sig: %+v\n", multiSignature) - - // Sign by wallet A - walletASignature, _ := privKeyA.Sign(multimultiSignBytes) - walletASignatureData := sdksigning.SingleSignatureData{ - SignMode: sdksigning.SignMode_SIGN_MODE_LEGACY_AMINO_JSON, - Signature: walletASignature, - } - walletBSignatureData := sdksigning.SingleSignatureData{ - SignMode: sdksigning.SignMode_SIGN_MODE_LEGACY_AMINO_JSON, - Signature: nil, // No signature provided - } - - fmt.Printf("wallet A sig: %v\n", walletASignature) - - _ = multisig.AddSignatureFromPubKey(multimultiSig, multiSignature, multisigAccount.public, multiSigPubKeys) - _ = multisig.AddSignatureFromPubKey(multimultiSig, &walletASignatureData, privKeyA.PubKey(), multiSigPubKeys) - _ = multisig.AddSignatureFromPubKey(multimultiSig, &walletBSignatureData, privKeyB.PubKey(), multiSigPubKeys) - - fmt.Printf("multimultisig sig: %+v\n", multimultiSig) - - multimultisigAcc := keeper.accountKeeper.GetAccount(ctx, multimultisigAccount.address.Bytes()) - signature := sdksigning.SignatureV2{ - PubKey: multimultisigAccount.public, - Sequence: multimultisigAcc.GetSequence(), - Data: multimultiSig, - } - err = builder.SetSignatures(signature) - require.NoError(t, err) - - tx := builder.(protoTxProvider) - txBytes, err := tx.GetProtoTx().Marshal() - require.NoError(t, err) - - ctx = ctx.WithTxBytes(txBytes) - - contractAddressA, _, err := keeper.Instantiate( - ctx, - codeID, - multimultisigAccount.address, - /* nil, */ - initMsgBz, - "demo contract 1", - sdk.NewCoins(sdk.NewInt64Coin("denom", 0)), - nil, - ) - if err != nil { - err = extractInnerError(t, err, nonce, true, false) - } - require.NoError(t, err) - - wasmEvents := getDecryptedWasmEvents(t, ctx, nonce) - - require.Equal(t, - []ContractEvent{ - { - {Key: "contract_address", Value: contractAddressA.String()}, - {Key: "init", Value: "🌈"}, - }, - }, - wasmEvents, - ) -} - -func TestMultiSigInMultiSigDifferentOrder(t *testing.T) { - t.SkipNow() // skipping till multisig is fixed - ctx, keeper, codeID, codeHash, _, privKeyA, _, privKeyB := setupTest(t, "./testdata/test-contract/contract.wasm", sdk.NewCoins()) - - accounts, multisigAccount := generateMultisigAccount(ctx, keeper, 5, 3) - multiSigPubKeys := []crypto.PubKey{multisigAccount.public, privKeyA.PubKey(), privKeyB.PubKey()} - multimultisigAccount := generateMultisigAccountFromPublicKeys(ctx, keeper, multiSigPubKeys, 2) - - initMsg := `{"nop":{}}` - - msg := types.SecretMsg{ - CodeHash: []byte(codeHash), - Msg: []byte(initMsg), - } - - initMsgBz, err := wasmCtx.Encrypt(msg.Serialize()) - require.NoError(t, err) - nonce := initMsgBz[0:32] - - sdkMsg := types.MsgInstantiateContract{ - Sender: multimultisigAccount.address, - // Admin: nil, - CodeID: codeID, - Label: "demo contract 1", - InitMsg: initMsgBz, - InitFunds: sdk.NewCoins(sdk.NewInt64Coin("denom", 0)), - } - - txConfig := authtx.NewTxConfig(nil, authtx.DefaultSignModes) - signModeHandler := txConfig.SignModeHandler() - builder := txConfig.NewTxBuilder() - builder.SetFeeAmount(nil) - builder.SetGasLimit(0) - builder.SetTimeoutHeight(0) - - _ = builder.SetMsgs(&sdkMsg) - multimultiSignBytes := getSignBytes(t, signModeHandler, builder, multimultisigAccount, multisigAccount) - multimultiSig := multisig.NewMultisig(3) - - // Sign by multisig - multiSignature := generateSignatures(t, signModeHandler, builder, multisigAccount, accounts, 3) - fmt.Printf("multisig sig: %+v\n", multiSignature) - - // Sign by wallet A - walletASignature, _ := privKeyA.Sign(multimultiSignBytes) - walletASignatureData := sdksigning.SingleSignatureData{ - SignMode: sdksigning.SignMode_SIGN_MODE_LEGACY_AMINO_JSON, - Signature: walletASignature, - } - walletBSignatureData := sdksigning.SingleSignatureData{ - SignMode: sdksigning.SignMode_SIGN_MODE_LEGACY_AMINO_JSON, - Signature: nil, // No signature provided - } - - fmt.Printf("wallet A sig: %v\n", walletASignature) - - err = multisig.AddSignatureFromPubKey(multimultiSig, &walletBSignatureData, privKeyB.PubKey(), multiSigPubKeys) - err = multisig.AddSignatureFromPubKey(multimultiSig, multiSignature, multisigAccount.public, multiSigPubKeys) - err = multisig.AddSignatureFromPubKey(multimultiSig, &walletASignatureData, privKeyA.PubKey(), multiSigPubKeys) - - fmt.Printf("multimultisig sig: %+v\n", multimultiSig) - - multimultisigAcc := keeper.accountKeeper.GetAccount(ctx, multimultisigAccount.address.Bytes()) - signature := sdksigning.SignatureV2{ - PubKey: multimultisigAccount.public, - Sequence: multimultisigAcc.GetSequence(), - Data: multimultiSig, - } - err = builder.SetSignatures(signature) - require.NoError(t, err) - - tx := builder.(protoTxProvider) - txBytes, err := tx.GetProtoTx().Marshal() - require.NoError(t, err) - - ctx = ctx.WithTxBytes(txBytes) - - contractAddressA, _, err := keeper.Instantiate( - ctx, - codeID, - multimultisigAccount.address, - /* nil, */ - initMsgBz, - "demo contract 1", - sdk.NewCoins(sdk.NewInt64Coin("denom", 0)), - nil, - ) - if err != nil { - err = extractInnerError(t, err, nonce, true, false) - } - require.NoError(t, err) - - wasmEvents := getDecryptedWasmEvents(t, ctx, nonce) - - require.Equal(t, - []ContractEvent{ - { - {Key: "contract_address", Value: contractAddressA.String()}, - {Key: "init", Value: "🌈"}, - }, - }, - wasmEvents, - ) -} - -func TestInvalidKeyType(t *testing.T) { - t.SkipNow() // skipping till multisig is fixed - ctx, keeper, codeID, codeHash, _, _, _, _ := setupTest(t, "./testdata/test-contract/contract.wasm", sdk.NewCoins()) - - edKey := ed25519.GenPrivKey() - edPub := edKey.PubKey() - edAddr := sdk.AccAddress(edPub.Address()) - baseAcct := authtypes.NewBaseAccountWithAddress(edAddr) - coins := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000)) - _ = baseAcct.SetPubKey(edPub) - - if err := keeper.bankKeeper.MintCoins(ctx, faucetAccountName, sdk.NewCoins(sdk.NewInt64Coin("denom", 100000))); err != nil { - panic(err) - } - - _ = keeper.bankKeeper.SendCoinsFromModuleToAccount(ctx, faucetAccountName, edAddr, coins) - - keeper.accountKeeper.SetAccount(ctx, baseAcct) - - initMsg := `{"nop":{}}` - - msg := types.SecretMsg{ - CodeHash: []byte(codeHash), - Msg: []byte(initMsg), - } - - initMsgBz, err := wasmCtx.Encrypt(msg.Serialize()) - require.NoError(t, err) - // nonce := initMsgBz[0:32] - - sdkMsg := types.MsgInstantiateContract{ - Sender: edAddr, - // Admin: nil, - CodeID: codeID, - Label: "demo contract 1", - InitMsg: initMsgBz, - InitFunds: sdk.NewCoins(sdk.NewInt64Coin("denom", 0)), - } - - ctx = prepareInitSignedTxMultipleMsgs(t, keeper, ctx, []sdk.AccAddress{edAddr}, []crypto.PrivKey{edKey}, []sdk.Msg{&sdkMsg}, codeID) - - _, _, err = keeper.Instantiate(ctx, codeID, edAddr /* nil,*/, initMsgBz, "demo contract 1", sdk.NewCoins(sdk.NewInt64Coin("denom", 0)), nil) - require.Contains(t, err.Error(), "failed to verify transaction signature") -} - -func TestInvalidKeyTypeInMultisig(t *testing.T) { - t.SkipNow() // skipping till multisig is fixed - ctx, keeper, codeID, codeHash, _, privKeyA, _, privKeyB := setupTest(t, "./testdata/test-contract/contract.wasm", sdk.NewCoins()) - - edKey := ed25519.GenPrivKey() - edPub := edKey.PubKey() - edAddr := sdk.AccAddress(edPub.Address()) - baseAcct := authtypes.NewBaseAccountWithAddress(edAddr) - coins := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000)) - _ = baseAcct.SetPubKey(edPub) - - if err := keeper.bankKeeper.MintCoins(ctx, faucetAccountName, coins); err != nil { - panic(err) - } - - _ = keeper.bankKeeper.SendCoinsFromModuleToAccount(ctx, faucetAccountName, edAddr, coins) - - keeper.accountKeeper.SetAccount(ctx, baseAcct) - - edPubAccount := Account{ - private: edKey, - public: edPub, - address: edAddr, - acct: baseAcct, - } - AccountA := newAccount(ctx, keeper, privKeyA) - AccountB := newAccount(ctx, keeper, privKeyB) - - pubKeys := []crypto.PubKey{edPub, privKeyA.PubKey(), privKeyB.PubKey()} - accounts := []Account{edPubAccount, AccountA, AccountB} - multisigPubkey := generateMultisigAccountFromPublicKeys(ctx, keeper, pubKeys, 2) - - initMsg := `{"nop":{}}` - - msg := types.SecretMsg{ - CodeHash: []byte(codeHash), - Msg: []byte(initMsg), - } - - initMsgBz, err := wasmCtx.Encrypt(msg.Serialize()) - require.NoError(t, err) - - sdkMsg := types.MsgInstantiateContract{ - Sender: multisigPubkey.address.Bytes(), - // Admin: nil, - CodeID: codeID, - Label: "demo contract 1", - InitMsg: initMsgBz, - InitFunds: sdk.NewCoins(sdk.NewInt64Coin("denom", 0)), - } - - txConfig := authtx.NewTxConfig(nil, authtx.DefaultSignModes) - signModeHanler := txConfig.SignModeHandler() - builder := txConfig.NewTxBuilder() - builder.SetFeeAmount(nil) - builder.SetGasLimit(0) - builder.SetTimeoutHeight(0) - - _ = builder.SetMsgs(&sdkMsg) - - multiSignature := generateSignatures(t, signModeHanler, builder, multisigPubkey, accounts, 3) - - multisigAcc := keeper.accountKeeper.GetAccount(ctx, multisigPubkey.address.Bytes()) - signature := sdksigning.SignatureV2{ - PubKey: multisigPubkey.public, - Sequence: multisigAcc.GetSequence(), - Data: multiSignature, - } - err = builder.SetSignatures(signature) - require.NoError(t, err) - - tx := builder.(protoTxProvider) - txBytes, err := tx.GetProtoTx().Marshal() - require.NoError(t, err) - ctx = ctx.WithTxBytes(txBytes) - - _, _, err = keeper.Instantiate( - ctx, - codeID, - sdk.AccAddress(multisigPubkey.address), - /* nil, */ - initMsgBz, - "demo contract 1", - sdk.NewCoins(sdk.NewInt64Coin("denom", 0)), - nil, - ) - require.Error(t, err) - require.Contains(t, err.Error(), "failed to verify transaction signature") -} - -func TestWrongFundsNoFunds(t *testing.T) { - t.SkipNow() - ctx, keeper, codeID, codeHash, walletA, privKeyA, _, _ := setupTest(t, "./testdata/test-contract/contract.wasm", sdk.NewCoins()) - - initMsg := `{"nop":{}}` - - msg := types.SecretMsg{ - CodeHash: []byte(codeHash), - Msg: []byte(initMsg), - } - - initMsgBz, err := wasmCtx.Encrypt(msg.Serialize()) - require.NoError(t, err) - nonce := initMsgBz[0:32] - - ctx = PrepareInitSignedTx(t, keeper, ctx, walletA, privKeyA, initMsgBz, codeID, nil) - - _, _, err = keeper.Instantiate(ctx, codeID, walletA /* nil,*/, initMsgBz, "demo contract 1", sdk.NewCoins(sdk.NewInt64Coin("denom", 1000)), nil) - if err != nil { - err = extractInnerError(t, err, nonce, false, false) - } - require.Error(t, err) - require.Contains(t, err.Error(), "failed to verify transaction signature") -} - -func TestWrongFundsSomeFunds(t *testing.T) { - t.SkipNow() - ctx, keeper, codeID, codeHash, walletA, privKeyA, _, _ := setupTest(t, "./testdata/test-contract/contract.wasm", sdk.NewCoins()) - - initMsg := `{"nop":{}}` - - msg := types.SecretMsg{ - CodeHash: []byte(codeHash), - Msg: []byte(initMsg), - } - - initMsgBz, err := wasmCtx.Encrypt(msg.Serialize()) - require.NoError(t, err) - nonce := initMsgBz[0:32] - - ctx = PrepareInitSignedTx(t, keeper, ctx, walletA, privKeyA, initMsgBz, codeID, sdk.NewCoins(sdk.NewInt64Coin("denom", 200))) - - _, _, err = keeper.Instantiate(ctx, codeID, walletA /* nil,*/, initMsgBz, "demo contract 1", sdk.NewCoins(sdk.NewInt64Coin("denom", 1000)), nil) - if err != nil { - err = extractInnerError(t, err, nonce, false, false) - } - require.Error(t, err) - require.Contains(t, err.Error(), "failed to verify transaction signature") -} - -func TestWrongMessage(t *testing.T) { - t.SkipNow() - ctx, keeper, codeID, codeHash, walletA, privKeyA, _, _ := setupTest(t, "./testdata/test-contract/contract.wasm", sdk.NewCoins()) - - initMsg := `{"nop":{}}` - - msg := types.SecretMsg{ - CodeHash: []byte(codeHash), - Msg: []byte(initMsg), - } - - initMsgBz, err := wasmCtx.Encrypt(msg.Serialize()) - require.NoError(t, err) - nonce := initMsgBz[0:32] - - notTheRealMsg := `{"no_logs":{}}` - - notReallyTheMsg := types.SecretMsg{ - CodeHash: []byte(codeHash), - Msg: []byte(notTheRealMsg), - } - - notTheRealMsgBz, err := wasmCtx.Encrypt(notReallyTheMsg.Serialize()) - require.NoError(t, err) - - ctx = PrepareInitSignedTx(t, keeper, ctx, walletA, privKeyA, initMsgBz, codeID, nil) - - _, _, err = keeper.Instantiate(ctx, codeID, walletA /* nil, */, notTheRealMsgBz, "demo contract 1", sdk.NewCoins(sdk.NewInt64Coin("denom", 1000)), nil) - if err != nil { - err = extractInnerError(t, err, nonce, false, false) - } - require.Error(t, err) - require.Contains(t, err.Error(), "failed to verify transaction signature") -} - -func TestWrongContractAddress(t *testing.T) { - t.SkipNow() - ctx, keeper, codeID, codeHash, walletA, privKeyA, walletB, privKeyB := setupTest(t, "./testdata/erc20.wasm", sdk.NewCoins()) - - initMsg := fmt.Sprintf(`{"decimals":10,"initial_balances":[{"address":"%s","amount":"108"},{"address":"%s","amount":"53"}],"name":"ReuvenPersonalRustCoin","symbol":"RPRC"}`, walletA.String(), walletB.String()) - - _, _, contractAddress, _, stderr := initHelper(t, keeper, ctx, codeID, walletB, privKeyB, initMsg, true, false, defaultGasForTests) - require.Empty(t, stderr) - _, _, differentContractAddress, _, stderr := initHelper(t, keeper, ctx, codeID, walletB, privKeyB, initMsg, true, false, defaultGasForTests) - require.Empty(t, stderr) - - require.NotEqual(t, contractAddress, differentContractAddress) - - execMsg := fmt.Sprintf(`{"transfer":{"amount":"10","recipient":"%s"}}`, walletB.String()) - - msg := types.SecretMsg{ - CodeHash: []byte(codeHash), - Msg: []byte(execMsg), - } - - execMsgBz, err := wasmCtx.Encrypt(msg.Serialize()) - require.NoError(t, err) - nonce := execMsgBz[0:32] - - ctx = PrepareExecSignedTx(t, keeper, ctx, walletA, privKeyA, execMsgBz, contractAddress, sdk.NewCoins(sdk.NewInt64Coin("denom", 0))) - - _, err = keeper.Execute(ctx, differentContractAddress, walletA, execMsgBz, sdk.NewCoins(sdk.NewInt64Coin("denom", 0)), nil) - if err != nil { - err = extractInnerError(t, err, nonce, false, false) - } - require.Error(t, err) - require.Contains(t, err.Error(), "failed to verify transaction signature") -} diff --git a/x/compute/internal/keeper/querier.go b/x/compute/internal/keeper/querier.go index 5a30da3cf..712c624df 100644 --- a/x/compute/internal/keeper/querier.go +++ b/x/compute/internal/keeper/querier.go @@ -16,7 +16,7 @@ type GrpcQuerier struct { } // todo: this needs proper tests and doc -func NewQuerier(keeper Keeper) GrpcQuerier { +func NewGrpcQuerier(keeper Keeper) GrpcQuerier { return GrpcQuerier{keeper: keeper} } @@ -37,24 +37,6 @@ func (q GrpcQuerier) ContractInfo(c context.Context, req *types.QueryContractInf }, nil } -/* -func (q GrpcQuerier) ContractHistory(c context.Context, req *types.QueryContractHistoryRequest) (*types.QueryContractHistoryResponse, error) { - if err := sdk.VerifyAddressFormat(req.Address); err != nil { - return nil, err - } - rsp, err := queryContractHistory(sdk.UnwrapSDKContext(c), req.Address, q.keeper) - switch { - case err != nil: - return nil, err - case rsp == nil: - return nil, types.ErrNotFound - } - return &types.QueryContractHistoryResponse{ - Entries: rsp, - }, nil -} -*/ - func (q GrpcQuerier) ContractsByCode(c context.Context, req *types.QueryContractsByCodeRequest) (*types.QueryContractsByCodeResponse, error) { if req.CodeId == 0 { return nil, sdkerrors.Wrap(types.ErrInvalid, "code id") @@ -71,40 +53,6 @@ func (q GrpcQuerier) ContractsByCode(c context.Context, req *types.QueryContract }, nil } -/* -func (q GrpcQuerier) AllContractState(c context.Context, req *types.QueryAllContractStateRequest) (*types.QueryAllContractStateResponse, error) { - if err := sdk.VerifyAddressFormat(req.Address); err != nil { - return nil, err - } - ctx := sdk.UnwrapSDKContext(c) - if !q.keeper.containsContractInfo(ctx, req.Address) { - return nil, types.ErrNotFound - } - var resultData []types.Model - for iter := q.keeper.GetContractState(ctx, req.Address); iter.Valid(); iter.Next() { - resultData = append(resultData, types.Model{ - Key: iter.Key(), - Value: iter.Value(), - }) - } - return &types.QueryAllContractStateResponse{Models: resultData}, nil -} - -func (q GrpcQuerier) RawContractState(c context.Context, req *types.QueryRawContractStateRequest) (*types.QueryRawContractStateResponse, error) { - ctx := sdk.UnwrapSDKContext(c) - - if err := sdk.VerifyAddressFormat(req.Address); err != nil { - return nil, err - } - - if !q.keeper.containsContractInfo(ctx, req.Address) { - return nil, types.ErrNotFound - } - rsp := q.keeper.QueryRaw(ctx, req.Address, req.QueryData) - return &types.QueryRawContractStateResponse{Data: rsp}, nil -} -*/ - func (q GrpcQuerier) SmartContractState(c context.Context, req *types.QuerySmartContractStateRequest) (*types.QuerySmartContractStateResponse, error) { if err := sdk.VerifyAddressFormat(req.Address); err != nil { return nil, err @@ -233,17 +181,18 @@ func queryCode(ctx sdk.Context, codeID uint64, keeper Keeper) (*types.QueryCodeR if codeID == 0 { return nil, nil } - res := keeper.GetCodeInfo(ctx, codeID) - if res == nil { - // nil, nil leads to 404 in rest handler + + codeInfo, err := keeper.GetCodeInfo(ctx, codeID) + if err != nil { return nil, nil } + info := types.CodeInfoResponse{ CodeID: codeID, - Creator: res.Creator, - DataHash: res.CodeHash, - Source: res.Source, - Builder: res.Builder, + Creator: codeInfo.Creator, + DataHash: codeInfo.CodeHash, + Source: codeInfo.Source, + Builder: codeInfo.Builder, } code, err := keeper.GetByteCode(ctx, codeID) @@ -269,30 +218,6 @@ func queryCodeList(ctx sdk.Context, keeper Keeper) ([]types.CodeInfoResponse, er return info, nil } -/* -func queryContractHistory(ctx sdk.Context, bech string, keeper Keeper) ([]byte, error) { - contractAddr, err := sdk.AccAddressFromBech32(bech) - if err != nil { - return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, err.Error()) - } - entries := keeper.GetContractHistory(ctx, contractAddr) - if entries == nil { - // nil, nil leads to 404 in rest handler - return nil, nil - } - // redact response - for i := range entries { - entries[i].Updated = nil - } - - bz, err := json.MarshalIndent(entries, "", " ") - if err != nil { - return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) - } - return bz, nil -} -*/ - func queryContractAddress(ctx sdk.Context, label string, keeper Keeper) (sdk.AccAddress, error) { res := keeper.GetContractAddress(ctx, label) if res == nil { @@ -317,5 +242,10 @@ func queryContractHash(ctx sdk.Context, address sdk.AccAddress, keeper Keeper) ( return nil, nil } - return keeper.GetCodeInfo(ctx, res.CodeID).CodeHash, nil + codeInfo, err := keeper.GetCodeInfo(ctx, res.CodeID) + if err != nil { + return nil, nil + } + + return codeInfo.CodeHash, nil } diff --git a/x/compute/internal/keeper/querier_test.go b/x/compute/internal/keeper/querier_test.go index 2acd9b0a2..dfbfc13c8 100644 --- a/x/compute/internal/keeper/querier_test.go +++ b/x/compute/internal/keeper/querier_test.go @@ -48,7 +48,10 @@ func TestQueryContractLabel(t *testing.T) { initMsgBz, err := json.Marshal(initMsg) require.NoError(t, err) - hash := keeper.GetCodeInfo(ctx, contractID).CodeHash + codeInfo, err := keeper.GetCodeInfo(ctx, contractID) + require.NoError(t, err) + + hash := codeInfo.CodeHash msg := types.SecretMsg{ CodeHash: []byte(hex.EncodeToString(hash)), @@ -149,7 +152,10 @@ func TestQueryContractState(t *testing.T) { initMsgBz, err := json.Marshal(initMsg) require.NoError(t, err) - key := keeper.GetCodeInfo(ctx, contractID).CodeHash + codeInfo, err := keeper.GetCodeInfo(ctx, contractID) + require.NoError(t, err) + + key := codeInfo.CodeHash keyStr := hex.EncodeToString(key) msg := types.SecretMsg{ @@ -290,7 +296,10 @@ func TestListContractByCodeOrdering(t *testing.T) { initMsgBz, err := json.Marshal(initMsg) require.NoError(t, err) - key := keeper.GetCodeInfo(ctx, codeID).CodeHash + codeInfo, err := keeper.GetCodeInfo(ctx, codeID) + require.NoError(t, err) + + key := codeInfo.CodeHash keyStr := hex.EncodeToString(key) msg := types.SecretMsg{ diff --git a/x/compute/internal/keeper/query_plugins.go b/x/compute/internal/keeper/query_plugins.go index e96201191..b29aebcb0 100644 --- a/x/compute/internal/keeper/query_plugins.go +++ b/x/compute/internal/keeper/query_plugins.go @@ -2,10 +2,13 @@ package keeper import ( "encoding/json" + "fmt" "strings" + channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" "github.com/enigmampc/SecretNetwork/x/compute/internal/types" + "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/codec" bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" distrkeeper "github.com/cosmos/cosmos-sdk/x/distribution/keeper" @@ -22,9 +25,14 @@ import ( abci "github.com/tendermint/tendermint/abci/types" ) +type GRPCQueryRouter interface { + Route(path string) baseapp.GRPCQueryHandler +} + type QueryHandler struct { Ctx sdk.Context Plugins QueryPlugins + Caller sdk.AccAddress } var _ wasmTypes.Querier = QueryHandler{} @@ -61,6 +69,12 @@ func (q QueryHandler) Query(request wasmTypes.QueryRequest, gasLimit uint64) ([] if request.Gov != nil { return q.Plugins.Gov(q.Ctx, request.Gov) } + if request.IBC != nil { + return q.Plugins.IBC(q.Ctx, q.Caller, request.IBC) + } + if request.Stargate != nil { + return q.Plugins.Stargate(q.Ctx, request.Stargate) + } return nil, wasmTypes.Unknown{} } @@ -71,24 +85,28 @@ func (q QueryHandler) GasConsumed() uint64 { type CustomQuerier func(ctx sdk.Context, request json.RawMessage) ([]byte, error) type QueryPlugins struct { - Bank func(ctx sdk.Context, request *wasmTypes.BankQuery) ([]byte, error) - Custom CustomQuerier - Staking func(ctx sdk.Context, request *wasmTypes.StakingQuery) ([]byte, error) - Wasm func(ctx sdk.Context, request *wasmTypes.WasmQuery) ([]byte, error) - Dist func(ctx sdk.Context, request *wasmTypes.DistQuery) ([]byte, error) - Mint func(ctx sdk.Context, request *wasmTypes.MintQuery) ([]byte, error) - Gov func(ctx sdk.Context, request *wasmTypes.GovQuery) ([]byte, error) + Bank func(ctx sdk.Context, request *wasmTypes.BankQuery) ([]byte, error) + Custom CustomQuerier + Staking func(ctx sdk.Context, request *wasmTypes.StakingQuery) ([]byte, error) + Wasm func(ctx sdk.Context, request *wasmTypes.WasmQuery) ([]byte, error) + Dist func(ctx sdk.Context, request *wasmTypes.DistQuery) ([]byte, error) + Mint func(ctx sdk.Context, request *wasmTypes.MintQuery) ([]byte, error) + Gov func(ctx sdk.Context, request *wasmTypes.GovQuery) ([]byte, error) + IBC func(ctx sdk.Context, caller sdk.AccAddress, request *wasmTypes.IBCQuery) ([]byte, error) + Stargate func(ctx sdk.Context, request *wasmTypes.StargateQuery) ([]byte, error) } -func DefaultQueryPlugins(gov govkeeper.Keeper, dist distrkeeper.Keeper, mint mintkeeper.Keeper, bank bankkeeper.Keeper, staking stakingkeeper.Keeper, wasm *Keeper) QueryPlugins { +func DefaultQueryPlugins(gov govkeeper.Keeper, dist distrkeeper.Keeper, mint mintkeeper.Keeper, bank bankkeeper.Keeper, staking stakingkeeper.Keeper, stargateQueryRouter GRPCQueryRouter, wasm *Keeper, channelKeeper types.ChannelKeeper) QueryPlugins { return QueryPlugins{ - Bank: BankQuerier(bank), - Custom: NoCustomQuerier, - Staking: StakingQuerier(staking, dist), - Wasm: WasmQuerier(wasm), - Dist: DistQuerier(dist), - Mint: MintQuerier(mint), - Gov: GovQuerier(gov), + Bank: BankQuerier(bank), + Custom: NoCustomQuerier, + Staking: StakingQuerier(staking, dist), + Wasm: WasmQuerier(wasm), + Dist: DistQuerier(dist), + Mint: MintQuerier(mint), + Gov: GovQuerier(gov), + Stargate: StargateQuerier(stargateQueryRouter), + IBC: IBCQuerier(wasm, channelKeeper), } } @@ -118,9 +136,126 @@ func (e QueryPlugins) Merge(o *QueryPlugins) QueryPlugins { if o.Gov != nil { e.Gov = o.Gov } + if o.IBC != nil { + e.IBC = o.IBC + } + if o.Stargate != nil { + e.Stargate = o.Stargate + } return e } +// Assaf: stargateQueryAllowlist is a list of all safe and efficient queries +// +// excluded from this list (should be safe, but needs a clear use case): +// - /secret.registration.* +// - /ibc.core.* +// - /secret.intertx.* +// - /cosmos.evidence.* +// - /cosmos.upgrade.* +// +// we reserve the right to add/remove queries in future chain upgrades +// +// used this to find all query paths: +// find -name query.proto | sort | xargs grep -Poin 'package [a-z0-9.]+;|rpc [a-zA-Z]+\(' +var stargateQueryAllowlist = map[string]bool{ + "/cosmos.auth.v1beta1.Query/Account": true, + "/cosmos.auth.v1beta1.Query/Accounts": true, + "/cosmos.auth.v1beta1.Query/Params": true, + + "/cosmos.authz.v1beta1.Query/Grants": true, + "/cosmos.authz.v1beta1.Query/GranterGrants": true, + "/cosmos.authz.v1beta1.Query/GranteeGrants": true, + + "/cosmos.bank.v1beta1.Query/Balance": true, + "/cosmos.bank.v1beta1.Query/AllBalances": true, + "/cosmos.bank.v1beta1.Query/SpendableBalances": true, + "/cosmos.bank.v1beta1.Query/TotalSupply": true, + "/cosmos.bank.v1beta1.Query/SupplyOf": true, + "/cosmos.bank.v1beta1.Query/Params": true, + "/cosmos.bank.v1beta1.Query/DenomMetadata": true, + "/cosmos.bank.v1beta1.Query/DenomsMetadata": true, + + "/cosmos.distribution.v1beta1.Query/Params": true, + "/cosmos.distribution.v1beta1.Query/ValidatorOutstandingRewards": true, + "/cosmos.distribution.v1beta1.Query/ValidatorCommission": true, + "/cosmos.distribution.v1beta1.Query/ValidatorSlashes": true, + "/cosmos.distribution.v1beta1.Query/DelegationRewards": true, + "/cosmos.distribution.v1beta1.Query/DelegationTotalRewards": true, + "/cosmos.distribution.v1beta1.Query/DelegatorValidators": true, + "/cosmos.distribution.v1beta1.Query/DelegatorWithdrawAddress": true, + "/cosmos.distribution.v1beta1.Query/CommunityPool": true, + "/cosmos.distribution.v1beta1.Query/FoundationTax": true, + + "/cosmos.feegrant.v1beta1.Query/Allowance": true, + "/cosmos.feegrant.v1beta1.Query/Allowances": true, + + "/cosmos.gov.v1beta1.Query/Proposal": true, + "/cosmos.gov.v1beta1.Query/Proposals": true, + "/cosmos.gov.v1beta1.Query/Vote": true, + "/cosmos.gov.v1beta1.Query/Votes": true, + "/cosmos.gov.v1beta1.Query/Params": true, + "/cosmos.gov.v1beta1.Query/Deposit": true, + "/cosmos.gov.v1beta1.Query/Deposits": true, + "/cosmos.gov.v1beta1.Query/TallyResult": true, + + "/cosmos.mint.v1beta1.Query/Params": true, + "/cosmos.mint.v1beta1.Query/Inflation": true, + "/cosmos.mint.v1beta1.Query/AnnualProvisions": true, + + "/cosmos.params.v1beta1.Query/Params": true, + + "/cosmos.slashing.v1beta1.Query/Params": true, + "/cosmos.slashing.v1beta1.Query/SigningInfo": true, + "/cosmos.slashing.v1beta1.Query/SigningInfos": true, + + "/cosmos.staking.v1beta1.Query/Validators": true, + "/cosmos.staking.v1beta1.Query/Validator": true, + "/cosmos.staking.v1beta1.Query/ValidatorDelegations": true, + "/cosmos.staking.v1beta1.Query/ValidatorUnbondingDelegations": true, + "/cosmos.staking.v1beta1.Query/Delegation": true, + "/cosmos.staking.v1beta1.Query/UnbondingDelegation": true, + "/cosmos.staking.v1beta1.Query/DelegatorDelegations": true, + "/cosmos.staking.v1beta1.Query/DelegatorUnbondingDelegations": true, + "/cosmos.staking.v1beta1.Query/Redelegations": true, + "/cosmos.staking.v1beta1.Query/DelegatorValidators": true, + "/cosmos.staking.v1beta1.Query/DelegatorValidator": true, + "/cosmos.staking.v1beta1.Query/HistoricalInfo": true, + "/cosmos.staking.v1beta1.Query/Pool": true, + "/cosmos.staking.v1beta1.Query/Params": true, + + "/ibc.applications.transfer.v1.Query/DenomTrace": true, + "/ibc.applications.transfer.v1.Query/DenomTraces": true, + "/ibc.applications.transfer.v1.Query/Params": true, + "/ibc.applications.transfer.v1.Query/DenomHash": true, + + "/secret.compute.v1beta1.Query/ContractInfo": true, + "/secret.compute.v1beta1.Query/ContractsByCode": true, + "/secret.compute.v1beta1.Query/Codes": true, +} + +func StargateQuerier(queryRouter GRPCQueryRouter) func(ctx sdk.Context, request *wasmTypes.StargateQuery) ([]byte, error) { + return func(ctx sdk.Context, msg *wasmTypes.StargateQuery) ([]byte, error) { + if !stargateQueryAllowlist[msg.Path] { + return nil, wasmTypes.UnsupportedRequest{Kind: fmt.Sprintf("query path '%s' is not allowed from the contract", msg.Path)} + } + + route := queryRouter.Route(msg.Path) + if route == nil { + return nil, wasmTypes.UnsupportedRequest{Kind: fmt.Sprintf("No route to query path '%s'", msg.Path)} + } + req := abci.RequestQuery{ + Data: msg.Data, + Path: msg.Path, + } + res, err := route(ctx, req) + if err != nil { + return nil, err + } + return res.Value, nil + } +} + func GovQuerier(keeper govkeeper.Keeper) func(ctx sdk.Context, request *wasmTypes.GovQuery) ([]byte, error) { return func(ctx sdk.Context, request *wasmTypes.GovQuery) ([]byte, error) { if request.Proposals != nil { @@ -149,6 +284,77 @@ func GovQuerier(keeper govkeeper.Keeper) func(ctx sdk.Context, request *wasmType } } +func IBCQuerier(wasm *Keeper, channelKeeper types.ChannelKeeper) func(ctx sdk.Context, caller sdk.AccAddress, request *wasmTypes.IBCQuery) ([]byte, error) { + return func(ctx sdk.Context, caller sdk.AccAddress, request *wasmTypes.IBCQuery) ([]byte, error) { + if request.PortID != nil { + contractInfo := wasm.GetContractInfo(ctx, caller) + res := wasmTypes.PortIDResponse{ + PortID: contractInfo.IBCPortID, + } + return json.Marshal(res) + } + if request.ListChannels != nil { + portID := request.ListChannels.PortID + channels := make(wasmTypes.IBCChannels, 0) + channelKeeper.IterateChannels(ctx, func(ch channeltypes.IdentifiedChannel) bool { + // it must match the port and be in open state + if (portID == "" || portID == ch.PortId) && ch.State == channeltypes.OPEN { + newChan := wasmTypes.IBCChannel{ + Endpoint: wasmTypes.IBCEndpoint{ + PortID: ch.PortId, + ChannelID: ch.ChannelId, + }, + CounterpartyEndpoint: wasmTypes.IBCEndpoint{ + PortID: ch.Counterparty.PortId, + ChannelID: ch.Counterparty.ChannelId, + }, + Order: ch.Ordering.String(), + Version: ch.Version, + ConnectionID: ch.ConnectionHops[0], + } + channels = append(channels, newChan) + } + return false + }) + res := wasmTypes.ListChannelsResponse{ + Channels: channels, + } + return json.Marshal(res) + } + if request.Channel != nil { + channelID := request.Channel.ChannelID + portID := request.Channel.PortID + if portID == "" { + contractInfo := wasm.GetContractInfo(ctx, caller) + portID = contractInfo.IBCPortID + } + got, found := channelKeeper.GetChannel(ctx, portID, channelID) + var channel *wasmTypes.IBCChannel + // it must be in open state + if found && got.State == channeltypes.OPEN { + channel = &wasmTypes.IBCChannel{ + Endpoint: wasmTypes.IBCEndpoint{ + PortID: portID, + ChannelID: channelID, + }, + CounterpartyEndpoint: wasmTypes.IBCEndpoint{ + PortID: got.Counterparty.PortId, + ChannelID: got.Counterparty.ChannelId, + }, + Order: got.Ordering.String(), + Version: got.Version, + ConnectionID: got.ConnectionHops[0], + } + } + res := wasmTypes.ChannelResponse{ + Channel: channel, + } + return json.Marshal(res) + } + return nil, wasmTypes.UnsupportedRequest{Kind: "unknown IBCQuery variant"} + } +} + func MintQuerier(keeper mintkeeper.Keeper) func(ctx sdk.Context, request *wasmTypes.MintQuery) ([]byte, error) { return func(ctx sdk.Context, request *wasmTypes.MintQuery) ([]byte, error) { if request.BondedRatio != nil { @@ -352,6 +558,40 @@ func StakingQuerier(keeper stakingkeeper.Keeper, distKeeper distrkeeper.Keeper) return json.Marshal(res) } + if request.Validator != nil { + valAddr, err := sdk.ValAddressFromBech32(request.Validator.Address) + if err != nil { + return nil, err + } + v, found := keeper.GetValidator(ctx, valAddr) + res := wasmTypes.ValidatorResponse{} + if found { + res.Validator = &wasmTypes.Validator{ + Address: v.OperatorAddress, + Commission: v.Commission.Rate.String(), + MaxCommission: v.Commission.MaxRate.String(), + MaxChangeRate: v.Commission.MaxChangeRate.String(), + } + } + return json.Marshal(res) + } + if request.AllValidators != nil { + validators := keeper.GetBondedValidatorsByPower(ctx) + // validators := keeper.GetAllValidators(ctx) + wasmVals := make([]wasmTypes.Validator, len(validators)) + for i, v := range validators { + wasmVals[i] = wasmTypes.Validator{ + Address: v.OperatorAddress, + Commission: v.Commission.Rate.String(), + MaxCommission: v.Commission.MaxRate.String(), + MaxChangeRate: v.Commission.MaxChangeRate.String(), + } + } + res := wasmTypes.AllValidatorsResponse{ + Validators: wasmVals, + } + return json.Marshal(res) + } return nil, wasmTypes.UnsupportedRequest{Kind: "unknown Staking variant"} } } diff --git a/x/compute/internal/keeper/recurse_test.go b/x/compute/internal/keeper/recurse_test.go index 7c7467810..11d8721cd 100644 --- a/x/compute/internal/keeper/recurse_test.go +++ b/x/compute/internal/keeper/recurse_test.go @@ -155,7 +155,10 @@ func TestGasCostOnQuery(t *testing.T) { recurse := tc.msg recurse.Contract = contractAddr - msg := buildQuery(t, recurse, hex.EncodeToString(keeper.GetContractHash(ctx, contractAddr))) + codeHash, err := keeper.GetContractHash(ctx, contractAddr) + require.NoError(t, err) + + msg := buildQuery(t, recurse, hex.EncodeToString(codeHash)) data, qErr := queryHelper(t, keeper, ctx, contractAddr, string(msg), true, false, tc.gasLimit) require.Empty(t, qErr) @@ -169,7 +172,7 @@ func TestGasCostOnQuery(t *testing.T) { // assert result is 32 byte sha256 hash (if hashed), or contractAddr if not var resp recurseResponse - err := json.Unmarshal([]byte(data), &resp) + err = json.Unmarshal([]byte(data), &resp) require.NoError(t, err) if recurse.Work == 0 { assert.Equal(t, len(resp.Hashed), len(creator.String())) @@ -233,14 +236,18 @@ func TestGasOnExternalQuery(t *testing.T) { recurse := tc.msg recurse.Contract = contractAddr - msg := buildQuery(t, recurse, hex.EncodeToString(keeper.GetContractHash(ctx, contractAddr))) + + codeHash, err := keeper.GetContractHash(ctx, contractAddr) + require.NoError(t, err) + + msg := buildQuery(t, recurse, hex.EncodeToString(codeHash)) secretMsg := types.SecretMsg{ - CodeHash: []byte(hex.EncodeToString(keeper.GetContractHash(ctx, contractAddr))), + CodeHash: []byte(hex.EncodeToString(codeHash)), Msg: msg, } - msg, err := wasmCtx.Encrypt(secretMsg.Serialize()) + msg, err = wasmCtx.Encrypt(secretMsg.Serialize()) require.NoError(t, err) // do the query @@ -349,7 +356,11 @@ func TestLimitRecursiveQueryGas(t *testing.T) { // prepare the query recurse := tc.msg recurse.Contract = contractAddr - msg := buildQuery(t, recurse, hex.EncodeToString(keeper.GetContractHash(ctx, contractAddr))) + + codeHash, err := keeper.GetContractHash(ctx, contractAddr) + require.NoError(t, err) + + msg := buildQuery(t, recurse, hex.EncodeToString(codeHash)) // if we expect out of gas, make sure this panics if tc.expectOutOfGas { diff --git a/x/compute/internal/keeper/relay.go b/x/compute/internal/keeper/relay.go new file mode 100644 index 000000000..2bef5b8e7 --- /dev/null +++ b/x/compute/internal/keeper/relay.go @@ -0,0 +1,295 @@ +package keeper + +import ( + "encoding/json" + "fmt" + "time" + + "github.com/cosmos/cosmos-sdk/telemetry" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + sdktxsigning "github.com/cosmos/cosmos-sdk/types/tx/signing" + wasmTypes "github.com/enigmampc/SecretNetwork/go-cosmwasm/types" + v1types "github.com/enigmampc/SecretNetwork/go-cosmwasm/types/v1" + + "github.com/enigmampc/SecretNetwork/x/compute/internal/types" +) + +var _ types.IBCContractKeeper = (*Keeper)(nil) + +func (k Keeper) ibcContractCall(ctx sdk.Context, + contractAddress sdk.AccAddress, + msgBz []byte, + callType wasmTypes.HandleType, +) (interface{}, error) { + verificationInfo := types.NewVerificationInfo([]byte{}, sdktxsigning.SignMode_SIGN_MODE_UNSPECIFIED, []byte{}, []byte{}, []byte{}, nil) + + _, codeInfo, prefixStore, err := k.contractInstance(ctx, contractAddress) + if err != nil { + return "", err + } + + store := ctx.KVStore(k.storeKey) + + contractKey := store.Get(types.GetContractEnclaveKey(contractAddress)) + env := types.NewEnv( + ctx, + sdk.AccAddress{}, /* there's no MessageInfo for IBC contract calls */ + sdk.NewCoins(), /* there's no MessageInfo for IBC contract calls */ + contractAddress, + contractKey, + ) + + // prepare querier + querier := QueryHandler{ + Ctx: ctx, + Plugins: k.queryPlugins, + } + + gas := gasForContract(ctx) + res, gasUsed, err := k.wasmer.Execute(codeInfo.CodeHash, env, msgBz, prefixStore, cosmwasmAPI, querier, ctx.GasMeter(), gas, verificationInfo, callType) + consumeGas(ctx, gasUsed) + + return res, err +} + +func (k Keeper) parseThenHandleIBCBasicContractResponse(ctx sdk.Context, + contractAddress sdk.AccAddress, + inputMsg []byte, + res interface{}, +) error { + switch resp := res.(type) { + case *v1types.IBCBasicResponse: + if resp != nil { + contractInfo, _, _, err := k.contractInstance(ctx, contractAddress) + if err != nil { + return err + } + + return k.handleIBCBasicContractResponse(ctx, contractAddress, contractInfo.IBCPortID, inputMsg, resp) + } + + return sdkerrors.Wrap(types.ErrExecuteFailed, fmt.Sprintf("null pointer IBCBasicResponse: %+v", res)) + default: + return sdkerrors.Wrap(types.ErrExecuteFailed, fmt.Sprintf("cannot cast res to IBCBasicResponse: %+v", res)) + } +} + +// OnOpenChannel calls the contract to participate in the IBC channel handshake step. +// In the IBC protocol this is either the `Channel Open Init` event on the initiating chain or +// `Channel Open Try` on the counterparty chain. +// Protocol version and channel ordering should be verified for example. +// See https://github.com/cosmos/ics/tree/master/spec/ics-004-channel-and-packet-semantics#channel-lifecycle-management +func (k Keeper) OnOpenChannel( + ctx sdk.Context, + contractAddress sdk.AccAddress, + msg v1types.IBCChannelOpenMsg, +) (string, error) { + defer telemetry.MeasureSince(time.Now(), "compute", "keeper", "ibc-open-channel") + + ctx.GasMeter().ConsumeGas(types.InstanceCost, "Loading Compute module: ibc-open-channel") + + msgBz, err := json.Marshal(msg) + if err != nil { + return "", sdkerrors.Wrap(err, "ibc-open-channel") + } + + res, err := k.ibcContractCall(ctx, contractAddress, msgBz, wasmTypes.HandleTypeIbcChannelOpen) + if err != nil { + return "", sdkerrors.Wrap(types.ErrExecuteFailed, err.Error()) + } + + switch resp := res.(type) { + case *string: + return *resp, nil + default: + return "", sdkerrors.Wrap(types.ErrExecuteFailed, fmt.Sprintf("ibc-open-channel: cannot cast res to IBC3ChannelOpenResponse: %+v", res)) + } +} + +// OnConnectChannel calls the contract to let it know the IBC channel was established. +// In the IBC protocol this is either the `Channel Open Ack` event on the initiating chain or +// `Channel Open Confirm` on the counterparty chain. +// +// There is an open issue with the [cosmos-sdk](https://github.com/cosmos/cosmos-sdk/issues/8334) +// that the counterparty channelID is empty on the initiating chain +// See https://github.com/cosmos/ics/tree/master/spec/ics-004-channel-and-packet-semantics#channel-lifecycle-management +func (k Keeper) OnConnectChannel( + ctx sdk.Context, + contractAddress sdk.AccAddress, + msg v1types.IBCChannelConnectMsg, +) error { + defer telemetry.MeasureSince(time.Now(), "compute", "keeper", "ibc-connect-channel") + + ctx.GasMeter().ConsumeGas(types.InstanceCost, "Loading Compute module: ibc-connect-channel") + + msgBz, err := json.Marshal(msg) + if err != nil { + return sdkerrors.Wrap(err, "ibc-connect-channel") + } + + res, err := k.ibcContractCall(ctx, contractAddress, msgBz, wasmTypes.HandleTypeIbcChannelConnect) + if err != nil { + return sdkerrors.Wrap(types.ErrExecuteFailed, err.Error()) + } + err = k.parseThenHandleIBCBasicContractResponse(ctx, contractAddress, msgBz, res) + if err != nil { + return sdkerrors.Wrap(err, "ibc-connect-channel") + } + return nil +} + +// OnCloseChannel calls the contract to let it know the IBC channel is closed. +// Calling modules MAY atomically execute appropriate application logic in conjunction with calling chanCloseConfirm. +// +// Once closed, channels cannot be reopened and identifiers cannot be reused. Identifier reuse is prevented because +// we want to prevent potential replay of previously sent packets +// See https://github.com/cosmos/ics/tree/master/spec/ics-004-channel-and-packet-semantics#channel-lifecycle-management +func (k Keeper) OnCloseChannel( + ctx sdk.Context, + contractAddress sdk.AccAddress, + msg v1types.IBCChannelCloseMsg, +) error { + defer telemetry.MeasureSince(time.Now(), "compute", "keeper", "ibc-close-channel") + + ctx.GasMeter().ConsumeGas(types.InstanceCost, "Loading Compute module: ibc-close-channel") + + msgBz, err := json.Marshal(msg) + if err != nil { + return sdkerrors.Wrap(err, "ibc-close-channel") + } + + res, err := k.ibcContractCall(ctx, contractAddress, msgBz, wasmTypes.HandleTypeIbcChannelClose) + if err != nil { + return sdkerrors.Wrap(types.ErrExecuteFailed, err.Error()) + } + + err = k.parseThenHandleIBCBasicContractResponse(ctx, contractAddress, msgBz, res) + if err != nil { + sdkerrors.Wrap(err, "ibc-close-channel") + } + return nil +} + +// OnRecvPacket calls the contract to process the incoming IBC packet. The contract fully owns the data processing and +// returns the acknowledgement data for the chain level. This allows custom applications and protocols on top +// of IBC. Although it is recommended to use the standard acknowledgement envelope defined in +// https://github.com/cosmos/ics/tree/master/spec/ics-004-channel-and-packet-semantics#acknowledgement-envelope +// +// For more information see: https://github.com/cosmos/ics/tree/master/spec/ics-004-channel-and-packet-semantics#packet-flow--handling +func (k Keeper) OnRecvPacket( + ctx sdk.Context, + contractAddress sdk.AccAddress, + msg v1types.IBCPacketReceiveMsg, +) ([]byte, error) { + defer telemetry.MeasureSince(time.Now(), "compute", "keeper", "ibc-recv-packet") + + ctx.GasMeter().ConsumeGas(types.InstanceCost, "Loading Compute module: ibc-recv-packet") + + msgBz, err := json.Marshal(msg) + if err != nil { + return nil, sdkerrors.Wrap(err, "ibc-recv-packet") + } + + res, err := k.ibcContractCall(ctx, contractAddress, msgBz, wasmTypes.HandleTypeIbcPacketReceive) + if err != nil { + return nil, sdkerrors.Wrap(types.ErrExecuteFailed, err.Error()) + } + + switch resp := res.(type) { + case *v1types.IBCReceiveResponse: + if resp != nil { + contractInfo, _, _, err := k.contractInstance(ctx, contractAddress) + if err != nil { + return nil, err + } + verificationInfo := types.NewVerificationInfo([]byte{}, sdktxsigning.SignMode_SIGN_MODE_DIRECT, []byte{}, []byte{}, []byte{}, nil) + + ogTx := msg.Packet.Data + + // If the data contains less than 64 bytes (means plaintext) + // use the whole message just for compilation + if len(ogTx) < 64 { + ogTx = msgBz + } + + // note submessage reply results can overwrite the `Acknowledgement` data + return k.handleContractResponse(ctx, contractAddress, contractInfo.IBCPortID, resp.Messages, resp.Attributes, resp.Events, resp.Acknowledgement, ogTx, verificationInfo, wasmTypes.CosmosMsgVersionV1) + } + + // should never get here as it's already checked in + // https://github.com/scrtlabs/SecretNetwork/blob/bd46776c/go-cosmwasm/lib.go#L358 + return nil, sdkerrors.Wrap(types.ErrExecuteFailed, fmt.Sprintf("ibc-recv-packet: null pointer IBCReceiveResponse: %+v", res)) + default: + return nil, sdkerrors.Wrap(types.ErrExecuteFailed, fmt.Sprintf("ibc-recv-packet: cannot cast res to IBCReceiveResponse: %+v", res)) + } +} + +// OnAckPacket calls the contract to handle the "acknowledgement" data which can contain success or failure of a packet +// acknowledgement written on the receiving chain for example. This is application level data and fully owned by the +// contract. The use of the standard acknowledgement envelope is recommended: https://github.com/cosmos/ics/tree/master/spec/ics-004-channel-and-packet-semantics#acknowledgement-envelope +// +// On application errors the contract can revert an operation like returning tokens as in ibc-transfer. +// +// For more information see: https://github.com/cosmos/ics/tree/master/spec/ics-004-channel-and-packet-semantics#packet-flow--handling +func (k Keeper) OnAckPacket( + ctx sdk.Context, + contractAddress sdk.AccAddress, + msg v1types.IBCPacketAckMsg, +) error { + defer telemetry.MeasureSince(time.Now(), "compute", "keeper", "ibc-ack-packet") + + ctx.GasMeter().ConsumeGas(types.InstanceCost, "Loading Compute module: ibc-ack-packet") + + msgBz, err := json.Marshal(msg) + if err != nil { + return sdkerrors.Wrap(err, "ibc-ack-packet") + } + + res, err := k.ibcContractCall(ctx, contractAddress, msgBz, wasmTypes.HandleTypeIbcPacketAck) + if err != nil { + return sdkerrors.Wrap(types.ErrExecuteFailed, err.Error()) + } + + err = k.parseThenHandleIBCBasicContractResponse(ctx, contractAddress, msgBz, res) + if err != nil { + return sdkerrors.Wrap(err, "ibc-ack-packet") + } + return nil +} + +// OnTimeoutPacket calls the contract to let it know the packet was never received on the destination chain within +// the timeout boundaries. +// The contract should handle this on the application level and undo the original operation +func (k Keeper) OnTimeoutPacket( + ctx sdk.Context, + contractAddress sdk.AccAddress, + msg v1types.IBCPacketTimeoutMsg, +) error { + defer telemetry.MeasureSince(time.Now(), "compute", "keeper", "ibc-timeout-packet") + + ctx.GasMeter().ConsumeGas(types.InstanceCost, "Loading Compute module: ibc-timeout-packet") + + msgBz, err := json.Marshal(msg) + if err != nil { + return sdkerrors.Wrap(err, "ibc-timeout-packet") + } + + res, err := k.ibcContractCall(ctx, contractAddress, msgBz, wasmTypes.HandleTypeIbcPacketTimeout) + if err != nil { + return sdkerrors.Wrap(types.ErrExecuteFailed, err.Error()) + } + + err = k.parseThenHandleIBCBasicContractResponse(ctx, contractAddress, msgBz, res) + if err != nil { + return sdkerrors.Wrap(err, "ibc-timeout-packet") + } + return nil +} + +func (k Keeper) handleIBCBasicContractResponse(ctx sdk.Context, addr sdk.AccAddress, ibcPortID string, inputMsg []byte, res *v1types.IBCBasicResponse) error { + verificationInfo := types.NewVerificationInfo([]byte{}, sdktxsigning.SignMode_SIGN_MODE_UNSPECIFIED, []byte{}, []byte{}, []byte{}, nil) + + _, err := k.handleContractResponse(ctx, addr, ibcPortID, res.Messages, res.Attributes, res.Events, nil, inputMsg, verificationInfo, wasmTypes.CosmosMsgVersionV1) + return err +} diff --git a/x/compute/internal/keeper/secret_contracts_test.go b/x/compute/internal/keeper/secret_contracts_test.go index d96b25c6c..733eab829 100644 --- a/x/compute/internal/keeper/secret_contracts_test.go +++ b/x/compute/internal/keeper/secret_contracts_test.go @@ -53,10 +53,17 @@ var testContracts = []TestContract{ // if codeID isn't 0, it will try to use that. Otherwise will take the contractAddress func testEncrypt(t *testing.T, keeper Keeper, ctx sdk.Context, contractAddress sdk.AccAddress, codeId uint64, msg []byte) ([]byte, error) { var hash []byte + var err error + if codeId != 0 { - hash = keeper.GetCodeInfo(ctx, codeId).CodeHash + codeInfo, err := keeper.GetCodeInfo(ctx, codeId) + require.NoError(t, err) + + hash = codeInfo.CodeHash } else { - hash = keeper.GetContractHash(ctx, contractAddress) + hash, err = keeper.GetContractHash(ctx, contractAddress) + require.NoError(t, err) + } if hash == nil { @@ -81,7 +88,10 @@ func uploadCode(ctx sdk.Context, t *testing.T, keeper Keeper, wasmPath string, w codeID, err := keeper.Create(ctx, walletA, wasmCode, "", "") require.NoError(t, err) - codeHash := hex.EncodeToString(keeper.GetCodeInfo(ctx, codeID).CodeHash) + codeInfo, err := keeper.GetCodeInfo(ctx, codeID) + require.NoError(t, err) + + codeHash := hex.EncodeToString(codeInfo.CodeHash) return codeID, codeHash } @@ -157,7 +167,7 @@ func decryptAttribute(attr v010cosmwasm.LogAttribute, nonce []byte) (v010cosmwas } keyPlainBz, err := wasmCtx.Decrypt(keyCipherBz, nonce) if err != nil { - return v010cosmwasm.LogAttribute{}, fmt.Errorf("Failed Decrypt for key %+v", keyPlainBz) + return v010cosmwasm.LogAttribute{}, fmt.Errorf("Failed Decrypt for key %+v", keyCipherBz) } newAttr.Key = string(keyPlainBz) @@ -400,7 +410,10 @@ func queryHelperImpl( contractAddr sdk.AccAddress, input string, isErrorEncrypted bool, isV1Contract bool, gas uint64, wasmCallCount int64, ) (string, cosmwasm.StdError) { - hashStr := hex.EncodeToString(keeper.GetContractHash(ctx, contractAddr)) + hash, err := keeper.GetContractHash(ctx, contractAddr) + require.NoError(t, err) + + hashStr := hex.EncodeToString(hash) msg := types.SecretMsg{ CodeHash: []byte(hashStr), @@ -473,7 +486,10 @@ func execHelperMultipleCoinsImpl( contractAddress sdk.AccAddress, txSender sdk.AccAddress, senderPrivKey crypto.PrivKey, execMsg string, isErrorEncrypted bool, isV1Contract bool, gas uint64, coins sdk.Coins, wasmCallCount int64, shouldSkipAttributes ...bool, ) ([]byte, sdk.Context, []byte, []ContractEvent, uint64, cosmwasm.StdError) { - hashStr := hex.EncodeToString(keeper.GetContractHash(ctx, contractAddress)) + hash, err := keeper.GetContractHash(ctx, contractAddress) + require.NoError(t, err) + + hashStr := hex.EncodeToString(hash) msg := types.SecretMsg{ CodeHash: []byte(hashStr), @@ -537,7 +553,10 @@ func initHelperImpl( codeID uint64, creator sdk.AccAddress, creatorPrivKey crypto.PrivKey, initMsg string, isErrorEncrypted bool, isV1Contract bool, gas uint64, wasmCallCount int64, sentFunds sdk.Coins, shouldSkipAttributes ...bool, ) ([]byte, sdk.Context, sdk.AccAddress, []ContractEvent, cosmwasm.StdError) { - hashStr := hex.EncodeToString(keeper.GetCodeInfo(ctx, codeID).CodeHash) + codeInfo, err := keeper.GetCodeInfo(ctx, codeID) + require.NoError(t, err) + + hashStr := hex.EncodeToString(codeInfo.CodeHash) msg := types.SecretMsg{ CodeHash: []byte(hashStr), @@ -582,6 +601,33 @@ func initHelperImpl( return nonce, ctx, contractAddress, wasmEvents, cosmwasm.StdError{} } +// requireEvents checks events output +// Events are now sorted (since wasmd v0.28), +// but for us they're sorted while encrypted so when testing with random encryption keys +// this is non-deterministic +func requireEvents(t *testing.T, a, b []ContractEvent) { + require.Equal(t, len(a), len(b)) + + for i := range b { + require.Equal(t, len(a[i]), len(b[i])) + for j := range b[i] { + require.Contains(t, a[i], b[i][j]) + } + } +} + +// requireLogAttributes checks events output +// Events are now sorted (since wasmd v0.28), +// but for us they're sorted while encrypted so when testing with random encryption keys +// this is non-deterministic +func requireLogAttributes(t *testing.T, a, b []v010cosmwasm.LogAttribute) { + require.Equal(t, len(a), len(b)) + + for i := range b { + require.Contains(t, a, b[i]) + } +} + func TestCallbackSanity(t *testing.T) { for _, testContract := range testContracts { t.Run(testContract.CosmWasmVersion, func(t *testing.T) { @@ -591,35 +637,37 @@ func TestCallbackSanity(t *testing.T) { _, _, contractAddress, initEvents, err := initHelper(t, keeper, ctx, codeID, walletA, privKeyA, `{"nop":{}}`, true, testContract.IsCosmWasmV1, defaultGasForTests) require.Empty(t, err) - require.Equal(t, + requireEvents(t, + initEvents, []ContractEvent{ { {Key: "contract_address", Value: contractAddress.String()}, {Key: "init", Value: "🌈"}, }, }, - initEvents, ) _, _, data, execEvents, _, err := execHelper(t, keeper, ctx, contractAddress, walletA, privKeyA, fmt.Sprintf(`{"a":{"contract_addr":"%s","code_hash":"%s","x":2,"y":3}}`, contractAddress.String(), codeHash), true, testContract.IsCosmWasmV1, defaultGasForTests, 0) require.Empty(t, err) - require.Equal(t, + + requireEvents(t, []ContractEvent{ { {Key: "contract_address", Value: contractAddress.String()}, {Key: "banana", Value: "🍌"}, }, { - {Key: "contract_address", Value: contractAddress.String()}, {Key: "kiwi", Value: "🥝"}, + {Key: "contract_address", Value: contractAddress.String()}, }, { - {Key: "contract_address", Value: contractAddress.String()}, {Key: "watermelon", Value: "🍉"}, + {Key: "contract_address", Value: contractAddress.String()}, }, }, execEvents, ) + require.Equal(t, []byte{2, 3}, data) }) } @@ -650,7 +698,7 @@ func TestSanity(t *testing.T) { require.Empty(t, err) require.Empty(t, data) - require.Equal(t, + requireEvents(t, []ContractEvent{ { {Key: "contract_address", Value: contractAddress.String()}, @@ -680,7 +728,7 @@ func TestInitLogs(t *testing.T) { _, _, contractAddress, initEvents, initErr := initHelper(t, keeper, ctx, codeID, walletA, privKeyA, `{"nop":{}}`, true, testContract.IsCosmWasmV1, defaultGasForTests) require.Empty(t, initErr) require.Equal(t, 1, len(initEvents)) - require.Equal(t, + requireEvents(t, []ContractEvent{ { {Key: "contract_address", Value: contractAddress.String()}, @@ -704,7 +752,7 @@ func TestEmptyLogKeyValue(t *testing.T) { _, _, _, execEvents, _, execErr := execHelper(t, keeper, ctx, contractAddress, walletA, privKeyA, `{"empty_log_key_value":{}}`, true, testContract.IsCosmWasmV1, defaultGasForTests, 0) require.Empty(t, execErr) - require.Equal(t, + requireEvents(t, []ContractEvent{ { {Key: "contract_address", Value: contractAddress.String()}, @@ -796,7 +844,7 @@ func TestCallbackFromInitAndCallbackEvents(t *testing.T) { _, _, firstContractAddress, initEvents, initErr := initHelper(t, keeper, ctx, codeID, walletA, privKeyA, `{"nop":{}}`, true, testContract.IsCosmWasmV1, defaultGasForTests) require.Empty(t, initErr) - require.Equal(t, + requireEvents(t, []ContractEvent{ { {Key: "contract_address", Value: firstContractAddress.String()}, @@ -810,7 +858,7 @@ func TestCallbackFromInitAndCallbackEvents(t *testing.T) { _, _, contractAddress, initEvents, initErr := initHelper(t, keeper, ctx, codeID, walletA, privKeyA, fmt.Sprintf(`{"callback":{"contract_addr":"%s", "code_hash": "%s"}}`, firstContractAddress.String(), codeHash), true, testContract.IsCosmWasmV1, defaultGasForTests) require.Empty(t, initErr) - require.Equal(t, + requireEvents(t, []ContractEvent{ { {Key: "contract_address", Value: contractAddress.String()}, @@ -1232,33 +1280,6 @@ func TestInitNotEncryptedInputError(t *testing.T) { } } -func TestExecuteNotEncryptedInputError(t *testing.T) { - for _, testContract := range testContracts { - t.Run(testContract.CosmWasmVersion, func(t *testing.T) { - ctx, keeper, codeID, _, walletA, privKeyA, _, _ := setupTest(t, testContract.WasmFilePath, sdk.NewCoins()) - - _, _, contractAddress, _, initErr := initHelper(t, keeper, ctx, codeID, walletA, privKeyA, `{"nop":{}}`, true, testContract.IsCosmWasmV1, defaultGasForTests) - require.Empty(t, initErr) - - //ctx = sdk.NewContext( - // ctx.MultiStore(), - // ctx.BlockHeader(), - // ctx.IsCheckTx(), - // log.NewNopLogger(), - //).WithGasMeter(sdk.NewGasMeter(defaultGas)) - - execMsg := []byte(`{"empty_log_key_value":{}}`) - - ctx = PrepareExecSignedTx(t, keeper, ctx, walletA, privKeyA, execMsg, contractAddress, nil) - - _, err := keeper.Execute(ctx, contractAddress, walletA, execMsg, sdk.NewCoins(sdk.NewInt64Coin("denom", 0)), nil) - require.Error(t, err) - - require.Contains(t, err.Error(), "failed to decrypt data") - }) - } -} - func TestQueryNotEncryptedInputError(t *testing.T) { for _, testContract := range testContracts { t.Run(testContract.CosmWasmVersion, func(t *testing.T) { @@ -1321,20 +1342,25 @@ func TestExecCallbackToInit(t *testing.T) { require.Empty(t, execData) require.Equal(t, 2, len(execEvents)) - require.Equal(t, + requireLogAttributes(t, ContractEvent{ {Key: "contract_address", Value: contractAddress.String()}, {Key: "instantiating a new contract", Value: "🪂"}, }, execEvents[0], ) - require.Equal(t, + require.Contains(t, + execEvents[1], v010cosmwasm.LogAttribute{Key: "init", Value: "🌈"}, - execEvents[1][1], ) - require.Equal(t, "contract_address", execEvents[1][0].Key) - - secondContractAddressBech32 := execEvents[1][0].Value + var secondContractAddressBech32 string + for _, v := range execEvents[1] { + if v.Key == "contract_address" { + secondContractAddressBech32 = v.Value + break + } + } + require.NotEmpty(t, secondContractAddressBech32) secondContractAddress, err := sdk.AccAddressFromBech32(secondContractAddressBech32) require.NoError(t, err) @@ -1356,20 +1382,26 @@ func TestInitCallbackToInit(t *testing.T) { require.Empty(t, initErr) require.Equal(t, 2, len(initEvents)) - require.Equal(t, + requireLogAttributes(t, ContractEvent{ {Key: "contract_address", Value: contractAddress.String()}, {Key: "instantiating a new contract from init!", Value: "🐙"}, }, initEvents[0], ) - require.Equal(t, + + require.Contains(t, + initEvents[1], v010cosmwasm.LogAttribute{Key: "init", Value: "🌈"}, - initEvents[1][1], ) - require.Equal(t, "contract_address", initEvents[1][0].Key) - - secondContractAddressBech32 := initEvents[1][0].Value + var secondContractAddressBech32 string + for _, v := range initEvents[1] { + if v.Key == "contract_address" { + secondContractAddressBech32 = v.Value + break + } + } + require.NotEmpty(t, secondContractAddressBech32) secondContractAddress, err := sdk.AccAddressFromBech32(secondContractAddressBech32) require.NoError(t, err) @@ -1793,7 +1825,7 @@ func TestMsgSenderInCallback(t *testing.T) { _, _, _, events, _, err := execHelper(t, keeper, ctx, addr, walletA, privKeyA, fmt.Sprintf(`{"callback_to_log_msg_sender":{"to":"%s","code_hash":"%s"}}`, addr.String(), codeHash), true, testContract.IsCosmWasmV1, defaultGasForTests, 0) require.Empty(t, err) - require.Equal(t, []ContractEvent{ + requireEvents(t, []ContractEvent{ { {Key: "contract_address", Value: addr.String()}, {Key: "hi", Value: "hey"}, @@ -1876,7 +1908,7 @@ func TestQueryRecursionLimitEnforcedInInits(t *testing.T) { require.Nil(t, err.GenericErr) - require.Equal(t, []ContractEvent{ + requireEvents(t, []ContractEvent{ { {Key: "contract_address", Value: addr.String()}, {Key: "message", Value: "Recursion limit was correctly enforced"}, @@ -2021,7 +2053,16 @@ func TestContractSendFundsToInitCallback(t *testing.T) { contractCoinsAfter := keeper.bankKeeper.GetAllBalances(ctx, addr) walletCoinsAfter := keeper.bankKeeper.GetAllBalances(ctx, walletA) - newContract, err := sdk.AccAddressFromBech32(execEvents[1][0].Value) + var newContractBech32 string + for _, v := range execEvents[1] { + if v.Key == "contract_address" { + newContractBech32 = v.Value + break + } + } + require.NotEmpty(t, newContractBech32) + + newContract, err := sdk.AccAddressFromBech32(newContractBech32) require.NoError(t, err) newContractCoins := keeper.bankKeeper.GetAllBalances(ctx, newContract) @@ -2406,14 +2447,24 @@ func TestCodeHashInitCallInit(t *testing.T) { _, _, addr, events, err := initHelperImpl(t, keeper, ctx, codeID, walletA, privKeyA, fmt.Sprintf(`{"call_to_init":{"code_id":%d,"code_hash":"%s","msg":"%s","label":"1"}}`, codeID, codeHash, `{\"nop\":{}}`), true, testContract.IsCosmWasmV1, defaultGasForTests, 2, sdk.NewCoins()) require.Empty(t, err) - require.Equal(t, + + var newContractBech32 string + for _, v := range events[1] { + if v.Key == "contract_address" { + newContractBech32 = v.Value + break + } + } + require.NotEmpty(t, newContractBech32) + + requireEvents(t, []ContractEvent{ { {Key: "contract_address", Value: addr.String()}, {Key: "a", Value: "a"}, }, { - {Key: "contract_address", Value: events[1][0].Value}, + {Key: "contract_address", Value: newContractBech32}, {Key: "init", Value: "🌈"}, }, }, @@ -2472,7 +2523,7 @@ func TestCodeHashInitCallExec(t *testing.T) { _, _, addr2, events, err := initHelperImpl(t, keeper, ctx, codeID, walletA, privKeyA, fmt.Sprintf(`{"call_to_exec":{"addr":"%s","code_hash":"%s","msg":"%s"}}`, addr.String(), codeHash, `{\"c\":{\"x\":1,\"y\":1}}`), true, testContract.IsCosmWasmV1, defaultGasForTests, 2, sdk.NewCoins()) require.Empty(t, err) - require.Equal(t, + requireEvents(t, []ContractEvent{ { {Key: "contract_address", Value: addr2.String()}, @@ -2538,7 +2589,7 @@ func TestCodeHashInitCallQuery(t *testing.T) { _, _, addr2, events, err := initHelper(t, keeper, ctx, codeID, walletA, privKeyA, fmt.Sprintf(`{"call_to_query":{"addr":"%s","code_hash":"%s","msg":"%s"}}`, addr.String(), codeHash, `{\"receive_external_query\":{\"num\":1}}`), true, testContract.IsCosmWasmV1, defaultGasForTests) require.Empty(t, err) - require.Equal(t, + requireEvents(t, []ContractEvent{ { {Key: "contract_address", Value: addr2.String()}, @@ -2600,14 +2651,24 @@ func TestCodeHashExecCallInit(t *testing.T) { _, _, _, events, _, err := execHelperImpl(t, keeper, ctx, addr, walletA, privKeyA, fmt.Sprintf(`{"call_to_init":{"code_id":%d,"code_hash":"%s","msg":"%s","label":"1"}}`, codeID, codeHash, `{\"nop\":{}}`), true, testContract.IsCosmWasmV1, defaultGasForTests, 0, 2) require.Empty(t, err) - require.Equal(t, + + var newContractBech32 string + for _, v := range events[1] { + if v.Key == "contract_address" { + newContractBech32 = v.Value + break + } + } + require.NotEmpty(t, newContractBech32) + + requireEvents(t, []ContractEvent{ { {Key: "contract_address", Value: addr.String()}, {Key: "a", Value: "a"}, }, { - {Key: "contract_address", Value: events[1][0].Value}, + {Key: "contract_address", Value: newContractBech32}, {Key: "init", Value: "🌈"}, }, }, @@ -2692,14 +2753,24 @@ func TestCodeHashExecCallExec(t *testing.T) { _, _, _, events, _, err := execHelper(t, keeper, ctx, addr, walletA, privKeyA, fmt.Sprintf(`{"call_to_exec":{"addr":"%s","code_hash":"%s","msg":"%s"}}`, addr, codeHash, `{\"c\":{\"x\":1,\"y\":1}}`), true, testContract.IsCosmWasmV1, defaultGasForTests, 0) require.Empty(t, err) - require.Equal(t, + + var newContractBech32 string + for _, v := range events[1] { + if v.Key == "contract_address" { + newContractBech32 = v.Value + break + } + } + require.NotEmpty(t, newContractBech32) + + requireEvents(t, []ContractEvent{ { {Key: "contract_address", Value: addr.String()}, {Key: "b", Value: "b"}, }, { - {Key: "contract_address", Value: events[1][0].Value}, + {Key: "contract_address", Value: newContractBech32}, {Key: "watermelon", Value: "🍉"}, }, }, @@ -2783,7 +2854,7 @@ func TestCodeHashExecCallQuery(t *testing.T) { _, _, _, events, _, err := execHelper(t, keeper, ctx, addr, walletA, privKeyA, fmt.Sprintf(`{"call_to_query":{"addr":"%s","code_hash":"%s","msg":"%s"}}`, addr.String(), codeHash, `{\"receive_external_query\":{\"num\":1}}`), true, testContract.IsCosmWasmV1, defaultGasForTests, 0) require.Empty(t, err) - require.Equal(t, + requireEvents(t, []ContractEvent{ { {Key: "contract_address", Value: addr.String()}, @@ -2910,7 +2981,7 @@ func TestEncryptedAndPlaintextLogs(t *testing.T) { _, _, _, events, _, err := execHelperImpl(t, keeper, ctx, addr, walletA, privKeyA, "{}", true, false, defaultGasForTests, 0, 1) require.Empty(t, err) - require.Equal(t, + requireEvents(t, []ContractEvent{ { {Key: "contract_address", Value: addr.String()}, @@ -2937,7 +3008,7 @@ func TestSecp256k1Verify(t *testing.T) { _, _, _, events, _, err := execHelper(t, keeper, ctx, contractAddress, walletA, privKeyA, `{"secp256k1_verify":{"iterations":1,"pubkey":"A0ZGrlBHMWtCMNAIbIrOxofwCxzZ0dxjT2yzWKwKmo//","sig":"/hZeEYHs9trj+Akeb+7p3UAtXjcDNYP9/D/hj/ALIUAG9bfrJltxkfpMz/9Jn5K3c5QjLuvaNT2jgr7P/AEW8A==","msg_hash":"ARp3VEHssUlDEwoW8AzdQYGKg90ENy8yWePKcjfjzao="}}`, true, testContract.IsCosmWasmV1, defaultGasForTests, 0) require.Empty(t, err) - require.Equal(t, + requireEvents(t, []ContractEvent{ { {Key: "contract_address", Value: contractAddress.String()}, @@ -2951,7 +3022,7 @@ func TestSecp256k1Verify(t *testing.T) { _, _, _, events, _, err := execHelper(t, keeper, ctx, contractAddress, walletA, privKeyA, `{"secp256k1_verify":{"iterations":1,"pubkey":"BEZGrlBHMWtCMNAIbIrOxofwCxzZ0dxjT2yzWKwKmo///ne03QpL+5WFHztzVceB3WD4QY/Ipl0UkHr/R8kDpVk=","sig":"/hZeEYHs9trj+Akeb+7p3UAtXjcDNYP9/D/hj/ALIUAG9bfrJltxkfpMz/9Jn5K3c5QjLuvaNT2jgr7P/AEW8A==","msg_hash":"ARp3VEHssUlDEwoW8AzdQYGKg90ENy8yWePKcjfjzao="}}`, true, testContract.IsCosmWasmV1, defaultGasForTests, 0) require.Empty(t, err) - require.Equal(t, + requireEvents(t, []ContractEvent{ { {Key: "contract_address", Value: contractAddress.String()}, @@ -2965,7 +3036,7 @@ func TestSecp256k1Verify(t *testing.T) { _, _, _, events, _, err := execHelper(t, keeper, ctx, contractAddress, walletA, privKeyA, `{"secp256k1_verify":{"iterations":1,"pubkey":"A0ZGrlBHMWtCMNAIbIrOxofwCxzZ0dxjT2yzWKwKmo//","sig":"/hZeEYHs9trj+Akeb+7p3UAtXjcDNYP9/D/hj/ALIUAG9bfrJltxkfpMz/9Jn5K3c5QjLuvaNT2jgr7P/AEW8A==","msg_hash":"ARp3VEHssUlDEwoW8AzdQYGKg90ENy8yWePKcjfjzas="}}`, true, testContract.IsCosmWasmV1, defaultGasForTests, 0) require.Empty(t, err) - require.Equal(t, + requireEvents(t, []ContractEvent{ { {Key: "contract_address", Value: contractAddress.String()}, @@ -2979,7 +3050,7 @@ func TestSecp256k1Verify(t *testing.T) { _, _, _, events, _, err := execHelper(t, keeper, ctx, contractAddress, walletA, privKeyA, `{"secp256k1_verify":{"iterations":1,"pubkey":"BEZGrlBHMWtCMNAIbIrOxofwCxzZ0dxjT2yzWKwKmo///ne03QpL+5WFHztzVceB3WD4QY/Ipl0UkHr/R8kDpVk=","sig":"/hZeEYHs9trj+Akeb+7p3UAtXjcDNYP9/D/hj/ALIUAG9bfrJltxkfpMz/9Jn5K3c5QjLuvaNT2jgr7P/AEW8A==","msg_hash":"ARp3VEHssUlDEwoW8AzdQYGKg90ENy8yWePKcjfjzas="}}`, true, testContract.IsCosmWasmV1, defaultGasForTests, 0) require.Empty(t, err) - require.Equal(t, + requireEvents(t, []ContractEvent{ { {Key: "contract_address", Value: contractAddress.String()}, @@ -2993,7 +3064,7 @@ func TestSecp256k1Verify(t *testing.T) { _, _, _, events, _, err := execHelper(t, keeper, ctx, contractAddress, walletA, privKeyA, `{"secp256k1_verify":{"iterations":1,"pubkey":"A0ZGrlBHMWtCMNAIbIrOxofwCxzZ0dxjT2yzWKwKmo//","sig":"rhZeEYHs9trj+Akeb+7p3UAtXjcDNYP9/D/hj/ALIUAG9bfrJltxkfpMz/9Jn5K3c5QjLuvaNT2jgr7P/AEW8A==","msg_hash":"ARp3VEHssUlDEwoW8AzdQYGKg90ENy8yWePKcjfjzao="}}`, true, testContract.IsCosmWasmV1, defaultGasForTests, 0) require.Empty(t, err) - require.Equal(t, + requireEvents(t, []ContractEvent{ { {Key: "contract_address", Value: contractAddress.String()}, @@ -3007,7 +3078,7 @@ func TestSecp256k1Verify(t *testing.T) { _, _, _, events, _, err := execHelper(t, keeper, ctx, contractAddress, walletA, privKeyA, `{"secp256k1_verify":{"iterations":1,"pubkey":"BEZGrlBHMWtCMNAIbIrOxofwCxzZ0dxjT2yzWKwKmo///ne03QpL+5WFHztzVceB3WD4QY/Ipl0UkHr/R8kDpVk=","sig":"rhZeEYHs9trj+Akeb+7p3UAtXjcDNYP9/D/hj/ALIUAG9bfrJltxkfpMz/9Jn5K3c5QjLuvaNT2jgr7P/AEW8A==","msg_hash":"ARp3VEHssUlDEwoW8AzdQYGKg90ENy8yWePKcjfjzao="}}`, true, testContract.IsCosmWasmV1, defaultGasForTests, 0) require.Empty(t, err) - require.Equal(t, + requireEvents(t, []ContractEvent{ { {Key: "contract_address", Value: contractAddress.String()}, @@ -3021,7 +3092,7 @@ func TestSecp256k1Verify(t *testing.T) { _, _, _, events, _, err := execHelper(t, keeper, ctx, contractAddress, walletA, privKeyA, `{"secp256k1_verify":{"iterations":1,"pubkey":"AoSdDHH9J0Bfb9pT8GFn+bW9cEVkgIh4bFsepMWmczXc","sig":"/hZeEYHs9trj+Akeb+7p3UAtXjcDNYP9/D/hj/ALIUAG9bfrJltxkfpMz/9Jn5K3c5QjLuvaNT2jgr7P/AEW8A==","msg_hash":"ARp3VEHssUlDEwoW8AzdQYGKg90ENy8yWePKcjfjzao="}}`, true, testContract.IsCosmWasmV1, defaultGasForTests, 0) require.Empty(t, err) - require.Equal(t, + requireEvents(t, []ContractEvent{ { {Key: "contract_address", Value: contractAddress.String()}, @@ -3035,7 +3106,7 @@ func TestSecp256k1Verify(t *testing.T) { _, _, _, events, _, err := execHelper(t, keeper, ctx, contractAddress, walletA, privKeyA, `{"secp256k1_verify":{"iterations":1,"pubkey":"BISdDHH9J0Bfb9pT8GFn+bW9cEVkgIh4bFsepMWmczXcFWl11YCgu65hzvNDQE2Qo1hwTMQ/42Xif8O/MrxzvxI=","sig":"/hZeEYHs9trj+Akeb+7p3UAtXjcDNYP9/D/hj/ALIUAG9bfrJltxkfpMz/9Jn5K3c5QjLuvaNT2jgr7P/AEW8A==","msg_hash":"ARp3VEHssUlDEwoW8AzdQYGKg90ENy8yWePKcjfjzao="}}`, true, testContract.IsCosmWasmV1, defaultGasForTests, 0) require.Empty(t, err) - require.Equal(t, + requireEvents(t, []ContractEvent{ { {Key: "contract_address", Value: contractAddress.String()}, @@ -3100,7 +3171,7 @@ func TestEd25519Verify(t *testing.T) { _, _, _, events, _, err := execHelper(t, keeper, ctx, contractAddress, walletA, privKeyA, `{"ed25519_verify":{"iterations":1,"pubkey":"LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","sig":"8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","msg":"YXNzYWYgd2FzIGhlcmU="}}`, true, testContract.IsCosmWasmV1, defaultGasForTests, 0) require.Empty(t, err) - require.Equal(t, + requireEvents(t, []ContractEvent{ { {Key: "contract_address", Value: contractAddress.String()}, @@ -3114,7 +3185,7 @@ func TestEd25519Verify(t *testing.T) { _, _, _, events, _, err := execHelper(t, keeper, ctx, contractAddress, walletA, privKeyA, `{"ed25519_verify":{"iterations":1,"pubkey":"LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","sig":"8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","msg":"YXNzYWYgd2FzIGhlcmUK"}}`, true, testContract.IsCosmWasmV1, defaultGasForTests, 0) require.Empty(t, err) - require.Equal(t, + requireEvents(t, []ContractEvent{ { {Key: "contract_address", Value: contractAddress.String()}, @@ -3128,7 +3199,7 @@ func TestEd25519Verify(t *testing.T) { _, _, _, events, _, err := execHelper(t, keeper, ctx, contractAddress, walletA, privKeyA, `{"ed25519_verify":{"iterations":1,"pubkey":"LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","sig":"8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDw==","msg":"YXNzYWYgd2FzIGhlcmU="}}`, true, testContract.IsCosmWasmV1, defaultGasForTests, 0) require.Empty(t, err) - require.Equal(t, + requireEvents(t, []ContractEvent{ { {Key: "contract_address", Value: contractAddress.String()}, @@ -3142,7 +3213,7 @@ func TestEd25519Verify(t *testing.T) { _, _, _, events, _, err := execHelper(t, keeper, ctx, contractAddress, walletA, privKeyA, `{"ed25519_verify":{"iterations":1,"pubkey":"DV1lgRdKw7nt4hvl8XkGZXMzU9S3uM9NLTK0h0qMbUs=","sig":"8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","msg":"YXNzYWYgd2FzIGhlcmU="}}`, true, testContract.IsCosmWasmV1, defaultGasForTests, 0) require.Empty(t, err) - require.Equal(t, + requireEvents(t, []ContractEvent{ { {Key: "contract_address", Value: contractAddress.String()}, @@ -3169,7 +3240,7 @@ func TestEd25519BatchVerify(t *testing.T) { _, _, _, events, _, err := execHelper(t, keeper, ctx, contractAddress, walletA, privKeyA, `{"ed25519_batch_verify":{"iterations":1,"pubkeys":["LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA="],"sigs":["8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg=="],"msgs":["YXNzYWYgd2FzIGhlcmU="]}}`, true, testContract.IsCosmWasmV1, defaultGasForTests, 0) require.Empty(t, err) - require.Equal(t, + requireEvents(t, []ContractEvent{ { {Key: "contract_address", Value: contractAddress.String()}, @@ -3183,7 +3254,7 @@ func TestEd25519BatchVerify(t *testing.T) { _, _, _, events, _, err := execHelper(t, keeper, ctx, contractAddress, walletA, privKeyA, `{"ed25519_batch_verify":{"iterations":1,"pubkeys":["LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA="],"sigs":["8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg=="],"msgs":["YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU=","YXNzYWYgd2FzIGhlcmU="]}}`, true, testContract.IsCosmWasmV1, defaultGasForTests, 0) require.Empty(t, err) - require.Equal(t, + requireEvents(t, []ContractEvent{ { {Key: "contract_address", Value: contractAddress.String()}, @@ -3197,7 +3268,7 @@ func TestEd25519BatchVerify(t *testing.T) { _, _, _, events, _, err := execHelper(t, keeper, ctx, contractAddress, walletA, privKeyA, `{"ed25519_batch_verify":{"iterations":1,"pubkeys":["DV1lgRdKw7nt4hvl8XkGZXMzU9S3uM9NLTK0h0qMbUs="],"sigs":["8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg=="],"msgs":["YXNzYWYgd2FzIGhlcmU="]}}`, true, testContract.IsCosmWasmV1, defaultGasForTests, 0) require.Empty(t, err) - require.Equal(t, + requireEvents(t, []ContractEvent{ { {Key: "contract_address", Value: contractAddress.String()}, @@ -3211,7 +3282,7 @@ func TestEd25519BatchVerify(t *testing.T) { _, _, _, events, _, err := execHelper(t, keeper, ctx, contractAddress, walletA, privKeyA, `{"ed25519_batch_verify":{"iterations":1,"pubkeys":["LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA="],"sigs":["8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg=="],"msgs":["YXNzYWYgd2FzIGhlcmUK"]}}`, true, testContract.IsCosmWasmV1, defaultGasForTests, 0) require.Empty(t, err) - require.Equal(t, + requireEvents(t, []ContractEvent{ { {Key: "contract_address", Value: contractAddress.String()}, @@ -3225,7 +3296,7 @@ func TestEd25519BatchVerify(t *testing.T) { _, _, _, events, _, err := execHelper(t, keeper, ctx, contractAddress, walletA, privKeyA, `{"ed25519_batch_verify":{"iterations":1,"pubkeys":["LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA="],"sigs":["8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDw=="],"msgs":["YXNzYWYgd2FzIGhlcmU="]}}`, true, testContract.IsCosmWasmV1, defaultGasForTests, 0) require.Empty(t, err) - require.Equal(t, + requireEvents(t, []ContractEvent{ { {Key: "contract_address", Value: contractAddress.String()}, @@ -3239,7 +3310,7 @@ func TestEd25519BatchVerify(t *testing.T) { _, _, _, events, _, err := execHelper(t, keeper, ctx, contractAddress, walletA, privKeyA, `{"ed25519_batch_verify":{"iterations":1,"pubkeys":["LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA="],"sigs":[],"msgs":[]}}`, true, testContract.IsCosmWasmV1, defaultGasForTests, 0) require.Empty(t, err) - require.Equal(t, + requireEvents(t, []ContractEvent{ { {Key: "contract_address", Value: contractAddress.String()}, @@ -3253,7 +3324,7 @@ func TestEd25519BatchVerify(t *testing.T) { _, _, _, events, _, err := execHelper(t, keeper, ctx, contractAddress, walletA, privKeyA, `{"ed25519_batch_verify":{"iterations":1,"pubkeys":[],"sigs":[],"msgs":[]}}`, true, testContract.IsCosmWasmV1, defaultGasForTests, 0) require.Empty(t, err) - require.Equal(t, + requireEvents(t, []ContractEvent{ { {Key: "contract_address", Value: contractAddress.String()}, @@ -3267,7 +3338,7 @@ func TestEd25519BatchVerify(t *testing.T) { _, _, _, events, _, err := execHelper(t, keeper, ctx, contractAddress, walletA, privKeyA, `{"ed25519_batch_verify":{"iterations":1,"pubkeys":[],"sigs":[],"msgs":["YXNzYWYgd2FzIGhlcmUK"]}}`, true, testContract.IsCosmWasmV1, defaultGasForTests, 0) require.Empty(t, err) - require.Equal(t, + requireEvents(t, []ContractEvent{ { {Key: "contract_address", Value: contractAddress.String()}, @@ -3281,7 +3352,7 @@ func TestEd25519BatchVerify(t *testing.T) { _, _, _, events, _, err := execHelper(t, keeper, ctx, contractAddress, walletA, privKeyA, `{"ed25519_batch_verify":{"iterations":1,"pubkeys":["LO2+Bt+/FIjomSaPB+I++LXkxgxwfnrKHLyvCic72rA=","2ukhmWRNmcgCrB9fpLP9/HZVuJn6AhpITf455F4GsbM="],"sigs":["8O7nwhM71/B9srKwe8Ps39z5lAsLMMs6LxdvoPk0HXjEM97TNhKbdU6gEePT2MaaIUSiMEmoG28HIZMgMRTCDg==","bp/N4Ub2WFk9SE9poZVEanU1l46WMrFkTd5wQIXi6QJKjvZUi7+GTzmTe8y2yzgpBI+GWQmt0/QwYbnSVxq/Cg=="],"msgs":["YXNzYWYgd2FzIGhlcmU="]}}`, true, testContract.IsCosmWasmV1, defaultGasForTests, 0) require.Empty(t, err) - require.Equal(t, + requireEvents(t, []ContractEvent{ { {Key: "contract_address", Value: contractAddress.String()}, @@ -3295,7 +3366,7 @@ func TestEd25519BatchVerify(t *testing.T) { _, _, _, events, _, err := execHelper(t, keeper, ctx, contractAddress, walletA, privKeyA, `{"ed25519_batch_verify":{"iterations":1,"pubkeys":["2ukhmWRNmcgCrB9fpLP9/HZVuJn6AhpITf455F4GsbM="],"sigs":["bp/N4Ub2WFk9SE9poZVEanU1l46WMrFkTd5wQIXi6QJKjvZUi7+GTzmTe8y2yzgpBI+GWQmt0/QwYbnSVxq/Cg==","uuNxLEzAYDbuJ+BiYN94pTqhD7UhvCJNbxAbnWz0B9DivkPXmqIULko0DddP2/tVXPtjJ90J20faiWCEC3QkDg=="],"msgs":["YXNzYWYgd2FzIGhlcmU=","cGVhY2Ugb3V0"]}}`, true, testContract.IsCosmWasmV1, defaultGasForTests, 0) require.Empty(t, err) - require.Equal(t, + requireEvents(t, []ContractEvent{ { {Key: "contract_address", Value: contractAddress.String()}, @@ -3321,7 +3392,7 @@ func TestSecp256k1RecoverPubkey(t *testing.T) { _, _, _, events, _, err := execHelper(t, keeper, ctx, contractAddress, walletA, privKeyA, `{"secp256k1_recover_pubkey":{"iterations":1,"recovery_param":0,"sig":"/hZeEYHs9trj+Akeb+7p3UAtXjcDNYP9/D/hj/ALIUAG9bfrJltxkfpMz/9Jn5K3c5QjLuvaNT2jgr7P/AEW8A==","msg_hash":"ARp3VEHssUlDEwoW8AzdQYGKg90ENy8yWePKcjfjzao="}}`, true, testContract.IsCosmWasmV1, defaultGasForTests, 0) require.Empty(t, err) - require.Equal(t, + requireEvents(t, []ContractEvent{ { {Key: "contract_address", Value: contractAddress.String()}, @@ -3334,7 +3405,7 @@ func TestSecp256k1RecoverPubkey(t *testing.T) { _, _, _, events, _, err = execHelper(t, keeper, ctx, contractAddress, walletA, privKeyA, `{"secp256k1_recover_pubkey":{"iterations":1,"recovery_param":1,"sig":"/hZeEYHs9trj+Akeb+7p3UAtXjcDNYP9/D/hj/ALIUAG9bfrJltxkfpMz/9Jn5K3c5QjLuvaNT2jgr7P/AEW8A==","msg_hash":"ARp3VEHssUlDEwoW8AzdQYGKg90ENy8yWePKcjfjzao="}}`, true, testContract.IsCosmWasmV1, defaultGasForTests, 0) require.Empty(t, err) - require.Equal(t, + requireEvents(t, []ContractEvent{ { {Key: "contract_address", Value: contractAddress.String()}, @@ -3369,7 +3440,7 @@ func TestSecp256k1Sign(t *testing.T) { _, _, _, events, _, err = execHelper(t, keeper, ctx, contractAddress, walletA, privKeyA, fmt.Sprintf(`{"secp256k1_verify":{"iterations":1,"pubkey":"ArQojoh5TVlSSNA1HFlH5HcQsv0jnrpeE7hgwR/N46nS","sig":"%s","msg_hash":"K9vGEuzCYCUcIXlhMZu20ke2K4mJhreguYct5MqAzhA="}}`, signature), true, testContract.IsCosmWasmV1, defaultGasForTests, 0) require.Empty(t, err) - require.Equal(t, + requireEvents(t, []ContractEvent{ { {Key: "contract_address", Value: contractAddress.String()}, @@ -3404,7 +3475,7 @@ func TestEd25519Sign(t *testing.T) { _, _, _, events, _, err = execHelper(t, keeper, ctx, contractAddress, walletA, privKeyA, fmt.Sprintf(`{"ed25519_verify":{"iterations":1,"pubkey":"jh58UkC0FDsiupZBLdaqKUqYubJbk3LDaruZiJiy0Po=","sig":"%s","msg":"d2VuIG1vb24="}}`, signature), true, testContract.IsCosmWasmV1, defaultGasForTests, 0) require.Empty(t, err) - require.Equal(t, + requireEvents(t, []ContractEvent{ { {Key: "contract_address", Value: contractAddress.String()}, @@ -3535,7 +3606,17 @@ func TestInitCreateNewContract(t *testing.T) { _, _, _, ev, _, err := execHelper(t, keeper, ctx, contractAddress, walletA, privKeyA, `{"init_new_contract":{}}`, true, testContract.IsCosmWasmV1, math.MaxUint64, 0) require.Empty(t, err) - newContractAddress, Aerr := sdk.AccAddressFromBech32(ev[1][0].Value) + + var newContractBech32 string + for _, v := range ev[1] { + if v.Key == "contract_address" { + newContractBech32 = v.Value + break + } + } + require.NotEmpty(t, newContractBech32) + + newContractAddress, Aerr := sdk.AccAddressFromBech32(newContractBech32) require.Empty(t, Aerr) queryRes, qErr := queryHelper(t, keeper, ctx, contractAddress, `{"get":{}}`, true, true, math.MaxUint64) require.Empty(t, qErr) @@ -3868,7 +3949,16 @@ func TestSendFunds(t *testing.T) { require.Equal(t, test.balancesAfter, originCoinsAfter.String()) if destinationType == "init" && originType != "user" { - destinationAddr, _ = sdk.AccAddressFromBech32(wasmEvents[1][0].Value) + var newContractBech32 string + for _, v := range wasmEvents[1] { + if v.Key == "contract_address" { + newContractBech32 = v.Value + break + } + } + require.NotEmpty(t, newContractBech32) + + destinationAddr, _ = sdk.AccAddressFromBech32(newContractBech32) } destinationCoinsAfter := keeper.bankKeeper.GetAllBalances(ctx, destinationAddr) @@ -3934,7 +4024,9 @@ func TestWasmMsgStructure(t *testing.T) { require.NoError(t, err) toCodeID, err := keeper.Create(ctx, walletA, wasmCode, "", "") - toCodeHash := hex.EncodeToString(keeper.GetCodeInfo(ctx, toCodeID).CodeHash) + codeInfo, err := keeper.GetCodeInfo(ctx, toCodeID) + require.NoError(t, err) + toCodeHash := hex.EncodeToString(codeInfo.CodeHash) require.NoError(t, err) toAddress := sdk.AccAddress{} @@ -4103,7 +4195,9 @@ func TestV1InitV010ContractWithReply(t *testing.T) { v010CodeID, err := keeper.Create(ctx, walletA, wasmCode, "", "") require.NoError(t, err) - v010CodeHash := hex.EncodeToString(keeper.GetCodeInfo(ctx, v010CodeID).CodeHash) + codeInfo, err := keeper.GetCodeInfo(ctx, v010CodeID) + require.NoError(t, err) + v010CodeHash := hex.EncodeToString(codeInfo.CodeHash) _, _, contractAddress, _, _ := initHelper(t, keeper, ctx, codeID, walletA, privKeyA, `{"counter":{"counter":10, "expires":100}}`, true, true, defaultGasForTests) msg := fmt.Sprintf(`{"init_v10":{"counter":80, "code_id":%d, "code_hash":"%s"}}`, v010CodeID, v010CodeHash) @@ -4132,7 +4226,9 @@ func TestV1ExecuteV010ContractWithReply(t *testing.T) { v010CodeID, err := keeper.Create(ctx, walletA, wasmCode, "", "") require.NoError(t, err) - v010CodeHash := hex.EncodeToString(keeper.GetCodeInfo(ctx, v010CodeID).CodeHash) + codeInfo, err := keeper.GetCodeInfo(ctx, v010CodeID) + require.NoError(t, err) + v010CodeHash := hex.EncodeToString(codeInfo.CodeHash) _, _, contractAddress, _, err := initHelper(t, keeper, ctx, codeID, walletA, privKeyA, `{"nop":{}}`, true, true, defaultGasForTests) require.Empty(t, err) @@ -4156,7 +4252,9 @@ func TestV1InitV010ContractNoReply(t *testing.T) { v010CodeID, err := keeper.Create(ctx, walletA, wasmCode, "", "") require.NoError(t, err) - v010CodeHash := hex.EncodeToString(keeper.GetCodeInfo(ctx, v010CodeID).CodeHash) + codeInfo, err := keeper.GetCodeInfo(ctx, v010CodeID) + require.NoError(t, err) + v010CodeHash := hex.EncodeToString(codeInfo.CodeHash) _, _, contractAddress, _, _ := initHelper(t, keeper, ctx, codeID, walletA, privKeyA, `{"counter":{"counter":10, "expires":100}}`, true, true, defaultGasForTests) msg := fmt.Sprintf(`{"init_v10_no_reply":{"counter":180, "code_id":%d, "code_hash":"%s"}}`, v010CodeID, v010CodeHash) @@ -4164,7 +4262,17 @@ func TestV1InitV010ContractNoReply(t *testing.T) { _, _, _, ev, _, err := execHelper(t, keeper, ctx, contractAddress, walletA, privKeyA, msg, true, true, math.MaxUint64, 0) require.Empty(t, err) - accAddress, err := sdk.AccAddressFromBech32(ev[1][0].Value) + + var newContractBech32 string + for _, v := range ev[1] { + if v.Key == "contract_address" { + newContractBech32 = v.Value + break + } + } + require.NotEmpty(t, newContractBech32) + + accAddress, err := sdk.AccAddressFromBech32(newContractBech32) require.Empty(t, err) queryRes, qErr := queryHelper(t, keeper, ctx, accAddress, `{"get_count_from_v1":{}}`, true, false, math.MaxUint64) @@ -4185,7 +4293,9 @@ func TestV1ExecuteV010ContractNoReply(t *testing.T) { v010CodeID, err := keeper.Create(ctx, walletA, wasmCode, "", "") require.NoError(t, err) - v010CodeHash := hex.EncodeToString(keeper.GetCodeInfo(ctx, v010CodeID).CodeHash) + codeInfo, err := keeper.GetCodeInfo(ctx, v010CodeID) + require.NoError(t, err) + v010CodeHash := hex.EncodeToString(codeInfo.CodeHash) _, _, contractAddress, _, err := initHelper(t, keeper, ctx, codeID, walletA, privKeyA, `{"nop":{}}`, true, true, defaultGasForTests) require.Empty(t, err) @@ -4214,7 +4324,9 @@ func TestV1QueryV010Contract(t *testing.T) { v010CodeID, err := keeper.Create(ctx, walletA, wasmCode, "", "") require.NoError(t, err) - v010CodeHash := hex.EncodeToString(keeper.GetCodeInfo(ctx, v010CodeID).CodeHash) + codeInfo, err := keeper.GetCodeInfo(ctx, v010CodeID) + require.NoError(t, err) + v010CodeHash := hex.EncodeToString(codeInfo.CodeHash) _, _, contractAddress, _, err := initHelper(t, keeper, ctx, codeID, walletA, privKeyA, `{"nop":{}}`, true, true, defaultGasForTests) require.Empty(t, err) @@ -4238,7 +4350,9 @@ func TestV1InitV010ContractWithReplyWithError(t *testing.T) { v010CodeID, err := keeper.Create(ctx, walletA, wasmCode, "", "") require.NoError(t, err) - v010CodeHash := hex.EncodeToString(keeper.GetCodeInfo(ctx, v010CodeID).CodeHash) + codeInfo, err := keeper.GetCodeInfo(ctx, v010CodeID) + require.NoError(t, err) + v010CodeHash := hex.EncodeToString(codeInfo.CodeHash) _, _, contractAddress, _, _ := initHelper(t, keeper, ctx, codeID, walletA, privKeyA, `{"counter":{"counter":10, "expires":100}}`, true, true, defaultGasForTests) msg := fmt.Sprintf(`{"init_v10_with_error":{"code_id":%d, "code_hash":"%s"}}`, v010CodeID, v010CodeHash) @@ -4257,7 +4371,9 @@ func TestV1ExecuteV010ContractWithReplyWithError(t *testing.T) { v010CodeID, err := keeper.Create(ctx, walletA, wasmCode, "", "") require.NoError(t, err) - v010CodeHash := hex.EncodeToString(keeper.GetCodeInfo(ctx, v010CodeID).CodeHash) + codeInfo, err := keeper.GetCodeInfo(ctx, v010CodeID) + require.NoError(t, err) + v010CodeHash := hex.EncodeToString(codeInfo.CodeHash) _, _, contractAddress, _, err := initHelper(t, keeper, ctx, codeID, walletA, privKeyA, `{"nop":{}}`, true, true, defaultGasForTests) require.Empty(t, err) @@ -4280,7 +4396,9 @@ func TestV1InitV010ContractNoReplyWithError(t *testing.T) { v010CodeID, err := keeper.Create(ctx, walletA, wasmCode, "", "") require.NoError(t, err) - v010CodeHash := hex.EncodeToString(keeper.GetCodeInfo(ctx, v010CodeID).CodeHash) + codeInfo, err := keeper.GetCodeInfo(ctx, v010CodeID) + require.NoError(t, err) + v010CodeHash := hex.EncodeToString(codeInfo.CodeHash) _, _, contractAddress, _, _ := initHelper(t, keeper, ctx, codeID, walletA, privKeyA, `{"counter":{"counter":10, "expires":100}}`, true, true, defaultGasForTests) msg := fmt.Sprintf(`{"init_v10_no_reply_with_error":{"code_id":%d, "code_hash":"%s"}}`, v010CodeID, v010CodeHash) @@ -4300,7 +4418,9 @@ func TestV1ExecuteV010ContractNoReplyWithError(t *testing.T) { v010CodeID, err := keeper.Create(ctx, walletA, wasmCode, "", "") require.NoError(t, err) - v010CodeHash := hex.EncodeToString(keeper.GetCodeInfo(ctx, v010CodeID).CodeHash) + codeInfo, err := keeper.GetCodeInfo(ctx, v010CodeID) + require.NoError(t, err) + v010CodeHash := hex.EncodeToString(codeInfo.CodeHash) _, _, contractAddress, _, err := initHelper(t, keeper, ctx, codeID, walletA, privKeyA, `{"nop":{}}`, true, true, defaultGasForTests) require.Empty(t, err) @@ -4324,7 +4444,9 @@ func TestV1QueryV010ContractWithError(t *testing.T) { v010CodeID, err := keeper.Create(ctx, walletA, wasmCode, "", "") require.NoError(t, err) - v010CodeHash := hex.EncodeToString(keeper.GetCodeInfo(ctx, v010CodeID).CodeHash) + codeInfo, err := keeper.GetCodeInfo(ctx, v010CodeID) + require.NoError(t, err) + v010CodeHash := hex.EncodeToString(codeInfo.CodeHash) _, _, contractAddress, _, err := initHelper(t, keeper, ctx, codeID, walletA, privKeyA, `{"nop":{}}`, true, true, defaultGasForTests) require.Empty(t, err) @@ -4355,7 +4477,15 @@ func TestV010InitV1ContractFromInitWithOkResponse(t *testing.T) { require.Equal(t, queryRes, "10") require.Empty(t, err) - accAddress, err := sdk.AccAddressFromBech32(initEvents[1][0].Value) + var newContractBech32 string + for _, v := range initEvents[1] { + if v.Key == "contract_address" { + newContractBech32 = v.Value + break + } + } + require.NotEmpty(t, newContractBech32) + accAddress, err := sdk.AccAddressFromBech32(newContractBech32) require.Empty(t, err) queryRes, qErr = queryHelper(t, keeper, ctx, accAddress, `{"get_contract_version":{}}`, true, false, math.MaxUint64) @@ -4385,7 +4515,15 @@ func TestV010InitV1ContractFromExecuteWithOkResponse(t *testing.T) { require.Empty(t, execErr) require.Empty(t, execData) - accAddress, err := sdk.AccAddressFromBech32(execEvents[1][0].Value) + var newContractBech32 string + for _, v := range execEvents[1] { + if v.Key == "contract_address" { + newContractBech32 = v.Value + break + } + } + require.NotEmpty(t, newContractBech32) + accAddress, err := sdk.AccAddressFromBech32(newContractBech32) require.Empty(t, err) queryRes, qErr = queryHelper(t, keeper, ctx, accAddress, `{"get_contract_version":{}}`, true, false, math.MaxUint64) @@ -4455,7 +4593,7 @@ func TestV010QueryV1ContractFromInitWithOkResponse(t *testing.T) { _, _, contractAddress, _, err := initHelper(t, keeper, ctx, codeID, walletA, privKeyA, `{"nop":{}}`, true, true, defaultGasForTests) _, _, v010ContractAddress, events, err := initHelper(t, keeper, ctx, v010CodeID, walletA, privKeyA, fmt.Sprintf(`{"call_to_query":{"addr":"%s","code_hash":"%s","msg":"%s"}}`, contractAddress.String(), codeHash, `{\"receive_external_query_v1\":{\"num\":1}}`), true, true, defaultGasForTests) require.Empty(t, err) - require.Equal(t, + requireEvents(t, []ContractEvent{ { {Key: "contract_address", Value: v010ContractAddress.String()}, @@ -4480,7 +4618,7 @@ func TestV010QueryV1ContractFromExecuteWithOkResponse(t *testing.T) { _, _, _, events, _, err := execHelper(t, keeper, ctx, v010ContractAddress, walletA, privKeyA, fmt.Sprintf(`{"call_to_query":{"addr":"%s","code_hash":"%s","msg":"%s"}}`, contractAddress.String(), codeHash, `{\"receive_external_query_v1\":{\"num\":1}}`), true, true, defaultGasForTests, 0) require.Empty(t, err) - require.Equal(t, + requireEvents(t, []ContractEvent{ { {Key: "contract_address", Value: v010ContractAddress.String()}, @@ -4593,7 +4731,7 @@ func TestSendEncryptedAttributesFromInitWithoutSubmessageWithoutReply(t *testing _, _, contractAddress, events, err := initHelper(t, keeper, ctx, codeID, walletA, privKeyA, `{"add_attributes":{}}`, true, testContract.IsCosmWasmV1, defaultGasForTests) require.Empty(t, err) - require.Equal(t, + requireEvents(t, []ContractEvent{ { {Key: "contract_address", Value: contractAddress.String()}, @@ -4615,7 +4753,7 @@ func TestSendEncryptedAttributesFromInitWithSubmessageWithoutReply(t *testing.T) _, _, contractAddress, events, err := initHelper(t, keeper, ctx, codeID, walletA, privKeyA, `{"add_attributes_with_submessage":{"id":0}}`, true, testContract.IsCosmWasmV1, defaultGasForTests) require.Empty(t, err) - require.Equal(t, + requireEvents(t, []ContractEvent{ { {Key: "contract_address", Value: contractAddress.String()}, @@ -4640,7 +4778,7 @@ func TestV1SendsEncryptedAttributesFromInitWithSubmessageWithReply(t *testing.T) _, _, contractAddress, events, err := initHelper(t, keeper, ctx, codeID, walletA, privKeyA, `{"add_attributes_with_submessage":{"id":2200}}`, true, true, defaultGasForTests) require.Empty(t, err) - require.Equal(t, + requireEvents(t, []ContractEvent{ { {Key: "contract_address", Value: contractAddress.String()}, @@ -4672,7 +4810,7 @@ func TestSendEncryptedAttributesFromExecuteWithoutSubmessageWithoutReply(t *test _, _, _, events, _, err := execHelper(t, keeper, ctx, contractAddress, walletA, privKeyA, `{"add_attributes":{}}`, true, testContract.IsCosmWasmV1, defaultGasForTests, 0) require.Empty(t, err) - require.Equal(t, + requireEvents(t, []ContractEvent{ { {Key: "contract_address", Value: contractAddress.String()}, @@ -4696,7 +4834,7 @@ func TestSendEncryptedAttributesFromExecuteWithSubmessageWithoutReply(t *testing _, _, _, events, _, err := execHelper(t, keeper, ctx, contractAddress, walletA, privKeyA, `{"add_attributes_with_submessage":{"id":0}}`, true, testContract.IsCosmWasmV1, defaultGasForTests, 0) require.Empty(t, err) - require.Equal(t, + requireEvents(t, []ContractEvent{ { {Key: "contract_address", Value: contractAddress.String()}, @@ -4723,7 +4861,7 @@ func TestV1SendsEncryptedAttributesFromExecuteWithSubmessageWithReply(t *testing _, _, _, events, _, err := execHelper(t, keeper, ctx, contractAddress, walletA, privKeyA, `{"add_attributes_with_submessage":{"id":2200}}`, true, true, defaultGasForTests, 0) require.Empty(t, err) - require.Equal(t, + requireEvents(t, []ContractEvent{ { {Key: "contract_address", Value: contractAddress.String()}, @@ -4753,7 +4891,7 @@ func TestSendPlaintextFromInitWithoutSubmessageWithoutReply(t *testing.T) { _, _, contractAddress, events, err := initHelper(t, keeper, ctx, codeID, walletA, privKeyA, `{"add_plaintext_attributes":{}}`, true, testContract.IsCosmWasmV1, defaultGasForTests, true) require.Empty(t, err) - require.Equal(t, + requireEvents(t, []ContractEvent{ { {Key: "contract_address", Value: contractAddress.String()}, @@ -4775,7 +4913,7 @@ func TestSendPlaintextAttributesFromInitWithSubmessageWithoutReply(t *testing.T) _, _, contractAddress, events, err := initHelper(t, keeper, ctx, codeID, walletA, privKeyA, `{"add_plaintext_attributes_with_submessage":{"id":0}}`, true, testContract.IsCosmWasmV1, defaultGasForTests, true) require.Empty(t, err) - require.Equal(t, + requireEvents(t, []ContractEvent{ { {Key: "contract_address", Value: contractAddress.String()}, @@ -4800,7 +4938,7 @@ func TestV1SendsPlaintextAttributesFromInitWithSubmessageWithReply(t *testing.T) _, _, contractAddress, events, err := initHelper(t, keeper, ctx, codeID, walletA, privKeyA, `{"add_plaintext_attributes_with_submessage":{"id":2300}}`, true, true, defaultGasForTests, true) require.Empty(t, err) - require.Equal(t, + requireEvents(t, []ContractEvent{ { {Key: "contract_address", Value: contractAddress.String()}, @@ -4832,7 +4970,7 @@ func TestSendPlaintextAttributesFromExecuteWithoutSubmessageWithoutReply(t *test _, _, _, events, _, err := execHelper(t, keeper, ctx, contractAddress, walletA, privKeyA, `{"add_plaintext_attributes":{}}`, true, testContract.IsCosmWasmV1, defaultGasForTests, 0, true) require.Empty(t, err) - require.Equal(t, + requireEvents(t, []ContractEvent{ { {Key: "contract_address", Value: contractAddress.String()}, @@ -4856,7 +4994,7 @@ func TestSendPlaintextAttributesFromExecuteWithSubmessageWithoutReply(t *testing _, _, _, events, _, err := execHelper(t, keeper, ctx, contractAddress, walletA, privKeyA, `{"add_plaintext_attributes_with_submessage":{"id":0}}`, true, testContract.IsCosmWasmV1, defaultGasForTests, 0, true) require.Empty(t, err) - require.Equal(t, + requireEvents(t, []ContractEvent{ { {Key: "contract_address", Value: contractAddress.String()}, @@ -4883,7 +5021,7 @@ func TestV1SendsPlaintextAttributesFromExecuteWithSubmessageWithReply(t *testing _, _, _, events, _, err := execHelper(t, keeper, ctx, contractAddress, walletA, privKeyA, `{"add_plaintext_attributes_with_submessage":{"id":2300}}`, true, true, defaultGasForTests, 0, true) require.Empty(t, err) - require.Equal(t, + requireEvents(t, []ContractEvent{ { {Key: "contract_address", Value: contractAddress.String()}, @@ -4922,7 +5060,7 @@ func TestV1SendsEncryptedEventsFromInitWithoutSubmessageWithoutReply(t *testing. attrs, err := parseAndDecryptAttributes(e.Attributes, nonce, true) require.Empty(t, err) - require.Equal(t, + requireLogAttributes(t, []v010cosmwasm.LogAttribute{ {Key: "contract_address", Value: contractAddress.String()}, {Key: "attr1", Value: "🦄"}, @@ -4939,7 +5077,7 @@ func TestV1SendsEncryptedEventsFromInitWithoutSubmessageWithoutReply(t *testing. attrs, err := parseAndDecryptAttributes(e.Attributes, nonce, true) require.Empty(t, err) - require.Equal(t, + requireLogAttributes(t, []v010cosmwasm.LogAttribute{ {Key: "contract_address", Value: contractAddress.String()}, {Key: "attr3", Value: "🐙"}, @@ -4975,7 +5113,7 @@ func TestV1SendsEncryptedEventsFromInitWithSubmessageWithoutReply(t *testing.T) attrs, err := parseAndDecryptAttributes(e.Attributes, nonce, true) require.Empty(t, err) - require.Equal(t, + requireLogAttributes(t, []v010cosmwasm.LogAttribute{ {Key: "contract_address", Value: contractAddress.String()}, {Key: "attr1", Value: "🦄"}, @@ -4992,7 +5130,7 @@ func TestV1SendsEncryptedEventsFromInitWithSubmessageWithoutReply(t *testing.T) attrs, err := parseAndDecryptAttributes(e.Attributes, nonce, true) require.Empty(t, err) - require.Equal(t, + requireLogAttributes(t, []v010cosmwasm.LogAttribute{ {Key: "contract_address", Value: contractAddress.String()}, {Key: "attr3", Value: "🐙"}, @@ -5009,7 +5147,7 @@ func TestV1SendsEncryptedEventsFromInitWithSubmessageWithoutReply(t *testing.T) attrs, err := parseAndDecryptAttributes(e.Attributes, nonce, true) require.Empty(t, err) - require.Equal(t, + requireLogAttributes(t, []v010cosmwasm.LogAttribute{ {Key: "contract_address", Value: contractAddress.String()}, {Key: "attr1", Value: "🤯"}, @@ -5026,7 +5164,7 @@ func TestV1SendsEncryptedEventsFromInitWithSubmessageWithoutReply(t *testing.T) attrs, err := parseAndDecryptAttributes(e.Attributes, nonce, true) require.Empty(t, err) - require.Equal(t, + requireLogAttributes(t, []v010cosmwasm.LogAttribute{ {Key: "contract_address", Value: contractAddress.String()}, {Key: "attr3", Value: "😅"}, @@ -5066,7 +5204,7 @@ func TestV1SendsEncryptedEventsFromInitWithSubmessageWithReply(t *testing.T) { attrs, err := parseAndDecryptAttributes(e.Attributes, nonce, true) require.Empty(t, err) - require.Equal(t, + requireLogAttributes(t, []v010cosmwasm.LogAttribute{ {Key: "contract_address", Value: contractAddress.String()}, {Key: "attr1", Value: "🦄"}, @@ -5083,7 +5221,7 @@ func TestV1SendsEncryptedEventsFromInitWithSubmessageWithReply(t *testing.T) { attrs, err := parseAndDecryptAttributes(e.Attributes, nonce, true) require.Empty(t, err) - require.Equal(t, + requireLogAttributes(t, []v010cosmwasm.LogAttribute{ {Key: "contract_address", Value: contractAddress.String()}, {Key: "attr3", Value: "🐙"}, @@ -5100,7 +5238,7 @@ func TestV1SendsEncryptedEventsFromInitWithSubmessageWithReply(t *testing.T) { attrs, err := parseAndDecryptAttributes(e.Attributes, nonce, true) require.Empty(t, err) - require.Equal(t, + requireLogAttributes(t, []v010cosmwasm.LogAttribute{ {Key: "contract_address", Value: contractAddress.String()}, {Key: "attr1", Value: "🤯"}, @@ -5117,7 +5255,7 @@ func TestV1SendsEncryptedEventsFromInitWithSubmessageWithReply(t *testing.T) { attrs, err := parseAndDecryptAttributes(e.Attributes, nonce, true) require.Empty(t, err) - require.Equal(t, + requireLogAttributes(t, []v010cosmwasm.LogAttribute{ {Key: "contract_address", Value: contractAddress.String()}, {Key: "attr3", Value: "😅"}, @@ -5134,7 +5272,7 @@ func TestV1SendsEncryptedEventsFromInitWithSubmessageWithReply(t *testing.T) { attrs, err := parseAndDecryptAttributes(e.Attributes, nonce, true) require.Empty(t, err) - require.Equal(t, + requireLogAttributes(t, []v010cosmwasm.LogAttribute{ {Key: "contract_address", Value: contractAddress.String()}, {Key: "attr1", Value: "😗"}, @@ -5151,7 +5289,7 @@ func TestV1SendsEncryptedEventsFromInitWithSubmessageWithReply(t *testing.T) { attrs, err := parseAndDecryptAttributes(e.Attributes, nonce, true) require.Empty(t, err) - require.Equal(t, + requireLogAttributes(t, []v010cosmwasm.LogAttribute{ {Key: "contract_address", Value: contractAddress.String()}, {Key: "attr3", Value: "😉"}, @@ -5191,7 +5329,7 @@ func TestV1SendsEncryptedEventsFromExecuteWithoutSubmessageWithoutReply(t *testi attrs, err := parseAndDecryptAttributes(e.Attributes, nonce, true) require.Empty(t, err) - require.Equal(t, + requireLogAttributes(t, []v010cosmwasm.LogAttribute{ {Key: "contract_address", Value: contractAddress.String()}, {Key: "attr1", Value: "🦄"}, @@ -5208,7 +5346,7 @@ func TestV1SendsEncryptedEventsFromExecuteWithoutSubmessageWithoutReply(t *testi attrs, err := parseAndDecryptAttributes(e.Attributes, nonce, true) require.Empty(t, err) - require.Equal(t, + requireLogAttributes(t, []v010cosmwasm.LogAttribute{ {Key: "contract_address", Value: contractAddress.String()}, {Key: "attr3", Value: "🐙"}, @@ -5246,7 +5384,7 @@ func TestV1SendsEncryptedEventsFromExecuteWithSubmessageWithoutReply(t *testing. attrs, err := parseAndDecryptAttributes(e.Attributes, nonce, true) require.Empty(t, err) - require.Equal(t, + requireLogAttributes(t, []v010cosmwasm.LogAttribute{ {Key: "contract_address", Value: contractAddress.String()}, {Key: "attr1", Value: "🦄"}, @@ -5263,7 +5401,7 @@ func TestV1SendsEncryptedEventsFromExecuteWithSubmessageWithoutReply(t *testing. attrs, err := parseAndDecryptAttributes(e.Attributes, nonce, true) require.Empty(t, err) - require.Equal(t, + requireLogAttributes(t, []v010cosmwasm.LogAttribute{ {Key: "contract_address", Value: contractAddress.String()}, {Key: "attr3", Value: "🐙"}, @@ -5280,7 +5418,7 @@ func TestV1SendsEncryptedEventsFromExecuteWithSubmessageWithoutReply(t *testing. attrs, err := parseAndDecryptAttributes(e.Attributes, nonce, true) require.Empty(t, err) - require.Equal(t, + requireLogAttributes(t, []v010cosmwasm.LogAttribute{ {Key: "contract_address", Value: contractAddress.String()}, {Key: "attr1", Value: "🤯"}, @@ -5297,7 +5435,7 @@ func TestV1SendsEncryptedEventsFromExecuteWithSubmessageWithoutReply(t *testing. attrs, err := parseAndDecryptAttributes(e.Attributes, nonce, true) require.Empty(t, err) - require.Equal(t, + requireLogAttributes(t, []v010cosmwasm.LogAttribute{ {Key: "contract_address", Value: contractAddress.String()}, {Key: "attr3", Value: "😅"}, @@ -5339,7 +5477,7 @@ func TestV1SendsEncryptedEventsFromExecuteWithSubmessageWithReply(t *testing.T) attrs, err := parseAndDecryptAttributes(e.Attributes, nonce, true) require.Empty(t, err) - require.Equal(t, + requireLogAttributes(t, []v010cosmwasm.LogAttribute{ {Key: "contract_address", Value: contractAddress.String()}, {Key: "attr1", Value: "🦄"}, @@ -5356,7 +5494,7 @@ func TestV1SendsEncryptedEventsFromExecuteWithSubmessageWithReply(t *testing.T) attrs, err := parseAndDecryptAttributes(e.Attributes, nonce, true) require.Empty(t, err) - require.Equal(t, + requireLogAttributes(t, []v010cosmwasm.LogAttribute{ {Key: "contract_address", Value: contractAddress.String()}, {Key: "attr3", Value: "🐙"}, @@ -5373,7 +5511,7 @@ func TestV1SendsEncryptedEventsFromExecuteWithSubmessageWithReply(t *testing.T) attrs, err := parseAndDecryptAttributes(e.Attributes, nonce, true) require.Empty(t, err) - require.Equal(t, + requireLogAttributes(t, []v010cosmwasm.LogAttribute{ {Key: "contract_address", Value: contractAddress.String()}, {Key: "attr1", Value: "🤯"}, @@ -5390,7 +5528,7 @@ func TestV1SendsEncryptedEventsFromExecuteWithSubmessageWithReply(t *testing.T) attrs, err := parseAndDecryptAttributes(e.Attributes, nonce, true) require.Empty(t, err) - require.Equal(t, + requireLogAttributes(t, []v010cosmwasm.LogAttribute{ {Key: "contract_address", Value: contractAddress.String()}, {Key: "attr3", Value: "😅"}, @@ -5407,7 +5545,7 @@ func TestV1SendsEncryptedEventsFromExecuteWithSubmessageWithReply(t *testing.T) attrs, err := parseAndDecryptAttributes(e.Attributes, nonce, true) require.Empty(t, err) - require.Equal(t, + requireLogAttributes(t, []v010cosmwasm.LogAttribute{ {Key: "contract_address", Value: contractAddress.String()}, {Key: "attr1", Value: "😗"}, @@ -5424,7 +5562,7 @@ func TestV1SendsEncryptedEventsFromExecuteWithSubmessageWithReply(t *testing.T) attrs, err := parseAndDecryptAttributes(e.Attributes, nonce, true) require.Empty(t, err) - require.Equal(t, + requireLogAttributes(t, []v010cosmwasm.LogAttribute{ {Key: "contract_address", Value: contractAddress.String()}, {Key: "attr3", Value: "😉"}, @@ -5461,7 +5599,7 @@ func TestV1SendsMixedLogsFromInitWithoutSubmessageWithoutReply(t *testing.T) { attrs, err := parseAndDecryptAttributes(e.Attributes, nonce, false) require.Empty(t, err) - require.Equal(t, + requireLogAttributes(t, []v010cosmwasm.LogAttribute{ {Key: "contract_address", Value: contractAddress.String()}, {Key: "attr1", Value: "🦄"}, @@ -5476,7 +5614,7 @@ func TestV1SendsMixedLogsFromInitWithoutSubmessageWithoutReply(t *testing.T) { require.True(t, hadCyber1) - require.Equal(t, + requireEvents(t, []ContractEvent{ { {Key: "contract_address", Value: contractAddress.String()}, @@ -5505,7 +5643,7 @@ func TestV1SendsMixedAttributesAndEventsFromInitWithSubmessageWithoutReply(t *te attrs, err := parseAndDecryptAttributes(e.Attributes, nonce, true) require.Empty(t, err) - require.Equal(t, + requireLogAttributes(t, []v010cosmwasm.LogAttribute{ {Key: "contract_address", Value: contractAddress.String()}, {Key: "attr1", Value: "🦄"}, @@ -5522,7 +5660,7 @@ func TestV1SendsMixedAttributesAndEventsFromInitWithSubmessageWithoutReply(t *te attrs, err := parseAndDecryptAttributes(e.Attributes, nonce, true) require.Empty(t, err) - require.Equal(t, + requireLogAttributes(t, []v010cosmwasm.LogAttribute{ {Key: "contract_address", Value: contractAddress.String()}, {Key: "attr5", Value: "🐙"}, @@ -5538,7 +5676,7 @@ func TestV1SendsMixedAttributesAndEventsFromInitWithSubmessageWithoutReply(t *te require.True(t, hadCyber1) require.True(t, hadCyber2) - require.Equal(t, + requireEvents(t, []ContractEvent{ { {Key: "contract_address", Value: contractAddress.String()}, @@ -5573,7 +5711,7 @@ func TestV1SendsMixedAttributesAndEventsFromInitWithSubmessageWithReply(t *testi attrs, err := parseAndDecryptAttributes(e.Attributes, nonce, true) require.Empty(t, err) - require.Equal(t, + requireLogAttributes(t, []v010cosmwasm.LogAttribute{ {Key: "contract_address", Value: contractAddress.String()}, {Key: "attr1", Value: "🦄"}, @@ -5590,7 +5728,7 @@ func TestV1SendsMixedAttributesAndEventsFromInitWithSubmessageWithReply(t *testi attrs, err := parseAndDecryptAttributes(e.Attributes, nonce, true) require.Empty(t, err) - require.Equal(t, + requireLogAttributes(t, []v010cosmwasm.LogAttribute{ {Key: "contract_address", Value: contractAddress.String()}, {Key: "attr5", Value: "🐙"}, @@ -5607,7 +5745,7 @@ func TestV1SendsMixedAttributesAndEventsFromInitWithSubmessageWithReply(t *testi attrs, err := parseAndDecryptAttributes(e.Attributes, nonce, true) require.Empty(t, err) - require.Equal(t, + requireLogAttributes(t, []v010cosmwasm.LogAttribute{ {Key: "contract_address", Value: contractAddress.String()}, {Key: "attr9", Value: "🤯"}, @@ -5624,7 +5762,7 @@ func TestV1SendsMixedAttributesAndEventsFromInitWithSubmessageWithReply(t *testi require.True(t, hadCyber2) require.True(t, hadCyber3) - require.Equal(t, + requireEvents(t, []ContractEvent{ { {Key: "contract_address", Value: contractAddress.String()}, @@ -5664,7 +5802,7 @@ func TestV1SendsMixedAttributesAndEventsFromExecuteWithoutSubmessageWithoutReply attrs, err := parseAndDecryptAttributes(e.Attributes, nonce, false) require.Empty(t, err) - require.Equal(t, + requireLogAttributes(t, []v010cosmwasm.LogAttribute{ {Key: "contract_address", Value: contractAddress.String()}, {Key: "attr1", Value: "🦄"}, @@ -5679,7 +5817,7 @@ func TestV1SendsMixedAttributesAndEventsFromExecuteWithoutSubmessageWithoutReply require.True(t, hadCyber1) - require.Equal(t, + requireEvents(t, []ContractEvent{ { {Key: "contract_address", Value: contractAddress.String()}, @@ -5710,7 +5848,7 @@ func TestV1SendsMixedAttributesAndEventsFromExecuteWithSubmessageWithoutReply(t attrs, err := parseAndDecryptAttributes(e.Attributes, nonce, true) require.Empty(t, err) - require.Equal(t, + requireLogAttributes(t, []v010cosmwasm.LogAttribute{ {Key: "contract_address", Value: contractAddress.String()}, {Key: "attr1", Value: "🦄"}, @@ -5727,7 +5865,7 @@ func TestV1SendsMixedAttributesAndEventsFromExecuteWithSubmessageWithoutReply(t attrs, err := parseAndDecryptAttributes(e.Attributes, nonce, true) require.Empty(t, err) - require.Equal(t, + requireLogAttributes(t, []v010cosmwasm.LogAttribute{ {Key: "contract_address", Value: contractAddress.String()}, {Key: "attr5", Value: "🐙"}, @@ -5743,7 +5881,7 @@ func TestV1SendsMixedAttributesAndEventsFromExecuteWithSubmessageWithoutReply(t require.True(t, hadCyber1) require.True(t, hadCyber2) - require.Equal(t, + requireEvents(t, []ContractEvent{ { {Key: "contract_address", Value: contractAddress.String()}, @@ -5780,7 +5918,7 @@ func TestV1SendsMixedAttributesAndEventsFromExecuteWithSubmessageWithReply(t *te attrs, err := parseAndDecryptAttributes(e.Attributes, nonce, true) require.Empty(t, err) - require.Equal(t, + requireLogAttributes(t, []v010cosmwasm.LogAttribute{ {Key: "contract_address", Value: contractAddress.String()}, {Key: "attr1", Value: "🦄"}, @@ -5797,7 +5935,7 @@ func TestV1SendsMixedAttributesAndEventsFromExecuteWithSubmessageWithReply(t *te attrs, err := parseAndDecryptAttributes(e.Attributes, nonce, true) require.Empty(t, err) - require.Equal(t, + requireLogAttributes(t, []v010cosmwasm.LogAttribute{ {Key: "contract_address", Value: contractAddress.String()}, {Key: "attr5", Value: "🐙"}, @@ -5814,7 +5952,7 @@ func TestV1SendsMixedAttributesAndEventsFromExecuteWithSubmessageWithReply(t *te attrs, err := parseAndDecryptAttributes(e.Attributes, nonce, true) require.Empty(t, err) - require.Equal(t, + requireLogAttributes(t, []v010cosmwasm.LogAttribute{ {Key: "contract_address", Value: contractAddress.String()}, {Key: "attr9", Value: "🤯"}, @@ -5831,7 +5969,7 @@ func TestV1SendsMixedAttributesAndEventsFromExecuteWithSubmessageWithReply(t *te require.True(t, hadCyber2) require.True(t, hadCyber3) - require.Equal(t, + requireEvents(t, []ContractEvent{ { {Key: "contract_address", Value: contractAddress.String()}, @@ -5862,7 +6000,9 @@ func TestV1SendsLogsMixedWithV010WithoutReply(t *testing.T) { v010CodeID, err := keeper.Create(ctx, walletA, wasmCode, "", "") require.NoError(t, err) - v010CodeHash := hex.EncodeToString(keeper.GetCodeInfo(ctx, v010CodeID).CodeHash) + codeInfo, err := keeper.GetCodeInfo(ctx, v010CodeID) + require.NoError(t, err) + v010CodeHash := hex.EncodeToString(codeInfo.CodeHash) _, _, v010ContractAddress, _, err := initHelper(t, keeper, ctx, v010CodeID, walletA, privKeyA, `{"nop":{}}`, true, false, defaultGasForTests) require.Empty(t, err) @@ -5881,7 +6021,7 @@ func TestV1SendsLogsMixedWithV010WithoutReply(t *testing.T) { attrs, err := parseAndDecryptAttributes(e.Attributes, nonce, true) require.Empty(t, err) - require.Equal(t, + requireLogAttributes(t, []v010cosmwasm.LogAttribute{ {Key: "contract_address", Value: v1ContractAddress.String()}, {Key: "attr1", Value: "🦄"}, @@ -5896,7 +6036,7 @@ func TestV1SendsLogsMixedWithV010WithoutReply(t *testing.T) { require.True(t, hadCyber1) - require.Equal(t, + requireEvents(t, []ContractEvent{ { {Key: "contract_address", Value: v1ContractAddress.String()}, @@ -5922,7 +6062,9 @@ func TestV1SendsLogsMixedWithV010WithReply(t *testing.T) { v010CodeID, err := keeper.Create(ctx, walletA, wasmCode, "", "") require.NoError(t, err) - v010CodeHash := hex.EncodeToString(keeper.GetCodeInfo(ctx, v010CodeID).CodeHash) + codeInfo, err := keeper.GetCodeInfo(ctx, v010CodeID) + require.NoError(t, err) + v010CodeHash := hex.EncodeToString(codeInfo.CodeHash) _, _, v010ContractAddress, _, err := initHelper(t, keeper, ctx, v010CodeID, walletA, privKeyA, `{"nop":{}}`, true, false, defaultGasForTests) require.Empty(t, err) @@ -5942,7 +6084,7 @@ func TestV1SendsLogsMixedWithV010WithReply(t *testing.T) { attrs, err := parseAndDecryptAttributes(e.Attributes, nonce, true) require.Empty(t, err) - require.Equal(t, + requireLogAttributes(t, []v010cosmwasm.LogAttribute{ {Key: "contract_address", Value: v1ContractAddress.String()}, {Key: "attr1", Value: "🦄"}, @@ -5959,7 +6101,7 @@ func TestV1SendsLogsMixedWithV010WithReply(t *testing.T) { attrs, err := parseAndDecryptAttributes(e.Attributes, nonce, true) require.Empty(t, err) - require.Equal(t, + requireLogAttributes(t, []v010cosmwasm.LogAttribute{ {Key: "contract_address", Value: v1ContractAddress.String()}, {Key: "attr9", Value: "🤯"}, @@ -5975,7 +6117,7 @@ func TestV1SendsLogsMixedWithV010WithReply(t *testing.T) { require.True(t, hadCyber1) require.True(t, hadCyber3) - require.Equal(t, + requireEvents(t, []ContractEvent{ { {Key: "contract_address", Value: v1ContractAddress.String()}, @@ -6023,7 +6165,7 @@ func TestV010SendsLogsMixedWithV1(t *testing.T) { attrs, err := parseAndDecryptAttributes(e.Attributes, nonce, true) require.Empty(t, err) - require.Equal(t, + requireLogAttributes(t, []v010cosmwasm.LogAttribute{ {Key: "contract_address", Value: v1ContractAddress.String()}, {Key: "attr5", Value: "🐙"}, @@ -6038,7 +6180,7 @@ func TestV010SendsLogsMixedWithV1(t *testing.T) { require.True(t, hadCyber2) - require.Equal(t, + requireEvents(t, []ContractEvent{ { {Key: "contract_address", Value: v010ContractAddress.String()}, diff --git a/x/compute/internal/keeper/test_common.go b/x/compute/internal/keeper/test_common.go index cb44d21a1..386735766 100644 --- a/x/compute/internal/keeper/test_common.go +++ b/x/compute/internal/keeper/test_common.go @@ -2,6 +2,7 @@ package keeper import ( "encoding/binary" + "encoding/json" "fmt" "os" "testing" @@ -14,7 +15,6 @@ import ( "github.com/cosmos/cosmos-sdk/x/feegrant" upgradekeeper "github.com/cosmos/cosmos-sdk/x/upgrade/keeper" upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" - icahosttypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/host/types" ibctransfertypes "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" ibchost "github.com/cosmos/ibc-go/v3/modules/core/24-host" ibckeeper "github.com/cosmos/ibc-go/v3/modules/core/keeper" @@ -87,6 +87,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/upgrade" upgradeclient "github.com/cosmos/cosmos-sdk/x/upgrade/client" + v1types "github.com/enigmampc/SecretNetwork/go-cosmwasm/types/v1" wasmtypes "github.com/enigmampc/SecretNetwork/x/compute/internal/types" "github.com/enigmampc/SecretNetwork/x/registration" ) @@ -186,27 +187,42 @@ func CreateTestInput(t *testing.T, isCheckTx bool, supportedFeatures string, enc require.NoError(t, err) t.Cleanup(func() { os.RemoveAll(tempDir) }) - keyContract := sdk.NewKVStoreKey(wasmtypes.StoreKey) - keyAcc := sdk.NewKVStoreKey(authtypes.StoreKey) - keyStaking := sdk.NewKVStoreKey(stakingtypes.StoreKey) - keyDistro := sdk.NewKVStoreKey(distrtypes.StoreKey) - mintStore := sdk.NewKVStoreKey(minttypes.StoreKey) - keyParams := sdk.NewKVStoreKey(paramstypes.StoreKey) - tkeyParams := sdk.NewTransientStoreKey(paramstypes.TStoreKey) - keyGov := sdk.NewKVStoreKey(govtypes.StoreKey) - keyBank := sdk.NewKVStoreKey(banktypes.StoreKey) + //keyContract := sdk.NewKVStoreKey(wasmtypes.StoreKey) + //keyAcc := sdk.NewKVStoreKey(authtypes.StoreKey) + //keyStaking := sdk.NewKVStoreKey(stakingtypes.StoreKey) + //keyDistro := sdk.NewKVStoreKey(distrtypes.StoreKey) + //mintStore := sdk.NewKVStoreKey(minttypes.StoreKey) + //keyParams := sdk.NewKVStoreKey(paramstypes.StoreKey) + //tkeyParams := sdk.NewTransientStoreKey(paramstypes.TStoreKey) + //keyGov := sdk.NewKVStoreKey(govtypes.StoreKey) + //keyBank := sdk.NewKVStoreKey(banktypes.StoreKey) + + keys := sdk.NewKVStoreKeys( + authtypes.StoreKey, banktypes.StoreKey, stakingtypes.StoreKey, + minttypes.StoreKey, distrtypes.StoreKey, slashingtypes.StoreKey, + govtypes.StoreKey, paramstypes.StoreKey, ibchost.StoreKey, upgradetypes.StoreKey, + evidencetypes.StoreKey, ibctransfertypes.StoreKey, + capabilitytypes.StoreKey, feegrant.StoreKey, authzkeeper.StoreKey, + wasmtypes.StoreKey, + ) db := dbm.NewMemDB() + ms := store.NewCommitMultiStore(db) - ms.MountStoreWithDB(keyContract, sdk.StoreTypeIAVL, db) - ms.MountStoreWithDB(keyAcc, sdk.StoreTypeIAVL, db) - ms.MountStoreWithDB(keyParams, sdk.StoreTypeIAVL, db) - ms.MountStoreWithDB(keyStaking, sdk.StoreTypeIAVL, db) - ms.MountStoreWithDB(mintStore, sdk.StoreTypeIAVL, db) - ms.MountStoreWithDB(keyDistro, sdk.StoreTypeIAVL, db) - ms.MountStoreWithDB(tkeyParams, sdk.StoreTypeTransient, db) - ms.MountStoreWithDB(keyGov, sdk.StoreTypeIAVL, db) - ms.MountStoreWithDB(keyBank, sdk.StoreTypeIAVL, db) + for _, v := range keys { + ms.MountStoreWithDB(v, sdk.StoreTypeIAVL, db) + } + + tkeys := sdk.NewTransientStoreKeys(paramstypes.TStoreKey) + for _, v := range tkeys { + ms.MountStoreWithDB(v, sdk.StoreTypeTransient, db) + } + + memKeys := sdk.NewMemoryStoreKeys(capabilitytypes.MemStoreKey) + for _, v := range memKeys { + ms.MountStoreWithDB(v, sdk.StoreTypeMemory, db) + } + require.NoError(t, ms.LoadLatestVersion()) ctx := sdk.NewContext(ms, tmproto.Header{ @@ -215,7 +231,12 @@ func CreateTestInput(t *testing.T, isCheckTx bool, supportedFeatures string, enc ChainID: TestConfig.ChainID, }, isCheckTx, log.NewNopLogger()) encodingConfig := MakeEncodingConfig() - paramsKeeper := paramskeeper.NewKeeper(encodingConfig.Marshaler, encodingConfig.Amino, keyParams, tkeyParams) + paramsKeeper := paramskeeper.NewKeeper( + encodingConfig.Marshaler, + encodingConfig.Amino, + keys[paramstypes.StoreKey], + tkeys[paramstypes.TStoreKey], + ) paramsKeeper.Subspace(authtypes.ModuleName) paramsKeeper.Subspace(banktypes.ModuleName) paramsKeeper.Subspace(stakingtypes.ModuleName) @@ -238,7 +259,7 @@ func CreateTestInput(t *testing.T, isCheckTx bool, supportedFeatures string, enc authSubsp, _ := paramsKeeper.GetSubspace(authtypes.ModuleName) authKeeper := authkeeper.NewAccountKeeper( encodingConfig.Marshaler, - keyAcc, // target store + keys[authtypes.StoreKey], // target store authSubsp, authtypes.ProtoBaseAccount, // prototype maccPerms, @@ -252,7 +273,7 @@ func CreateTestInput(t *testing.T, isCheckTx bool, supportedFeatures string, enc bankSubsp, _ := paramsKeeper.GetSubspace(banktypes.ModuleName) bankKeeper := bankkeeper.NewBaseKeeper( encodingConfig.Marshaler, - keyBank, + keys[banktypes.StoreKey], authKeeper, bankSubsp, blockedAddrs, @@ -262,7 +283,13 @@ func CreateTestInput(t *testing.T, isCheckTx bool, supportedFeatures string, enc bankKeeper.SetParams(ctx, banktypes.DefaultParams()) stakingSubsp, _ := paramsKeeper.GetSubspace(stakingtypes.ModuleName) - stakingKeeper := stakingkeeper.NewKeeper(encodingConfig.Marshaler, keyStaking, authKeeper, bankKeeper, stakingSubsp) + stakingKeeper := stakingkeeper.NewKeeper( + encodingConfig.Marshaler, + keys[stakingtypes.StoreKey], + authKeeper, + bankKeeper, + stakingSubsp, + ) stakingKeeper.SetParams(ctx, TestingStakeParams) // mintSubsp, _ := paramsKeeper.GetSubspace(minttypes.ModuleName) @@ -281,7 +308,7 @@ func CreateTestInput(t *testing.T, isCheckTx bool, supportedFeatures string, enc distSubsp, _ := paramsKeeper.GetSubspace(distrtypes.ModuleName) distKeeper := distrkeeper.NewKeeper( encodingConfig.Marshaler, - keyDistro, + keys[distrtypes.StoreKey], distSubsp, authKeeper, bankKeeper, @@ -301,7 +328,7 @@ func CreateTestInput(t *testing.T, isCheckTx bool, supportedFeatures string, enc distrAcc := authtypes.NewEmptyModuleAccount(distrtypes.ModuleName) totalSupply := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(2000000))) - err := bankKeeper.MintCoins(ctx, faucetAccountName, totalSupply) + err = bankKeeper.MintCoins(ctx, faucetAccountName, totalSupply) require.NoError(t, err) // err = bankKeeper.SendCoinsFromModuleToAccount(ctx, faucetAccountName, distrAcc.GetAddress(), totalSupply) @@ -334,14 +361,14 @@ func CreateTestInput(t *testing.T, isCheckTx bool, supportedFeatures string, enc // AddRoute(wasmtypes.RouterKey, NewWasmProposalHandler(keeper, wasmtypes.EnableAllProposals)) govKeeper := govkeeper.NewKeeper( - encodingConfig.Marshaler, keyGov, paramsKeeper.Subspace(govtypes.ModuleName).WithKeyTable(govtypes.ParamKeyTable()), authKeeper, bankKeeper, stakingKeeper, govRouter, + encodingConfig.Marshaler, keys[govtypes.StoreKey], paramsKeeper.Subspace(govtypes.ModuleName).WithKeyTable(govtypes.ParamKeyTable()), authKeeper, bankKeeper, stakingKeeper, govRouter, ) // bank := bankKeeper. // bk := bank.Keeper(bankKeeper) mintSubsp, _ := paramsKeeper.GetSubspace(minttypes.ModuleName) - mintKeeper := mintkeeper.NewKeeper(encodingConfig.Marshaler, mintStore, mintSubsp, stakingKeeper, authKeeper, bankKeeper, authtypes.FeeCollectorName) + mintKeeper := mintkeeper.NewKeeper(encodingConfig.Marshaler, keys[minttypes.StoreKey], mintSubsp, stakingKeeper, authKeeper, bankKeeper, authtypes.FeeCollectorName) mintKeeper.SetMinter(ctx, minttypes.DefaultInitialMinter()) // keeper := NewKeeper(cdc, keyContract, accountKeeper, &bk, &govKeeper, &distKeeper, &mintKeeper, &stakingKeeper, router, tempDir, wasmConfig, supportedFeatures, encoders, queriers) @@ -358,15 +385,17 @@ func CreateTestInput(t *testing.T, isCheckTx bool, supportedFeatures string, enc // Load default wasm config wasmConfig := wasmtypes.DefaultWasmConfig() - keys := sdk.NewKVStoreKeys( - authtypes.StoreKey, banktypes.StoreKey, stakingtypes.StoreKey, - minttypes.StoreKey, distrtypes.StoreKey, slashingtypes.StoreKey, - govtypes.StoreKey, paramstypes.StoreKey, ibchost.StoreKey, upgradetypes.StoreKey, - evidencetypes.StoreKey, ibctransfertypes.StoreKey, capabilitytypes.StoreKey, - feegrant.StoreKey, authzkeeper.StoreKey, icahosttypes.StoreKey, - ) - - memKeys := sdk.NewMemoryStoreKeys(capabilitytypes.MemStoreKey) + //keys := sdk.NewKVStoreKeys( + // authtypes.StoreKey, banktypes.StoreKey, stakingtypes.StoreKey, + // minttypes.StoreKey, distrtypes.StoreKey, slashingtypes.StoreKey, + // govtypes.StoreKey, paramstypes.StoreKey, ibchost.StoreKey, upgradetypes.StoreKey, + // evidencetypes.StoreKey, ibctransfertypes.StoreKey, capabilitytypes.StoreKey, "compute", + // feegrant.StoreKey, authzkeeper.StoreKey, icahosttypes.StoreKey, + //) + //memKeys := sdk.NewMemoryStoreKeys(capabilitytypes.MemStoreKey) + //for _, v := range memKeys { + // ms.MountStoreWithDB(v, sdk.StoreTypeMemory, db) + //} upgradeKeeper := upgradekeeper.NewKeeper( map[int64]bool{}, @@ -383,11 +412,16 @@ func CreateTestInput(t *testing.T, isCheckTx bool, supportedFeatures string, enc ) scopedIBCKeeper := capabilityKeeper.ScopeToModule(ibchost.ModuleName) - scopedWasmKeeper := capabilityKeeper.ScopeToModule("compute") + scopedWasmKeeper := capabilityKeeper.ScopeToModule(wasmtypes.ModuleName) ibchostSubSp, _ := paramsKeeper.GetSubspace(ibchost.ModuleName) ibcKeeper := ibckeeper.NewKeeper( - encodingConfig.Marshaler, keys[ibchost.StoreKey], ibchostSubSp, stakingKeeper, upgradeKeeper, scopedIBCKeeper, + encodingConfig.Marshaler, + keys[ibchost.StoreKey], + ibchostSubSp, + stakingKeeper, + upgradeKeeper, + scopedIBCKeeper, ) // todo: new grpc routing @@ -403,10 +437,15 @@ func CreateTestInput(t *testing.T, isCheckTx bool, supportedFeatures string, enc // stakingtypes.RegisterMsgServer(serviceRouter, stakingMsgServer) // distrtypes.RegisterMsgServer(serviceRouter, distrMsgServer) + queryRouter := baseapp.NewGRPCQueryRouter() + queryRouter.SetInterfaceRegistry(encodingConfig.InterfaceRegistry) + msgRouter := baseapp.NewMsgServiceRouter() + msgRouter.SetInterfaceRegistry(encodingConfig.InterfaceRegistry) + keeper := NewKeeper( encodingConfig.Marshaler, *encodingConfig.Amino, - keyContract, + keys[wasmtypes.StoreKey], authKeeper, bankKeeper, govKeeper, @@ -419,6 +458,8 @@ func CreateTestInput(t *testing.T, isCheckTx bool, supportedFeatures string, enc MockIBCTransferKeeper{}, ibcKeeper.ChannelKeeper, router, + msgRouter, + queryRouter, tempDir, wasmConfig, supportedFeatures, @@ -429,6 +470,16 @@ func CreateTestInput(t *testing.T, isCheckTx bool, supportedFeatures string, enc // add wasm handler so we can loop-back (contracts calling contracts) router.AddRoute(sdk.NewRoute(wasmtypes.RouterKey, TestHandler(keeper))) + am := module.NewManager( // minimal module set that we use for message/ query tests + bank.NewAppModule(encodingConfig.Marshaler, bankKeeper, authKeeper), + staking.NewAppModule(encodingConfig.Marshaler, stakingKeeper, authKeeper, bankKeeper), + distribution.NewAppModule(encodingConfig.Marshaler, distKeeper, authKeeper, bankKeeper, stakingKeeper), + gov.NewAppModule(encodingConfig.Marshaler, govKeeper, authKeeper, bankKeeper), + ) + am.RegisterServices(module.NewConfigurator(encodingConfig.Marshaler, msgRouter, queryRouter)) + wasmtypes.RegisterMsgServer(msgRouter, NewMsgServerImpl(keeper)) + wasmtypes.RegisterQueryServer(queryRouter, NewGrpcQuerier(keeper)) + keepers := TestKeepers{ AccountKeeper: authKeeper, StakingKeeper: stakingKeeper, @@ -492,20 +543,13 @@ func handleExecute(ctx sdk.Context, k Keeper, msg *wasmtypes.MsgExecuteContract) return res, nil } -func PrepareInitSignedTx(t *testing.T, keeper Keeper, ctx sdk.Context, creator sdk.AccAddress, privKey crypto.PrivKey, encMsg []byte, codeID uint64, funds sdk.Coins) sdk.Context { - creatorAcc, err := ante.GetSignerAcc(ctx, keeper.accountKeeper, creator) - require.NoError(t, err) - - initMsg := wasmtypes.MsgInstantiateContract{ - Sender: creator, - CodeID: codeID, - Label: "demo contract 1", - InitMsg: encMsg, - InitFunds: funds, +func PrepareIBCOpenAck(t *testing.T, keeper Keeper, ctx sdk.Context, ibcOpenAck v1types.IBCOpenAck, ibcOpenConfirm v1types.IBCOpenConfirm) sdk.Context { + channelConnectMsg := v1types.IBCChannelConnectMsg{ + OpenAck: &ibcOpenAck, + OpenConfirm: &ibcOpenConfirm, } - tx := NewTestTx(&initMsg, creatorAcc, privKey) - txBytes, err := tx.Marshal() + txBytes, err := json.Marshal(channelConnectMsg) require.NoError(t, err) return ctx.WithTxBytes(txBytes) @@ -529,6 +573,25 @@ func PrepareExecSignedTx(t *testing.T, keeper Keeper, ctx sdk.Context, sender sd return ctx.WithTxBytes(txBytes) } +func PrepareInitSignedTx(t *testing.T, keeper Keeper, ctx sdk.Context, creator sdk.AccAddress, privKey crypto.PrivKey, encMsg []byte, codeID uint64, funds sdk.Coins) sdk.Context { + creatorAcc, err := ante.GetSignerAcc(ctx, keeper.accountKeeper, creator) + require.NoError(t, err) + + initMsg := wasmtypes.MsgInstantiateContract{ + Sender: creator, + CodeID: codeID, + Label: "demo contract 1", + InitMsg: encMsg, + InitFunds: funds, + } + tx := NewTestTx(&initMsg, creatorAcc, privKey) + + txBytes, err := tx.Marshal() + require.NoError(t, err) + + return ctx.WithTxBytes(txBytes) +} + func NewTestTx(msg sdk.Msg, creatorAcc authtypes.AccountI, privKey crypto.PrivKey) *tx.Tx { return NewTestTxMultiple([]sdk.Msg{msg}, []authtypes.AccountI{creatorAcc}, []crypto.PrivKey{privKey}) } diff --git a/x/compute/internal/keeper/testdata/ibc/.gitignore b/x/compute/internal/keeper/testdata/ibc/.gitignore new file mode 100644 index 000000000..0e24e33d5 --- /dev/null +++ b/x/compute/internal/keeper/testdata/ibc/.gitignore @@ -0,0 +1,13 @@ +# Build results +/target +*.wasm + +# Text file backups +**/*.rs.bk + +# macOS +.DS_Store + +# IDEs +*.iml +.idea diff --git a/x/compute/internal/keeper/testdata/ibc/Cargo.lock b/x/compute/internal/keeper/testdata/ibc/Cargo.lock new file mode 100644 index 000000000..cd7e008a5 --- /dev/null +++ b/x/compute/internal/keeper/testdata/ibc/Cargo.lock @@ -0,0 +1,639 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "base16ct" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce" + +[[package]] +name = "base64" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" + +[[package]] +name = "base64ct" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bdca834647821e0b13d9539a8634eb62d3501b6b6c2cec1722786ee6671b851" + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array", +] + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "cc" +version = "1.0.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "const-oid" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4c78c047431fee22c1a7bb92e00ad095a02a983affe4d8a72e2a2c62c1b94f3" + +[[package]] +name = "cosmwasm-crypto" +version = "1.0.0" +source = "git+https://github.com/scrtlabs/cosmwasm?branch=secret#e69869a8565e4e2318bdbfd3711fd1ceda0db209" +dependencies = [ + "digest", + "ed25519-zebra", + "k256", + "rand_core 0.6.3", + "thiserror", +] + +[[package]] +name = "cosmwasm-derive" +version = "1.0.0" +source = "git+https://github.com/scrtlabs/cosmwasm?branch=secret#e69869a8565e4e2318bdbfd3711fd1ceda0db209" +dependencies = [ + "syn", +] + +[[package]] +name = "cosmwasm-std" +version = "1.0.0" +source = "git+https://github.com/scrtlabs/cosmwasm?branch=secret#e69869a8565e4e2318bdbfd3711fd1ceda0db209" +dependencies = [ + "base64", + "cosmwasm-crypto", + "cosmwasm-derive", + "forward_ref", + "schemars", + "serde", + "serde-json-wasm 0.4.1", + "thiserror", + "uint", +] + +[[package]] +name = "cosmwasm-storage" +version = "1.0.0" +source = "git+https://github.com/scrtlabs/cosmwasm?branch=secret#e69869a8565e4e2318bdbfd3711fd1ceda0db209" +dependencies = [ + "cosmwasm-std", + "serde", +] + +[[package]] +name = "cpufeatures" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59a6001667ab124aebae2a495118e11d30984c3a653e99d86d58971708cf5e4b" +dependencies = [ + "libc", +] + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "crypto-bigint" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03c6a1d5fa1de37e071642dfa44ec552ca5b299adb128fab16138e24b548fd21" +dependencies = [ + "generic-array", + "rand_core 0.6.3", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-mac" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714" +dependencies = [ + "generic-array", + "subtle", +] + +[[package]] +name = "curve25519-dalek" +version = "3.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90f9d052967f590a76e62eb387bd0bbb1b000182c3cefe5364db6b7211651bc0" +dependencies = [ + "byteorder", + "digest", + "rand_core 0.5.1", + "subtle", + "zeroize", +] + +[[package]] +name = "der" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6919815d73839e7ad218de758883aae3a257ba6759ce7a9992501efbb53d705c" +dependencies = [ + "const-oid", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + +[[package]] +name = "dyn-clone" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d07a982d1fb29db01e5a59b1918e03da4df7297eaeee7686ac45542fd4e59c8" + +[[package]] +name = "ecdsa" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0d69ae62e0ce582d56380743515fefaf1a8c70cec685d9677636d7e30ae9dc9" +dependencies = [ + "der", + "elliptic-curve", + "rfc6979", + "signature", +] + +[[package]] +name = "ed25519-zebra" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "403ef3e961ab98f0ba902771d29f842058578bb1ce7e3c59dad5a6a93e784c69" +dependencies = [ + "curve25519-dalek", + "hex", + "rand_core 0.6.3", + "serde", + "sha2", + "thiserror", + "zeroize", +] + +[[package]] +name = "elliptic-curve" +version = "0.11.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25b477563c2bfed38a3b7a60964c49e058b2510ad3f12ba3483fd8f62c2306d6" +dependencies = [ + "base16ct", + "crypto-bigint", + "der", + "ff", + "generic-array", + "group", + "rand_core 0.6.3", + "sec1", + "subtle", + "zeroize", +] + +[[package]] +name = "ff" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "131655483be284720a17d74ff97592b8e76576dc25563148601df2d7c9080924" +dependencies = [ + "rand_core 0.6.3", + "subtle", +] + +[[package]] +name = "forward_ref" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8cbd1169bd7b4a0a20d92b9af7a7e0422888bd38a6f5ec29c1fd8c1558a272e" + +[[package]] +name = "generic-array" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", +] + +[[package]] +name = "group" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc5ac374b108929de78460075f3dc439fa66df9d8fc77e8f12caa5165fcf0c89" +dependencies = [ + "ff", + "rand_core 0.6.3", + "subtle", +] + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hmac" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" +dependencies = [ + "crypto-mac", + "digest", +] + +[[package]] +name = "ibc" +version = "0.0.1" +dependencies = [ + "cosmwasm-std", + "cosmwasm-storage", + "schemars", + "secp256k1", + "serde", + "serde-json-wasm 0.2.3", +] + +[[package]] +name = "itoa" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" + +[[package]] +name = "k256" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19c3a5e0a0b8450278feda242592512e09f61c72e018b8cd5c859482802daf2d" +dependencies = [ + "cfg-if", + "ecdsa", + "elliptic-curve", + "sec1", + "sha2", +] + +[[package]] +name = "libc" +version = "0.2.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" + +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + +[[package]] +name = "pkcs8" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cabda3fb821068a9a4fab19a683eac3af12edf0f34b94a8be53c4972b8149d0" +dependencies = [ + "der", + "spki", + "zeroize", +] + +[[package]] +name = "proc-macro2" +version = "1.0.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c278e965f1d8cf32d6e0e96de3d3e79712178ae67986d9cf9151f51e95aac89b" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom 0.1.16", +] + +[[package]] +name = "rand_core" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" +dependencies = [ + "getrandom 0.2.7", +] + +[[package]] +name = "rfc6979" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96ef608575f6392792f9ecf7890c00086591d29a83910939d430753f7c050525" +dependencies = [ + "crypto-bigint", + "hmac", + "zeroize", +] + +[[package]] +name = "ryu" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695" + +[[package]] +name = "schemars" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1847b767a3d62d95cbf3d8a9f0e421cf57a0d8aa4f411d4b16525afb0284d4ed" +dependencies = [ + "dyn-clone", + "schemars_derive", + "serde", + "serde_json", +] + +[[package]] +name = "schemars_derive" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af4d7e1b012cb3d9129567661a63755ea4b8a7386d339dc945ae187e403c6743" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals", + "syn", +] + +[[package]] +name = "sec1" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08da66b8b0965a5555b6bd6639e68ccba85e1e2506f5fbb089e93f8a04e1a2d1" +dependencies = [ + "der", + "generic-array", + "pkcs8", + "subtle", + "zeroize", +] + +[[package]] +name = "secp256k1" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97d03ceae636d0fed5bae6a7f4f664354c5f4fcedf6eef053fef17e49f837d0a" +dependencies = [ + "secp256k1-sys", +] + +[[package]] +name = "secp256k1-sys" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "957da2573cde917463ece3570eab4a0b3f19de6f1646cde62e6fd3868f566036" +dependencies = [ + "cc", +] + +[[package]] +name = "serde" +version = "1.0.140" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc855a42c7967b7c369eb5860f7164ef1f6f81c20c7cc1141f2a604e18723b03" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde-json-wasm" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "120bad73306616e91acd7ceed522ba96032a51cffeef3cc813de7f367df71e37" +dependencies = [ + "serde", +] + +[[package]] +name = "serde-json-wasm" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479b4dbc401ca13ee8ce902851b834893251404c4f3c65370a49e047a6be09a5" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.140" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f2122636b9fe3b81f1cb25099fcf2d3f542cdb1d45940d56c713158884a05da" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_derive_internals" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85bf8229e7920a9f636479437026331ce11aa132b4dde37d121944a44d6e5f3c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82c2c1fdcd807d1098552c5b9a36e425e42e9fbd7c6a37a8425f390f781f7fa7" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer", + "cfg-if", + "cpufeatures", + "digest", + "opaque-debug", +] + +[[package]] +name = "signature" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02658e48d89f2bec991f9a78e69cfa4c316f8d6a6c4ec12fae1aeb263d486788" +dependencies = [ + "digest", + "rand_core 0.6.3", +] + +[[package]] +name = "spki" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d01ac02a6ccf3e07db148d2be087da624fea0221a16152ed01f0496a6b0a27" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "subtle" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" + +[[package]] +name = "syn" +version = "1.0.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "1.0.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "typenum" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" + +[[package]] +name = "uint" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12f03af7ccf01dd611cc450a0d10dbc9b745770d096473e2faf0ca6e2d66d1e0" +dependencies = [ + "byteorder", + "crunchy", + "hex", + "static_assertions", +] + +[[package]] +name = "unicode-ident" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15c61ba63f9235225a22310255a29b806b907c9b8c964bcbd0a2c70f3f2deea7" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "zeroize" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4756f7db3f7b5574938c3eb1c117038b8e07f95ee6718c0efad4ac21508f1efd" diff --git a/x/compute/internal/keeper/testdata/ibc/Cargo.toml b/x/compute/internal/keeper/testdata/ibc/Cargo.toml new file mode 100644 index 000000000..f1271dd60 --- /dev/null +++ b/x/compute/internal/keeper/testdata/ibc/Cargo.toml @@ -0,0 +1,44 @@ +[package] +name = "ibc" +version = "0.0.1" +authors = ["Enigma "] +edition = "2018" +description = "A Test contract intended to use in system tests for the Secret Netowrk" +license = "MIT" +exclude = [ + # Those files are cosmwasm-opt artifacts. You might want to commit them for convenience but they should not be part of the source code publication. + "ibc.wasm", +] + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[lib] +crate-type = ["cdylib", "rlib"] + +[profile.release] +opt-level = 3 +debug = false +rpath = false +lto = true +debug-assertions = false +codegen-units = 1 +panic = 'abort' +incremental = false +overflow-checks = true + +[features] +default = [] +backtraces = ["cosmwasm-std/backtraces"] +with_floats = [] +stargate = [] +ibc3 = ["stargate"] + +[dependencies] +cosmwasm-std = { git = "https://github.com/scrtlabs/cosmwasm", branch = "secret", features=["stargate", "ibc3"] } +cosmwasm-storage = { git = "https://github.com/scrtlabs/cosmwasm", branch = "secret" } +schemars = "0.8.1" +serde = { version = "1.0.114", default-features = false, features = [ + "derive", + "alloc" +] } +serde-json-wasm = "0.2.1" +secp256k1 = "0.20.3" diff --git a/x/compute/internal/keeper/testdata/ibc/Makefile b/x/compute/internal/keeper/testdata/ibc/Makefile new file mode 100644 index 000000000..b6bb9953e --- /dev/null +++ b/x/compute/internal/keeper/testdata/ibc/Makefile @@ -0,0 +1,8 @@ +all: src/contract.rs src/lib.rs src/msg.rs src/state.rs Cargo.toml Cargo.lock + rustup target add wasm32-unknown-unknown + RUSTFLAGS='-C link-arg=-s' cargo build --release --target wasm32-unknown-unknown + cp ./target/wasm32-unknown-unknown/release/ibc.wasm ./contract.wasm + +clean: + cargo clean + -rm -f ./contract.wasm \ No newline at end of file diff --git a/x/compute/internal/keeper/testdata/ibc/rust-toolchain b/x/compute/internal/keeper/testdata/ibc/rust-toolchain new file mode 100644 index 000000000..a7efc46ca --- /dev/null +++ b/x/compute/internal/keeper/testdata/ibc/rust-toolchain @@ -0,0 +1 @@ +1.61 \ No newline at end of file diff --git a/x/compute/internal/keeper/testdata/ibc/src/contract.rs b/x/compute/internal/keeper/testdata/ibc/src/contract.rs new file mode 100644 index 000000000..3bf55f262 --- /dev/null +++ b/x/compute/internal/keeper/testdata/ibc/src/contract.rs @@ -0,0 +1,314 @@ +use crate::msg::{ExecuteMsg, InstantiateMsg, QueryMsg}; +use crate::state::{count, count_read}; +use cosmwasm_std::{ + entry_point, to_binary, Binary, CosmosMsg, Deps, DepsMut, Env, Event, Ibc3ChannelOpenResponse, + IbcBasicResponse, IbcChannelCloseMsg, IbcChannelConnectMsg, IbcChannelOpenMsg, + IbcChannelOpenResponse, IbcPacketAckMsg, IbcPacketReceiveMsg, IbcPacketTimeoutMsg, + IbcReceiveResponse, MessageInfo, Reply, ReplyOn, Response, StdError, StdResult, SubMsg, + SubMsgResult, WasmMsg, +}; +use serde::{Deserialize, Serialize}; +use serde_json_wasm as serde_json; + +pub const IBC_APP_VERSION: &str = "ibc-v1"; + +#[entry_point] +pub fn instantiate( + _deps: DepsMut, + _env: Env, + _info: MessageInfo, + _msg: InstantiateMsg, +) -> StdResult { + Ok(Response::default()) +} + +#[entry_point] +pub fn execute( + deps: DepsMut, + _env: Env, + _info: MessageInfo, + msg: ExecuteMsg, +) -> StdResult { + match msg { + ExecuteMsg::Increment { addition } => increment(deps, addition), + } +} + +#[entry_point] +pub fn query(deps: Deps, _env: Env, _msg: QueryMsg) -> StdResult { + let answer = count_read(deps.storage).load()?; + Ok(to_binary(&answer)?) +} + +#[entry_point] +pub fn reply(deps: DepsMut, env: Env, reply: Reply) -> StdResult { + match (reply.id, reply.result) { + (1, SubMsgResult::Err(_)) => Err(StdError::generic_err("Failed to inc")), + (1, SubMsgResult::Ok(_)) => { + increment(deps, 6)?; + Ok(Response::new().set_data(to_binary(&"out".to_string())?)) + } + (2, SubMsgResult::Err(_)) => Err(StdError::generic_err("Failed to inc")), + (2, SubMsgResult::Ok(_)) => { + increment(deps, 6)?; + Ok(Response::new().add_submessage(SubMsg { + id: 1, + msg: CosmosMsg::Wasm(WasmMsg::Execute { + code_hash: env.contract.code_hash, + contract_addr: env.contract.address.into_string(), + msg: Binary::from("{\"increment\":{\"addition\":5}}".as_bytes().to_vec()), + funds: vec![], + }) + .into(), + reply_on: ReplyOn::Always, + gas_limit: None, + })) + } + _ => Err(StdError::generic_err("invalid reply id or result")), + } +} + +#[entry_point] +pub fn ibc_channel_open( + deps: DepsMut, + _env: Env, + msg: IbcChannelOpenMsg, +) -> StdResult { + match msg { + IbcChannelOpenMsg::OpenInit { channel: _ } => count(deps.storage).save(&1)?, + IbcChannelOpenMsg::OpenTry { + channel: _, + counterparty_version: _, + } => count(deps.storage).save(&2)?, + _ => {} + } + + Ok(Some(Ibc3ChannelOpenResponse { + version: IBC_APP_VERSION.to_string(), + })) +} + +pub fn increment(deps: DepsMut, c: u64) -> StdResult { + let new_count = count_read(deps.storage).load()? + c; + count(deps.storage).save(&new_count)?; + + let mut resp = Response::default(); + resp.data = Some((new_count as u32).to_be_bytes().into()); + + Ok(resp) +} + +pub fn get_resp_based_on_num(env: Env, num: u64) -> StdResult { + match num { + 0 => Ok(IbcBasicResponse::default()), + 1 => Ok(IbcBasicResponse::new().add_submessage(SubMsg { + id: 1, + msg: CosmosMsg::Wasm(WasmMsg::Execute { + code_hash: env.contract.code_hash, + contract_addr: env.contract.address.into_string(), + msg: Binary::from("{\"increment\":{\"addition\":5}}".as_bytes().to_vec()), + funds: vec![], + }) + .into(), + reply_on: ReplyOn::Never, + gas_limit: None, + })), + 2 => Ok(IbcBasicResponse::new().add_submessage(SubMsg { + id: 1, + msg: CosmosMsg::Wasm(WasmMsg::Execute { + code_hash: env.contract.code_hash, + contract_addr: env.contract.address.into_string(), + msg: Binary::from("{\"increment\":{\"addition\":5}}".as_bytes().to_vec()), + funds: vec![], + }) + .into(), + reply_on: ReplyOn::Always, + gas_limit: None, + })), + 3 => Ok(IbcBasicResponse::new().add_attribute("attr1", "😗")), + 4 => Ok(IbcBasicResponse::new() + .add_event(Event::new("cyber1".to_string()).add_attribute("attr1", "🤯"))), + 5 => Err(StdError::generic_err("Intentional")), + _ => Err(StdError::generic_err("Unsupported channel connect type")), + } +} + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] +pub struct ContractInfo { + pub address: String, + pub hash: String, +} + +pub fn is_reply_on(num: u64) -> bool { + match num { + 2 | 6 => true, + _ => false, + } +} + +pub fn get_recv_resp_based_on_num( + env: Env, + num: u64, + data: Binary, +) -> StdResult { + match num { + 0 => Ok(IbcReceiveResponse::default()), + 1 => Ok(IbcReceiveResponse::new().add_submessage(SubMsg { + id: 1, + msg: CosmosMsg::Wasm(WasmMsg::Execute { + code_hash: env.contract.code_hash, + contract_addr: env.contract.address.into_string(), + msg: Binary::from("{\"increment\":{\"addition\":5}}".as_bytes().to_vec()), + funds: vec![], + }) + .into(), + reply_on: ReplyOn::Never, + gas_limit: None, + })), + 2 => Ok(IbcReceiveResponse::new().add_submessage(SubMsg { + id: 1, + msg: CosmosMsg::Wasm(WasmMsg::Execute { + code_hash: env.contract.code_hash, + contract_addr: env.contract.address.into_string(), + msg: Binary::from("{\"increment\":{\"addition\":5}}".as_bytes().to_vec()), + funds: vec![], + }) + .into(), + reply_on: ReplyOn::Always, + gas_limit: None, + })), + 3 => Ok(IbcReceiveResponse::new().add_attribute("attr1", "😗")), + 4 => Ok(IbcReceiveResponse::new() + .add_event(Event::new("cyber1".to_string()).add_attribute("attr1", "🤯"))), + 5 => Err(StdError::generic_err("Intentional")), + 6 => Ok(IbcReceiveResponse::new().add_submessage(SubMsg { + id: 2, + msg: CosmosMsg::Wasm(WasmMsg::Execute { + code_hash: env.contract.code_hash, + contract_addr: env.contract.address.into_string(), + msg: Binary::from("{\"increment\":{\"addition\":5}}".as_bytes().to_vec()), + funds: vec![], + }) + .into(), + reply_on: ReplyOn::Always, + gas_limit: None, + })), + 7 => { + let contract_info: ContractInfo = serde_json::from_slice(data.as_slice()).unwrap(); + Ok(IbcReceiveResponse::new().add_submessage(SubMsg { + id: 1, + msg: CosmosMsg::Wasm(WasmMsg::Execute { + code_hash: contract_info.hash, + contract_addr: contract_info.address, + msg: Binary::from( + "{\"increment_from_v1\":{\"addition\":5}}" + .as_bytes() + .to_vec(), + ), + funds: vec![], + }) + .into(), + reply_on: ReplyOn::Always, + gas_limit: None, + })) + } + _ => Err(StdError::generic_err("Unsupported channel connect type")), + } +} + +#[entry_point] +pub fn ibc_channel_connect( + deps: DepsMut, + env: Env, + msg: IbcChannelConnectMsg, +) -> StdResult { + match msg { + IbcChannelConnectMsg::OpenAck { + channel: _, + counterparty_version: _, + } => { + count(deps.storage).save(&3)?; + Ok(IbcBasicResponse::default()) + } + IbcChannelConnectMsg::OpenConfirm { channel } => { + let num: u64 = channel.connection_id.parse::().map_err(|err| { + StdError::generic_err(format!("Got an error from parsing: {:?}", err)) + })?; + + count(deps.storage).save(&(num + 4))?; + + get_resp_based_on_num(env, num) + } + _ => Err(StdError::generic_err("Unsupported channel connect")), + } +} + +#[entry_point] +pub fn ibc_channel_close( + deps: DepsMut, + env: Env, + msg: IbcChannelCloseMsg, +) -> StdResult { + match msg { + IbcChannelCloseMsg::CloseInit { channel: _ } => { + count(deps.storage).save(&5)?; + Ok(IbcBasicResponse::default()) + } + IbcChannelCloseMsg::CloseConfirm { channel } => { + let num: u64 = channel.connection_id.parse::().map_err(|err| { + StdError::generic_err(format!("Got an error from parsing: {:?}", err)) + })?; + + count(deps.storage).save(&(num + 6))?; + get_resp_based_on_num(env, num) + } + _ => Err(StdError::generic_err("Unsupported channel close")), + } +} + +#[entry_point] +pub fn ibc_packet_receive( + deps: DepsMut, + env: Env, + msg: IbcPacketReceiveMsg, +) -> StdResult { + count(deps.storage).save(&(msg.packet.sequence + 7))?; + let mut resp = get_recv_resp_based_on_num(env, msg.packet.sequence, msg.packet.data); + match &mut resp { + Ok(r) => { + if !is_reply_on(msg.packet.sequence) { + r.acknowledgement = to_binary(&"out".to_string())?; + } + } + Err(_) => {} + } + + resp +} + +#[entry_point] +pub fn ibc_packet_ack( + deps: DepsMut, + env: Env, + msg: IbcPacketAckMsg, +) -> StdResult { + let mut ack = [0u8; 8]; + ack.copy_from_slice(&msg.acknowledgement.data.as_slice()[0..8]); + + if u64::from_le_bytes(ack) != msg.original_packet.sequence { + return Err(StdError::generic_err("Wrong ack")); + } + + count(deps.storage).save(&(msg.original_packet.sequence + 8))?; + get_resp_based_on_num(env, msg.original_packet.sequence) +} + +#[entry_point] +pub fn ibc_packet_timeout( + deps: DepsMut, + env: Env, + msg: IbcPacketTimeoutMsg, +) -> StdResult { + count(deps.storage).save(&(msg.packet.sequence + 9))?; + get_resp_based_on_num(env, msg.packet.sequence) +} diff --git a/x/compute/internal/keeper/testdata/ibc/src/lib.rs b/x/compute/internal/keeper/testdata/ibc/src/lib.rs new file mode 100644 index 000000000..04ade40ed --- /dev/null +++ b/x/compute/internal/keeper/testdata/ibc/src/lib.rs @@ -0,0 +1,3 @@ +pub mod contract; +pub mod msg; +pub mod state; \ No newline at end of file diff --git a/x/compute/internal/keeper/testdata/ibc/src/msg.rs b/x/compute/internal/keeper/testdata/ibc/src/msg.rs new file mode 100644 index 000000000..8b51690a7 --- /dev/null +++ b/x/compute/internal/keeper/testdata/ibc/src/msg.rs @@ -0,0 +1,20 @@ +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] +#[serde(rename_all = "snake_case")] +pub enum InstantiateMsg { + Init {}, +} + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] +#[serde(rename_all = "snake_case")] +pub enum ExecuteMsg { + Increment { addition: u64 }, +} + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[serde(rename_all = "snake_case")] +pub enum QueryMsg { + Q {}, +} diff --git a/x/compute/internal/keeper/testdata/ibc/src/state.rs b/x/compute/internal/keeper/testdata/ibc/src/state.rs new file mode 100644 index 000000000..58b97292f --- /dev/null +++ b/x/compute/internal/keeper/testdata/ibc/src/state.rs @@ -0,0 +1,16 @@ +use cosmwasm_std::{Storage}; +use cosmwasm_storage::{ + singleton, singleton_read, ReadonlySingleton, Singleton, +}; + +pub const COUNT_KEY: &[u8] = b"count"; + +pub fn count(storage: &mut dyn Storage) -> Singleton { + singleton(storage, COUNT_KEY) +} + +pub fn count_read(storage: &dyn Storage) -> ReadonlySingleton { + singleton_read(storage, COUNT_KEY) +} + + diff --git a/x/compute/internal/keeper/testdata/v1-sanity-contract/src/contract.rs b/x/compute/internal/keeper/testdata/v1-sanity-contract/src/contract.rs index 1210a4b53..4dfa3fcdf 100644 --- a/x/compute/internal/keeper/testdata/v1-sanity-contract/src/contract.rs +++ b/x/compute/internal/keeper/testdata/v1-sanity-contract/src/contract.rs @@ -296,23 +296,31 @@ pub fn instantiate( InstantiateMsg::CosmosMsgCustom {} => { Ok(Response::new().add_message(CosmosMsg::Custom(Empty {}))) } - InstantiateMsg::SendMultipleFundsToInitCallback { coins, code_id, code_hash } => Ok( + InstantiateMsg::SendMultipleFundsToInitCallback { + coins, + code_id, + code_hash, + } => Ok( Response::new().add_message(CosmosMsg::Wasm(WasmMsg::Instantiate { code_id, code_hash, msg: Binary("{\"nop\":{}}".as_bytes().to_vec()), funds: coins, - label: "init test".to_string() - })) + label: "init test".to_string(), + })), ), - InstantiateMsg::SendMultipleFundsToExecCallback { coins, to, code_hash } => Ok( + InstantiateMsg::SendMultipleFundsToExecCallback { + coins, + to, + code_hash, + } => Ok( Response::new().add_message(CosmosMsg::Wasm(WasmMsg::Execute { contract_addr: to, code_hash, msg: Binary("{\"no_data\":{}}".as_bytes().to_vec()), funds: coins, - })) - ) + })), + ), } } @@ -531,7 +539,15 @@ pub fn execute(deps: DepsMut, env: Env, info: MessageInfo, msg: ExecuteMsg) -> S ) .add_attribute("attr3", "🐙") .add_attribute_plaintext("attr4", "🦄")), - ExecuteMsg::GasMeter {} => loop {}, + ExecuteMsg::GasMeter {} => { + // busy work + let mut v = vec![0; 65536]; + let mut x = 0; + loop { + x += (x + 1) % 65536; + v[x] = 65536 - x; + } + } ExecuteMsg::GasMeterProxy {} => Ok(Response::default()), ExecuteMsg::TransferMoney { amount } => transfer_money(deps, amount), ExecuteMsg::RecursiveReply {} => recursive_reply(env, deps), @@ -1123,22 +1139,30 @@ pub fn execute(deps: DepsMut, env: Env, info: MessageInfo, msg: ExecuteMsg) -> S ExecuteMsg::CosmosMsgCustom {} => { Ok(Response::new().add_message(CosmosMsg::Custom(Empty {}))) } - ExecuteMsg::SendMultipleFundsToInitCallback { coins, code_id, code_hash } => Ok( + ExecuteMsg::SendMultipleFundsToInitCallback { + coins, + code_id, + code_hash, + } => Ok( Response::new().add_message(CosmosMsg::Wasm(WasmMsg::Instantiate { code_id, code_hash, msg: Binary("{\"nop\":{}}".as_bytes().to_vec()), funds: coins, - label: "test".to_string() - })) + label: "test".to_string(), + })), ), - ExecuteMsg::SendMultipleFundsToExecCallback { coins, to, code_hash } => Ok( + ExecuteMsg::SendMultipleFundsToExecCallback { + coins, + to, + code_hash, + } => Ok( Response::new().add_message(CosmosMsg::Wasm(WasmMsg::Execute { contract_addr: to, code_hash, msg: Binary("{\"no_data\":{}}".as_bytes().to_vec()), funds: coins, - })) + })), ), } } diff --git a/x/compute/internal/types/expected_keepers.go b/x/compute/internal/types/expected_keepers.go index 1bef78e26..04355c92a 100644 --- a/x/compute/internal/types/expected_keepers.go +++ b/x/compute/internal/types/expected_keepers.go @@ -1,8 +1,25 @@ package types -import sdk "github.com/cosmos/cosmos-sdk/types" +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" + channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + ibcexported "github.com/cosmos/ibc-go/v3/modules/core/exported" +) // ICS20TransferPortSource is a subset of the ibc transfer keeper. type ICS20TransferPortSource interface { GetPort(ctx sdk.Context) string } + +// ChannelKeeper defines the expected IBC channel keeper +type ChannelKeeper interface { + GetChannel(ctx sdk.Context, srcPort, srcChan string) (channel channeltypes.Channel, found bool) + GetNextSequenceSend(ctx sdk.Context, portID, channelID string) (uint64, bool) + SendPacket(ctx sdk.Context, channelCap *capabilitytypes.Capability, packet ibcexported.PacketI) error + ChanCloseInit(ctx sdk.Context, portID, channelID string, chanCap *capabilitytypes.Capability) error + GetAllChannels(ctx sdk.Context) (channels []channeltypes.IdentifiedChannel) + IterateChannels(ctx sdk.Context, cb func(channeltypes.IdentifiedChannel) bool) + SetChannel(ctx sdk.Context, portID, channelID string, channel channeltypes.Channel) +} diff --git a/x/compute/internal/types/exported_keepers.go b/x/compute/internal/types/exported_keepers.go new file mode 100644 index 000000000..477f668e7 --- /dev/null +++ b/x/compute/internal/types/exported_keepers.go @@ -0,0 +1,46 @@ +package types + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" + v1types "github.com/enigmampc/SecretNetwork/go-cosmwasm/types/v1" +) + +// IBCContractKeeper IBC lifecycle event handler +type IBCContractKeeper interface { + OnOpenChannel( + ctx sdk.Context, + contractAddr sdk.AccAddress, + msg v1types.IBCChannelOpenMsg, + ) (string, error) + OnConnectChannel( + ctx sdk.Context, + contractAddr sdk.AccAddress, + msg v1types.IBCChannelConnectMsg, + ) error + OnCloseChannel( + ctx sdk.Context, + contractAddr sdk.AccAddress, + msg v1types.IBCChannelCloseMsg, + ) error + OnRecvPacket( + ctx sdk.Context, + contractAddr sdk.AccAddress, + msg v1types.IBCPacketReceiveMsg, + ) ([]byte, error) + OnAckPacket( + ctx sdk.Context, + contractAddr sdk.AccAddress, + acknowledgement v1types.IBCPacketAckMsg, + ) error + OnTimeoutPacket( + ctx sdk.Context, + contractAddr sdk.AccAddress, + msg v1types.IBCPacketTimeoutMsg, + ) error + // ClaimCapability allows the transfer module to claim a capability + // that IBC module passes to it + ClaimCapability(ctx sdk.Context, cap *capabilitytypes.Capability, name string) error + // AuthenticateCapability wraps the scopedKeeper's AuthenticateCapability function + AuthenticateCapability(ctx sdk.Context, cap *capabilitytypes.Capability, name string) bool +} diff --git a/x/compute/internal/types/msg.go b/x/compute/internal/types/msg.go index 7eb0f4877..5d7b8fcc4 100644 --- a/x/compute/internal/types/msg.go +++ b/x/compute/internal/types/msg.go @@ -29,13 +29,7 @@ func (msg MsgStoreCode) ValidateBasic() error { if err := validateBuilder(msg.Builder); err != nil { return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "builder %s", err.Error()) } - /* - if msg.InstantiatePermission != nil { - if err := msg.InstantiatePermission.ValidateBasic(); err != nil { - return sdkerrors.Wrap(err, "instantiate permission") - } - } - */ + return nil } @@ -72,16 +66,6 @@ func (msg MsgInstantiateContract) ValidateBasic() error { return sdkerrors.ErrInvalidCoins } - /* - if len(msg.Admin) != 0 { - if err := sdk.VerifyAddressFormat(msg.Admin); err != nil { - return err - } - } - if !json.Valid(msg.InitMsg) { - return sdkerrors.Wrap(ErrInvalid, "init msg json") - } - */ return nil } @@ -112,11 +96,7 @@ func (msg MsgExecuteContract) ValidateBasic() error { if !msg.SentFunds.IsValid() { return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, "sentFunds") } - /* - if !json.Valid(msg.Msg) { - return sdkerrors.Wrap(ErrInvalid, "msg json") - } - */ + return nil } @@ -127,114 +107,3 @@ func (msg MsgExecuteContract) GetSignBytes() []byte { func (msg MsgExecuteContract) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{msg.Sender} } - -/* -type MsgMigrateContract struct { - Sender sdk.AccAddress `json:"sender" yaml:"sender"` - Contract sdk.AccAddress `json:"contract" yaml:"contract"` - CodeID uint64 `json:"code_id" yaml:"code_id"` - MigrateMsg json.RawMessage `json:"msg" yaml:"msg"` -} - -func (msg MsgMigrateContract) Route() string { - return RouterKey -} - -func (msg MsgMigrateContract) Type() string { - return "migrate" -} - -func (msg MsgMigrateContract) ValidateBasic() error { - if msg.CodeID == 0 { - return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "code_id is required") - } - if err := sdk.VerifyAddressFormat(msg.Sender); err != nil { - return sdkerrors.Wrap(err, "sender") - } - if err := sdk.VerifyAddressFormat(msg.Contract); err != nil { - return sdkerrors.Wrap(err, "contract") - } - if !json.Valid(msg.MigrateMsg) { - return sdkerrors.Wrap(ErrInvalid, "migrate msg json") - } - - return nil -} - -func (msg MsgMigrateContract) GetSignBytes() []byte { - return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(msg)) -} - -func (msg MsgMigrateContract) GetSigners() []sdk.AccAddress { - return []sdk.AccAddress{msg.Sender} -} - -type MsgUpdateAdmin struct { - Sender sdk.AccAddress `json:"sender" yaml:"sender"` - NewAdmin sdk.AccAddress `json:"new_admin" yaml:"new_admin"` - Contract sdk.AccAddress `json:"contract" yaml:"contract"` -} - -func (msg MsgUpdateAdmin) Route() string { - return RouterKey -} - -func (msg MsgUpdateAdmin) Type() string { - return "update-contract-admin" -} - -func (msg MsgUpdateAdmin) ValidateBasic() error { - if err := sdk.VerifyAddressFormat(msg.Sender); err != nil { - return sdkerrors.Wrap(err, "sender") - } - if err := sdk.VerifyAddressFormat(msg.Contract); err != nil { - return sdkerrors.Wrap(err, "contract") - } - if err := sdk.VerifyAddressFormat(msg.NewAdmin); err != nil { - return sdkerrors.Wrap(err, "new admin") - } - if msg.Sender.Equals(msg.NewAdmin) { - return sdkerrors.Wrap(ErrInvalidMsg, "new admin is the same as the old") - } - return nil -} - -func (msg MsgUpdateAdmin) GetSignBytes() []byte { - return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(msg)) -} - -func (msg MsgUpdateAdmin) GetSigners() []sdk.AccAddress { - return []sdk.AccAddress{msg.Sender} -} - -type MsgClearAdmin struct { - Sender sdk.AccAddress `json:"sender" yaml:"sender"` - Contract sdk.AccAddress `json:"contract" yaml:"contract"` -} - -func (msg MsgClearAdmin) Route() string { - return RouterKey -} - -func (msg MsgClearAdmin) Type() string { - return "clear-contract-admin" -} - -func (msg MsgClearAdmin) ValidateBasic() error { - if err := sdk.VerifyAddressFormat(msg.Sender); err != nil { - return sdkerrors.Wrap(err, "sender") - } - if err := sdk.VerifyAddressFormat(msg.Contract); err != nil { - return sdkerrors.Wrap(err, "contract") - } - return nil -} - -func (msg MsgClearAdmin) GetSignBytes() []byte { - return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(msg)) -} - -func (msg MsgClearAdmin) GetSigners() []sdk.AccAddress { - return []sdk.AccAddress{msg.Sender} -} -*/ diff --git a/x/compute/internal/types/msg.pb.go b/x/compute/internal/types/msg.pb.go index 7b2dda060..148c9c588 100644 --- a/x/compute/internal/types/msg.pb.go +++ b/x/compute/internal/types/msg.pb.go @@ -4,11 +4,16 @@ package types import ( + context "context" fmt "fmt" github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" types "github.com/cosmos/cosmos-sdk/types" _ "github.com/gogo/protobuf/gogoproto" + grpc1 "github.com/gogo/protobuf/grpc" proto "github.com/gogo/protobuf/proto" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" io "io" math "math" math_bits "math/bits" @@ -39,7 +44,7 @@ func (m *MsgStoreCode) Reset() { *m = MsgStoreCode{} } func (m *MsgStoreCode) String() string { return proto.CompactTextString(m) } func (*MsgStoreCode) ProtoMessage() {} func (*MsgStoreCode) Descriptor() ([]byte, []int) { - return fileDescriptor_6815433faf72a133, []int{0} + return fileDescriptor_ba393690c2c2062e, []int{0} } func (m *MsgStoreCode) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -68,6 +73,52 @@ func (m *MsgStoreCode) XXX_DiscardUnknown() { var xxx_messageInfo_MsgStoreCode proto.InternalMessageInfo +// MsgStoreCodeResponse returns store result data. +type MsgStoreCodeResponse struct { + // CodeID is the reference to the stored WASM code + CodeID uint64 `protobuf:"varint,1,opt,name=code_id,json=codeId,proto3" json:"code_id,omitempty"` +} + +func (m *MsgStoreCodeResponse) Reset() { *m = MsgStoreCodeResponse{} } +func (m *MsgStoreCodeResponse) String() string { return proto.CompactTextString(m) } +func (*MsgStoreCodeResponse) ProtoMessage() {} +func (*MsgStoreCodeResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_ba393690c2c2062e, []int{1} +} +func (m *MsgStoreCodeResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgStoreCodeResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgStoreCodeResponse.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 *MsgStoreCodeResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgStoreCodeResponse.Merge(m, src) +} +func (m *MsgStoreCodeResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgStoreCodeResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgStoreCodeResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgStoreCodeResponse proto.InternalMessageInfo + +func (m *MsgStoreCodeResponse) GetCodeID() uint64 { + if m != nil { + return m.CodeID + } + return 0 +} + type MsgInstantiateContract struct { Sender github_com_cosmos_cosmos_sdk_types.AccAddress `protobuf:"bytes,1,opt,name=sender,proto3,casttype=github.com/cosmos/cosmos-sdk/types.AccAddress" json:"sender,omitempty"` // Admin is an optional address that can execute migrations @@ -84,7 +135,7 @@ func (m *MsgInstantiateContract) Reset() { *m = MsgInstantiateContract{} func (m *MsgInstantiateContract) String() string { return proto.CompactTextString(m) } func (*MsgInstantiateContract) ProtoMessage() {} func (*MsgInstantiateContract) Descriptor() ([]byte, []int) { - return fileDescriptor_6815433faf72a133, []int{1} + return fileDescriptor_ba393690c2c2062e, []int{2} } func (m *MsgInstantiateContract) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -113,6 +164,61 @@ func (m *MsgInstantiateContract) XXX_DiscardUnknown() { var xxx_messageInfo_MsgInstantiateContract 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 []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"` +} + +func (m *MsgInstantiateContractResponse) Reset() { *m = MsgInstantiateContractResponse{} } +func (m *MsgInstantiateContractResponse) String() string { return proto.CompactTextString(m) } +func (*MsgInstantiateContractResponse) ProtoMessage() {} +func (*MsgInstantiateContractResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_ba393690c2c2062e, []int{3} +} +func (m *MsgInstantiateContractResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgInstantiateContractResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgInstantiateContractResponse.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 *MsgInstantiateContractResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgInstantiateContractResponse.Merge(m, src) +} +func (m *MsgInstantiateContractResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgInstantiateContractResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgInstantiateContractResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgInstantiateContractResponse proto.InternalMessageInfo + +func (m *MsgInstantiateContractResponse) GetAddress() string { + if m != nil { + return m.Address + } + return "" +} + +func (m *MsgInstantiateContractResponse) GetData() []byte { + if m != nil { + return m.Data + } + return nil +} + type MsgExecuteContract struct { Sender github_com_cosmos_cosmos_sdk_types.AccAddress `protobuf:"bytes,1,opt,name=sender,proto3,casttype=github.com/cosmos/cosmos-sdk/types.AccAddress" json:"sender,omitempty"` Contract github_com_cosmos_cosmos_sdk_types.AccAddress `protobuf:"bytes,2,opt,name=contract,proto3,casttype=github.com/cosmos/cosmos-sdk/types.AccAddress" json:"contract,omitempty"` @@ -126,7 +232,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_6815433faf72a133, []int{2} + return fileDescriptor_ba393690c2c2062e, []int{4} } func (m *MsgExecuteContract) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -155,52 +261,267 @@ func (m *MsgExecuteContract) XXX_DiscardUnknown() { 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 []byte `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"` +} + +func (m *MsgExecuteContractResponse) Reset() { *m = MsgExecuteContractResponse{} } +func (m *MsgExecuteContractResponse) String() string { return proto.CompactTextString(m) } +func (*MsgExecuteContractResponse) ProtoMessage() {} +func (*MsgExecuteContractResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_ba393690c2c2062e, []int{5} +} +func (m *MsgExecuteContractResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgExecuteContractResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgExecuteContractResponse.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 *MsgExecuteContractResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgExecuteContractResponse.Merge(m, src) +} +func (m *MsgExecuteContractResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgExecuteContractResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgExecuteContractResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgExecuteContractResponse proto.InternalMessageInfo + +func (m *MsgExecuteContractResponse) GetData() []byte { + if m != nil { + return m.Data + } + return nil +} + func init() { proto.RegisterType((*MsgStoreCode)(nil), "secret.compute.v1beta1.MsgStoreCode") + proto.RegisterType((*MsgStoreCodeResponse)(nil), "secret.compute.v1beta1.MsgStoreCodeResponse") proto.RegisterType((*MsgInstantiateContract)(nil), "secret.compute.v1beta1.MsgInstantiateContract") + proto.RegisterType((*MsgInstantiateContractResponse)(nil), "secret.compute.v1beta1.MsgInstantiateContractResponse") proto.RegisterType((*MsgExecuteContract)(nil), "secret.compute.v1beta1.MsgExecuteContract") + proto.RegisterType((*MsgExecuteContractResponse)(nil), "secret.compute.v1beta1.MsgExecuteContractResponse") +} + +func init() { proto.RegisterFile("secret/compute/v1beta1/tx.proto", fileDescriptor_ba393690c2c2062e) } + +var fileDescriptor_ba393690c2c2062e = []byte{ + // 696 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x55, 0x3f, 0x4f, 0xdb, 0x4e, + 0x18, 0x8e, 0x71, 0x48, 0xc8, 0x4b, 0xf4, 0x03, 0xdd, 0x0f, 0x21, 0x93, 0xc1, 0x46, 0x69, 0x87, + 0xa8, 0x02, 0x1b, 0x52, 0x89, 0xa1, 0x4c, 0x84, 0xb6, 0x6a, 0x86, 0x30, 0x38, 0xaa, 0x2a, 0x75, + 0x89, 0xce, 0xe7, 0xab, 0x63, 0x48, 0x7c, 0xa9, 0xef, 0x52, 0x60, 0xe8, 0xde, 0xa5, 0x52, 0x87, + 0x7e, 0x80, 0xce, 0xfd, 0x24, 0x74, 0x63, 0x64, 0x4a, 0xab, 0xf0, 0x2d, 0x3a, 0x55, 0xe7, 0x7f, + 0x89, 0x68, 0x40, 0x69, 0x55, 0xa6, 0xdc, 0x9b, 0xf7, 0xf1, 0xf3, 0xfe, 0x79, 0x1e, 0xdd, 0x81, + 0xc1, 0x29, 0x09, 0xa9, 0xb0, 0x08, 0xeb, 0x0f, 0x86, 0x82, 0x5a, 0xef, 0x76, 0x1d, 0x2a, 0xf0, + 0xae, 0x25, 0xce, 0xcc, 0x41, 0xc8, 0x04, 0x43, 0xeb, 0x31, 0xc0, 0x4c, 0x00, 0x66, 0x02, 0xa8, + 0xac, 0x79, 0xcc, 0x63, 0x11, 0xc4, 0x92, 0xa7, 0x18, 0x5d, 0xd1, 0x09, 0xe3, 0x7d, 0xc6, 0x2d, + 0x07, 0xf3, 0x09, 0x17, 0x61, 0x7e, 0x10, 0xe7, 0xab, 0xdf, 0x14, 0x28, 0xb7, 0xb8, 0xd7, 0x16, + 0x2c, 0xa4, 0x87, 0xcc, 0xa5, 0xa8, 0x09, 0x05, 0x4e, 0x03, 0x97, 0x86, 0x9a, 0xb2, 0xa9, 0xd4, + 0xca, 0x8d, 0xdd, 0x9f, 0x23, 0x63, 0xdb, 0xf3, 0x45, 0x77, 0xe8, 0xc8, 0x92, 0x56, 0xc2, 0x17, + 0xff, 0x6c, 0x73, 0xf7, 0xc4, 0x12, 0xe7, 0x03, 0xca, 0xcd, 0x03, 0x42, 0x0e, 0x5c, 0x37, 0xa4, + 0x9c, 0xdb, 0x09, 0x01, 0xda, 0x83, 0xff, 0x4e, 0x31, 0xef, 0x77, 0x9c, 0x73, 0x41, 0x3b, 0x84, + 0xb9, 0x54, 0x5b, 0x88, 0x28, 0x57, 0xc7, 0x23, 0xa3, 0xfc, 0xea, 0xa0, 0xdd, 0x6a, 0x9c, 0x8b, + 0xa8, 0xa8, 0x5d, 0x96, 0xb8, 0x34, 0x42, 0xeb, 0x50, 0xe0, 0x6c, 0x18, 0x12, 0xaa, 0xa9, 0x9b, + 0x4a, 0xad, 0x64, 0x27, 0x11, 0xd2, 0xa0, 0xe8, 0x0c, 0xfd, 0x9e, 0xec, 0x2d, 0x1f, 0x25, 0xd2, + 0xf0, 0x49, 0xfe, 0xc3, 0x17, 0x23, 0x57, 0xdd, 0x87, 0xb5, 0xe9, 0x51, 0x6c, 0xca, 0x07, 0x2c, + 0xe0, 0x14, 0x3d, 0x80, 0xa2, 0xac, 0xde, 0xf1, 0xdd, 0x68, 0xa6, 0x7c, 0x03, 0xc6, 0x23, 0xa3, + 0x20, 0x21, 0xcd, 0xa7, 0x76, 0x41, 0xa6, 0x9a, 0x6e, 0xf5, 0xa3, 0x0a, 0xeb, 0x2d, 0xee, 0x35, + 0x03, 0x2e, 0x70, 0x20, 0x7c, 0x2c, 0x7b, 0x09, 0x44, 0x88, 0x89, 0xf8, 0x97, 0x2b, 0xd9, 0x02, + 0x44, 0x70, 0xaf, 0xe7, 0x60, 0x72, 0x12, 0x6d, 0xa4, 0xd3, 0xc5, 0xbc, 0x1b, 0xad, 0xa5, 0x64, + 0xaf, 0xa6, 0x19, 0xd9, 0xd9, 0x0b, 0xcc, 0xbb, 0xd3, 0x8d, 0xab, 0xb7, 0x35, 0x8e, 0xd6, 0x60, + 0xb1, 0x87, 0x1d, 0xda, 0x4b, 0x76, 0x12, 0x07, 0x68, 0x03, 0x96, 0xfc, 0xc0, 0x17, 0x9d, 0x3e, + 0xf7, 0xb4, 0x45, 0xd9, 0xb5, 0x5d, 0x94, 0x71, 0x8b, 0x7b, 0xe8, 0x18, 0x20, 0x4a, 0xbd, 0x19, + 0x06, 0x2e, 0xd7, 0x0a, 0x9b, 0x6a, 0x6d, 0xb9, 0xbe, 0x61, 0xc6, 0xdd, 0x9b, 0xd2, 0x27, 0xa9, + 0xa5, 0xcc, 0x43, 0xe6, 0x07, 0x8d, 0x9d, 0x8b, 0x91, 0x91, 0xfb, 0xfa, 0xdd, 0xa8, 0xcd, 0x31, + 0xb1, 0xfc, 0x80, 0xdb, 0x25, 0x49, 0xff, 0x5c, 0xb2, 0xa3, 0x3a, 0x94, 0xb3, 0x79, 0xb9, 0xef, + 0x69, 0xc5, 0x68, 0x81, 0x2b, 0xe3, 0x91, 0xb1, 0x7c, 0x98, 0xfc, 0xdf, 0xf6, 0x3d, 0x7b, 0x99, + 0x4c, 0x82, 0x44, 0xcc, 0x23, 0xd0, 0x67, 0xcb, 0x91, 0xc9, 0xaa, 0x41, 0x11, 0xc7, 0xeb, 0x8d, + 0x74, 0x29, 0xd9, 0x69, 0x88, 0x10, 0xe4, 0x5d, 0x2c, 0x70, 0x6c, 0x37, 0x3b, 0x3a, 0x57, 0x3f, + 0xab, 0x80, 0x5a, 0xdc, 0x7b, 0x76, 0x46, 0xc9, 0xf0, 0x7e, 0xb4, 0x6d, 0xc1, 0x12, 0x49, 0x68, + 0x13, 0xa3, 0xff, 0x05, 0x59, 0x46, 0x81, 0x56, 0x41, 0x95, 0xe2, 0xa9, 0xd1, 0x0c, 0xf2, 0x78, + 0x8b, 0x79, 0xf2, 0xb7, 0x98, 0xe7, 0x18, 0x80, 0xd3, 0x20, 0x95, 0x79, 0xf1, 0x1e, 0x64, 0x96, + 0xf4, 0xb3, 0x65, 0x2e, 0xcc, 0x2d, 0xf3, 0x0e, 0x54, 0x7e, 0x57, 0x25, 0x93, 0x38, 0x15, 0x52, + 0x99, 0x08, 0x59, 0xbf, 0x5a, 0x00, 0x55, 0xda, 0xb8, 0x03, 0xa5, 0xc9, 0xad, 0xf5, 0xd0, 0x9c, + 0x7d, 0x2b, 0x9a, 0xd3, 0x17, 0x42, 0x65, 0x6b, 0x1e, 0x54, 0x56, 0xfc, 0x3d, 0xfc, 0x3f, 0xeb, + 0x36, 0x30, 0xef, 0x20, 0x99, 0x81, 0xaf, 0xec, 0xfd, 0x19, 0x3e, 0x2b, 0xff, 0x16, 0x56, 0x6e, + 0x9a, 0xf5, 0xd1, 0x1d, 0x54, 0x37, 0xb0, 0x95, 0xfa, 0xfc, 0xd8, 0xb4, 0x64, 0xe3, 0xe5, 0xc5, + 0x58, 0x57, 0x2e, 0xc7, 0xba, 0xf2, 0x63, 0xac, 0x2b, 0x9f, 0xae, 0xf5, 0xdc, 0xe5, 0xb5, 0x9e, + 0xbb, 0xba, 0xd6, 0x73, 0xaf, 0xf7, 0xa7, 0x5c, 0x41, 0x03, 0xdf, 0xeb, 0xe3, 0xfe, 0x80, 0x58, + 0xed, 0xa8, 0xc2, 0x11, 0x15, 0xa7, 0x2c, 0x3c, 0xb1, 0xce, 0xb2, 0x37, 0xcb, 0x0f, 0x04, 0x0d, + 0x03, 0xdc, 0x8b, 0xed, 0xe2, 0x14, 0xa2, 0xa7, 0xe6, 0xf1, 0xaf, 0x00, 0x00, 0x00, 0xff, 0xff, + 0x2d, 0x4f, 0xbc, 0x89, 0xdb, 0x06, 0x00, 0x00, +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// MsgClient is the client API for Msg service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +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(ctx context.Context, in *MsgInstantiateContract, opts ...grpc.CallOption) (*MsgInstantiateContractResponse, error) + // Execute submits the given message data to a smart contract + ExecuteContract(ctx context.Context, in *MsgExecuteContract, opts ...grpc.CallOption) (*MsgExecuteContractResponse, error) +} + +type msgClient struct { + cc grpc1.ClientConn +} + +func NewMsgClient(cc grpc1.ClientConn) MsgClient { + return &msgClient{cc} +} + +func (c *msgClient) StoreCode(ctx context.Context, in *MsgStoreCode, opts ...grpc.CallOption) (*MsgStoreCodeResponse, error) { + out := new(MsgStoreCodeResponse) + err := c.cc.Invoke(ctx, "/secret.compute.v1beta1.Msg/StoreCode", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) InstantiateContract(ctx context.Context, in *MsgInstantiateContract, opts ...grpc.CallOption) (*MsgInstantiateContractResponse, error) { + out := new(MsgInstantiateContractResponse) + err := c.cc.Invoke(ctx, "/secret.compute.v1beta1.Msg/InstantiateContract", 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, "/secret.compute.v1beta1.Msg/ExecuteContract", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// MsgServer is the server API for Msg service. +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(context.Context, *MsgInstantiateContract) (*MsgInstantiateContractResponse, error) + // Execute submits the given message data to a smart contract + ExecuteContract(context.Context, *MsgExecuteContract) (*MsgExecuteContractResponse, error) +} + +// UnimplementedMsgServer can be embedded to have forward compatible implementations. +type UnimplementedMsgServer struct { +} + +func (*UnimplementedMsgServer) StoreCode(ctx context.Context, req *MsgStoreCode) (*MsgStoreCodeResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method StoreCode not implemented") +} +func (*UnimplementedMsgServer) InstantiateContract(ctx context.Context, req *MsgInstantiateContract) (*MsgInstantiateContractResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method InstantiateContract not implemented") +} +func (*UnimplementedMsgServer) ExecuteContract(ctx context.Context, req *MsgExecuteContract) (*MsgExecuteContractResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ExecuteContract not implemented") +} + +func RegisterMsgServer(s grpc1.Server, srv MsgServer) { + s.RegisterService(&_Msg_serviceDesc, srv) +} + +func _Msg_StoreCode_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgStoreCode) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).StoreCode(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/secret.compute.v1beta1.Msg/StoreCode", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).StoreCode(ctx, req.(*MsgStoreCode)) + } + return interceptor(ctx, in, info, handler) +} + +func _Msg_InstantiateContract_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgInstantiateContract) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).InstantiateContract(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/secret.compute.v1beta1.Msg/InstantiateContract", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).InstantiateContract(ctx, req.(*MsgInstantiateContract)) + } + 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 { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).ExecuteContract(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/secret.compute.v1beta1.Msg/ExecuteContract", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).ExecuteContract(ctx, req.(*MsgExecuteContract)) + } + return interceptor(ctx, in, info, handler) } -func init() { proto.RegisterFile("secret/compute/v1beta1/msg.proto", fileDescriptor_6815433faf72a133) } - -var fileDescriptor_6815433faf72a133 = []byte{ - // 572 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x54, 0x31, 0x6f, 0xd3, 0x40, - 0x18, 0x8d, 0x49, 0xea, 0xb4, 0xd7, 0x08, 0xaa, 0x53, 0x55, 0xb9, 0x1d, 0xec, 0xa8, 0x2c, 0x19, - 0xa8, 0x4d, 0x8b, 0xc4, 0x00, 0x53, 0x53, 0x40, 0x64, 0x08, 0x83, 0x23, 0x84, 0xc4, 0x12, 0x9d, - 0xcf, 0xc7, 0xe5, 0xda, 0xf8, 0x2e, 0xf2, 0x77, 0xa6, 0xed, 0x3f, 0x60, 0x41, 0x62, 0xe0, 0x07, - 0x30, 0xf3, 0x4b, 0xca, 0xd6, 0x91, 0x29, 0x20, 0xf7, 0x5f, 0x30, 0xa1, 0x3b, 0x3b, 0x2d, 0x03, - 0x95, 0x2a, 0x44, 0xa7, 0xdc, 0xcb, 0x7b, 0x7e, 0xf7, 0xbd, 0x7b, 0xa7, 0x43, 0x5d, 0x60, 0x34, - 0x67, 0x3a, 0xa2, 0x2a, 0x9b, 0x15, 0x9a, 0x45, 0xef, 0x77, 0x13, 0xa6, 0xc9, 0x6e, 0x94, 0x01, - 0x0f, 0x67, 0xb9, 0xd2, 0x0a, 0x6f, 0x54, 0x8a, 0xb0, 0x56, 0x84, 0xb5, 0x62, 0x6b, 0x9d, 0x2b, - 0xae, 0xac, 0x24, 0x32, 0xab, 0x4a, 0xbd, 0xe5, 0x53, 0x05, 0x99, 0x82, 0x28, 0x21, 0x70, 0x65, - 0x46, 0x95, 0x90, 0x15, 0xbf, 0xfd, 0xcd, 0x41, 0x9d, 0x21, 0xf0, 0x91, 0x56, 0x39, 0x3b, 0x50, - 0x29, 0xc3, 0x03, 0xe4, 0x02, 0x93, 0x29, 0xcb, 0x3d, 0xa7, 0xeb, 0xf4, 0x3a, 0xfd, 0xdd, 0x5f, - 0xf3, 0x60, 0x87, 0x0b, 0x3d, 0x29, 0x12, 0xb3, 0x65, 0x54, 0xfb, 0x55, 0x3f, 0x3b, 0x90, 0x1e, - 0x45, 0xfa, 0x74, 0xc6, 0x20, 0xdc, 0xa7, 0x74, 0x3f, 0x4d, 0x73, 0x06, 0x10, 0xd7, 0x06, 0xf8, - 0x31, 0xba, 0x7b, 0x4c, 0x20, 0x1b, 0x27, 0xa7, 0x9a, 0x8d, 0xa9, 0x4a, 0x99, 0x77, 0xc7, 0x5a, - 0xae, 0x95, 0xf3, 0xa0, 0xf3, 0x66, 0x7f, 0x34, 0xec, 0x9f, 0x6a, 0xbb, 0x69, 0xdc, 0x31, 0xba, - 0x05, 0xc2, 0x1b, 0xc8, 0x05, 0x55, 0xe4, 0x94, 0x79, 0xcd, 0xae, 0xd3, 0x5b, 0x89, 0x6b, 0x84, - 0x3d, 0xd4, 0x4e, 0x0a, 0x31, 0x35, 0xb3, 0xb5, 0x2c, 0xb1, 0x80, 0x4f, 0x5a, 0x1f, 0xbe, 0x04, - 0x8d, 0xed, 0x8f, 0x4d, 0xb4, 0x31, 0x04, 0x3e, 0x90, 0xa0, 0x89, 0xd4, 0x82, 0x18, 0x3b, 0xa9, - 0x73, 0x42, 0xf5, 0xff, 0x4c, 0xf5, 0x00, 0x61, 0x4a, 0xa6, 0xd3, 0x84, 0xd0, 0x23, 0x1b, 0x6a, - 0x3c, 0x21, 0x30, 0xb1, 0xc9, 0x56, 0xe2, 0xb5, 0x05, 0x63, 0x72, 0xbc, 0x24, 0x30, 0xc1, 0xf7, - 0x51, 0xdb, 0x8a, 0x44, 0x6a, 0xc3, 0xb4, 0xfa, 0xa8, 0x9c, 0x07, 0xae, 0xa1, 0x07, 0xcf, 0x62, - 0xd7, 0x50, 0x83, 0x14, 0xaf, 0xa3, 0xa5, 0x29, 0x49, 0xd8, 0xb4, 0x8e, 0x55, 0x01, 0xbc, 0x89, - 0x96, 0x85, 0x14, 0x7a, 0x9c, 0x01, 0xf7, 0x96, 0xcc, 0xd4, 0x71, 0xdb, 0xe0, 0x21, 0x70, 0x7c, - 0x88, 0x90, 0xa5, 0xde, 0x15, 0x32, 0x05, 0xcf, 0xed, 0x36, 0x7b, 0xab, 0x7b, 0x9b, 0x61, 0x35, - 0x7d, 0x68, 0xaa, 0x5e, 0xdc, 0x8a, 0xf0, 0x40, 0x09, 0xd9, 0x7f, 0x78, 0x36, 0x0f, 0x1a, 0x5f, - 0x7f, 0x04, 0xbd, 0x1b, 0x24, 0x36, 0x1f, 0x40, 0xbc, 0x62, 0xec, 0x5f, 0x18, 0x77, 0xbc, 0x87, - 0x3a, 0x97, 0x79, 0x41, 0x70, 0xaf, 0x6d, 0x0f, 0xf0, 0x5e, 0x39, 0x0f, 0x56, 0x0f, 0xea, 0xff, - 0x47, 0x82, 0xc7, 0xab, 0xf4, 0x0a, 0xd4, 0x7d, 0x7c, 0x6e, 0x22, 0x3c, 0x04, 0xfe, 0xfc, 0x84, - 0xd1, 0xe2, 0x76, 0xba, 0x18, 0xa2, 0x65, 0x5a, 0xdb, 0xd6, 0x77, 0xeb, 0x1f, 0xcc, 0x2e, 0x2d, - 0xf0, 0x1a, 0x6a, 0x9a, 0xc3, 0x6e, 0xda, 0xc3, 0x36, 0xcb, 0x6b, 0xca, 0x6e, 0x5d, 0x53, 0xf6, - 0x21, 0x42, 0xc0, 0xe4, 0xa2, 0x96, 0xa5, 0x5b, 0xa8, 0xc5, 0xd8, 0xff, 0xbd, 0x16, 0xf7, 0xa6, - 0xb5, 0xf4, 0x5f, 0x9f, 0x95, 0xbe, 0x73, 0x5e, 0xfa, 0xce, 0xcf, 0xd2, 0x77, 0x3e, 0x5d, 0xf8, - 0x8d, 0xf3, 0x0b, 0xbf, 0xf1, 0xfd, 0xc2, 0x6f, 0xbc, 0x7d, 0xfa, 0xc7, 0x20, 0x4c, 0x0a, 0x9e, - 0x91, 0x6c, 0x46, 0xa3, 0x91, 0x7d, 0x6f, 0x5e, 0x31, 0x7d, 0xac, 0xf2, 0xa3, 0xe8, 0xe4, 0xf2, - 0x69, 0x12, 0x52, 0xb3, 0x5c, 0x92, 0x69, 0x35, 0x61, 0xe2, 0xda, 0x07, 0xe5, 0xd1, 0xef, 0x00, - 0x00, 0x00, 0xff, 0xff, 0xea, 0x28, 0x0f, 0x71, 0xc2, 0x04, 0x00, 0x00, +var _Msg_serviceDesc = grpc.ServiceDesc{ + ServiceName: "secret.compute.v1beta1.Msg", + HandlerType: (*MsgServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "StoreCode", + Handler: _Msg_StoreCode_Handler, + }, + { + MethodName: "InstantiateContract", + Handler: _Msg_InstantiateContract_Handler, + }, + { + MethodName: "ExecuteContract", + Handler: _Msg_ExecuteContract_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "secret/compute/v1beta1/tx.proto", } func (m *MsgStoreCode) Marshal() (dAtA []byte, err error) { @@ -226,34 +547,62 @@ func (m *MsgStoreCode) MarshalToSizedBuffer(dAtA []byte) (int, error) { if len(m.Builder) > 0 { i -= len(m.Builder) copy(dAtA[i:], m.Builder) - i = encodeVarintMsg(dAtA, i, uint64(len(m.Builder))) + i = encodeVarintTx(dAtA, i, uint64(len(m.Builder))) i-- dAtA[i] = 0x22 } if len(m.Source) > 0 { i -= len(m.Source) copy(dAtA[i:], m.Source) - i = encodeVarintMsg(dAtA, i, uint64(len(m.Source))) + i = encodeVarintTx(dAtA, i, uint64(len(m.Source))) i-- dAtA[i] = 0x1a } if len(m.WASMByteCode) > 0 { i -= len(m.WASMByteCode) copy(dAtA[i:], m.WASMByteCode) - i = encodeVarintMsg(dAtA, i, uint64(len(m.WASMByteCode))) + i = encodeVarintTx(dAtA, i, uint64(len(m.WASMByteCode))) i-- dAtA[i] = 0x12 } if len(m.Sender) > 0 { i -= len(m.Sender) copy(dAtA[i:], m.Sender) - i = encodeVarintMsg(dAtA, i, uint64(len(m.Sender))) + i = encodeVarintTx(dAtA, i, uint64(len(m.Sender))) i-- dAtA[i] = 0xa } return len(dAtA) - i, nil } +func (m *MsgStoreCodeResponse) 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 *MsgStoreCodeResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgStoreCodeResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.CodeID != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.CodeID)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + func (m *MsgInstantiateContract) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -277,7 +626,7 @@ func (m *MsgInstantiateContract) MarshalToSizedBuffer(dAtA []byte) (int, error) if len(m.CallbackSig) > 0 { i -= len(m.CallbackSig) copy(dAtA[i:], m.CallbackSig) - i = encodeVarintMsg(dAtA, i, uint64(len(m.CallbackSig))) + i = encodeVarintTx(dAtA, i, uint64(len(m.CallbackSig))) i-- dAtA[i] = 0x3a } @@ -289,7 +638,7 @@ func (m *MsgInstantiateContract) MarshalToSizedBuffer(dAtA []byte) (int, error) return 0, err } i -= size - i = encodeVarintMsg(dAtA, i, uint64(size)) + i = encodeVarintTx(dAtA, i, uint64(size)) } i-- dAtA[i] = 0x32 @@ -298,33 +647,70 @@ func (m *MsgInstantiateContract) MarshalToSizedBuffer(dAtA []byte) (int, error) if len(m.InitMsg) > 0 { i -= len(m.InitMsg) copy(dAtA[i:], m.InitMsg) - i = encodeVarintMsg(dAtA, i, uint64(len(m.InitMsg))) + i = encodeVarintTx(dAtA, i, uint64(len(m.InitMsg))) i-- dAtA[i] = 0x2a } if len(m.Label) > 0 { i -= len(m.Label) copy(dAtA[i:], m.Label) - i = encodeVarintMsg(dAtA, i, uint64(len(m.Label))) + i = encodeVarintTx(dAtA, i, uint64(len(m.Label))) i-- dAtA[i] = 0x22 } if m.CodeID != 0 { - i = encodeVarintMsg(dAtA, i, uint64(m.CodeID)) + i = encodeVarintTx(dAtA, i, uint64(m.CodeID)) i-- dAtA[i] = 0x18 } if len(m.CallbackCodeHash) > 0 { i -= len(m.CallbackCodeHash) copy(dAtA[i:], m.CallbackCodeHash) - i = encodeVarintMsg(dAtA, i, uint64(len(m.CallbackCodeHash))) + i = encodeVarintTx(dAtA, i, uint64(len(m.CallbackCodeHash))) i-- dAtA[i] = 0x12 } if len(m.Sender) > 0 { i -= len(m.Sender) copy(dAtA[i:], m.Sender) - i = encodeVarintMsg(dAtA, i, uint64(len(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) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgInstantiateContractResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgInstantiateContractResponse) 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 } @@ -354,7 +740,7 @@ func (m *MsgExecuteContract) MarshalToSizedBuffer(dAtA []byte) (int, error) { if len(m.CallbackSig) > 0 { i -= len(m.CallbackSig) copy(dAtA[i:], m.CallbackSig) - i = encodeVarintMsg(dAtA, i, uint64(len(m.CallbackSig))) + i = encodeVarintTx(dAtA, i, uint64(len(m.CallbackSig))) i-- dAtA[i] = 0x32 } @@ -366,7 +752,7 @@ func (m *MsgExecuteContract) MarshalToSizedBuffer(dAtA []byte) (int, error) { return 0, err } i -= size - i = encodeVarintMsg(dAtA, i, uint64(size)) + i = encodeVarintTx(dAtA, i, uint64(size)) } i-- dAtA[i] = 0x2a @@ -375,36 +761,66 @@ func (m *MsgExecuteContract) MarshalToSizedBuffer(dAtA []byte) (int, error) { if len(m.CallbackCodeHash) > 0 { i -= len(m.CallbackCodeHash) copy(dAtA[i:], m.CallbackCodeHash) - i = encodeVarintMsg(dAtA, i, uint64(len(m.CallbackCodeHash))) + i = encodeVarintTx(dAtA, i, uint64(len(m.CallbackCodeHash))) i-- dAtA[i] = 0x22 } if len(m.Msg) > 0 { i -= len(m.Msg) copy(dAtA[i:], m.Msg) - i = encodeVarintMsg(dAtA, i, uint64(len(m.Msg))) + i = encodeVarintTx(dAtA, i, uint64(len(m.Msg))) i-- dAtA[i] = 0x1a } if len(m.Contract) > 0 { i -= len(m.Contract) copy(dAtA[i:], m.Contract) - i = encodeVarintMsg(dAtA, i, uint64(len(m.Contract))) + i = encodeVarintTx(dAtA, i, uint64(len(m.Contract))) i-- dAtA[i] = 0x12 } if len(m.Sender) > 0 { i -= len(m.Sender) copy(dAtA[i:], m.Sender) - i = encodeVarintMsg(dAtA, i, uint64(len(m.Sender))) + i = encodeVarintTx(dAtA, i, uint64(len(m.Sender))) i-- dAtA[i] = 0xa } return len(dAtA) - i, nil } -func encodeVarintMsg(dAtA []byte, offset int, v uint64) int { - offset -= sovMsg(v) +func (m *MsgExecuteContractResponse) 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 *MsgExecuteContractResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgExecuteContractResponse) 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] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintTx(dAtA []byte, offset int, v uint64) int { + offset -= sovTx(v) base := offset for v >= 1<<7 { dAtA[offset] = uint8(v&0x7f | 0x80) @@ -422,19 +838,31 @@ func (m *MsgStoreCode) Size() (n int) { _ = l l = len(m.Sender) if l > 0 { - n += 1 + l + sovMsg(uint64(l)) + n += 1 + l + sovTx(uint64(l)) } l = len(m.WASMByteCode) if l > 0 { - n += 1 + l + sovMsg(uint64(l)) + n += 1 + l + sovTx(uint64(l)) } l = len(m.Source) if l > 0 { - n += 1 + l + sovMsg(uint64(l)) + n += 1 + l + sovTx(uint64(l)) } l = len(m.Builder) if l > 0 { - n += 1 + l + sovMsg(uint64(l)) + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgStoreCodeResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.CodeID != 0 { + n += 1 + sovTx(uint64(m.CodeID)) } return n } @@ -447,32 +875,49 @@ func (m *MsgInstantiateContract) Size() (n int) { _ = l l = len(m.Sender) if l > 0 { - n += 1 + l + sovMsg(uint64(l)) + n += 1 + l + sovTx(uint64(l)) } l = len(m.CallbackCodeHash) if l > 0 { - n += 1 + l + sovMsg(uint64(l)) + n += 1 + l + sovTx(uint64(l)) } if m.CodeID != 0 { - n += 1 + sovMsg(uint64(m.CodeID)) + n += 1 + sovTx(uint64(m.CodeID)) } l = len(m.Label) if l > 0 { - n += 1 + l + sovMsg(uint64(l)) + n += 1 + l + sovTx(uint64(l)) } l = len(m.InitMsg) if l > 0 { - n += 1 + l + sovMsg(uint64(l)) + n += 1 + l + sovTx(uint64(l)) } if len(m.InitFunds) > 0 { for _, e := range m.InitFunds { l = e.Size() - n += 1 + l + sovMsg(uint64(l)) + n += 1 + l + sovTx(uint64(l)) } } l = len(m.CallbackSig) if l > 0 { - n += 1 + l + sovMsg(uint64(l)) + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgInstantiateContractResponse) 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 } @@ -485,38 +930,51 @@ func (m *MsgExecuteContract) Size() (n int) { _ = l l = len(m.Sender) if l > 0 { - n += 1 + l + sovMsg(uint64(l)) + n += 1 + l + sovTx(uint64(l)) } l = len(m.Contract) if l > 0 { - n += 1 + l + sovMsg(uint64(l)) + n += 1 + l + sovTx(uint64(l)) } l = len(m.Msg) if l > 0 { - n += 1 + l + sovMsg(uint64(l)) + n += 1 + l + sovTx(uint64(l)) } l = len(m.CallbackCodeHash) if l > 0 { - n += 1 + l + sovMsg(uint64(l)) + n += 1 + l + sovTx(uint64(l)) } if len(m.SentFunds) > 0 { for _, e := range m.SentFunds { l = e.Size() - n += 1 + l + sovMsg(uint64(l)) + n += 1 + l + sovTx(uint64(l)) } } l = len(m.CallbackSig) if l > 0 { - n += 1 + l + sovMsg(uint64(l)) + n += 1 + l + sovTx(uint64(l)) } return n } -func sovMsg(x uint64) (n int) { +func (m *MsgExecuteContractResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Data) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func sovTx(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } -func sozMsg(x uint64) (n int) { - return sovMsg(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +func sozTx(x uint64) (n int) { + return sovTx(uint64((x << 1) ^ uint64((int64(x) >> 63)))) } func (m *MsgStoreCode) Unmarshal(dAtA []byte) error { l := len(dAtA) @@ -526,7 +984,7 @@ func (m *MsgStoreCode) Unmarshal(dAtA []byte) error { var wire uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowMsg + return ErrIntOverflowTx } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -554,7 +1012,7 @@ func (m *MsgStoreCode) Unmarshal(dAtA []byte) error { var byteLen int for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowMsg + return ErrIntOverflowTx } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -567,11 +1025,11 @@ func (m *MsgStoreCode) Unmarshal(dAtA []byte) error { } } if byteLen < 0 { - return ErrInvalidLengthMsg + return ErrInvalidLengthTx } postIndex := iNdEx + byteLen if postIndex < 0 { - return ErrInvalidLengthMsg + return ErrInvalidLengthTx } if postIndex > l { return io.ErrUnexpectedEOF @@ -588,7 +1046,7 @@ func (m *MsgStoreCode) Unmarshal(dAtA []byte) error { var byteLen int for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowMsg + return ErrIntOverflowTx } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -601,11 +1059,11 @@ func (m *MsgStoreCode) Unmarshal(dAtA []byte) error { } } if byteLen < 0 { - return ErrInvalidLengthMsg + return ErrInvalidLengthTx } postIndex := iNdEx + byteLen if postIndex < 0 { - return ErrInvalidLengthMsg + return ErrInvalidLengthTx } if postIndex > l { return io.ErrUnexpectedEOF @@ -622,7 +1080,7 @@ func (m *MsgStoreCode) Unmarshal(dAtA []byte) error { var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowMsg + return ErrIntOverflowTx } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -636,11 +1094,11 @@ func (m *MsgStoreCode) Unmarshal(dAtA []byte) error { } intStringLen := int(stringLen) if intStringLen < 0 { - return ErrInvalidLengthMsg + return ErrInvalidLengthTx } postIndex := iNdEx + intStringLen if postIndex < 0 { - return ErrInvalidLengthMsg + return ErrInvalidLengthTx } if postIndex > l { return io.ErrUnexpectedEOF @@ -654,7 +1112,7 @@ func (m *MsgStoreCode) Unmarshal(dAtA []byte) error { var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowMsg + return ErrIntOverflowTx } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -668,11 +1126,11 @@ func (m *MsgStoreCode) Unmarshal(dAtA []byte) error { } intStringLen := int(stringLen) if intStringLen < 0 { - return ErrInvalidLengthMsg + return ErrInvalidLengthTx } postIndex := iNdEx + intStringLen if postIndex < 0 { - return ErrInvalidLengthMsg + return ErrInvalidLengthTx } if postIndex > l { return io.ErrUnexpectedEOF @@ -681,12 +1139,81 @@ func (m *MsgStoreCode) Unmarshal(dAtA []byte) error { iNdEx = postIndex default: iNdEx = preIndex - skippy, err := skipMsg(dAtA[iNdEx:]) + 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 *MsgStoreCodeResponse) 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: MsgStoreCodeResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgStoreCodeResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + 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 + } + } + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) if err != nil { return err } if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthMsg + return ErrInvalidLengthTx } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF @@ -708,7 +1235,7 @@ func (m *MsgInstantiateContract) Unmarshal(dAtA []byte) error { var wire uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowMsg + return ErrIntOverflowTx } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -736,7 +1263,7 @@ func (m *MsgInstantiateContract) Unmarshal(dAtA []byte) error { var byteLen int for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowMsg + return ErrIntOverflowTx } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -749,11 +1276,11 @@ func (m *MsgInstantiateContract) Unmarshal(dAtA []byte) error { } } if byteLen < 0 { - return ErrInvalidLengthMsg + return ErrInvalidLengthTx } postIndex := iNdEx + byteLen if postIndex < 0 { - return ErrInvalidLengthMsg + return ErrInvalidLengthTx } if postIndex > l { return io.ErrUnexpectedEOF @@ -770,7 +1297,7 @@ func (m *MsgInstantiateContract) Unmarshal(dAtA []byte) error { var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowMsg + return ErrIntOverflowTx } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -784,11 +1311,11 @@ func (m *MsgInstantiateContract) Unmarshal(dAtA []byte) error { } intStringLen := int(stringLen) if intStringLen < 0 { - return ErrInvalidLengthMsg + return ErrInvalidLengthTx } postIndex := iNdEx + intStringLen if postIndex < 0 { - return ErrInvalidLengthMsg + return ErrInvalidLengthTx } if postIndex > l { return io.ErrUnexpectedEOF @@ -802,7 +1329,7 @@ func (m *MsgInstantiateContract) Unmarshal(dAtA []byte) error { m.CodeID = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowMsg + return ErrIntOverflowTx } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -821,7 +1348,7 @@ func (m *MsgInstantiateContract) Unmarshal(dAtA []byte) error { var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowMsg + return ErrIntOverflowTx } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -835,11 +1362,11 @@ func (m *MsgInstantiateContract) Unmarshal(dAtA []byte) error { } intStringLen := int(stringLen) if intStringLen < 0 { - return ErrInvalidLengthMsg + return ErrInvalidLengthTx } postIndex := iNdEx + intStringLen if postIndex < 0 { - return ErrInvalidLengthMsg + return ErrInvalidLengthTx } if postIndex > l { return io.ErrUnexpectedEOF @@ -853,7 +1380,7 @@ func (m *MsgInstantiateContract) Unmarshal(dAtA []byte) error { var byteLen int for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowMsg + return ErrIntOverflowTx } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -866,11 +1393,11 @@ func (m *MsgInstantiateContract) Unmarshal(dAtA []byte) error { } } if byteLen < 0 { - return ErrInvalidLengthMsg + return ErrInvalidLengthTx } postIndex := iNdEx + byteLen if postIndex < 0 { - return ErrInvalidLengthMsg + return ErrInvalidLengthTx } if postIndex > l { return io.ErrUnexpectedEOF @@ -887,7 +1414,7 @@ func (m *MsgInstantiateContract) Unmarshal(dAtA []byte) error { var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowMsg + return ErrIntOverflowTx } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -900,11 +1427,11 @@ func (m *MsgInstantiateContract) Unmarshal(dAtA []byte) error { } } if msglen < 0 { - return ErrInvalidLengthMsg + return ErrInvalidLengthTx } postIndex := iNdEx + msglen if postIndex < 0 { - return ErrInvalidLengthMsg + return ErrInvalidLengthTx } if postIndex > l { return io.ErrUnexpectedEOF @@ -921,7 +1448,7 @@ func (m *MsgInstantiateContract) Unmarshal(dAtA []byte) error { var byteLen int for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowMsg + return ErrIntOverflowTx } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -934,11 +1461,11 @@ func (m *MsgInstantiateContract) Unmarshal(dAtA []byte) error { } } if byteLen < 0 { - return ErrInvalidLengthMsg + return ErrInvalidLengthTx } postIndex := iNdEx + byteLen if postIndex < 0 { - return ErrInvalidLengthMsg + return ErrInvalidLengthTx } if postIndex > l { return io.ErrUnexpectedEOF @@ -950,12 +1477,128 @@ func (m *MsgInstantiateContract) Unmarshal(dAtA []byte) error { iNdEx = postIndex default: iNdEx = preIndex - skippy, err := skipMsg(dAtA[iNdEx:]) + skippy, err := skipTx(dAtA[iNdEx:]) if err != nil { return err } if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthMsg + 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 + 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: MsgInstantiateContractResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgInstantiateContractResponse: 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 @@ -977,7 +1620,7 @@ func (m *MsgExecuteContract) Unmarshal(dAtA []byte) error { var wire uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowMsg + return ErrIntOverflowTx } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -1005,7 +1648,7 @@ func (m *MsgExecuteContract) Unmarshal(dAtA []byte) error { var byteLen int for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowMsg + return ErrIntOverflowTx } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -1018,11 +1661,11 @@ func (m *MsgExecuteContract) Unmarshal(dAtA []byte) error { } } if byteLen < 0 { - return ErrInvalidLengthMsg + return ErrInvalidLengthTx } postIndex := iNdEx + byteLen if postIndex < 0 { - return ErrInvalidLengthMsg + return ErrInvalidLengthTx } if postIndex > l { return io.ErrUnexpectedEOF @@ -1039,7 +1682,7 @@ func (m *MsgExecuteContract) Unmarshal(dAtA []byte) error { var byteLen int for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowMsg + return ErrIntOverflowTx } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -1052,11 +1695,11 @@ func (m *MsgExecuteContract) Unmarshal(dAtA []byte) error { } } if byteLen < 0 { - return ErrInvalidLengthMsg + return ErrInvalidLengthTx } postIndex := iNdEx + byteLen if postIndex < 0 { - return ErrInvalidLengthMsg + return ErrInvalidLengthTx } if postIndex > l { return io.ErrUnexpectedEOF @@ -1073,7 +1716,7 @@ func (m *MsgExecuteContract) Unmarshal(dAtA []byte) error { var byteLen int for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowMsg + return ErrIntOverflowTx } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -1086,11 +1729,11 @@ func (m *MsgExecuteContract) Unmarshal(dAtA []byte) error { } } if byteLen < 0 { - return ErrInvalidLengthMsg + return ErrInvalidLengthTx } postIndex := iNdEx + byteLen if postIndex < 0 { - return ErrInvalidLengthMsg + return ErrInvalidLengthTx } if postIndex > l { return io.ErrUnexpectedEOF @@ -1107,7 +1750,7 @@ func (m *MsgExecuteContract) Unmarshal(dAtA []byte) error { var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowMsg + return ErrIntOverflowTx } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -1121,11 +1764,11 @@ func (m *MsgExecuteContract) Unmarshal(dAtA []byte) error { } intStringLen := int(stringLen) if intStringLen < 0 { - return ErrInvalidLengthMsg + return ErrInvalidLengthTx } postIndex := iNdEx + intStringLen if postIndex < 0 { - return ErrInvalidLengthMsg + return ErrInvalidLengthTx } if postIndex > l { return io.ErrUnexpectedEOF @@ -1139,7 +1782,7 @@ func (m *MsgExecuteContract) Unmarshal(dAtA []byte) error { var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowMsg + return ErrIntOverflowTx } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -1152,11 +1795,11 @@ func (m *MsgExecuteContract) Unmarshal(dAtA []byte) error { } } if msglen < 0 { - return ErrInvalidLengthMsg + return ErrInvalidLengthTx } postIndex := iNdEx + msglen if postIndex < 0 { - return ErrInvalidLengthMsg + return ErrInvalidLengthTx } if postIndex > l { return io.ErrUnexpectedEOF @@ -1173,7 +1816,7 @@ func (m *MsgExecuteContract) Unmarshal(dAtA []byte) error { var byteLen int for shift := uint(0); ; shift += 7 { if shift >= 64 { - return ErrIntOverflowMsg + return ErrIntOverflowTx } if iNdEx >= l { return io.ErrUnexpectedEOF @@ -1186,11 +1829,11 @@ func (m *MsgExecuteContract) Unmarshal(dAtA []byte) error { } } if byteLen < 0 { - return ErrInvalidLengthMsg + return ErrInvalidLengthTx } postIndex := iNdEx + byteLen if postIndex < 0 { - return ErrInvalidLengthMsg + return ErrInvalidLengthTx } if postIndex > l { return io.ErrUnexpectedEOF @@ -1202,12 +1845,96 @@ func (m *MsgExecuteContract) Unmarshal(dAtA []byte) error { iNdEx = postIndex default: iNdEx = preIndex - skippy, err := skipMsg(dAtA[iNdEx:]) + 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 *MsgExecuteContractResponse) 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: MsgExecuteContractResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgExecuteContractResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + 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 ErrInvalidLengthMsg + return ErrInvalidLengthTx } if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF @@ -1221,7 +1948,7 @@ func (m *MsgExecuteContract) Unmarshal(dAtA []byte) error { } return nil } -func skipMsg(dAtA []byte) (n int, err error) { +func skipTx(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 depth := 0 @@ -1229,7 +1956,7 @@ func skipMsg(dAtA []byte) (n int, err error) { var wire uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { - return 0, ErrIntOverflowMsg + return 0, ErrIntOverflowTx } if iNdEx >= l { return 0, io.ErrUnexpectedEOF @@ -1246,7 +1973,7 @@ func skipMsg(dAtA []byte) (n int, err error) { case 0: for shift := uint(0); ; shift += 7 { if shift >= 64 { - return 0, ErrIntOverflowMsg + return 0, ErrIntOverflowTx } if iNdEx >= l { return 0, io.ErrUnexpectedEOF @@ -1262,7 +1989,7 @@ func skipMsg(dAtA []byte) (n int, err error) { var length int for shift := uint(0); ; shift += 7 { if shift >= 64 { - return 0, ErrIntOverflowMsg + return 0, ErrIntOverflowTx } if iNdEx >= l { return 0, io.ErrUnexpectedEOF @@ -1275,14 +2002,14 @@ func skipMsg(dAtA []byte) (n int, err error) { } } if length < 0 { - return 0, ErrInvalidLengthMsg + return 0, ErrInvalidLengthTx } iNdEx += length case 3: depth++ case 4: if depth == 0 { - return 0, ErrUnexpectedEndOfGroupMsg + return 0, ErrUnexpectedEndOfGroupTx } depth-- case 5: @@ -1291,7 +2018,7 @@ func skipMsg(dAtA []byte) (n int, err error) { return 0, fmt.Errorf("proto: illegal wireType %d", wireType) } if iNdEx < 0 { - return 0, ErrInvalidLengthMsg + return 0, ErrInvalidLengthTx } if depth == 0 { return iNdEx, nil @@ -1301,7 +2028,7 @@ func skipMsg(dAtA []byte) (n int, err error) { } var ( - ErrInvalidLengthMsg = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowMsg = fmt.Errorf("proto: integer overflow") - ErrUnexpectedEndOfGroupMsg = fmt.Errorf("proto: unexpected end of group") + ErrInvalidLengthTx = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowTx = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupTx = fmt.Errorf("proto: unexpected end of group") ) diff --git a/x/compute/internal/types/types.go b/x/compute/internal/types/types.go index b36c03854..e7fa33014 100644 --- a/x/compute/internal/types/types.go +++ b/x/compute/internal/types/types.go @@ -172,7 +172,8 @@ func ContractLogsToSdkEvents(logs []wasmTypesV010.LogAttribute, contractAddr sdk attrs = append(attrs, attr) } } - // each wasm invokation always returns one sdk.Event + + // each wasm invocation always returns one sdk.Event return sdk.Events{sdk.NewEvent(CustomEventType, attrs...)} } diff --git a/x/compute/module.go b/x/compute/module.go index 95fdd3291..ca3d85f64 100644 --- a/x/compute/module.go +++ b/x/compute/module.go @@ -103,7 +103,9 @@ func NewAppModule(keeper Keeper) AppModule { func (AppModule) ConsensusVersion() uint64 { return 1 } func (am AppModule) RegisterServices(configurator module.Configurator) { + types.RegisterMsgServer(configurator.MsgServer(), keeper.NewMsgServerImpl(am.keeper)) types.RegisterQueryServer(configurator.QueryServer(), NewQuerier(am.keeper)) + // TODO register migrations here if needed } func (am AppModule) LegacyQuerierHandler(amino *codec.LegacyAmino) sdk.Querier { diff --git a/x/registration/client/cli/query.go b/x/registration/client/cli/query.go index c3cc7d400..ad74bfdd8 100644 --- a/x/registration/client/cli/query.go +++ b/x/registration/client/cli/query.go @@ -56,7 +56,7 @@ func GetCmdEncryptedSeed() *cobra.Command { if err != nil { return err } - fmt.Println(fmt.Sprintf("0x%s", hex.EncodeToString(res))) //nolint:gosimple + fmt.Printf("0x%s\n", hex.EncodeToString(res)) return nil }, } diff --git a/x/registration/internal/keeper/querier_test.go b/x/registration/internal/keeper/querier_test.go index 637dfbd56..70ff6f993 100644 --- a/x/registration/internal/keeper/querier_test.go +++ b/x/registration/internal/keeper/querier_test.go @@ -99,5 +99,6 @@ func TestNewQuerier(t *testing.T) { keeper.setMasterCertificate(ctx, types.MasterCertificate{Bytes: regInfo.Certificate}, types.MasterIoKeyId) binResult, err := querier(ctx, []string{QueryMasterCertificate}, abci.RequestQuery{Data: []byte("")}) + require.NoError(t, err) require.Equal(t, string(binResult), string(expectedSecretParams)) }