Repository: CosmWasm/cw-multi-test
Pull request #55 (2023-08-23 23:23:16)

Derive Clone for App
This is useful in testing. It's common to run a complicated setup procedure to build an app state, then to run different tests on that app. Rather that constantly rebuilding the state this allows you to clone it around.

It seems that perhaps other useful derives are missing as well (Debug being an obvious one). Though I don't immediately have a use case for that.


Patch:
diff --git a/.circleci/config.yml b/.circleci/config.yml
index 1f400e1..3078304 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -76,10 +76,10 @@ jobs:
             - cargocache-v2-multi-test:1.65.0-minimal-{{ checksum "Cargo.toml" }}
       - run:
           name: Build library for native target
-          command: cargo build -Zminimal-versions --features backtrace,cosmwasm_1_1,cosmwasm_1_2,cosmwasm_1_3,cosmwasm_1_4,iterator,staking,stargate
+          command: cargo build -Zminimal-versions --all-features
       - run:
           name: Run unit tests
-          command: cargo test --workspace -Zminimal-versions --features backtrace,cosmwasm_1_1,cosmwasm_1_2,cosmwasm_1_3,cosmwasm_1_4,iterator,staking,stargate
+          command: cargo test --workspace -Zminimal-versions --all-features
       - save_cache:
           paths:
             - /usr/local/cargo/registry
@@ -106,7 +106,7 @@ jobs:
           command: cargo build --locked --all-features
       - run:
           name: Run unit tests
-          command: cargo test --workspace --locked --features backtrace,cosmwasm_1_1,cosmwasm_1_2,cosmwasm_1_3,cosmwasm_1_4,iterator,staking,stargate
+          command: cargo test --workspace --locked --all-features
       - save_cache:
           paths:
             - /usr/local/cargo/registry
@@ -159,6 +159,6 @@ jobs:
           command: |
             mkdir -p cov
             docker run --security-opt seccomp=unconfined -v "${PWD}:/volume" xd009642/tarpaulin \
-              sh -c "cargo tarpaulin --workspace --features backtrace,cosmwasm_1_1,cosmwasm_1_2,cosmwasm_1_3,cosmwasm_1_4,iterator,staking,stargate --force-clean --engine llvm --out xml --output-dir cov"
+              sh -c "cargo tarpaulin --workspace --skip-clean --frozen --out Xml --output-dir cov"
       - codecov/upload:
           file: cov/cobertura.xml
diff --git a/CHANGELOG.md b/CHANGELOG.md
index dc26380..74c245a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,30 +1,5 @@
 # Changelog
 
