Repository: CosmWasm/cosmwasm
Pull request #1076 (2021-09-06 22:03:07)

Move generic type to QuerierWrapper and Deps
Moves the generic type for the custom query from the `custom_query` method to the QuerierWrapper instance. This way we gain type safety once a QuerierWrapper is created.

By constructing QuerierWrapper on demand in `Deps::custom_querier()` we keep deps free of this generic.

ethanfrey: This doesn't really address my use case, but did inspire me. I added a few more comments on #1075
webmaster128: Added one more commit. This moves the generic type to deps and has to be added to all entry points as well. This is heavy but seems to be okay from the user's perspective.
ethanfrey: BTW, you have to use Clone not Copy as PhantomData<C> requires that C implement Clone or Copy, right? Even though that is not really needed on the runtime.

If that is the case, since you already have a lifetime, you should be able to use PhantomData<&'a C> which always has Clone and Copy like any non mutable reference. At least I remember doing something like this in the past
webmaster128: > BTW, you have to use Clone not Copy as PhantomData requires that C implement Clone or Copy, right?

No. The primary motivation is then `#[derive(Copy)]` on a type with generic `C` only implements `Copy` for `C: Copy`. I.e. an `impl<C: Copy> Copy for MyType<C>` is derived. Since our `CustomQuery` is not `Copy`, `#[derive(Copy)]` does nothing on `QuerierWrapper` and `Deps`. It would be possible to implement `Copy` manually for all `C`.

I wonder if we really want to guarantee that such complex types can always implement Copy. Maybe it works now. With Clone we are much more flexible.
ethanfrey: I agree. We do not want to require C: Copy. That would be bad.

But we can require &C implements Copy as that is given for all C.
webmaster128: @ethanfrey please have a look at the last commit 64d61a6. There you see what it takes to keep the Copy implementation. This is not so much about PhantomData.

The main question is if we WANT to implement Copy for those types. This comes with the restriction that we can never add any field that is not Copy. My feeling is no, because they are too complex. But it is possible.
ethanfrey: I looked at this, and then tried modifying it to `PhantomData<&'a C>` and deriving Copy. Which failed (as you found out already).

