Repository: CosmWasm/sylvia
Pull request #416 (2024-08-21 13:09:06)

fix: Revert breaking changes
Revert breaking parts of
Refs:
-  d4c94cab52351900b22e1bf6697fe8e4c64a9047
- abfa2a562b6fe7b9dc94810c6a54b70678b65351



Patch:
diff --git a/MIGRATING.md b/MIGRATING.md
index e31b641..b75c1a8 100644
--- a/MIGRATING.md
+++ b/MIGRATING.md
@@ -11,7 +11,7 @@ The `, custom(msg=..., query=...)` part is now not supported and can be safely r
 
 ```diff
 -#[entry_points(generics<Empty, Empty>, custom(msg=Empty, query=Empty))]
-+#[entry_points(generics<msg=Empty, query=Empty>)]
++#[entry_points(generics<Empty, Empty>)]
 #[contract]
 #[sv::custom(msg=E, query=Q)]
 impl<E, Q> CounterContract<E, Q>
@@ -24,15 +24,14 @@ where
 
 ### Removed `InterfaceApi` trait
 
-The `InterfaceApi` trait has been removed in favor of the `InterfaceMessagesApi`.
+The `InterfaceApi` trait has been deprecated in favor of the `InterfaceMessagesApi`.
+It will be removed in the `2.0.0` release.
 
 ```diff
 -let _ = <dyn super::sv::Api as sylvia::types::InterfaceApi>::Query::query_something();
 +let _ = <dyn super::MyInterface as super::sv::InterfaceMessagesApi>::Query::query_something();
 ```
 
-Note: the `InterfaceMessagesApi` does not expose Querier type.
-
 ## 1.0.2 -> 1.1.0
 
 ### Generics in `sv::messages` not required
diff --git a/examples/interfaces/custom-and-generic/src/lib.rs b/examples/interfaces/custom-and-generic/src/lib.rs
index d24a7f7..97637a0 100644
--- a/examples/interfaces/custom-and-generic/src/lib.rs
+++ b/examples/interfaces/custom-and-generic/src/lib.rs
@@ -69,9 +69,11 @@ pub trait CustomAndGeneric {
 }
 
 #[cfg(test)]
+#[allow(deprecated)]
 mod tests {
     use cosmwasm_std::testing::mock_dependencies;
     use cosmwasm_std::{Addr, CosmosMsg, Empty, QuerierWrapper};
+    use sylvia::types::InterfaceApi;
 
     use crate::sv::Querier;
 
@@ -232,5 +234,130 @@ mod tests {
             CosmosMsg::Custom(SvCustomMsg {}),
             CosmosMsg::Custom(SvCustomMsg {}),
         );
+
+        let _ = <dyn super::CustomAndGeneric<
+            Error = (),
+            Exec1T = SvCustomMsg,
+            Exec2T = SvCustomMsg,
+            Exec3T = SvCustomMsg,
+            Query1T = SvCustomMsg,
+            Query2T = SvCustomMsg,
+            Query3T = SvCustomMsg,
+            Sudo1T = SvCustomMsg,
+            Sudo2T = SvCustomMsg,
+            Sudo3T = SvCustomMsg,
+            ExecC = SvCustomMsg,
+            QueryC = SvCustomQuery,
+            RetT = SvCustomMsg,
+        > as super::sv::InterfaceMessagesApi>::Querier::borrowed(
+            &contract, &querier_wrapper
+        );
+
+        // Construct messages with InterfaceApi
+        let _ = <super::sv::Api<
+            SvCustomMsg,
+            SvCustomMsg,
+            SvCustomMsg,
+            SvCustomMsg,
+            SvCustomMsg,
+            SvCustomMsg,
+            SvCustomMsg,
+            SvCustomMsg,
+            SvCustomMsg,
+            SvCustomMsg,
+            SvCustomQuery,
+            SvCustomMsg,
+        > as InterfaceApi>::Query::custom_generic_query_one(
+            SvCustomMsg {}, SvCustomMsg {}
+        );
+
+        let _ = <super::sv::Api<
+            SvCustomMsg,
+            SvCustomMsg,
+            SvCustomMsg,
+            SvCustomMsg,
+            SvCustomMsg,
+            SvCustomMsg,
+            SvCustomMsg,
+            SvCustomMsg,
+            SvCustomMsg,
+            SvCustomMsg,
+            SvCustomQuery,
+            SvCustomMsg,
+        > as InterfaceApi>::Query::custom_generic_query_two(
+            SvCustomMsg {}, SvCustomMsg {}
+        );
+
+        let _ = <super::sv::Api<
+            SvCustomMsg,
+            SvCustomMsg,
+            SvCustomMsg,
+            SvCustomMsg,
+            SvCustomMsg,
+            SvCustomMsg,
+            SvCustomMsg,
+            SvCustomMsg,
+            SvCustomMsg,
+            SvCustomMsg,
+            SvCustomQuery,
+            SvCustomMsg,
+        > as InterfaceApi>::Exec::custom_generic_execute_one(
+            vec![CosmosMsg::Custom(SvCustomMsg {})],
+            vec![CosmosMsg::Custom(SvCustomMsg {})],
+        );
+
+        let _ = <super::sv::Api<
+            SvCustomMsg,
+            SvCustomMsg,
+            SvCustomMsg,
+            SvCustomMsg,
+            SvCustomMsg,
+            SvCustomMsg,
+            SvCustomMsg,
+            SvCustomMsg,
+            SvCustomMsg,
+            SvCustomMsg,
+            SvCustomQuery,
+            SvCustomMsg,
+        > as InterfaceApi>::Exec::custom_generic_execute_two(
+            vec![CosmosMsg::Custom(SvCustomMsg {})],
+            vec![CosmosMsg::Custom(SvCustomMsg {})],
+        );
+
+        let _ = <super::sv::Api<
+            SvCustomMsg,
+            SvCustomMsg,
+            SvCustomMsg,
+            SvCustomMsg,
+            SvCustomMsg,
+            SvCustomMsg,
+            SvCustomMsg,
+            SvCustomMsg,
+            SvCustomMsg,
+            SvCustomMsg,
+            SvCustomQuery,
+            SvCustomMsg,
+        > as InterfaceApi>::Sudo::custom_generic_sudo_one(
+            CosmosMsg::Custom(SvCustomMsg {}),
+            CosmosMsg::Custom(SvCustomMsg {}),
+        );
+
+        let _ = <super::sv::Api<
+            SvCustomMsg,
+            SvCustomMsg,
+            SvCustomMsg,
+            SvCustomMsg,
+            SvCustomMsg,
+            SvCustomMsg,
+            SvCustomMsg,
+            SvCustomMsg,
+            SvCustomMsg,
+            SvCustomMsg,
+            SvCustomQuery,
+            SvCustomMsg,
+        > as InterfaceApi>::Sudo::custom_generic_sudo_two(
+            CosmosMsg::Custom(SvCustomMsg {}),
+            CosmosMsg::Custom(SvCustomMsg {}),
+        );
     }
 }
diff --git a/examples/interfaces/generic/src/lib.rs b/examples/interfaces/generic/src/lib.rs
index 174ad87..b2e1dc3 100644
--- a/examples/interfaces/generic/src/lib.rs
+++ b/examples/interfaces/generic/src/lib.rs
@@ -68,9 +68,11 @@ pub trait Generic {
 }
 
 #[cfg(test)]
+#[allow(deprecated)]
 mod tests {
     use cosmwasm_std::testing::mock_dependencies;
     use cosmwasm_std::{Addr, CosmosMsg, Empty, QuerierWrapper};
+    use sylvia::types::InterfaceApi;
 
     use crate::sv::Querier;
 
@@ -209,6 +211,7 @@ mod tests {
             CosmosMsg::Custom(SvCustomMsg {}),
             CosmosMsg::Custom(SvCustomMsg {}),
         );
+
         let _ = <dyn super::Generic<
             Exec1T = SvCustomMsg,
             Exec2T = SvCustomMsg,
@@ -225,5 +228,112 @@ mod tests {
             CosmosMsg::Custom(SvCustomMsg {}),
             CosmosMsg::Custom(SvCustomMsg {}),
         );
+
+        let _ = <dyn super::Generic<
+            Exec1T = SvCustomMsg,
+            Exec2T = SvCustomMsg,
+            Exec3T = SvCustomMsg,
+            Query1T = SvCustomMsg,
+            Query2T = SvCustomMsg,
+            Query3T = SvCustomMsg,
+            Sudo1T = SvCustomMsg,
+            Sudo2T = SvCustomMsg,
+            Sudo3T = SvCustomMsg,
+            RetT = Empty,
+            Error = (),
+        > as super::sv::InterfaceMessagesApi>::Querier::borrowed(
+            &contract, &querier_wrapper
+        );
+
+        // Construct messages with InterfaceApi
+        let _ = <super::sv::Api<
+            SvCustomMsg,
+            SvCustomMsg,
+            SvCustomMsg,
+            _,
+            _,
+            SvCustomMsg,
+            SvCustomMsg,
+            SvCustomMsg,
+            SvCustomMsg,
+            SvCustomMsg,
+        > as InterfaceApi>::Query::generic_query_one(SvCustomMsg {}, SvCustomMsg {});
+
+        let _ = <super::sv::Api<
+            SvCustomMsg,
+            SvCustomMsg,
+            SvCustomMsg,
+            SvCustomMsg,
+            _,
+            _,
+            SvCustomMsg,
+            SvCustomMsg,
+            SvCustomMsg,
+            SvCustomMsg,
+        > as InterfaceApi>::Query::generic_query_two(SvCustomMsg {}, SvCustomMsg {});
+
+        let _ = <super::sv::Api<
+            _,
+            _,
+            SvCustomMsg,
+            SvCustomMsg,
+            SvCustomMsg,
+            SvCustomMsg,
+            SvCustomMsg,
+            SvCustomMsg,
+            SvCustomMsg,
+            cosmwasm_std::Empty,
+        > as InterfaceApi>::Exec::generic_exec_one(
+            vec![CosmosMsg::Custom(SvCustomMsg {})],
+            vec![CosmosMsg::Custom(SvCustomMsg {})],
+        );
+
+        let _ = <super::sv::Api<
+            SvCustomMsg,
+            _,
+            _,
+            SvCustomMsg,
+            SvCustomMsg,
+            SvCustomMsg,
+            cosmwasm_std::Empty,
+            SvCustomMsg,
+            SvCustomMsg,
+            SvCustomMsg,
+        > as InterfaceApi>::Exec::generic_exec_two(
+            vec![CosmosMsg::Custom(SvCustomMsg {})],
+            vec![CosmosMsg::Custom(SvCustomMsg {})],
+        );
+
+        let _ = <super::sv::Api<
+            SvCustomMsg,
+            SvCustomMsg,
+            SvCustomMsg,
+            SvCustomMsg,
+            SvCustomMsg,
+            SvCustomMsg,
+            _,
+            _,
+            SvCustomMsg,
+            cosmwasm_std::Empty,
+        > as InterfaceApi>::Sudo::generic_sudo_one(
+            CosmosMsg::Custom(SvCustomMsg {}),
+            CosmosMsg::Custom(SvCustomMsg {}),
+        );
+
+        let _ = <super::sv::Api<
+            SvCustomMsg,
+            SvCustomMsg,
+            SvCustomMsg,
+            SvCustomMsg,
+            cosmwasm_std::Empty,
+            SvCustomMsg,
+            SvCustomMsg,
+            _,
+            _,
+            SvCustomMsg,
+        > as InterfaceApi>::Sudo::generic_sudo_two(
+            CosmosMsg::Custom(SvCustomMsg {}),
+            CosmosMsg::Custom(SvCustomMsg {}),
+        );
     }
 }
diff --git a/sylvia-derive/src/interface.rs b/sylvia-derive/src/interface.rs
index 8909452..5f956cc 100644
--- a/sylvia-derive/src/interface.rs
+++ b/sylvia-derive/src/interface.rs
@@ -96,7 +96,7 @@ impl<'a> InterfaceInput<'a> {
         let Self {
             associated_types,
             item,
-            ..
+            custom,
         } = self;
         let messages = self.emit_messages();
         let associated_names: Vec<_> = associated_types
@@ -113,7 +113,7 @@ impl<'a> InterfaceInput<'a> {
         let querier =
             Querier::new(&query_variants, associated_types, &item.ident).emit_querier_trait();
 
-        let interface_messages = Api::new(item, associated_types).emit();
+        let interface_messages = Api::new(item, custom, associated_types).emit();
 
         let multitest_helpers = self.emit_multitest_helpers();
 
diff --git a/sylvia-derive/src/interface/communication/api.rs b/sylvia-derive/src/interface/communication/api.rs
index 082b5e2..1288c9b 100644
--- a/sylvia-derive/src/interface/communication/api.rs
+++ b/sylvia-derive/src/interface/communication/api.rs
@@ -1,5 +1,6 @@
+use crate::crate_module;
 use crate::parser::variant_descs::AsVariantDescs;
-use crate::parser::MsgType;
+use crate::parser::{Custom, MsgType};
 use crate::types::associated_types::{AssociatedTypes, ItemType};
 use crate::types::msg_variant::MsgVariants;
 use proc_macro2::TokenStream;
@@ -13,23 +14,33 @@ use syn::ItemTrait;
 /// It ease the dispatch of generic types.
 pub struct Api<'a> {
     source: &'a ItemTrait,
+    custom: &'a Custom,
     associated_types: &'a AssociatedTypes<'a>,
 }
 
 impl<'a> Api<'a> {
-    pub fn new(source: &'a ItemTrait, associated_types: &'a AssociatedTypes<'a>) -> Self {
+    pub fn new(
+        source: &'a ItemTrait,
+        custom: &'a Custom,
+        associated_types: &'a AssociatedTypes<'a>,
+    ) -> Self {
         Self {
             source,
+            custom,
             associated_types,
         }
     }
 
     pub fn emit(&self) -> TokenStream {
+        let sylvia = crate_module();
         let Self {
             source,
+            custom,
             associated_types,
         } = self;
 
+        let where_clause = &self.associated_types.as_where_clause();
+        let custom_query = custom.query_or_default();
         let interface_name = &source.ident;
         let generics: Vec<_> = associated_types
             .without_error()
@@ -58,23 +69,46 @@ impl<'a> Api<'a> {
         let query_generics = &query_variants.used_generics();
         let sudo_generics = &sudo_variants.used_generics();
 
+        let phantom = if !generics.is_empty() {
+            quote! {
+                _phantom: std::marker::PhantomData<( #(#generics,)* )>,
+            }
+        } else {
+            quote! {}
+        };
+
         quote! {
             pub trait InterfaceMessagesApi {
                 type Exec;
                 type Query;
                 type Sudo;
+                type Querier<'querier>;
             }
 
             impl<Contract: #interface_name> InterfaceMessagesApi for Contract {
                 type Exec = ExecMsg < #(<Contract as #interface_name >:: #exec_generics,)* >;
                 type Query = QueryMsg < #(<Contract as #interface_name >:: #query_generics,)* >;
                 type Sudo = SudoMsg < #(<Contract as #interface_name >:: #sudo_generics ,)* >;
+                type Querier<'querier> = #sylvia ::types::BoundQuerier<'querier, #custom_query, Contract >;
             }
 
             impl<'sv_iface_msg_api, Error, #(#generics),*> InterfaceMessagesApi for dyn #interface_name < Error = Error, #(#generics = #generics,)* > + 'sv_iface_msg_api {
                 type Exec = ExecMsg < #(#exec_generics,)* >;
                 type Query = QueryMsg < #(#query_generics,)* >;
                 type Sudo = SudoMsg < #(#sudo_generics,)* >;
+                type Querier<'querier> = #sylvia ::types::BoundQuerier<'querier, #custom_query, Self >;
+            }
+
+            pub struct Api < #(#generics,)* > {
+                #phantom
+            }
+
+            #[allow(deprecated)]
+            impl < #(#generics,)* > #sylvia ::types::InterfaceApi for Api < #(#generics,)* > #where_clause {
+                type Exec = ExecMsg < #(#exec_generics,)* >;
+                type Query = QueryMsg < #(#query_generics,)* >;
+                type Sudo = SudoMsg < #(#sudo_generics,)* >;
+                type Querier<'querier, Contract> = #sylvia ::types::BoundQuerier<'querier, #custom_query, Contract >;
             }
         }
     }
diff --git a/sylvia-derive/src/parser/entry_point.rs b/sylvia-derive/src/parser/entry_point.rs
index 584eb92..0a610aa 100644
--- a/sylvia-derive/src/parser/entry_point.rs
+++ b/sylvia-derive/src/parser/entry_point.rs
@@ -1,9 +1,11 @@
 use proc_macro2::TokenStream as TokenStream2;
-use proc_macro_error::emit_error;
-use syn::parse::{Error, Nothing, Parse, ParseStream};
+use proc_macro_error::{emit_error, emit_warning};
+use syn::parse::{Error, Nothing, Parse, ParseStream, Parser};
 use syn::punctuated::Punctuated;
 use syn::spanned::Spanned;
-use syn::{parse2, GenericArgument, Path, Result, Token};
+use syn::{parenthesized, parse2, GenericArgument, Path, Result, Token};
+
+use crate::parser::Custom;
 
 use super::extract_generics_from_path;
 
@@ -40,6 +42,28 @@ impl Parse for EntryPointArgs {
             _ => return Err(Error::new(generics.span(), "Expected `generics`.")),
         };
 
+        let comma: Option<Token![,]> = input.parse().ok();
+        if comma.is_some() {
+            emit_warning!(
+                comma.span(), "Deprecated `, custom(msg=.., query=..)` found.";
+                note = "You can safely remove this parameter as `entry_points` macro does not require it anymore."
+            );
+
+            // Parse custom attribute to not break semver
+            let custom: Option<Path> = input.parse().ok();
+            match custom {
+                Some(custom)
+                    if custom.get_ident().map(|custom| custom.to_string())
+                        == Some("custom".to_owned()) =>
+                {
+                    let content;
+                    parenthesized!(content in input);
+                    let _ = Custom::parse.parse2(content.parse()?);
+                }
+                _ => (),
+            };
+        }
+
         let _: Nothing = input.parse()?;
 
         Ok(entry_points_args)
diff --git a/sylvia/src/types.rs b/sylvia/src/types.rs
index 30a98ec..0c0e937 100644
--- a/sylvia/src/types.rs
+++ b/sylvia/src/types.rs
@@ -562,6 +562,18 @@ pub trait CustomQuery: cosmwasm_std::CustomQuery + DeserializeOwned + JsonSchema
 
 impl<T> CustomQuery for T where T: cosmwasm_std::CustomQuery + DeserializeOwned + JsonSchema {}
 
+/// Api trait for easier access to generated types and messages.
+#[deprecated(
+    since = "1.2.1",
+    note = "InterfaceApi will be removed in 2.0.0. Please use generated sv::InterfaceMessagesApi instead."
+)]
+pub trait InterfaceApi {
+    type Exec;
+    type Query;
+    type Sudo;
+    type Querier<'querier, Contract>;
+}
+
 /// Api trait for easier access to generated types and messages.
 pub trait ContractApi {
     type Instantiate;


Test patch:
diff --git a/sylvia/tests/interface_impl.rs b/sylvia/tests/interface_impl.rs
index 88d5427..ac638f8 100644
--- a/sylvia/tests/interface_impl.rs
+++ b/sylvia/tests/interface_impl.rs
@@ -1,138 +1,178 @@
-use cosmwasm_std::{Response, StdError, StdResult};
-use sylvia::types::{ExecCtx, InstantiateCtx, QueryCtx, SudoCtx};
+use cosmwasm_std::{Empty, Response, StdError, StdResult};
+use sylvia::types::{CustomMsg, CustomQuery, ExecCtx, InstantiateCtx, QueryCtx, SudoCtx};
 use sylvia::{contract, entry_points};
 
 mod interface1 {
     use cosmwasm_std::{Response, StdError, StdResult};
     use sylvia::interface;
-    use sylvia::types::{ExecCtx, QueryCtx, SudoCtx};
+    use sylvia::types::{CustomMsg, CustomQuery, ExecCtx, QueryCtx, SudoCtx};
 
     #[interface]
-    #[sv::custom(msg=cosmwasm_std::Empty, query=cosmwasm_std::Empty)]
     pub trait SylviaInterface1 {
         type Error: From<StdError>;
+        type ExecC: CustomMsg;
+        type QueryC: CustomQuery;
 
         #[sv::msg(exec)]
-        fn interface1_method_exec(&self, _ctx: ExecCtx) -> StdResult<Response>;
+        fn interface1_method_exec(
+            &self,
+            _ctx: ExecCtx<Self::QueryC>,
+        ) -> StdResult<Response<Self::ExecC>>;
 
         #[sv::msg(query)]
-        fn interface1_method_query(&self, _ctx: QueryCtx) -> StdResult<Response>;
+        fn interface1_method_query(
+            &self,
+            _ctx: QueryCtx<Self::QueryC>,
+        ) -> StdResult<Response<Self::ExecC>>;
 
         #[sv::msg(sudo)]
-        fn interface1_method_sudo(&self, _ctx: SudoCtx) -> StdResult<Response>;
+        fn interface1_method_sudo(
+            &self,
+            _ctx: SudoCtx<Self::QueryC>,
+        ) -> StdResult<Response<Self::ExecC>>;
     }
 }
 
 mod interface2 {
     use cosmwasm_std::{Response, StdError, StdResult};
     use sylvia::interface;
-    use sylvia::types::{ExecCtx, QueryCtx, SudoCtx};
+    use sylvia::types::{CustomMsg, CustomQuery, ExecCtx, QueryCtx, SudoCtx};
 
     #[interface]
-    #[sv::custom(msg=cosmwasm_std::Empty, query=cosmwasm_std::Empty)]
     pub trait SylviaInterface2 {
         type Error: From<StdError>;
+        type ExecC: CustomMsg;
+        type QueryC: CustomQuery;
 
         #[sv::msg(exec)]
-        fn interface2_method_exec(&self, _ctx: ExecCtx) -> StdResult<Response>;
+        fn interface2_method_exec(
+            &self,
+            _ctx: ExecCtx<Self::QueryC>,
+        ) -> StdResult<Response<Self::ExecC>>;
 
         #[sv::msg(query)]
-        fn interface2_method_query(&self, _ctx: QueryCtx) -> StdResult<Response>;
+        fn interface2_method_query(
+            &self,
+            _ctx: QueryCtx<Self::QueryC>,
+        ) -> StdResult<Response<Self::ExecC>>;
 
         #[sv::msg(sudo)]
-        fn interface2_method_sudo(&self, _ctx: SudoCtx) -> StdResult<Response>;
+        fn interface2_method_sudo(
+            &self,
+            _ctx: SudoCtx<Self::QueryC>,
+        ) -> StdResult<Response<Self::ExecC>>;
     }
 }
 
-pub struct Contract;
+pub struct Contract<E, Q> {
+    _phantom: std::marker::PhantomData<(E, Q)>,
+}
 
-#[entry_points]
+// Check that the macro expansion won't fail due to deprecated `, custom` parameter.
+#[entry_points(generics<Empty, Empty>, custom(msg=Empty, query=Empty))]
 #[contract]
 #[sv::messages(interface1)]
 #[sv::messages(interface2)]
-impl Contract {
+#[sv::custom(msg=E, query=Q)]
+impl<E, Q> Contract<E, Q>
+where
+    E: CustomMsg + 'static,
+    Q: CustomQuery + 'static,
+{
     pub fn new() -> Self {
-        Self
+        Self {
+            _phantom: Default::default(),
+        }
     }
 
     #[sv::msg(instantiate)]
-    fn instantiate(&self, _ctx: InstantiateCtx) -> StdResult<Response> {
+    fn instantiate(&self, _ctx: InstantiateCtx<Q>) -> StdResult<Response<E>> {
         Ok(Response::new())
     }
 
     #[sv::msg(exec)]
-    fn contract_method_exec(&self, _ctx: ExecCtx) -> StdResult<Response> {
+    fn contract_method_exec(&self, _ctx: ExecCtx<Q>) -> StdResult<Response<E>> {
         Ok(Response::new())
     }
 
     #[sv::msg(query)]
-    fn contract_method_query(&self, _ctx: QueryCtx) -> StdResult<Response> {
+    fn contract_method_query(&self, _ctx: QueryCtx<Q>) -> StdResult<Response<E>> {
         Ok(Response::new())
     }
 
     #[sv::msg(sudo)]
-    fn contract_method_sudo(&self, _ctx: SudoCtx) -> StdResult<Response> {
+    fn contract_method_sudo(&self, _ctx: SudoCtx<Q>) -> StdResult<Response<E>> {
         Ok(Response::new())
     }
 }
 
-impl interface1::SylviaInterface1 for Contract {
+impl<E, Q> interface1::SylviaInterface1 for Contract<E, Q>
+where
+    E: CustomMsg + 'static,
+    Q: CustomQuery + 'static,
+{
     type Error = StdError;
+    type ExecC = E;
+    type QueryC = Q;
 
-    fn interface1_method_exec(&self, _ctx: ExecCtx) -> StdResult<Response> {
+    fn interface1_method_exec(&self, _ctx: ExecCtx<Q>) -> StdResult<Response<E>> {
         Ok(Response::new())
     }
 
-    fn interface1_method_query(&self, _ctx: QueryCtx) -> StdResult<Response> {
+    fn interface1_method_query(&self, _ctx: QueryCtx<Q>) -> StdResult<Response<E>> {
         Ok(Response::new())
     }
 
-    fn interface1_method_sudo(&self, _ctx: SudoCtx) -> StdResult<Response> {
+    fn interface1_method_sudo(&self, _ctx: SudoCtx<Q>) -> StdResult<Response<E>> {
         Ok(Response::new())
     }
 }
 
-impl interface2::SylviaInterface2 for Contract {
+impl<E, Q> interface2::SylviaInterface2 for Contract<E, Q>
+where
+    E: CustomMsg + 'static,
+    Q: CustomQuery + 'static,
+{
     type Error = StdError;
+    type ExecC = E;
+    type QueryC = Q;
 
-    fn interface2_method_exec(&self, _ctx: ExecCtx) -> StdResult<Response> {
+    fn interface2_method_exec(&self, _ctx: ExecCtx<Q>) -> StdResult<Response<E>> {
         Ok(Response::new())
     }
 
-    fn interface2_method_query(&self, _ctx: QueryCtx) -> StdResult<Response> {
+    fn interface2_method_query(&self, _ctx: QueryCtx<Q>) -> StdResult<Response<E>> {
         Ok(Response::new())
     }
 
-    fn interface2_method_sudo(&self, _ctx: SudoCtx) -> StdResult<Response> {
+    fn interface2_method_sudo(&self, _ctx: SudoCtx<Q>) -> StdResult<Response<E>> {
         Ok(Response::new())
     }
 }
 
-impl Default for Contract {
-    fn default() -> Self {
-        Self::new()
-    }
-}
-
 #[test]
 fn check_from_trait_implementations() {
-    let _ =
-        sv::ContractExecMsg::from(interface1::sv::SylviaInterface1ExecMsg::Interface1MethodExec {});
-    let _ = sv::ContractQueryMsg::from(
+    let _ = sv::ContractExecMsg::<Empty, Empty>::from(
+        interface1::sv::SylviaInterface1ExecMsg::Interface1MethodExec {},
+    );
+    let _ = sv::ContractQueryMsg::<Empty, Empty>::from(
         interface1::sv::SylviaInterface1QueryMsg::Interface1MethodQuery {},
     );
-    let _ =
-        sv::ContractSudoMsg::from(interface1::sv::SylviaInterface1SudoMsg::Interface1MethodSudo {});
+    let _ = sv::ContractSudoMsg::<Empty, Empty>::from(
+        interface1::sv::SylviaInterface1SudoMsg::Interface1MethodSudo {},
+    );
 
-    let _ =
-        sv::ContractExecMsg::from(interface2::sv::SylviaInterface2ExecMsg::Interface2MethodExec {});
-    let _ = sv::ContractQueryMsg::from(
+    let _ = sv::ContractExecMsg::<Empty, Empty>::from(
+        interface2::sv::SylviaInterface2ExecMsg::Interface2MethodExec {},
+    );
+    let _ = sv::ContractQueryMsg::<Empty, Empty>::from(
         interface2::sv::SylviaInterface2QueryMsg::Interface2MethodQuery {},
     );
-    let _ =
-        sv::ContractSudoMsg::from(interface2::sv::SylviaInterface2SudoMsg::Interface2MethodSudo {});
+    let _ = sv::ContractSudoMsg::<Empty, Empty>::from(
+        interface2::sv::SylviaInterface2SudoMsg::Interface2MethodSudo {},
+    );
 
-    let _ = sv::ContractExecMsg::from(sv::ExecMsg::ContractMethodExec {});
-    let _ = sv::ContractQueryMsg::from(sv::QueryMsg::ContractMethodQuery {});
-    let _ = sv::ContractSudoMsg::from(sv::SudoMsg::ContractMethodSudo {});
+    let _ = sv::ContractExecMsg::<Empty, Empty>::from(sv::ExecMsg::ContractMethodExec {});
+    let _ = sv::ContractQueryMsg::<Empty, Empty>::from(sv::QueryMsg::ContractMethodQuery {});
+    let _ = sv::ContractSudoMsg::<Empty, Empty>::from(sv::SudoMsg::ContractMethodSudo {});
 }