-## [v0.17.0](https://github.com/CosmWasm/cw-multi-test/tree/v0.17.0) (2023-09-27)
-
-[Full Changelog](https://github.com/CosmWasm/cw-multi-test/compare/v0.16.5...v0.17.0)
-
-**Closed issues:**
-
-- Refactoring: replace EmptyMsg with cosmwasm_std::Empty [\#61](https://github.com/CosmWasm/cw-multi-test/issues/61)
-- Better error loggin when a message execution fails [\#60](https://github.com/CosmWasm/cw-multi-test/issues/60)
-- Add function App::duplicate_code [\#58](https://github.com/CosmWasm/cw-multi-test/issues/58)
-- Include CodeData support [\#49](https://github.com/CosmWasm/cw-multi-test/issues/49)
-
-**Merged pull requests:**
-
-- Removed multitest_api_1_0 feature [\#71](https://github.com/CosmWasm/cw-multi-test/pull/71) ([DariuszDepta](https://github.com/DariuszDepta))
-- Final line-break in Cargo.toml [\#68](https://github.com/CosmWasm/cw-multi-test/pull/68) ([DariuszDepta](https://github.com/DariuszDepta))
-- Updated dependencies [\#67](https://github.com/CosmWasm/cw-multi-test/pull/67) ([DariuszDepta](https://github.com/DariuszDepta))
-- Handling WasmMsg::instantiate2 message [\#65](https://github.com/CosmWasm/cw-multi-test/pull/65) ([DariuszDepta](https://github.com/DariuszDepta))
-- Improved error logging when the message execution fails [\#63](https://github.com/CosmWasm/cw-multi-test/pull/63) ([DariuszDepta](https://github.com/DariuszDepta))
-- Replaced test_helpers::EmptyMsg with cosmwasm_std::Empty [\#62](https://github.com/CosmWasm/cw-multi-test/pull/62) ([DariuszDepta](https://github.com/DariuszDepta))
-- Duplicate contract code [\#59](https://github.com/CosmWasm/cw-multi-test/pull/59) ([DariuszDepta](https://github.com/DariuszDepta))
-- CodeInfo support [\#57](https://github.com/CosmWasm/cw-multi-test/pull/57) ([DariuszDepta](https://github.com/DariuszDepta))
-- Change contract address attribute [\#52](https://github.com/CosmWasm/cw-multi-test/pull/52) ([chipshort](https://github.com/chipshort))
-- Adds BankQuery::Supply support [\#51](https://github.com/CosmWasm/cw-multi-test/pull/51) ([JakeHartnell](https://github.com/JakeHartnell))
-- Remove direct k256 dependencies [\#47](https://github.com/CosmWasm/cw-multi-test/pull/47) ([webmaster128](https://github.com/webmaster128))
-
 ## [v0.16.5](https://github.com/CosmWasm/cw-multi-test/tree/v0.16.5) (2023-06-07)
 
 [Full Changelog](https://github.com/CosmWasm/cw-multi-test/compare/v0.16.4...v0.16.5)
diff --git a/Cargo.lock b/Cargo.lock
index ec283b1..83dce0e 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4,9 +4,9 @@ version = 3
 
 [[package]]
 name = "addr2line"
-version = "0.21.0"
+version = "0.19.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb"
+checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97"
 dependencies = [
  "gimli",
 ]
@@ -30,18 +30,18 @@ dependencies = [
 
 [[package]]
 name = "anyhow"
-version = "1.0.75"
+version = "1.0.66"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
+checksum = "216261ddc8289130e551ddcd5ce8a064710c0d064a4d2895c67151c92b5443f6"
 dependencies = [
  "backtrace",
 ]
 
 [[package]]
 name = "backtrace"
-version = "0.3.69"
+version = "0.3.67"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837"
+checksum = "233d376d6d185f2a3093e58f283f60f880315b6c60075b01f36b3b85154564ca"
 dependencies = [
  "addr2line",
  "cc",
@@ -54,21 +54,21 @@ dependencies = [
 
 [[package]]
 name = "base16ct"
-version = "0.2.0"
+version = "0.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf"
+checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce"
 
 [[package]]
 name = "base64"
-version = "0.21.4"
+version = "0.13.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2"
+checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
 
 [[package]]
 name = "base64ct"
-version = "1.6.0"
+version = "1.5.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b"
+checksum = "b645a089122eccb6111b4f81cbc1a49f5900ac4666bb93ac027feaecf15607bf"
 
 [[package]]
 name = "block-buffer"
@@ -81,19 +81,13 @@ dependencies = [
 
 [[package]]
 name = "block-buffer"
-version = "0.10.4"
+version = "0.10.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
+checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e"
 dependencies = [
  "generic-array",
 ]
 
-[[package]]
-name = "bnum"
-version = "0.8.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "128a44527fc0d6abf05f9eda748b9027536e12dff93f5acc8449f51583309350"
-
 [[package]]
 name = "byteorder"
 version = "1.4.3"
@@ -102,18 +96,15 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
 
 [[package]]
 name = "bytes"
-version = "1.5.0"
+version = "1.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223"
+checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c"
 
 [[package]]
 name = "cc"
-version = "1.0.83"
+version = "1.0.78"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
-dependencies = [
- "libc",
-]
+checksum = "a20104e2335ce8a659d6dd92a51a767a0c062599c73b343fd152cb401e828c3d"
 
 [[package]]
 name = "cfg-if"
@@ -123,17 +114,17 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
 [[package]]
 name = "const-oid"
-version = "0.9.5"
+version = "0.9.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "28c122c3980598d243d63d9a704629a2d748d101f278052ff068be5a4423ab6f"
+checksum = "cec318a675afcb6a1ea1d4340e2d377e56e47c266f28043ceccbf4412ddfdd3b"
 
 [[package]]
 name = "cosmwasm-crypto"
-version = "1.4.0"
+version = "1.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1ca101fbf2f76723711a30ea3771ef312ec3ec254ad021b237871ed802f9f175"
+checksum = "6a8263ce52392898aa17c2a0984b7c542df416e434f6e0cb1c1a11771054d159"
 dependencies = [
- "digest 0.10.7",
+ "digest 0.10.6",
  "ed25519-zebra",
  "k256",
  "rand_core 0.6.4",
@@ -142,18 +133,18 @@ dependencies = [
 
 [[package]]
 name = "cosmwasm-derive"
-version = "1.4.0"
+version = "1.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c73d2dd292f60e42849d2b07c03d809cf31e128a4299a805abd6d24553bcaaf5"
+checksum = "f1895f6d7a191bb044e3c555190d1da555c2571a3af41f849f60c855580e392f"
 dependencies = [
- "syn 1.0.109",
+ "syn",
 ]
 
 [[package]]
 name = "cosmwasm-schema"
-version = "1.4.0"
+version = "1.1.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6ce34a08020433989af5cc470104f6bd22134320fe0221bd8aeb919fd5ec92d5"
+checksum = "04135971e2c3b867eb793ca4e832543c077dbf72edaef7672699190f8fcdb619"
 dependencies = [
  "cosmwasm-schema-derive",
  "schemars",
@@ -164,23 +155,22 @@ dependencies = [
 
 [[package]]
 name = "cosmwasm-schema-derive"
-version = "1.4.0"
+version = "1.1.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "96694ec781a7dd6dea1f968a2529ade009c21ad999c88b5f53d6cc495b3b96f7"
+checksum = "a06c8f516a13ae481016aa35f0b5c4652459e8aee65b15b6fb51547a07cea5a0"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 1.0.109",
+ "syn",
 ]
 
 [[package]]
 name = "cosmwasm-std"
-version = "1.4.0"
+version = "1.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2a44d3f9c25b2f864737c6605a98f2e4675d53fd8bbc7cf4d7c02475661a793d"
+checksum = "ecc01051aab3bb88d5efe0b90f24a6df1ca96a873b12fc21b862b17539c84ee9"
 dependencies = [
  "base64",
- "bnum",
  "cosmwasm-crypto",
  "cosmwasm-derive",
  "derivative",
@@ -189,24 +179,31 @@ dependencies = [
  "schemars",
  "serde",
  "serde-json-wasm",
- "sha2 0.10.8",
+ "sha2 0.10.6",
  "thiserror",
+ "uint",
 ]
 
 [[package]]
 name = "cpufeatures"
-version = "0.2.9"
+version = "0.2.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1"
+checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320"
 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.5.3"
+version = "0.4.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "740fe28e594155f10cfc383984cbefd529d7396050557148f79cb0f621204124"
+checksum = "ef2b4b23cddf68b89b8f8069890e8c270d54e2d5fe1b143820234805e4cb17ef"
 dependencies = [
  "generic-array",
  "rand_core 0.6.4",
@@ -239,27 +236,27 @@ dependencies = [
 
 [[package]]
 name = "cw-multi-test"
-version = "0.17.0"
+version = "0.16.5"
 dependencies = [
  "anyhow",
  "cosmwasm-std",
- "cw-storage-plus",
+ "cw-storage-plus 1.0.1",
  "cw-utils",
  "derivative",
- "ecdsa",
  "itertools",
+ "k256",
  "prost",
  "schemars",
  "serde",
- "sha2 0.10.8",
+ "serde_json",
  "thiserror",
 ]
 
 [[package]]
 name = "cw-storage-plus"
-version = "1.1.0"
+version = "0.16.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3f0e92a069d62067f3472c62e30adedb4cab1754725c0f2a682b3128d2bf3c79"
+checksum = "d9b6f91c0b94481a3e9ef1ceb183c37d00764f8751e39b45fc09f4d9b970d469"
 dependencies = [
  "cosmwasm-std",
  "schemars",
@@ -267,14 +264,27 @@ dependencies = [
 ]
 
 [[package]]
-name = "cw-utils"
+name = "cw-storage-plus"
 version = "1.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c80e93d1deccb8588db03945016a292c3c631e6325d349ebb35d2db6f4f946f7"
+checksum = "053a5083c258acd68386734f428a5a171b29f7d733151ae83090c6fcc9417ffa"
 dependencies = [
+ "cosmwasm-std",
+ "schemars",
+ "serde",
+]
+
+[[package]]
+name = "cw-utils"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b50d0cac456f98b4339b78e890fbe60e4dfe888c87abacc1129fc3fe34bbe20a"
+dependencies = [
+ "anyhow",
  "cosmwasm-schema",
  "cosmwasm-std",
  "cw2",
+ "k256",
  "schemars",
  "semver",
  "serde",
@@ -283,23 +293,22 @@ dependencies = [
 
 [[package]]
 name = "cw2"
-version = "1.1.0"
+version = "0.16.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "29ac2dc7a55ad64173ca1e0a46697c31b7a5c51342f55a1e84a724da4eb99908"
+checksum = "91398113b806f4d2a8d5f8d05684704a20ffd5968bf87e3473e1973710b884ad"
 dependencies = [
  "cosmwasm-schema",
  "cosmwasm-std",
- "cw-storage-plus",
+ "cw-storage-plus 0.16.0",
  "schemars",
  "serde",
- "thiserror",
 ]
 
 [[package]]
 name = "der"
-version = "0.7.8"
+version = "0.6.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c"
+checksum = "f1a467a65c5e759bce6e65eaf91cc29f466cdc57cb65777bd646872a8a1fd4de"
 dependencies = [
  "const-oid",
  "zeroize",
@@ -313,7 +322,7 @@ checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 1.0.109",
+ "syn",
 ]
 
 [[package]]
@@ -327,34 +336,31 @@ dependencies = [
 
 [[package]]
 name = "digest"
-version = "0.10.7"
+version = "0.10.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
+checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f"
 dependencies = [
- "block-buffer 0.10.4",
- "const-oid",
+ "block-buffer 0.10.3",
  "crypto-common",
  "subtle",
 ]
 
 [[package]]
 name = "dyn-clone"
-version = "1.0.14"
+version = "1.0.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "23d2f3407d9a573d666de4b5bdf10569d73ca9478087346697dcbae6244bfbcd"
+checksum = "4f94fa09c2aeea5b8839e414b7b841bf429fd25b9c522116ac97ee87856d88b2"
 
 [[package]]
 name = "ecdsa"
-version = "0.16.8"
+version = "0.14.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a4b1e0c257a9e9f25f90ff76d7a68360ed497ee519c8e428d1825ef0000799d4"
+checksum = "413301934810f597c1d19ca71c8710e99a3f1ba28a0d2ebc01551a2daeea3c5c"
 dependencies = [
  "der",
- "digest 0.10.7",
  "elliptic-curve",
  "rfc6979",
  "signature",
- "spki",
 ]
 
 [[package]]
@@ -374,19 +380,20 @@ dependencies = [
 
 [[package]]
 name = "either"
-version = "1.9.0"
+version = "1.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
+checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797"
 
 [[package]]
 name = "elliptic-curve"
-version = "0.13.5"
+version = "0.12.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "968405c8fdc9b3bf4df0a6638858cc0b52462836ab6b1c87377785dd09cf1c0b"
+checksum = "e7bb888ab5300a19b8e5bceef25ac745ad065f3c9f7efc6de1b91958110891d3"
 dependencies = [
  "base16ct",
  "crypto-bigint",
- "digest 0.10.7",
+ "der",
+ "digest 0.10.6",
  "ff",
  "generic-array",
  "group",
@@ -399,9 +406,9 @@ dependencies = [
 
 [[package]]
 name = "ff"
-version = "0.13.0"
+version = "0.12.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449"
+checksum = "d013fc25338cc558c5c2cfbad646908fb23591e2404481826742b651c9af7160"
 dependencies = [
  "rand_core 0.6.4",
  "subtle",
@@ -415,20 +422,19 @@ checksum = "c8cbd1169bd7b4a0a20d92b9af7a7e0422888bd38a6f5ec29c1fd8c1558a272e"
 
 [[package]]
 name = "generic-array"
-version = "0.14.7"
+version = "0.14.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
+checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9"
 dependencies = [
  "typenum",
  "version_check",
- "zeroize",
 ]
 
 [[package]]
 name = "getrandom"
-version = "0.2.10"
+version = "0.2.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427"
+checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31"
 dependencies = [
  "cfg-if",
  "libc",
@@ -437,15 +443,15 @@ dependencies = [
 
 [[package]]
 name = "gimli"
-version = "0.28.0"
+version = "0.27.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0"
+checksum = "dec7af912d60cdbd3677c1af9352ebae6fb8394d165568a2234df0fa00f87793"
 
 [[package]]
 name = "group"
-version = "0.13.0"
+version = "0.12.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63"
+checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7"
 dependencies = [
  "ff",
  "rand_core 0.6.4",
@@ -473,73 +479,71 @@ version = "0.12.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
 dependencies = [
- "digest 0.10.7",
+ "digest 0.10.6",
 ]
 
 [[package]]
 name = "itertools"
-version = "0.11.0"
+version = "0.10.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57"
+checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
 dependencies = [
  "either",
 ]
 
 [[package]]
 name = "itoa"
-version = "1.0.9"
+version = "1.0.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38"
+checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc"
 
 [[package]]
 name = "k256"
-version = "0.13.1"
+version = "0.11.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cadb76004ed8e97623117f3df85b17aaa6626ab0b0831e6573f104df16cd1bcc"
+checksum = "72c1e0b51e7ec0a97369623508396067a486bd0cbed95a2659a4b863d28cfc8b"
 dependencies = [
  "cfg-if",
  "ecdsa",
  "elliptic-curve",
- "once_cell",
- "sha2 0.10.8",
- "signature",
+ "sha2 0.10.6",
 ]
 
 [[package]]
 name = "libc"
-version = "0.2.148"
+version = "0.2.138"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b"
+checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8"
 
 [[package]]
 name = "memchr"
-version = "2.6.3"
+version = "2.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c"
+checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
 
 [[package]]
 name = "miniz_oxide"
-version = "0.7.1"
+version = "0.6.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7"
+checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa"
 dependencies = [
  "adler",
 ]
 
 [[package]]
 name = "object"
-version = "0.32.1"
+version = "0.30.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0"
+checksum = "239da7f290cfa979f43f85a8efeee9a8a76d0827c356d37f9d3d7254d6b537fb"
 dependencies = [
  "memchr",
 ]
 
 [[package]]
 name = "once_cell"
-version = "1.18.0"
+version = "1.16.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
+checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860"
 
 [[package]]
 name = "opaque-debug"
@@ -549,9 +553,9 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
 
 [[package]]
 name = "pkcs8"
-version = "0.10.2"
+version = "0.9.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7"
+checksum = "9eca2c590a5f85da82668fa685c09ce2888b9430e83299debf1f34b65fd4a4ba"
 dependencies = [
  "der",
  "spki",
@@ -559,18 +563,18 @@ dependencies = [
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.67"
+version = "1.0.47"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328"
+checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725"
 dependencies = [
  "unicode-ident",
 ]
 
 [[package]]
 name = "prost"
-version = "0.12.1"
+version = "0.9.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f4fdd22f3b9c31b53c060df4a0613a1c7f062d4115a2b984dd15b1858f7e340d"
+checksum = "444879275cb4fd84958b1a1d5420d15e6fcf7c235fe47f053c9c2a80aceb6001"
 dependencies = [
  "bytes",
  "prost-derive",
@@ -578,22 +582,22 @@ dependencies = [
 
 [[package]]
 name = "prost-derive"
-version = "0.12.1"
+version = "0.9.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "265baba7fabd416cf5078179f7d2cbeca4ce7a9041111900675ea7c4cb8a4c32"
+checksum = "f9cc1a3263e07e0bf68e96268f37665207b49560d98739662cdfaae215c720fe"
 dependencies = [
  "anyhow",
  "itertools",
  "proc-macro2",
  "quote",
- "syn 2.0.37",
+ "syn",
 ]
 
 [[package]]
 name = "quote"
-version = "1.0.33"
+version = "1.0.21"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
+checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179"
 dependencies = [
  "proc-macro2",
 ]
@@ -615,31 +619,32 @@ dependencies = [
 
 [[package]]
 name = "rfc6979"
-version = "0.4.0"
+version = "0.3.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2"
+checksum = "7743f17af12fa0b03b803ba12cd6a8d9483a587e89c69445e3909655c0b9fabb"
 dependencies = [
+ "crypto-bigint",
  "hmac",
- "subtle",
+ "zeroize",
 ]
 
 [[package]]
 name = "rustc-demangle"
-version = "0.1.23"
+version = "0.1.21"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
+checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342"
 
 [[package]]
 name = "ryu"
-version = "1.0.15"
+version = "1.0.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
+checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09"
 
 [[package]]
 name = "schemars"
-version = "0.8.15"
+version = "0.8.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1f7b0ce13155372a76ee2e1c5ffba1fe61ede73fbea5630d61eee6fac4929c0c"
+checksum = "2a5fb6c61f29e723026dc8e923d94c694313212abbecbbe5f55a7748eec5b307"
 dependencies = [
  "dyn-clone",
  "schemars_derive",
@@ -649,21 +654,21 @@ dependencies = [
 
 [[package]]
 name = "schemars_derive"
-version = "0.8.15"
+version = "0.8.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e85e2a16b12bdb763244c69ab79363d71db2b4b918a2def53f80b02e0574b13c"
+checksum = "f188d036977451159430f3b8dc82ec76364a42b7e289c2b18a9a18f4470058e9"
 dependencies = [
  "proc-macro2",
  "quote",
  "serde_derive_internals",
- "syn 1.0.109",
+ "syn",
 ]
 
 [[package]]
 name = "sec1"
-version = "0.7.3"
+version = "0.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc"
+checksum = "3be24c1842290c45df0a7bf069e0c268a747ad05a192f2fd7dcfdbc1cba40928"
 dependencies = [
  "base16ct",
  "der",
@@ -675,37 +680,37 @@ dependencies = [
 
 [[package]]
 name = "semver"
-version = "1.0.19"
+version = "1.0.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ad977052201c6de01a8ef2aa3378c4bd23217a056337d1d6da40468d267a4fb0"
+checksum = "e25dfac463d778e353db5be2449d1cce89bd6fd23c9f1ea21310ce6e5a1b29c4"
 
 [[package]]
 name = "serde"
-version = "1.0.188"
+version = "1.0.150"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e"
+checksum = "e326c9ec8042f1b5da33252c8a37e9ffbd2c9bef0155215b6e6c80c790e05f91"
 dependencies = [
  "serde_derive",
 ]
 
 [[package]]
 name = "serde-json-wasm"
-version = "0.5.1"
+version = "0.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "16a62a1fad1e1828b24acac8f2b468971dade7b8c3c2e672bcadefefb1f8c137"
+checksum = "a15bee9b04dd165c3f4e142628982ddde884c2022a89e8ddf99c4829bf2c3a58"
 dependencies = [
  "serde",
 ]
 
 [[package]]
 name = "serde_derive"
-version = "1.0.188"
+version = "1.0.150"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2"
+checksum = "42a3df25b0713732468deadad63ab9da1f1fd75a48a15024b50363f128db627e"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.37",
+ "syn",
 ]
 
 [[package]]
@@ -716,14 +721,14 @@ checksum = "85bf8229e7920a9f636479437026331ce11aa132b4dde37d121944a44d6e5f3c"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 1.0.109",
+ "syn",
 ]
 
 [[package]]
 name = "serde_json"
-version = "1.0.107"
+version = "1.0.89"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65"
+checksum = "020ff22c755c2ed3f8cf162dbb41a7268d934702f3ed3631656ea597e08fc3db"
 dependencies = [
  "itoa",
  "ryu",
@@ -745,57 +750,52 @@ dependencies = [
 
 [[package]]
 name = "sha2"
-version = "0.10.8"
+version = "0.10.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8"
+checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0"
 dependencies = [
  "cfg-if",
  "cpufeatures",
- "digest 0.10.7",
+ "digest 0.10.6",
 ]
 
 [[package]]
 name = "signature"
-version = "2.1.0"
+version = "1.6.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500"
+checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c"
 dependencies = [
- "digest 0.10.7",
+ "digest 0.10.6",
  "rand_core 0.6.4",
 ]
 
 [[package]]
 name = "spki"
-version = "0.7.2"
+version = "0.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9d1e996ef02c474957d681f1b05213dfb0abab947b446a62d37770b23500184a"
+checksum = "67cf02bbac7a337dc36e4f5a693db6c21e7863f45070f7064577eb4367a3212b"
 dependencies = [
  "base64ct",
  "der",
 ]
 
 [[package]]
-name = "subtle"
-version = "2.5.0"
+name = "static_assertions"
+version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc"
+checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
 
 [[package]]
-name = "syn"
-version = "1.0.109"
+name = "subtle"
+version = "2.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
-dependencies = [
- "proc-macro2",
- "quote",
- "unicode-ident",
-]
+checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"
 
 [[package]]
 name = "syn"
-version = "2.0.37"
+version = "1.0.105"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7303ef2c05cd654186cb250d29049a24840ca25d2747c25c0381c8d9e2f582e8"
+checksum = "60b9b43d45702de4c839cb9b51d9f529c5dd26a4aff255b42b1ebc03e88ee908"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -804,35 +804,47 @@ dependencies = [
 
 [[package]]
 name = "thiserror"
-version = "1.0.49"
+version = "1.0.39"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1177e8c6d7ede7afde3585fd2513e611227efd6481bd78d2e82ba1ce16557ed4"
+checksum = "a5ab016db510546d856297882807df8da66a16fb8c4101cb8b30054b0d5b2d9c"
 dependencies = [
  "thiserror-impl",
 ]
 
 [[package]]
 name = "thiserror-impl"
-version = "1.0.49"
+version = "1.0.39"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "10712f02019e9288794769fba95cd6847df9874d49d871d062172f9dd41bc4cc"
+checksum = "5420d42e90af0c38c3290abcca25b9b3bdf379fc9f55c528f53a269d9c9a267e"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.37",
+ "syn",
 ]
 
 [[package]]
 name = "typenum"
-version = "1.17.0"
+version = "1.16.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
+
+[[package]]
+name = "uint"
+version = "0.9.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
+checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52"
+dependencies = [
+ "byteorder",
+ "crunchy",
+ "hex",
+ "static_assertions",
+]
 
 [[package]]
 name = "unicode-ident"
-version = "1.0.12"
+version = "1.0.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
+checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3"
 
 [[package]]
 name = "version_check"
@@ -848,6 +860,6 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
 
 [[package]]
 name = "zeroize"
-version = "1.6.0"
+version = "1.5.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9"
+checksum = "c394b5bd0c6f669e7275d9c20aa90ae064cb22e75a1cad54e1b34088034b149f"
diff --git a/Cargo.toml b/Cargo.toml
index 48d93e4..455e8d9 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "cw-multi-test"
-version = "0.17.0"
+version = "0.16.5"
 authors = ["Ethan Frey <ethanfrey@users.noreply.github.com>"]
 edition = "2021"
 description = "Test helpers for multi-contract interactions"
@@ -8,6 +8,7 @@ license = "Apache-2.0"
 repository = "https://github.com/CosmWasm/cw-multi-test"
 homepage = "https://cosmwasm.com"
 
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 [features]
 default = ["iterator", "staking", "cosmwasm_1_1"]
 iterator = ["cosmwasm-std/iterator"]
@@ -15,24 +16,26 @@ stargate = ["cosmwasm-std/stargate"]
 staking = ["cosmwasm-std/staking"]
 backtrace = ["anyhow/backtrace"]
 cosmwasm_1_1 = ["cosmwasm-std/cosmwasm_1_1"]
-cosmwasm_1_2 = ["cosmwasm_1_1", "cosmwasm-std/cosmwasm_1_2"]
-cosmwasm_1_3 = ["cosmwasm_1_2", "cosmwasm-std/cosmwasm_1_3"]
-cosmwasm_1_4 = ["cosmwasm_1_3", "cosmwasm-std/cosmwasm_1_4"]
 
 [dependencies]
-cw-utils = "1.0.1"
-cw-storage-plus = "1.1.0"
-cosmwasm-std = { version = "1.4.0", features = ["staking", "stargate"] }
-itertools = "0.11.0"
-schemars = "0.8.13"
-serde = { version = "1.0.188", default-features = false, features = ["derive"] }
-prost = "0.12.0"
-anyhow = "1.0.75"
-thiserror = "1.0.48"
-derivative = "2.2.0"
-sha2 = "0.10.7"
+cw-utils = "1.0"
+cw-storage-plus = "1.0"
+cosmwasm-std = { version = "1.2", features = ["staking", "stargate"] }
+itertools = "0.10.1"
+schemars = "0.8.1"
+serde = { version = "1.0", default-features = false, features = ["derive"] }
+prost = "0.9"
+anyhow = "1.0.41"
+thiserror = "1.0"
+derivative = "2"
+
+# We don't use the following dependencies directly. They're dependencies of our dependencies.
+# We specify them to tighten their version requirements so that builds with `-Zminimal-versions` work.
+# Once we bump `cosmwasm-*` deps to a version after `1.1.5`, we can remove these.
+k256 = { version = "0.11.1", features = ["ecdsa"] }
 
 [dev-dependencies]
-# We don't use these dependencies directly,
-# we tighten versions that builds with `-Zminimal-versions` work.
-ecdsa = "0.16.8"
+# We don't use the following dependencies directly. They're dependencies of our dependencies.
+# We specify them to tighten their version requirements so that builds with `-Zminimal-versions` work.
+# Once we bump `cosmwasm-*` deps to a version after `1.1.5`, we can remove these.
+serde_json = "1.0.40"
diff --git a/clippy.toml b/clippy.toml
index ddd33ae..1590630 100644
--- a/clippy.toml
+++ b/clippy.toml
@@ -1,1 +1,1 @@
-too-many-arguments-threshold = 12
+too-many-arguments-threshold = 10
diff --git a/src/app.rs b/src/app.rs
index de69121..1a4cc5d 100644
--- a/src/app.rs
+++ b/src/app.rs
@@ -1,3 +1,18 @@
+use std::fmt::{self, Debug};
+use std::marker::PhantomData;
+
+use anyhow::bail;
+use anyhow::Result as AnyResult;
+use cosmwasm_std::testing::{mock_env, MockApi, MockStorage};
+use cosmwasm_std::{
+    from_slice, to_binary, Addr, Api, Binary, BlockInfo, ContractResult, CosmosMsg, CustomQuery,
+    Empty, GovMsg, IbcMsg, IbcQuery, Querier, QuerierResult, QuerierWrapper, QueryRequest, Record,
+    Storage, SystemError, SystemResult,
+};
+use schemars::JsonSchema;
+use serde::de::DeserializeOwned;
+use serde::Serialize;
+
 use crate::bank::{Bank, BankKeeper, BankSudo};
 use crate::contracts::Contract;
 use crate::executor::{AppResponse, Executor};
@@ -7,18 +22,6 @@ use crate::module::{FailingModule, Module};
 use crate::staking::{Distribution, DistributionKeeper, StakeKeeper, Staking, StakingSudo};
 use crate::transactions::transactional;
 use crate::wasm::{ContractData, Wasm, WasmKeeper, WasmSudo};
-use anyhow::{bail, Result as AnyResult};
-use cosmwasm_std::{
-    from_slice,
-    testing::{mock_env, MockApi, MockStorage},
-    to_binary, Addr, Api, Binary, BlockInfo, ContractResult, CosmosMsg, CustomQuery, Empty, GovMsg,
-    IbcMsg, IbcQuery, Querier, QuerierResult, QuerierWrapper, QueryRequest, Record, Storage,
-    SystemError, SystemResult,
-};
-use schemars::JsonSchema;
-use serde::{de::DeserializeOwned, Serialize};
-use std::fmt::Debug;
-use std::marker::PhantomData;
 
 pub fn next_block(block: &mut BlockInfo) {
     block.time = block.time.plus_seconds(5);
@@ -40,6 +43,7 @@ pub type BasicApp<ExecC = Empty, QueryC = Empty> = App<
 /// Router is a persisted state. You can query this.
 /// Execution generally happens on the RouterCache, which then can be atomically committed or rolled back.
 /// We offer .execute() as a wrapper around cache, execute, commit/rollback process.
+#[derive(Clone)]
 pub struct App<
     Bank = BankKeeper,
     Api = MockApi,
@@ -57,7 +61,7 @@ pub struct App<
     block: BlockInfo,
 }
 
-pub fn no_init<BankT, CustomT, WasmT, StakingT, DistrT, IbcT, GovT>(
+fn no_init<BankT, CustomT, WasmT, StakingT, DistrT, IbcT, GovT>(
     _: &mut Router<BankT, CustomT, WasmT, StakingT, DistrT, IbcT, GovT>,
     _: &dyn Api,
     _: &mut dyn Storage,
@@ -118,7 +122,7 @@ where
 impl<BankT, ApiT, StorageT, CustomT, WasmT, StakingT, DistrT, IbcT, GovT> Querier
     for App<BankT, ApiT, StorageT, CustomT, WasmT, StakingT, DistrT, IbcT, GovT>
 where
-    CustomT::ExecT: Clone + Debug + PartialEq + JsonSchema + DeserializeOwned + 'static,
+    CustomT::ExecT: Clone + fmt::Debug + PartialEq + JsonSchema + DeserializeOwned + 'static,
     CustomT::QueryT: CustomQuery + DeserializeOwned + 'static,
     WasmT: Wasm<CustomT::ExecT, CustomT::QueryT>,
     BankT: Bank,
@@ -140,7 +144,7 @@ where
 impl<BankT, ApiT, StorageT, CustomT, WasmT, StakingT, DistrT, IbcT, GovT> Executor<CustomT::ExecT>
     for App<BankT, ApiT, StorageT, CustomT, WasmT, StakingT, DistrT, IbcT, GovT>
 where
-    CustomT::ExecT: Clone + Debug + PartialEq + JsonSchema + DeserializeOwned + 'static,
+    CustomT::ExecT: Clone + fmt::Debug + PartialEq + JsonSchema + DeserializeOwned + 'static,
     CustomT::QueryT: CustomQuery + DeserializeOwned + 'static,
     WasmT: Wasm<CustomT::ExecT, CustomT::QueryT>,
     BankT: Bank,
@@ -152,7 +156,11 @@ where
     IbcT: Ibc,
     GovT: Gov,
 {
-    fn execute(&mut self, sender: Addr, msg: CosmosMsg<CustomT::ExecT>) -> AnyResult<AppResponse> {
+    fn execute(
+        &mut self,
+        sender: Addr,
+        msg: cosmwasm_std::CosmosMsg<CustomT::ExecT>,
+    ) -> AnyResult<AppResponse> {
         let mut all = self.execute_multi(sender, vec![msg])?;
         let res = all.pop().unwrap();
         Ok(res)
@@ -173,8 +181,7 @@ pub type BasicAppBuilder<ExecC, QueryC> = AppBuilder<
     FailingModule<GovMsg, Empty, Empty>,
 >;
 
-/// Utility to build [App] in stages. If particular items/properties are not explicitly set,
-/// then default values are used.
+/// Utility to build App in stages. If particular items wont be set, defaults would be used
 pub struct AppBuilder<Bank, Api, Storage, Custom, Wasm, Staking, Distr, Ibc, Gov> {
     api: Api,
     block: BlockInfo,
@@ -272,16 +279,17 @@ where
 
 impl<BankT, ApiT, StorageT, CustomT, WasmT, StakingT, DistrT, IbcT, GovT>
     AppBuilder<BankT, ApiT, StorageT, CustomT, WasmT, StakingT, DistrT, IbcT, GovT>
-where
-    CustomT: Module,
-    WasmT: Wasm<CustomT::ExecT, CustomT::QueryT>,
 {
-    /// Overwrites the default wasm executor.
+    /// Overwrites default wasm executor.
     ///
     /// At this point it is needed that new wasm implements some `Wasm` trait, but it doesn't need
     /// to be bound to Bank or Custom yet - as those may change. The cross-components validation is
     /// done on final building.
-    pub fn with_wasm<NewWasm: Wasm<CustomT::ExecT, CustomT::QueryT>>(
+    ///
+    /// Also it is possible to completely abandon trait bounding here which would not be bad idea,
+    /// however it might make the message on build creepy in many cases, so as for properly build
+    /// `App` we always want `Wasm` to be `Wasm`, some checks are done early.
+    pub fn with_wasm<C: Module, NewWasm: Wasm<C::ExecT, C::QueryT>>(
         self,
         wasm: NewWasm,
     ) -> AppBuilder<BankT, ApiT, StorageT, CustomT, NewWasm, StakingT, DistrT, IbcT, GovT> {
@@ -312,7 +320,7 @@ where
         }
     }
 
-    /// Overwrites the default bank interface.
+    /// Overwrites default bank interface
     pub fn with_bank<NewBank: Bank>(
         self,
         bank: NewBank,
@@ -344,7 +352,7 @@ where
         }
     }
 
-    /// Overwrites the default api interface.
+    /// Overwrites default api interface
     pub fn with_api<NewApi: Api>(
         self,
         api: NewApi,
@@ -376,7 +384,7 @@ where
         }
     }
 
-    /// Overwrites the default storage interface.
+    /// Overwrites default storage interface
     pub fn with_storage<NewStorage: Storage>(
         self,
         storage: NewStorage,
@@ -408,11 +416,15 @@ where
         }
     }
 
-    /// Overwrites the default custom messages handler.
+    /// Overwrites default custom messages handler
     ///
     /// At this point it is needed that new custom implements some `Module` trait, but it doesn't need
     /// to be bound to ExecC or QueryC yet - as those may change. The cross-components validation is
     /// done on final building.
+    ///
+    /// Also it is possible to completely abandon trait bounding here which would not be bad idea,
+    /// however it might make the message on build creepy in many cases, so as for properly build
+    /// `App` we always want `Wasm` to be `Wasm`, some checks are done early.
     pub fn with_custom<NewCustom: Module>(
         self,
         custom: NewCustom,
@@ -444,7 +456,7 @@ where
         }
     }
 
-    /// Overwrites the default staking interface.
+    /// Overwrites default bank interface
     pub fn with_staking<NewStaking: Staking>(
         self,
         staking: NewStaking,
@@ -476,7 +488,7 @@ where
         }
     }
 
-    /// Overwrites the default distribution interface.
+    /// Overwrites default distribution interface
     pub fn with_distribution<NewDistribution: Distribution>(
         self,
         distribution: NewDistribution,
@@ -509,13 +521,10 @@ where
         }
     }
 
-    /// Overwrites the default ibc interface.
+    /// Overwrites default ibc interface.
     ///
-    /// If you wish to simply ignore/drop all returned IBC Messages,
-    /// you can use the `IbcAcceptingModule` type:
-    /// ```text
-    /// builder.with_ibc(IbcAcceptingModule::new())
-    /// ```
+    /// If you wish to simply ignore/drop all returned IBC Messages, you can use the `IbcAcceptingModule` type.
+    ///     builder.with_ibc(IbcAcceptingModule::new())
     pub fn with_ibc<NewIbc: Ibc>(
         self,
         ibc: NewIbc,
@@ -547,7 +556,7 @@ where
         }
     }
 
-    /// Overwrites the default gov interface.
+    /// Overwrites default gov interface
     pub fn with_gov<NewGov: Gov>(
         self,
         gov: NewGov,
@@ -579,14 +588,14 @@ where
         }
     }
 
-    /// Overwrites the initial block.
+    /// Overwrites default initial block
     pub fn with_block(mut self, block: BlockInfo) -> Self {
         self.block = block;
         self
     }
 
     /// Builds final `App`. At this point all components type have to be properly related to each
-    /// other. If there are some generics related compilation errors, make sure that all components
+    /// other. If there are some generics related compilation error make sure, that all components
     /// are properly relating to each other.
     pub fn build<F>(
         self,
@@ -667,100 +676,42 @@ where
 
 // Helper functions to call some custom WasmKeeper logic.
 // They show how we can easily add such calls to other custom keepers (CustomT, StakingT, etc)
-impl<BankT, ApiT, StorageT, CustomT, WasmT, StakingT, DistrT, IbcT, GovT>
-    App<BankT, ApiT, StorageT, CustomT, WasmT, StakingT, DistrT, IbcT, GovT>
+impl<BankT, ApiT, StorageT, CustomT, StakingT, DistrT, IbcT, GovT>
+    App<
+        BankT,
+        ApiT,
+        StorageT,
+        CustomT,
+        WasmKeeper<CustomT::ExecT, CustomT::QueryT>,
+        StakingT,
+        DistrT,
+        IbcT,
+        GovT,
+    >
 where
     BankT: Bank,
     ApiT: Api,
     StorageT: Storage,
     CustomT: Module,
-    WasmT: Wasm<CustomT::ExecT, CustomT::QueryT>,
     StakingT: Staking,
     DistrT: Distribution,
     IbcT: Ibc,
     GovT: Gov,
-    CustomT::ExecT: Clone + Debug + PartialEq + JsonSchema + DeserializeOwned + 'static,
+    CustomT::ExecT: Clone + fmt::Debug + PartialEq + JsonSchema + DeserializeOwned + 'static,
     CustomT::QueryT: CustomQuery + DeserializeOwned + 'static,
 {
-    /// Registers contract code (like uploading wasm bytecode on a chain),
+    /// This registers contract code (like uploading wasm bytecode on a chain),
     /// so it can later be used to instantiate a contract.
     pub fn store_code(&mut self, code: Box<dyn Contract<CustomT::ExecT, CustomT::QueryT>>) -> u64 {
-        self.init_modules(|router, _, _| {
-            router
-                .wasm
-                .store_code(Addr::unchecked("code-creator"), code)
-        })
-    }
-
-    /// Registers contract code (like [store_code](Self::store_code)),
-    /// but takes the address of the code creator as an additional argument.
-    pub fn store_code_with_creator(
-        &mut self,
-        creator: Addr,
-        code: Box<dyn Contract<CustomT::ExecT, CustomT::QueryT>>,
-    ) -> u64 {
-        self.init_modules(|router, _, _| router.wasm.store_code(creator, code))
-    }
-
-    /// Duplicates the contract code identified by `code_id` and returns
-    /// the identifier of the newly created copy of the contract code.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use cosmwasm_std::Addr;
-    /// use cw_multi_test::App;
-    ///
-    /// // contract implementation
-    /// mod echo {
-    ///   // contract entry points not shown here
-    /// #  use std::todo;
-    /// #  use cosmwasm_std::{Binary, Deps, DepsMut, Empty, Env, MessageInfo, Response, StdError, SubMsg, WasmMsg};
-    /// #  use serde::{Deserialize, Serialize};
-    /// #  use cw_multi_test::{Contract, ContractWrapper};
-    /// #
-    /// #  fn instantiate(_: DepsMut, _: Env, _: MessageInfo, _: Empty) -> Result<Response, StdError> {  
-    /// #    todo!()
-    /// #  }
-    /// #
-    /// #  fn execute(_: DepsMut, _: Env, _info: MessageInfo, msg: WasmMsg) -> Result<Response, StdError> {
-    /// #    todo!()
-    /// #  }
-    /// #
-    /// #  fn query(_deps: Deps, _env: Env, _msg: Empty) -> Result<Binary, StdError> {
-    /// #    todo!()
-    /// #  }
-    /// #  
-    ///   pub fn contract() -> Box<dyn Contract<Empty>> {
-    ///     // should return the contract
-    /// #   Box::new(ContractWrapper::new(execute, instantiate, query))
-    ///   }
-    /// }
-    ///
-    /// let mut app = App::default();
-    ///
-    /// // store a new contract, save the code id
-    /// let code_id = app.store_code(echo::contract());
-    ///
-    /// // duplicate the existing contract, duplicated contract has different code id
-    /// assert_ne!(code_id, app.duplicate_code(code_id).unwrap());
-    ///
-    /// // zero is an invalid identifier for contract code, returns an error
-    /// assert_eq!("code id: invalid", app.duplicate_code(0).unwrap_err().to_string());
-    ///
-    /// // there is no contract code with identifier 100 stored yet, returns an error
-    /// assert_eq!("code id 100: no such code", app.duplicate_code(100).unwrap_err().to_string());
-    /// ```
-    pub fn duplicate_code(&mut self, code_id: u64) -> AnyResult<u64> {
-        self.init_modules(|router, _, _| router.wasm.duplicate_code(code_id))
+        self.init_modules(|router, _, _| router.wasm.store_code(code) as u64)
     }
 
-    /// Returns `ContractData` for the contract with specified address.
+    /// This allows to get `ContractData` for specific contract
     pub fn contract_data(&self, address: &Addr) -> AnyResult<ContractData> {
-        self.read_module(|router, _, storage| router.wasm.contract_data(storage, address))
+        self.read_module(|router, _, storage| router.wasm.load_contract(storage, address))
     }
 
-    /// Returns a raw state dump of all key-values held by a contract with specified address.
+    /// This gets a raw state dump of all key-values held by a given contract
     pub fn dump_wasm_raw(&self, address: &Addr) -> Vec<Record> {
         self.read_module(|router, _, storage| router.wasm.dump_wasm_raw(storage, address))
     }
@@ -769,7 +720,7 @@ where
 impl<BankT, ApiT, StorageT, CustomT, WasmT, StakingT, DistrT, IbcT, GovT>
     App<BankT, ApiT, StorageT, CustomT, WasmT, StakingT, DistrT, IbcT, GovT>
 where
-    CustomT::ExecT: Debug + PartialEq + Clone + JsonSchema + DeserializeOwned + 'static,
+    CustomT::ExecT: std::fmt::Debug + PartialEq + Clone + JsonSchema + DeserializeOwned + 'static,
     CustomT::QueryT: CustomQuery + DeserializeOwned + 'static,
     WasmT: Wasm<CustomT::ExecT, CustomT::QueryT>,
     BankT: Bank,
@@ -807,7 +758,7 @@ where
     pub fn execute_multi(
         &mut self,
         sender: Addr,
-        msgs: Vec<CosmosMsg<CustomT::ExecT>>,
+        msgs: Vec<cosmwasm_std::CosmosMsg<CustomT::ExecT>>,
     ) -> AnyResult<Vec<AppResponse>> {
         // we need to do some caching of storage here, once in the entry point:
         // meaning, wrap current state, all writes go to a cache, only when execute
@@ -871,6 +822,7 @@ where
     }
 }
 
+#[derive(Clone)]
 pub struct Router<Bank, Custom, Wasm, Staking, Distr, Ibc, Gov> {
     // this can remain crate-only as all special functions are wired up to app currently
     // we need to figure out another format for wasm, as some like sudo need to be called after init
@@ -887,7 +839,7 @@ pub struct Router<Bank, Custom, Wasm, Staking, Distr, Ibc, Gov> {
 impl<BankT, CustomT, WasmT, StakingT, DistrT, IbcT, GovT>
     Router<BankT, CustomT, WasmT, StakingT, DistrT, IbcT, GovT>
 where
-    CustomT::ExecT: Clone + Debug + PartialEq + JsonSchema + DeserializeOwned + 'static,
+    CustomT::ExecT: Clone + fmt::Debug + PartialEq + JsonSchema + DeserializeOwned + 'static,
     CustomT::QueryT: CustomQuery + DeserializeOwned + 'static,
     CustomT: Module,
     WasmT: Wasm<CustomT::ExecT, CustomT::QueryT>,
@@ -972,7 +924,7 @@ pub trait CosmosRouter {
 impl<BankT, CustomT, WasmT, StakingT, DistrT, IbcT, GovT> CosmosRouter
     for Router<BankT, CustomT, WasmT, StakingT, DistrT, IbcT, GovT>
 where
-    CustomT::ExecT: Debug + Clone + PartialEq + JsonSchema + DeserializeOwned + 'static,
+    CustomT::ExecT: std::fmt::Debug + Clone + PartialEq + JsonSchema + DeserializeOwned + 'static,
     CustomT::QueryT: CustomQuery + DeserializeOwned + 'static,
     CustomT: Module,
     WasmT: Wasm<CustomT::ExecT, CustomT::QueryT>,
@@ -1128,7 +1080,7 @@ impl<'a, ExecC, QueryC> RouterQuerier<'a, ExecC, QueryC> {
 
 impl<'a, ExecC, QueryC> Querier for RouterQuerier<'a, ExecC, QueryC>
 where
-    ExecC: Clone + Debug + PartialEq + JsonSchema + DeserializeOwned + 'static,
+    ExecC: Clone + fmt::Debug + PartialEq + JsonSchema + DeserializeOwned + 'static,
     QueryC: CustomQuery + DeserializeOwned + 'static,
 {
     fn raw_query(&self, bin_request: &[u8]) -> QuerierResult {
@@ -1150,11 +1102,665 @@ where
 }
 
 #[cfg(test)]
-mod tests {
+mod test {
     use super::*;
-    use crate::transactions::StorageTransaction;
     use cosmwasm_std::testing::MockQuerier;
-    use cosmwasm_std::{coin, coins, AllBalanceResponse, BankMsg, BankQuery, Coin};
+    use cosmwasm_std::{
+        coin, coins, to_binary, AllBalanceResponse, Attribute, BankMsg, BankQuery, Coin, Event,
+        OverflowError, OverflowOperation, Reply, StdError, StdResult, SubMsg, WasmMsg,
+    };
+
+    use crate::error::Error;
+    use crate::test_helpers::contracts::{caller, echo, error, hackatom, payout, reflect};
+    use crate::test_helpers::{CustomMsg, EmptyMsg};
+    use crate::transactions::StorageTransaction;
+
+    fn get_balance<BankT, ApiT, StorageT, CustomT, WasmT>(
+        app: &App<BankT, ApiT, StorageT, CustomT, WasmT>,
+        addr: &Addr,
+    ) -> Vec<Coin>
+    where
+        CustomT::ExecT: Clone + fmt::Debug + PartialEq + JsonSchema + DeserializeOwned + 'static,
+        CustomT::QueryT: CustomQuery + DeserializeOwned + 'static,
+        WasmT: Wasm<CustomT::ExecT, CustomT::QueryT>,
+        BankT: Bank,
+        ApiT: Api,
+        StorageT: Storage,
+        CustomT: Module,
+    {
+        app.wrap().query_all_balances(addr).unwrap()
+    }
+
+    #[test]
+    fn update_block() {
+        let mut app = App::default();
+
+        let BlockInfo { time, height, .. } = app.block;
+        app.update_block(next_block);
+
+        assert_eq!(time.plus_seconds(5), app.block.time);
+        assert_eq!(height + 1, app.block.height);
+    }
+
+    #[test]
+    fn send_tokens() {
+        let owner = Addr::unchecked("owner");
+        let rcpt = Addr::unchecked("receiver");
+        let init_funds = vec![coin(20, "btc"), coin(100, "eth")];
+        let rcpt_funds = vec![coin(5, "btc")];
+
+        let mut app = App::new(|router, _, storage| {
+            // initialization moved to App construction
+            router
+                .bank
+                .init_balance(storage, &owner, init_funds)
+                .unwrap();
+            router
+                .bank
+                .init_balance(storage, &rcpt, rcpt_funds)
+                .unwrap();
+        });
+
+        // send both tokens
+        let to_send = vec![coin(30, "eth"), coin(5, "btc")];
+        let msg: cosmwasm_std::CosmosMsg = BankMsg::Send {
+            to_address: rcpt.clone().into(),
+            amount: to_send,
+        }
+        .into();
+        app.execute(owner.clone(), msg.clone()).unwrap();
+        let rich = get_balance(&app, &owner);
+        assert_eq!(vec![coin(15, "btc"), coin(70, "eth")], rich);
+        let poor = get_balance(&app, &rcpt);
+        assert_eq!(vec![coin(10, "btc"), coin(30, "eth")], poor);
+
+        // can send from other account (but funds will be deducted from sender)
+        app.execute(rcpt.clone(), msg).unwrap();
+
+        // cannot send too much
+        let msg = BankMsg::Send {
+            to_address: rcpt.into(),
+            amount: coins(20, "btc"),
+        }
+        .into();
+        app.execute(owner.clone(), msg).unwrap_err();
+
+        let rich = get_balance(&app, &owner);
+        assert_eq!(vec![coin(15, "btc"), coin(70, "eth")], rich);
+    }
+
+    #[test]
+    fn simple_contract() {
+        // set personal balance
+        let owner = Addr::unchecked("owner");
+        let init_funds = vec![coin(20, "btc"), coin(100, "eth")];
+
+        let mut app = App::new(|router, _, storage| {
+            router
+                .bank
+                .init_balance(storage, &owner, init_funds)
+                .unwrap();
+        });
+
+        // set up contract
+        let code_id = app.store_code(payout::contract());
+        let msg = payout::InstantiateMessage {
+            payout: coin(5, "eth"),
+        };
+        let contract_addr = app
+            .instantiate_contract(
+                code_id,
+                owner.clone(),
+                &msg,
+                &coins(23, "eth"),
+                "Payout",
+                None,
+            )
+            .unwrap();
+
+        let contract_data = app.contract_data(&contract_addr).unwrap();
+        assert_eq!(
+            contract_data,
+            ContractData {
+                code_id: code_id as usize,
+                creator: owner.clone(),
+                admin: None,
+                label: "Payout".to_owned(),
+                created: app.block_info().height
+            }
+        );
+
+        // sender funds deducted
+        let sender = get_balance(&app, &owner);
+        assert_eq!(sender, vec![coin(20, "btc"), coin(77, "eth")]);
+        // get contract address, has funds
+        let funds = get_balance(&app, &contract_addr);
+        assert_eq!(funds, coins(23, "eth"));
+
+        // create empty account
+        let random = Addr::unchecked("random");
+        let funds = get_balance(&app, &random);
+        assert_eq!(funds, vec![]);
+
+        // do one payout and see money coming in
+        let res = app
+            .execute_contract(random.clone(), contract_addr.clone(), &EmptyMsg {}, &[])
+            .unwrap();
+        assert_eq!(3, res.events.len());
+
+        // the call to payout does emit this as well as custom attributes
+        let payout_exec = &res.events[0];
+        assert_eq!(payout_exec.ty.as_str(), "execute");
+        assert_eq!(
+            payout_exec.attributes,
+            [("_contract_address", &contract_addr)]
+        );
+
+        // next is a custom wasm event
+        let custom_attrs = res.custom_attrs(1);
+        assert_eq!(custom_attrs, [("action", "payout")]);
+
+        // then the transfer event
+        let expected_transfer = Event::new("transfer")
+            .add_attribute("recipient", "random")
+            .add_attribute("sender", &contract_addr)
+            .add_attribute("amount", "5eth");
+        assert_eq!(&expected_transfer, &res.events[2]);
+
+        // random got cash
+        let funds = get_balance(&app, &random);
+        assert_eq!(funds, coins(5, "eth"));
+        // contract lost it
+        let funds = get_balance(&app, &contract_addr);
+        assert_eq!(funds, coins(18, "eth"));
+    }
+
+    #[test]
+    fn reflect_success() {
+        // set personal balance
+        let owner = Addr::unchecked("owner");
+        let init_funds = vec![coin(20, "btc"), coin(100, "eth")];
+
+        let mut app = custom_app::<CustomMsg, Empty, _>(|router, _, storage| {
+            router
+                .bank
+                .init_balance(storage, &owner, init_funds)
+                .unwrap();
+        });
+
+        // set up payout contract
+        let payout_id = app.store_code(payout::contract());
+        let msg = payout::InstantiateMessage {
+            payout: coin(5, "eth"),
+        };
+        let payout_addr = app
+            .instantiate_contract(
+                payout_id,
+                owner.clone(),
+                &msg,
+                &coins(23, "eth"),
+                "Payout",
+                None,
+            )
+            .unwrap();
+
+        // set up reflect contract
+        let reflect_id = app.store_code(reflect::contract());
+        let reflect_addr = app
+            .instantiate_contract(reflect_id, owner, &EmptyMsg {}, &[], "Reflect", None)
+            .unwrap();
+
+        // reflect account is empty
+        let funds = get_balance(&app, &reflect_addr);
+        assert_eq!(funds, vec![]);
+        // reflect count is 1
+        let qres: payout::CountResponse = app
+            .wrap()
+            .query_wasm_smart(&reflect_addr, &reflect::QueryMsg::Count {})
+            .unwrap();
+        assert_eq!(0, qres.count);
+
+        // reflecting payout message pays reflect contract
+        let msg = SubMsg::new(WasmMsg::Execute {
+            contract_addr: payout_addr.clone().into(),
+            msg: b"{}".into(),
+            funds: vec![],
+        });
+        let msgs = reflect::Message {
+            messages: vec![msg],
+        };
+        let res = app
+            .execute_contract(Addr::unchecked("random"), reflect_addr.clone(), &msgs, &[])
+            .unwrap();
+
+        // ensure the attributes were relayed from the sub-message
+        assert_eq!(4, res.events.len(), "{:?}", res.events);
+
+        // reflect only returns standard wasm-execute event
+        let ref_exec = &res.events[0];
+        assert_eq!(ref_exec.ty.as_str(), "execute");
+        assert_eq!(ref_exec.attributes, [("_contract_address", &reflect_addr)]);
+
+        // the call to payout does emit this as well as custom attributes
+        let payout_exec = &res.events[1];
+        assert_eq!(payout_exec.ty.as_str(), "execute");
+        assert_eq!(
+            payout_exec.attributes,
+            [("_contract_address", &payout_addr)]
+        );
+
+        let payout = &res.events[2];
+        assert_eq!(payout.ty.as_str(), "wasm");
+        assert_eq!(
+            payout.attributes,
+            [
+                ("_contract_address", payout_addr.as_str()),
+                ("action", "payout")
+            ]
+        );
+
+        // final event is the transfer from bank
+        let second = &res.events[3];
+        assert_eq!(second.ty.as_str(), "transfer");
+        assert_eq!(3, second.attributes.len());
+        assert_eq!(second.attributes[0], ("recipient", &reflect_addr));
+        assert_eq!(second.attributes[1], ("sender", &payout_addr));
+        assert_eq!(second.attributes[2], ("amount", "5eth"));
+
+        // ensure transfer was executed with reflect as sender
+        let funds = get_balance(&app, &reflect_addr);
+        assert_eq!(funds, coins(5, "eth"));
+
+        // reflect count updated
+        let qres: payout::CountResponse = app
+            .wrap()
+            .query_wasm_smart(&reflect_addr, &reflect::QueryMsg::Count {})
+            .unwrap();
+        assert_eq!(1, qres.count);
+    }
+
+    #[test]
+    fn reflect_error() {
+        // set personal balance
+        let owner = Addr::unchecked("owner");
+        let init_funds = vec![coin(20, "btc"), coin(100, "eth")];
+
+        let mut app = custom_app::<CustomMsg, Empty, _>(|router, _, storage| {
+            router
+                .bank
+                .init_balance(storage, &owner, init_funds)
+                .unwrap();
+        });
+
+        // set up reflect contract
+        let reflect_id = app.store_code(reflect::contract());
+        let reflect_addr = app
+            .instantiate_contract(
+                reflect_id,
+                owner,
+                &EmptyMsg {},
+                &coins(40, "eth"),
+                "Reflect",
+                None,
+            )
+            .unwrap();
+
+        // reflect has 40 eth
+        let funds = get_balance(&app, &reflect_addr);
+        assert_eq!(funds, coins(40, "eth"));
+        let random = Addr::unchecked("random");
+
+        // sending 7 eth works
+        let msg = SubMsg::new(BankMsg::Send {
+            to_address: random.clone().into(),
+            amount: coins(7, "eth"),
+        });
+        let msgs = reflect::Message {
+            messages: vec![msg],
+        };
+        let res = app
+            .execute_contract(random.clone(), reflect_addr.clone(), &msgs, &[])
+            .unwrap();
+        // no wasm events as no attributes
+        assert_eq!(2, res.events.len());
+        // standard wasm-execute event
+        let exec = &res.events[0];
+        assert_eq!(exec.ty.as_str(), "execute");
+        assert_eq!(exec.attributes, [("_contract_address", &reflect_addr)]);
+        // only transfer event from bank
+        let transfer = &res.events[1];
+        assert_eq!(transfer.ty.as_str(), "transfer");
+
+        // ensure random got paid
+        let funds = get_balance(&app, &random);
+        assert_eq!(funds, coins(7, "eth"));
+
+        // reflect count should be updated to 1
+        let qres: payout::CountResponse = app
+            .wrap()
+            .query_wasm_smart(&reflect_addr, &reflect::QueryMsg::Count {})
+            .unwrap();
+        assert_eq!(1, qres.count);
+
+        // sending 8 eth, then 3 btc should fail both
+        let msg = SubMsg::new(BankMsg::Send {
+            to_address: random.clone().into(),
+            amount: coins(8, "eth"),
+        });
+        let msg2 = SubMsg::new(BankMsg::Send {
+            to_address: random.clone().into(),
+            amount: coins(3, "btc"),
+        });
+        let msgs = reflect::Message {
+            messages: vec![msg, msg2],
+        };
+        let err = app
+            .execute_contract(random.clone(), reflect_addr.clone(), &msgs, &[])
+            .unwrap_err();
+        assert_eq!(
+            StdError::overflow(OverflowError::new(OverflowOperation::Sub, 0, 3)),
+            err.downcast().unwrap()
+        );
+
+        // first one should have been rolled-back on error (no second payment)
+        let funds = get_balance(&app, &random);
+        assert_eq!(funds, coins(7, "eth"));
+
+        // failure should not update reflect count
+        let qres: payout::CountResponse = app
+            .wrap()
+            .query_wasm_smart(&reflect_addr, &reflect::QueryMsg::Count {})
+            .unwrap();
+        assert_eq!(1, qres.count);
+    }
+
+    #[test]
+    fn sudo_works() {
+        let owner = Addr::unchecked("owner");
+        let init_funds = vec![coin(100, "eth")];
+
+        let mut app = App::new(|router, _, storage| {
+            router
+                .bank
+                .init_balance(storage, &owner, init_funds)
+                .unwrap();
+        });
+
+        let payout_id = app.store_code(payout::contract());
+        let msg = payout::InstantiateMessage {
+            payout: coin(5, "eth"),
+        };
+        let payout_addr = app
+            .instantiate_contract(payout_id, owner, &msg, &coins(23, "eth"), "Payout", None)
+            .unwrap();
+
+        // count is 1
+        let payout::CountResponse { count } = app
+            .wrap()
+            .query_wasm_smart(&payout_addr, &payout::QueryMsg::Count {})
+            .unwrap();
+        assert_eq!(1, count);
+
+        // wasm_sudo call
+        let msg = payout::SudoMsg { set_count: 25 };
+        app.wasm_sudo(payout_addr.clone(), &msg).unwrap();
+
+        // count is 25
+        let payout::CountResponse { count } = app
+            .wrap()
+            .query_wasm_smart(&payout_addr, &payout::QueryMsg::Count {})
+            .unwrap();
+        assert_eq!(25, count);
+
+        // we can do the same with sudo call
+        let msg = payout::SudoMsg { set_count: 49 };
+        let sudo_msg = WasmSudo {
+            contract_addr: payout_addr.clone(),
+            msg: to_binary(&msg).unwrap(),
+        };
+        app.sudo(sudo_msg.into()).unwrap();
+
+        let payout::CountResponse { count } = app
+            .wrap()
+            .query_wasm_smart(&payout_addr, &payout::QueryMsg::Count {})
+            .unwrap();
+        assert_eq!(49, count);
+    }
+
+    // this demonstrates that we can mint tokens and send from other accounts via a custom module,
+    // as an example of ability to do privileged actions
+    mod custom_handler {
+        use super::*;
+
+        use anyhow::{bail, Result as AnyResult};
+        use cw_storage_plus::Item;
+        use serde::{Deserialize, Serialize};
+
+        use crate::Executor;
+
+        const LOTTERY: Item<Coin> = Item::new("lottery");
+        const PITY: Item<Coin> = Item::new("pity");
+
+        #[derive(Clone, std::fmt::Debug, PartialEq, JsonSchema, Serialize, Deserialize)]
+        struct CustomMsg {
+            // we mint LOTTERY tokens to this one
+            lucky_winner: String,
+            // we transfer PITY from lucky_winner to runner_up
+            runner_up: String,
+        }
+
+        struct CustomHandler {}
+
+        impl Module for CustomHandler {
+            type ExecT = CustomMsg;
+            type QueryT = Empty;
+            type SudoT = Empty;
+
+            fn execute<ExecC, QueryC>(
+                &self,
+                api: &dyn Api,
+                storage: &mut dyn Storage,
+                router: &dyn CosmosRouter<ExecC = ExecC, QueryC = QueryC>,
+                block: &BlockInfo,
+                _sender: Addr,
+                msg: Self::ExecT,
+            ) -> AnyResult<AppResponse>
+            where
+                ExecC:
+                    std::fmt::Debug + Clone + PartialEq + JsonSchema + DeserializeOwned + 'static,
+                QueryC: CustomQuery + DeserializeOwned + 'static,
+            {
+                let lottery = LOTTERY.load(storage)?;
+                let pity = PITY.load(storage)?;
+
+                // mint new tokens
+                let mint = BankSudo::Mint {
+                    to_address: msg.lucky_winner.clone(),
+                    amount: vec![lottery],
+                };
+                router.sudo(api, storage, block, mint.into())?;
+
+                // send from an arbitrary account (not the module)
+                let transfer = BankMsg::Send {
+                    to_address: msg.runner_up,
+                    amount: vec![pity],
+                };
+                let rcpt = api.addr_validate(&msg.lucky_winner)?;
+                router.execute(api, storage, block, rcpt, transfer.into())?;
+
+                Ok(AppResponse::default())
+            }
+
+            fn sudo<ExecC, QueryC>(
+                &self,
+                _api: &dyn Api,
+                _storage: &mut dyn Storage,
+                _router: &dyn CosmosRouter<ExecC = ExecC, QueryC = QueryC>,
+                _block: &BlockInfo,
+                _msg: Self::SudoT,
+            ) -> AnyResult<AppResponse>
+            where
+                ExecC:
+                    std::fmt::Debug + Clone + PartialEq + JsonSchema + DeserializeOwned + 'static,
+                QueryC: CustomQuery + DeserializeOwned + 'static,
+            {
+                bail!("sudo not implemented for CustomHandler")
+            }
+
+            fn query(
+                &self,
+                _api: &dyn Api,
+                _storage: &dyn Storage,
+                _querier: &dyn Querier,
+                _block: &BlockInfo,
+                _request: Self::QueryT,
+            ) -> AnyResult<Binary> {
+                bail!("query not implemented for CustomHandler")
+            }
+        }
+
+        impl CustomHandler {
+            // this is a custom initialization method
+            pub fn set_payout(
+                &self,
+                storage: &mut dyn Storage,
+                lottery: Coin,
+                pity: Coin,
+            ) -> AnyResult<()> {
+                LOTTERY.save(storage, &lottery)?;
+                PITY.save(storage, &pity)?;
+                Ok(())
+            }
+        }
+
+        // let's call this custom handler
+        #[test]
+        fn dispatches_messages() {
+            let winner = "winner".to_string();
+            let second = "second".to_string();
+
+            // payments. note 54321 - 12321 = 42000
+            let denom = "tix";
+            let lottery = coin(54321, denom);
+            let bonus = coin(12321, denom);
+
+            let mut app = BasicAppBuilder::<CustomMsg, Empty>::new_custom()
+                .with_custom(CustomHandler {})
+                .build(|router, _, storage| {
+                    router
+                        .custom
+                        .set_payout(storage, lottery.clone(), bonus.clone())
+                        .unwrap();
+                });
+
+            // query that balances are empty
+            let start = app.wrap().query_balance(&winner, denom).unwrap();
+            assert_eq!(start, coin(0, denom));
+
+            // trigger the custom module
+            let msg = CosmosMsg::Custom(CustomMsg {
+                lucky_winner: winner.clone(),
+                runner_up: second.clone(),
+            });
+            app.execute(Addr::unchecked("anyone"), msg).unwrap();
+
+            // see if coins were properly added
+            let big_win = app.wrap().query_balance(&winner, denom).unwrap();
+            assert_eq!(big_win, coin(42000, denom));
+            let little_win = app.wrap().query_balance(&second, denom).unwrap();
+            assert_eq!(little_win, bonus);
+        }
+    }
+
+    #[test]
+    fn reflect_submessage_reply_works() {
+        // set personal balance
+        let owner = Addr::unchecked("owner");
+        let random = Addr::unchecked("random");
+        let init_funds = vec![coin(20, "btc"), coin(100, "eth")];
+
+        let mut app = custom_app::<CustomMsg, Empty, _>(|router, _, storage| {
+            router
+                .bank
+                .init_balance(storage, &owner, init_funds)
+                .unwrap();
+        });
+
+        // set up reflect contract
+        let reflect_id = app.store_code(reflect::contract());
+        let reflect_addr = app
+            .instantiate_contract(
+                reflect_id,
+                owner,
+                &EmptyMsg {},
+                &coins(40, "eth"),
+                "Reflect",
+                None,
+            )
+            .unwrap();
+
+        // no reply writen beforehand
+        let query = reflect::QueryMsg::Reply { id: 123 };
+        let res: StdResult<Reply> = app.wrap().query_wasm_smart(&reflect_addr, &query);
+        res.unwrap_err();
+
+        // reflect sends 7 eth, success
+        let msg = SubMsg::reply_always(
+            BankMsg::Send {
+                to_address: random.clone().into(),
+                amount: coins(7, "eth"),
+            },
+            123,
+        );
+        let msgs = reflect::Message {
+            messages: vec![msg],
+        };
+        let res = app
+            .execute_contract(random.clone(), reflect_addr.clone(), &msgs, &[])
+            .unwrap();
+
+        // expected events: execute, transfer, reply, custom wasm (set in reply)
+        assert_eq!(4, res.events.len(), "{:?}", res.events);
+        res.assert_event(&Event::new("execute").add_attribute("_contract_address", &reflect_addr));
+        res.assert_event(&Event::new("transfer").add_attribute("amount", "7eth"));
+        res.assert_event(
+            &Event::new("reply")
+                .add_attribute("_contract_address", reflect_addr.as_str())
+                .add_attribute("mode", "handle_success"),
+        );
+        res.assert_event(&Event::new("wasm-custom").add_attribute("from", "reply"));
+
+        // ensure success was written
+        let res: Reply = app.wrap().query_wasm_smart(&reflect_addr, &query).unwrap();
+        assert_eq!(res.id, 123);
+        // validate the events written in the reply blob...should just be bank transfer
+        let reply = res.result.unwrap();
+        assert_eq!(1, reply.events.len());
+        AppResponse::from(reply)
+            .assert_event(&Event::new("transfer").add_attribute("amount", "7eth"));
+
+        // reflect sends 300 btc, failure, but error caught by submessage (so shows success)
+        let msg = SubMsg::reply_always(
+            BankMsg::Send {
+                to_address: random.clone().into(),
+                amount: coins(300, "btc"),
+            },
+            456,
+        );
+        let msgs = reflect::Message {
+            messages: vec![msg],
+        };
+        let _res = app
+            .execute_contract(random, reflect_addr.clone(), &msgs, &[])
+            .unwrap();
+
+        // ensure error was written
+        let query = reflect::QueryMsg::Reply { id: 456 };
+        let res: Reply = app.wrap().query_wasm_smart(&reflect_addr, &query).unwrap();
+        assert_eq!(res.id, 456);
+        assert!(res.result.is_err());
+        // TODO: check error?
+    }
 
     fn query_router<BankT, CustomT, WasmT, StakingT, DistrT, IbcT, GovT>(
         router: &Router<BankT, CustomT, WasmT, StakingT, DistrT, IbcT, GovT>,
@@ -1163,7 +1769,7 @@ mod tests {
         rcpt: &Addr,
     ) -> Vec<Coin>
     where
-        CustomT::ExecT: Clone + Debug + PartialEq + JsonSchema,
+        CustomT::ExecT: Clone + fmt::Debug + PartialEq + JsonSchema,
         CustomT::QueryT: CustomQuery + DeserializeOwned,
         WasmT: Wasm<CustomT::ExecT, CustomT::QueryT>,
         BankT: Bank,
@@ -1189,7 +1795,8 @@ mod tests {
         rcpt: &Addr,
     ) -> Vec<Coin>
     where
-        CustomT::ExecT: Debug + PartialEq + Clone + JsonSchema + DeserializeOwned + 'static,
+        CustomT::ExecT:
+            std::fmt::Debug + PartialEq + Clone + JsonSchema + DeserializeOwned + 'static,
         CustomT::QueryT: CustomQuery + DeserializeOwned + 'static,
         WasmT: Wasm<CustomT::ExecT, CustomT::QueryT>,
         BankT: Bank,
@@ -1207,17 +1814,6 @@ mod tests {
         val.amount
     }
 
-    #[test]
-    fn update_block() {
-        let mut app = App::default();
-
-        let BlockInfo { time, height, .. } = app.block;
-        app.update_block(next_block);
-
-        assert_eq!(time.plus_seconds(5), app.block.time);
-        assert_eq!(height + 1, app.block.height);
-    }
-
     #[test]
     fn multi_level_bank_cache() {
         // set personal balance
@@ -1273,4 +1869,1099 @@ mod tests {
         let committed = query_app(&app, &rcpt);
         assert_eq!(coins(37, "eth"), committed);
     }
+
+    #[test]
+    fn sent_funds_properly_visible_on_execution() {
+        // Testing if funds on contract are properly visible on contract.
+        // Hackatom contract is initialized with 10btc. Then, the contract is executed, with
+        // additional 20btc. Then beneficiary balance is checked - expeced value is 30btc. 10btc
+        // would mean that sending tokens with message is not visible for this very message, and
+        // 20btc means, that only such just send funds are visible.
+        let owner = Addr::unchecked("owner");
+        let beneficiary = Addr::unchecked("beneficiary");
+        let init_funds = coins(30, "btc");
+
+        let mut app = App::new(|router, _, storage| {
+            router
+                .bank
+                .init_balance(storage, &owner, init_funds)
+                .unwrap();
+        });
+
+        let contract_id = app.store_code(hackatom::contract());
+        let contract = app
+            .instantiate_contract(
+                contract_id,
+                owner.clone(),
+                &hackatom::InstantiateMsg {
+                    beneficiary: beneficiary.as_str().to_owned(),
+                },
+                &coins(10, "btc"),
+                "Hackatom",
+                None,
+            )
+            .unwrap();
+
+        app.execute_contract(
+            owner.clone(),
+            contract.clone(),
+            &EmptyMsg {},
+            &coins(20, "btc"),
+        )
+        .unwrap();
+
+        // Check balance of all accounts to ensure no tokens where burned or created, and they are
+        // in correct places
+        assert_eq!(get_balance(&app, &owner), &[]);
+        assert_eq!(get_balance(&app, &contract), &[]);
+        assert_eq!(get_balance(&app, &beneficiary), coins(30, "btc"));
+    }
+
+    #[test]
+    fn sent_wasm_migration_works() {
+        // The plan:
+        // create a hackatom contract with some funds
+        // check admin set properly
+        // check beneficiary set properly
+        // migrate fails if not admin
+        // migrate succeeds if admin
+        // check beneficiary updated
+        let owner = Addr::unchecked("owner");
+        let beneficiary = Addr::unchecked("beneficiary");
+        let init_funds = coins(30, "btc");
+
+        let mut app = App::new(|router, _, storage| {
+            router
+                .bank
+                .init_balance(storage, &owner, init_funds)
+                .unwrap();
+        });
+
+        // create a hackatom contract with some funds
+        let contract_id = app.store_code(hackatom::contract());
+        let contract = app
+            .instantiate_contract(
+                contract_id,
+                owner.clone(),
+                &hackatom::InstantiateMsg {
+                    beneficiary: beneficiary.as_str().to_owned(),
+                },
+                &coins(20, "btc"),
+                "Hackatom",
+                Some(owner.to_string()),
+            )
+            .unwrap();
+
+        // check admin set properly
+        let info = app.contract_data(&contract).unwrap();
+        assert_eq!(info.admin, Some(owner.clone()));
+        // check beneficiary set properly
+        let state: hackatom::InstantiateMsg = app
+            .wrap()
+            .query_wasm_smart(&contract, &hackatom::QueryMsg::Beneficiary {})
+            .unwrap();
+        assert_eq!(state.beneficiary, beneficiary);
+
+        // migrate fails if not admin
+        let random = Addr::unchecked("random");
+        let migrate_msg = hackatom::MigrateMsg {
+            new_guy: random.to_string(),
+        };
+        app.migrate_contract(beneficiary, contract.clone(), &migrate_msg, contract_id)
+            .unwrap_err();
+
+        // migrate fails if unregistred code id
+        app.migrate_contract(
+            owner.clone(),
+            contract.clone(),
+            &migrate_msg,
+            contract_id + 7,
+        )
+        .unwrap_err();
+
+        // migrate succeeds when the stars align
+        app.migrate_contract(owner, contract.clone(), &migrate_msg, contract_id)
+            .unwrap();
+
+        // check beneficiary updated
+        let state: hackatom::InstantiateMsg = app
+            .wrap()
+            .query_wasm_smart(&contract, &hackatom::QueryMsg::Beneficiary {})
+            .unwrap();
+        assert_eq!(state.beneficiary, random);
+    }
+
+    #[test]
+    fn send_update_admin_works() {
+        // The plan:
+        // create a hackatom contract
+        // check admin set properly
+        // update admin succeeds if admin
+        // update admin fails if not (new) admin
+        // check admin set properly
+        let owner = Addr::unchecked("owner");
+        let owner2 = Addr::unchecked("owner2");
+        let beneficiary = Addr::unchecked("beneficiary");
+
+        let mut app = App::default();
+
+        // create a hackatom contract with some funds
+        let contract_id = app.store_code(hackatom::contract());
+        let contract = app
+            .instantiate_contract(
+                contract_id,
+                owner.clone(),
+                &hackatom::InstantiateMsg {
+                    beneficiary: beneficiary.as_str().to_owned(),
+                },
+                &[],
+                "Hackatom",
+                Some(owner.to_string()),
+            )
+            .unwrap();
+
+        // check admin set properly
+        let info = app.contract_data(&contract).unwrap();
+        assert_eq!(info.admin, Some(owner.clone()));
+
+        // transfer adminship to owner2
+        app.execute(
+            owner.clone(),
+            CosmosMsg::Wasm(WasmMsg::UpdateAdmin {
+                contract_addr: contract.to_string(),
+                admin: owner2.to_string(),
+            }),
+        )
+        .unwrap();
+
+        // check admin set properly
+        let info = app.contract_data(&contract).unwrap();
+        assert_eq!(info.admin, Some(owner2.clone()));
+
+        // update admin fails if not owner2
+        app.execute(
+            owner.clone(),
+            CosmosMsg::Wasm(WasmMsg::UpdateAdmin {
+                contract_addr: contract.to_string(),
+                admin: owner.to_string(),
+            }),
+        )
+        .unwrap_err();
+
+        // check admin still the same
+        let info = app.contract_data(&contract).unwrap();
+        assert_eq!(info.admin, Some(owner2));
+    }
+
+    mod reply_data_overwrite {
+        use super::*;
+
+        use echo::EXECUTE_REPLY_BASE_ID;
+
+        fn make_echo_submsg(
+            contract: Addr,
+            data: impl Into<Option<&'static str>>,
+            sub_msg: Vec<SubMsg>,
+            id: u64,
+        ) -> SubMsg {
+            let data = data.into().map(|s| s.to_owned());
+            SubMsg::reply_always(
+                CosmosMsg::Wasm(WasmMsg::Execute {
+                    contract_addr: contract.into(),
+                    msg: to_binary(&echo::Message {
+                        data,
+                        sub_msg,
+                        ..echo::Message::default()
+                    })
+                    .unwrap(),
+                    funds: vec![],
+                }),
+                id,
+            )
+        }
+
+        fn make_echo_submsg_no_reply(
+            contract: Addr,
+            data: impl Into<Option<&'static str>>,
+            sub_msg: Vec<SubMsg>,
+        ) -> SubMsg {
+            let data = data.into().map(|s| s.to_owned());
+            SubMsg::new(CosmosMsg::Wasm(WasmMsg::Execute {
+                contract_addr: contract.into(),
+                msg: to_binary(&echo::Message {
+                    data,
+                    sub_msg,
+                    ..echo::Message::default()
+                })
+                .unwrap(),
+                funds: vec![],
+            }))
+        }
+
+        #[test]
+        fn no_submsg() {
+            let mut app = App::default();
+
+            let owner = Addr::unchecked("owner");
+
+            let contract_id = app.store_code(echo::contract());
+            let contract = app
+                .instantiate_contract(contract_id, owner.clone(), &EmptyMsg {}, &[], "Echo", None)
+                .unwrap();
+
+            let response = app
+                .execute_contract(
+                    owner,
+                    contract,
+                    &echo::Message::<Empty> {
+                        data: Some("Data".to_owned()),
+                        ..echo::Message::default()
+                    },
+                    &[],
+                )
+                .unwrap();
+
+            assert_eq!(response.data, Some(b"Data".into()));
+        }
+
+        #[test]
+        fn single_submsg() {
+            let mut app = App::default();
+
+            let owner = Addr::unchecked("owner");
+
+            let contract_id = app.store_code(echo::contract());
+            let contract = app
+                .instantiate_contract(contract_id, owner.clone(), &EmptyMsg {}, &[], "Echo", None)
+                .unwrap();
+
+            let response = app
+                .execute_contract(
+                    owner,
+                    contract.clone(),
+                    &echo::Message {
+                        data: Some("First".to_owned()),
+                        sub_msg: vec![make_echo_submsg(
+                            contract,
+                            "Second",
+                            vec![],
+                            EXECUTE_REPLY_BASE_ID,
+                        )],
+                        ..echo::Message::default()
+                    },
+                    &[],
+                )
+                .unwrap();
+
+            assert_eq!(response.data, Some(b"Second".into()));
+        }
+
+        #[test]
+        fn single_submsg_no_reply() {
+            let mut app = App::default();
+
+            let owner = Addr::unchecked("owner");
+
+            let contract_id = app.store_code(echo::contract());
+            let contract = app
+                .instantiate_contract(contract_id, owner.clone(), &EmptyMsg {}, &[], "Echo", None)
+                .unwrap();
+
+            let response = app
+                .execute_contract(
+                    owner,
+                    contract.clone(),
+                    &echo::Message {
+                        data: Some("First".to_owned()),
+                        sub_msg: vec![make_echo_submsg_no_reply(contract, "Second", vec![])],
+                        ..echo::Message::default()
+                    },
+                    &[],
+                )
+                .unwrap();
+
+            assert_eq!(response.data, Some(b"First".into()));
+        }
+
+        #[test]
+        fn single_no_submsg_data() {
+            let mut app = App::default();
+
+            let owner = Addr::unchecked("owner");
+
+            let contract_id = app.store_code(echo::contract());
+            let contract = app
+                .instantiate_contract(contract_id, owner.clone(), &EmptyMsg {}, &[], "Echo", None)
+                .unwrap();
+
+            let response = app
+                .execute_contract(
+                    owner,
+                    contract.clone(),
+                    &echo::Message {
+                        data: Some("First".to_owned()),
+                        sub_msg: vec![make_echo_submsg(contract, None, vec![], 1)],
+                        ..echo::Message::default()
+                    },
+                    &[],
+                )
+                .unwrap();
+
+            assert_eq!(response.data, Some(b"First".into()));
+        }
+
+        #[test]
+        fn single_no_top_level_data() {
+            let mut app = App::default();
+
+            let owner = Addr::unchecked("owner");
+
+            let contract_id = app.store_code(echo::contract());
+            let contract = app
+                .instantiate_contract(contract_id, owner.clone(), &EmptyMsg {}, &[], "Echo", None)
+                .unwrap();
+
+            let response = app
+                .execute_contract(
+                    owner,
+                    contract.clone(),
+                    &echo::Message {
+                        sub_msg: vec![make_echo_submsg(
+                            contract,
+                            "Second",
+                            vec![],
+                            EXECUTE_REPLY_BASE_ID,
+                        )],
+                        ..echo::Message::default()
+                    },
+                    &[],
+                )
+                .unwrap();
+
+            assert_eq!(response.data, Some(b"Second".into()));
+        }
+
+        #[test]
+        fn single_submsg_reply_returns_none() {
+            // set personal balance
+            let owner = Addr::unchecked("owner");
+            let init_funds = coins(100, "tgd");
+
+            let mut app = custom_app::<CustomMsg, Empty, _>(|router, _, storage| {
+                router
+                    .bank
+                    .init_balance(storage, &owner, init_funds)
+                    .unwrap();
+            });
+
+            // set up reflect contract
+            let reflect_id = app.store_code(reflect::contract());
+            let reflect_addr = app
+                .instantiate_contract(
+                    reflect_id,
+                    owner.clone(),
+                    &EmptyMsg {},
+                    &[],
+                    "Reflect",
+                    None,
+                )
+                .unwrap();
+
+            // set up echo contract
+            let echo_id = app.store_code(echo::custom_contract());
+            let echo_addr = app
+                .instantiate_contract(echo_id, owner.clone(), &EmptyMsg {}, &[], "Echo", None)
+                .unwrap();
+
+            // reflect will call echo
+            // echo will set the data
+            // top-level app will not display the data
+            let echo_msg = echo::Message::<Empty> {
+                data: Some("my echo".into()),
+                events: vec![Event::new("echo").add_attribute("called", "true")],
+                ..echo::Message::default()
+            };
+            let reflect_msg = reflect::Message {
+                messages: vec![SubMsg::new(WasmMsg::Execute {
+                    contract_addr: echo_addr.to_string(),
+                    msg: to_binary(&echo_msg).unwrap(),
+                    funds: vec![],
+                })],
+            };
+
+            let res = app
+                .execute_contract(owner, reflect_addr.clone(), &reflect_msg, &[])
+                .unwrap();
+
+            // ensure data is empty
+            assert_eq!(res.data, None);
+            // ensure expected events
+            assert_eq!(res.events.len(), 3, "{:?}", res.events);
+            res.assert_event(
+                &Event::new("execute").add_attribute("_contract_address", &reflect_addr),
+            );
+            res.assert_event(&Event::new("execute").add_attribute("_contract_address", &echo_addr));
+            res.assert_event(&Event::new("wasm-echo"));
+        }
+
+        #[test]
+        fn multiple_submsg() {
+            let mut app = App::default();
+
+            let owner = Addr::unchecked("owner");
+
+            let contract_id = app.store_code(echo::contract());
+            let contract = app
+                .instantiate_contract(contract_id, owner.clone(), &EmptyMsg {}, &[], "Echo", None)
+                .unwrap();
+
+            let response = app
+                .execute_contract(
+                    owner,
+                    contract.clone(),
+                    &echo::Message {
+                        data: Some("Orig".to_owned()),
+                        sub_msg: vec![
+                            make_echo_submsg(
+                                contract.clone(),
+                                None,
+                                vec![],
+                                EXECUTE_REPLY_BASE_ID + 1,
+                            ),
+                            make_echo_submsg(
+                                contract.clone(),
+                                "First",
+                                vec![],
+                                EXECUTE_REPLY_BASE_ID + 2,
+                            ),
+                            make_echo_submsg(
+                                contract.clone(),
+                                "Second",
+                                vec![],
+                                EXECUTE_REPLY_BASE_ID + 3,
+                            ),
+                            make_echo_submsg(contract, None, vec![], EXECUTE_REPLY_BASE_ID + 4),
+                        ],
+                        ..echo::Message::default()
+                    },
+                    &[],
+                )
+                .unwrap();
+
+            assert_eq!(response.data, Some(b"Second".into()));
+        }
+
+        #[test]
+        fn multiple_submsg_no_reply() {
+            let mut app = App::default();
+
+            let owner = Addr::unchecked("owner");
+
+            let contract_id = app.store_code(echo::contract());
+            let contract = app
+                .instantiate_contract(contract_id, owner.clone(), &EmptyMsg {}, &[], "Echo", None)
+                .unwrap();
+
+            let response = app
+                .execute_contract(
+                    owner,
+                    contract.clone(),
+                    &echo::Message {
+                        data: Some("Orig".to_owned()),
+                        sub_msg: vec![
+                            make_echo_submsg_no_reply(contract.clone(), None, vec![]),
+                            make_echo_submsg_no_reply(contract.clone(), "First", vec![]),
+                            make_echo_submsg_no_reply(contract.clone(), "Second", vec![]),
+                            make_echo_submsg_no_reply(contract, None, vec![]),
+                        ],
+                        ..echo::Message::default()
+                    },
+                    &[],
+                )
+                .unwrap();
+
+            assert_eq!(response.data, Some(b"Orig".into()));
+        }
+
+        #[test]
+        fn multiple_submsg_mixed() {
+            let mut app = App::default();
+
+            let owner = Addr::unchecked("owner");
+
+            let contract_id = app.store_code(echo::contract());
+            let contract = app
+                .instantiate_contract(contract_id, owner.clone(), &EmptyMsg {}, &[], "Echo", None)
+                .unwrap();
+
+            let response = app
+                .execute_contract(
+                    owner,
+                    contract.clone(),
+                    &echo::Message {
+                        sub_msg: vec![
+                            make_echo_submsg(
+                                contract.clone(),
+                                None,
+                                vec![],
+                                EXECUTE_REPLY_BASE_ID + 1,
+                            ),
+                            make_echo_submsg_no_reply(contract.clone(), "Hidden", vec![]),
+                            make_echo_submsg(
+                                contract.clone(),
+                                "Shown",
+                                vec![],
+                                EXECUTE_REPLY_BASE_ID + 2,
+                            ),
+                            make_echo_submsg(
+                                contract.clone(),
+                                None,
+                                vec![],
+                                EXECUTE_REPLY_BASE_ID + 3,
+                            ),
+                            make_echo_submsg_no_reply(contract, "Lost", vec![]),
+                        ],
+                        ..echo::Message::default()
+                    },
+                    &[],
+                )
+                .unwrap();
+
+            assert_eq!(response.data, Some(b"Shown".into()));
+        }
+
+        #[test]
+        fn nested_submsg() {
+            let mut app = App::default();
+
+            let owner = Addr::unchecked("owner");
+
+            let contract_id = app.store_code(echo::contract());
+            let contract = app
+                .instantiate_contract(contract_id, owner.clone(), &EmptyMsg {}, &[], "Echo", None)
+                .unwrap();
+
+            let response = app
+                .execute_contract(
+                    owner,
+                    contract.clone(),
+                    &echo::Message {
+                        data: Some("Orig".to_owned()),
+                        sub_msg: vec![make_echo_submsg(
+                            contract.clone(),
+                            None,
+                            vec![make_echo_submsg(
+                                contract.clone(),
+                                "First",
+                                vec![make_echo_submsg(
+                                    contract.clone(),
+                                    "Second",
+                                    vec![make_echo_submsg(
+                                        contract,
+                                        None,
+                                        vec![],
+                                        EXECUTE_REPLY_BASE_ID + 4,
+                                    )],
+                                    EXECUTE_REPLY_BASE_ID + 3,
+                                )],
+                                EXECUTE_REPLY_BASE_ID + 2,
+                            )],
+                            EXECUTE_REPLY_BASE_ID + 1,
+                        )],
+                        ..echo::Message::default()
+                    },
+                    &[],
+                )
+                .unwrap();
+
+            assert_eq!(response.data, Some(b"Second".into()));
+        }
+    }
+
+    mod response_validation {
+        use super::*;
+
+        #[test]
+        fn empty_attribute_key() {
+            let mut app = App::default();
+
+            let owner = Addr::unchecked("owner");
+
+            let contract_id = app.store_code(echo::contract());
+            let contract = app
+                .instantiate_contract(contract_id, owner.clone(), &EmptyMsg {}, &[], "Echo", None)
+                .unwrap();
+
+            let err = app
+                .execute_contract(
+                    owner,
+                    contract,
+                    &echo::Message::<Empty> {
+                        data: None,
+                        attributes: vec![
+                            Attribute::new("   ", "value"),
+                            Attribute::new("proper", "proper_val"),
+                        ],
+                        ..echo::Message::default()
+                    },
+                    &[],
+                )
+                .unwrap_err();
+
+            assert_eq!(Error::empty_attribute_key("value"), err.downcast().unwrap(),);
+        }
+
+        #[test]
+        fn empty_attribute_value() {
+            let mut app = App::default();
+
+            let owner = Addr::unchecked("owner");
+
+            let contract_id = app.store_code(echo::contract());
+            let contract = app
+                .instantiate_contract(contract_id, owner.clone(), &EmptyMsg {}, &[], "Echo", None)
+                .unwrap();
+
+            let err = app
+                .execute_contract(
+                    owner,
+                    contract,
+                    &echo::Message::<Empty> {
+                        data: None,
+                        attributes: vec![
+                            Attribute::new("key", "   "),
+                            Attribute::new("proper", "proper_val"),
+                        ],
+                        ..echo::Message::default()
+                    },
+                    &[],
+                )
+                .unwrap_err();
+
+            assert_eq!(Error::empty_attribute_value("key"), err.downcast().unwrap());
+        }
+
+        #[test]
+        fn empty_event_attribute_key() {
+            let mut app = App::default();
+
+            let owner = Addr::unchecked("owner");
+
+            let contract_id = app.store_code(echo::contract());
+            let contract = app
+                .instantiate_contract(contract_id, owner.clone(), &EmptyMsg {}, &[], "Echo", None)
+                .unwrap();
+
+            let err = app
+                .execute_contract(
+                    owner,
+                    contract,
+                    &echo::Message::<Empty> {
+                        data: None,
+                        events: vec![Event::new("event")
+                            .add_attribute("   ", "value")
+                            .add_attribute("proper", "proper_val")],
+                        ..echo::Message::default()
+                    },
+                    &[],
+                )
+                .unwrap_err();
+
+            assert_eq!(Error::empty_attribute_key("value"), err.downcast().unwrap());
+        }
+
+        #[test]
+        fn empty_event_attribute_value() {
+            let mut app = App::default();
+
+            let owner = Addr::unchecked("owner");
+
+            let contract_id = app.store_code(echo::contract());
+            let contract = app
+                .instantiate_contract(contract_id, owner.clone(), &EmptyMsg {}, &[], "Echo", None)
+                .unwrap();
+
+            let err = app
+                .execute_contract(
+                    owner,
+                    contract,
+                    &echo::Message::<Empty> {
+                        data: None,
+                        events: vec![Event::new("event")
+                            .add_attribute("key", "   ")
+                            .add_attribute("proper", "proper_val")],
+                        ..echo::Message::default()
+                    },
+                    &[],
+                )
+                .unwrap_err();
+
+            assert_eq!(Error::empty_attribute_value("key"), err.downcast().unwrap());
+        }
+
+        #[test]
+        fn too_short_event_type() {
+            let mut app = App::default();
+
+            let owner = Addr::unchecked("owner");
+
+            let contract_id = app.store_code(echo::contract());
+            let contract = app
+                .instantiate_contract(contract_id, owner.clone(), &EmptyMsg {}, &[], "Echo", None)
+                .unwrap();
+
+            let err = app
+                .execute_contract(
+                    owner,
+                    contract,
+                    &echo::Message::<Empty> {
+                        data: None,
+                        events: vec![Event::new(" e "), Event::new("event")],
+                        ..echo::Message::default()
+                    },
+                    &[],
+                )
+                .unwrap_err();
+
+            assert_eq!(Error::event_type_too_short("e"), err.downcast().unwrap());
+        }
+    }
+
+    mod custom_messages {
+        use super::*;
+        use crate::custom_handler::CachingCustomHandler;
+
+        #[test]
+        fn triggering_custom_msg() {
+            let api = MockApi::default();
+            let sender = api.addr_validate("sender").unwrap();
+            let owner = api.addr_validate("owner").unwrap();
+
+            let custom_handler = CachingCustomHandler::<CustomMsg, Empty>::new();
+            let custom_handler_state = custom_handler.state();
+
+            let mut app = AppBuilder::new_custom()
+                .with_api(api)
+                .with_custom(custom_handler)
+                .build(no_init);
+
+            let contract_id = app.store_code(echo::custom_contract());
+            let contract = app
+                .instantiate_contract(contract_id, owner, &EmptyMsg {}, &[], "Echo", None)
+                .unwrap();
+
+            app.execute_contract(
+                sender,
+                contract,
+                &echo::Message {
+                    sub_msg: vec![SubMsg::new(CosmosMsg::Custom(CustomMsg::SetAge {
+                        age: 20,
+                    }))],
+                    ..Default::default()
+                },
+                &[],
+            )
+            .unwrap();
+
+            assert_eq!(
+                custom_handler_state.execs().to_owned(),
+                vec![CustomMsg::SetAge { age: 20 }]
+            );
+
+            assert!(custom_handler_state.queries().is_empty());
+        }
+    }
+
+    mod protobuf_wrapped_data {
+        use super::*;
+        use crate::test_helpers::contracts::echo::EXECUTE_REPLY_BASE_ID;
+        use cw_utils::parse_instantiate_response_data;
+
+        #[test]
+        fn instantiate_wrapped_properly() {
+            // set personal balance
+            let owner = Addr::unchecked("owner");
+            let init_funds = vec![coin(20, "btc")];
+
+            let mut app = custom_app::<CustomMsg, Empty, _>(|router, _, storage| {
+                router
+                    .bank
+                    .init_balance(storage, &owner, init_funds)
+                    .unwrap();
+            });
+
+            // set up reflect contract
+            let code_id = app.store_code(reflect::contract());
+            let init_msg = to_binary(&EmptyMsg {}).unwrap();
+            let msg = WasmMsg::Instantiate {
+                admin: None,
+                code_id,
+                msg: init_msg,
+                funds: vec![],
+                label: "label".into(),
+            };
+            let res = app.execute(owner, msg.into()).unwrap();
+
+            // assert we have a proper instantiate result
+            let parsed = parse_instantiate_response_data(res.data.unwrap().as_slice()).unwrap();
+            assert!(parsed.data.is_none());
+            // check the address is right
+
+            let count: payout::CountResponse = app
+                .wrap()
+                .query_wasm_smart(&parsed.contract_address, &reflect::QueryMsg::Count {})
+                .unwrap();
+            assert_eq!(count.count, 0);
+        }
+
+        #[test]
+        fn instantiate_with_data_works() {
+            let owner = Addr::unchecked("owner");
+            let mut app = BasicApp::new(|_, _, _| {});
+
+            // set up echo contract
+            let code_id = app.store_code(echo::contract());
+            let msg = echo::InitMessage::<Empty> {
+                data: Some("food".into()),
+                sub_msg: None,
+            };
+            let init_msg = to_binary(&msg).unwrap();
+            let msg = WasmMsg::Instantiate {
+                admin: None,
+                code_id,
+                msg: init_msg,
+                funds: vec![],
+                label: "label".into(),
+            };
+            let res = app.execute(owner, msg.into()).unwrap();
+
+            // assert we have a proper instantiate result
+            let parsed = parse_instantiate_response_data(res.data.unwrap().as_slice()).unwrap();
+            assert!(parsed.data.is_some());
+            assert_eq!(parsed.data.unwrap(), Binary::from(b"food"));
+            assert!(!parsed.contract_address.is_empty());
+        }
+
+        #[test]
+        fn instantiate_with_reply_works() {
+            let owner = Addr::unchecked("owner");
+            let mut app = BasicApp::new(|_, _, _| {});
+
+            // set up echo contract
+            let code_id = app.store_code(echo::contract());
+            let msg = echo::InitMessage::<Empty> {
+                data: Some("food".into()),
+                ..Default::default()
+            };
+            let addr1 = app
+                .instantiate_contract(code_id, owner.clone(), &msg, &[], "first", None)
+                .unwrap();
+
+            // another echo contract
+            let msg = echo::Message::<Empty> {
+                data: Some("Passed to contract instantiation, returned as reply, and then returned as response".into()),
+                ..Default::default()
+            };
+            let sub_msg = SubMsg::reply_on_success(
+                WasmMsg::Execute {
+                    contract_addr: addr1.to_string(),
+                    msg: to_binary(&msg).unwrap(),
+                    funds: vec![],
+                },
+                EXECUTE_REPLY_BASE_ID,
+            );
+            let init_msg = echo::InitMessage::<Empty> {
+                data: Some("Overwrite me".into()),
+                sub_msg: Some(vec![sub_msg]),
+            };
+            let init_msg = to_binary(&init_msg).unwrap();
+            let msg = WasmMsg::Instantiate {
+                admin: None,
+                code_id,
+                msg: init_msg,
+                funds: vec![],
+                label: "label".into(),
+            };
+            let res = app.execute(owner, msg.into()).unwrap();
+
+            // assert we have a proper instantiate result
+            let parsed = parse_instantiate_response_data(res.data.unwrap().as_slice()).unwrap();
+            assert!(parsed.data.is_some());
+            // Result is from the reply, not the original one
+            assert_eq!(parsed.data.unwrap(), Binary::from(b"Passed to contract instantiation, returned as reply, and then returned as response"));
+            assert!(!parsed.contract_address.is_empty());
+            assert_ne!(parsed.contract_address, addr1.to_string());
+        }
+
+        #[test]
+        fn execute_wrapped_properly() {
+            let owner = Addr::unchecked("owner");
+            let mut app = BasicApp::new(|_, _, _| {});
+
+            // set up reflect contract
+            let code_id = app.store_code(echo::contract());
+            let echo_addr = app
+                .instantiate_contract(code_id, owner.clone(), &EmptyMsg {}, &[], "label", None)
+                .unwrap();
+
+            // ensure the execute has the same wrapper as it should
+            let msg = echo::Message::<Empty> {
+                data: Some("hello".into()),
+                ..echo::Message::default()
+            };
+            // execute_contract now decodes a protobuf wrapper, so we get the top-level response
+            let exec_res = app.execute_contract(owner, echo_addr, &msg, &[]).unwrap();
+            assert_eq!(exec_res.data, Some(Binary::from(b"hello")));
+        }
+    }
+
+    mod errors {
+        use super::*;
+
+        #[test]
+        fn simple_instantiation() {
+            let owner = Addr::unchecked("owner");
+            let mut app = App::default();
+
+            // set up contract
+            let code_id = app.store_code(error::contract(false));
+            let msg = EmptyMsg {};
+            let err = app
+                .instantiate_contract(code_id, owner, &msg, &[], "error", None)
+                .unwrap_err();
+
+            // we should be able to retrieve the original error by downcasting
+            let source: &StdError = err.downcast_ref().unwrap();
+            if let StdError::GenericErr { msg } = source {
+                assert_eq!(msg, "Init failed");
+            } else {
+                panic!("wrong StdError variant");
+            }
+
+            // We're expecting exactly 2 nested error types
+            // (the original error, WasmMsg context)
+            assert_eq!(err.chain().count(), 2);
+        }
+
+        #[test]
+        fn simple_call() {
+            let owner = Addr::unchecked("owner");
+            let mut app = App::default();
+
+            // set up contract
+            let code_id = app.store_code(error::contract(true));
+            let msg = EmptyMsg {};
+            let contract_addr = app
+                .instantiate_contract(code_id, owner, &msg, &[], "error", None)
+                .unwrap();
+
+            // execute should error
+            let err = app
+                .execute_contract(Addr::unchecked("random"), contract_addr, &msg, &[])
+                .unwrap_err();
+
+            // we should be able to retrieve the original error by downcasting
+            let source: &StdError = err.downcast_ref().unwrap();
+            if let StdError::GenericErr { msg } = source {
+                assert_eq!(msg, "Handle failed");
+            } else {
+                panic!("wrong StdError variant");
+            }
+
+            // We're expecting exactly 2 nested error types
+            // (the original error, WasmMsg context)
+            assert_eq!(err.chain().count(), 2);
+        }
+
+        #[test]
+        fn nested_call() {
+            let owner = Addr::unchecked("owner");
+            let mut app = App::default();
+
+            let error_code_id = app.store_code(error::contract(true));
+            let caller_code_id = app.store_code(caller::contract());
+
+            // set up contracts
+            let msg = EmptyMsg {};
+            let caller_addr = app
+                .instantiate_contract(caller_code_id, owner.clone(), &msg, &[], "caller", None)
+                .unwrap();
+            let error_addr = app
+                .instantiate_contract(error_code_id, owner, &msg, &[], "error", None)
+                .unwrap();
+
+            // execute should error
+            let msg = WasmMsg::Execute {
+                contract_addr: error_addr.into(),
+                msg: to_binary(&EmptyMsg {}).unwrap(),
+                funds: vec![],
+            };
+            let err = app
+                .execute_contract(Addr::unchecked("random"), caller_addr, &msg, &[])
+                .unwrap_err();
+
+            // we can downcast to get the original error
+            let source: &StdError = err.downcast_ref().unwrap();
+            if let StdError::GenericErr { msg } = source {
+                assert_eq!(msg, "Handle failed");
+            } else {
+                panic!("wrong StdError variant");
+            }
+
+            // We're expecting exactly 3 nested error types
+            // (the original error, 2 WasmMsg contexts)
+            assert_eq!(err.chain().count(), 3);
+        }
+
+        #[test]
+        fn double_nested_call() {
+            let owner = Addr::unchecked("owner");
+            let mut app = App::default();
+
+            let error_code_id = app.store_code(error::contract(true));
+            let caller_code_id = app.store_code(caller::contract());
+
+            // set up contracts
+            let msg = EmptyMsg {};
+            let caller_addr1 = app
+                .instantiate_contract(caller_code_id, owner.clone(), &msg, &[], "caller", None)
+                .unwrap();
+            let caller_addr2 = app
+                .instantiate_contract(caller_code_id, owner.clone(), &msg, &[], "caller", None)
+                .unwrap();
+            let error_addr = app
+                .instantiate_contract(error_code_id, owner, &msg, &[], "error", None)
+                .unwrap();
+
+            // caller1 calls caller2, caller2 calls error
+            let msg = WasmMsg::Execute {
+                contract_addr: caller_addr2.into(),
+                msg: to_binary(&WasmMsg::Execute {
+                    contract_addr: error_addr.into(),
+                    msg: to_binary(&EmptyMsg {}).unwrap(),
+                    funds: vec![],
+                })
+                .unwrap(),
+                funds: vec![],
+            };
+            let err = app
+                .execute_contract(Addr::unchecked("random"), caller_addr1, &msg, &[])
+                .unwrap_err();
+
+            // uncomment to have the test fail and see how the error stringifies
+            // panic!("{:?}", err);
+
+            // we can downcast to get the original error
+            let source: &StdError = err.downcast_ref().unwrap();
+            if let StdError::GenericErr { msg } = source {
+                assert_eq!(msg, "Handle failed");
+            } else {
+                panic!("wrong StdError variant");
+            }
+
+            // We're expecting exactly 4 nested error types
+            // (the original error, 3 WasmMsg contexts)
+            assert_eq!(err.chain().count(), 4);
+        }
+    }
 }
diff --git a/src/contracts.rs b/src/contracts.rs
index e362328..b38cdc1 100644
--- a/src/contracts.rs
+++ b/src/contracts.rs
@@ -11,7 +11,7 @@ use cosmwasm_std::{
 
 use anyhow::{anyhow, bail, Result as AnyResult};
 
-/// Interface to call into a `Contract`.
+/// Interface to call into a Contract
 pub trait Contract<T, Q = Empty>
 where
     T: Clone + fmt::Debug + PartialEq + JsonSchema,
@@ -119,8 +119,8 @@ where
         }
     }
 
-    /// This will take a contract that returns `Response<Empty>` and will "upgrade" it
-    /// to `Response<C>` if needed to be compatible with a chain-specific extension.
+    /// this will take a contract that returns Response<Empty> and will "upgrade" it
+    /// to Response<C> if needed to be compatible with a chain-specific extension
     pub fn new_with_empty(
         execute_fn: ContractFn<T1, Empty, E1, Empty>,
         instantiate_fn: ContractFn<T2, Empty, E2, Empty>,
diff --git a/src/error.rs b/src/error.rs
index 626b792..f0bd092 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -9,7 +9,7 @@ pub enum Error {
     #[error("Empty attribute value. Key: {key}")]
     EmptyAttributeValue { key: String },
 
-    #[error("Attribute key starts with reserved prefix _: {0}")]
+    #[error("Attribute key strats with reserved prefix _: {0}")]
     ReservedAttributeKey(String),
 
     #[error("Event type too short: {0}")]
@@ -21,11 +21,8 @@ pub enum Error {
     #[error("Unsupported wasm message: {0:?}")]
     UnsupportedWasmMsg(WasmMsg),
 
-    #[error("code id: invalid")]
-    InvalidCodeId,
-
-    #[error("code id {0}: no such code")]
-    UnregisteredCodeId(u64),
+    #[error("Unregistered code id")]
+    UnregisteredCodeId(usize),
 }
 
 impl Error {
diff --git a/src/gov.rs b/src/gov.rs
index 0569cb4..cce65de 100644
--- a/src/gov.rs
+++ b/src/gov.rs
@@ -5,3 +5,115 @@ use crate::{FailingModule, Module};
 pub trait Gov: Module<ExecT = GovMsg, QueryT = Empty, SudoT = Empty> {}
 
 impl Gov for FailingModule<GovMsg, Empty, Empty> {}
+
+#[cfg(test)]
+mod test {
+    use cosmwasm_std::{Addr, Binary, Empty, GovMsg};
+
+    use crate::test_helpers::contracts::stargate::{contract, ExecMsg};
+    use crate::{App, AppBuilder, AppResponse, Executor, Module};
+
+    use super::Gov;
+
+    struct AcceptingModule;
+
+    impl Module for AcceptingModule {
+        type ExecT = GovMsg;
+        type QueryT = Empty;
+        type SudoT = Empty;
+
+        fn execute<ExecC, QueryC>(
+            &self,
+            _api: &dyn cosmwasm_std::Api,
+            _storage: &mut dyn cosmwasm_std::Storage,
+            _router: &dyn crate::CosmosRouter<ExecC = ExecC, QueryC = QueryC>,
+            _block: &cosmwasm_std::BlockInfo,
+            _sender: cosmwasm_std::Addr,
+            _msg: Self::ExecT,
+        ) -> anyhow::Result<crate::AppResponse>
+        where
+            ExecC: std::fmt::Debug
+                + Clone
+                + PartialEq
+                + schemars::JsonSchema
+                + serde::de::DeserializeOwned
+                + 'static,
+            QueryC: cosmwasm_std::CustomQuery + serde::de::DeserializeOwned + 'static,
+        {
+            Ok(AppResponse::default())
+        }
+
+        fn sudo<ExecC, QueryC>(
+            &self,
+            _api: &dyn cosmwasm_std::Api,
+            _storage: &mut dyn cosmwasm_std::Storage,
+            _router: &dyn crate::CosmosRouter<ExecC = ExecC, QueryC = QueryC>,
+            _block: &cosmwasm_std::BlockInfo,
+            _msg: Self::SudoT,
+        ) -> anyhow::Result<crate::AppResponse>
+        where
+            ExecC: std::fmt::Debug
+                + Clone
+                + PartialEq
+                + schemars::JsonSchema
+                + serde::de::DeserializeOwned
+                + 'static,
+            QueryC: cosmwasm_std::CustomQuery + serde::de::DeserializeOwned + 'static,
+        {
+            Ok(AppResponse::default())
+        }
+
+        fn query(
+            &self,
+            _api: &dyn cosmwasm_std::Api,
+            _storage: &dyn cosmwasm_std::Storage,
+            _querier: &dyn cosmwasm_std::Querier,
+            _block: &cosmwasm_std::BlockInfo,
+            _request: Self::QueryT,
+        ) -> anyhow::Result<cosmwasm_std::Binary> {
+            Ok(Binary::default())
+        }
+    }
+
+    impl Gov for AcceptingModule {}
+
+    #[test]
+    fn default_gov() {
+        let mut app = App::default();
+        let code = app.store_code(contract());
+        let contract = app
+            .instantiate_contract(
+                code,
+                Addr::unchecked("owner"),
+                &Empty {},
+                &[],
+                "contract",
+                None,
+            )
+            .unwrap();
+
+        app.execute_contract(Addr::unchecked("owner"), contract, &ExecMsg::Gov {}, &[])
+            .unwrap_err();
+    }
+
+    #[test]
+    fn subsituting_gov() {
+        let mut app = AppBuilder::new()
+            .with_gov(AcceptingModule)
+            .build(|_, _, _| ());
+        let code = app.store_code(contract());
+        let contract = app
+            .instantiate_contract(
+                code,
+                Addr::unchecked("owner"),
+                &Empty {},
+                &[],
+                "contract",
+                None,
+            )
+            .unwrap();
+
+        app.execute_contract(Addr::unchecked("owner"), contract, &ExecMsg::Gov {}, &[])
+            .unwrap();
+    }
+}
diff --git a/src/ibc.rs b/src/ibc.rs
index c7bec27..ca74101 100644
--- a/src/ibc.rs
+++ b/src/ibc.rs
@@ -21,7 +21,7 @@ impl Module for IbcAcceptingModule {
         _block: &cosmwasm_std::BlockInfo,
         _sender: cosmwasm_std::Addr,
         _msg: Self::ExecT,
-    ) -> anyhow::Result<AppResponse>
+    ) -> anyhow::Result<crate::AppResponse>
     where
         ExecC: std::fmt::Debug
             + Clone
@@ -41,7 +41,7 @@ impl Module for IbcAcceptingModule {
         _router: &dyn crate::CosmosRouter<ExecC = ExecC, QueryC = QueryC>,
         _block: &cosmwasm_std::BlockInfo,
         _msg: Self::SudoT,
-    ) -> anyhow::Result<AppResponse>
+    ) -> anyhow::Result<crate::AppResponse>
     where
         ExecC: std::fmt::Debug
             + Clone
@@ -61,9 +61,59 @@ impl Module for IbcAcceptingModule {
         _querier: &dyn cosmwasm_std::Querier,
         _block: &cosmwasm_std::BlockInfo,
         _request: Self::QueryT,
-    ) -> anyhow::Result<Binary> {
+    ) -> anyhow::Result<cosmwasm_std::Binary> {
         Ok(Binary::default())
     }
 }
 
 impl Ibc for IbcAcceptingModule {}
+
+#[cfg(test)]
+mod test {
+    use cosmwasm_std::{Addr, Empty};
+
+    use crate::test_helpers::contracts::stargate::{contract, ExecMsg};
+    use crate::{App, AppBuilder, Executor};
+
+    use super::*;
+
+    #[test]
+    fn default_ibc() {
+        let mut app = App::default();
+        let code = app.store_code(contract());
+        let contract = app
+            .instantiate_contract(
+                code,
+                Addr::unchecked("owner"),
+                &Empty {},
+                &[],
+                "contract",
+                None,
+            )
+            .unwrap();
+
+        app.execute_contract(Addr::unchecked("owner"), contract, &ExecMsg::Ibc {}, &[])
+            .unwrap_err();
+    }
+
+    #[test]
+    fn subsituting_ibc() {
+        let mut app = AppBuilder::new()
+            .with_ibc(IbcAcceptingModule)
+            .build(|_, _, _| ());
+        let code = app.store_code(contract());
+        let contract = app
+            .instantiate_contract(
+                code,
+                Addr::unchecked("owner"),
+                &Empty {},
+                &[],
+                "contract",
+                None,
+            )
+            .unwrap();
+
+        app.execute_contract(Addr::unchecked("owner"), contract, &ExecMsg::Ibc {}, &[])
+            .unwrap();
+    }
+}
diff --git a/src/lib.rs b/src/lib.rs
index ab166c3..0292ef5 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -2,7 +2,7 @@
 //! This allows us to run unit tests that involve contract -> contract,
 //! and contract -> bank interactions. This is not intended to be a full blockchain app
 //! but to simulate the Cosmos SDK x/wasm module close enough to gain confidence in
-//! multi-contract deployments before testing them on a live blockchain.
+//! multi-contract deployements before testing them on a live blockchain.
 //!
 //! To understand the design of this module, please refer to `../DESIGN.md`
 
@@ -19,7 +19,6 @@ mod module;
 mod prefixed_storage;
 mod staking;
 mod test_helpers;
-mod tests;
 mod transactions;
 mod wasm;
 
@@ -36,4 +35,4 @@ pub use crate::module::{FailingModule, Module};
 pub use crate::staking::{
     Distribution, DistributionKeeper, StakeKeeper, Staking, StakingInfo, StakingSudo,
 };
-pub use crate::wasm::{AddressGenerator, ContractData, Wasm, WasmKeeper, WasmSudo};
+pub use crate::wasm::{AddressGenerator, Wasm, WasmKeeper, WasmSudo};
diff --git a/src/module.rs b/src/module.rs
index 08ea118..7125a3e 100644
--- a/src/module.rs
+++ b/src/module.rs
@@ -8,7 +8,6 @@ use crate::AppResponse;
 use schemars::JsonSchema;
 use serde::de::DeserializeOwned;
 
-/// Interface of the module.
 pub trait Module {
     type ExecT;
     type QueryT;
diff --git a/src/prefixed_storage/length_prefixed.rs b/src/prefixed_storage/length_prefixed.rs
index 18543f5..5d97b3b 100644
--- a/src/prefixed_storage/length_prefixed.rs
+++ b/src/prefixed_storage/length_prefixed.rs
@@ -1,15 +1,11 @@
-//! This module is an implementation of a namespacing scheme.
-//!
-//! Namespacing scheme is described in
-//! <https://github.com/webmaster128/key-namespacing#length-prefixed-keys>.
+//! This module is an implemention of a namespacing scheme described
+//! in https://github.com/webmaster128/key-namespacing#length-prefixed-keys
 //!
 //! Everything in this file is only responsible for building such keys
-//! and is not specific to any kind of storage.
+//! and is in no way specific to any kind of storage.
 
-/// Calculates the raw key prefix for a given namespace.
-///
-/// See <https://github.com/webmaster128/key-namespacing#length-prefixed-keys>
-/// for details.
+/// Calculates the raw key prefix for a given namespace as documented
+/// in https://github.com/webmaster128/key-namespacing#length-prefixed-keys
 pub fn to_length_prefixed(namespace: &[u8]) -> Vec<u8> {
     let mut out = Vec::with_capacity(namespace.len() + 2);
     out.extend_from_slice(&encode_length(namespace));
@@ -17,10 +13,8 @@ pub fn to_length_prefixed(namespace: &[u8]) -> Vec<u8> {
     out
 }
 
-/// Calculates the raw key prefix for a given nested namespace.
-///
-/// See <https://github.com/webmaster128/key-namespacing#nesting>
-/// for details.
+/// Calculates the raw key prefix for a given nested namespace
+/// as documented in https://github.com/webmaster128/key-namespacing#nesting
 pub fn to_length_prefixed_nested(namespaces: &[&[u8]]) -> Vec<u8> {
     let mut size = 0;
     for &namespace in namespaces {
diff --git a/src/transactions.rs b/src/transactions.rs
index 8cfcecd..7b9c5b5 100644
--- a/src/transactions.rs
+++ b/src/transactions.rs
@@ -15,7 +15,7 @@ use cosmwasm_std::{Order, Record};
 use anyhow::Result as AnyResult;
 
 #[cfg(feature = "iterator")]
-/// The BTreeMap specific key-value pair reference type, as returned by `BTreeMap<Vec<u8>, T>::range`.
+/// The BTreeMap specific key-value pair reference type, as returned by BTreeMap<Vec<u8>, T>::range.
 /// This is internal as it can change any time if the map implementation is swapped out.
 type BTreeMapPairRef<'a, T = Vec<u8>> = (&'a Vec<u8>, &'a T);
 
diff --git a/src/wasm.rs b/src/wasm.rs
index b4e3fee..2b9b6bb 100644
--- a/src/wasm.rs
+++ b/src/wasm.rs
@@ -1,26 +1,29 @@
-use crate::app::{CosmosRouter, RouterQuerier};
-use crate::contracts::Contract;
-use crate::error::Error;
-use crate::executor::AppResponse;
-use crate::prefixed_storage::{prefixed, prefixed_read, PrefixedStorage, ReadonlyPrefixedStorage};
-use crate::transactions::transactional;
-use anyhow::{bail, Context, Result as AnyResult};
-use cosmwasm_std::testing::mock_wasmd_attr;
+use std::collections::HashMap;
+use std::fmt;
+use std::ops::Deref;
+
 use cosmwasm_std::{
     to_binary, Addr, Api, Attribute, BankMsg, Binary, BlockInfo, Coin, ContractInfo,
     ContractInfoResponse, CustomQuery, Deps, DepsMut, Env, Event, MessageInfo, Order, Querier,
     QuerierWrapper, Record, Reply, ReplyOn, Response, StdResult, Storage, SubMsg, SubMsgResponse,
     SubMsgResult, TransactionInfo, WasmMsg, WasmQuery,
 };
-use cw_storage_plus::Map;
 use prost::Message;
 use schemars::JsonSchema;
 use serde::de::DeserializeOwned;
 use serde::{Deserialize, Serialize};
-#[cfg(feature = "cosmwasm_1_2")]
-use sha2::{Digest, Sha256};
-use std::borrow::Borrow;
-use std::fmt::Debug;
+
+use cw_storage_plus::Map;
+
+use crate::app::{CosmosRouter, RouterQuerier};
+use crate::contracts::Contract;
+use crate::error::Error;
+use crate::executor::AppResponse;
+use crate::prefixed_storage::{prefixed, prefixed_read, PrefixedStorage, ReadonlyPrefixedStorage};
+use crate::transactions::transactional;
+use cosmwasm_std::testing::mock_wasmd_attr;
+
+use anyhow::{bail, Context, Result as AnyResult};
 
 // Contract state is kept in Storage, separate from the contracts themselves
 const CONTRACTS: Map<&Addr, ContractData> = Map::new("contracts");
@@ -29,7 +32,7 @@ pub const NAMESPACE_WASM: &[u8] = b"wasm";
 /// See <https://github.com/chipshort/wasmd/blob/d0e3ed19f041e65f112d8e800416b3230d0005a2/x/wasm/types/events.go#L58>
 const CONTRACT_ATTR: &str = "_contract_address";
 
-#[derive(Clone, Debug, PartialEq, Eq, JsonSchema)]
+#[derive(Clone, std::fmt::Debug, PartialEq, Eq, JsonSchema)]
 pub struct WasmSudo {
     pub contract_addr: Addr,
     pub msg: Binary,
@@ -44,12 +47,12 @@ impl WasmSudo {
     }
 }
 
-/// Contract data includes information about contract,
-/// equivalent of `ContractInfo` in **wasmd** interface.
+/// Contract Data includes information about contract, equivalent of `ContractInfo` in wasmd
+/// interface.
 #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
 pub struct ContractData {
     /// Identifier of stored contract code
-    pub code_id: u64,
+    pub code_id: usize,
     /// Address of account who initially instantiated the contract
     pub creator: Addr,
     /// Optional address of account who can execute migrations
@@ -60,23 +63,8 @@ pub struct ContractData {
     pub created: u64,
 }
 
-/// Contract code base data.
-struct CodeData {
-    /// Address of an account that initially stored the contract code.
-    //FIXME Remove this feature flag when the default flag is `cosmwasm_1_2` or higher.
-    #[cfg_attr(feature = "cosmwasm_1_1", allow(dead_code))]
-    creator: Addr,
-    /// Seed used to generate a checksum for underlying code base.
-    //FIXME Remove this feature flag when the default flag is `cosmwasm_1_2` or higher.
-    #[cfg_attr(feature = "cosmwasm_1_1", allow(dead_code))]
-    seed: usize,
-    /// Identifier of the code base where the contract code is stored in memory.
-    code_base_id: usize,
-}
-
-/// Interface to call into a `Wasm` module.
 pub trait Wasm<ExecC, QueryC> {
-    /// Handles all `WasmQuery` requests.
+    /// Handles all WasmQuery requests
     fn query(
         &self,
         api: &dyn Api,
@@ -86,7 +74,7 @@ pub trait Wasm<ExecC, QueryC> {
         request: WasmQuery,
     ) -> AnyResult<Binary>;
 
-    /// Handles all `WasmMsg` messages.
+    /// Handles all WasmMsg messages
     fn execute(
         &self,
         api: &dyn Api,
@@ -97,7 +85,7 @@ pub trait Wasm<ExecC, QueryC> {
         msg: WasmMsg,
     ) -> AnyResult<AppResponse>;
 
-    /// Handles all sudo messages, this is an admin interface and can not be called via `CosmosMsg`.
+    /// Admin interface, cannot be called via CosmosMsg
     fn sudo(
         &self,
         api: &dyn Api,
@@ -107,26 +95,12 @@ pub trait Wasm<ExecC, QueryC> {
         block: &BlockInfo,
         msg: Binary,
     ) -> AnyResult<AppResponse>;
-
-    /// Stores the contract's code and returns an identifier of the stored contract's code.
-    fn store_code(&mut self, creator: Addr, code: Box<dyn Contract<ExecC, QueryC>>) -> u64;
-
-    /// Duplicates the contract's code with specified identifier
-    /// and returns an identifier of the copy of the contract's code.
-    fn duplicate_code(&mut self, code_id: u64) -> AnyResult<u64>;
-
-    /// Returns `ContractData` for the contract with specified address.
-    fn contract_data(&self, storage: &dyn Storage, address: &Addr) -> AnyResult<ContractData>;
-
-    /// Returns a raw state dump of all key-values held by a contract with specified address.
-    fn dump_wasm_raw(&self, storage: &dyn Storage, address: &Addr) -> Vec<Record>;
 }
 
 pub struct WasmKeeper<ExecC, QueryC> {
-    /// Contract codes that stand for wasm code in real-life blockchain.
-    code_base: Vec<Box<dyn Contract<ExecC, QueryC>>>,
-    /// Code data with code base identifier and additional attributes.  
-    code_data: Vec<CodeData>,
+    /// code is in-memory lookup that stands in for wasm code
+    /// this can only be edited on the WasmRouter, and just read in caches
+    codes: HashMap<usize, Box<dyn Contract<ExecC, QueryC>>>,
     /// Just markers to make type elision fork when using it as `Wasm` trait
     _p: std::marker::PhantomData<QueryC>,
     generator: Box<dyn AddressGenerator>,
@@ -136,6 +110,7 @@ pub trait AddressGenerator {
     fn next_address(&self, storage: &mut dyn Storage) -> Addr;
 }
 
+#[derive(Debug)]
 struct SimpleAddressGenerator();
 
 impl AddressGenerator for SimpleAddressGenerator {
@@ -153,11 +128,9 @@ impl AddressGenerator for SimpleAddressGenerator {
 }
 
 impl<ExecC, QueryC> Default for WasmKeeper<ExecC, QueryC> {
-    /// Returns the default value for [WasmKeeper].
     fn default() -> Self {
         Self {
-            code_base: Vec::default(),
-            code_data: Vec::default(),
+            codes: HashMap::default(),
             _p: std::marker::PhantomData,
             generator: Box::new(SimpleAddressGenerator()),
         }
@@ -166,7 +139,7 @@ impl<ExecC, QueryC> Default for WasmKeeper<ExecC, QueryC> {
 
 impl<ExecC, QueryC> Wasm<ExecC, QueryC> for WasmKeeper<ExecC, QueryC>
 where
-    ExecC: Clone + Debug + PartialEq + JsonSchema + DeserializeOwned + 'static,
+    ExecC: Clone + fmt::Debug + PartialEq + JsonSchema + DeserializeOwned + 'static,
     QueryC: CustomQuery + DeserializeOwned + 'static,
 {
     fn query(
@@ -188,25 +161,14 @@ where
             }
             WasmQuery::ContractInfo { contract_addr } => {
                 let addr = api.addr_validate(&contract_addr)?;
-                let contract = self.contract_data(storage, &addr)?;
+                let contract = self.load_contract(storage, &addr)?;
                 let mut res = ContractInfoResponse::default();
-                res.code_id = contract.code_id;
+                res.code_id = contract.code_id as u64;
                 res.creator = contract.creator.to_string();
                 res.admin = contract.admin.map(|x| x.into());
                 to_binary(&res).map_err(Into::into)
             }
-            #[cfg(feature = "cosmwasm_1_2")]
-            WasmQuery::CodeInfo { code_id } => {
-                let code_data = self.code_data(code_id)?;
-                let mut res = cosmwasm_std::CodeInfoResponse::default();
-                res.code_id = code_id;
-                res.creator = code_data.creator.to_string();
-                res.checksum = cosmwasm_std::HexBinary::from(
-                    Sha256::digest(format!("contract code {}", code_data.seed)).to_vec(),
-                );
-                to_binary(&res).map_err(Into::into)
-            }
-            other => bail!(Error::UnsupportedWasmQuery(other)),
+            query => bail!(Error::UnsupportedWasmQuery(query)),
         }
     }
 
@@ -221,7 +183,7 @@ where
     ) -> AnyResult<AppResponse> {
         self.execute_wasm(api, storage, router, block, sender.clone(), msg.clone())
             .context(format!(
-                "Error executing WasmMsg:\n  sender: {}\n  {:?}",
+                "error executing WasmMsg:\nsender: {}\n{:?}",
                 sender, msg
             ))
     }
@@ -241,64 +203,25 @@ where
         let (res, msgs) = self.build_app_response(&contract, custom_event, res);
         self.process_response(api, router, storage, block, contract, res, msgs)
     }
+}
 
-    /// Stores the contract's code in the in-memory lookup table.
-    /// Returns an identifier of the stored contract code.
-    fn store_code(&mut self, creator: Addr, code: Box<dyn Contract<ExecC, QueryC>>) -> u64 {
-        let code_base_id = self.code_base.len();
-        self.code_base.push(code);
-        let code_id = self.code_data.len() + 1;
-        self.code_data.push(CodeData {
-            creator,
-            seed: code_id,
-            code_base_id,
-        });
-        code_id as u64
-    }
-
-    /// Duplicates the contract's code with specified identifier.
-    /// Returns an identifier of the copy of the contract's code.
-    fn duplicate_code(&mut self, code_id: u64) -> AnyResult<u64> {
-        let code_data = self.code_data(code_id)?;
-        self.code_data.push(CodeData {
-            creator: code_data.creator.clone(),
-            seed: code_data.seed,
-            code_base_id: code_data.code_base_id,
-        });
-        Ok(code_id + 1)
+impl<ExecC, QueryC> WasmKeeper<ExecC, QueryC> {
+    pub fn store_code(&mut self, code: Box<dyn Contract<ExecC, QueryC>>) -> usize {
+        let idx = self.codes.len() + 1;
+        self.codes.insert(idx, code);
+        idx
     }
 
-    /// Returns `ContractData` for the contract with specified address.
-    fn contract_data(&self, storage: &dyn Storage, address: &Addr) -> AnyResult<ContractData> {
+    pub fn load_contract(&self, storage: &dyn Storage, address: &Addr) -> AnyResult<ContractData> {
         CONTRACTS
             .load(&prefixed_read(storage, NAMESPACE_WASM), address)
             .map_err(Into::into)
     }
 
-    /// Returns a raw state dump of all key-values held by a contract with specified address.
-    fn dump_wasm_raw(&self, storage: &dyn Storage, address: &Addr) -> Vec<Record> {
+    pub fn dump_wasm_raw(&self, storage: &dyn Storage, address: &Addr) -> Vec<Record> {
         let storage = self.contract_storage_readonly(storage, address);
         storage.range(None, None, Order::Ascending).collect()
     }
-}
-
-impl<ExecC, QueryC> WasmKeeper<ExecC, QueryC> {
-    /// Returns a handler to code of the contract with specified code id.
-    pub fn contract_code(&self, code_id: u64) -> AnyResult<&dyn Contract<ExecC, QueryC>> {
-        let code_data = self.code_data(code_id)?;
-        Ok(self.code_base[code_data.code_base_id].borrow())
-    }
-
-    /// Returns code data of the contract with specified code id.
-    fn code_data(&self, code_id: u64) -> AnyResult<&CodeData> {
-        if code_id < 1 {
-            bail!(Error::InvalidCodeId);
-        }
-        Ok(self
-            .code_data
-            .get((code_id - 1) as usize)
-            .ok_or(Error::UnregisteredCodeId(code_id))?)
-    }
 
     fn contract_namespace(&self, contract: &Addr) -> Vec<u8> {
         let mut name = b"contract_data/".to_vec();
@@ -354,7 +277,7 @@ impl<ExecC, QueryC> WasmKeeper<ExecC, QueryC> {
 
     fn verify_response<T>(response: Response<T>) -> AnyResult<Response<T>>
     where
-        T: Clone + Debug + PartialEq + JsonSchema,
+        T: Clone + fmt::Debug + PartialEq + JsonSchema,
     {
         Self::verify_attributes(&response.attributes)?;
 
@@ -372,7 +295,7 @@ impl<ExecC, QueryC> WasmKeeper<ExecC, QueryC> {
 
 impl<ExecC, QueryC> WasmKeeper<ExecC, QueryC>
 where
-    ExecC: Clone + Debug + PartialEq + JsonSchema + DeserializeOwned + 'static,
+    ExecC: Clone + fmt::Debug + PartialEq + JsonSchema + DeserializeOwned + 'static,
     QueryC: CustomQuery + DeserializeOwned + 'static,
 {
     pub fn new() -> Self {
@@ -380,9 +303,11 @@ where
     }
 
     pub fn new_with_custom_address_generator(generator: impl AddressGenerator + 'static) -> Self {
+        let default = Self::default();
         Self {
+            codes: default.codes,
+            _p: default._p,
             generator: Box::new(generator),
-            ..Default::default()
         }
     }
 
@@ -450,7 +375,7 @@ where
         let admin = new_admin.map(|a| api.addr_validate(&a)).transpose()?;
 
         // check admin status
-        let mut data = self.contract_data(storage, &contract_addr)?;
+        let mut data = self.load_contract(storage, &contract_addr)?;
         if data.admin != Some(sender) {
             bail!("Only admin can update the contract admin: {:?}", data.admin);
         }
@@ -520,30 +445,60 @@ where
                 msg,
                 funds,
                 label,
-            } => self.process_wasm_msg_instantiate(
-                api, storage, router, block, sender, admin, code_id, msg, funds, label, None,
-            ),
-            #[cfg(feature = "cosmwasm_1_2")]
-            WasmMsg::Instantiate2 {
-                admin,
-                code_id,
-                msg,
-                funds,
-                label,
-                salt,
-            } => self.process_wasm_msg_instantiate(
-                api,
-                storage,
-                router,
-                block,
-                sender,
-                admin,
-                code_id,
-                msg,
-                funds,
-                label,
-                Some(salt),
-            ),
+            } => {
+                if label.is_empty() {
+                    bail!("Label is required on all contracts");
+                }
+
+                let contract_addr = self.register_contract(
+                    storage,
+                    code_id as usize,
+                    sender.clone(),
+                    admin.map(Addr::unchecked),
+                    label,
+                    block.height,
+                )?;
+
+                // move the cash
+                self.send(
+                    api,
+                    storage,
+                    router,
+                    block,
+                    sender.clone(),
+                    contract_addr.clone().into(),
+                    &funds,
+                )?;
+
+                // then call the contract
+                let info = MessageInfo { sender, funds };
+                let res = self.call_instantiate(
+                    contract_addr.clone(),
+                    api,
+                    storage,
+                    router,
+                    block,
+                    info,
+                    msg.to_vec(),
+                )?;
+
+                let custom_event = Event::new("instantiate")
+                    .add_attribute(CONTRACT_ATTR, &contract_addr)
+                    .add_attribute("code_id", code_id.to_string());
+
+                let (res, msgs) = self.build_app_response(&contract_addr, custom_event, res);
+                let mut res = self.process_response(
+                    api,
+                    router,
+                    storage,
+                    block,
+                    contract_addr.clone(),
+                    res,
+                    msgs,
+                )?;
+                res.data = Some(instantiate_response(res.data, &contract_addr));
+                Ok(res)
+            }
             WasmMsg::Migrate {
                 contract_addr,
                 new_code_id,
@@ -552,10 +507,11 @@ where
                 let contract_addr = api.addr_validate(&contract_addr)?;
 
                 // check admin status and update the stored code_id
-                if new_code_id as usize > self.code_data.len() {
+                let new_code_id = new_code_id as usize;
+                if !self.codes.contains_key(&new_code_id) {
                     bail!("Cannot migrate contract to unregistered code id");
                 }
-                let mut data = self.contract_data(storage, &contract_addr)?;
+                let mut data = self.load_contract(storage, &contract_addr)?;
                 if data.admin != Some(sender) {
                     bail!("Only admin can migrate contract: {:?}", data.admin);
                 }
@@ -592,75 +548,6 @@ where
         }
     }
 
-    /// Processes WasmMsg::Instantiate and WasmMsg::Instantiate2 messages.
-    fn process_wasm_msg_instantiate(
-        &self,
-        api: &dyn Api,
-        storage: &mut dyn Storage,
-        router: &dyn CosmosRouter<ExecC = ExecC, QueryC = QueryC>,
-        block: &BlockInfo,
-        sender: Addr,
-        admin: Option<String>,
-        code_id: u64,
-        msg: Binary,
-        funds: Vec<Coin>,
-        label: String,
-        _salt: Option<Binary>,
-    ) -> AnyResult<AppResponse> {
-        if label.is_empty() {
-            bail!("Label is required on all contracts");
-        }
-
-        let contract_addr = self.register_contract(
-            storage,
-            code_id,
-            sender.clone(),
-            admin.map(Addr::unchecked),
-            label,
-            block.height,
-        )?;
-
-        // move the cash
-        self.send(
-            api,
-            storage,
-            router,
-            block,
-            sender.clone(),
-            contract_addr.clone().into(),
-            &funds,
-        )?;
-
-        // then call the contract
-        let info = MessageInfo { sender, funds };
-        let res = self.call_instantiate(
-            contract_addr.clone(),
-            api,
-            storage,
-            router,
-            block,
-            info,
-            msg.to_vec(),
-        )?;
-
-        let custom_event = Event::new("instantiate")
-            .add_attribute(CONTRACT_ATTR, &contract_addr)
-            .add_attribute("code_id", code_id.to_string());
-
-        let (res, msgs) = self.build_app_response(&contract_addr, custom_event, res);
-        let mut res = self.process_response(
-            api,
-            router,
-            storage,
-            block,
-            contract_addr.clone(),
-            res,
-            msgs,
-        )?;
-        res.data = Some(instantiate_response(res.data, &contract_addr));
-        Ok(res)
-    }
-
     /// This will execute the given messages, making all changes to the local cache.
     /// This *will* write some data to the cache if the message fails half-way through.
     /// All sequential calls to RouterCache will be one atomic unit (all commit or all fail).
@@ -669,7 +556,7 @@ where
     /// This is designed to be handled internally as part of larger process flows.
     ///
     /// The `data` on `AppResponse` is data returned from `reply` call, not from execution of
-    /// sub-message itself. In case if `reply` is not called, no `data` is set.
+    /// submessage itself. In case if `reply` is not called, no `data` is set.
     fn execute_submsg(
         &self,
         api: &dyn Api,
@@ -705,7 +592,7 @@ where
                 // append the events
                 r.events.extend_from_slice(&reply_res.events);
             } else {
-                // reply is not called, no data should be returned
+                // reply is not called, no data should be rerturned
                 r.data = None;
             }
 
@@ -714,7 +601,7 @@ where
             if matches!(reply_on, ReplyOn::Always | ReplyOn::Error) {
                 let reply = Reply {
                     id,
-                    result: SubMsgResult::Err(format!("{:?}", e)),
+                    result: SubMsgResult::Err(e.to_string()),
                 };
                 self._reply(api, router, storage, block, contract, reply)
             } else {
@@ -808,10 +695,10 @@ where
 
         // recurse in all messages
         let data = messages.into_iter().try_fold(data, |data, resend| {
-            let sub_res =
+            let subres =
                 self.execute_submsg(api, router, storage, block, contract.clone(), resend)?;
-            events.extend_from_slice(&sub_res.events);
-            Ok::<_, anyhow::Error>(sub_res.data.or(data))
+            events.extend_from_slice(&subres.events);
+            Ok::<_, anyhow::Error>(subres.data.or(data))
         })?;
 
         Ok(AppResponse { events, data })
@@ -823,13 +710,13 @@ where
     pub fn register_contract(
         &self,
         storage: &mut dyn Storage,
-        code_id: u64,
+        code_id: usize,
         creator: Addr,
         admin: impl Into<Option<Addr>>,
         label: String,
         created: u64,
     ) -> AnyResult<Addr> {
-        if code_id as usize > self.code_data.len() {
+        if !self.codes.contains_key(&code_id) {
             bail!("Cannot init contract with unregistered code id");
         }
 
@@ -963,16 +850,19 @@ where
         action: F,
     ) -> AnyResult<T>
     where
-        F: FnOnce(&dyn Contract<ExecC, QueryC>, Deps<QueryC>, Env) -> AnyResult<T>,
+        F: FnOnce(&Box<dyn Contract<ExecC, QueryC>>, Deps<QueryC>, Env) -> AnyResult<T>,
     {
-        let contract = self.contract_data(storage, &address)?;
-        let handler = self.contract_code(contract.code_id)?;
+        let contract = self.load_contract(storage, &address)?;
+        let handler = self
+            .codes
+            .get(&contract.code_id)
+            .ok_or(Error::UnregisteredCodeId(contract.code_id))?;
         let storage = self.contract_storage_readonly(storage, &address);
         let env = self.get_env(address, block);
 
         let deps = Deps {
             storage: storage.as_ref(),
-            api,
+            api: api.deref(),
             querier: QuerierWrapper::new(querier),
         };
         action(handler, deps, env)
@@ -988,11 +878,14 @@ where
         action: F,
     ) -> AnyResult<T>
     where
-        F: FnOnce(&dyn Contract<ExecC, QueryC>, DepsMut<QueryC>, Env) -> AnyResult<T>,
+        F: FnOnce(&Box<dyn Contract<ExecC, QueryC>>, DepsMut<QueryC>, Env) -> AnyResult<T>,
         ExecC: DeserializeOwned,
     {
-        let contract = self.contract_data(storage, &address)?;
-        let handler = self.contract_code(contract.code_id)?;
+        let contract = self.load_contract(storage, &address)?;
+        let handler = self
+            .codes
+            .get(&contract.code_id)
+            .ok_or(Error::UnregisteredCodeId(contract.code_id))?;
 
         // We don't actually need a transaction here, as it is already embedded in a transactional.
         // execute_submsg or App.execute_multi.
@@ -1005,7 +898,7 @@ where
 
             let deps = DepsMut {
                 storage: contract_storage.as_mut(),
-                api,
+                api: api.deref(),
                 querier: QuerierWrapper::new(&querier),
             };
             action(handler, deps, env)
@@ -1066,19 +959,22 @@ fn execute_response(data: Option<Binary>) -> Option<Binary> {
 
 #[cfg(test)]
 mod test {
-    use super::*;
-    use crate::app::Router;
-    use crate::bank::BankKeeper;
-    use crate::module::FailingModule;
-    use crate::staking::{DistributionKeeper, StakeKeeper};
-    use crate::test_helpers::{caller, error, payout};
-    use crate::transactions::StorageTransaction;
     use cosmwasm_std::testing::{mock_env, mock_info, MockApi, MockQuerier, MockStorage};
     use cosmwasm_std::{
         coin, from_slice, to_vec, BankMsg, Coin, CosmosMsg, Empty, GovMsg, IbcMsg, IbcQuery,
         StdError,
     };
 
+    use crate::app::Router;
+    use crate::bank::BankKeeper;
+    use crate::module::FailingModule;
+    use crate::staking::{DistributionKeeper, StakeKeeper};
+    use crate::test_helpers::contracts::{caller, error, payout};
+    use crate::test_helpers::EmptyMsg;
+    use crate::transactions::StorageTransaction;
+
+    use super::*;
+
     /// Type alias for default build `Router` to make its reference in typical scenario
     type BasicRouter<ExecC = Empty, QueryC = Empty> = Router<
         BankKeeper,
@@ -1090,10 +986,6 @@ mod test {
         FailingModule<GovMsg, Empty, Empty>,
     >;
 
-    fn wasm_keeper() -> WasmKeeper<Empty, Empty> {
-        WasmKeeper::new()
-    }
-
     fn mock_router() -> BasicRouter {
         Router {
             wasm: WasmKeeper::new(),
@@ -1110,13 +1002,13 @@ mod test {
     fn register_contract() {
         let api = MockApi::default();
         let mut wasm_storage = MockStorage::new();
-        let mut wasm_keeper = wasm_keeper();
+        let mut keeper = WasmKeeper::new();
         let block = mock_env().block;
-        let code_id = wasm_keeper.store_code(Addr::unchecked("creator"), error::contract(false));
+        let code_id = keeper.store_code(error::contract(false));
 
         transactional(&mut wasm_storage, |cache, _| {
             // cannot register contract with unregistered codeId
-            wasm_keeper.register_contract(
+            keeper.register_contract(
                 cache,
                 code_id + 1,
                 Addr::unchecked("foobar"),
@@ -1129,7 +1021,7 @@ mod test {
 
         let contract_addr = transactional(&mut wasm_storage, |cache, _| {
             // we can register a new instance of this code
-            wasm_keeper.register_contract(
+            keeper.register_contract(
                 cache,
                 code_id,
                 Addr::unchecked("foobar"),
@@ -1141,9 +1033,7 @@ mod test {
         .unwrap();
 
         // verify contract data are as expected
-        let contract_data = wasm_keeper
-            .contract_data(&wasm_storage, &contract_addr)
-            .unwrap();
+        let contract_data = keeper.load_contract(&wasm_storage, &contract_addr).unwrap();
 
         assert_eq!(
             contract_data,
@@ -1159,7 +1049,7 @@ mod test {
         let err = transactional(&mut wasm_storage, |cache, _| {
             // now, we call this contract and see the error message from the contract
             let info = mock_info("foobar", &[]);
-            wasm_keeper.call_instantiate(
+            keeper.call_instantiate(
                 contract_addr.clone(),
                 &api,
                 cache,
@@ -1180,7 +1070,7 @@ mod test {
         let err = transactional(&mut wasm_storage, |cache, _| {
             // and the error for calling an unregistered contract
             let info = mock_info("foobar", &[]);
-            wasm_keeper.call_instantiate(
+            keeper.call_instantiate(
                 Addr::unchecked("unregistered"),
                 &api,
                 cache,
@@ -1200,23 +1090,20 @@ mod test {
     }
 
     #[test]
-    fn query_contract_info() {
+    fn query_contract_into() {
         let api = MockApi::default();
-        let mut wasm_storage = MockStorage::new();
-        let mut wasm_keeper = wasm_keeper();
+        let mut keeper = WasmKeeper::<Empty, Empty>::new();
         let block = mock_env().block;
-        let code_id = wasm_keeper.store_code(Addr::unchecked("buzz"), payout::contract());
-        assert_eq!(1, code_id);
+        let code_id = keeper.store_code(payout::contract());
 
-        let creator = "foobar";
-        let admin = "admin";
+        let mut wasm_storage = MockStorage::new();
 
-        let contract_addr = wasm_keeper
+        let contract_addr = keeper
             .register_contract(
                 &mut wasm_storage,
                 code_id,
-                Addr::unchecked(creator),
-                Addr::unchecked(admin),
+                Addr::unchecked("foobar"),
+                Addr::unchecked("admin"),
                 "label".to_owned(),
                 1000,
             )
@@ -1224,97 +1111,29 @@ mod test {
 
         let querier: MockQuerier<Empty> = MockQuerier::new(&[]);
         let query = WasmQuery::ContractInfo {
-            contract_addr: contract_addr.into(),
+            contract_addr: contract_addr.to_string(),
         };
-
-        let contract_info = wasm_keeper
+        let info = keeper
             .query(&api, &wasm_storage, &querier, &block, query)
             .unwrap();
 
-        let actual: ContractInfoResponse = from_slice(&contract_info).unwrap();
         let mut expected = ContractInfoResponse::default();
-        expected.code_id = code_id;
-        expected.creator = creator.into();
-        expected.admin = Some(admin.into());
-        assert_eq!(expected, actual);
-    }
-
-    #[test]
-    #[cfg(feature = "cosmwasm_1_2")]
-    fn query_code_info() {
-        let api = MockApi::default();
-        let wasm_storage = MockStorage::new();
-        let mut wasm_keeper = wasm_keeper();
-        let block = mock_env().block;
-        let code_id = wasm_keeper.store_code(Addr::unchecked("creator"), payout::contract());
-        let querier: MockQuerier<Empty> = MockQuerier::new(&[]);
-        let query = WasmQuery::CodeInfo { code_id };
-        let code_info = wasm_keeper
-            .query(&api, &wasm_storage, &querier, &block, query)
-            .unwrap();
-        let actual: cosmwasm_std::CodeInfoResponse = from_slice(&code_info).unwrap();
-        assert_eq!(code_id, actual.code_id);
-        assert_eq!("creator", actual.creator);
-        assert!(!actual.checksum.is_empty());
-    }
-
-    #[test]
-    #[cfg(feature = "cosmwasm_1_2")]
-    fn different_contracts_must_have_different_checksum() {
-        let api = MockApi::default();
-        let wasm_storage = MockStorage::new();
-        let mut wasm_keeper = wasm_keeper();
-        let block = mock_env().block;
-        let code_id_payout = wasm_keeper.store_code(Addr::unchecked("creator"), payout::contract());
-        let code_id_caller = wasm_keeper.store_code(Addr::unchecked("creator"), caller::contract());
-        let querier: MockQuerier<Empty> = MockQuerier::new(&[]);
-        let query_payout = WasmQuery::CodeInfo {
-            code_id: code_id_payout,
-        };
-        let query_caller = WasmQuery::CodeInfo {
-            code_id: code_id_caller,
-        };
-        let code_info_payout = wasm_keeper
-            .query(&api, &wasm_storage, &querier, &block, query_payout)
-            .unwrap();
-        let code_info_caller = wasm_keeper
-            .query(&api, &wasm_storage, &querier, &block, query_caller)
-            .unwrap();
-        let info_payout: cosmwasm_std::CodeInfoResponse = from_slice(&code_info_payout).unwrap();
-        let info_caller: cosmwasm_std::CodeInfoResponse = from_slice(&code_info_caller).unwrap();
-        assert_eq!(code_id_payout, info_payout.code_id);
-        assert_eq!(code_id_caller, info_caller.code_id);
-        assert_ne!(info_caller.code_id, info_payout.code_id);
-        assert_eq!(info_caller.creator, info_payout.creator);
-        assert_ne!(info_caller.checksum, info_payout.checksum);
-    }
-
-    #[test]
-    #[cfg(feature = "cosmwasm_1_2")]
-    fn querying_invalid_code_info_must_fail() {
-        let api = MockApi::default();
-        let wasm_storage = MockStorage::new();
-        let wasm_keeper = wasm_keeper();
-        let block = mock_env().block;
-
-        let querier: MockQuerier<Empty> = MockQuerier::new(&[]);
-        let query = WasmQuery::CodeInfo { code_id: 100 };
-
-        wasm_keeper
-            .query(&api, &wasm_storage, &querier, &block, query)
-            .unwrap_err();
+        expected.code_id = code_id as u64;
+        expected.creator = "foobar".to_string();
+        expected.admin = Some("admin".to_owned());
+        assert_eq!(expected, from_slice(&info).unwrap());
     }
 
     #[test]
     fn can_dump_raw_wasm_state() {
         let api = MockApi::default();
-        let mut wasm_keeper = wasm_keeper();
+        let mut keeper = WasmKeeper::<Empty, Empty>::new();
         let block = mock_env().block;
-        let code_id = wasm_keeper.store_code(Addr::unchecked("buzz"), payout::contract());
+        let code_id = keeper.store_code(payout::contract());
 
         let mut wasm_storage = MockStorage::new();
 
-        let contract_addr = wasm_keeper
+        let contract_addr = keeper
             .register_contract(
                 &mut wasm_storage,
                 code_id,
@@ -1330,7 +1149,7 @@ mod test {
         let msg = payout::InstantiateMessage {
             payout: payout.clone(),
         };
-        wasm_keeper
+        keeper
             .call_instantiate(
                 contract_addr.clone(),
                 &api,
@@ -1343,7 +1162,7 @@ mod test {
             .unwrap();
 
         // dump state
-        let state = wasm_keeper.dump_wasm_raw(&wasm_storage, &contract_addr);
+        let state = keeper.dump_wasm_raw(&wasm_storage, &contract_addr);
         assert_eq!(state.len(), 2);
         // check contents
         let (k, v) = &state[0];
@@ -1359,14 +1178,14 @@ mod test {
     #[test]
     fn contract_send_coins() {
         let api = MockApi::default();
-        let mut wasm_keeper = wasm_keeper();
+        let mut keeper = WasmKeeper::new();
         let block = mock_env().block;
-        let code_id = wasm_keeper.store_code(Addr::unchecked("buzz"), payout::contract());
+        let code_id = keeper.store_code(payout::contract());
 
         let mut wasm_storage = MockStorage::new();
         let mut cache = StorageTransaction::new(&wasm_storage);
 
-        let contract_addr = wasm_keeper
+        let contract_addr = keeper
             .register_contract(
                 &mut cache,
                 code_id,
@@ -1385,7 +1204,7 @@ mod test {
             payout: payout.clone(),
         })
         .unwrap();
-        let res = wasm_keeper
+        let res = keeper
             .call_instantiate(
                 contract_addr.clone(),
                 &api,
@@ -1400,7 +1219,7 @@ mod test {
 
         // execute the contract
         let info = mock_info("foobar", &[]);
-        let res = wasm_keeper
+        let res = keeper
             .call_execute(
                 &api,
                 &mut cache,
@@ -1426,7 +1245,7 @@ mod test {
         // query the contract
         let query = to_vec(&payout::QueryMsg::Payout {}).unwrap();
         let querier: MockQuerier<Empty> = MockQuerier::new(&[]);
-        let data = wasm_keeper
+        let data = keeper
             .query_smart(contract_addr, &api, &wasm_storage, &querier, &block, query)
             .unwrap();
         let res: payout::InstantiateMessage = from_slice(&data).unwrap();
@@ -1470,9 +1289,9 @@ mod test {
     #[test]
     fn multi_level_wasm_cache() {
         let api = MockApi::default();
-        let mut wasm_keeper = wasm_keeper();
+        let mut keeper = WasmKeeper::new();
         let block = mock_env().block;
-        let code_id = wasm_keeper.store_code(Addr::unchecked("buzz"), payout::contract());
+        let code_id = keeper.store_code(payout::contract());
 
         let mut wasm_storage = MockStorage::new();
 
@@ -1480,7 +1299,7 @@ mod test {
 
         // set contract 1 and commit (on router)
         let contract1 = transactional(&mut wasm_storage, |cache, _| {
-            let contract = wasm_keeper
+            let contract = keeper
                 .register_contract(
                     cache,
                     code_id,
@@ -1495,7 +1314,7 @@ mod test {
                 payout: payout1.clone(),
             })
             .unwrap();
-            wasm_keeper
+            keeper
                 .call_instantiate(
                     contract.clone(),
                     &api,
@@ -1516,10 +1335,10 @@ mod test {
 
         // create a new cache and check we can use contract 1
         let (contract2, contract3) = transactional(&mut wasm_storage, |cache, wasm_reader| {
-            assert_payout(&wasm_keeper, cache, &contract1, &payout1);
+            assert_payout(&keeper, cache, &contract1, &payout1);
 
             // create contract 2 and use it
-            let contract2 = wasm_keeper
+            let contract2 = keeper
                 .register_contract(
                     cache,
                     code_id,
@@ -1534,7 +1353,7 @@ mod test {
                 payout: payout2.clone(),
             })
             .unwrap();
-            let _res = wasm_keeper
+            let _res = keeper
                 .call_instantiate(
                     contract2.clone(),
                     &api,
@@ -1545,15 +1364,15 @@ mod test {
                     init_msg,
                 )
                 .unwrap();
-            assert_payout(&wasm_keeper, cache, &contract2, &payout2);
+            assert_payout(&keeper, cache, &contract2, &payout2);
 
             // create a level2 cache and check we can use contract 1 and contract 2
             let contract3 = transactional(cache, |cache2, read| {
-                assert_payout(&wasm_keeper, cache2, &contract1, &payout1);
-                assert_payout(&wasm_keeper, cache2, &contract2, &payout2);
+                assert_payout(&keeper, cache2, &contract1, &payout1);
+                assert_payout(&keeper, cache2, &contract2, &payout2);
 
                 // create a contract on level 2
-                let contract3 = wasm_keeper
+                let contract3 = keeper
                     .register_contract(
                         cache2,
                         code_id,
@@ -1568,7 +1387,7 @@ mod test {
                     payout: payout3.clone(),
                 })
                 .unwrap();
-                let _res = wasm_keeper
+                let _res = keeper
                     .call_instantiate(
                         contract3.clone(),
                         &api,
@@ -1579,7 +1398,7 @@ mod test {
                         init_msg,
                     )
                     .unwrap();
-                assert_payout(&wasm_keeper, cache2, &contract3, &payout3);
+                assert_payout(&keeper, cache2, &contract3, &payout3);
 
                 // ensure first cache still doesn't see this contract
                 assert_no_contract(read, &contract3);
@@ -1588,9 +1407,9 @@ mod test {
             .unwrap();
 
             // after applying transaction, all contracts present on cache
-            assert_payout(&wasm_keeper, cache, &contract1, &payout1);
-            assert_payout(&wasm_keeper, cache, &contract2, &payout2);
-            assert_payout(&wasm_keeper, cache, &contract3, &payout3);
+            assert_payout(&keeper, cache, &contract1, &payout1);
+            assert_payout(&keeper, cache, &contract2, &payout2);
+            assert_payout(&keeper, cache, &contract3, &payout3);
 
             // but not yet the root router
             assert_no_contract(wasm_reader, &contract1);
@@ -1602,21 +1421,21 @@ mod test {
         .unwrap();
 
         // ensure that it is now applied to the router
-        assert_payout(&wasm_keeper, &mut wasm_storage, &contract1, &payout1);
-        assert_payout(&wasm_keeper, &mut wasm_storage, &contract2, &payout2);
-        assert_payout(&wasm_keeper, &mut wasm_storage, &contract3, &payout3);
+        assert_payout(&keeper, &mut wasm_storage, &contract1, &payout1);
+        assert_payout(&keeper, &mut wasm_storage, &contract2, &payout2);
+        assert_payout(&keeper, &mut wasm_storage, &contract3, &payout3);
     }
 
     fn assert_admin(
         storage: &dyn Storage,
-        wasm_keeper: &WasmKeeper<Empty, Empty>,
+        keeper: &WasmKeeper<Empty, Empty>,
         contract_addr: &impl ToString,
         admin: Option<Addr>,
     ) {
         let api = MockApi::default();
         let querier: MockQuerier<Empty> = MockQuerier::new(&[]);
         // query
-        let data = wasm_keeper
+        let data = keeper
             .query(
                 &api,
                 storage,
@@ -1634,9 +1453,9 @@ mod test {
     #[test]
     fn update_clear_admin_works() {
         let api = MockApi::default();
-        let mut wasm_keeper = wasm_keeper();
+        let mut keeper = WasmKeeper::new();
         let block = mock_env().block;
-        let code_id = wasm_keeper.store_code(Addr::unchecked("creator"), caller::contract());
+        let code_id = keeper.store_code(caller::contract());
 
         let mut wasm_storage = MockStorage::new();
 
@@ -1644,7 +1463,7 @@ mod test {
         let new_admin: Addr = Addr::unchecked("new_admin");
         let normal_user: Addr = Addr::unchecked("normal_user");
 
-        let contract_addr = wasm_keeper
+        let contract_addr = keeper
             .register_contract(
                 &mut wasm_storage,
                 code_id,
@@ -1657,8 +1476,8 @@ mod test {
 
         // init the contract
         let info = mock_info("admin", &[]);
-        let init_msg = to_vec(&Empty {}).unwrap();
-        let res = wasm_keeper
+        let init_msg = to_vec(&EmptyMsg {}).unwrap();
+        let res = keeper
             .call_instantiate(
                 contract_addr.clone(),
                 &api,
@@ -1671,15 +1490,10 @@ mod test {
             .unwrap();
         assert_eq!(0, res.messages.len());
 
-        assert_admin(
-            &wasm_storage,
-            &wasm_keeper,
-            &contract_addr,
-            Some(admin.clone()),
-        );
+        assert_admin(&wasm_storage, &keeper, &contract_addr, Some(admin.clone()));
 
         // non-admin should not be allowed to become admin on their own
-        wasm_keeper
+        keeper
             .execute_wasm(
                 &api,
                 &mut wasm_storage,
@@ -1694,15 +1508,10 @@ mod test {
             .unwrap_err();
 
         // should still be admin
-        assert_admin(
-            &wasm_storage,
-            &wasm_keeper,
-            &contract_addr,
-            Some(admin.clone()),
-        );
+        assert_admin(&wasm_storage, &keeper, &contract_addr, Some(admin.clone()));
 
-        // admin should be allowed to transfer administration permissions
-        let res = wasm_keeper
+        // admin should be allowed to transfers adminship
+        let res = keeper
             .execute_wasm(
                 &api,
                 &mut wasm_storage,
@@ -1720,13 +1529,13 @@ mod test {
         // new_admin should now be admin
         assert_admin(
             &wasm_storage,
-            &wasm_keeper,
+            &keeper,
             &contract_addr,
             Some(new_admin.clone()),
         );
 
         // new_admin should now be able to clear to admin
-        let res = wasm_keeper
+        let res = keeper
             .execute_wasm(
                 &api,
                 &mut wasm_storage,
@@ -1741,17 +1550,17 @@ mod test {
         assert_eq!(res.events.len(), 0);
 
         // should have no admin now
-        assert_admin(&wasm_storage, &wasm_keeper, &contract_addr, None);
+        assert_admin(&wasm_storage, &keeper, &contract_addr, None);
     }
 
     #[test]
     fn by_default_uses_simple_address_generator() {
-        let mut wasm_keeper = wasm_keeper();
-        let code_id = wasm_keeper.store_code(Addr::unchecked("creator"), payout::contract());
+        let mut keeper = WasmKeeper::<Empty, Empty>::new();
+        let code_id = keeper.store_code(payout::contract());
 
         let mut wasm_storage = MockStorage::new();
 
-        let contract_addr = wasm_keeper
+        let contract_addr = keeper
             .register_contract(
                 &mut wasm_storage,
                 code_id,
@@ -1780,15 +1589,15 @@ mod test {
     #[test]
     fn can_use_custom_address_generator() {
         let expected_addr = Addr::unchecked("new_test_addr");
-        let mut wasm_keeper: WasmKeeper<Empty, Empty> =
-            WasmKeeper::new_with_custom_address_generator(TestAddressGenerator {
+        let mut keeper =
+            WasmKeeper::<Empty, Empty>::new_with_custom_address_generator(TestAddressGenerator {
                 addr_to_return: expected_addr.clone(),
             });
-        let code_id = wasm_keeper.store_code(Addr::unchecked("creator"), payout::contract());
+        let code_id = keeper.store_code(payout::contract());
 
         let mut wasm_storage = MockStorage::new();
 
-        let contract_addr = wasm_keeper
+        let contract_addr = keeper
             .register_contract(
                 &mut wasm_storage,
                 code_id,


Test patch:
diff --git a/src/test_helpers/mod.rs b/src/test_helpers.rs
similarity index 54%
rename from src/test_helpers/mod.rs
rename to src/test_helpers.rs
index f67efbc..cb55119 100644
--- a/src/test_helpers/mod.rs
+++ b/src/test_helpers.rs
@@ -1,18 +1,15 @@
 #![cfg(test)]
-
-use cw_storage_plus::Item;
 use schemars::JsonSchema;
 use serde::{Deserialize, Serialize};
 
-pub mod caller;
-pub mod echo;
-pub mod error;
-pub mod hackatom;
-pub mod payout;
-pub mod reflect;
-pub mod stargate;
+use cw_storage_plus::Item;
+
+pub mod contracts;
+
+#[derive(Debug, Clone, Serialize, Deserialize, Default)]
+pub struct EmptyMsg {}
 
-/// Custom message for testing purposes.
+/// This is just a demo place so we can test custom message handling
 #[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
 #[serde(rename = "snake_case")]
 pub enum CustomMsg {
@@ -20,5 +17,4 @@ pub enum CustomMsg {
     SetAge { age: u32 },
 }
 
-/// Persisted counter for testing purposes.
-pub const COUNT: Item<u32> = Item::new("count");
+const COUNT: Item<u32> = Item::new("count");
diff --git a/src/test_helpers/contracts.rs b/src/test_helpers/contracts.rs
new file mode 100644
index 0000000..3b495e0
--- /dev/null
+++ b/src/test_helpers/contracts.rs
@@ -0,0 +1,9 @@
+//! Module for simple contracts to be used in tests
+
+pub mod caller;
+pub mod echo;
+pub mod error;
+pub mod hackatom;
+pub mod payout;
+pub mod reflect;
+pub mod stargate;
diff --git a/src/test_helpers/caller.rs b/src/test_helpers/contracts/caller.rs
similarity index 65%
rename from src/test_helpers/caller.rs
rename to src/test_helpers/contracts/caller.rs
index c283cda..92367a3 100644
--- a/src/test_helpers/caller.rs
+++ b/src/test_helpers/contracts/caller.rs
@@ -1,15 +1,15 @@
-use crate::{Contract, ContractWrapper};
-use cosmwasm_std::{
-    Binary, Deps, DepsMut, Empty, Env, MessageInfo, Response, StdError, SubMsg, WasmMsg,
-};
+use std::fmt;
+
+use cosmwasm_std::{Binary, Deps, DepsMut, Env, MessageInfo, Response, StdError, SubMsg, WasmMsg};
 use schemars::JsonSchema;
-use std::fmt::Debug;
+
+use crate::{test_helpers::EmptyMsg, Contract, ContractWrapper};
 
 fn instantiate(
     _deps: DepsMut,
     _env: Env,
     _info: MessageInfo,
-    _msg: Empty,
+    _msg: EmptyMsg,
 ) -> Result<Response, StdError> {
     Ok(Response::default())
 }
@@ -25,7 +25,7 @@ fn execute(
     Ok(Response::new().add_submessage(message))
 }
 
-fn query(_deps: Deps, _env: Env, _msg: Empty) -> Result<Binary, StdError> {
+fn query(_deps: Deps, _env: Env, _msg: EmptyMsg) -> Result<Binary, StdError> {
     Err(StdError::generic_err(
         "query not implemented for the `caller` contract",
     ))
@@ -33,7 +33,7 @@ fn query(_deps: Deps, _env: Env, _msg: Empty) -> Result<Binary, StdError> {
 
 pub fn contract<C>() -> Box<dyn Contract<C>>
 where
-    C: Clone + Debug + PartialEq + JsonSchema + 'static,
+    C: Clone + fmt::Debug + PartialEq + JsonSchema + 'static,
 {
     let contract = ContractWrapper::new_with_empty(execute, instantiate, query);
     Box::new(contract)
diff --git a/src/test_helpers/echo.rs b/src/test_helpers/contracts/echo.rs
similarity index 90%
rename from src/test_helpers/echo.rs
rename to src/test_helpers/contracts/echo.rs
index aa8984c..fb87602 100644
--- a/src/test_helpers/echo.rs
+++ b/src/test_helpers/contracts/echo.rs
@@ -1,22 +1,24 @@
-//! Very simple echoing contract which just returns incoming string if any,
-//! but performing sub call of given message to test response.
+//! Very simple echoing contract which just returns incomming string if any, but performming subcall of
+//! given message to test response.
 //!
-//! Additionally it bypasses all events and attributes send to it.
+//! Additionally it bypass all events and attributes send to it
 
-use crate::{Contract, ContractWrapper};
 use cosmwasm_std::{
     to_binary, Attribute, Binary, Deps, DepsMut, Empty, Env, Event, MessageInfo, Reply, Response,
     StdError, SubMsg, SubMsgResponse, SubMsgResult,
 };
-use cw_utils::{parse_execute_response_data, parse_instantiate_response_data};
-use derivative::Derivative;
-use schemars::JsonSchema;
 use serde::{de::DeserializeOwned, Deserialize, Serialize};
+
+use crate::{test_helpers::EmptyMsg, Contract, ContractWrapper};
+use schemars::JsonSchema;
 use std::fmt::Debug;
 
+use cw_utils::{parse_execute_response_data, parse_instantiate_response_data};
+use derivative::Derivative;
+
 // Choosing a reply id less than ECHO_EXECUTE_BASE_ID indicates an Instantiate message reply by convention.
 // An Execute message reply otherwise.
-pub const EXECUTE_REPLY_BASE_ID: u64 = i64::MAX as u64;
+pub(crate) const EXECUTE_REPLY_BASE_ID: u64 = i64::MAX as u64;
 
 #[derive(Debug, Clone, Serialize, Deserialize, Derivative)]
 #[derivative(Default(bound = "", new = "true"))]
@@ -83,7 +85,7 @@ where
         .add_events(msg.events))
 }
 
-fn query(_deps: Deps, _env: Env, msg: Empty) -> Result<Binary, StdError> {
+fn query(_deps: Deps, _env: Env, msg: EmptyMsg) -> Result<Binary, StdError> {
     to_binary(&msg)
 }
 
diff --git a/src/test_helpers/error.rs b/src/test_helpers/contracts/error.rs
similarity index 69%
rename from src/test_helpers/error.rs
rename to src/test_helpers/contracts/error.rs
index 033853d..e707e80 100644
--- a/src/test_helpers/error.rs
+++ b/src/test_helpers/contracts/error.rs
@@ -1,13 +1,15 @@
-use crate::{Contract, ContractWrapper};
-use cosmwasm_std::{Binary, Deps, DepsMut, Empty, Env, MessageInfo, Response, StdError};
+use std::fmt;
+
+use cosmwasm_std::{Binary, Deps, DepsMut, Env, MessageInfo, Response, StdError};
 use schemars::JsonSchema;
-use std::fmt::Debug;
+
+use crate::{test_helpers::EmptyMsg, Contract, ContractWrapper};
 
 fn instantiate_err(
     _deps: DepsMut,
     _env: Env,
     _info: MessageInfo,
-    _msg: Empty,
+    _msg: EmptyMsg,
 ) -> Result<Response, StdError> {
     Err(StdError::generic_err("Init failed"))
 }
@@ -16,7 +18,7 @@ fn instantiate_ok(
     _deps: DepsMut,
     _env: Env,
     _info: MessageInfo,
-    _msg: Empty,
+    _msg: EmptyMsg,
 ) -> Result<Response, StdError> {
     Ok(Response::default())
 }
@@ -25,18 +27,18 @@ fn execute(
     _deps: DepsMut,
     _env: Env,
     _info: MessageInfo,
-    _msg: Empty,
+    _msg: EmptyMsg,
 ) -> Result<Response, StdError> {
     Err(StdError::generic_err("Handle failed"))
 }
 
-fn query(_deps: Deps, _env: Env, _msg: Empty) -> Result<Binary, StdError> {
+fn query(_deps: Deps, _env: Env, _msg: EmptyMsg) -> Result<Binary, StdError> {
     Err(StdError::generic_err("Query failed"))
 }
 
 pub fn contract<C>(instantiable: bool) -> Box<dyn Contract<C>>
 where
-    C: Clone + Debug + PartialEq + JsonSchema + 'static,
+    C: Clone + fmt::Debug + PartialEq + JsonSchema + 'static,
 {
     let contract = if instantiable {
         ContractWrapper::new_with_empty(execute, instantiate_ok, query)
diff --git a/src/test_helpers/hackatom.rs b/src/test_helpers/contracts/hackatom.rs
similarity index 89%
rename from src/test_helpers/hackatom.rs
rename to src/test_helpers/contracts/hackatom.rs
index e968ccd..7ceabbd 100644
--- a/src/test_helpers/hackatom.rs
+++ b/src/test_helpers/contracts/hackatom.rs
@@ -1,13 +1,14 @@
 //! Simplified contract which when executed releases the funds to beneficiary
 
-use crate::{Contract, ContractWrapper};
 use cosmwasm_std::{
     to_binary, BankMsg, Binary, Deps, DepsMut, Empty, Env, MessageInfo, Response, StdError,
 };
 use cw_storage_plus::Item;
-use schemars::JsonSchema;
 use serde::{Deserialize, Serialize};
-use std::fmt::Debug;
+
+use crate::{test_helpers::EmptyMsg, Contract, ContractWrapper};
+use schemars::JsonSchema;
+use std::fmt;
 
 #[derive(Debug, Clone, Serialize, Deserialize)]
 pub struct InstantiateMsg {
@@ -39,7 +40,12 @@ fn instantiate(
     Ok(Response::default())
 }
 
-fn execute(deps: DepsMut, env: Env, _info: MessageInfo, _msg: Empty) -> Result<Response, StdError> {
+fn execute(
+    deps: DepsMut,
+    env: Env,
+    _info: MessageInfo,
+    _msg: EmptyMsg,
+) -> Result<Response, StdError> {
     let init = HACKATOM.load(deps.storage)?;
     let balance = deps.querier.query_all_balances(env.contract.address)?;
 
@@ -77,7 +83,7 @@ pub fn contract() -> Box<dyn Contract<Empty>> {
 #[allow(dead_code)]
 pub fn custom_contract<C>() -> Box<dyn Contract<C>>
 where
-    C: Clone + Debug + PartialEq + JsonSchema + 'static,
+    C: Clone + fmt::Debug + PartialEq + JsonSchema + 'static,
 {
     let contract =
         ContractWrapper::new_with_empty(execute, instantiate, query).with_migrate_empty(migrate);
diff --git a/src/test_helpers/payout.rs b/src/test_helpers/contracts/payout.rs
similarity index 83%
rename from src/test_helpers/payout.rs
rename to src/test_helpers/contracts/payout.rs
index 8198afb..4e9f1c1 100644
--- a/src/test_helpers/payout.rs
+++ b/src/test_helpers/contracts/payout.rs
@@ -1,12 +1,14 @@
-use crate::test_helpers::COUNT;
-use crate::{Contract, ContractWrapper};
+use schemars::JsonSchema;
+use serde::{Deserialize, Serialize};
+use std::fmt;
+
 use cosmwasm_std::{
-    to_binary, BankMsg, Binary, Coin, Deps, DepsMut, Empty, Env, MessageInfo, Response, StdError,
+    to_binary, BankMsg, Binary, Coin, Deps, DepsMut, Env, MessageInfo, Response, StdError,
 };
 use cw_storage_plus::Item;
-use schemars::JsonSchema;
-use serde::{Deserialize, Serialize};
-use std::fmt::Debug;
+
+use crate::contracts::{Contract, ContractWrapper};
+use crate::test_helpers::{EmptyMsg, COUNT};
 
 #[derive(Debug, Clone, Serialize, Deserialize, Default)]
 pub struct InstantiateMessage {
@@ -42,7 +44,12 @@ fn instantiate(
     Ok(Response::default())
 }
 
-fn execute(deps: DepsMut, _env: Env, info: MessageInfo, _msg: Empty) -> Result<Response, StdError> {
+fn execute(
+    deps: DepsMut,
+    _env: Env,
+    info: MessageInfo,
+    _msg: EmptyMsg,
+) -> Result<Response, StdError> {
     // always try to payout what was set originally
     let payout = PAYOUT.load(deps.storage)?;
     let msg = BankMsg::Send {
@@ -75,7 +82,7 @@ fn query(deps: Deps, _env: Env, msg: QueryMsg) -> Result<Binary, StdError> {
 
 pub fn contract<C>() -> Box<dyn Contract<C>>
 where
-    C: Clone + Debug + PartialEq + JsonSchema + 'static,
+    C: Clone + fmt::Debug + PartialEq + JsonSchema + 'static,
 {
     let contract =
         ContractWrapper::new_with_empty(execute, instantiate, query).with_sudo_empty(sudo);
diff --git a/src/test_helpers/reflect.rs b/src/test_helpers/contracts/reflect.rs
similarity index 86%
rename from src/test_helpers/reflect.rs
rename to src/test_helpers/contracts/reflect.rs
index de8a465..11a107e 100644
--- a/src/test_helpers/reflect.rs
+++ b/src/test_helpers/contracts/reflect.rs
@@ -1,11 +1,13 @@
-use crate::test_helpers::{payout, CustomMsg, COUNT};
-use crate::{Contract, ContractWrapper};
+use serde::{Deserialize, Serialize};
+
 use cosmwasm_std::{
-    to_binary, Binary, Deps, DepsMut, Empty, Env, Event, MessageInfo, Reply, Response, StdError,
-    SubMsg,
+    to_binary, Binary, Deps, DepsMut, Env, Event, MessageInfo, Reply, Response, StdError, SubMsg,
 };
 use cw_storage_plus::Map;
-use serde::{Deserialize, Serialize};
+
+use crate::contracts::{Contract, ContractWrapper};
+use crate::test_helpers::contracts::payout;
+use crate::test_helpers::{CustomMsg, EmptyMsg, COUNT};
 
 #[derive(Debug, Clone, Serialize, Deserialize, Default)]
 pub struct Message {
@@ -24,7 +26,7 @@ fn instantiate(
     deps: DepsMut,
     _env: Env,
     _info: MessageInfo,
-    _msg: Empty,
+    _msg: EmptyMsg,
 ) -> Result<Response<CustomMsg>, StdError> {
     COUNT.save(deps.storage, &0)?;
     Ok(Response::default())
diff --git a/src/test_helpers/stargate.rs b/src/test_helpers/contracts/stargate.rs
similarity index 99%
rename from src/test_helpers/stargate.rs
rename to src/test_helpers/contracts/stargate.rs
index 0a31efc..d5f4f2e 100644
--- a/src/test_helpers/stargate.rs
+++ b/src/test_helpers/contracts/stargate.rs
@@ -1,9 +1,10 @@
-use crate::{Contract, ContractWrapper};
 use cosmwasm_std::{
     Binary, CosmosMsg, Deps, DepsMut, Empty, Env, GovMsg, IbcMsg, MessageInfo, Response, StdResult,
 };
 use serde::{Deserialize, Serialize};
 
+use crate::{Contract, ContractWrapper};
+
 #[derive(Debug, Clone, Serialize, Deserialize)]
 pub enum ExecMsg {
     Ibc {},
diff --git a/src/tests/app.rs b/src/tests/app.rs
deleted file mode 100644
index 6a6b54e..0000000
--- a/src/tests/app.rs
+++ /dev/null
@@ -1,1845 +0,0 @@
-use crate::app::no_init;
-use crate::custom_handler::CachingCustomHandler;
-use crate::test_helpers::echo::EXECUTE_REPLY_BASE_ID;
-use crate::test_helpers::{caller, echo, error, hackatom, payout, reflect, CustomMsg};
-use crate::wasm::ContractData;
-use crate::{custom_app, App, AppResponse, Bank, Executor, Module, Wasm, WasmSudo};
-use anyhow::{bail, Result as AnyResult};
-use cosmwasm_std::{
-    coin, coins, testing::MockApi, to_binary, Addr, Api, Attribute, BankMsg, Binary, BlockInfo,
-    Coin, CosmosMsg, CustomQuery, Empty, Event, OverflowError, OverflowOperation, Querier, Reply,
-    StdError, StdResult, Storage, SubMsg, WasmMsg,
-};
-use cw_storage_plus::Item;
-use cw_utils::parse_instantiate_response_data;
-use schemars::JsonSchema;
-use serde::de::DeserializeOwned;
-use serde::{Deserialize, Serialize};
-use std::fmt::Debug;
-
-/// Utility function that returns all balances for specified address.
-fn get_balance<BankT, ApiT, StorageT, CustomT, WasmT>(
-    app: &App<BankT, ApiT, StorageT, CustomT, WasmT>,
-    addr: &Addr,
-) -> Vec<Coin>
-where
-    CustomT::ExecT: Clone + Debug + PartialEq + JsonSchema + DeserializeOwned + 'static,
-    CustomT::QueryT: CustomQuery + DeserializeOwned + 'static,
-    WasmT: Wasm<CustomT::ExecT, CustomT::QueryT>,
-    BankT: Bank,
-    ApiT: Api,
-    StorageT: Storage,
-    CustomT: Module,
-{
-    app.wrap().query_all_balances(addr).unwrap()
-}
-
-#[test]
-#[cfg(feature = "cosmwasm_1_2")]
-fn duplicate_contract_code() {
-    // set up the multi-test application
-    let mut app = App::default();
-
-    // store the original contract code
-    let code_id = app.store_code(payout::contract());
-
-    // duplicate previously stored contract code
-    let dup_code_id = app.duplicate_code(code_id).unwrap();
-    assert_ne!(code_id, dup_code_id);
-
-    // query and compare code info of both contract_helpers
-    let response = app.wrap().query_wasm_code_info(code_id).unwrap();
-    let dup_response = app.wrap().query_wasm_code_info(dup_code_id).unwrap();
-    assert_ne!(response.code_id, dup_response.code_id);
-    assert_eq!(response.creator, dup_response.creator);
-    assert_eq!(response.checksum, dup_response.checksum);
-}
-
-#[test]
-fn send_tokens() {
-    let owner = Addr::unchecked("owner");
-    let rcpt = Addr::unchecked("receiver");
-    let init_funds = vec![coin(20, "btc"), coin(100, "eth")];
-    let rcpt_funds = vec![coin(5, "btc")];
-
-    let mut app = App::new(|router, _, storage| {
-        // initialization moved to App construction
-        router
-            .bank
-            .init_balance(storage, &owner, init_funds)
-            .unwrap();
-        router
-            .bank
-            .init_balance(storage, &rcpt, rcpt_funds)
-            .unwrap();
-    });
-
-    // send both tokens
-    let to_send = vec![coin(30, "eth"), coin(5, "btc")];
-    let msg: CosmosMsg = BankMsg::Send {
-        to_address: rcpt.clone().into(),
-        amount: to_send,
-    }
-    .into();
-    app.execute(owner.clone(), msg.clone()).unwrap();
-    let rich = get_balance(&app, &owner);
-    assert_eq!(vec![coin(15, "btc"), coin(70, "eth")], rich);
-    let poor = get_balance(&app, &rcpt);
-    assert_eq!(vec![coin(10, "btc"), coin(30, "eth")], poor);
-
-    // can send from other account (but funds will be deducted from sender)
-    app.execute(rcpt.clone(), msg).unwrap();
-
-    // cannot send too much
-    let msg = BankMsg::Send {
-        to_address: rcpt.into(),
-        amount: coins(20, "btc"),
-    }
-    .into();
-    app.execute(owner.clone(), msg).unwrap_err();
-
-    let rich = get_balance(&app, &owner);
-    assert_eq!(vec![coin(15, "btc"), coin(70, "eth")], rich);
-}
-
-#[test]
-fn simple_contract() {
-    // set personal balance
-    let owner = Addr::unchecked("owner");
-    let init_funds = vec![coin(20, "btc"), coin(100, "eth")];
-
-    let mut app = App::new(|router, _, storage| {
-        router
-            .bank
-            .init_balance(storage, &owner, init_funds)
-            .unwrap();
-    });
-
-    // set up contract
-    let code_id = app.store_code(payout::contract());
-
-    let msg = payout::InstantiateMessage {
-        payout: coin(5, "eth"),
-    };
-    let contract_addr = app
-        .instantiate_contract(
-            code_id,
-            owner.clone(),
-            &msg,
-            &coins(23, "eth"),
-            "Payout",
-            None,
-        )
-        .unwrap();
-
-    let contract_data = app.contract_data(&contract_addr).unwrap();
-    assert_eq!(
-        contract_data,
-        ContractData {
-            code_id,
-            creator: owner.clone(),
-            admin: None,
-            label: "Payout".to_owned(),
-            created: app.block_info().height
-        }
-    );
-
-    // sender funds deducted
-    let sender = get_balance(&app, &owner);
-    assert_eq!(sender, vec![coin(20, "btc"), coin(77, "eth")]);
-    // get contract address, has funds
-    let funds = get_balance(&app, &contract_addr);
-    assert_eq!(funds, coins(23, "eth"));
-
-    // create empty account
-    let random = Addr::unchecked("random");
-    let funds = get_balance(&app, &random);
-    assert_eq!(funds, vec![]);
-
-    // do one payout and see money coming in
-    let res = app
-        .execute_contract(random.clone(), contract_addr.clone(), &Empty {}, &[])
-        .unwrap();
-    assert_eq!(3, res.events.len());
-
-    // the call to payout does emit this as well as custom attributes
-    let payout_exec = &res.events[0];
-    assert_eq!(payout_exec.ty.as_str(), "execute");
-    assert_eq!(
-        payout_exec.attributes,
-        [("_contract_address", &contract_addr)]
-    );
-
-    // next is a custom wasm event
-    let custom_attrs = res.custom_attrs(1);
-    assert_eq!(custom_attrs, [("action", "payout")]);
-
-    // then the transfer event
-    let expected_transfer = Event::new("transfer")
-        .add_attribute("recipient", "random")
-        .add_attribute("sender", &contract_addr)
-        .add_attribute("amount", "5eth");
-    assert_eq!(&expected_transfer, &res.events[2]);
-
-    // random got cash
-    let funds = get_balance(&app, &random);
-    assert_eq!(funds, coins(5, "eth"));
-    // contract lost it
-    let funds = get_balance(&app, &contract_addr);
-    assert_eq!(funds, coins(18, "eth"));
-}
-
-#[test]
-fn reflect_success() {
-    // set personal balance
-    let owner = Addr::unchecked("owner");
-    let init_funds = vec![coin(20, "btc"), coin(100, "eth")];
-
-    let mut app = custom_app::<CustomMsg, Empty, _>(|router, _, storage| {
-        router
-            .bank
-            .init_balance(storage, &owner, init_funds)
-            .unwrap();
-    });
-
-    // set up payout contract
-    let payout_id = app.store_code(payout::contract());
-
-    let msg = payout::InstantiateMessage {
-        payout: coin(5, "eth"),
-    };
-    let payout_addr = app
-        .instantiate_contract(
-            payout_id,
-            owner.clone(),
-            &msg,
-            &coins(23, "eth"),
-            "Payout",
-            None,
-        )
-        .unwrap();
-
-    // set up reflect contract
-    let reflect_id = app.store_code(reflect::contract());
-
-    let reflect_addr = app
-        .instantiate_contract(reflect_id, owner, &Empty {}, &[], "Reflect", None)
-        .unwrap();
-
-    // reflect account is empty
-    let funds = get_balance(&app, &reflect_addr);
-    assert_eq!(funds, vec![]);
-    // reflect count is 1
-    let query_res: payout::CountResponse = app
-        .wrap()
-        .query_wasm_smart(&reflect_addr, &reflect::QueryMsg::Count {})
-        .unwrap();
-    assert_eq!(0, query_res.count);
-
-    // reflecting payout message pays reflect contract
-    let msg = SubMsg::new(WasmMsg::Execute {
-        contract_addr: payout_addr.clone().into(),
-        msg: b"{}".into(),
-        funds: vec![],
-    });
-    let msgs = reflect::Message {
-        messages: vec![msg],
-    };
-    let res = app
-        .execute_contract(Addr::unchecked("random"), reflect_addr.clone(), &msgs, &[])
-        .unwrap();
-
-    // ensure the attributes were relayed from the sub-message
-    assert_eq!(4, res.events.len(), "{:?}", res.events);
-
-    // reflect only returns standard wasm-execute event
-    let ref_exec = &res.events[0];
-    assert_eq!(ref_exec.ty.as_str(), "execute");
-    assert_eq!(ref_exec.attributes, [("_contract_address", &reflect_addr)]);
-
-    // the call to payout does emit this as well as custom attributes
-    let payout_exec = &res.events[1];
-    assert_eq!(payout_exec.ty.as_str(), "execute");
-    assert_eq!(
-        payout_exec.attributes,
-        [("_contract_address", &payout_addr)]
-    );
-
-    let payout = &res.events[2];
-    assert_eq!(payout.ty.as_str(), "wasm");
-    assert_eq!(
-        payout.attributes,
-        [
-            ("_contract_address", payout_addr.as_str()),
-            ("action", "payout")
-        ]
-    );
-
-    // final event is the transfer from bank
-    let second = &res.events[3];
-    assert_eq!(second.ty.as_str(), "transfer");
-    assert_eq!(3, second.attributes.len());
-    assert_eq!(second.attributes[0], ("recipient", &reflect_addr));
-    assert_eq!(second.attributes[1], ("sender", &payout_addr));
-    assert_eq!(second.attributes[2], ("amount", "5eth"));
-
-    // ensure transfer was executed with reflect as sender
-    let funds = get_balance(&app, &reflect_addr);
-    assert_eq!(funds, coins(5, "eth"));
-
-    // reflect count updated
-    let query_res: payout::CountResponse = app
-        .wrap()
-        .query_wasm_smart(&reflect_addr, &reflect::QueryMsg::Count {})
-        .unwrap();
-    assert_eq!(1, query_res.count);
-}
-
-#[test]
-fn reflect_error() {
-    // set personal balance
-    let owner = Addr::unchecked("owner");
-    let init_funds = vec![coin(20, "btc"), coin(100, "eth")];
-
-    let mut app = custom_app::<CustomMsg, Empty, _>(|router, _, storage| {
-        router
-            .bank
-            .init_balance(storage, &owner, init_funds)
-            .unwrap();
-    });
-
-    // set up reflect contract
-    let reflect_id = app.store_code(reflect::contract());
-
-    let reflect_addr = app
-        .instantiate_contract(
-            reflect_id,
-            owner,
-            &Empty {},
-            &coins(40, "eth"),
-            "Reflect",
-            None,
-        )
-        .unwrap();
-
-    // reflect has 40 eth
-    let funds = get_balance(&app, &reflect_addr);
-    assert_eq!(funds, coins(40, "eth"));
-    let random = Addr::unchecked("random");
-
-    // sending 7 eth works
-    let msg = SubMsg::new(BankMsg::Send {
-        to_address: random.clone().into(),
-        amount: coins(7, "eth"),
-    });
-    let msgs = reflect::Message {
-        messages: vec![msg],
-    };
-    let res = app
-        .execute_contract(random.clone(), reflect_addr.clone(), &msgs, &[])
-        .unwrap();
-    // no wasm events as no attributes
-    assert_eq!(2, res.events.len());
-    // standard wasm-execute event
-    let exec = &res.events[0];
-    assert_eq!(exec.ty.as_str(), "execute");
-    assert_eq!(exec.attributes, [("_contract_address", &reflect_addr)]);
-    // only transfer event from bank
-    let transfer = &res.events[1];
-    assert_eq!(transfer.ty.as_str(), "transfer");
-
-    // ensure random got paid
-    let funds = get_balance(&app, &random);
-    assert_eq!(funds, coins(7, "eth"));
-
-    // reflect count should be updated to 1
-    let query_res: payout::CountResponse = app
-        .wrap()
-        .query_wasm_smart(&reflect_addr, &reflect::QueryMsg::Count {})
-        .unwrap();
-    assert_eq!(1, query_res.count);
-
-    // sending 8 eth, then 3 btc should fail both
-    let msg = SubMsg::new(BankMsg::Send {
-        to_address: random.clone().into(),
-        amount: coins(8, "eth"),
-    });
-    let msg2 = SubMsg::new(BankMsg::Send {
-        to_address: random.clone().into(),
-        amount: coins(3, "btc"),
-    });
-    let msgs = reflect::Message {
-        messages: vec![msg, msg2],
-    };
-    let err = app
-        .execute_contract(random.clone(), reflect_addr.clone(), &msgs, &[])
-        .unwrap_err();
-    assert_eq!(
-        StdError::overflow(OverflowError::new(OverflowOperation::Sub, 0, 3)),
-        err.downcast().unwrap()
-    );
-
-    // first one should have been rolled-back on error (no second payment)
-    let funds = get_balance(&app, &random);
-    assert_eq!(funds, coins(7, "eth"));
-
-    // failure should not update reflect count
-    let query_res: payout::CountResponse = app
-        .wrap()
-        .query_wasm_smart(&reflect_addr, &reflect::QueryMsg::Count {})
-        .unwrap();
-    assert_eq!(1, query_res.count);
-}
-
-#[test]
-fn sudo_works() {
-    let owner = Addr::unchecked("owner");
-    let init_funds = vec![coin(100, "eth")];
-
-    let mut app = App::new(|router, _, storage| {
-        router
-            .bank
-            .init_balance(storage, &owner, init_funds)
-            .unwrap();
-    });
-
-    let payout_id = app.store_code(payout::contract());
-
-    let msg = payout::InstantiateMessage {
-        payout: coin(5, "eth"),
-    };
-    let payout_addr = app
-        .instantiate_contract(payout_id, owner, &msg, &coins(23, "eth"), "Payout", None)
-        .unwrap();
-
-    // count is 1
-    let payout::CountResponse { count } = app
-        .wrap()
-        .query_wasm_smart(&payout_addr, &payout::QueryMsg::Count {})
-        .unwrap();
-    assert_eq!(1, count);
-
-    // wasm_sudo call
-    let msg = payout::SudoMsg { set_count: 25 };
-    app.wasm_sudo(payout_addr.clone(), &msg).unwrap();
-
-    // count is 25
-    let payout::CountResponse { count } = app
-        .wrap()
-        .query_wasm_smart(&payout_addr, &payout::QueryMsg::Count {})
-        .unwrap();
-    assert_eq!(25, count);
-
-    // we can do the same with sudo call
-    let msg = payout::SudoMsg { set_count: 49 };
-    let sudo_msg = WasmSudo {
-        contract_addr: payout_addr.clone(),
-        msg: to_binary(&msg).unwrap(),
-    };
-    app.sudo(sudo_msg.into()).unwrap();
-
-    let payout::CountResponse { count } = app
-        .wrap()
-        .query_wasm_smart(&payout_addr, &payout::QueryMsg::Count {})
-        .unwrap();
-    assert_eq!(49, count);
-}
-
-#[test]
-fn reflect_sub_message_reply_works() {
-    // set personal balance
-    let owner = Addr::unchecked("owner");
-    let random = Addr::unchecked("random");
-    let init_funds = vec![coin(20, "btc"), coin(100, "eth")];
-
-    let mut app = custom_app::<CustomMsg, Empty, _>(|router, _, storage| {
-        router
-            .bank
-            .init_balance(storage, &owner, init_funds)
-            .unwrap();
-    });
-
-    // set up reflect contract
-    let reflect_id = app.store_code(reflect::contract());
-
-    let reflect_addr = app
-        .instantiate_contract(
-            reflect_id,
-            owner,
-            &Empty {},
-            &coins(40, "eth"),
-            "Reflect",
-            None,
-        )
-        .unwrap();
-
-    // no reply writen beforehand
-    let query = reflect::QueryMsg::Reply { id: 123 };
-    let res: StdResult<Reply> = app.wrap().query_wasm_smart(&reflect_addr, &query);
-    res.unwrap_err();
-
-    // reflect sends 7 eth, success
-    let msg = SubMsg::reply_always(
-        BankMsg::Send {
-            to_address: random.clone().into(),
-            amount: coins(7, "eth"),
-        },
-        123,
-    );
-    let msgs = reflect::Message {
-        messages: vec![msg],
-    };
-    let res = app
-        .execute_contract(random.clone(), reflect_addr.clone(), &msgs, &[])
-        .unwrap();
-
-    // expected events: execute, transfer, reply, custom wasm (set in reply)
-    assert_eq!(4, res.events.len(), "{:?}", res.events);
-    res.assert_event(&Event::new("execute").add_attribute("_contract_address", &reflect_addr));
-    res.assert_event(&Event::new("transfer").add_attribute("amount", "7eth"));
-    res.assert_event(
-        &Event::new("reply")
-            .add_attribute("_contract_address", reflect_addr.as_str())
-            .add_attribute("mode", "handle_success"),
-    );
-    res.assert_event(&Event::new("wasm-custom").add_attribute("from", "reply"));
-
-    // ensure success was written
-    let res: Reply = app.wrap().query_wasm_smart(&reflect_addr, &query).unwrap();
-    assert_eq!(res.id, 123);
-    // validate the events written in the reply blob...should just be bank transfer
-    let reply = res.result.unwrap();
-    assert_eq!(1, reply.events.len());
-    AppResponse::from(reply).assert_event(&Event::new("transfer").add_attribute("amount", "7eth"));
-
-    // reflect sends 300 btc, failure, but error caught by sub-message (so shows success)
-    let msg = SubMsg::reply_always(
-        BankMsg::Send {
-            to_address: random.clone().into(),
-            amount: coins(300, "btc"),
-        },
-        456,
-    );
-    let msgs = reflect::Message {
-        messages: vec![msg],
-    };
-    let _res = app
-        .execute_contract(random, reflect_addr.clone(), &msgs, &[])
-        .unwrap();
-
-    // ensure error was written
-    let query = reflect::QueryMsg::Reply { id: 456 };
-    let res: Reply = app.wrap().query_wasm_smart(&reflect_addr, &query).unwrap();
-    assert_eq!(res.id, 456);
-    assert!(res.result.is_err());
-    // TODO: check error?
-}
-
-#[test]
-fn send_update_admin_works() {
-    // The plan:
-    // create a hackatom contract
-    // check admin set properly
-    // update admin succeeds if admin
-    // update admin fails if not (new) admin
-    // check admin set properly
-    let owner = Addr::unchecked("owner");
-    let owner2 = Addr::unchecked("owner2");
-    let beneficiary = Addr::unchecked("beneficiary");
-
-    let mut app = App::default();
-
-    // create a hackatom contract with some funds
-    let code_id = app.store_code(hackatom::contract());
-
-    let contract = app
-        .instantiate_contract(
-            code_id,
-            owner.clone(),
-            &hackatom::InstantiateMsg {
-                beneficiary: beneficiary.as_str().to_owned(),
-            },
-            &[],
-            "Hackatom",
-            Some(owner.to_string()),
-        )
-        .unwrap();
-
-    // check admin set properly
-    let info = app.contract_data(&contract).unwrap();
-    assert_eq!(info.admin, Some(owner.clone()));
-
-    // transfer admin permissions to owner2
-    app.execute(
-        owner.clone(),
-        CosmosMsg::Wasm(WasmMsg::UpdateAdmin {
-            contract_addr: contract.to_string(),
-            admin: owner2.to_string(),
-        }),
-    )
-    .unwrap();
-
-    // check admin set properly
-    let info = app.contract_data(&contract).unwrap();
-    assert_eq!(info.admin, Some(owner2.clone()));
-
-    // update admin fails if not owner2
-    app.execute(
-        owner.clone(),
-        CosmosMsg::Wasm(WasmMsg::UpdateAdmin {
-            contract_addr: contract.to_string(),
-            admin: owner.to_string(),
-        }),
-    )
-    .unwrap_err();
-
-    // check admin still the same
-    let info = app.contract_data(&contract).unwrap();
-    assert_eq!(info.admin, Some(owner2));
-}
-
-#[test]
-fn sent_wasm_migration_works() {
-    // The plan:
-    // create a hackatom contract with some funds
-    // check admin set properly
-    // check beneficiary set properly
-    // migrate fails if not admin
-    // migrate succeeds if admin
-    // check beneficiary updated
-    let owner = Addr::unchecked("owner");
-    let beneficiary = Addr::unchecked("beneficiary");
-    let init_funds = coins(30, "btc");
-
-    let mut app = App::new(|router, _, storage| {
-        router
-            .bank
-            .init_balance(storage, &owner, init_funds)
-            .unwrap();
-    });
-
-    // create a hackatom contract with some funds
-    let code_id = app.store_code(hackatom::contract());
-
-    let contract = app
-        .instantiate_contract(
-            code_id,
-            owner.clone(),
-            &hackatom::InstantiateMsg {
-                beneficiary: beneficiary.as_str().to_owned(),
-            },
-            &coins(20, "btc"),
-            "Hackatom",
-            Some(owner.to_string()),
-        )
-        .unwrap();
-
-    // check admin set properly
-    let info = app.contract_data(&contract).unwrap();
-    assert_eq!(info.admin, Some(owner.clone()));
-    // check beneficiary set properly
-    let state: hackatom::InstantiateMsg = app
-        .wrap()
-        .query_wasm_smart(&contract, &hackatom::QueryMsg::Beneficiary {})
-        .unwrap();
-    assert_eq!(state.beneficiary, beneficiary);
-
-    // migrate fails if not admin
-    let random = Addr::unchecked("random");
-    let migrate_msg = hackatom::MigrateMsg {
-        new_guy: random.to_string(),
-    };
-    app.migrate_contract(beneficiary, contract.clone(), &migrate_msg, code_id)
-        .unwrap_err();
-
-    // migrate fails if unregistered code id
-    app.migrate_contract(owner.clone(), contract.clone(), &migrate_msg, code_id + 7)
-        .unwrap_err();
-
-    // migrate succeeds when the stars align
-    app.migrate_contract(owner, contract.clone(), &migrate_msg, code_id)
-        .unwrap();
-
-    // check beneficiary updated
-    let state: hackatom::InstantiateMsg = app
-        .wrap()
-        .query_wasm_smart(&contract, &hackatom::QueryMsg::Beneficiary {})
-        .unwrap();
-    assert_eq!(state.beneficiary, random);
-}
-
-#[test]
-fn sent_funds_properly_visible_on_execution() {
-    // Testing if funds on contract are properly visible on contract.
-    // Hackatom contract is initialized with 10btc. Then, the contract is executed, with
-    // additional 20btc. Then beneficiary balance is checked - expected value is 30btc. 10btc
-    // would mean that sending tokens with message is not visible for this very message, and
-    // 20btc means, that only such just send funds are visible.
-    let owner = Addr::unchecked("owner");
-    let beneficiary = Addr::unchecked("beneficiary");
-    let init_funds = coins(30, "btc");
-
-    let mut app = App::new(|router, _, storage| {
-        router
-            .bank
-            .init_balance(storage, &owner, init_funds)
-            .unwrap();
-    });
-
-    let code_id = app.store_code(hackatom::contract());
-
-    let contract = app
-        .instantiate_contract(
-            code_id,
-            owner.clone(),
-            &hackatom::InstantiateMsg {
-                beneficiary: beneficiary.as_str().to_owned(),
-            },
-            &coins(10, "btc"),
-            "Hackatom",
-            None,
-        )
-        .unwrap();
-
-    app.execute_contract(
-        owner.clone(),
-        contract.clone(),
-        &Empty {},
-        &coins(20, "btc"),
-    )
-    .unwrap();
-
-    // Check balance of all accounts to ensure no tokens where burned or created, and they are
-    // in correct places
-    assert_eq!(get_balance(&app, &owner), &[]);
-    assert_eq!(get_balance(&app, &contract), &[]);
-    assert_eq!(get_balance(&app, &beneficiary), coins(30, "btc"));
-}
-
-/// Demonstrates that we can mint tokens and send from other accounts
-/// via a custom module, as an example of ability to do privileged actions.
-mod custom_handler {
-    use super::*;
-    use crate::{BankSudo, BasicAppBuilder, CosmosRouter};
-
-    const LOTTERY: Item<Coin> = Item::new("lottery");
-    const PITY: Item<Coin> = Item::new("pity");
-
-    #[derive(Clone, Debug, PartialEq, JsonSchema, Serialize, Deserialize)]
-    struct CustomMsg {
-        // we mint LOTTERY tokens to this one
-        lucky_winner: String,
-        // we transfer PITY from lucky_winner to runner_up
-        runner_up: String,
-    }
-
-    struct CustomHandler {}
-
-    impl Module for CustomHandler {
-        type ExecT = CustomMsg;
-        type QueryT = Empty;
-        type SudoT = Empty;
-
-        fn execute<ExecC, QueryC>(
-            &self,
-            api: &dyn Api,
-            storage: &mut dyn Storage,
-            router: &dyn CosmosRouter<ExecC = ExecC, QueryC = QueryC>,
-            block: &BlockInfo,
-            _sender: Addr,
-            msg: Self::ExecT,
-        ) -> AnyResult<AppResponse>
-        where
-            ExecC: Debug + Clone + PartialEq + JsonSchema + DeserializeOwned + 'static,
-            QueryC: CustomQuery + DeserializeOwned + 'static,
-        {
-            let lottery = LOTTERY.load(storage)?;
-            let pity = PITY.load(storage)?;
-
-            // mint new tokens
-            let mint = BankSudo::Mint {
-                to_address: msg.lucky_winner.clone(),
-                amount: vec![lottery],
-            };
-            router.sudo(api, storage, block, mint.into())?;
-
-            // send from an arbitrary account (not the module)
-            let transfer = BankMsg::Send {
-                to_address: msg.runner_up,
-                amount: vec![pity],
-            };
-            let rcpt = api.addr_validate(&msg.lucky_winner)?;
-            router.execute(api, storage, block, rcpt, transfer.into())?;
-
-            Ok(AppResponse::default())
-        }
-
-        fn sudo<ExecC, QueryC>(
-            &self,
-            _api: &dyn Api,
-            _storage: &mut dyn Storage,
-            _router: &dyn CosmosRouter<ExecC = ExecC, QueryC = QueryC>,
-            _block: &BlockInfo,
-            _msg: Self::SudoT,
-        ) -> AnyResult<AppResponse>
-        where
-            ExecC: Debug + Clone + PartialEq + JsonSchema + DeserializeOwned + 'static,
-            QueryC: CustomQuery + DeserializeOwned + 'static,
-        {
-            bail!("sudo not implemented for CustomHandler")
-        }
-
-        fn query(
-            &self,
-            _api: &dyn Api,
-            _storage: &dyn Storage,
-            _querier: &dyn Querier,
-            _block: &BlockInfo,
-            _request: Self::QueryT,
-        ) -> AnyResult<Binary> {
-            bail!("query not implemented for CustomHandler")
-        }
-    }
-
-    impl CustomHandler {
-        // this is a custom initialization method
-        pub fn set_payout(
-            &self,
-            storage: &mut dyn Storage,
-            lottery: Coin,
-            pity: Coin,
-        ) -> AnyResult<()> {
-            LOTTERY.save(storage, &lottery)?;
-            PITY.save(storage, &pity)?;
-            Ok(())
-        }
-    }
-
-    // let's call this custom handler
-    #[test]
-    fn dispatches_messages() {
-        let winner = "winner".to_string();
-        let second = "second".to_string();
-
-        // payments. note 54321 - 12321 = 42000
-        let denom = "tix";
-        let lottery = coin(54321, denom);
-        let bonus = coin(12321, denom);
-
-        let mut app = BasicAppBuilder::<CustomMsg, Empty>::new_custom()
-            .with_custom(CustomHandler {})
-            .build(|router, _, storage| {
-                router
-                    .custom
-                    .set_payout(storage, lottery.clone(), bonus.clone())
-                    .unwrap();
-            });
-
-        // query that balances are empty
-        let start = app.wrap().query_balance(&winner, denom).unwrap();
-        assert_eq!(start, coin(0, denom));
-
-        // trigger the custom module
-        let msg = CosmosMsg::Custom(CustomMsg {
-            lucky_winner: winner.clone(),
-            runner_up: second.clone(),
-        });
-        app.execute(Addr::unchecked("anyone"), msg).unwrap();
-
-        // see if coins were properly added
-        let big_win = app.wrap().query_balance(&winner, denom).unwrap();
-        assert_eq!(big_win, coin(42000, denom));
-        let little_win = app.wrap().query_balance(&second, denom).unwrap();
-        assert_eq!(little_win, bonus);
-    }
-}
-
-mod reply_data_overwrite {
-    use super::*;
-
-    use echo::EXECUTE_REPLY_BASE_ID;
-
-    fn make_echo_submsg(
-        contract: Addr,
-        data: impl Into<Option<&'static str>>,
-        sub_msg: Vec<SubMsg>,
-        id: u64,
-    ) -> SubMsg {
-        let data = data.into().map(|s| s.to_owned());
-        SubMsg::reply_always(
-            CosmosMsg::Wasm(WasmMsg::Execute {
-                contract_addr: contract.into(),
-                msg: to_binary(&echo::Message {
-                    data,
-                    sub_msg,
-                    ..echo::Message::default()
-                })
-                .unwrap(),
-                funds: vec![],
-            }),
-            id,
-        )
-    }
-
-    fn make_echo_submsg_no_reply(
-        contract: Addr,
-        data: impl Into<Option<&'static str>>,
-        sub_msg: Vec<SubMsg>,
-    ) -> SubMsg {
-        let data = data.into().map(|s| s.to_owned());
-        SubMsg::new(CosmosMsg::Wasm(WasmMsg::Execute {
-            contract_addr: contract.into(),
-            msg: to_binary(&echo::Message {
-                data,
-                sub_msg,
-                ..echo::Message::default()
-            })
-            .unwrap(),
-            funds: vec![],
-        }))
-    }
-
-    #[test]
-    fn no_submsg() {
-        let mut app = App::default();
-
-        let owner = Addr::unchecked("owner");
-
-        let code_id = app.store_code(echo::contract());
-
-        let contract = app
-            .instantiate_contract(code_id, owner.clone(), &Empty {}, &[], "Echo", None)
-            .unwrap();
-
-        let response = app
-            .execute_contract(
-                owner,
-                contract,
-                &echo::Message::<Empty> {
-                    data: Some("Data".to_owned()),
-                    ..echo::Message::default()
-                },
-                &[],
-            )
-            .unwrap();
-
-        assert_eq!(response.data, Some(b"Data".into()));
-    }
-
-    #[test]
-    fn single_submsg() {
-        let mut app = App::default();
-
-        let owner = Addr::unchecked("owner");
-
-        let code_id = app.store_code(echo::contract());
-
-        let contract = app
-            .instantiate_contract(code_id, owner.clone(), &Empty {}, &[], "Echo", None)
-            .unwrap();
-
-        let response = app
-            .execute_contract(
-                owner,
-                contract.clone(),
-                &echo::Message {
-                    data: Some("First".to_owned()),
-                    sub_msg: vec![make_echo_submsg(
-                        contract,
-                        "Second",
-                        vec![],
-                        EXECUTE_REPLY_BASE_ID,
-                    )],
-                    ..echo::Message::default()
-                },
-                &[],
-            )
-            .unwrap();
-
-        assert_eq!(response.data, Some(b"Second".into()));
-    }
-
-    #[test]
-    fn single_submsg_no_reply() {
-        let mut app = App::default();
-
-        let owner = Addr::unchecked("owner");
-
-        let code_id = app.store_code(echo::contract());
-
-        let contract = app
-            .instantiate_contract(code_id, owner.clone(), &Empty {}, &[], "Echo", None)
-            .unwrap();
-
-        let response = app
-            .execute_contract(
-                owner,
-                contract.clone(),
-                &echo::Message {
-                    data: Some("First".to_owned()),
-                    sub_msg: vec![make_echo_submsg_no_reply(contract, "Second", vec![])],
-                    ..echo::Message::default()
-                },
-                &[],
-            )
-            .unwrap();
-
-        assert_eq!(response.data, Some(b"First".into()));
-    }
-
-    #[test]
-    fn single_no_submsg_data() {
-        let mut app = App::default();
-
-        let owner = Addr::unchecked("owner");
-
-        let code_id = app.store_code(echo::contract());
-
-        let contract = app
-            .instantiate_contract(code_id, owner.clone(), &Empty {}, &[], "Echo", None)
-            .unwrap();
-
-        let response = app
-            .execute_contract(
-                owner,
-                contract.clone(),
-                &echo::Message {
-                    data: Some("First".to_owned()),
-                    sub_msg: vec![make_echo_submsg(contract, None, vec![], 1)],
-                    ..echo::Message::default()
-                },
-                &[],
-            )
-            .unwrap();
-
-        assert_eq!(response.data, Some(b"First".into()));
-    }
-
-    #[test]
-    fn single_no_top_level_data() {
-        let mut app = App::default();
-
-        let owner = Addr::unchecked("owner");
-
-        let code_id = app.store_code(echo::contract());
-
-        let contract = app
-            .instantiate_contract(code_id, owner.clone(), &Empty {}, &[], "Echo", None)
-            .unwrap();
-
-        let response = app
-            .execute_contract(
-                owner,
-                contract.clone(),
-                &echo::Message {
-                    sub_msg: vec![make_echo_submsg(
-                        contract,
-                        "Second",
-                        vec![],
-                        EXECUTE_REPLY_BASE_ID,
-                    )],
-                    ..echo::Message::default()
-                },
-                &[],
-            )
-            .unwrap();
-
-        assert_eq!(response.data, Some(b"Second".into()));
-    }
-
-    #[test]
-    fn single_submsg_reply_returns_none() {
-        // set personal balance
-        let owner = Addr::unchecked("owner");
-        let init_funds = coins(100, "tgd");
-
-        let mut app = custom_app::<CustomMsg, Empty, _>(|router, _, storage| {
-            router
-                .bank
-                .init_balance(storage, &owner, init_funds)
-                .unwrap();
-        });
-
-        // set up reflect contract
-        let reflect_id = app.store_code(reflect::contract());
-
-        let reflect_addr = app
-            .instantiate_contract(reflect_id, owner.clone(), &Empty {}, &[], "Reflect", None)
-            .unwrap();
-
-        // set up echo contract
-        let echo_id = app.store_code(echo::custom_contract());
-
-        let echo_addr = app
-            .instantiate_contract(echo_id, owner.clone(), &Empty {}, &[], "Echo", None)
-            .unwrap();
-
-        // reflect will call echo
-        // echo will set the data
-        // top-level app will not display the data
-        let echo_msg = echo::Message::<Empty> {
-            data: Some("my echo".into()),
-            events: vec![Event::new("echo").add_attribute("called", "true")],
-            ..echo::Message::default()
-        };
-        let reflect_msg = reflect::Message {
-            messages: vec![SubMsg::new(WasmMsg::Execute {
-                contract_addr: echo_addr.to_string(),
-                msg: to_binary(&echo_msg).unwrap(),
-                funds: vec![],
-            })],
-        };
-
-        let res = app
-            .execute_contract(owner, reflect_addr.clone(), &reflect_msg, &[])
-            .unwrap();
-
-        // ensure data is empty
-        assert_eq!(res.data, None);
-        // ensure expected events
-        assert_eq!(res.events.len(), 3, "{:?}", res.events);
-        res.assert_event(&Event::new("execute").add_attribute("_contract_address", &reflect_addr));
-        res.assert_event(&Event::new("execute").add_attribute("_contract_address", &echo_addr));
-        res.assert_event(&Event::new("wasm-echo"));
-    }
-
-    #[test]
-    fn multiple_submsg() {
-        let mut app = App::default();
-
-        let owner = Addr::unchecked("owner");
-
-        let code_id = app.store_code(echo::contract());
-
-        let contract = app
-            .instantiate_contract(code_id, owner.clone(), &Empty {}, &[], "Echo", None)
-            .unwrap();
-
-        let response = app
-            .execute_contract(
-                owner,
-                contract.clone(),
-                &echo::Message {
-                    data: Some("Orig".to_owned()),
-                    sub_msg: vec![
-                        make_echo_submsg(contract.clone(), None, vec![], EXECUTE_REPLY_BASE_ID + 1),
-                        make_echo_submsg(
-                            contract.clone(),
-                            "First",
-                            vec![],
-                            EXECUTE_REPLY_BASE_ID + 2,
-                        ),
-                        make_echo_submsg(
-                            contract.clone(),
-                            "Second",
-                            vec![],
-                            EXECUTE_REPLY_BASE_ID + 3,
-                        ),
-                        make_echo_submsg(contract, None, vec![], EXECUTE_REPLY_BASE_ID + 4),
-                    ],
-                    ..echo::Message::default()
-                },
-                &[],
-            )
-            .unwrap();
-
-        assert_eq!(response.data, Some(b"Second".into()));
-    }
-
-    #[test]
-    fn multiple_submsg_no_reply() {
-        let mut app = App::default();
-
-        let owner = Addr::unchecked("owner");
-
-        let code_id = app.store_code(echo::contract());
-
-        let contract = app
-            .instantiate_contract(code_id, owner.clone(), &Empty {}, &[], "Echo", None)
-            .unwrap();
-
-        let response = app
-            .execute_contract(
-                owner,
-                contract.clone(),
-                &echo::Message {
-                    data: Some("Orig".to_owned()),
-                    sub_msg: vec![
-                        make_echo_submsg_no_reply(contract.clone(), None, vec![]),
-                        make_echo_submsg_no_reply(contract.clone(), "First", vec![]),
-                        make_echo_submsg_no_reply(contract.clone(), "Second", vec![]),
-                        make_echo_submsg_no_reply(contract, None, vec![]),
-                    ],
-                    ..echo::Message::default()
-                },
-                &[],
-            )
-            .unwrap();
-
-        assert_eq!(response.data, Some(b"Orig".into()));
-    }
-
-    #[test]
-    fn multiple_submsg_mixed() {
-        let mut app = App::default();
-
-        let owner = Addr::unchecked("owner");
-
-        let code_id = app.store_code(echo::contract());
-
-        let contract = app
-            .instantiate_contract(code_id, owner.clone(), &Empty {}, &[], "Echo", None)
-            .unwrap();
-
-        let response = app
-            .execute_contract(
-                owner,
-                contract.clone(),
-                &echo::Message {
-                    sub_msg: vec![
-                        make_echo_submsg(contract.clone(), None, vec![], EXECUTE_REPLY_BASE_ID + 1),
-                        make_echo_submsg_no_reply(contract.clone(), "Hidden", vec![]),
-                        make_echo_submsg(
-                            contract.clone(),
-                            "Shown",
-                            vec![],
-                            EXECUTE_REPLY_BASE_ID + 2,
-                        ),
-                        make_echo_submsg(contract.clone(), None, vec![], EXECUTE_REPLY_BASE_ID + 3),
-                        make_echo_submsg_no_reply(contract, "Lost", vec![]),
-                    ],
-                    ..echo::Message::default()
-                },
-                &[],
-            )
-            .unwrap();
-
-        assert_eq!(response.data, Some(b"Shown".into()));
-    }
-
-    #[test]
-    fn nested_submsg() {
-        let mut app = App::default();
-
-        let owner = Addr::unchecked("owner");
-
-        let code_id = app.store_code(echo::contract());
-
-        let contract = app
-            .instantiate_contract(code_id, owner.clone(), &Empty {}, &[], "Echo", None)
-            .unwrap();
-
-        let response = app
-            .execute_contract(
-                owner,
-                contract.clone(),
-                &echo::Message {
-                    data: Some("Orig".to_owned()),
-                    sub_msg: vec![make_echo_submsg(
-                        contract.clone(),
-                        None,
-                        vec![make_echo_submsg(
-                            contract.clone(),
-                            "First",
-                            vec![make_echo_submsg(
-                                contract.clone(),
-                                "Second",
-                                vec![make_echo_submsg(
-                                    contract,
-                                    None,
-                                    vec![],
-                                    EXECUTE_REPLY_BASE_ID + 4,
-                                )],
-                                EXECUTE_REPLY_BASE_ID + 3,
-                            )],
-                            EXECUTE_REPLY_BASE_ID + 2,
-                        )],
-                        EXECUTE_REPLY_BASE_ID + 1,
-                    )],
-                    ..echo::Message::default()
-                },
-                &[],
-            )
-            .unwrap();
-
-        assert_eq!(response.data, Some(b"Second".into()));
-    }
-}
-
-mod response_validation {
-    use super::*;
-    use crate::error::Error;
-
-    #[test]
-    fn empty_attribute_key() {
-        let mut app = App::default();
-
-        let owner = Addr::unchecked("owner");
-
-        let code_id = app.store_code(echo::contract());
-
-        let contract = app
-            .instantiate_contract(code_id, owner.clone(), &Empty {}, &[], "Echo", None)
-            .unwrap();
-
-        let err = app
-            .execute_contract(
-                owner,
-                contract,
-                &echo::Message::<Empty> {
-                    data: None,
-                    attributes: vec![
-                        Attribute::new("   ", "value"),
-                        Attribute::new("proper", "proper_val"),
-                    ],
-                    ..echo::Message::default()
-                },
-                &[],
-            )
-            .unwrap_err();
-
-        assert_eq!(Error::empty_attribute_key("value"), err.downcast().unwrap(),);
-    }
-
-    #[test]
-    fn empty_attribute_value() {
-        let mut app = App::default();
-
-        let owner = Addr::unchecked("owner");
-
-        let code_id = app.store_code(echo::contract());
-
-        let contract = app
-            .instantiate_contract(code_id, owner.clone(), &Empty {}, &[], "Echo", None)
-            .unwrap();
-
-        let err = app
-            .execute_contract(
-                owner,
-                contract,
-                &echo::Message::<Empty> {
-                    data: None,
-                    attributes: vec![
-                        Attribute::new("key", "   "),
-                        Attribute::new("proper", "proper_val"),
-                    ],
-                    ..echo::Message::default()
-                },
-                &[],
-            )
-            .unwrap_err();
-
-        assert_eq!(Error::empty_attribute_value("key"), err.downcast().unwrap());
-    }
-
-    #[test]
-    fn empty_event_attribute_key() {
-        let mut app = App::default();
-
-        let owner = Addr::unchecked("owner");
-
-        let code_id = app.store_code(echo::contract());
-
-        let contract = app
-            .instantiate_contract(code_id, owner.clone(), &Empty {}, &[], "Echo", None)
-            .unwrap();
-
-        let err = app
-            .execute_contract(
-                owner,
-                contract,
-                &echo::Message::<Empty> {
-                    data: None,
-                    events: vec![Event::new("event")
-                        .add_attribute("   ", "value")
-                        .add_attribute("proper", "proper_val")],
-                    ..echo::Message::default()
-                },
-                &[],
-            )
-            .unwrap_err();
-
-        assert_eq!(Error::empty_attribute_key("value"), err.downcast().unwrap());
-    }
-
-    #[test]
-    fn empty_event_attribute_value() {
-        let mut app = App::default();
-
-        let owner = Addr::unchecked("owner");
-
-        let code_id = app.store_code(echo::contract());
-
-        let contract = app
-            .instantiate_contract(code_id, owner.clone(), &Empty {}, &[], "Echo", None)
-            .unwrap();
-
-        let err = app
-            .execute_contract(
-                owner,
-                contract,
-                &echo::Message::<Empty> {
-                    data: None,
-                    events: vec![Event::new("event")
-                        .add_attribute("key", "   ")
-                        .add_attribute("proper", "proper_val")],
-                    ..echo::Message::default()
-                },
-                &[],
-            )
-            .unwrap_err();
-
-        assert_eq!(Error::empty_attribute_value("key"), err.downcast().unwrap());
-    }
-
-    #[test]
-    fn too_short_event_type() {
-        let mut app = App::default();
-
-        let owner = Addr::unchecked("owner");
-
-        let code_id = app.store_code(echo::contract());
-
-        let contract = app
-            .instantiate_contract(code_id, owner.clone(), &Empty {}, &[], "Echo", None)
-            .unwrap();
-
-        let err = app
-            .execute_contract(
-                owner,
-                contract,
-                &echo::Message::<Empty> {
-                    data: None,
-                    events: vec![Event::new(" e "), Event::new("event")],
-                    ..echo::Message::default()
-                },
-                &[],
-            )
-            .unwrap_err();
-
-        assert_eq!(Error::event_type_too_short("e"), err.downcast().unwrap());
-    }
-}
-
-mod contract_instantiation {
-
-    #[test]
-    #[cfg(feature = "cosmwasm_1_2")]
-    fn instantiate2_works() {
-        use super::*;
-
-        // prepare application and actors
-        let mut app = App::default();
-        let sender = Addr::unchecked("sender");
-
-        // store contract's code
-        let code_id = app.store_code_with_creator(Addr::unchecked("creator"), echo::contract());
-
-        // initialize the contract
-        let init_msg = to_binary(&Empty {}).unwrap();
-        let msg = WasmMsg::Instantiate2 {
-            admin: None,
-            code_id,
-            msg: init_msg,
-            funds: vec![],
-            label: "label".into(),
-            salt: [0, 1, 2, 3, 4, 5].as_slice().into(),
-        };
-        let res = app.execute(sender, msg.into()).unwrap();
-
-        // assert a proper instantiate result
-        let parsed = parse_instantiate_response_data(res.data.unwrap().as_slice()).unwrap();
-        assert!(parsed.data.is_none());
-
-        // assert contract's address is exactly the predicted one
-        //
-        // REMARK:
-        //   Currently implemented address generator is used to generate
-        //   the predictable address of newly instantiated contract.
-        //
-        //   Conceptually, the address of the contract is fully predictable,
-        //   because it is just the contract0 for the first instance,
-        //   contract1 for the second and so forth.
-        //
-        //   Comparing this address to real-life blockchain and the implementation
-        //   of cosmwasm_std::instantiate2_address, this approach is totally incompatible.
-        //   This problem will be handled in the next step, please see:
-        //   https://github.com/CosmWasm/cosmwasm/issues/1873
-        //   for details.
-        assert_eq!("contract0", parsed.contract_address);
-    }
-}
-
-mod wasm_queries {
-
-    #[test]
-    #[cfg(feature = "cosmwasm_1_2")]
-    fn query_existing_code_info() {
-        use super::*;
-        let mut app = App::default();
-        let code_id = app.store_code_with_creator(Addr::unchecked("creator"), echo::contract());
-        let code_info_response = app.wrap().query_wasm_code_info(code_id).unwrap();
-        assert_eq!(code_id, code_info_response.code_id);
-        assert_eq!("creator", code_info_response.creator);
-        assert!(!code_info_response.checksum.is_empty());
-    }
-
-    #[test]
-    #[cfg(feature = "cosmwasm_1_2")]
-    fn query_non_existing_code_info() {
-        use super::*;
-        let app = App::default();
-        assert_eq!(
-            "Generic error: Querier contract error: code id: invalid",
-            app.wrap().query_wasm_code_info(0).unwrap_err().to_string()
-        );
-        assert_eq!(
-            "Generic error: Querier contract error: code id 1: no such code",
-            app.wrap().query_wasm_code_info(1).unwrap_err().to_string()
-        );
-    }
-}
-
-mod custom_messages {
-    use super::*;
-    use crate::AppBuilder;
-
-    #[test]
-    fn triggering_custom_msg() {
-        let api = MockApi::default();
-        let sender = api.addr_validate("sender").unwrap();
-        let owner = api.addr_validate("owner").unwrap();
-
-        let custom_handler = CachingCustomHandler::<CustomMsg, Empty>::new();
-        let custom_handler_state = custom_handler.state();
-
-        let mut app = AppBuilder::new_custom()
-            .with_api(api)
-            .with_custom(custom_handler)
-            .build(no_init);
-
-        let contract_id = app.store_code(echo::custom_contract());
-
-        let contract = app
-            .instantiate_contract(contract_id, owner, &Empty {}, &[], "Echo", None)
-            .unwrap();
-
-        app.execute_contract(
-            sender,
-            contract,
-            &echo::Message {
-                sub_msg: vec![SubMsg::new(CosmosMsg::Custom(CustomMsg::SetAge {
-                    age: 20,
-                }))],
-                ..Default::default()
-            },
-            &[],
-        )
-        .unwrap();
-
-        assert_eq!(
-            custom_handler_state.execs().to_owned(),
-            vec![CustomMsg::SetAge { age: 20 }]
-        );
-
-        assert!(custom_handler_state.queries().is_empty());
-    }
-}
-
-mod protobuf_wrapped_data {
-    use super::*;
-    use crate::BasicApp;
-
-    #[test]
-    fn instantiate_wrapped_properly() {
-        // set personal balance
-        let owner = Addr::unchecked("owner");
-        let init_funds = vec![coin(20, "btc")];
-
-        let mut app = custom_app::<CustomMsg, Empty, _>(|router, _, storage| {
-            router
-                .bank
-                .init_balance(storage, &owner, init_funds)
-                .unwrap();
-        });
-
-        // set up reflect contract
-        let code_id = app.store_code(reflect::contract());
-
-        let init_msg = to_binary(&Empty {}).unwrap();
-        let msg = WasmMsg::Instantiate {
-            admin: None,
-            code_id,
-            msg: init_msg,
-            funds: vec![],
-            label: "label".into(),
-        };
-        let res = app.execute(owner, msg.into()).unwrap();
-
-        // assert we have a proper instantiate result
-        let parsed = parse_instantiate_response_data(res.data.unwrap().as_slice()).unwrap();
-        assert!(parsed.data.is_none());
-        // check the address is right
-
-        let count: payout::CountResponse = app
-            .wrap()
-            .query_wasm_smart(&parsed.contract_address, &reflect::QueryMsg::Count {})
-            .unwrap();
-        assert_eq!(count.count, 0);
-    }
-
-    #[test]
-    fn instantiate_with_data_works() {
-        let owner = Addr::unchecked("owner");
-        let mut app = BasicApp::new(|_, _, _| {});
-
-        // set up echo contract
-        let code_id = app.store_code(echo::contract());
-
-        let msg = echo::InitMessage::<Empty> {
-            data: Some("food".into()),
-            sub_msg: None,
-        };
-        let init_msg = to_binary(&msg).unwrap();
-        let msg = WasmMsg::Instantiate {
-            admin: None,
-            code_id,
-            msg: init_msg,
-            funds: vec![],
-            label: "label".into(),
-        };
-        let res = app.execute(owner, msg.into()).unwrap();
-
-        // assert we have a proper instantiate result
-        let parsed = parse_instantiate_response_data(res.data.unwrap().as_slice()).unwrap();
-        assert!(parsed.data.is_some());
-        assert_eq!(parsed.data.unwrap(), Binary::from(b"food"));
-        assert!(!parsed.contract_address.is_empty());
-    }
-
-    #[test]
-    fn instantiate_with_reply_works() {
-        let owner = Addr::unchecked("owner");
-        let mut app = BasicApp::new(|_, _, _| {});
-
-        // set up echo contract
-        let code_id = app.store_code(echo::contract());
-
-        let msg = echo::InitMessage::<Empty> {
-            data: Some("food".into()),
-            ..Default::default()
-        };
-        let addr1 = app
-            .instantiate_contract(code_id, owner.clone(), &msg, &[], "first", None)
-            .unwrap();
-
-        // another echo contract
-        let msg = echo::Message::<Empty> {
-            data: Some("Passed to contract instantiation, returned as reply, and then returned as response".into()),
-            ..Default::default()
-        };
-        let sub_msg = SubMsg::reply_on_success(
-            WasmMsg::Execute {
-                contract_addr: addr1.to_string(),
-                msg: to_binary(&msg).unwrap(),
-                funds: vec![],
-            },
-            EXECUTE_REPLY_BASE_ID,
-        );
-        let init_msg = echo::InitMessage::<Empty> {
-            data: Some("Overwrite me".into()),
-            sub_msg: Some(vec![sub_msg]),
-        };
-        let init_msg = to_binary(&init_msg).unwrap();
-        let msg = WasmMsg::Instantiate {
-            admin: None,
-            code_id,
-            msg: init_msg,
-            funds: vec![],
-            label: "label".into(),
-        };
-        let res = app.execute(owner, msg.into()).unwrap();
-
-        // assert we have a proper instantiate result
-        let parsed = parse_instantiate_response_data(res.data.unwrap().as_slice()).unwrap();
-        assert!(parsed.data.is_some());
-        // Result is from the reply, not the original one
-        assert_eq!(parsed.data.unwrap(), Binary::from(b"Passed to contract instantiation, returned as reply, and then returned as response"));
-        assert!(!parsed.contract_address.is_empty());
-        assert_ne!(parsed.contract_address, addr1.to_string());
-    }
-
-    #[test]
-    fn execute_wrapped_properly() {
-        let owner = Addr::unchecked("owner");
-        let mut app = BasicApp::new(|_, _, _| {});
-
-        // set up reflect contract
-        let code_id = app.store_code(echo::contract());
-
-        let echo_addr = app
-            .instantiate_contract(code_id, owner.clone(), &Empty {}, &[], "label", None)
-            .unwrap();
-
-        // ensure the execute has the same wrapper as it should
-        let msg = echo::Message::<Empty> {
-            data: Some("hello".into()),
-            ..echo::Message::default()
-        };
-        // execute_contract now decodes a protobuf wrapper, so we get the top-level response
-        let exec_res = app.execute_contract(owner, echo_addr, &msg, &[]).unwrap();
-        assert_eq!(exec_res.data, Some(Binary::from(b"hello")));
-    }
-}
-
-mod errors {
-    use super::*;
-
-    #[test]
-    fn simple_instantiation() {
-        let owner = Addr::unchecked("owner");
-        let mut app = App::default();
-
-        // set up contract
-        let code_id = app.store_code(error::contract(false));
-
-        let msg = Empty {};
-        let err = app
-            .instantiate_contract(code_id, owner, &msg, &[], "error", None)
-            .unwrap_err();
-
-        // we should be able to retrieve the original error by downcasting
-        let source: &StdError = err.downcast_ref().unwrap();
-        if let StdError::GenericErr { msg } = source {
-            assert_eq!(msg, "Init failed");
-        } else {
-            panic!("wrong StdError variant");
-        }
-
-        // We're expecting exactly 2 nested error types
-        // (the original error, WasmMsg context)
-        assert_eq!(err.chain().count(), 2);
-    }
-
-    #[test]
-    fn simple_call() {
-        let owner = Addr::unchecked("owner");
-        let mut app = App::default();
-
-        // set up contract
-        let code_id = app.store_code(error::contract(true));
-
-        let msg = Empty {};
-        let contract_addr = app
-            .instantiate_contract(code_id, owner, &msg, &[], "error", None)
-            .unwrap();
-
-        // execute should error
-        let err = app
-            .execute_contract(Addr::unchecked("random"), contract_addr, &msg, &[])
-            .unwrap_err();
-
-        // we should be able to retrieve the original error by downcasting
-        let source: &StdError = err.downcast_ref().unwrap();
-        if let StdError::GenericErr { msg } = source {
-            assert_eq!(msg, "Handle failed");
-        } else {
-            panic!("wrong StdError variant");
-        }
-
-        // We're expecting exactly 2 nested error types
-        // (the original error, WasmMsg context)
-        assert_eq!(err.chain().count(), 2);
-    }
-
-    #[test]
-    fn nested_call() {
-        let owner = Addr::unchecked("owner");
-        let mut app = App::default();
-
-        let error_code_id = app.store_code(error::contract(true));
-        let caller_code_id = app.store_code(caller::contract());
-
-        // set up contract_helpers
-        let msg = Empty {};
-        let caller_addr = app
-            .instantiate_contract(caller_code_id, owner.clone(), &msg, &[], "caller", None)
-            .unwrap();
-        let error_addr = app
-            .instantiate_contract(error_code_id, owner, &msg, &[], "error", None)
-            .unwrap();
-
-        // execute should error
-        let msg = WasmMsg::Execute {
-            contract_addr: error_addr.into(),
-            msg: to_binary(&Empty {}).unwrap(),
-            funds: vec![],
-        };
-        let err = app
-            .execute_contract(Addr::unchecked("random"), caller_addr, &msg, &[])
-            .unwrap_err();
-
-        // we can downcast to get the original error
-        let source: &StdError = err.downcast_ref().unwrap();
-        if let StdError::GenericErr { msg } = source {
-            assert_eq!(msg, "Handle failed");
-        } else {
-            panic!("wrong StdError variant");
-        }
-
-        // We're expecting exactly 3 nested error types
-        // (the original error, 2 WasmMsg contexts)
-        assert_eq!(err.chain().count(), 3);
-    }
-
-    #[test]
-    fn double_nested_call() {
-        let owner = Addr::unchecked("owner");
-        let mut app = App::default();
-
-        let error_code_id = app.store_code(error::contract(true));
-        let caller_code_id = app.store_code(caller::contract());
-
-        // set up contract_helpers
-        let msg = Empty {};
-        let caller_addr1 = app
-            .instantiate_contract(caller_code_id, owner.clone(), &msg, &[], "caller", None)
-            .unwrap();
-        let caller_addr2 = app
-            .instantiate_contract(caller_code_id, owner.clone(), &msg, &[], "caller", None)
-            .unwrap();
-        let error_addr = app
-            .instantiate_contract(error_code_id, owner, &msg, &[], "error", None)
-            .unwrap();
-
-        // caller1 calls caller2, caller2 calls error
-        let msg = WasmMsg::Execute {
-            contract_addr: caller_addr2.into(),
-            msg: to_binary(&WasmMsg::Execute {
-                contract_addr: error_addr.into(),
-                msg: to_binary(&Empty {}).unwrap(),
-                funds: vec![],
-            })
-            .unwrap(),
-            funds: vec![],
-        };
-        let err = app
-            .execute_contract(Addr::unchecked("random"), caller_addr1, &msg, &[])
-            .unwrap_err();
-
-        // uncomment to have the test fail and see how the error stringifies
-        // panic!("{:?}", err);
-
-        // we can downcast to get the original error
-        let source: &StdError = err.downcast_ref().unwrap();
-        if let StdError::GenericErr { msg } = source {
-            assert_eq!(msg, "Handle failed");
-        } else {
-            panic!("wrong StdError variant");
-        }
-
-        // We're expecting exactly 4 nested error types
-        // (the original error, 3 WasmMsg contexts)
-        assert_eq!(err.chain().count(), 4);
-    }
-}
diff --git a/src/tests/gov.rs b/src/tests/gov.rs
deleted file mode 100644
index d1c9ecb..0000000
--- a/src/tests/gov.rs
+++ /dev/null
@@ -1,105 +0,0 @@
-use crate::test_helpers::{stargate, stargate::ExecMsg};
-use crate::{App, AppBuilder, AppResponse, CosmosRouter, Executor, Gov, Module};
-use cosmwasm_std::{Addr, Api, Binary, BlockInfo, Empty, GovMsg, Querier, Storage};
-
-struct AcceptingModule;
-
-impl Module for AcceptingModule {
-    type ExecT = GovMsg;
-    type QueryT = Empty;
-    type SudoT = Empty;
-
-    fn execute<ExecC, QueryC>(
-        &self,
-        _api: &dyn Api,
-        _storage: &mut dyn Storage,
-        _router: &dyn CosmosRouter<ExecC = ExecC, QueryC = QueryC>,
-        _block: &BlockInfo,
-        _sender: Addr,
-        _msg: Self::ExecT,
-    ) -> anyhow::Result<AppResponse>
-    where
-        ExecC: std::fmt::Debug
-            + Clone
-            + PartialEq
-            + schemars::JsonSchema
-            + serde::de::DeserializeOwned
-            + 'static,
-        QueryC: cosmwasm_std::CustomQuery + serde::de::DeserializeOwned + 'static,
-    {
-        Ok(AppResponse::default())
-    }
-
-    fn sudo<ExecC, QueryC>(
-        &self,
-        _api: &dyn Api,
-        _storage: &mut dyn Storage,
-        _router: &dyn CosmosRouter<ExecC = ExecC, QueryC = QueryC>,
-        _block: &BlockInfo,
-        _msg: Self::SudoT,
-    ) -> anyhow::Result<AppResponse>
-    where
-        ExecC: std::fmt::Debug
-            + Clone
-            + PartialEq
-            + schemars::JsonSchema
-            + serde::de::DeserializeOwned
-            + 'static,
-        QueryC: cosmwasm_std::CustomQuery + serde::de::DeserializeOwned + 'static,
-    {
-        Ok(AppResponse::default())
-    }
-
-    fn query(
-        &self,
-        _api: &dyn Api,
-        _storage: &dyn Storage,
-        _querier: &dyn Querier,
-        _block: &BlockInfo,
-        _request: Self::QueryT,
-    ) -> anyhow::Result<Binary> {
-        Ok(Binary::default())
-    }
-}
-
-impl Gov for AcceptingModule {}
-
-#[test]
-fn default_gov() {
-    let mut app = App::default();
-    let code = app.store_code(stargate::contract());
-    let contract = app
-        .instantiate_contract(
-            code,
-            Addr::unchecked("owner"),
-            &Empty {},
-            &[],
-            "contract",
-            None,
-        )
-        .unwrap();
-
-    app.execute_contract(Addr::unchecked("owner"), contract, &ExecMsg::Gov {}, &[])
-        .unwrap_err();
-}
-
-#[test]
-fn substituting_gov() {
-    let mut app = AppBuilder::new()
-        .with_gov(AcceptingModule)
-        .build(|_, _, _| ());
-    let code = app.store_code(stargate::contract());
-    let contract = app
-        .instantiate_contract(
-            code,
-            Addr::unchecked("owner"),
-            &Empty {},
-            &[],
-            "contract",
-            None,
-        )
-        .unwrap();
-
-    app.execute_contract(Addr::unchecked("owner"), contract, &ExecMsg::Gov {}, &[])
-        .unwrap();
-}
diff --git a/src/tests/ibc.rs b/src/tests/ibc.rs
deleted file mode 100644
index ff19651..0000000
--- a/src/tests/ibc.rs
+++ /dev/null
@@ -1,43 +0,0 @@
-use crate::test_helpers::{stargate, stargate::ExecMsg};
-use crate::{App, AppBuilder, Executor, IbcAcceptingModule};
-use cosmwasm_std::{Addr, Empty};
-
-#[test]
-fn default_ibc() {
-    let mut app = App::default();
-    let code = app.store_code(stargate::contract());
-    let contract = app
-        .instantiate_contract(
-            code,
-            Addr::unchecked("owner"),
-            &Empty {},
-            &[],
-            "contract",
-            None,
-        )
-        .unwrap();
-
-    app.execute_contract(Addr::unchecked("owner"), contract, &ExecMsg::Ibc {}, &[])
-        .unwrap_err();
-}
-
-#[test]
-fn substituting_ibc() {
-    let mut app = AppBuilder::new()
-        .with_ibc(IbcAcceptingModule)
-        .build(|_, _, _| ());
-    let code = app.store_code(stargate::contract());
-    let contract = app
-        .instantiate_contract(
-            code,
-            Addr::unchecked("owner"),
-            &Empty {},
-            &[],
-            "contract",
-            None,
-        )
-        .unwrap();
-
-    app.execute_contract(Addr::unchecked("owner"), contract, &ExecMsg::Ibc {}, &[])
-        .unwrap();
-}
diff --git a/src/tests/mod.rs b/src/tests/mod.rs
deleted file mode 100644
index cfd65cd..0000000
--- a/src/tests/mod.rs
+++ /dev/null
@@ -1,5 +0,0 @@
-#![cfg(test)]
-
-mod app;
-mod gov;
-mod ibc;
diff --git a/tests/app_builder/mod.rs b/tests/app_builder/mod.rs
deleted file mode 100644
index 42eecf3..0000000
--- a/tests/app_builder/mod.rs
+++ /dev/null
@@ -1,1 +0,0 @@
-mod with_wasm;
diff --git a/tests/app_builder/with_wasm.rs b/tests/app_builder/with_wasm.rs
deleted file mode 100644
index 2361e0a..0000000
--- a/tests/app_builder/with_wasm.rs
+++ /dev/null
@@ -1,126 +0,0 @@
-use anyhow::Result as AnyResult;
-use cosmwasm_std::{
-    Addr, Api, Binary, BlockInfo, Deps, DepsMut, Empty, Env, MessageInfo, Querier, Record,
-    Response, StdError, Storage, SubMsg, WasmMsg, WasmQuery,
-};
-use cw_multi_test::{
-    AppBuilder, AppResponse, Contract, ContractData, ContractWrapper, CosmosRouter, Wasm,
-};
-use schemars::JsonSchema;
-use std::fmt::Debug;
-use std::marker::PhantomData;
-
-mod contracts {
-    use super::*;
-
-    pub mod caller {
-        use super::*;
-
-        fn instantiate(
-            _deps: DepsMut,
-            _env: Env,
-            _info: MessageInfo,
-            _msg: Empty,
-        ) -> Result<Response, StdError> {
-            Ok(Response::default())
-        }
-
-        fn execute(
-            _deps: DepsMut,
-            _env: Env,
-            _info: MessageInfo,
-            msg: WasmMsg,
-        ) -> Result<Response, StdError> {
-            let message = SubMsg::new(msg);
-
-            Ok(Response::new().add_submessage(message))
-        }
-
-        fn query(_deps: Deps, _env: Env, _msg: Empty) -> Result<Binary, StdError> {
-            Err(StdError::generic_err(
-                "query not implemented for the `caller` contract",
-            ))
-        }
-
-        pub fn contract<C>() -> Box<dyn Contract<C>>
-        where
-            C: Clone + Debug + PartialEq + JsonSchema + 'static,
-        {
-            let contract = ContractWrapper::new_with_empty(execute, instantiate, query);
-            Box::new(contract)
-        }
-    }
-}
-
-#[test]
-fn building_app_with_custom_wasm_should_work() {
-    struct MyWasm<ExecT, QueryT>(PhantomData<(ExecT, QueryT)>);
-
-    impl<ExecT, QueryT> Default for MyWasm<ExecT, QueryT> {
-        fn default() -> Self {
-            Self(PhantomData)
-        }
-    }
-
-    impl<ExecT, QueryT> Wasm<ExecT, QueryT> for MyWasm<ExecT, QueryT> {
-        fn query(
-            &self,
-            _api: &dyn Api,
-            _storage: &dyn Storage,
-            _querier: &dyn Querier,
-            _block: &BlockInfo,
-            _request: WasmQuery,
-        ) -> AnyResult<Binary> {
-            todo!()
-        }
-
-        fn execute(
-            &self,
-            _api: &dyn Api,
-            _storage: &mut dyn Storage,
-            _router: &dyn CosmosRouter<ExecC = ExecT, QueryC = QueryT>,
-            _block: &BlockInfo,
-            _sender: Addr,
-            _msg: WasmMsg,
-        ) -> AnyResult<AppResponse> {
-            todo!()
-        }
-
-        fn sudo(
-            &self,
-            _api: &dyn Api,
-            _contract_addr: Addr,
-            _storage: &mut dyn Storage,
-            _router: &dyn CosmosRouter<ExecC = ExecT, QueryC = QueryT>,
-            _block: &BlockInfo,
-            _msg: Binary,
-        ) -> AnyResult<AppResponse> {
-            todo!()
-        }
-
-        fn store_code(&mut self, _creator: Addr, _code: Box<dyn Contract<ExecT, QueryT>>) -> u64 {
-            154
-        }
-
-        fn duplicate_code(&mut self, _code_id: u64) -> AnyResult<u64> {
-            todo!()
-        }
-
-        fn contract_data(
-            &self,
-            _storage: &dyn Storage,
-            _address: &Addr,
-        ) -> AnyResult<ContractData> {
-            todo!()
-        }
-
-        fn dump_wasm_raw(&self, _storage: &dyn Storage, _address: &Addr) -> Vec<Record> {
-            todo!()
-        }
-    }
-
-    let app_builder = AppBuilder::default();
-    let mut app = app_builder.with_wasm(MyWasm::default()).build(|_, _, _| {});
-    let code_id = app.store_code(contracts::caller::contract());
-    assert_eq!(154, code_id);
-}
diff --git a/tests/mod.rs b/tests/mod.rs
deleted file mode 100644
index a641a2e..0000000
--- a/tests/mod.rs
+++ /dev/null
@@ -1,1 +0,0 @@
-mod app_builder;