Seemed odd, as PhantomData [always implements Copy](https://doc.rust-lang.org/std/marker/struct.PhantomData.html#impl-Copy).  As well as [&T for all T](https://doc.rust-lang.org/std/marker/trait.Copy.html#impl-Copy-72). 

But this is a limitation of device, not Copy, as explained here: https://stackoverflow.com/a/60907370

Since this is just about the issues with derive macro, and the manual implementation will fail if we add a field that does not implement Copy, I think your solution in https://github.com/CosmWasm/cosmwasm/commit/64d61a65a0e3bf05575cf461ee7fc0a739de94df is nice and least API breaking, most flexible to work with. I tested this, by adding a fake String to the type, and got this error:

```
error[E0204]: the trait `Copy` may not be implemented for this type
   --> packages/std/src/traits.rs:149:26
    |
142 |     foo: String,
    |     ----------- this field does not implement `Copy`
...
149 | impl<'a, C: CustomQuery> Copy for QuerierWrapper<'a, C> {}
    |                          ^^^^

error: aborting due to previous error
```

All in all, I think this is a very nice PR, which adds type safety for contracts that use custom queries and has zero impact for contract developers who do not.

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c60c40102..d9e114341 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -12,6 +12,15 @@ and this project adheres to
   flag is set (enabled by default).
 - cosmwasm-vm: Increase `MAX_LENGTH_HUMAN_ADDRESS` from 90 to 256 in order to
   support longer address formats than bech32.
+- cosmwasm-std: Make `CustomQuery` a subtrait of `Clone`, i.e. types that
+  implement `CustomQuery` need to be `Clone`able.
+- cosmwasm-std: Add generic for custom query type to `QuerierWrapper`, `Deps`,
+  `DepsMut` and `OwnedDeps`. Merge `QuerierWrapper::custom_query` into the now
+  fully typed `QuerierWrapper::query`.
+- cosmwasm-std: Add generic type `Q` for the custom query request type to
+  `do_instantiate`, `do_execute`, `do_migrate`, `do_sudo`, `do_reply`,
+  `do_query`, `ibc_channel_open`, `ibc_channel_connect`, `ibc_channel_close`,
+  `ibc_packet_receive`, `ibc_packet_ack` and `ibc_packet_timeout`.
 
 ### Removed
 
diff --git a/contracts/reflect/src/contract.rs b/contracts/reflect/src/contract.rs
index 02bfa51d8..3528e5635 100644
--- a/contracts/reflect/src/contract.rs
+++ b/contracts/reflect/src/contract.rs
@@ -12,7 +12,7 @@ use crate::msg::{
 use crate::state::{config, config_read, replies, replies_read, State};
 
 pub fn instantiate(
-    deps: DepsMut,
+    deps: DepsMut<SpecialQuery>,
     _env: Env,
     info: MessageInfo,
     _msg: InstantiateMsg,
@@ -23,7 +23,7 @@ pub fn instantiate(
 }
 
 pub fn execute(
-    deps: DepsMut,
+    deps: DepsMut<SpecialQuery>,
     env: Env,
     info: MessageInfo,
     msg: ExecuteMsg,
@@ -36,7 +36,7 @@ pub fn execute(
 }
 
 pub fn try_reflect(
-    deps: DepsMut,
+    deps: DepsMut<SpecialQuery>,
     _env: Env,
     info: MessageInfo,
     msgs: Vec<CosmosMsg<CustomMsg>>,
@@ -60,7 +60,7 @@ pub fn try_reflect(
 }
 
 pub fn try_reflect_subcall(
-    deps: DepsMut,
+    deps: DepsMut<SpecialQuery>,
     _env: Env,
     info: MessageInfo,
     msgs: Vec<SubMsg<CustomMsg>>,
@@ -83,7 +83,7 @@ pub fn try_reflect_subcall(
 }
 
 pub fn try_change_owner(
-    deps: DepsMut,
+    deps: DepsMut<SpecialQuery>,
     _env: Env,
     info: MessageInfo,
     new_owner: String,
@@ -106,13 +106,13 @@ pub fn try_change_owner(
 
 /// This just stores the result for future query
 #[entry_point]
-pub fn reply(deps: DepsMut, _env: Env, msg: Reply) -> Result<Response, ReflectError> {
+pub fn reply(deps: DepsMut<SpecialQuery>, _env: Env, msg: Reply) -> Result<Response, ReflectError> {
     let key = msg.id.to_be_bytes();
     replies(deps.storage).save(&key, &msg)?;
     Ok(Response::default())
 }
 
-pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult<QueryResponse> {
+pub fn query(deps: Deps<SpecialQuery>, _env: Env, msg: QueryMsg) -> StdResult<QueryResponse> {
     match msg {
         QueryMsg::Owner {} => to_binary(&query_owner(deps)?),
         QueryMsg::Capitalized { text } => to_binary(&query_capitalized(deps, text)?),
@@ -122,7 +122,7 @@ pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult<QueryResponse> {
     }
 }
 
-fn query_owner(deps: Deps) -> StdResult<OwnerResponse> {
+fn query_owner(deps: Deps<SpecialQuery>) -> StdResult<OwnerResponse> {
     let state = config_read(deps.storage).load()?;
     let resp = OwnerResponse {
         owner: state.owner.into(),
@@ -130,18 +130,21 @@ fn query_owner(deps: Deps) -> StdResult<OwnerResponse> {
     Ok(resp)
 }
 
-fn query_subcall(deps: Deps, id: u64) -> StdResult<Reply> {
+fn query_subcall(deps: Deps<SpecialQuery>, id: u64) -> StdResult<Reply> {
     let key = id.to_be_bytes();
     replies_read(deps.storage).load(&key)
 }
 
-fn query_capitalized(deps: Deps, text: String) -> StdResult<CapitalizedResponse> {
+fn query_capitalized(deps: Deps<SpecialQuery>, text: String) -> StdResult<CapitalizedResponse> {
     let req = SpecialQuery::Capitalized { text }.into();
-    let response: SpecialResponse = deps.querier.custom_query(&req)?;
+    let response: SpecialResponse = deps.querier.query(&req)?;
     Ok(CapitalizedResponse { text: response.msg })
 }
 
-fn query_chain(deps: Deps, request: &QueryRequest<SpecialQuery>) -> StdResult<ChainResponse> {
+fn query_chain(
+    deps: Deps<SpecialQuery>,
+    request: &QueryRequest<SpecialQuery>,
+) -> StdResult<ChainResponse> {
     let raw = to_vec(request).map_err(|serialize_err| {
         StdError::generic_err(format!("Serializing QueryRequest: {}", serialize_err))
     })?;
@@ -158,7 +161,7 @@ fn query_chain(deps: Deps, request: &QueryRequest<SpecialQuery>) -> StdResult<Ch
     }
 }
 
-fn query_raw(deps: Deps, contract: String, key: Binary) -> StdResult<RawResponse> {
+fn query_raw(deps: Deps<SpecialQuery>, contract: String, key: Binary) -> StdResult<RawResponse> {
     let response: Option<Vec<u8>> = deps.querier.query_wasm_raw(contract, key)?;
     Ok(RawResponse {
         data: response.unwrap_or_default().into(),
diff --git a/devtools/check_workspace.sh b/devtools/check_workspace.sh
index 713ab9e40..5b5c856bb 100755
--- a/devtools/check_workspace.sh
+++ b/devtools/check_workspace.sh
@@ -4,7 +4,15 @@ command -v shellcheck >/dev/null && shellcheck "$0"
 
 cargo fmt
 (cd packages/crypto && cargo build && cargo clippy --all-targets -- -D warnings)
-(cd packages/std && cargo wasm-debug --features iterator && cargo clippy --all-targets --features iterator -- -D warnings && cargo schema)
+(
+  cd packages/std
+  cargo check
+  cargo check --features iterator,staking,stargate
+  cargo wasm-debug
+  cargo wasm-debug --features iterator,staking,stargate
+  cargo clippy --all-targets --features iterator,staking,stargate -- -D warnings
+  cargo schema
+)
 (cd packages/storage && cargo build && cargo clippy --all-targets --features iterator -- -D warnings)
 (cd packages/schema && cargo build && cargo clippy --all-targets -- -D warnings)
 (cd packages/vm && cargo build --features iterator,stargate && cargo clippy --all-targets --features iterator,stargate -- -D warnings)
diff --git a/packages/std/src/deps.rs b/packages/std/src/deps.rs
index 4dfff8030..1569e383c 100644
--- a/packages/std/src/deps.rs
+++ b/packages/std/src/deps.rs
@@ -1,3 +1,7 @@
+use std::marker::PhantomData;
+
+use crate::query::CustomQuery;
+use crate::results::Empty;
 use crate::traits::{Api, Querier, Storage};
 use crate::QuerierWrapper;
 
@@ -5,27 +9,34 @@ use crate::QuerierWrapper;
 /// Designed to allow easy dependency injection at runtime.
 /// This cannot be copied or cloned since it would behave differently
 /// for mock storages and a bridge storage in the VM.
-pub struct OwnedDeps<S: Storage, A: Api, Q: Querier> {
+pub struct OwnedDeps<S: Storage, A: Api, Q: Querier, C: CustomQuery = Empty> {
     pub storage: S,
     pub api: A,
     pub querier: Q,
+    pub custom_query_type: PhantomData<C>,
 }
 
-pub struct DepsMut<'a> {
+pub struct DepsMut<'a, C: CustomQuery = Empty> {
     pub storage: &'a mut dyn Storage,
     pub api: &'a dyn Api,
-    pub querier: QuerierWrapper<'a>,
+    pub querier: QuerierWrapper<'a, C>,
 }
 
-#[derive(Copy, Clone)]
-pub struct Deps<'a> {
+#[derive(Clone)]
+pub struct Deps<'a, C: CustomQuery = Empty> {
     pub storage: &'a dyn Storage,
     pub api: &'a dyn Api,
-    pub querier: QuerierWrapper<'a>,
+    pub querier: QuerierWrapper<'a, C>,
 }
 
-impl<S: Storage, A: Api, Q: Querier> OwnedDeps<S, A, Q> {
-    pub fn as_ref(&'_ self) -> Deps<'_> {
+// Use custom implementation on order to implement Copy in case `C` is not `Copy`.
+// See "There is a small difference between the two: the derive strategy will also
+// place a Copy bound on type parameters, which isn’t always desired."
+// https://doc.rust-lang.org/std/marker/trait.Copy.html
+impl<'a, C: CustomQuery> Copy for Deps<'a, C> {}
+
+impl<S: Storage, A: Api, Q: Querier, C: CustomQuery> OwnedDeps<S, A, Q, C> {
+    pub fn as_ref(&'_ self) -> Deps<'_, C> {
         Deps {
             storage: &self.storage,
             api: &self.api,
@@ -33,7 +44,7 @@ impl<S: Storage, A: Api, Q: Querier> OwnedDeps<S, A, Q> {
         }
     }
 
-    pub fn as_mut(&'_ mut self) -> DepsMut<'_> {
+    pub fn as_mut(&'_ mut self) -> DepsMut<'_, C> {
         DepsMut {
             storage: &mut self.storage,
             api: &self.api,
@@ -42,8 +53,8 @@ impl<S: Storage, A: Api, Q: Querier> OwnedDeps<S, A, Q> {
     }
 }
 
-impl<'a> DepsMut<'a> {
-    pub fn as_ref(&'_ self) -> Deps<'_> {
+impl<'a, C: CustomQuery> DepsMut<'a, C> {
+    pub fn as_ref(&'_ self) -> Deps<'_, C> {
         Deps {
             storage: self.storage,
             api: self.api,
@@ -51,7 +62,7 @@ impl<'a> DepsMut<'a> {
         }
     }
 
-    pub fn branch(&'_ mut self) -> DepsMut<'_> {
+    pub fn branch(&'_ mut self) -> DepsMut<'_, C> {
         DepsMut {
             storage: self.storage,
             api: self.api,
@@ -63,7 +74,8 @@ impl<'a> DepsMut<'a> {
 #[cfg(test)]
 mod tests {
     use super::*;
-    use crate::mock::mock_dependencies;
+    use crate::mock::{mock_dependencies, MockApi, MockQuerier, MockStorage};
+    use serde::{Deserialize, Serialize};
 
     // ensure we can call these many times, eg. as sub-calls
     fn execute(mut deps: DepsMut) {
@@ -85,4 +97,34 @@ mod tests {
         execute(deps.as_mut());
         query(deps.as_ref())
     }
+
+    #[test]
+    fn deps_implements_copy() {
+        impl CustomQuery for u64 {}
+        #[derive(Clone, Serialize, Deserialize)]
+        struct MyQuery;
+        impl CustomQuery for MyQuery {}
+
+        // With C: Copy
+        let owned = OwnedDeps::<_, _, _, u64> {
+            storage: MockStorage::default(),
+            api: MockApi::default(),
+            querier: MockQuerier::<u64>::new(&[]),
+            custom_query_type: PhantomData,
+        };
+        let deps: Deps<u64> = owned.as_ref();
+        let _copy1 = deps;
+        let _copy2 = deps;
+
+        // Without C: Copy
+        let owned = OwnedDeps::<_, _, _, MyQuery> {
+            storage: MockStorage::default(),
+            api: MockApi::default(),
+            querier: MockQuerier::<MyQuery>::new(&[]),
+            custom_query_type: PhantomData,
+        };
+        let deps: Deps<MyQuery> = owned.as_ref();
+        let _copy1 = deps;
+        let _copy2 = deps;
+    }
 }
diff --git a/packages/std/src/exports.rs b/packages/std/src/exports.rs
index 0745d7d19..c41a3c224 100644
--- a/packages/std/src/exports.rs
+++ b/packages/std/src/exports.rs
@@ -8,14 +8,21 @@
 //! the contract-specific function pointer. This is done via the `#[entry_point]`
 //! macro attribute from cosmwasm-derive.
 use std::fmt;
+use std::marker::PhantomData;
 use std::vec::Vec;
 
 use schemars::JsonSchema;
 use serde::{de::DeserializeOwned, Serialize};
 
 use crate::deps::OwnedDeps;
+#[cfg(feature = "stargate")]
+use crate::ibc::{
+    IbcBasicResponse, IbcChannelCloseMsg, IbcChannelConnectMsg, IbcChannelOpenMsg, IbcPacketAckMsg,
+    IbcPacketReceiveMsg, IbcPacketTimeoutMsg, IbcReceiveResponse,
+};
 use crate::imports::{ExternalApi, ExternalQuerier, ExternalStorage};
 use crate::memory::{alloc, consume_region, release_buffer, Region};
+use crate::query::CustomQuery;
 use crate::results::{ContractResult, QueryResponse, Reply, Response};
 use crate::serde::{from_slice, to_vec};
 use crate::types::Env;
@@ -72,16 +79,18 @@ macro_rules! r#try_into_contract_result {
 
 /// This should be wrapped in an external "C" export, containing a contract-specific function as an argument.
 ///
+/// - `Q`: custom query type (see QueryRequest)
 /// - `M`: message type for request
 /// - `C`: custom response message type (see CosmosMsg)
 /// - `E`: error type for responses
-pub fn do_instantiate<M, C, E>(
-    instantiate_fn: &dyn Fn(DepsMut, Env, MessageInfo, M) -> Result<Response<C>, E>,
+pub fn do_instantiate<Q, M, C, E>(
+    instantiate_fn: &dyn Fn(DepsMut<Q>, Env, MessageInfo, M) -> Result<Response<C>, E>,
     env_ptr: u32,
     info_ptr: u32,
     msg_ptr: u32,
 ) -> u32
 where
+    Q: CustomQuery,
     M: DeserializeOwned + JsonSchema,
     C: Serialize + Clone + fmt::Debug + PartialEq + JsonSchema,
     E: ToString,
@@ -98,16 +107,18 @@ where
 
 /// do_execute should be wrapped in an external "C" export, containing a contract-specific function as arg
 ///
+/// - `Q`: custom query type (see QueryRequest)
 /// - `M`: message type for request
 /// - `C`: custom response message type (see CosmosMsg)
 /// - `E`: error type for responses
-pub fn do_execute<M, C, E>(
-    execute_fn: &dyn Fn(DepsMut, Env, MessageInfo, M) -> Result<Response<C>, E>,
+pub fn do_execute<Q, M, C, E>(
+    execute_fn: &dyn Fn(DepsMut<Q>, Env, MessageInfo, M) -> Result<Response<C>, E>,
     env_ptr: u32,
     info_ptr: u32,
     msg_ptr: u32,
 ) -> u32
 where
+    Q: CustomQuery,
     M: DeserializeOwned + JsonSchema,
     C: Serialize + Clone + fmt::Debug + PartialEq + JsonSchema,
     E: ToString,
@@ -124,15 +135,17 @@ where
 
 /// do_migrate should be wrapped in an external "C" export, containing a contract-specific function as arg
 ///
+/// - `Q`: custom query type (see QueryRequest)
 /// - `M`: message type for request
 /// - `C`: custom response message type (see CosmosMsg)
 /// - `E`: error type for responses
-pub fn do_migrate<M, C, E>(
-    migrate_fn: &dyn Fn(DepsMut, Env, M) -> Result<Response<C>, E>,
+pub fn do_migrate<Q, M, C, E>(
+    migrate_fn: &dyn Fn(DepsMut<Q>, Env, M) -> Result<Response<C>, E>,
     env_ptr: u32,
     msg_ptr: u32,
 ) -> u32
 where
+    Q: CustomQuery,
     M: DeserializeOwned + JsonSchema,
     C: Serialize + Clone + fmt::Debug + PartialEq + JsonSchema,
     E: ToString,
@@ -144,15 +157,17 @@ where
 
 /// do_sudo should be wrapped in an external "C" export, containing a contract-specific function as arg
 ///
+/// - `Q`: custom query type (see QueryRequest)
 /// - `M`: message type for request
 /// - `C`: custom response message type (see CosmosMsg)
 /// - `E`: error type for responses
-pub fn do_sudo<M, C, E>(
-    sudo_fn: &dyn Fn(DepsMut, Env, M) -> Result<Response<C>, E>,
+pub fn do_sudo<Q, M, C, E>(
+    sudo_fn: &dyn Fn(DepsMut<Q>, Env, M) -> Result<Response<C>, E>,
     env_ptr: u32,
     msg_ptr: u32,
 ) -> u32
 where
+    Q: CustomQuery,
     M: DeserializeOwned + JsonSchema,
     C: Serialize + Clone + fmt::Debug + PartialEq + JsonSchema,
     E: ToString,
@@ -164,14 +179,17 @@ where
 
 /// do_reply should be wrapped in an external "C" export, containing a contract-specific function as arg
 /// message body is always `SubcallResult`
+///
+/// - `Q`: custom query type (see QueryRequest)
 /// - `C`: custom response message type (see CosmosMsg)
 /// - `E`: error type for responses
-pub fn do_reply<C, E>(
-    reply_fn: &dyn Fn(DepsMut, Env, Reply) -> Result<Response<C>, E>,
+pub fn do_reply<Q, C, E>(
+    reply_fn: &dyn Fn(DepsMut<Q>, Env, Reply) -> Result<Response<C>, E>,
     env_ptr: u32,
     msg_ptr: u32,
 ) -> u32
 where
+    Q: CustomQuery,
     C: Serialize + Clone + fmt::Debug + PartialEq + JsonSchema,
     E: ToString,
 {
@@ -182,14 +200,16 @@ where
 
 /// do_query should be wrapped in an external "C" export, containing a contract-specific function as arg
 ///
+/// - `Q`: custom query type (see QueryRequest)
 /// - `M`: message type for request
 /// - `E`: error type for responses
-pub fn do_query<M, E>(
-    query_fn: &dyn Fn(Deps, Env, M) -> Result<QueryResponse, E>,
+pub fn do_query<Q, M, E>(
+    query_fn: &dyn Fn(Deps<Q>, Env, M) -> Result<QueryResponse, E>,
     env_ptr: u32,
     msg_ptr: u32,
 ) -> u32
 where
+    Q: CustomQuery,
     M: DeserializeOwned + JsonSchema,
     E: ToString,
 {
@@ -198,13 +218,154 @@ where
     release_buffer(v) as u32
 }
 
-fn _do_instantiate<M, C, E>(
-    instantiate_fn: &dyn Fn(DepsMut, Env, MessageInfo, M) -> Result<Response<C>, E>,
+/// do_ibc_channel_open is designed for use with #[entry_point] to make a "C" extern
+///
+/// contract_fn does the protocol version negotiation during channel handshake phase
+///
+/// - `Q`: custom query type (see QueryRequest)
+/// - `E`: error type for responses
+#[cfg(feature = "stargate")]
+pub fn do_ibc_channel_open<Q, E>(
+    contract_fn: &dyn Fn(DepsMut<Q>, Env, IbcChannelOpenMsg) -> Result<(), E>,
+    env_ptr: u32,
+    msg_ptr: u32,
+) -> u32
+where
+    Q: CustomQuery,
+    E: ToString,
+{
+    let res = _do_ibc_channel_open(contract_fn, env_ptr as *mut Region, msg_ptr as *mut Region);
+    let v = to_vec(&res).unwrap();
+    release_buffer(v) as u32
+}
+
+/// do_ibc_channel_connect is designed for use with #[entry_point] to make a "C" extern
+///
+/// contract_fn is a callback when a IBC channel is established (after both sides agree in open)
+///
+/// - `Q`: custom query type (see QueryRequest)
+/// - `C`: custom response message type (see CosmosMsg)
+/// - `E`: error type for responses
+#[cfg(feature = "stargate")]
+pub fn do_ibc_channel_connect<Q, C, E>(
+    contract_fn: &dyn Fn(DepsMut<Q>, Env, IbcChannelConnectMsg) -> Result<IbcBasicResponse<C>, E>,
+    env_ptr: u32,
+    msg_ptr: u32,
+) -> u32
+where
+    Q: CustomQuery,
+    C: Serialize + Clone + fmt::Debug + PartialEq + JsonSchema,
+    E: ToString,
+{
+    let res = _do_ibc_channel_connect(contract_fn, env_ptr as *mut Region, msg_ptr as *mut Region);
+    let v = to_vec(&res).unwrap();
+    release_buffer(v) as u32
+}
+
+/// do_ibc_channel_close is designed for use with #[entry_point] to make a "C" extern
+///
+/// contract_fn is a callback when a IBC channel belonging to this contract is closed
+///
+/// - `Q`: custom query type (see QueryRequest)
+/// - `C`: custom response message type (see CosmosMsg)
+/// - `E`: error type for responses
+#[cfg(feature = "stargate")]
+pub fn do_ibc_channel_close<Q, C, E>(
+    contract_fn: &dyn Fn(DepsMut<Q>, Env, IbcChannelCloseMsg) -> Result<IbcBasicResponse<C>, E>,
+    env_ptr: u32,
+    msg_ptr: u32,
+) -> u32
+where
+    Q: CustomQuery,
+    C: Serialize + Clone + fmt::Debug + PartialEq + JsonSchema,
+    E: ToString,
+{
+    let res = _do_ibc_channel_close(contract_fn, env_ptr as *mut Region, msg_ptr as *mut Region);
+    let v = to_vec(&res).unwrap();
+    release_buffer(v) as u32
+}
+
+/// do_ibc_packet_receive is designed for use with #[entry_point] to make a "C" extern
+///
+/// contract_fn is called when this chain receives an IBC Packet on a channel belonging
+/// to this contract
+///
+/// - `Q`: custom query type (see QueryRequest)
+/// - `C`: custom response message type (see CosmosMsg)
+/// - `E`: error type for responses
+#[cfg(feature = "stargate")]
+pub fn do_ibc_packet_receive<Q, C, E>(
+    contract_fn: &dyn Fn(DepsMut<Q>, Env, IbcPacketReceiveMsg) -> Result<IbcReceiveResponse<C>, E>,
+    env_ptr: u32,
+    msg_ptr: u32,
+) -> u32
+where
+    Q: CustomQuery,
+    C: Serialize + Clone + fmt::Debug + PartialEq + JsonSchema,
+    E: ToString,
+{
+    let res = _do_ibc_packet_receive(contract_fn, env_ptr as *mut Region, msg_ptr as *mut Region);
+    let v = to_vec(&res).unwrap();
+    release_buffer(v) as u32
+}
+
+/// do_ibc_packet_ack is designed for use with #[entry_point] to make a "C" extern
+///
+/// contract_fn is called when this chain receives an IBC Acknowledgement for a packet
+/// that this contract previously sent
+///
+/// - `Q`: custom query type (see QueryRequest)
+/// - `C`: custom response message type (see CosmosMsg)
+/// - `E`: error type for responses
+#[cfg(feature = "stargate")]
+pub fn do_ibc_packet_ack<Q, C, E>(
+    contract_fn: &dyn Fn(DepsMut<Q>, Env, IbcPacketAckMsg) -> Result<IbcBasicResponse<C>, E>,
+    env_ptr: u32,
+    msg_ptr: u32,
+) -> u32
+where
+    Q: CustomQuery,
+    C: Serialize + Clone + fmt::Debug + PartialEq + JsonSchema,
+    E: ToString,
+{
+    let res = _do_ibc_packet_ack(contract_fn, env_ptr as *mut Region, msg_ptr as *mut Region);
+    let v = to_vec(&res).unwrap();
+    release_buffer(v) as u32
+}
+
+/// do_ibc_packet_timeout is designed for use with #[entry_point] to make a "C" extern
+///
+/// contract_fn is called when a packet that this contract previously sent has provably
+/// timedout and will never be relayed to the calling chain. This generally behaves
+/// like ick_ack_fn upon an acknowledgement containing an error.
+///
+/// - `Q`: custom query type (see QueryRequest)
+/// - `C`: custom response message type (see CosmosMsg)
+/// - `E`: error type for responses
+#[cfg(feature = "stargate")]
+pub fn do_ibc_packet_timeout<Q, C, E>(
+    contract_fn: &dyn Fn(DepsMut<Q>, Env, IbcPacketTimeoutMsg) -> Result<IbcBasicResponse<C>, E>,
+    env_ptr: u32,
+    msg_ptr: u32,
+) -> u32
+where
+    Q: CustomQuery,
+    C: Serialize + Clone + fmt::Debug + PartialEq + JsonSchema,
+    E: ToString,
+{
+    let res = _do_ibc_packet_timeout(contract_fn, env_ptr as *mut Region, msg_ptr as *mut Region);
+    let v = to_vec(&res).unwrap();
+    release_buffer(v) as u32
+}
+
+fn _do_instantiate<Q, M, C, E>(
+    instantiate_fn: &dyn Fn(DepsMut<Q>, Env, MessageInfo, M) -> Result<Response<C>, E>,
     env_ptr: *mut Region,
     info_ptr: *mut Region,
     msg_ptr: *mut Region,
 ) -> ContractResult<Response<C>>
 where
+    Q: CustomQuery,
     M: DeserializeOwned + JsonSchema,
     C: Serialize + Clone + fmt::Debug + PartialEq + JsonSchema,
     E: ToString,
@@ -221,13 +382,14 @@ where
     instantiate_fn(deps.as_mut(), env, info, msg).into()
 }
 
-fn _do_execute<M, C, E>(
-    execute_fn: &dyn Fn(DepsMut, Env, MessageInfo, M) -> Result<Response<C>, E>,
+fn _do_execute<Q, M, C, E>(
+    execute_fn: &dyn Fn(DepsMut<Q>, Env, MessageInfo, M) -> Result<Response<C>, E>,
     env_ptr: *mut Region,
     info_ptr: *mut Region,
     msg_ptr: *mut Region,
 ) -> ContractResult<Response<C>>
 where
+    Q: CustomQuery,
     M: DeserializeOwned + JsonSchema,
     C: Serialize + Clone + fmt::Debug + PartialEq + JsonSchema,
     E: ToString,
@@ -244,12 +406,13 @@ where
     execute_fn(deps.as_mut(), env, info, msg).into()
 }
 
-fn _do_migrate<M, C, E>(
-    migrate_fn: &dyn Fn(DepsMut, Env, M) -> Result<Response<C>, E>,
+fn _do_migrate<Q, M, C, E>(
+    migrate_fn: &dyn Fn(DepsMut<Q>, Env, M) -> Result<Response<C>, E>,
     env_ptr: *mut Region,
     msg_ptr: *mut Region,
 ) -> ContractResult<Response<C>>
 where
+    Q: CustomQuery,
     M: DeserializeOwned + JsonSchema,
     C: Serialize + Clone + fmt::Debug + PartialEq + JsonSchema,
     E: ToString,
@@ -264,12 +427,13 @@ where
     migrate_fn(deps.as_mut(), env, msg).into()
 }
 
-fn _do_sudo<M, C, E>(
-    sudo_fn: &dyn Fn(DepsMut, Env, M) -> Result<Response<C>, E>,
+fn _do_sudo<Q, M, C, E>(
+    sudo_fn: &dyn Fn(DepsMut<Q>, Env, M) -> Result<Response<C>, E>,
     env_ptr: *mut Region,
     msg_ptr: *mut Region,
 ) -> ContractResult<Response<C>>
 where
+    Q: CustomQuery,
     M: DeserializeOwned + JsonSchema,
     C: Serialize + Clone + fmt::Debug + PartialEq + JsonSchema,
     E: ToString,
@@ -284,12 +448,13 @@ where
     sudo_fn(deps.as_mut(), env, msg).into()
 }
 
-fn _do_reply<C, E>(
-    reply_fn: &dyn Fn(DepsMut, Env, Reply) -> Result<Response<C>, E>,
+fn _do_reply<Q, C, E>(
+    reply_fn: &dyn Fn(DepsMut<Q>, Env, Reply) -> Result<Response<C>, E>,
     env_ptr: *mut Region,
     msg_ptr: *mut Region,
 ) -> ContractResult<Response<C>>
 where
+    Q: CustomQuery,
     C: Serialize + Clone + fmt::Debug + PartialEq + JsonSchema,
     E: ToString,
 {
@@ -303,12 +468,13 @@ where
     reply_fn(deps.as_mut(), env, msg).into()
 }
 
-fn _do_query<M, E>(
-    query_fn: &dyn Fn(Deps, Env, M) -> Result<QueryResponse, E>,
+fn _do_query<Q, M, E>(
+    query_fn: &dyn Fn(Deps<Q>, Env, M) -> Result<QueryResponse, E>,
     env_ptr: *mut Region,
     msg_ptr: *mut Region,
 ) -> ContractResult<QueryResponse>
 where
+    Q: CustomQuery,
     M: DeserializeOwned + JsonSchema,
     E: ToString,
 {
@@ -322,11 +488,140 @@ where
     query_fn(deps.as_ref(), env, msg).into()
 }
 
+#[cfg(feature = "stargate")]
+fn _do_ibc_channel_open<Q, E>(
+    contract_fn: &dyn Fn(DepsMut<Q>, Env, IbcChannelOpenMsg) -> Result<(), E>,
+    env_ptr: *mut Region,
+    msg_ptr: *mut Region,
+) -> ContractResult<()>
+where
+    Q: CustomQuery,
+    E: ToString,
+{
+    let env: Vec<u8> = unsafe { consume_region(env_ptr) };
+    let msg: Vec<u8> = unsafe { consume_region(msg_ptr) };
+
+    let env: Env = try_into_contract_result!(from_slice(&env));
+    let msg: IbcChannelOpenMsg = try_into_contract_result!(from_slice(&msg));
+
+    let mut deps = make_dependencies();
+    contract_fn(deps.as_mut(), env, msg).into()
+}
+
+#[cfg(feature = "stargate")]
+fn _do_ibc_channel_connect<Q, C, E>(
+    contract_fn: &dyn Fn(DepsMut<Q>, Env, IbcChannelConnectMsg) -> Result<IbcBasicResponse<C>, E>,
+    env_ptr: *mut Region,
+    msg_ptr: *mut Region,
+) -> ContractResult<IbcBasicResponse<C>>
+where
+    Q: CustomQuery,
+    C: Serialize + Clone + fmt::Debug + PartialEq + JsonSchema,
+    E: ToString,
+{
+    let env: Vec<u8> = unsafe { consume_region(env_ptr) };
+    let msg: Vec<u8> = unsafe { consume_region(msg_ptr) };
+
+    let env: Env = try_into_contract_result!(from_slice(&env));
+    let msg: IbcChannelConnectMsg = try_into_contract_result!(from_slice(&msg));
+
+    let mut deps = make_dependencies();
+    contract_fn(deps.as_mut(), env, msg).into()
+}
+
+#[cfg(feature = "stargate")]
+fn _do_ibc_channel_close<Q, C, E>(
+    contract_fn: &dyn Fn(DepsMut<Q>, Env, IbcChannelCloseMsg) -> Result<IbcBasicResponse<C>, E>,
+    env_ptr: *mut Region,
+    msg_ptr: *mut Region,
+) -> ContractResult<IbcBasicResponse<C>>
+where
+    Q: CustomQuery,
+    C: Serialize + Clone + fmt::Debug + PartialEq + JsonSchema,
+    E: ToString,
+{
+    let env: Vec<u8> = unsafe { consume_region(env_ptr) };
+    let msg: Vec<u8> = unsafe { consume_region(msg_ptr) };
+
+    let env: Env = try_into_contract_result!(from_slice(&env));
+    let msg: IbcChannelCloseMsg = try_into_contract_result!(from_slice(&msg));
+
+    let mut deps = make_dependencies();
+    contract_fn(deps.as_mut(), env, msg).into()
+}
+
+#[cfg(feature = "stargate")]
+fn _do_ibc_packet_receive<Q, C, E>(
+    contract_fn: &dyn Fn(DepsMut<Q>, Env, IbcPacketReceiveMsg) -> Result<IbcReceiveResponse<C>, E>,
+    env_ptr: *mut Region,
+    msg_ptr: *mut Region,
+) -> ContractResult<IbcReceiveResponse<C>>
+where
+    Q: CustomQuery,
+    C: Serialize + Clone + fmt::Debug + PartialEq + JsonSchema,
+    E: ToString,
+{
+    let env: Vec<u8> = unsafe { consume_region(env_ptr) };
+    let msg: Vec<u8> = unsafe { consume_region(msg_ptr) };
+
+    let env: Env = try_into_contract_result!(from_slice(&env));
+    let msg: IbcPacketReceiveMsg = try_into_contract_result!(from_slice(&msg));
+
+    let mut deps = make_dependencies();
+    contract_fn(deps.as_mut(), env, msg).into()
+}
+
+#[cfg(feature = "stargate")]
+fn _do_ibc_packet_ack<Q, C, E>(
+    contract_fn: &dyn Fn(DepsMut<Q>, Env, IbcPacketAckMsg) -> Result<IbcBasicResponse<C>, E>,
+    env_ptr: *mut Region,
+    msg_ptr: *mut Region,
+) -> ContractResult<IbcBasicResponse<C>>
+where
+    Q: CustomQuery,
+    C: Serialize + Clone + fmt::Debug + PartialEq + JsonSchema,
+    E: ToString,
+{
+    let env: Vec<u8> = unsafe { consume_region(env_ptr) };
+    let msg: Vec<u8> = unsafe { consume_region(msg_ptr) };
+
+    let env: Env = try_into_contract_result!(from_slice(&env));
+    let msg: IbcPacketAckMsg = try_into_contract_result!(from_slice(&msg));
+
+    let mut deps = make_dependencies();
+    contract_fn(deps.as_mut(), env, msg).into()
+}
+
+#[cfg(feature = "stargate")]
+fn _do_ibc_packet_timeout<Q, C, E>(
+    contract_fn: &dyn Fn(DepsMut<Q>, Env, IbcPacketTimeoutMsg) -> Result<IbcBasicResponse<C>, E>,
+    env_ptr: *mut Region,
+    msg_ptr: *mut Region,
+) -> ContractResult<IbcBasicResponse<C>>
+where
+    Q: CustomQuery,
+    C: Serialize + Clone + fmt::Debug + PartialEq + JsonSchema,
+    E: ToString,
+{
+    let env: Vec<u8> = unsafe { consume_region(env_ptr) };
+    let msg: Vec<u8> = unsafe { consume_region(msg_ptr) };
+
+    let env: Env = try_into_contract_result!(from_slice(&env));
+    let msg: IbcPacketTimeoutMsg = try_into_contract_result!(from_slice(&msg));
+
+    let mut deps = make_dependencies();
+    contract_fn(deps.as_mut(), env, msg).into()
+}
+
 /// Makes all bridges to external dependencies (i.e. Wasm imports) that are injected by the VM
-pub(crate) fn make_dependencies() -> OwnedDeps<ExternalStorage, ExternalApi, ExternalQuerier> {
+pub(crate) fn make_dependencies<Q>() -> OwnedDeps<ExternalStorage, ExternalApi, ExternalQuerier, Q>
+where
+    Q: CustomQuery,
+{
     OwnedDeps {
         storage: ExternalStorage::new(),
         api: ExternalApi::new(),
         querier: ExternalQuerier::new(),
+        custom_query_type: PhantomData,
     }
 }
diff --git a/packages/std/src/ibc_exports.rs b/packages/std/src/ibc_exports.rs
deleted file mode 100644
index ca3762f42..000000000
--- a/packages/std/src/ibc_exports.rs
+++ /dev/null
@@ -1,250 +0,0 @@
-#![cfg(all(feature = "stargate", target_arch = "wasm32"))]
-use std::fmt;
-use std::vec::Vec;
-
-use schemars::JsonSchema;
-use serde::Serialize;
-
-use crate::deps::DepsMut;
-use crate::exports::make_dependencies;
-use crate::ibc::{
-    IbcBasicResponse, IbcChannelCloseMsg, IbcChannelConnectMsg, IbcChannelOpenMsg, IbcPacketAckMsg,
-    IbcPacketReceiveMsg, IbcPacketTimeoutMsg, IbcReceiveResponse,
-};
-use crate::memory::{consume_region, release_buffer, Region};
-use crate::results::ContractResult;
-use crate::serde::{from_slice, to_vec};
-use crate::types::Env;
-
-// TODO: replace with https://doc.rust-lang.org/std/ops/trait.Try.html once stabilized
-macro_rules! r#try_into_contract_result {
-    ($expr:expr) => {
-        match $expr {
-            Ok(val) => val,
-            Err(err) => {
-                return ContractResult::Err(err.to_string());
-            }
-        }
-    };
-    ($expr:expr,) => {
-        $crate::try_into_contract_result!($expr)
-    };
-}
-
-/// do_ibc_channel_open is designed for use with #[entry_point] to make a "C" extern
-///
-/// contract_fn does the protocol version negotiation during channel handshake phase
-pub fn do_ibc_channel_open<E>(
-    contract_fn: &dyn Fn(DepsMut, Env, IbcChannelOpenMsg) -> Result<(), E>,
-    env_ptr: u32,
-    msg_ptr: u32,
-) -> u32
-where
-    E: ToString,
-{
-    let res = _do_ibc_channel_open(contract_fn, env_ptr as *mut Region, msg_ptr as *mut Region);
-    let v = to_vec(&res).unwrap();
-    release_buffer(v) as u32
-}
-
-fn _do_ibc_channel_open<E>(
-    contract_fn: &dyn Fn(DepsMut, Env, IbcChannelOpenMsg) -> Result<(), E>,
-    env_ptr: *mut Region,
-    msg_ptr: *mut Region,
-) -> ContractResult<()>
-where
-    E: ToString,
-{
-    let env: Vec<u8> = unsafe { consume_region(env_ptr) };
-    let msg: Vec<u8> = unsafe { consume_region(msg_ptr) };
-
-    let env: Env = try_into_contract_result!(from_slice(&env));
-    let msg: IbcChannelOpenMsg = try_into_contract_result!(from_slice(&msg));
-
-    let mut deps = make_dependencies();
-    contract_fn(deps.as_mut(), env, msg).into()
-}
-
-/// do_ibc_channel_connect is designed for use with #[entry_point] to make a "C" extern
-///
-/// contract_fn is a callback when a IBC channel is established (after both sides agree in open)
-pub fn do_ibc_channel_connect<C, E>(
-    contract_fn: &dyn Fn(DepsMut, Env, IbcChannelConnectMsg) -> Result<IbcBasicResponse<C>, E>,
-    env_ptr: u32,
-    msg_ptr: u32,
-) -> u32
-where
-    C: Serialize + Clone + fmt::Debug + PartialEq + JsonSchema,
-    E: ToString,
-{
-    let res = _do_ibc_channel_connect(contract_fn, env_ptr as *mut Region, msg_ptr as *mut Region);
-    let v = to_vec(&res).unwrap();
-    release_buffer(v) as u32
-}
-
-fn _do_ibc_channel_connect<C, E>(
-    contract_fn: &dyn Fn(DepsMut, Env, IbcChannelConnectMsg) -> Result<IbcBasicResponse<C>, E>,
-    env_ptr: *mut Region,
-    msg_ptr: *mut Region,
-) -> ContractResult<IbcBasicResponse<C>>
-where
-    C: Serialize + Clone + fmt::Debug + PartialEq + JsonSchema,
-    E: ToString,
-{
-    let env: Vec<u8> = unsafe { consume_region(env_ptr) };
-    let msg: Vec<u8> = unsafe { consume_region(msg_ptr) };
-
-    let env: Env = try_into_contract_result!(from_slice(&env));
-    let msg: IbcChannelConnectMsg = try_into_contract_result!(from_slice(&msg));
-
-    let mut deps = make_dependencies();
-    contract_fn(deps.as_mut(), env, msg).into()
-}
-
-/// do_ibc_channel_close is designed for use with #[entry_point] to make a "C" extern
-///
-/// contract_fn is a callback when a IBC channel belonging to this contract is closed
-pub fn do_ibc_channel_close<C, E>(
-    contract_fn: &dyn Fn(DepsMut, Env, IbcChannelCloseMsg) -> Result<IbcBasicResponse<C>, E>,
-    env_ptr: u32,
-    msg_ptr: u32,
-) -> u32
-where
-    C: Serialize + Clone + fmt::Debug + PartialEq + JsonSchema,
-    E: ToString,
-{
-    let res = _do_ibc_channel_close(contract_fn, env_ptr as *mut Region, msg_ptr as *mut Region);
-    let v = to_vec(&res).unwrap();
-    release_buffer(v) as u32
-}
-
-fn _do_ibc_channel_close<C, E>(
-    contract_fn: &dyn Fn(DepsMut, Env, IbcChannelCloseMsg) -> Result<IbcBasicResponse<C>, E>,
-    env_ptr: *mut Region,
-    msg_ptr: *mut Region,
-) -> ContractResult<IbcBasicResponse<C>>
-where
-    C: Serialize + Clone + fmt::Debug + PartialEq + JsonSchema,
-    E: ToString,
-{
-    let env: Vec<u8> = unsafe { consume_region(env_ptr) };
-    let msg: Vec<u8> = unsafe { consume_region(msg_ptr) };
-
-    let env: Env = try_into_contract_result!(from_slice(&env));
-    let msg: IbcChannelCloseMsg = try_into_contract_result!(from_slice(&msg));
-
-    let mut deps = make_dependencies();
-    contract_fn(deps.as_mut(), env, msg).into()
-}
-
-/// do_ibc_packet_receive is designed for use with #[entry_point] to make a "C" extern
-///
-/// contract_fn is called when this chain receives an IBC Packet on a channel belonging
-/// to this contract
-pub fn do_ibc_packet_receive<C, E>(
-    contract_fn: &dyn Fn(DepsMut, Env, IbcPacketReceiveMsg) -> Result<IbcReceiveResponse<C>, E>,
-    env_ptr: u32,
-    msg_ptr: u32,
-) -> u32
-where
-    C: Serialize + Clone + fmt::Debug + PartialEq + JsonSchema,
-    E: ToString,
-{
-    let res = _do_ibc_packet_receive(contract_fn, env_ptr as *mut Region, msg_ptr as *mut Region);
-    let v = to_vec(&res).unwrap();
-    release_buffer(v) as u32
-}
-
-fn _do_ibc_packet_receive<C, E>(
-    contract_fn: &dyn Fn(DepsMut, Env, IbcPacketReceiveMsg) -> Result<IbcReceiveResponse<C>, E>,
-    env_ptr: *mut Region,
-    msg_ptr: *mut Region,
-) -> ContractResult<IbcReceiveResponse<C>>
-where
-    C: Serialize + Clone + fmt::Debug + PartialEq + JsonSchema,
-    E: ToString,
-{
-    let env: Vec<u8> = unsafe { consume_region(env_ptr) };
-    let msg: Vec<u8> = unsafe { consume_region(msg_ptr) };
-
-    let env: Env = try_into_contract_result!(from_slice(&env));
-    let msg: IbcPacketReceiveMsg = try_into_contract_result!(from_slice(&msg));
-
-    let mut deps = make_dependencies();
-    contract_fn(deps.as_mut(), env, msg).into()
-}
-
-/// do_ibc_packet_ack is designed for use with #[entry_point] to make a "C" extern
-///
-/// contract_fn is called when this chain receives an IBC Acknowledgement for a packet
-/// that this contract previously sent
-pub fn do_ibc_packet_ack<C, E>(
-    contract_fn: &dyn Fn(DepsMut, Env, IbcPacketAckMsg) -> Result<IbcBasicResponse<C>, E>,
-    env_ptr: u32,
-    msg_ptr: u32,
-) -> u32
-where
-    C: Serialize + Clone + fmt::Debug + PartialEq + JsonSchema,
-    E: ToString,
-{
-    let res = _do_ibc_packet_ack(contract_fn, env_ptr as *mut Region, msg_ptr as *mut Region);
-    let v = to_vec(&res).unwrap();
-    release_buffer(v) as u32
-}
-
-fn _do_ibc_packet_ack<C, E>(
-    contract_fn: &dyn Fn(DepsMut, Env, IbcPacketAckMsg) -> Result<IbcBasicResponse<C>, E>,
-    env_ptr: *mut Region,
-    msg_ptr: *mut Region,
-) -> ContractResult<IbcBasicResponse<C>>
-where
-    C: Serialize + Clone + fmt::Debug + PartialEq + JsonSchema,
-    E: ToString,
-{
-    let env: Vec<u8> = unsafe { consume_region(env_ptr) };
-    let msg: Vec<u8> = unsafe { consume_region(msg_ptr) };
-
-    let env: Env = try_into_contract_result!(from_slice(&env));
-    let msg: IbcPacketAckMsg = try_into_contract_result!(from_slice(&msg));
-
-    let mut deps = make_dependencies();
-    contract_fn(deps.as_mut(), env, msg).into()
-}
-
-/// do_ibc_packet_timeout is designed for use with #[entry_point] to make a "C" extern
-///
-/// contract_fn is called when a packet that this contract previously sent has provably
-/// timedout and will never be relayed to the calling chain. This generally behaves
-/// like ick_ack_fn upon an acknowledgement containing an error.
-pub fn do_ibc_packet_timeout<C, E>(
-    contract_fn: &dyn Fn(DepsMut, Env, IbcPacketTimeoutMsg) -> Result<IbcBasicResponse<C>, E>,
-    env_ptr: u32,
-    msg_ptr: u32,
-) -> u32
-where
-    C: Serialize + Clone + fmt::Debug + PartialEq + JsonSchema,
-    E: ToString,
-{
-    let res = _do_ibc_packet_timeout(contract_fn, env_ptr as *mut Region, msg_ptr as *mut Region);
-    let v = to_vec(&res).unwrap();
-    release_buffer(v) as u32
-}
-
-fn _do_ibc_packet_timeout<C, E>(
-    contract_fn: &dyn Fn(DepsMut, Env, IbcPacketTimeoutMsg) -> Result<IbcBasicResponse<C>, E>,
-    env_ptr: *mut Region,
-    msg_ptr: *mut Region,
-) -> ContractResult<IbcBasicResponse<C>>
-where
-    C: Serialize + Clone + fmt::Debug + PartialEq + JsonSchema,
-    E: ToString,
-{
-    let env: Vec<u8> = unsafe { consume_region(env_ptr) };
-    let msg: Vec<u8> = unsafe { consume_region(msg_ptr) };
-
-    let env: Env = try_into_contract_result!(from_slice(&env));
-    let msg: IbcPacketTimeoutMsg = try_into_contract_result!(from_slice(&msg));
-
-    let mut deps = make_dependencies();
-    contract_fn(deps.as_mut(), env, msg).into()
-}
diff --git a/packages/std/src/lib.rs b/packages/std/src/lib.rs
index c5be163e1..4b702f9f7 100644
--- a/packages/std/src/lib.rs
+++ b/packages/std/src/lib.rs
@@ -76,16 +76,13 @@ mod memory; // Used by exports and imports only. This assumes pointers are 32 bi
 
 #[cfg(target_arch = "wasm32")]
 pub use crate::exports::{do_execute, do_instantiate, do_migrate, do_query, do_reply, do_sudo};
-#[cfg(target_arch = "wasm32")]
-pub use crate::imports::{ExternalApi, ExternalQuerier, ExternalStorage};
-
 #[cfg(all(feature = "stargate", target_arch = "wasm32"))]
-mod ibc_exports;
-#[cfg(all(feature = "stargate", target_arch = "wasm32"))]
-pub use crate::ibc_exports::{
+pub use crate::exports::{
     do_ibc_channel_close, do_ibc_channel_connect, do_ibc_channel_open, do_ibc_packet_ack,
     do_ibc_packet_receive, do_ibc_packet_timeout,
 };
+#[cfg(target_arch = "wasm32")]
+pub use crate::imports::{ExternalApi, ExternalQuerier, ExternalStorage};
 
 // Exposed for testing only
 // Both unit tests and integration tests are compiled to native code, so everything in here does not need to compile to Wasm.
diff --git a/packages/std/src/mock.rs b/packages/std/src/mock.rs
index a43e1957e..9ea019351 100644
--- a/packages/std/src/mock.rs
+++ b/packages/std/src/mock.rs
@@ -2,6 +2,7 @@ use serde::de::DeserializeOwned;
 #[cfg(feature = "stargate")]
 use serde::Serialize;
 use std::collections::HashMap;
+use std::marker::PhantomData;
 
 use crate::addresses::{Addr, CanonicalAddr};
 use crate::binary::Binary;
@@ -36,11 +37,12 @@ pub const MOCK_CONTRACT_ADDR: &str = "cosmos2contract";
 /// It sets the given balance for the contract itself, nothing else
 pub fn mock_dependencies(
     contract_balance: &[Coin],
-) -> OwnedDeps<MockStorage, MockApi, MockQuerier> {
+) -> OwnedDeps<MockStorage, MockApi, MockQuerier, Empty> {
     OwnedDeps {
         storage: MockStorage::default(),
         api: MockApi::default(),
         querier: MockQuerier::new(&[(MOCK_CONTRACT_ADDR, contract_balance)]),
+        custom_query_type: PhantomData,
     }
 }
 
@@ -53,6 +55,7 @@ pub fn mock_dependencies_with_balances(
         storage: MockStorage::default(),
         api: MockApi::default(),
         querier: MockQuerier::new(balances),
+        custom_query_type: PhantomData,
     }
 }
 
diff --git a/packages/std/src/query/mod.rs b/packages/std/src/query/mod.rs
index 1b8a791c1..f1e6afff4 100644
--- a/packages/std/src/query/mod.rs
+++ b/packages/std/src/query/mod.rs
@@ -66,7 +66,9 @@ pub enum QueryRequest<C: CustomQuery> {
 ///
 /// impl CustomQuery for MyCustomQuery {}
 /// ```
-pub trait CustomQuery: Serialize {}
+pub trait CustomQuery: Serialize + Clone {}
+// We require `Clone` because `Clone` in `QueryRequest<C>` is only derived for
+// `C: Clone` and we want consistent behaviour for all `QueryRequest<C>`
 
 impl CustomQuery for Empty {}
 
diff --git a/packages/std/src/traits.rs b/packages/std/src/traits.rs
index bb9ae0f78..1e2cf2bd0 100644
--- a/packages/std/src/traits.rs
+++ b/packages/std/src/traits.rs
@@ -1,4 +1,5 @@
 use serde::{de::DeserializeOwned, Serialize};
+use std::marker::PhantomData;
 use std::ops::Deref;
 
 use crate::addresses::{Addr, CanonicalAddr};
@@ -134,41 +135,42 @@ pub trait Querier {
     fn raw_query(&self, bin_request: &[u8]) -> QuerierResult;
 }
 
-#[derive(Copy, Clone)]
-pub struct QuerierWrapper<'a>(&'a dyn Querier);
+#[derive(Clone)]
+pub struct QuerierWrapper<'a, C: CustomQuery = Empty> {
+    querier: &'a dyn Querier,
+    custom_query_type: PhantomData<C>,
+}
+
+// Use custom implementation on order to implement Copy in case `C` is not `Copy`.
+// See "There is a small difference between the two: the derive strategy will also
+// place a Copy bound on type parameters, which isn’t always desired."
+// https://doc.rust-lang.org/std/marker/trait.Copy.html
+impl<'a, C: CustomQuery> Copy for QuerierWrapper<'a, C> {}
 
 /// This allows us to use self.raw_query to access the querier.
 /// It also allows external callers to access the querier easily.
-impl<'a> Deref for QuerierWrapper<'a> {
+impl<'a, C: CustomQuery> Deref for QuerierWrapper<'a, C> {
     type Target = dyn Querier + 'a;
 
     fn deref(&self) -> &Self::Target {
-        self.0
+        self.querier
     }
 }
 
-impl<'a> QuerierWrapper<'a> {
+impl<'a, C: CustomQuery> QuerierWrapper<'a, C> {
     pub fn new(querier: &'a dyn Querier) -> Self {
-        QuerierWrapper(querier)
-    }
-
-    /// query is a shorthand for custom_query when we are not using a custom type,
-    /// this allows us to avoid specifying "Empty" in all the type definitions.
-    pub fn query<T: DeserializeOwned>(&self, request: &QueryRequest<Empty>) -> StdResult<T> {
-        self.custom_query(request)
+        QuerierWrapper {
+            querier,
+            custom_query_type: PhantomData,
+        }
     }
 
-    /// Makes the query and parses the response. Also handles custom queries,
-    /// so you need to specify the custom query type in the function parameters.
-    /// If you are no using a custom query, just use `query` for easier interface.
+    /// Makes the query and parses the response.
     ///
     /// Any error (System Error, Error or called contract, or Parse Error) are flattened into
     /// one level. Only use this if you don't need to check the SystemError
     /// eg. If you don't differentiate between contract missing and contract returned error
-    pub fn custom_query<C: CustomQuery, U: DeserializeOwned>(
-        &self,
-        request: &QueryRequest<C>,
-    ) -> StdResult<U> {
+    pub fn query<U: DeserializeOwned>(&self, request: &QueryRequest<C>) -> StdResult<U> {
         let raw = to_vec(request).map_err(|serialize_err| {
             StdError::generic_err(format!("Serializing QueryRequest: {}", serialize_err))
         })?;
@@ -330,7 +332,7 @@ mod tests {
     #[test]
     fn use_querier_wrapper_as_querier() {
         let querier: MockQuerier<Empty> = MockQuerier::new(&[]);
-        let wrapper = QuerierWrapper::new(&querier);
+        let wrapper = QuerierWrapper::<Empty>::new(&querier);
 
         // call with deref shortcut
         let res = demo_helper(&*wrapper);
@@ -345,7 +347,7 @@ mod tests {
     fn auto_deref_raw_query() {
         let acct = String::from("foobar");
         let querier: MockQuerier<Empty> = MockQuerier::new(&[(&acct, &coins(5, "BTC"))]);
-        let wrapper = QuerierWrapper::new(&querier);
+        let wrapper = QuerierWrapper::<Empty>::new(&querier);
         let query = QueryRequest::<Empty>::Bank(BankQuery::Balance {
             address: acct,
             denom: "BTC".to_string(),


Test patch:
diff --git a/contracts/reflect/src/testing.rs b/contracts/reflect/src/testing.rs
index 8237329b1..8f6ce714b 100644
--- a/contracts/reflect/src/testing.rs
+++ b/contracts/reflect/src/testing.rs
@@ -1,3 +1,5 @@
+use std::marker::PhantomData;
+
 use crate::msg::{SpecialQuery, SpecialResponse};
 
 use cosmwasm_std::testing::{MockApi, MockQuerier, MockStorage, MOCK_CONTRACT_ADDR};
@@ -7,7 +9,7 @@ use cosmwasm_std::{to_binary, Binary, Coin, ContractResult, OwnedDeps, SystemRes
 /// this uses our CustomQuerier.
 pub fn mock_dependencies_with_custom_querier(
     contract_balance: &[Coin],
-) -> OwnedDeps<MockStorage, MockApi, MockQuerier<SpecialQuery>> {
+) -> OwnedDeps<MockStorage, MockApi, MockQuerier<SpecialQuery>, SpecialQuery> {
     let custom_querier: MockQuerier<SpecialQuery> =
         MockQuerier::new(&[(MOCK_CONTRACT_ADDR, contract_balance)])
             .with_custom_handler(|query| SystemResult::Ok(custom_query_execute(query)));
@@ -15,6 +17,7 @@ pub fn mock_dependencies_with_custom_querier(
         storage: MockStorage::default(),
         api: MockApi::default(),
         querier: custom_querier,
+        custom_query_type: PhantomData,
     }
 }
 
@@ -56,7 +59,7 @@ mod tests {
         }
         .into();
         let wrapper = QuerierWrapper::new(&deps.querier);
-        let response: SpecialResponse = wrapper.custom_query(&req).unwrap();
+        let response: SpecialResponse = wrapper.query(&req).unwrap();
         assert_eq!(response.msg, "FOOD");
     }
 }