Repository: CosmWasm/sylvia
Pull request #411 (2024-08-05 17:07:10)

chore: Setup new directory structure

codecov[bot]: ## [Codecov](https://app.codecov.io/gh/CosmWasm/sylvia/pull/411?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=CosmWasm) Report
Attention: Patch coverage is `87.00422%` with `154 lines` in your changes missing coverage. Please review.
> Project coverage is 85.15%. Comparing base [(`bbd4eb2`)](https://app.codecov.io/gh/CosmWasm/sylvia/commit/bbd4eb28a30a4ec83f893d059d263aaa86e4bce1?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=CosmWasm) to head [(`3f2a751`)](https://app.codecov.io/gh/CosmWasm/sylvia/commit/3f2a751681a599ba1f441743df1730175e32bfdf?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=CosmWasm).

| [Files](https://app.codecov.io/gh/CosmWasm/sylvia/pull/411?dropdown=coverage&src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=CosmWasm) | Patch % | Lines |
|---|---|---|
| [sylvia-derive/src/entry\_points.rs](https://app.codecov.io/gh/CosmWasm/sylvia/pull/411?src=pr&el=tree&filepath=sylvia-derive%2Fsrc%2Fentry_points.rs&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=CosmWasm#diff-c3lsdmlhLWRlcml2ZS9zcmMvZW50cnlfcG9pbnRzLnJz) | 0.00% | [102 Missing :warning: ](https://app.codecov.io/gh/CosmWasm/sylvia/pull/411?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=CosmWasm) |
| [sylvia-derive/src/interface.rs](https://app.codecov.io/gh/CosmWasm/sylvia/pull/411?src=pr&el=tree&filepath=sylvia-derive%2Fsrc%2Finterface.rs&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=CosmWasm#diff-c3lsdmlhLWRlcml2ZS9zcmMvaW50ZXJmYWNlLnJz) | 78.43% | [22 Missing :warning: ](https://app.codecov.io/gh/CosmWasm/sylvia/pull/411?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=CosmWasm) |
| [sylvia-derive/src/interface/mt.rs](https://app.codecov.io/gh/CosmWasm/sylvia/pull/411?src=pr&el=tree&filepath=sylvia-derive%2Fsrc%2Finterface%2Fmt.rs&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=CosmWasm#diff-c3lsdmlhLWRlcml2ZS9zcmMvaW50ZXJmYWNlL210LnJz) | 92.56% | [11 Missing :warning: ](https://app.codecov.io/gh/CosmWasm/sylvia/pull/411?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=CosmWasm) |
| [...ia-derive/src/contract/communication/struct\_msg.rs](https://app.codecov.io/gh/CosmWasm/sylvia/pull/411?src=pr&el=tree&filepath=sylvia-derive%2Fsrc%2Fcontract%2Fcommunication%2Fstruct_msg.rs&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=CosmWasm#diff-c3lsdmlhLWRlcml2ZS9zcmMvY29udHJhY3QvY29tbXVuaWNhdGlvbi9zdHJ1Y3RfbXNnLnJz) | 89.01% | [10 Missing :warning: ](https://app.codecov.io/gh/CosmWasm/sylvia/pull/411?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=CosmWasm) |
| [sylvia-derive/src/types/msg\_field.rs](https://app.codecov.io/gh/CosmWasm/sylvia/pull/411?src=pr&el=tree&filepath=sylvia-derive%2Fsrc%2Ftypes%2Fmsg_field.rs&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=CosmWasm#diff-c3lsdmlhLWRlcml2ZS9zcmMvdHlwZXMvbXNnX2ZpZWxkLnJz) | 93.61% | [3 Missing :warning: ](https://app.codecov.io/gh/CosmWasm/sylvia/pull/411?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=CosmWasm) |
| [sylvia-derive/src/types/msg\_variant.rs](https://app.codecov.io/gh/CosmWasm/sylvia/pull/411?src=pr&el=tree&filepath=sylvia-derive%2Fsrc%2Ftypes%2Fmsg_variant.rs&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=CosmWasm#diff-c3lsdmlhLWRlcml2ZS9zcmMvdHlwZXMvbXNnX3ZhcmlhbnQucnM=) | 97.82% | [3 Missing :warning: ](https://app.codecov.io/gh/CosmWasm/sylvia/pull/411?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=CosmWasm) |
| [...a-derive/src/contract/communication/wrapper\_msg.rs](https://app.codecov.io/gh/CosmWasm/sylvia/pull/411?src=pr&el=tree&filepath=sylvia-derive%2Fsrc%2Fcontract%2Fcommunication%2Fwrapper_msg.rs&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=CosmWasm#diff-c3lsdmlhLWRlcml2ZS9zcmMvY29udHJhY3QvY29tbXVuaWNhdGlvbi93cmFwcGVyX21zZy5ycw==) | 98.41% | [2 Missing :warning: ](https://app.codecov.io/gh/CosmWasm/sylvia/pull/411?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=CosmWasm) |
| [sylvia-derive/src/contract.rs](https://app.codecov.io/gh/CosmWasm/sylvia/pull/411?src=pr&el=tree&filepath=sylvia-derive%2Fsrc%2Fcontract.rs&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=CosmWasm#diff-c3lsdmlhLWRlcml2ZS9zcmMvY29udHJhY3QucnM=) | 98.64% | [1 Missing :warning: ](https://app.codecov.io/gh/CosmWasm/sylvia/pull/411?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=CosmWasm) |

<details><summary>Additional details and impacted files</summary>


```diff
@@                       Coverage Diff                       @@
##           jawoznia/fix_attr_on_struct     #411      +/-   ##
===============================================================
+ Coverage                        85.05%   85.15%   +0.09%     
===============================================================
  Files                               42       54      +12     
  Lines                             2924     3024     +100     
===============================================================
+ Hits                              2487     2575      +88     
- Misses                             437      449      +12     
```

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/CosmWasm/sylvia/pull/411?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=CosmWasm).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=CosmWasm).


Patch:
diff --git a/sylvia-derive/src/contract.rs b/sylvia-derive/src/contract.rs
new file mode 100644
index 0000000..780474d
--- /dev/null
+++ b/sylvia-derive/src/contract.rs
@@ -0,0 +1,162 @@
+use communication::api::Api;
+use communication::enum_msg::EnumMessage;
+use communication::executor::Executor;
+use communication::querier::Querier;
+use communication::struct_msg::StructMessage;
+use communication::wrapper_msg::GlueMessage;
+use mt::MtHelpers;
+use proc_macro2::TokenStream;
+use quote::quote;
+use syn::{GenericParam, ItemImpl};
+
+use crate::parser::attributes::msg::MsgType;
+use crate::parser::variant_descs::AsVariantDescs;
+use crate::parser::{
+    assert_new_method_defined, ContractErrorAttr, Custom, OverrideEntryPoint,
+    ParsedSylviaAttributes,
+};
+use crate::types::interfaces::Interfaces;
+use crate::types::msg_variant::MsgVariants;
+
+mod communication;
+mod mt;
+
+/// Preprocessed `contract` macro input for non-trait impl block
+pub struct ContractInput<'a> {
+    error: ContractErrorAttr,
+    item: &'a ItemImpl,
+    generics: Vec<&'a GenericParam>,
+    custom: Custom,
+    override_entry_points: Vec<OverrideEntryPoint>,
+    interfaces: Interfaces,
+}
+
+impl<'a> ContractInput<'a> {
+    pub fn new(item: &'a ItemImpl) -> Self {
+        assert_new_method_defined(item);
+
+        let generics = item.generics.params.iter().collect();
+        let parsed_attrs = ParsedSylviaAttributes::new(item.attrs.iter());
+        let error = parsed_attrs.error_attrs.unwrap_or_default();
+        let custom = parsed_attrs.custom_attr.unwrap_or_default();
+        let override_entry_points = parsed_attrs.override_entry_point_attrs;
+        let interfaces = Interfaces::new(item);
+
+        Self {
+            item,
+            generics,
+            error,
+            custom,
+            override_entry_points,
+            interfaces,
+        }
+    }
+
+    pub fn process(&self) -> TokenStream {
+        let Self {
+            item,
+            generics,
+            custom,
+            ..
+        } = self;
+        let multitest_helpers = self.emit_multitest_helpers();
+
+        let executor_variants = MsgVariants::new(item.as_variants(), MsgType::Exec, &[], &None);
+        let querier_variants = MsgVariants::new(item.as_variants(), MsgType::Query, &[], &None);
+        let executor = Executor::new(
+            item.generics.clone(),
+            *item.self_ty.clone(),
+            executor_variants,
+        )
+        .emit();
+        let querier = Querier::new(
+            item.generics.clone(),
+            *item.self_ty.clone(),
+            querier_variants,
+        )
+        .emit();
+        let messages = self.emit_messages();
+        let contract_api = Api::new(item, generics, custom).emit();
+
+        quote! {
+            pub mod sv {
+                use super::*;
+
+                #messages
+
+                #multitest_helpers
+
+                #querier
+
+                #executor
+
+                #contract_api
+            }
+        }
+    }
+
+    fn emit_messages(&self) -> TokenStream {
+        let instantiate = self.emit_struct_msg(MsgType::Instantiate);
+        let migrate = self.emit_struct_msg(MsgType::Migrate);
+        let exec_impl = self.emit_enum_msg(MsgType::Exec);
+        let query_impl = self.emit_enum_msg(MsgType::Query);
+        let sudo_impl = self.emit_enum_msg(MsgType::Sudo);
+        let exec = self.emit_glue_msg(MsgType::Exec);
+        let query = self.emit_glue_msg(MsgType::Query);
+        let sudo = self.emit_glue_msg(MsgType::Sudo);
+
+        quote! {
+            #instantiate
+
+            #exec_impl
+
+            #query_impl
+
+            #sudo_impl
+
+            #migrate
+
+            #exec
+
+            #query
+
+            #sudo
+        }
+    }
+
+    fn emit_struct_msg(&self, msg_ty: MsgType) -> TokenStream {
+        StructMessage::new(self.item, msg_ty, &self.generics, &self.custom)
+            .map_or(quote! {}, |msg| msg.emit())
+    }
+
+    fn emit_enum_msg(&self, msg_ty: MsgType) -> TokenStream {
+        EnumMessage::new(self.item, msg_ty, &self.generics, &self.error, &self.custom).emit()
+    }
+
+    fn emit_glue_msg(&self, msg_ty: MsgType) -> TokenStream {
+        GlueMessage::new(
+            self.item,
+            msg_ty,
+            &self.error,
+            &self.custom,
+            &self.interfaces,
+        )
+        .emit()
+    }
+
+    fn emit_multitest_helpers(&self) -> TokenStream {
+        if !cfg!(feature = "mt") {
+            return quote! {};
+        }
+
+        let Self {
+            item,
+            custom,
+            override_entry_points,
+            ..
+        } = self;
+
+        let generic_params = &self.generics;
+        MtHelpers::new(item, generic_params, custom, override_entry_points.clone()).emit()
+    }
+}
diff --git a/sylvia-derive/src/contract/communication/api.rs b/sylvia-derive/src/contract/communication/api.rs
new file mode 100644
index 0000000..48d4907
--- /dev/null
+++ b/sylvia-derive/src/contract/communication/api.rs
@@ -0,0 +1,124 @@
+use crate::crate_module;
+use crate::parser::variant_descs::AsVariantDescs;
+use crate::parser::{Custom, MsgType};
+use crate::types::msg_variant::MsgVariants;
+use crate::utils::emit_bracketed_generics;
+use proc_macro2::TokenStream;
+use quote::quote;
+use syn::{GenericParam, ItemImpl};
+
+pub struct Api<'a> {
+    source: &'a ItemImpl,
+    exec_variants: MsgVariants<'a, GenericParam>,
+    query_variants: MsgVariants<'a, GenericParam>,
+    instantiate_variants: MsgVariants<'a, GenericParam>,
+    migrate_variants: MsgVariants<'a, GenericParam>,
+    sudo_variants: MsgVariants<'a, GenericParam>,
+    generics: &'a [&'a GenericParam],
+    custom: &'a Custom,
+}
+
+impl<'a> Api<'a> {
+    pub fn new(source: &'a ItemImpl, generics: &'a [&'a GenericParam], custom: &'a Custom) -> Self {
+        let exec_variants = MsgVariants::new(
+            source.as_variants(),
+            MsgType::Exec,
+            generics,
+            &source.generics.where_clause,
+        );
+
+        let query_variants = MsgVariants::new(
+            source.as_variants(),
+            MsgType::Query,
+            generics,
+            &source.generics.where_clause,
+        );
+
+        let instantiate_variants = MsgVariants::new(
+            source.as_variants(),
+            MsgType::Instantiate,
+            generics,
+            &source.generics.where_clause,
+        );
+
+        let migrate_variants = MsgVariants::new(
+            source.as_variants(),
+            MsgType::Migrate,
+            generics,
+            &source.generics.where_clause,
+        );
+
+        let sudo_variants = MsgVariants::new(
+            source.as_variants(),
+            MsgType::Sudo,
+            generics,
+            &source.generics.where_clause,
+        );
+
+        Self {
+            source,
+            exec_variants,
+            query_variants,
+            instantiate_variants,
+            migrate_variants,
+            sudo_variants,
+            generics,
+            custom,
+        }
+    }
+
+    pub fn emit(&self) -> TokenStream {
+        let sylvia = crate_module();
+        let Self {
+            source,
+            exec_variants,
+            query_variants,
+            instantiate_variants,
+            migrate_variants,
+            sudo_variants,
+            generics,
+            custom,
+            ..
+        } = self;
+
+        let where_clause = &source.generics.where_clause;
+        let contract_name = &source.self_ty;
+        let exec_generics = &exec_variants.used_generics();
+        let query_generics = &query_variants.used_generics();
+        let instantiate_generics = &instantiate_variants.used_generics();
+        let migrate_generics = &migrate_variants.used_generics();
+        let sudo_generics = &sudo_variants.used_generics();
+
+        let bracket_generics = emit_bracketed_generics(generics);
+        let exec_bracketed_generics = emit_bracketed_generics(exec_generics);
+        let query_bracketed_generics = emit_bracketed_generics(query_generics);
+        let sudo_bracketed_generics = emit_bracketed_generics(sudo_generics);
+        let instantiate_bracketed_generics = emit_bracketed_generics(instantiate_generics);
+        let migrate_bracketed_generics = emit_bracketed_generics(migrate_generics);
+
+        let migrate_type = if migrate_variants.variants().count() != 0 {
+            quote! { type Migrate = MigrateMsg #migrate_bracketed_generics; }
+        } else {
+            quote! { type Migrate = #sylvia ::cw_std::Empty; }
+        };
+        let custom_msg = custom.msg_or_default();
+        let custom_query = custom.query_or_default();
+
+        quote! {
+            impl #bracket_generics #sylvia ::types::ContractApi for #contract_name #where_clause {
+                type ContractExec = ContractExecMsg #bracket_generics;
+                type ContractQuery = ContractQueryMsg #bracket_generics;
+                type ContractSudo = ContractSudoMsg #bracket_generics;
+                type Exec = ExecMsg #exec_bracketed_generics;
+                type Query = QueryMsg #query_bracketed_generics;
+                type Sudo = SudoMsg #sudo_bracketed_generics;
+                type Instantiate = InstantiateMsg #instantiate_bracketed_generics;
+                #migrate_type
+                type Remote<'remote> = #sylvia ::types::Remote<'remote, Self >;
+                type Querier<'querier> = #sylvia ::types::BoundQuerier<'querier, #custom_query, Self >;
+                type CustomMsg = #custom_msg;
+                type CustomQuery = #custom_query;
+            }
+        }
+    }
+}
diff --git a/sylvia-derive/src/contract/communication/enum_msg.rs b/sylvia-derive/src/contract/communication/enum_msg.rs
new file mode 100644
index 0000000..ad3ffa8
--- /dev/null
+++ b/sylvia-derive/src/contract/communication/enum_msg.rs
@@ -0,0 +1,125 @@
+use crate::crate_module;
+use crate::parser::attributes::MsgAttrForwarding;
+use crate::parser::variant_descs::AsVariantDescs;
+use crate::parser::{ContractErrorAttr, Custom, MsgType, ParsedSylviaAttributes};
+use crate::types::msg_variant::MsgVariants;
+use crate::utils::emit_bracketed_generics;
+use proc_macro2::TokenStream;
+use quote::quote;
+use syn::spanned::Spanned;
+use syn::{GenericParam, Ident, ItemImpl, Type, WhereClause};
+
+/// Representation of single enum message
+pub struct EnumMessage<'a> {
+    variants: MsgVariants<'a, GenericParam>,
+    msg_ty: MsgType,
+    contract: &'a Type,
+    error: &'a ContractErrorAttr,
+    custom: &'a Custom,
+    where_clause: &'a Option<WhereClause>,
+    msg_attrs_to_forward: Vec<MsgAttrForwarding>,
+}
+
+impl<'a> EnumMessage<'a> {
+    pub fn new(
+        source: &'a ItemImpl,
+        msg_ty: MsgType,
+        generics: &'a [&'a GenericParam],
+        error: &'a ContractErrorAttr,
+        custom: &'a Custom,
+    ) -> Self {
+        let where_clause = &source.generics.where_clause;
+        let variants = MsgVariants::new(source.as_variants(), msg_ty, generics, where_clause);
+        let msg_attrs_to_forward = ParsedSylviaAttributes::new(source.attrs.iter())
+            .msg_attrs_forward
+            .into_iter()
+            .filter(|attr| attr.msg_type == msg_ty)
+            .collect();
+
+        Self {
+            variants,
+            msg_ty,
+            contract: &source.self_ty,
+            error,
+            custom,
+            where_clause,
+            msg_attrs_to_forward,
+        }
+    }
+
+    pub fn emit(&self) -> TokenStream {
+        let sylvia = crate_module();
+
+        let Self {
+            variants,
+            msg_ty,
+            contract,
+            error,
+            custom,
+            where_clause,
+            msg_attrs_to_forward,
+            ..
+        } = self;
+
+        let enum_name = msg_ty.emit_msg_name();
+        let match_arms = variants.emit_dispatch_legs();
+        let unused_generics = variants.unused_generics();
+        let bracketed_unused_generics = emit_bracketed_generics(unused_generics);
+        let used_generics = variants.used_generics();
+        let bracketed_used_generics = emit_bracketed_generics(used_generics);
+
+        let mut variant_names = variants.as_names_snake_cased();
+        variant_names.sort();
+        let variants_cnt = variant_names.len();
+        let variants_constructors = variants.emit_constructors();
+        let variants = variants.emit();
+
+        let ctx_type = msg_ty.emit_ctx_type(&custom.query_or_default());
+        let ret_type = msg_ty.emit_result_type(&custom.msg_or_default(), &error.error);
+
+        let derive_query = match msg_ty {
+            MsgType::Query => quote! { #sylvia ::cw_schema::QueryResponses },
+            _ => quote! {},
+        };
+
+        let ep_name = msg_ty.emit_ep_name();
+        let messages_fn_name = Ident::new(&format!("{}_messages", ep_name), contract.span());
+
+        let phantom_variant = msg_ty.emit_phantom_variant(used_generics);
+        let phantom_match_arm = match !used_generics.is_empty() {
+            true => quote! {
+                _Phantom(_) => Err(#sylvia ::cw_std::StdError::generic_err("Phantom message should not be constructed.")).map_err(Into::into),
+            },
+            false => quote! {},
+        };
+        let msg_attrs_to_forward = msg_attrs_to_forward.iter().map(|attr| &attr.attrs);
+
+        quote! {
+            #[allow(clippy::derive_partial_eq_without_eq)]
+            #[derive(#sylvia ::serde::Serialize, #sylvia ::serde::Deserialize, Clone, Debug, PartialEq, #sylvia ::schemars::JsonSchema, #derive_query )]
+            #( #[ #msg_attrs_to_forward ] )*
+            #[serde(rename_all="snake_case")]
+            pub enum #enum_name #bracketed_used_generics {
+                #(#variants,)*
+                #phantom_variant
+            }
+
+            impl #bracketed_used_generics #enum_name #bracketed_used_generics {
+                pub fn dispatch #bracketed_unused_generics (self, contract: &#contract, ctx: #ctx_type) -> #ret_type #where_clause {
+                    use #enum_name::*;
+
+                    match self {
+                        #(#match_arms,)*
+                        #phantom_match_arm
+                    }
+                }
+
+                #(#variants_constructors)*
+            }
+
+            pub const fn #messages_fn_name () -> [&'static str; #variants_cnt] {
+                [#(#variant_names,)*]
+            }
+        }
+    }
+}
diff --git a/sylvia-derive/src/contract/communication/executor.rs b/sylvia-derive/src/contract/communication/executor.rs
new file mode 100644
index 0000000..02f56e2
--- /dev/null
+++ b/sylvia-derive/src/contract/communication/executor.rs
@@ -0,0 +1,117 @@
+use convert_case::Case;
+use proc_macro2::TokenStream;
+use quote::quote;
+use syn::{GenericParam, Generics, Type};
+
+use crate::crate_module;
+use crate::parser::attributes::msg::MsgType;
+use crate::types::associated_types::EmitAssociated;
+use crate::types::msg_field::MsgField;
+use crate::types::msg_variant::{MsgVariant, MsgVariants};
+use crate::utils::SvCasing;
+
+pub struct Executor<'a> {
+    generics: Generics,
+    self_ty: Type,
+    variants: MsgVariants<'a, GenericParam>,
+}
+
+impl<'a> Executor<'a> {
+    pub fn new(generics: Generics, self_ty: Type, variants: MsgVariants<'a, GenericParam>) -> Self {
+        Self {
+            generics,
+            self_ty,
+            variants,
+        }
+    }
+
+    pub fn emit(&self) -> TokenStream {
+        let sylvia = crate_module();
+        let Self {
+            generics,
+            self_ty,
+            variants,
+            ..
+        } = self;
+
+        let where_clause = &generics.where_clause;
+        let generics: Vec<_> = generics.params.iter().collect();
+        let contract = &self_ty;
+
+        let accessor = MsgType::Exec.as_accessor_name();
+        let executor_api_path = quote! { < #contract as #sylvia ::types::ContractApi>:: #accessor };
+
+        let executor_methods_impl = variants
+            .variants()
+            .map(|variant| variant.emit_executor_impl(&executor_api_path));
+
+        let executor_methods_declaration = variants
+            .variants()
+            .map(|variant| variant.emit_executor_method_declaration());
+
+        let types_declaration = where_clause
+            .as_ref()
+            .map(EmitAssociated::emit_declaration)
+            .unwrap_or(vec![]);
+
+        let types_implementation = where_clause
+            .as_ref()
+            .map(EmitAssociated::emit_implementation)
+            .unwrap_or(vec![]);
+
+        quote! {
+            pub trait Executor<#(#generics,)*> #where_clause {
+                #(#types_declaration)*
+                #(#executor_methods_declaration)*
+            }
+
+            impl <#(#generics,)*> Executor<#(#generics,)*>
+                for #sylvia ::types::ExecutorBuilder<( #sylvia ::types::EmptyExecutorBuilderState, #contract )> #where_clause {
+                #(#types_implementation)*
+                #(#executor_methods_impl)*
+            }
+        }
+    }
+}
+
+trait EmitExecutorMethod {
+    fn emit_executor_impl(&self, api_path: &TokenStream) -> TokenStream;
+    fn emit_executor_method_declaration(&self) -> TokenStream;
+}
+
+impl EmitExecutorMethod for MsgVariant<'_> {
+    fn emit_executor_impl(&self, api_path: &TokenStream) -> TokenStream {
+        let name = self.name();
+        let fields = self.fields();
+        let sylvia = crate_module();
+
+        let parameters = fields.iter().map(MsgField::emit_method_field_folded);
+        let fields_names = fields.iter().map(MsgField::name);
+        let variant_name = name.to_case(Case::Snake);
+
+        quote! {
+            fn #variant_name(self, #(#parameters),*) -> Result<#sylvia ::types::ExecutorBuilder< #sylvia ::types::ReadyExecutorBuilderState >, #sylvia ::cw_std::StdError> {
+                Ok(#sylvia ::types::ExecutorBuilder::<#sylvia ::types::ReadyExecutorBuilderState>::new(
+                    self.contract().to_owned(),
+                    self.funds().to_owned(),
+                    #sylvia ::cw_std::to_json_binary( & #api_path :: #variant_name (#(#fields_names),*) )?,
+                ))
+            }
+        }
+    }
+
+    fn emit_executor_method_declaration(&self) -> TokenStream {
+        let name = self.name();
+        let sylvia = crate_module();
+
+        let parameters = self
+            .fields()
+            .iter()
+            .map(|field| field.emit_method_field_folded());
+        let variant_name = name.to_case(Case::Snake);
+
+        quote! {
+            fn #variant_name(self, #(#parameters),*) -> Result< #sylvia ::types::ExecutorBuilder<#sylvia ::types::ReadyExecutorBuilderState>, #sylvia ::cw_std::StdError>;
+        }
+    }
+}
diff --git a/sylvia-derive/src/contract/communication/mod.rs b/sylvia-derive/src/contract/communication/mod.rs
new file mode 100644
index 0000000..012695c
--- /dev/null
+++ b/sylvia-derive/src/contract/communication/mod.rs
@@ -0,0 +1,6 @@
+pub mod api;
+pub mod enum_msg;
+pub mod executor;
+pub mod querier;
+pub mod struct_msg;
+pub mod wrapper_msg;
diff --git a/sylvia-derive/src/contract/communication/querier.rs b/sylvia-derive/src/contract/communication/querier.rs
new file mode 100644
index 0000000..4ef785d
--- /dev/null
+++ b/sylvia-derive/src/contract/communication/querier.rs
@@ -0,0 +1,121 @@
+use convert_case::Case;
+use proc_macro2::TokenStream;
+use quote::quote;
+use syn::{GenericParam, Generics, Type};
+
+use crate::crate_module;
+use crate::parser::attributes::msg::MsgType;
+use crate::types::associated_types::EmitAssociated;
+use crate::types::msg_field::MsgField;
+use crate::types::msg_variant::{MsgVariant, MsgVariants};
+use crate::utils::SvCasing;
+
+pub struct Querier<'a> {
+    generics: Generics,
+    self_ty: Type,
+    variants: MsgVariants<'a, GenericParam>,
+}
+
+impl<'a> Querier<'a> {
+    pub fn new(generics: Generics, self_ty: Type, variants: MsgVariants<'a, GenericParam>) -> Self {
+        Self {
+            generics,
+            self_ty,
+            variants,
+        }
+    }
+
+    pub fn emit(&self) -> TokenStream {
+        let sylvia = crate_module();
+        let Self {
+            generics,
+            self_ty,
+            variants,
+            ..
+        } = self;
+
+        let where_clause = &generics.where_clause;
+        let generics: Vec<_> = generics.params.iter().collect();
+        let contract = &self_ty;
+
+        let accessor = MsgType::Query.as_accessor_name();
+        let api_path = quote! { < #contract as #sylvia ::types::ContractApi>:: #accessor };
+
+        let querier_methods_impl = variants
+            .variants()
+            .map(|variant| variant.emit_querier_impl(&api_path));
+
+        let querier_methods_declaration = variants
+            .variants()
+            .map(|variant| variant.emit_querier_method_declaration());
+
+        let types_declaration = where_clause
+            .as_ref()
+            .map(EmitAssociated::emit_declaration)
+            .unwrap_or(vec![]);
+
+        let types_implementation = where_clause
+            .as_ref()
+            .map(EmitAssociated::emit_implementation)
+            .unwrap_or(vec![]);
+
+        let bracketed_generics = if !generics.is_empty() {
+            quote! { < #(#generics,)* > }
+        } else {
+            quote! {}
+        };
+
+        quote! {
+            pub trait Querier #bracketed_generics {
+                #(#types_declaration)*
+                #(#querier_methods_declaration)*
+            }
+
+            impl <'sv_querier_lifetime, #(#generics,)* C: #sylvia ::cw_std::CustomQuery> Querier #bracketed_generics for #sylvia ::types::BoundQuerier<'sv_querier_lifetime, C, #contract > #where_clause {
+                #(#types_implementation)*
+                #(#querier_methods_impl)*
+            }
+        }
+    }
+}
+
+trait EmitQuerierMethod {
+    fn emit_querier_impl(&self, api_path: &TokenStream) -> TokenStream;
+    fn emit_querier_method_declaration(&self) -> TokenStream;
+}
+
+impl EmitQuerierMethod for MsgVariant<'_> {
+    fn emit_querier_impl(&self, api_path: &TokenStream) -> TokenStream {
+        let sylvia = crate_module();
+        let name = self.name();
+        let fields = self.fields();
+        let return_type = self.return_type();
+
+        let parameters = fields.iter().map(MsgField::emit_method_field_folded);
+        let fields_names = fields.iter().map(MsgField::name);
+        let variant_name = name.to_case(Case::Snake);
+
+        quote! {
+            fn #variant_name(&self, #(#parameters),*) -> Result< #return_type, #sylvia:: cw_std::StdError> {
+                let query = #api_path :: #variant_name (#(#fields_names),*);
+                self.querier().query_wasm_smart(self.contract(), &query)
+            }
+        }
+    }
+
+    fn emit_querier_method_declaration(&self) -> TokenStream {
+        let sylvia = crate_module();
+        let name = self.name();
+        let return_type = self.return_type();
+
+        let parameters = self
+            .fields()
+            .iter()
+            .map(|field| field.emit_method_field_folded());
+        let variant_name = name.to_case(Case::Snake);
+
+        quote! {
+            fn #variant_name(&self, #(#parameters),*) -> Result< #return_type, #sylvia:: cw_std::StdError>;
+        }
+    }
+}
diff --git a/sylvia-derive/src/contract/communication/struct_msg.rs b/sylvia-derive/src/contract/communication/struct_msg.rs
new file mode 100644
index 0000000..6e30e53
--- /dev/null
+++ b/sylvia-derive/src/contract/communication/struct_msg.rs
@@ -0,0 +1,174 @@
+use crate::crate_module;
+use crate::parser::attributes::MsgAttrForwarding;
+use crate::parser::check_generics::CheckGenerics;
+use crate::parser::{Custom, MsgAttr, MsgType, ParsedSylviaAttributes};
+use crate::types::msg_field::MsgField;
+use crate::utils::{as_where_clause, emit_bracketed_generics, filter_wheres, process_fields};
+use proc_macro2::{Span, TokenStream};
+use proc_macro_error::emit_error;
+use quote::quote;
+use syn::spanned::Spanned;
+use syn::{
+    GenericParam, Ident, ImplItem, ImplItemFn, ItemImpl, ReturnType, Type, WhereClause,
+    WherePredicate,
+};
+
+/// Representation of single struct message
+pub struct StructMessage<'a> {
+    contract_type: &'a Type,
+    fields: Vec<MsgField<'a>>,
+    function_name: &'a Ident,
+    generics: Vec<&'a GenericParam>,
+    unused_generics: Vec<&'a GenericParam>,
+    wheres: Vec<&'a WherePredicate>,
+    full_where: Option<&'a WhereClause>,
+    result: &'a ReturnType,
+    msg_attr: MsgAttr,
+    custom: &'a Custom,
+    msg_attrs_to_forward: Vec<MsgAttrForwarding>,
+}
+
+impl<'a> StructMessage<'a> {
+    /// Creates new struct message of given type from impl block
+    pub fn new(
+        source: &'a ItemImpl,
+        ty: MsgType,
+        generics: &'a [&'a GenericParam],
+        custom: &'a Custom,
+    ) -> Option<StructMessage<'a>> {
+        let mut generics_checker = CheckGenerics::new(generics);
+
+        let contract_type = &source.self_ty;
+
+        let parsed = Self::parse_struct_message(source, ty);
+        let (method, msg_attr) = parsed?;
+
+        let function_name = &method.sig.ident;
+        let fields = process_fields(&method.sig, &mut generics_checker);
+        let (used_generics, unused_generics) = generics_checker.used_unused();
+        let wheres = filter_wheres(&source.generics.where_clause, generics, &used_generics);
+
+        let msg_attrs_to_forward = ParsedSylviaAttributes::new(source.attrs.iter())
+            .msg_attrs_forward
+            .into_iter()
+            .filter(|attr| attr.msg_type == ty)
+            .collect();
+
+        Some(Self {
+            contract_type,
+            fields,
+            function_name,
+            generics: used_generics,
+            unused_generics,
+            wheres,
+            full_where: source.generics.where_clause.as_ref(),
+            result: &method.sig.output,
+            msg_attr,
+            custom,
+            msg_attrs_to_forward,
+        })
+    }
+
+    fn parse_struct_message(source: &ItemImpl, ty: MsgType) -> Option<(&ImplItemFn, MsgAttr)> {
+        let mut methods = source.items.iter().filter_map(|item| match item {
+            ImplItem::Fn(method) => {
+                let attr = ParsedSylviaAttributes::new(method.attrs.iter()).msg_attr?;
+                if attr == ty {
+                    Some((method, attr))
+                } else {
+                    None
+                }
+            }
+            _ => None,
+        });
+
+        let (method, msg_attr) = if let Some(method) = methods.next() {
+            method
+        } else {
+            if ty == MsgType::Instantiate {
+                emit_error!(
+                    source.span(), "Missing instantiation message.";
+                    note = source.span() => "`sylvia::contract` requires exactly one method marked with `#[sv::msg(instantiation)]` attribute."
+                );
+            }
+            return None;
+        };
+
+        if let Some((obsolete, _)) = methods.next() {
+            emit_error!(
+                obsolete.span(), "More than one instantiation or migration message";
+                note = method.span() => "Instantiation/Migration message previously defined here"
+            );
+        }
+        Some((method, msg_attr))
+    }
+
+    pub fn emit(&self) -> TokenStream {
+        use MsgAttr::*;
+
+        let instantiate_msg = Ident::new("InstantiateMsg", self.function_name.span());
+        let migrate_msg = Ident::new("MigrateMsg", self.function_name.span());
+
+        match &self.msg_attr {
+            Instantiate { .. } => self.emit_struct(&instantiate_msg),
+            Migrate { .. } => self.emit_struct(&migrate_msg),
+            _ => {
+                emit_error!(Span::mixed_site(), "Invalid message type");
+                quote! {}
+            }
+        }
+    }
+
+    pub fn emit_struct(&self, name: &Ident) -> TokenStream {
+        let sylvia = crate_module();
+
+        let Self {
+            contract_type,
+            fields,
+            function_name,
+            generics,
+            unused_generics,
+            wheres,
+            full_where,
+            result,
+            msg_attr,
+            custom,
+            msg_attrs_to_forward,
+        } = self;
+
+        let ctx_type = msg_attr
+            .msg_type()
+            .emit_ctx_type(&custom.query_or_default());
+        let fields_names: Vec<_> = fields.iter().map(MsgField::name).collect();
+        let parameters = fields.iter().map(MsgField::emit_method_field);
+        let fields = fields.iter().map(MsgField::emit_pub);
+
+        let where_clause = as_where_clause(wheres);
+        let generics = emit_bracketed_generics(generics);
+        let unused_generics = emit_bracketed_generics(unused_generics);
+        let msg_attrs_to_forward = msg_attrs_to_forward.iter().map(|attr| &attr.attrs);
+
+        quote! {
+            #[allow(clippy::derive_partial_eq_without_eq)]
+            #[derive(#sylvia ::serde::Serialize, #sylvia ::serde::Deserialize, Clone, Debug, PartialEq, #sylvia ::schemars::JsonSchema)]
+            #( #[ #msg_attrs_to_forward ] )*
+            #[serde(rename_all="snake_case")]
+            pub struct #name #generics {
+                #(#fields,)*
+            }
+
+            impl #generics #name #generics #where_clause {
+                pub fn new(#(#parameters,)*) -> Self {
+                    Self { #(#fields_names,)* }
+                }
+
+                pub fn dispatch #unused_generics(self, contract: &#contract_type, ctx: #ctx_type)
+                    #result #full_where
+                {
+                    let Self { #(#fields_names,)* } = self;
+                    contract.#function_name(Into::into(ctx), #(#fields_names,)*).map_err(Into::into)
+                }
+            }
+        }
+    }
+}
diff --git a/sylvia-derive/src/contract/communication/wrapper_msg.rs b/sylvia-derive/src/contract/communication/wrapper_msg.rs
new file mode 100644
index 0000000..ff0da79
--- /dev/null
+++ b/sylvia-derive/src/contract/communication/wrapper_msg.rs
@@ -0,0 +1,240 @@
+use crate::crate_module;
+use crate::fold::StripGenerics;
+use crate::parser::{ContractErrorAttr, Custom, MsgType};
+use crate::types::interfaces::Interfaces;
+use crate::utils::emit_bracketed_generics;
+use proc_macro2::TokenStream;
+use quote::quote;
+use syn::fold::Fold;
+use syn::spanned::Spanned;
+use syn::{Ident, ItemImpl, Type};
+
+/// Glue message is the message composing Exec/Query messages from several traits
+#[derive(Debug)]
+pub struct GlueMessage<'a> {
+    source: &'a ItemImpl,
+    contract: &'a Type,
+    msg_ty: MsgType,
+    error: &'a ContractErrorAttr,
+    custom: &'a Custom,
+    interfaces: &'a Interfaces,
+}
+
+impl<'a> GlueMessage<'a> {
+    pub fn new(
+        source: &'a ItemImpl,
+        msg_ty: MsgType,
+        error: &'a ContractErrorAttr,
+        custom: &'a Custom,
+        interfaces: &'a Interfaces,
+    ) -> Self {
+        GlueMessage {
+            source,
+            contract: &source.self_ty,
+            msg_ty,
+            error,
+            custom,
+            interfaces,
+        }
+    }
+
+    pub fn emit(&self) -> TokenStream {
+        let sylvia = crate_module();
+        let Self {
+            source,
+            contract,
+            msg_ty,
+            error,
+            custom,
+            interfaces,
+            ..
+        } = self;
+
+        let generics: Vec<_> = source.generics.params.iter().collect();
+        let full_where_clause = &source.generics.where_clause;
+        let bracketed_wrapper_generics = emit_bracketed_generics(&generics);
+
+        let contract_enum_name = msg_ty.emit_msg_wrapper_name();
+        let enum_accessor = msg_ty.as_accessor_name();
+        let contract_name = StripGenerics.fold_type((*contract).clone());
+
+        let variants = interfaces.emit_glue_message_variants(msg_ty, contract);
+        let types = interfaces.emit_glue_message_types(msg_ty, contract);
+
+        let ep_name = msg_ty.emit_ep_name();
+        let messages_fn_name = Ident::new(&format!("{}_messages", ep_name), contract.span());
+        let contract_variant = quote! { #contract_name ( <#contract as #sylvia ::types::ContractApi> :: #enum_accessor ) };
+        let mut messages_call = interfaces.emit_messages_call(msg_ty);
+        messages_call.push(quote! { &#messages_fn_name() });
+
+        let variants_cnt = messages_call.len();
+
+        let dispatch_arms = interfaces.emit_dispatch_arms(msg_ty);
+
+        let dispatch_arm =
+            quote! {#contract_enum_name :: #contract_name (msg) => msg.dispatch(contract, ctx)};
+
+        let interfaces_deserialization_attempts = interfaces.emit_deserialization_attempts(msg_ty);
+
+        let contract_deserialization_attempt = quote! {
+            let msgs = &#messages_fn_name();
+            if msgs.into_iter().any(|msg| msg == &recv_msg_name) {
+                match val.deserialize_into() {
+                    Ok(msg) => return Ok(Self:: #contract_name (msg)),
+                    Err(err) => return Err(D::Error::custom(err)).map(Self:: #contract_name )
+                };
+            }
+        };
+
+        let ctx_type = msg_ty.emit_ctx_type(&custom.query_or_default());
+        let ret_type = msg_ty.emit_result_type(&custom.msg_or_default(), &error.error);
+
+        let mut response_schemas_calls = interfaces.emit_response_schemas_calls(msg_ty, contract);
+        response_schemas_calls
+            .push(quote! {<#contract as #sylvia ::types::ContractApi> :: #enum_accessor ::response_schemas_impl()});
+
+        let response_schemas = match msg_ty {
+            MsgType::Query => {
+                quote! {
+                    #[cfg(not(target_arch = "wasm32"))]
+                    impl #bracketed_wrapper_generics #sylvia ::cw_schema::QueryResponses for #contract_enum_name #bracketed_wrapper_generics #full_where_clause {
+                        fn response_schemas_impl() -> std::collections::BTreeMap<String, #sylvia ::schemars::schema::RootSchema> {
+                            let responses = [#(#response_schemas_calls),*];
+                            responses.into_iter().flatten().collect()
+                        }
+                    }
+                }
+            }
+            _ => {
+                quote! {}
+            }
+        };
+
+        let modules_names = interfaces.variants_modules();
+        let variants_names = interfaces.variants_names();
+
+        quote! {
+            #[allow(clippy::derive_partial_eq_without_eq)]
+            #[derive(#sylvia ::serde::Serialize, Clone, Debug, PartialEq)]
+            #[serde(rename_all="snake_case", untagged)]
+            pub enum #contract_enum_name #bracketed_wrapper_generics #full_where_clause {
+                #(#variants,)*
+                #contract_variant
+            }
+
+            // `schemars` v0.8.16 requires every generic type to implement JsonSchema in
+            // order to use derive JsonSchema macro. The goal of that trait bound is to
+            // generate schema_name. Currently there's no way to provide such a name in an
+            // attribute, so Sylvia needs to implement this trait manually:
+            //
+            impl #bracketed_wrapper_generics #sylvia ::schemars::JsonSchema
+                for #contract_enum_name #bracketed_wrapper_generics #full_where_clause {
+
+                fn schema_name() -> std::string::String {
+                    {
+                        let res = format!(
+                                "{0}",
+                                std::any::type_name::<Self>()
+                        );
+                        res
+                    }
+                }
+
+                fn json_schema(
+                    gen: &mut #sylvia ::schemars::gen::SchemaGenerator,
+                ) -> #sylvia ::schemars::schema::Schema {
+                    #sylvia ::schemars::schema::Schema::Object( #sylvia ::schemars::schema::SchemaObject {
+                        subschemas: Some(
+                            Box::new( #sylvia ::schemars::schema::SubschemaValidation {
+                                any_of: Some(
+                                    <[_]>::into_vec(
+                                        Box::new([
+                                            #(gen.subschema_for::<#types>(),)*
+                                            gen.subschema_for::< <#contract as #sylvia ::types::ContractApi> :: #enum_accessor >(),
+                                        ]),
+                                    ),
+                                ),
+                                ..Default::default()
+                            }),
+                        ),
+                        ..Default::default()
+                    })
+                }
+            }
+
+            impl #bracketed_wrapper_generics #contract_enum_name #bracketed_wrapper_generics #full_where_clause {
+                pub fn dispatch (
+                    self,
+                    contract: &#contract,
+                    ctx: #ctx_type,
+                ) -> #ret_type #full_where_clause {
+                    const _: () = {
+                        let msgs: [&[&str]; #variants_cnt] = [#(#messages_call),*];
+                        #sylvia ::utils::assert_no_intersection(msgs);
+                    };
+
+                    match self {
+                        #(#dispatch_arms,)*
+                        #dispatch_arm
+                    }
+                }
+            }
+
+            #response_schemas
+
+            impl<'sv_de, #(#generics,)* > serde::Deserialize<'sv_de> for #contract_enum_name #bracketed_wrapper_generics #full_where_clause {
+                fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+                    where D: serde::Deserializer<'sv_de>,
+                {
+                    use serde::de::Error;
+
+                    let val = #sylvia ::serde_value::Value::deserialize(deserializer)?;
+                    let map = match &val {
+                        #sylvia ::serde_value::Value::Map(map) => map,
+                        _ => return Err(D::Error::custom("Wrong message format!"))
+                    };
+                    if map.len() != 1 {
+                        return Err(D::Error::custom(format!("Expected exactly one message. Received {}", map.len())))
+                    }
+
+                    // Due to earlier size check of map this unwrap is safe
+                    let recv_msg_name = map.into_iter().next().unwrap();
+
+                    if let #sylvia ::serde_value::Value::String(recv_msg_name) = &recv_msg_name .0 {
+                        #(#interfaces_deserialization_attempts)*
+                        #contract_deserialization_attempt
+                    }
+
+                    let msgs: [&[&str]; #variants_cnt] = [#(#messages_call),*];
+                    let mut err_msg = msgs.into_iter().flatten().fold(
+                        // It might be better to forward the error or serialization, but we just
+                        // deserialized it from JSON, not reason to expect failure here.
+                        format!(
+                            "Unsupported message received: {}. Messages supported by this contract: ",
+                            #sylvia ::serde_json::to_string(&val).unwrap_or_else(|_| String::new())
+                        ),
+                        |mut acc, message| acc + message + ", ",
+                    );
+                    err_msg.truncate(err_msg.len() - 2);
+                    Err(D::Error::custom(err_msg))
+                }
+            }
+
+            impl #bracketed_wrapper_generics From<<#contract as #sylvia ::types::ContractApi>:: #enum_accessor>
+                for #contract_enum_name #bracketed_wrapper_generics #full_where_clause {
+                fn from(a: <#contract as #sylvia ::types::ContractApi>:: #enum_accessor ) -> Self {
+                    Self:: #contract_name (a)
+                }
+            }
+
+            #(
+            impl #bracketed_wrapper_generics From<<#contract as #modules_names ::sv::InterfaceMessagesApi>:: #enum_accessor>
+                for #contract_enum_name #bracketed_wrapper_generics #full_where_clause {
+                fn from(a: <#contract as #modules_names ::sv::InterfaceMessagesApi>:: #enum_accessor ) -> Self {
+                    Self:: #variants_names (a)
+                }
+            }
+            )*
+        }
+    }
+}
diff --git a/sylvia-derive/src/entry_points.rs b/sylvia-derive/src/entry_points.rs
new file mode 100644
index 0000000..d205a54
--- /dev/null
+++ b/sylvia-derive/src/entry_points.rs
@@ -0,0 +1,212 @@
+use proc_macro2::{Span, TokenStream};
+use proc_macro_error::emit_error;
+use quote::quote;
+use syn::fold::Fold;
+use syn::{parse_quote, GenericParam, Ident, ItemImpl, Type, WhereClause};
+
+use crate::crate_module;
+use crate::fold::StripGenerics;
+use crate::parser::attributes::msg::MsgType;
+use crate::parser::variant_descs::AsVariantDescs;
+use crate::parser::{
+    EntryPointArgs, FilteredOverrideEntryPoints, OverrideEntryPoint, ParsedSylviaAttributes,
+};
+use crate::types::msg_variant::MsgVariants;
+
+pub struct EntryPointInput<'a> {
+    item: &'a ItemImpl,
+    args: EntryPointArgs,
+}
+
+impl<'a> EntryPointInput<'a> {
+    pub fn new(item: &'a ItemImpl, args: EntryPointArgs, attr_span: Span) -> Self {
+        let instantiate =
+            MsgVariants::<GenericParam>::new(item.as_variants(), MsgType::Instantiate, &[], &None);
+
+        if args.generics.len() != item.generics.params.len() {
+            emit_error!(
+                attr_span,
+                "Missing concrete types.";
+                note = "For every generic type in the contract, a concrete type must be provided in `#[entry_points(generics<T1, T2, ...>)]`.";
+            );
+        }
+
+        if instantiate.get_only_variant().is_none() {
+            emit_error!(
+                attr_span, "Missing instantiation message.";
+                note = "`sylvia::entry_points` requires exactly one method marked with `#[sv::msg(instantiation)]` attribute.";
+                note = "Make sure you implemented the `entry_points` macro above the `contract` macro."
+            );
+        }
+
+        Self { item, args }
+    }
+
+    pub fn process(&self) -> TokenStream {
+        let Self { item, args } = self;
+
+        EntryPoints::new(item, args).emit()
+    }
+}
+
+pub struct EntryPoints<'a> {
+    source: &'a ItemImpl,
+    name: Type,
+    error: Type,
+    reply: Option<Ident>,
+    override_entry_points: Vec<OverrideEntryPoint>,
+    generics: Vec<&'a GenericParam>,
+    where_clause: &'a Option<WhereClause>,
+    attrs: &'a EntryPointArgs,
+}
+
+impl<'a> EntryPoints<'a> {
+    pub fn new(source: &'a ItemImpl, attrs: &'a EntryPointArgs) -> Self {
+        let name = StripGenerics.fold_type(*source.self_ty.clone());
+        let parsed_attrs = ParsedSylviaAttributes::new(source.attrs.iter());
+        let override_entry_points = parsed_attrs.override_entry_point_attrs;
+
+        let error = parsed_attrs.error_attrs.unwrap_or_default().error;
+
+        let generics: Vec<_> = source.generics.params.iter().collect();
+        let where_clause = &source.generics.where_clause;
+
+        let reply =
+            MsgVariants::<GenericParam>::new(source.as_variants(), MsgType::Reply, &[], &None)
+                .variants()
+                .map(|variant| variant.function_name().clone())
+                .next();
+
+        Self {
+            source,
+            name,
+            error,
+            reply,
+            override_entry_points,
+            generics,
+            where_clause,
+            attrs,
+        }
+    }
+
+    pub fn emit(&self) -> TokenStream {
+        let Self {
+            source,
+            reply,
+            override_entry_points,
+            generics,
+            where_clause,
+            ..
+        } = self;
+
+        let entry_points = [
+            MsgType::Instantiate,
+            MsgType::Exec,
+            MsgType::Query,
+            MsgType::Sudo,
+        ]
+        .into_iter()
+        .map(
+            |msg_ty| match override_entry_points.get_entry_point(msg_ty) {
+                Some(_) => quote! {},
+                None => self.emit_default_entry_point(msg_ty),
+            },
+        );
+
+        let is_migrate = MsgVariants::new(
+            source.as_variants(),
+            MsgType::Migrate,
+            generics,
+            where_clause,
+        )
+        .get_only_variant()
+        .is_some();
+
+        let migrate_not_overridden = override_entry_points
+            .get_entry_point(MsgType::Migrate)
+            .is_none();
+
+        let migrate = if migrate_not_overridden && is_migrate {
+            self.emit_default_entry_point(MsgType::Migrate)
+        } else {
+            quote! {}
+        };
+
+        let reply_ep = override_entry_points
+            .get_entry_point(MsgType::Reply)
+            .map(|_| quote! {})
+            .unwrap_or_else(|| {
+                if reply.is_some() {
+                    self.emit_default_entry_point(MsgType::Reply)
+                } else {
+                    quote! {}
+                }
+            });
+
+        quote! {
+            pub mod entry_points {
+                use super::*;
+
+                #(#entry_points)*
+
+                #migrate
+
+                #reply_ep
+            }
+        }
+    }
+
+    pub fn emit_default_entry_point(&self, msg_ty: MsgType) -> TokenStream {
+        let Self {
+            name,
+            error,
+            attrs,
+            reply,
+            ..
+        } = self;
+        let sylvia = crate_module();
+
+        let attr_generics = &attrs.generics;
+        let (contract, contract_turbo) = if attr_generics.is_empty() {
+            (quote! { #name }, quote! { #name })
+        } else {
+            (
+                quote! { #name < #attr_generics > },
+                quote! { #name :: < #attr_generics > },
+            )
+        };
+
+        let custom_msg: Type =
+            parse_quote! { < #contract as #sylvia ::types::ContractApi > :: CustomMsg };
+        let custom_query: Type =
+            parse_quote! { < #contract as #sylvia ::types::ContractApi > :: CustomQuery };
+
+        let result = msg_ty.emit_result_type(&custom_msg, error);
+        let params = msg_ty.emit_ctx_params(&custom_query);
+        let values = msg_ty.emit_ctx_values();
+        let ep_name = msg_ty.emit_ep_name();
+        let associated_name = msg_ty.as_accessor_wrapper_name();
+        let msg = match msg_ty {
+            MsgType::Reply => quote! { msg: #sylvia ::cw_std::Reply },
+            _ => quote! { msg: < #contract as #sylvia ::types::ContractApi> :: #associated_name },
+        };
+        let dispatch = match msg_ty {
+            MsgType::Reply => quote! {
+                #contract_turbo ::new(). #reply((deps, env).into(), msg).map_err(Into::into)
+            },
+            _ => quote! {
+                msg.dispatch(& #contract_turbo ::new() , ( #values )).map_err(Into::into)
+            },
+        };
+
+        quote! {
+            #[#sylvia ::cw_std::entry_point]
+            pub fn #ep_name (
+                #params ,
+                #msg
+            ) -> #result {
+                #dispatch
+            }
+        }
+    }
+}
diff --git a/sylvia-derive/src/strip_input.rs b/sylvia-derive/src/fold.rs
similarity index 75%
rename from sylvia-derive/src/strip_input.rs
rename to sylvia-derive/src/fold.rs
index 19f47dd..11ac2cc 100644
--- a/sylvia-derive/src/strip_input.rs
+++ b/sylvia-derive/src/fold.rs
@@ -1,7 +1,7 @@
 use syn::fold::{self, Fold};
 use syn::punctuated::Punctuated;
 use syn::{
-    FnArg, ImplItemFn, ItemImpl, ItemTrait, PatType, Receiver, Signature, Token, TraitItemFn,
+    FnArg, ImplItemFn, ItemImpl, ItemTrait, PatType, Path, Receiver, Signature, Token, TraitItemFn,
 };
 
 use crate::parser::SylviaAttribute;
@@ -77,3 +77,26 @@ impl Fold for StripInput {
         fold::fold_item_impl(self, ItemImpl { attrs, ..i })
     }
 }
+
+/// Removes all generics from type assumning default values for it
+pub struct StripGenerics;
+
+impl Fold for StripGenerics {
+    fn fold_path_arguments(&mut self, _: syn::PathArguments) -> syn::PathArguments {
+        syn::PathArguments::None
+    }
+}
+
+/// Removes `Self` from associated type [Path].
+pub struct StripSelfPath;
+
+impl Fold for StripSelfPath {
+    fn fold_path(&mut self, path: Path) -> Path {
+        let segments = path
+            .segments
+            .into_iter()
+            .filter(|segment| segment.ident != "Self")
+            .collect();
+        syn::fold::fold_path(self, Path { segments, ..path })
+    }
+}
diff --git a/sylvia-derive/src/input.rs b/sylvia-derive/src/input.rs
deleted file mode 100644
index 582df26..0000000
--- a/sylvia-derive/src/input.rs
+++ /dev/null
@@ -1,377 +0,0 @@
-use proc_macro2::{Span, TokenStream};
-use proc_macro_error::{emit_error, emit_warning};
-use quote::quote;
-use syn::{GenericParam, Ident, ItemImpl, ItemTrait, TraitItem};
-
-use crate::associated_types::{AssociatedTypes, ItemType, EXEC_TYPE, QUERY_TYPE};
-use crate::executor::{ContractExecutor, InterfaceExecutor};
-use crate::interfaces::Interfaces;
-use crate::message::{
-    ContractApi, ContractEnumMessage, EntryPoints, EnumMessage, GlueMessage, InterfaceApi,
-    MsgVariants, StructMessage,
-};
-use crate::multitest::{ContractMtHelpers, TraitMtHelpers};
-use crate::parser::attributes::msg::MsgType;
-use crate::parser::{
-    assert_new_method_defined, ContractErrorAttr, Custom, EntryPointArgs, OverrideEntryPoint,
-    ParsedSylviaAttributes,
-};
-use crate::querier::{ContractQuerier, InterfaceQuerier};
-use crate::variant_descs::AsVariantDescs;
-
-/// Preprocessed `interface` macro input
-pub struct TraitInput<'a> {
-    item: &'a ItemTrait,
-    custom: Custom,
-    associated_types: AssociatedTypes<'a>,
-}
-
-impl<'a> TraitInput<'a> {
-    pub fn new(item: &'a ItemTrait) -> Self {
-        if !item.generics.params.is_empty() {
-            emit_error!(
-                item.ident.span(), "Generics on traits are not supported. Use associated types instead.";
-                note = "Sylvia interfaces can be implemented only a single time per contract.";
-            );
-        }
-
-        if !item
-            .items
-            .iter()
-            .any(|item| matches!(item, TraitItem::Type(ty) if ty.ident == Ident::new("Error", ty.ident.span())))
-        {
-            emit_error!(
-                item.ident.span(), "Missing `Error` type defined for trait.";
-                note = "Error is an error type returned by generated types dispatch function. Messages handling function have to return an error type convertible to this Error type.";
-                note = "A trait error type should be bound to implement `From<cosmwasm_std::StdError>`.";
-            );
-        }
-
-        let custom = ParsedSylviaAttributes::new(item.attrs.iter())
-            .custom_attr
-            .unwrap_or_default();
-        let associated_types = AssociatedTypes::new(item);
-
-        if custom.msg.is_none()
-            && !associated_types
-                .all_names()
-                .any(|assoc_type| assoc_type == EXEC_TYPE)
-        {
-            emit_warning!(
-                item.ident.span(), "Missing both `{}` type and `#[sv::custom(msg=...)]` defined for the trait.", EXEC_TYPE;
-                note = "Implicitly it means that the trait could not be implemented for contracts that use CustomMsg different than `cosmwasm_std::Empty`";
-                note = "If this behaviour is intended, please add `#[sv::custom(msg=sylvia::cw_std::Empty]` attribute.";
-            );
-        }
-
-        if custom.query.is_none()
-            && !associated_types
-                .all_names()
-                .any(|assoc_type| assoc_type == QUERY_TYPE)
-        {
-            emit_warning!(
-                item.ident.span(), "Missing both `{}` type and `#[sv::custom(query=...)]` defined for the trait.", QUERY_TYPE;
-                note = "Implicitly it means that the trait could not be implemented for contracts that use CustomQuery different than `cosmwasm_std::Empty`";
-                note = "If this behaviour is intended, please add `#[sv::custom(query=sylvia::cw_std::Empty]` attribute.";
-            );
-        }
-
-        Self {
-            item,
-            custom,
-            associated_types,
-        }
-    }
-
-    pub fn process(&self) -> TokenStream {
-        let Self {
-            associated_types,
-            item,
-            custom,
-        } = self;
-        let messages = self.emit_messages();
-        let associated_names: Vec<_> = associated_types.as_filtered_names().collect();
-
-        let executor_variants =
-            MsgVariants::new(item.as_variants(), MsgType::Exec, &associated_names, &None);
-        let query_variants =
-            MsgVariants::new(item.as_variants(), MsgType::Query, &associated_names, &None);
-        let executor = InterfaceExecutor::new(&executor_variants, associated_types, &item.ident)
-            .emit_executor_trait();
-        let querier = InterfaceQuerier::new(&query_variants, associated_types, &item.ident)
-            .emit_querier_trait();
-
-        let interface_messages = InterfaceApi::new(item, associated_types, custom).emit();
-
-        let multitest_helpers = self.emit_multitest_helpers();
-
-        quote! {
-            pub mod sv {
-                use super::*;
-                #messages
-
-                #querier
-
-                #executor
-
-                #interface_messages
-
-                #multitest_helpers
-            }
-        }
-    }
-
-    fn emit_messages(&self) -> TokenStream {
-        let exec = self.emit_msg(MsgType::Exec);
-        let query = self.emit_msg(MsgType::Query);
-        let sudo = self.emit_msg(MsgType::Sudo);
-
-        let instantiate = MsgVariants::new(
-            self.item.as_variants(),
-            MsgType::Instantiate,
-            &[] as &[&Ident],
-            &None,
-        );
-
-        if let Some(msg_variant) = instantiate.variants().next() {
-            emit_error!(
-                msg_variant.name().span(), "The message attribute `instantiate` is not supported in interfaces.";
-                note = "Contracts need to implement `instantiate` method within their `impl` block.";
-            );
-        }
-
-        let migrate = MsgVariants::new(
-            self.item.as_variants(),
-            MsgType::Migrate,
-            &[] as &[&Ident],
-            &None,
-        );
-
-        if let Some(msg_variant) = migrate.variants().next() {
-            emit_error!(
-                msg_variant.name().span(), "The message attribute `migrate` is not supported in interfaces";
-                note = "Contracts need to implement `migrate` method within their `impl` block.";
-            );
-        }
-
-        quote! {
-            #exec
-
-            #query
-
-            #sudo
-        }
-    }
-
-    fn emit_msg(&self, msg_ty: MsgType) -> TokenStream {
-        let where_clause = &self.associated_types.as_where_clause();
-        let associated_names: Vec<_> = self
-            .associated_types
-            .without_error()
-            .map(ItemType::as_name)
-            .collect();
-        let variants = MsgVariants::new(
-            self.item.as_variants(),
-            msg_ty,
-            &associated_names,
-            where_clause,
-        );
-
-        EnumMessage::new(
-            self.item,
-            msg_ty,
-            &self.custom,
-            variants,
-            &self.associated_types,
-        )
-        .emit()
-    }
-
-    fn emit_multitest_helpers(&self) -> TokenStream {
-        if !cfg!(feature = "mt") {
-            return quote! {};
-        }
-
-        let Self { item, .. } = self;
-        let associated_types = &self.associated_types;
-
-        TraitMtHelpers::new(item, associated_types).emit()
-    }
-}
-
-/// Preprocessed `contract` macro input for non-trait impl block
-pub struct ImplInput<'a> {
-    error: ContractErrorAttr,
-    item: &'a ItemImpl,
-    generics: Vec<&'a GenericParam>,
-    custom: Custom,
-    override_entry_points: Vec<OverrideEntryPoint>,
-    interfaces: Interfaces,
-}
-
-impl<'a> ImplInput<'a> {
-    pub fn new(item: &'a ItemImpl) -> Self {
-        assert_new_method_defined(item);
-
-        let generics = item.generics.params.iter().collect();
-        let parsed_attrs = ParsedSylviaAttributes::new(item.attrs.iter());
-        let error = parsed_attrs.error_attrs.unwrap_or_default();
-        let custom = parsed_attrs.custom_attr.unwrap_or_default();
-        let override_entry_points = parsed_attrs.override_entry_point_attrs;
-        let interfaces = Interfaces::new(item);
-
-        Self {
-            item,
-            generics,
-            error,
-            custom,
-            override_entry_points,
-            interfaces,
-        }
-    }
-
-    pub fn process(&self) -> TokenStream {
-        let Self {
-            item,
-            generics,
-            custom,
-            ..
-        } = self;
-        let multitest_helpers = self.emit_multitest_helpers();
-
-        let executor_variants = MsgVariants::new(item.as_variants(), MsgType::Exec, &[], &None);
-        let querier_variants = MsgVariants::new(item.as_variants(), MsgType::Query, &[], &None);
-        let executor = ContractExecutor::new(
-            item.generics.clone(),
-            *item.self_ty.clone(),
-            executor_variants,
-        )
-        .emit();
-        let querier = ContractQuerier::new(
-            item.generics.clone(),
-            *item.self_ty.clone(),
-            querier_variants,
-        )
-        .emit();
-        let messages = self.emit_messages();
-        let contract_api = ContractApi::new(item, generics, custom).emit();
-
-        quote! {
-            pub mod sv {
-                use super::*;
-
-                #messages
-
-                #multitest_helpers
-
-                #querier
-
-                #executor
-
-                #contract_api
-            }
-        }
-    }
-
-    fn emit_messages(&self) -> TokenStream {
-        let instantiate = self.emit_struct_msg(MsgType::Instantiate);
-        let migrate = self.emit_struct_msg(MsgType::Migrate);
-        let exec_impl = self.emit_enum_msg(MsgType::Exec);
-        let query_impl = self.emit_enum_msg(MsgType::Query);
-        let sudo_impl = self.emit_enum_msg(MsgType::Sudo);
-        let exec = self.emit_glue_msg(MsgType::Exec);
-        let query = self.emit_glue_msg(MsgType::Query);
-        let sudo = self.emit_glue_msg(MsgType::Sudo);
-
-        quote! {
-            #instantiate
-
-            #exec_impl
-
-            #query_impl
-
-            #sudo_impl
-
-            #migrate
-
-            #exec
-
-            #query
-
-            #sudo
-        }
-    }
-
-    fn emit_struct_msg(&self, msg_ty: MsgType) -> TokenStream {
-        StructMessage::new(self.item, msg_ty, &self.generics, &self.custom)
-            .map_or(quote! {}, |msg| msg.emit())
-    }
-
-    fn emit_enum_msg(&self, msg_ty: MsgType) -> TokenStream {
-        ContractEnumMessage::new(self.item, msg_ty, &self.generics, &self.error, &self.custom)
-            .emit()
-    }
-
-    fn emit_glue_msg(&self, msg_ty: MsgType) -> TokenStream {
-        GlueMessage::new(
-            self.item,
-            msg_ty,
-            &self.error,
-            &self.custom,
-            &self.interfaces,
-        )
-        .emit()
-    }
-
-    fn emit_multitest_helpers(&self) -> TokenStream {
-        if !cfg!(feature = "mt") {
-            return quote! {};
-        }
-
-        let Self {
-            item,
-            custom,
-            override_entry_points,
-            ..
-        } = self;
-
-        let generic_params = &self.generics;
-        ContractMtHelpers::new(item, generic_params, custom, override_entry_points.clone()).emit()
-    }
-}
-
-pub struct EntryPointInput<'a> {
-    item: &'a ItemImpl,
-    args: EntryPointArgs,
-}
-
-impl<'a> EntryPointInput<'a> {
-    pub fn new(item: &'a ItemImpl, args: EntryPointArgs, attr_span: Span) -> Self {
-        let instantiate =
-            MsgVariants::<GenericParam>::new(item.as_variants(), MsgType::Instantiate, &[], &None);
-
-        if args.generics.len() != item.generics.params.len() {
-            emit_error!(
-                attr_span,
-                "Missing concrete types.";
-                note = "For every generic type in the contract, a concrete type must be provided in `#[entry_points(generics<T1, T2, ...>)]`.";
-            );
-        }
-
-        if instantiate.get_only_variant().is_none() {
-            emit_error!(
-                attr_span, "Missing instantiation message.";
-                note = "`sylvia::entry_points` requires exactly one method marked with `#[sv::msg(instantiation)]` attribute.";
-                note = "Make sure you implemented the `entry_points` macro above the `contract` macro."
-            );
-        }
-
-        Self { item, args }
-    }
-
-    pub fn process(&self) -> TokenStream {
-        let Self { item, args } = self;
-
-        EntryPoints::new(item, args).emit()
-    }
-}
diff --git a/sylvia-derive/src/interface.rs b/sylvia-derive/src/interface.rs
new file mode 100644
index 0000000..f17cad0
--- /dev/null
+++ b/sylvia-derive/src/interface.rs
@@ -0,0 +1,198 @@
+use communication::api::Api;
+use communication::enum_msg::EnumMessage;
+use communication::executor::Executor;
+use communication::querier::Querier;
+use mt::MtHelpers;
+use proc_macro2::TokenStream;
+use proc_macro_error::{emit_error, emit_warning};
+use quote::quote;
+use syn::{Ident, ItemTrait, TraitItem};
+
+use crate::parser::attributes::msg::MsgType;
+use crate::parser::variant_descs::AsVariantDescs;
+use crate::parser::{Custom, ParsedSylviaAttributes};
+use crate::types::associated_types::{AssociatedTypes, ItemType, EXEC_TYPE, QUERY_TYPE};
+use crate::types::msg_variant::MsgVariants;
+
+mod communication;
+mod mt;
+
+/// Preprocessed `interface` macro input
+pub struct InterfaceInput<'a> {
+    item: &'a ItemTrait,
+    custom: Custom,
+    associated_types: AssociatedTypes<'a>,
+}
+
+impl<'a> InterfaceInput<'a> {
+    pub fn new(item: &'a ItemTrait) -> Self {
+        if !item.generics.params.is_empty() {
+            emit_error!(
+                item.ident.span(), "Generics on traits are not supported. Use associated types instead.";
+                note = "Sylvia interfaces can be implemented only a single time per contract.";
+            );
+        }
+
+        if !item
+            .items
+            .iter()
+            .any(|item| matches!(item, TraitItem::Type(ty) if ty.ident == Ident::new("Error", ty.ident.span())))
+        {
+            emit_error!(
+                item.ident.span(), "Missing `Error` type defined for trait.";
+                note = "Error is an error type returned by generated types dispatch function. Messages handling function have to return an error type convertible to this Error type.";
+                note = "A trait error type should be bound to implement `From<cosmwasm_std::StdError>`.";
+            );
+        }
+
+        let custom = ParsedSylviaAttributes::new(item.attrs.iter())
+            .custom_attr
+            .unwrap_or_default();
+        let associated_types = AssociatedTypes::new(item);
+
+        if custom.msg.is_none()
+            && !associated_types
+                .all_names()
+                .any(|assoc_type| assoc_type == EXEC_TYPE)
+        {
+            emit_warning!(
+                item.ident.span(), "Missing both `{}` type and `#[sv::custom(msg=...)]` defined for the trait.", EXEC_TYPE;
+                note = "Implicitly it means that the trait could not be implemented for contracts that use CustomMsg different than `cosmwasm_std::Empty`";
+                note = "If this behaviour is intended, please add `#[sv::custom(msg=sylvia::cw_std::Empty]` attribute.";
+            );
+        }
+
+        if custom.query.is_none()
+            && !associated_types
+                .all_names()
+                .any(|assoc_type| assoc_type == QUERY_TYPE)
+        {
+            emit_warning!(
+                item.ident.span(), "Missing both `{}` type and `#[sv::custom(query=...)]` defined for the trait.", QUERY_TYPE;
+                note = "Implicitly it means that the trait could not be implemented for contracts that use CustomQuery different than `cosmwasm_std::Empty`";
+                note = "If this behaviour is intended, please add `#[sv::custom(query=sylvia::cw_std::Empty]` attribute.";
+            );
+        }
+
+        Self {
+            item,
+            custom,
+            associated_types,
+        }
+    }
+
+    pub fn process(&self) -> TokenStream {
+        let Self {
+            associated_types,
+            item,
+            custom,
+        } = self;
+        let messages = self.emit_messages();
+        let associated_names: Vec<_> = associated_types.as_filtered_names().collect();
+
+        let executor_variants =
+            MsgVariants::new(item.as_variants(), MsgType::Exec, &associated_names, &None);
+        let query_variants =
+            MsgVariants::new(item.as_variants(), MsgType::Query, &associated_names, &None);
+        let executor =
+            Executor::new(&executor_variants, associated_types, &item.ident).emit_executor_trait();
+        let querier =
+            Querier::new(&query_variants, associated_types, &item.ident).emit_querier_trait();
+
+        let interface_messages = Api::new(item, associated_types, custom).emit();
+
+        let multitest_helpers = self.emit_multitest_helpers();
+
+        quote! {
+            pub mod sv {
+                use super::*;
+                #messages
+
+                #querier
+
+                #executor
+
+                #interface_messages
+
+                #multitest_helpers
+            }
+        }
+    }
+
+    fn emit_messages(&self) -> TokenStream {
+        let exec = self.emit_msg(MsgType::Exec);
+        let query = self.emit_msg(MsgType::Query);
+        let sudo = self.emit_msg(MsgType::Sudo);
+
+        let instantiate = MsgVariants::new(
+            self.item.as_variants(),
+            MsgType::Instantiate,
+            &[] as &[&Ident],
+            &None,
+        );
+
+        if let Some(msg_variant) = instantiate.variants().next() {
+            emit_error!(
+                msg_variant.name().span(), "The message attribute `instantiate` is not supported in interfaces.";
+                note = "Contracts need to implement `instantiate` method within their `impl` block.";
+            );
+        }
+
+        let migrate = MsgVariants::new(
+            self.item.as_variants(),
+            MsgType::Migrate,
+            &[] as &[&Ident],
+            &None,
+        );
+
+        if let Some(msg_variant) = migrate.variants().next() {
+            emit_error!(
+                msg_variant.name().span(), "The message attribute `migrate` is not supported in interfaces";
+                note = "Contracts need to implement `migrate` method within their `impl` block.";
+            );
+        }
+
+        quote! {
+            #exec
+
+            #query
+
+            #sudo
+        }
+    }
+
+    fn emit_msg(&self, msg_ty: MsgType) -> TokenStream {
+        let where_clause = &self.associated_types.as_where_clause();
+        let associated_names: Vec<_> = self
+            .associated_types
+            .without_error()
+            .map(ItemType::as_name)
+            .collect();
+        let variants = MsgVariants::new(
+            self.item.as_variants(),
+            msg_ty,
+            &associated_names,
+            where_clause,
+        );
+
+        EnumMessage::new(
+            self.item,
+            msg_ty,
+            &self.custom,
+            variants,
+            &self.associated_types,
+        )
+        .emit()
+    }
+
+    fn emit_multitest_helpers(&self) -> TokenStream {
+        if !cfg!(feature = "mt") {
+            return quote! {};
+        }
+
+        let Self { item, .. } = self;
+        let associated_types = &self.associated_types;
+
+        MtHelpers::new(item, associated_types).emit()
+    }
+}
diff --git a/sylvia-derive/src/interface/communication/api.rs b/sylvia-derive/src/interface/communication/api.rs
new file mode 100644
index 0000000..ab3e271
--- /dev/null
+++ b/sylvia-derive/src/interface/communication/api.rs
@@ -0,0 +1,103 @@
+use crate::crate_module;
+use crate::parser::variant_descs::AsVariantDescs;
+use crate::parser::{Custom, MsgType};
+use crate::types::associated_types::{AssociatedTypes, ItemType};
+use crate::types::msg_variant::MsgVariants;
+use proc_macro2::TokenStream;
+use quote::quote;
+use syn::ItemTrait;
+
+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>,
+        custom: &'a Custom,
+    ) -> Self {
+        Self {
+            source,
+            custom,
+            associated_types,
+        }
+    }
+
+    pub fn emit(&self) -> TokenStream {
+        let sylvia = crate_module();
+        let Self {
+            source,
+            custom,
+            associated_types,
+        } = self;
+
+        let interface_name = &source.ident;
+        let generics: Vec<_> = associated_types
+            .without_special()
+            .map(ItemType::as_name)
+            .collect();
+        let exec_variants = MsgVariants::new(
+            source.as_variants(),
+            MsgType::Exec,
+            &generics,
+            &source.generics.where_clause,
+        );
+        let query_variants = MsgVariants::new(
+            source.as_variants(),
+            MsgType::Query,
+            &generics,
+            &source.generics.where_clause,
+        );
+        let sudo_variants = MsgVariants::new(
+            source.as_variants(),
+            MsgType::Sudo,
+            &generics,
+            &source.generics.where_clause,
+        );
+
+        let where_clause = &self.associated_types.as_where_clause();
+        let custom_query = custom.query_or_default();
+        let exec_generics = &exec_variants.used_generics();
+        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 >;
+            }
+
+
+            pub struct Api < #(#generics,)* > {
+                #phantom
+            }
+
+            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/interface/communication/enum_msg.rs b/sylvia-derive/src/interface/communication/enum_msg.rs
new file mode 100644
index 0000000..3bfcb84
--- /dev/null
+++ b/sylvia-derive/src/interface/communication/enum_msg.rs
@@ -0,0 +1,137 @@
+use crate::parser::attributes::MsgAttrForwarding;
+use crate::parser::{parse_associated_custom_type, Custom, MsgType, ParsedSylviaAttributes};
+use crate::types::associated_types::{AssociatedTypes, ItemType, EXEC_TYPE, QUERY_TYPE};
+use crate::types::msg_variant::MsgVariants;
+use crate::utils::emit_bracketed_generics;
+use proc_macro2::TokenStream;
+use quote::quote;
+use syn::{parse_quote, Ident, ItemTrait, Type};
+
+/// Representation of single enum message
+pub struct EnumMessage<'a> {
+    source: &'a ItemTrait,
+    variants: MsgVariants<'a, Ident>,
+    associated_types: &'a AssociatedTypes<'a>,
+    msg_ty: MsgType,
+    resp_type: Type,
+    query_type: Type,
+    msg_attrs_to_forward: Vec<MsgAttrForwarding>,
+}
+
+impl<'a> EnumMessage<'a> {
+    pub fn new(
+        source: &'a ItemTrait,
+        msg_ty: MsgType,
+        custom: &'a Custom,
+        variants: MsgVariants<'a, Ident>,
+        associated_types: &'a AssociatedTypes<'a>,
+    ) -> Self {
+        let associated_exec = parse_associated_custom_type(source, EXEC_TYPE);
+        let associated_query = parse_associated_custom_type(source, QUERY_TYPE);
+
+        let resp_type = custom
+            .msg
+            .clone()
+            .or(associated_exec)
+            .unwrap_or_else(Custom::default_type);
+
+        let query_type = custom
+            .query
+            .clone()
+            .or(associated_query)
+            .unwrap_or_else(Custom::default_type);
+
+        let msg_attrs_to_forward = ParsedSylviaAttributes::new(source.attrs.iter())
+            .msg_attrs_forward
+            .into_iter()
+            .filter(|attr| attr.msg_type == msg_ty)
+            .collect();
+
+        Self {
+            source,
+            variants,
+            associated_types,
+            msg_ty,
+            resp_type,
+            query_type,
+            msg_attrs_to_forward,
+        }
+    }
+
+    pub fn emit(&self) -> TokenStream {
+        let Self {
+            source,
+            variants,
+            associated_types,
+            msg_ty,
+            resp_type,
+            query_type,
+            msg_attrs_to_forward,
+        } = self;
+
+        let trait_name = &source.ident;
+        let enum_name = msg_ty.emit_msg_name();
+        let unique_enum_name =
+            Ident::new(&format!("{}{}", trait_name, enum_name), enum_name.span());
+
+        let match_arms = variants.emit_dispatch_legs();
+        let mut msgs = variants.as_names_snake_cased();
+        msgs.sort();
+        let msgs_cnt = msgs.len();
+        let variants_constructors = variants.emit_constructors();
+        let msg_variants = variants.emit();
+
+        let ctx_type = msg_ty.emit_ctx_type(query_type);
+        let dispatch_type = msg_ty.emit_result_type(resp_type, &parse_quote!(ContractT::Error));
+
+        let used_generics = variants.used_generics();
+        let unused_generics = variants.unused_generics();
+        let where_predicates = associated_types
+            .without_error()
+            .map(ItemType::as_where_predicate);
+        let where_clause = variants.where_clause();
+        let contract_predicate = associated_types.emit_contract_predicate(trait_name);
+
+        let phantom_variant = variants.emit_phantom_variant();
+        let phatom_match_arm = variants.emit_phantom_match_arm();
+        let bracketed_used_generics = emit_bracketed_generics(used_generics);
+
+        let ep_name = msg_ty.emit_ep_name();
+        let messages_fn_name = Ident::new(&format!("{}_messages", ep_name), enum_name.span());
+        let derive_call = msg_ty.emit_derive_call();
+        let msg_attrs_to_forward = msg_attrs_to_forward.iter().map(|attr| &attr.attrs);
+
+        quote! {
+            #[allow(clippy::derive_partial_eq_without_eq)]
+            #derive_call
+            #( #[ #msg_attrs_to_forward ] )*
+            #[serde(rename_all="snake_case")]
+            pub enum #unique_enum_name #bracketed_used_generics {
+                #(#msg_variants,)*
+                #phantom_variant
+            }
+            pub type #enum_name #bracketed_used_generics = #unique_enum_name #bracketed_used_generics;
+
+            impl #bracketed_used_generics #unique_enum_name #bracketed_used_generics #where_clause {
+                pub fn dispatch<ContractT, #(#unused_generics,)*>(self, contract: &ContractT, ctx: #ctx_type)
+                    -> #dispatch_type
+                where
+                    #(#where_predicates,)*
+                    #contract_predicate
+                {
+                    use #unique_enum_name::*;
+
+                    match self {
+                        #(#match_arms,)*
+                        #phatom_match_arm
+                    }
+                }
+                #(#variants_constructors)*
+            }
+
+            pub const fn #messages_fn_name () -> [&'static str; #msgs_cnt] {
+                [#(#msgs,)*]
+            }
+        }
+    }
+}
diff --git a/sylvia-derive/src/executor.rs b/sylvia-derive/src/interface/communication/executor.rs
similarity index 66%
rename from sylvia-derive/src/executor.rs
rename to sylvia-derive/src/interface/communication/executor.rs
index 9e28875..74d44a8 100644
--- a/sylvia-derive/src/executor.rs
+++ b/sylvia-derive/src/interface/communication/executor.rs
@@ -1,22 +1,23 @@
 use convert_case::Case;
 use proc_macro2::TokenStream;
 use quote::{quote, ToTokens};
-use syn::{GenericParam, Generics, Ident, Type};
+use syn::Ident;
 
-use crate::associated_types::{AssociatedTypes, EmitAssociated, ItemType};
-use crate::check_generics::GetPath;
 use crate::crate_module;
-use crate::message::{MsgField, MsgVariant, MsgVariants};
 use crate::parser::attributes::msg::MsgType;
+use crate::parser::check_generics::GetPath;
+use crate::types::associated_types::{AssociatedTypes, ItemType};
+use crate::types::msg_field::MsgField;
+use crate::types::msg_variant::{MsgVariant, MsgVariants};
 use crate::utils::{emit_bracketed_generics, SvCasing};
 
-pub struct InterfaceExecutor<'a, Generic> {
+pub struct Executor<'a, Generic> {
     variants: &'a MsgVariants<'a, Generic>,
     associated_types: &'a AssociatedTypes<'a>,
     interface_name: &'a Ident,
 }
 
-impl<'a, Generic> InterfaceExecutor<'a, Generic>
+impl<'a, Generic> Executor<'a, Generic>
 where
     Generic: GetPath + PartialEq + ToTokens,
 {
@@ -88,70 +89,6 @@ where
     }
 }
 
-pub struct ContractExecutor<'a> {
-    generics: Generics,
-    self_ty: Type,
-    variants: MsgVariants<'a, GenericParam>,
-}
-
-impl<'a> ContractExecutor<'a> {
-    pub fn new(generics: Generics, self_ty: Type, variants: MsgVariants<'a, GenericParam>) -> Self {
-        Self {
-            generics,
-            self_ty,
-            variants,
-        }
-    }
-
-    pub fn emit(&self) -> TokenStream {
-        let sylvia = crate_module();
-        let Self {
-            generics,
-            self_ty,
-            variants,
-            ..
-        } = self;
-
-        let where_clause = &generics.where_clause;
-        let generics: Vec<_> = generics.params.iter().collect();
-        let contract = &self_ty;
-
-        let accessor = MsgType::Exec.as_accessor_name();
-        let executor_api_path = quote! { < #contract as #sylvia ::types::ContractApi>:: #accessor };
-
-        let executor_methods_impl = variants
-            .variants()
-            .map(|variant| variant.emit_executor_impl(&executor_api_path));
-
-        let executor_methods_declaration = variants
-            .variants()
-            .map(|variant| variant.emit_executor_method_declaration());
-
-        let types_declaration = where_clause
-            .as_ref()
-            .map(EmitAssociated::emit_declaration)
-            .unwrap_or(vec![]);
-
-        let types_implementation = where_clause
-            .as_ref()
-            .map(EmitAssociated::emit_implementation)
-            .unwrap_or(vec![]);
-
-        quote! {
-            pub trait Executor<#(#generics,)*> #where_clause {
-                #(#types_declaration)*
-                #(#executor_methods_declaration)*
-            }
-
-            impl <#(#generics,)*> Executor<#(#generics,)*>
-                for #sylvia ::types::ExecutorBuilder<( #sylvia ::types::EmptyExecutorBuilderState, #contract )> #where_clause {
-                #(#types_implementation)*
-                #(#executor_methods_impl)*
-            }
-        }
-    }
-}
-
 trait EmitExecutorMethod {
     fn emit_executor_impl(&self, api_path: &TokenStream) -> TokenStream;
     fn emit_executor_method_declaration(&self) -> TokenStream;
diff --git a/sylvia-derive/src/interface/communication/mod.rs b/sylvia-derive/src/interface/communication/mod.rs
new file mode 100644
index 0000000..c318e87
--- /dev/null
+++ b/sylvia-derive/src/interface/communication/mod.rs
@@ -0,0 +1,4 @@
+pub mod api;
+pub mod enum_msg;
+pub mod executor;
+pub mod querier;
diff --git a/sylvia-derive/src/querier.rs b/sylvia-derive/src/interface/communication/querier.rs
similarity index 63%
rename from sylvia-derive/src/querier.rs
rename to sylvia-derive/src/interface/communication/querier.rs
index 1bdbbce..2156cd7 100644
--- a/sylvia-derive/src/querier.rs
+++ b/sylvia-derive/src/interface/communication/querier.rs
@@ -1,22 +1,23 @@
 use convert_case::Case;
 use proc_macro2::TokenStream;
 use quote::{quote, ToTokens};
-use syn::{GenericParam, Generics, Ident, Type};
+use syn::Ident;
 
-use crate::associated_types::{AssociatedTypes, EmitAssociated, ItemType};
-use crate::check_generics::GetPath;
 use crate::crate_module;
-use crate::message::{MsgField, MsgVariant, MsgVariants};
 use crate::parser::attributes::msg::MsgType;
+use crate::parser::check_generics::GetPath;
+use crate::types::associated_types::{AssociatedTypes, ItemType};
+use crate::types::msg_field::MsgField;
+use crate::types::msg_variant::{MsgVariant, MsgVariants};
 use crate::utils::{emit_bracketed_generics, SvCasing};
 
-pub struct InterfaceQuerier<'a, Generic> {
+pub struct Querier<'a, Generic> {
     variants: &'a MsgVariants<'a, Generic>,
     associated_types: &'a AssociatedTypes<'a>,
     interface_name: &'a Ident,
 }
 
-impl<'a, Generic> InterfaceQuerier<'a, Generic>
+impl<'a, Generic> Querier<'a, Generic>
 where
     Generic: GetPath + PartialEq + ToTokens,
 {
@@ -85,75 +86,6 @@ where
     }
 }
 
-pub struct ContractQuerier<'a> {
-    generics: Generics,
-    self_ty: Type,
-    variants: MsgVariants<'a, GenericParam>,
-}
-
-impl<'a> ContractQuerier<'a> {
-    pub fn new(generics: Generics, self_ty: Type, variants: MsgVariants<'a, GenericParam>) -> Self {
-        Self {
-            generics,
-            self_ty,
-            variants,
-        }
-    }
-
-    pub fn emit(&self) -> TokenStream {
-        let sylvia = crate_module();
-        let Self {
-            generics,
-            self_ty,
-            variants,
-            ..
-        } = self;
-
-        let where_clause = &generics.where_clause;
-        let generics: Vec<_> = generics.params.iter().collect();
-        let contract = &self_ty;
-
-        let accessor = MsgType::Query.as_accessor_name();
-        let api_path = quote! { < #contract as #sylvia ::types::ContractApi>:: #accessor };
-
-        let querier_methods_impl = variants
-            .variants()
-            .map(|variant| variant.emit_querier_impl(&api_path));
-
-        let querier_methods_declaration = variants
-            .variants()
-            .map(|variant| variant.emit_querier_method_declaration());
-
-        let types_declaration = where_clause
-            .as_ref()
-            .map(EmitAssociated::emit_declaration)
-            .unwrap_or(vec![]);
-
-        let types_implementation = where_clause
-            .as_ref()
-            .map(EmitAssociated::emit_implementation)
-            .unwrap_or(vec![]);
-
-        let bracketed_generics = if !generics.is_empty() {
-            quote! { < #(#generics,)* > }
-        } else {
-            quote! {}
-        };
-
-        quote! {
-            pub trait Querier #bracketed_generics {
-                #(#types_declaration)*
-                #(#querier_methods_declaration)*
-            }
-
-            impl <'sv_querier_lifetime, #(#generics,)* C: #sylvia ::cw_std::CustomQuery> Querier #bracketed_generics for #sylvia ::types::BoundQuerier<'sv_querier_lifetime, C, #contract > #where_clause {
-                #(#types_implementation)*
-                #(#querier_methods_impl)*
-            }
-        }
-    }
-}
-
 trait EmitQuerierMethod {
     fn emit_querier_impl(&self, api_path: &TokenStream) -> TokenStream;
     fn emit_querier_method_declaration(&self) -> TokenStream;
diff --git a/sylvia-derive/src/interface/mt.rs b/sylvia-derive/src/interface/mt.rs
new file mode 100644
index 0000000..40f39b7
--- /dev/null
+++ b/sylvia-derive/src/interface/mt.rs
@@ -0,0 +1,290 @@
+use convert_case::Case;
+use proc_macro2::{Ident, TokenStream};
+use quote::quote;
+use syn::{parse_quote, GenericParam, ItemTrait, TraitItem, Type};
+
+use crate::crate_module;
+use crate::parser::attributes::msg::MsgType;
+use crate::parser::variant_descs::AsVariantDescs;
+use crate::types::associated_types::AssociatedTypes;
+use crate::types::msg_variant::{MsgVariant, MsgVariants};
+use crate::utils::{emit_bracketed_generics, SvCasing};
+
+pub struct MtHelpers<'a> {
+    source: &'a ItemTrait,
+    error_type: Type,
+    associated_types: &'a AssociatedTypes<'a>,
+    exec_variants: MsgVariants<'a, GenericParam>,
+    query_variants: MsgVariants<'a, GenericParam>,
+    sudo_variants: MsgVariants<'a, GenericParam>,
+    where_clause: &'a Option<syn::WhereClause>,
+}
+
+impl<'a> MtHelpers<'a> {
+    pub fn new(source: &'a ItemTrait, associated_types: &'a AssociatedTypes) -> Self {
+        let where_clause = &source.generics.where_clause;
+        let exec_variants =
+            MsgVariants::new(source.as_variants(), MsgType::Exec, &[], where_clause);
+        let query_variants =
+            MsgVariants::new(source.as_variants(), MsgType::Query, &[], where_clause);
+        let sudo_variants =
+            MsgVariants::new(source.as_variants(), MsgType::Sudo, &[], where_clause);
+        let associated_error = source.items.iter().find_map(|item| match item {
+            TraitItem::Type(ty) if ty.ident == "Error" => Some(&ty.ident),
+            _ => None,
+        });
+        let error_type: Type = match associated_error {
+            Some(error) => parse_quote!(#error),
+            // This should never happen as the `interface` macro requires the trait to have an associated `Error` type
+            None => unreachable!(),
+        };
+
+        Self {
+            error_type,
+            source,
+            associated_types,
+            where_clause,
+            exec_variants,
+            query_variants,
+            sudo_variants,
+        }
+    }
+
+    pub fn emit(&self) -> TokenStream {
+        let Self {
+            error_type,
+            source,
+            associated_types,
+            where_clause,
+            exec_variants,
+            query_variants,
+            sudo_variants,
+        } = self;
+
+        let sylvia = crate_module();
+
+        let interface_name = &source.ident;
+        let trait_name = Ident::new(&format!("{}Proxy", interface_name), interface_name.span());
+
+        let custom_msg: Type = parse_quote! { CustomMsgT };
+        let prefixed_error_type: Type = parse_quote! { Self:: #error_type };
+
+        let mt_app = parse_quote! {
+            #sylvia ::cw_multi_test::App<
+                BankT,
+                ApiT,
+                StorageT,
+                CustomT,
+                WasmT,
+                StakingT,
+                DistrT,
+                IbcT,
+                GovT,
+            >
+        };
+
+        let associated_args: Vec<_> = associated_types
+            .without_error()
+            .map(|associated| &associated.ident)
+            .collect();
+
+        let associated_args_for_api: Vec<_> = associated_types
+            .without_special()
+            .map(|associated| {
+                let assoc = &associated.ident;
+                quote! { Self:: #assoc }
+            })
+            .collect();
+
+        let bracketed_generics = emit_bracketed_generics(&associated_args_for_api);
+        let api = quote! { < Api #bracketed_generics as #sylvia ::types::InterfaceApi> };
+
+        let associated_types_declaration = associated_types.without_error();
+
+        let exec_methods = exec_variants.variants().map(|variant| {
+            variant.emit_mt_method_definition(&custom_msg, &mt_app, &prefixed_error_type, &api)
+        });
+        let query_methods = query_variants.variants().map(|variant| {
+            variant.emit_mt_method_definition(&custom_msg, &mt_app, &prefixed_error_type, &api)
+        });
+        let sudo_methods = sudo_variants.variants().map(|variant| {
+            variant.emit_mt_method_definition(&custom_msg, &mt_app, &prefixed_error_type, &api)
+        });
+
+        let exec_methods_declarations = exec_variants.variants().map(|variant| {
+            variant.emit_mt_method_declaration(&custom_msg, &prefixed_error_type, &api)
+        });
+        let query_methods_declarations = query_variants.variants().map(|variant| {
+            variant.emit_mt_method_declaration(&custom_msg, &prefixed_error_type, &api)
+        });
+        let sudo_methods_declarations = sudo_variants.variants().map(|variant| {
+            variant.emit_mt_method_declaration(&custom_msg, &prefixed_error_type, &api)
+        });
+
+        let where_predicates = where_clause
+            .as_ref()
+            .map(|where_clause| &where_clause.predicates);
+
+        quote! {
+            pub mod mt {
+                use super::*;
+
+                pub trait #trait_name <MtApp, #custom_msg > #where_clause {
+                    type #error_type: std::fmt::Debug + std::fmt::Display + Send + Sync + 'static;
+                    #(#associated_types_declaration)*
+
+                    #(#query_methods_declarations)*
+                    #(#exec_methods_declarations)*
+                    #(#sudo_methods_declarations)*
+                }
+
+                impl<BankT, ApiT, StorageT, CustomT, WasmT, StakingT, DistrT, IbcT, GovT, #custom_msg, ContractT: super:: #interface_name > #trait_name < #mt_app, #custom_msg > for #sylvia ::multitest::Proxy<'_, #mt_app, ContractT >
+                where
+                    ContractT:: #error_type : std::fmt::Debug + std::fmt::Display + Send + Sync + 'static,
+                    #custom_msg: #sylvia ::types::CustomMsg + 'static,
+                    CustomT: #sylvia ::cw_multi_test::Module,
+                    WasmT: #sylvia ::cw_multi_test::Wasm<CustomT::ExecT, CustomT::QueryT>,
+                    BankT: #sylvia ::cw_multi_test::Bank,
+                    ApiT: #sylvia ::cw_std::Api,
+                    StorageT: #sylvia ::cw_std::Storage,
+                    CustomT: #sylvia ::cw_multi_test::Module,
+                    StakingT: #sylvia ::cw_multi_test::Staking,
+                    DistrT: #sylvia ::cw_multi_test::Distribution,
+                    IbcT: #sylvia ::cw_multi_test::Ibc,
+                    GovT: #sylvia ::cw_multi_test::Gov,
+                    CustomT::ExecT: #sylvia ::types::CustomMsg + 'static,
+                    CustomT::QueryT: #sylvia:: types::CustomQuery + 'static,
+                    #mt_app : #sylvia ::cw_multi_test::Executor< #custom_msg >,
+                    #where_predicates
+                {
+                    type #error_type = <ContractT as super:: #interface_name>:: #error_type ;
+                    #(type #associated_args = <ContractT as super:: #interface_name>:: #associated_args ;)*
+
+                    #(#query_methods)*
+                    #(#exec_methods)*
+                    #(#sudo_methods)*
+                }
+            }
+        }
+    }
+}
+
+trait EmitMethods {
+    fn emit_mt_method_definition(
+        &self,
+        custom_msg: &Type,
+        mt_app: &Type,
+        error_type: &Type,
+        api: &TokenStream,
+    ) -> TokenStream;
+
+    fn emit_mt_method_declaration(
+        &self,
+        custom_msg: &Type,
+        error_type: &Type,
+        api: &TokenStream,
+    ) -> TokenStream;
+}
+
+impl EmitMethods for MsgVariant<'_> {
+    fn emit_mt_method_definition(
+        &self,
+        custom_msg: &Type,
+        mt_app: &Type,
+        error_type: &Type,
+        api: &TokenStream,
+    ) -> TokenStream {
+        let sylvia = crate_module();
+
+        let name = self.name();
+        let return_type = self.return_type();
+
+        let params: Vec<_> = self
+            .fields()
+            .iter()
+            .map(|field| field.emit_method_field_folded())
+            .collect();
+        let arguments = self.as_fields_names();
+        let type_name = self.msg_type().as_accessor_name();
+        let name = name.to_case(Case::Snake);
+
+        match self.msg_type() {
+            MsgType::Exec => quote! {
+                #[track_caller]
+                fn #name (&self, #(#params,)* ) -> #sylvia ::multitest::ExecProxy::< #error_type, #api :: #type_name, #mt_app, #custom_msg> {
+                    let msg = #api :: #type_name :: #name ( #(#arguments),* );
+
+                    #sylvia ::multitest::ExecProxy::new(&self.contract_addr, msg, &self.app)
+                }
+            },
+            MsgType::Query => {
+                quote! {
+                    fn #name (&self, #(#params,)* ) -> Result<#return_type, #error_type> {
+                        let msg = #api :: #type_name :: #name ( #(#arguments),* );
+
+                        (*self.app)
+                            .querier()
+                            .query_wasm_smart(self.contract_addr.clone(), &msg)
+                            .map_err(Into::into)
+                    }
+                }
+            }
+            MsgType::Sudo => quote! {
+                fn #name (&self, #(#params,)* ) -> Result< #sylvia ::cw_multi_test::AppResponse, #error_type> {
+                    let msg = #api :: #type_name :: #name ( #(#arguments),* );
+
+                    (*self.app)
+                        .app_mut()
+                        .wasm_sudo(self.contract_addr.clone(), &msg)
+                        .map_err(|err| err.downcast().unwrap())
+                }
+            },
+            MsgType::Migrate => quote! {
+                #[track_caller]
+                fn #name (&self, #(#params,)* ) -> #sylvia ::multitest::MigrateProxy::< #error_type, #api :: #type_name , #mt_app, #custom_msg> {
+                    let msg = #api :: #type_name ::new( #(#arguments),* );
+
+                    #sylvia ::multitest::MigrateProxy::new(&self.contract_addr, msg, &self.app)
+                }
+            },
+            _ => quote! {},
+        }
+    }
+
+    fn emit_mt_method_declaration(
+        &self,
+        custom_msg: &Type,
+        error_type: &Type,
+        api: &TokenStream,
+    ) -> TokenStream {
+        let sylvia = crate_module();
+
+        let name = self.name();
+        let return_type = self.return_type();
+
+        let params: Vec<_> = self
+            .fields()
+            .iter()
+            .map(|field| field.emit_method_field_folded())
+            .collect();
+        let type_name = self.msg_type().as_accessor_name();
+        let name = name.to_case(Case::Snake);
+
+        match self.msg_type() {
+            MsgType::Exec => quote! {
+                fn #name (&self, #(#params,)* ) -> #sylvia ::multitest::ExecProxy::< #error_type, #api:: #type_name, MtApp, #custom_msg>;
+            },
+            MsgType::Query => quote! {
+                fn #name (&self, #(#params,)* ) -> Result<#return_type, #error_type>;
+            },
+            MsgType::Sudo => quote! {
+                fn #name (&self, #(#params,)* ) -> Result< #sylvia ::cw_multi_test::AppResponse, #error_type>;
+            },
+            MsgType::Migrate => quote! {
+                #[track_caller]
+                fn #name (&self, #(#params,)* ) -> #sylvia ::multitest::MigrateProxy::< #error_type, #api :: #type_name, MtApp, #custom_msg>;
+            },
+            _ => quote! {},
+        }
+    }
+}
diff --git a/sylvia-derive/src/lib.rs b/sylvia-derive/src/lib.rs
index 2fe5b9f..f581f8a 100644
--- a/sylvia-derive/src/lib.rs
+++ b/sylvia-derive/src/lib.rs
@@ -3,31 +3,25 @@
 //! Please refer to the [Sylvia-book](https://cosmwasm.github.io/sylvia-book/index.html) on how to use these macros.
 
 use crate::parser::EntryPointArgs;
-use input::{EntryPointInput, ImplInput, TraitInput};
+use contract::ContractInput;
+use entry_points::EntryPointInput;
+use fold::StripInput;
+use interface::InterfaceInput;
 use proc_macro::TokenStream;
 use proc_macro2::TokenStream as TokenStream2;
 use proc_macro_error::proc_macro_error;
 use quote::quote;
-use strip_input::StripInput;
 use syn::fold::Fold;
 use syn::spanned::Spanned;
 use syn::{parse2, parse_quote, ItemImpl, ItemTrait, Path};
 
-mod associated_types;
-pub(crate) mod check_generics;
-mod executor;
-mod input;
-mod interfaces;
-mod message;
-mod message_type;
-mod multitest;
+mod contract;
+mod entry_points;
+mod fold;
+mod interface;
 mod parser;
-mod querier;
-mod strip_generics;
-mod strip_input;
-mod strip_self_path;
+mod types;
 mod utils;
-mod variant_descs;
 
 #[cfg(not(test))]
 pub(crate) fn crate_module() -> Path {
@@ -250,7 +244,7 @@ fn interface_impl(_attr: TokenStream2, item: TokenStream2) -> TokenStream2 {
     fn inner(item: TokenStream2) -> syn::Result<TokenStream2> {
         let input: ItemTrait = parse2(item)?;
 
-        let expanded = TraitInput::new(&input).process();
+        let expanded = InterfaceInput::new(&input).process();
         let input = StripInput.fold_item_trait(input);
 
         Ok(quote! {
@@ -638,7 +632,7 @@ fn contract_impl(attr: TokenStream2, item: TokenStream2) -> TokenStream2 {
     fn inner(attr: TokenStream2, item: TokenStream2) -> syn::Result<TokenStream2> {
         let input: ItemImpl = parse2(item)?;
         let expanded = if attr.is_empty() {
-            ImplInput::new(&input).process()
+            ContractInput::new(&input).process()
         } else {
             quote! {}
         };
diff --git a/sylvia-derive/src/message.rs b/sylvia-derive/src/message.rs
deleted file mode 100644
index 615e9fc..0000000
--- a/sylvia-derive/src/message.rs
+++ /dev/null
@@ -1,1433 +0,0 @@
-use crate::associated_types::{AssociatedTypes, ItemType, EXEC_TYPE, QUERY_TYPE};
-use crate::check_generics::{CheckGenerics, GetPath};
-use crate::crate_module;
-use crate::interfaces::Interfaces;
-use crate::parser::attributes::{MsgAttrForwarding, VariantAttrForwarding};
-use crate::parser::{
-    parse_associated_custom_type, ContractErrorAttr, Custom, EntryPointArgs,
-    FilteredOverrideEntryPoints, MsgAttr, MsgType, OverrideEntryPoint, ParsedSylviaAttributes,
-};
-use crate::strip_generics::StripGenerics;
-use crate::strip_self_path::StripSelfPath;
-use crate::utils::{
-    as_where_clause, emit_bracketed_generics, extract_return_type, filter_wheres, process_fields,
-    SvCasing,
-};
-use crate::variant_descs::{AsVariantDescs, VariantDescs};
-use convert_case::{Case, Casing};
-use proc_macro2::{Span, TokenStream};
-use proc_macro_error::emit_error;
-use quote::{quote, ToTokens};
-use syn::fold::Fold;
-use syn::spanned::Spanned;
-use syn::visit::Visit;
-use syn::{
-    parse_quote, Attribute, GenericParam, Ident, ImplItem, ImplItemFn, ItemImpl, ItemTrait, Pat,
-    PatType, ReturnType, Signature, Type, WhereClause, WherePredicate,
-};
-
-/// Representation of single struct message
-pub struct StructMessage<'a> {
-    contract_type: &'a Type,
-    fields: Vec<MsgField<'a>>,
-    function_name: &'a Ident,
-    generics: Vec<&'a GenericParam>,
-    unused_generics: Vec<&'a GenericParam>,
-    wheres: Vec<&'a WherePredicate>,
-    full_where: Option<&'a WhereClause>,
-    result: &'a ReturnType,
-    msg_attr: MsgAttr,
-    custom: &'a Custom,
-    msg_attrs_to_forward: Vec<MsgAttrForwarding>,
-}
-
-impl<'a> StructMessage<'a> {
-    /// Creates new struct message of given type from impl block
-    pub fn new(
-        source: &'a ItemImpl,
-        ty: MsgType,
-        generics: &'a [&'a GenericParam],
-        custom: &'a Custom,
-    ) -> Option<StructMessage<'a>> {
-        let mut generics_checker = CheckGenerics::new(generics);
-
-        let contract_type = &source.self_ty;
-
-        let parsed = Self::parse_struct_message(source, ty);
-        let (method, msg_attr) = parsed?;
-
-        let function_name = &method.sig.ident;
-        let fields = process_fields(&method.sig, &mut generics_checker);
-        let (used_generics, unused_generics) = generics_checker.used_unused();
-        let wheres = filter_wheres(&source.generics.where_clause, generics, &used_generics);
-
-        let msg_attrs_to_forward = ParsedSylviaAttributes::new(source.attrs.iter())
-            .msg_attrs_forward
-            .into_iter()
-            .filter(|attr| attr.msg_type == ty)
-            .collect();
-
-        Some(Self {
-            contract_type,
-            fields,
-            function_name,
-            generics: used_generics,
-            unused_generics,
-            wheres,
-            full_where: source.generics.where_clause.as_ref(),
-            result: &method.sig.output,
-            msg_attr,
-            custom,
-            msg_attrs_to_forward,
-        })
-    }
-
-    fn parse_struct_message(source: &ItemImpl, ty: MsgType) -> Option<(&ImplItemFn, MsgAttr)> {
-        let mut methods = source.items.iter().filter_map(|item| match item {
-            ImplItem::Fn(method) => {
-                let attr = ParsedSylviaAttributes::new(method.attrs.iter()).msg_attr?;
-                if attr == ty {
-                    Some((method, attr))
-                } else {
-                    None
-                }
-            }
-            _ => None,
-        });
-
-        let (method, msg_attr) = if let Some(method) = methods.next() {
-            method
-        } else {
-            if ty == MsgType::Instantiate {
-                emit_error!(
-                    source.span(), "Missing instantiation message.";
-                    note = source.span() => "`sylvia::contract` requires exactly one method marked with `#[sv::msg(instantiation)]` attribute."
-                );
-            }
-            return None;
-        };
-
-        if let Some((obsolete, _)) = methods.next() {
-            emit_error!(
-                obsolete.span(), "More than one instantiation or migration message";
-                note = method.span() => "Instantiation/Migration message previously defined here"
-            );
-        }
-        Some((method, msg_attr))
-    }
-
-    pub fn emit(&self) -> TokenStream {
-        use MsgAttr::*;
-
-        let instantiate_msg = Ident::new("InstantiateMsg", self.function_name.span());
-        let migrate_msg = Ident::new("MigrateMsg", self.function_name.span());
-
-        match &self.msg_attr {
-            Instantiate { .. } => self.emit_struct(&instantiate_msg),
-            Migrate { .. } => self.emit_struct(&migrate_msg),
-            _ => {
-                emit_error!(Span::mixed_site(), "Invalid message type");
-                quote! {}
-            }
-        }
-    }
-
-    pub fn emit_struct(&self, name: &Ident) -> TokenStream {
-        let sylvia = crate_module();
-
-        let Self {
-            contract_type,
-            fields,
-            function_name,
-            generics,
-            unused_generics,
-            wheres,
-            full_where,
-            result,
-            msg_attr,
-            custom,
-            msg_attrs_to_forward,
-        } = self;
-
-        let ctx_type = msg_attr
-            .msg_type()
-            .emit_ctx_type(&custom.query_or_default());
-        let fields_names: Vec<_> = fields.iter().map(MsgField::name).collect();
-        let parameters = fields.iter().map(MsgField::emit_method_field);
-        let fields = fields.iter().map(MsgField::emit_pub);
-
-        let where_clause = as_where_clause(wheres);
-        let generics = emit_bracketed_generics(generics);
-        let unused_generics = emit_bracketed_generics(unused_generics);
-        let msg_attrs_to_forward = msg_attrs_to_forward.iter().map(|attr| &attr.attrs);
-
-        quote! {
-            #[allow(clippy::derive_partial_eq_without_eq)]
-            #[derive(#sylvia ::serde::Serialize, #sylvia ::serde::Deserialize, Clone, Debug, PartialEq, #sylvia ::schemars::JsonSchema)]
-            #( #[ #msg_attrs_to_forward ] )*
-            #[serde(rename_all="snake_case")]
-            pub struct #name #generics {
-                #(#fields,)*
-            }
-
-            impl #generics #name #generics #where_clause {
-                pub fn new(#(#parameters,)*) -> Self {
-                    Self { #(#fields_names,)* }
-                }
-
-                pub fn dispatch #unused_generics(self, contract: &#contract_type, ctx: #ctx_type)
-                    #result #full_where
-                {
-                    let Self { #(#fields_names,)* } = self;
-                    contract.#function_name(Into::into(ctx), #(#fields_names,)*).map_err(Into::into)
-                }
-            }
-        }
-    }
-}
-
-/// Representation of single enum message
-pub struct EnumMessage<'a> {
-    source: &'a ItemTrait,
-    variants: MsgVariants<'a, Ident>,
-    associated_types: &'a AssociatedTypes<'a>,
-    msg_ty: MsgType,
-    resp_type: Type,
-    query_type: Type,
-    msg_attrs_to_forward: Vec<MsgAttrForwarding>,
-}
-
-impl<'a> EnumMessage<'a> {
-    pub fn new(
-        source: &'a ItemTrait,
-        msg_ty: MsgType,
-        custom: &'a Custom,
-        variants: MsgVariants<'a, Ident>,
-        associated_types: &'a AssociatedTypes<'a>,
-    ) -> Self {
-        let associated_exec = parse_associated_custom_type(source, EXEC_TYPE);
-        let associated_query = parse_associated_custom_type(source, QUERY_TYPE);
-
-        let resp_type = custom
-            .msg
-            .clone()
-            .or(associated_exec)
-            .unwrap_or_else(Custom::default_type);
-
-        let query_type = custom
-            .query
-            .clone()
-            .or(associated_query)
-            .unwrap_or_else(Custom::default_type);
-
-        let msg_attrs_to_forward = ParsedSylviaAttributes::new(source.attrs.iter())
-            .msg_attrs_forward
-            .into_iter()
-            .filter(|attr| attr.msg_type == msg_ty)
-            .collect();
-
-        Self {
-            source,
-            variants,
-            associated_types,
-            msg_ty,
-            resp_type,
-            query_type,
-            msg_attrs_to_forward,
-        }
-    }
-
-    pub fn emit(&self) -> TokenStream {
-        let Self {
-            source,
-            variants,
-            associated_types,
-            msg_ty,
-            resp_type,
-            query_type,
-            msg_attrs_to_forward,
-        } = self;
-
-        let trait_name = &source.ident;
-        let enum_name = msg_ty.emit_msg_name();
-        let unique_enum_name =
-            Ident::new(&format!("{}{}", trait_name, enum_name), enum_name.span());
-
-        let match_arms = variants.emit_dispatch_legs();
-        let mut msgs = variants.as_names_snake_cased();
-        msgs.sort();
-        let msgs_cnt = msgs.len();
-        let variants_constructors = variants.emit_constructors();
-        let msg_variants = variants.emit();
-
-        let ctx_type = msg_ty.emit_ctx_type(query_type);
-        let dispatch_type = msg_ty.emit_result_type(resp_type, &parse_quote!(ContractT::Error));
-
-        let used_generics = variants.used_generics();
-        let unused_generics = variants.unused_generics();
-        let where_predicates = associated_types
-            .without_error()
-            .map(ItemType::as_where_predicate);
-        let where_clause = variants.where_clause();
-        let contract_predicate = associated_types.emit_contract_predicate(trait_name);
-
-        let phantom_variant = variants.emit_phantom_variant();
-        let phatom_match_arm = variants.emit_phantom_match_arm();
-        let bracketed_used_generics = emit_bracketed_generics(used_generics);
-
-        let ep_name = msg_ty.emit_ep_name();
-        let messages_fn_name = Ident::new(&format!("{}_messages", ep_name), enum_name.span());
-        let derive_call = msg_ty.emit_derive_call();
-        let msg_attrs_to_forward = msg_attrs_to_forward.iter().map(|attr| &attr.attrs);
-
-        quote! {
-            #[allow(clippy::derive_partial_eq_without_eq)]
-            #derive_call
-            #( #[ #msg_attrs_to_forward ] )*
-            #[serde(rename_all="snake_case")]
-            pub enum #unique_enum_name #bracketed_used_generics {
-                #(#msg_variants,)*
-                #phantom_variant
-            }
-            pub type #enum_name #bracketed_used_generics = #unique_enum_name #bracketed_used_generics;
-
-            impl #bracketed_used_generics #unique_enum_name #bracketed_used_generics #where_clause {
-                pub fn dispatch<ContractT, #(#unused_generics,)*>(self, contract: &ContractT, ctx: #ctx_type)
-                    -> #dispatch_type
-                where
-                    #(#where_predicates,)*
-                    #contract_predicate
-                {
-                    use #unique_enum_name::*;
-
-                    match self {
-                        #(#match_arms,)*
-                        #phatom_match_arm
-                    }
-                }
-                #(#variants_constructors)*
-            }
-
-            pub const fn #messages_fn_name () -> [&'static str; #msgs_cnt] {
-                [#(#msgs,)*]
-            }
-        }
-    }
-}
-
-/// Representation of single enum message
-pub struct ContractEnumMessage<'a> {
-    variants: MsgVariants<'a, GenericParam>,
-    msg_ty: MsgType,
-    contract: &'a Type,
-    error: &'a ContractErrorAttr,
-    custom: &'a Custom,
-    where_clause: &'a Option<WhereClause>,
-    msg_attrs_to_forward: Vec<MsgAttrForwarding>,
-}
-
-impl<'a> ContractEnumMessage<'a> {
-    pub fn new(
-        source: &'a ItemImpl,
-        msg_ty: MsgType,
-        generics: &'a [&'a GenericParam],
-        error: &'a ContractErrorAttr,
-        custom: &'a Custom,
-    ) -> Self {
-        let where_clause = &source.generics.where_clause;
-        let variants = MsgVariants::new(source.as_variants(), msg_ty, generics, where_clause);
-        let msg_attrs_to_forward = ParsedSylviaAttributes::new(source.attrs.iter())
-            .msg_attrs_forward
-            .into_iter()
-            .filter(|attr| attr.msg_type == msg_ty)
-            .collect();
-
-        Self {
-            variants,
-            msg_ty,
-            contract: &source.self_ty,
-            error,
-            custom,
-            where_clause,
-            msg_attrs_to_forward,
-        }
-    }
-
-    pub fn emit(&self) -> TokenStream {
-        let sylvia = crate_module();
-
-        let Self {
-            variants,
-            msg_ty,
-            contract,
-            error,
-            custom,
-            where_clause,
-            msg_attrs_to_forward,
-            ..
-        } = self;
-
-        let enum_name = msg_ty.emit_msg_name();
-        let match_arms = variants.emit_dispatch_legs();
-        let unused_generics = variants.unused_generics();
-        let bracketed_unused_generics = emit_bracketed_generics(unused_generics);
-        let used_generics = variants.used_generics();
-        let bracketed_used_generics = emit_bracketed_generics(used_generics);
-
-        let mut variant_names = variants.as_names_snake_cased();
-        variant_names.sort();
-        let variants_cnt = variant_names.len();
-        let variants_constructors = variants.emit_constructors();
-        let variants = variants.emit();
-
-        let ctx_type = msg_ty.emit_ctx_type(&custom.query_or_default());
-        let ret_type = msg_ty.emit_result_type(&custom.msg_or_default(), &error.error);
-
-        let derive_query = match msg_ty {
-            MsgType::Query => quote! { #sylvia ::cw_schema::QueryResponses },
-            _ => quote! {},
-        };
-
-        let ep_name = msg_ty.emit_ep_name();
-        let messages_fn_name = Ident::new(&format!("{}_messages", ep_name), contract.span());
-
-        let phantom_variant = msg_ty.emit_phantom_variant(used_generics);
-        let phantom_match_arm = match !used_generics.is_empty() {
-            true => quote! {
-                _Phantom(_) => Err(#sylvia ::cw_std::StdError::generic_err("Phantom message should not be constructed.")).map_err(Into::into),
-            },
-            false => quote! {},
-        };
-        let msg_attrs_to_forward = msg_attrs_to_forward.iter().map(|attr| &attr.attrs);
-
-        quote! {
-            #[allow(clippy::derive_partial_eq_without_eq)]
-            #[derive(#sylvia ::serde::Serialize, #sylvia ::serde::Deserialize, Clone, Debug, PartialEq, #sylvia ::schemars::JsonSchema, #derive_query )]
-            #( #[ #msg_attrs_to_forward ] )*
-            #[serde(rename_all="snake_case")]
-            pub enum #enum_name #bracketed_used_generics {
-                #(#variants,)*
-                #phantom_variant
-            }
-
-            impl #bracketed_used_generics #enum_name #bracketed_used_generics {
-                pub fn dispatch #bracketed_unused_generics (self, contract: &#contract, ctx: #ctx_type) -> #ret_type #where_clause {
-                    use #enum_name::*;
-
-                    match self {
-                        #(#match_arms,)*
-                        #phantom_match_arm
-                    }
-                }
-
-                #(#variants_constructors)*
-            }
-
-            pub const fn #messages_fn_name () -> [&'static str; #variants_cnt] {
-                [#(#variant_names,)*]
-            }
-        }
-    }
-}
-
-/// Representation of whole message variant
-#[derive(Debug)]
-pub struct MsgVariant<'a> {
-    name: Ident,
-    function_name: &'a Ident,
-    fields: Vec<MsgField<'a>>,
-    /// Type extracted only in case of `Query` and used in `cosmwasm_schema::QueryResponses`
-    /// `returns` attribute.
-    return_type: Option<Type>,
-    msg_type: MsgType,
-    attrs_to_forward: Vec<VariantAttrForwarding>,
-}
-
-impl<'a> MsgVariant<'a> {
-    /// Creates new message variant from trait method
-    pub fn new<Generic>(
-        sig: &'a Signature,
-        generics_checker: &mut CheckGenerics<Generic>,
-        msg_attr: MsgAttr,
-        attrs_to_forward: Vec<VariantAttrForwarding>,
-    ) -> MsgVariant<'a>
-    where
-        Generic: GetPath + PartialEq,
-    {
-        let function_name = &sig.ident;
-
-        let name = function_name.to_case(Case::UpperCamel);
-        let fields = process_fields(sig, generics_checker);
-        let msg_type = msg_attr.msg_type();
-
-        let return_type = if let MsgAttr::Query { resp_type, .. } = msg_attr {
-            match resp_type {
-                Some(resp_type) => {
-                    let resp_type = parse_quote! { #resp_type };
-                    generics_checker.visit_type(&resp_type);
-                    Some(resp_type)
-                }
-                None => {
-                    let return_type = extract_return_type(&sig.output);
-                    let stripped_return_type = StripSelfPath.fold_path(return_type.clone());
-                    generics_checker.visit_path(&stripped_return_type);
-                    Some(parse_quote! { #return_type })
-                }
-            }
-        } else {
-            None
-        };
-
-        Self {
-            name,
-            function_name,
-            fields,
-            return_type,
-            msg_type,
-            attrs_to_forward,
-        }
-    }
-
-    /// Emits message variant
-    pub fn emit(&self) -> TokenStream {
-        let Self {
-            name,
-            fields,
-            msg_type,
-            return_type,
-            attrs_to_forward,
-            ..
-        } = self;
-        let fields = fields.iter().map(MsgField::emit);
-        let returns_attribute = msg_type.emit_returns_attribute(return_type);
-        let attrs_to_forward = attrs_to_forward.iter().map(|attr| &attr.attrs);
-
-        quote! {
-            #returns_attribute
-            #( #[ #attrs_to_forward ] )*
-            #name {
-                #(#fields,)*
-            }
-        }
-    }
-
-    /// Emits match leg dispatching against this variant. Assumes enum variants are imported into the
-    /// scope. Dispatching is performed by calling the function this variant is build from on the
-    /// `contract` variable, with `ctx` as its first argument - both of them should be in scope.
-    pub fn emit_dispatch_leg(&self) -> TokenStream {
-        let Self {
-            name,
-            fields,
-            function_name,
-            msg_type,
-            ..
-        } = self;
-
-        let args: Vec<_> = fields
-            .iter()
-            .zip(1..)
-            .map(|(field, num)| Ident::new(&format!("field{}", num), field.name.span()))
-            .collect();
-
-        let fields = fields
-            .iter()
-            .map(|field| field.name)
-            .zip(args.clone())
-            .map(|(field, num_field)| quote!(#field : #num_field));
-
-        let method_call = msg_type.emit_dispatch_leg(function_name, &args);
-
-        quote! {
-            #name {
-                #(#fields,)*
-            } => #method_call
-        }
-    }
-
-    /// Emits variants constructors. Constructors names are variants names in snake_case.
-    pub fn emit_variants_constructors(&self) -> TokenStream {
-        let Self { name, fields, .. } = self;
-
-        let method_name = name.to_case(Case::Snake);
-        let parameters = fields.iter().map(MsgField::emit_method_field);
-        let arguments = fields.iter().map(MsgField::name);
-
-        quote! {
-            pub fn #method_name( #(#parameters),*) -> Self {
-                Self :: #name { #(#arguments),* }
-            }
-        }
-    }
-
-    pub fn as_fields_names(&self) -> Vec<&Ident> {
-        self.fields.iter().map(MsgField::name).collect()
-    }
-
-    pub fn emit_method_field(&self) -> Vec<TokenStream> {
-        self.fields
-            .iter()
-            .map(MsgField::emit_method_field)
-            .collect()
-    }
-
-    pub fn name(&self) -> &Ident {
-        &self.name
-    }
-
-    pub fn fields(&self) -> &Vec<MsgField> {
-        &self.fields
-    }
-
-    pub fn msg_type(&self) -> &MsgType {
-        &self.msg_type
-    }
-
-    pub fn return_type(&self) -> &Option<Type> {
-        &self.return_type
-    }
-}
-
-#[derive(Debug)]
-pub struct MsgVariants<'a, Generic> {
-    variants: Vec<MsgVariant<'a>>,
-    used_generics: Vec<&'a Generic>,
-    unused_generics: Vec<&'a Generic>,
-    where_predicates: Vec<&'a WherePredicate>,
-    msg_ty: MsgType,
-}
-
-impl<'a, Generic> MsgVariants<'a, Generic>
-where
-    Generic: GetPath + PartialEq + ToTokens,
-{
-    pub fn new(
-        source: VariantDescs<'a>,
-        msg_ty: MsgType,
-        all_generics: &'a [&'a Generic],
-        unfiltered_where_clause: &'a Option<WhereClause>,
-    ) -> Self {
-        let mut generics_checker = CheckGenerics::new(all_generics);
-        let variants: Vec<_> = source
-            .filter_map(|variant_desc| {
-                let msg_attr: MsgAttr = variant_desc.attr_msg()?;
-                let attrs_to_forward = variant_desc.attrs_to_forward();
-
-                if msg_attr.msg_type() != msg_ty {
-                    return None;
-                }
-
-                Some(MsgVariant::new(
-                    variant_desc.into_sig(),
-                    &mut generics_checker,
-                    msg_attr,
-                    attrs_to_forward,
-                ))
-            })
-            .collect();
-
-        let (used_generics, unused_generics) = generics_checker.used_unused();
-        let where_predicates = filter_wheres(unfiltered_where_clause, all_generics, &used_generics);
-
-        Self {
-            variants,
-            used_generics,
-            unused_generics,
-            where_predicates,
-            msg_ty,
-        }
-    }
-
-    pub fn where_clause(&self) -> Option<WhereClause> {
-        let where_predicates = &self.where_predicates;
-        if !where_predicates.is_empty() {
-            Some(parse_quote! { where #(#where_predicates),* })
-        } else {
-            None
-        }
-    }
-
-    pub fn variants(&self) -> impl Iterator<Item = &MsgVariant> {
-        self.variants.iter()
-    }
-
-    pub fn used_generics(&self) -> &Vec<&'a Generic> {
-        &self.used_generics
-    }
-
-    pub fn unused_generics(&self) -> &Vec<&'a Generic> {
-        &self.unused_generics
-    }
-
-    pub fn emit_phantom_match_arm(&self) -> TokenStream {
-        let sylvia = crate_module();
-        let Self { used_generics, .. } = self;
-        if used_generics.is_empty() {
-            return quote! {};
-        }
-        quote! {
-            _Phantom(_) => Err(#sylvia ::cw_std::StdError::generic_err("Phantom message should not be constructed.")).map_err(Into::into),
-        }
-    }
-
-    pub fn emit_dispatch_legs(&self) -> impl Iterator<Item = TokenStream> + '_ {
-        self.variants
-            .iter()
-            .map(|variant| variant.emit_dispatch_leg())
-    }
-
-    pub fn as_names_snake_cased(&self) -> Vec<String> {
-        self.variants
-            .iter()
-            .map(|variant| variant.name.to_string().to_case(Case::Snake))
-            .collect()
-    }
-
-    pub fn emit_constructors(&self) -> impl Iterator<Item = TokenStream> + '_ {
-        self.variants
-            .iter()
-            .map(MsgVariant::emit_variants_constructors)
-    }
-
-    pub fn emit(&self) -> impl Iterator<Item = TokenStream> + '_ {
-        self.variants.iter().map(MsgVariant::emit)
-    }
-
-    pub fn get_only_variant(&self) -> Option<&MsgVariant> {
-        self.variants.first()
-    }
-
-    pub fn emit_phantom_variant(&self) -> TokenStream {
-        let Self {
-            msg_ty,
-            used_generics,
-            ..
-        } = self;
-
-        if used_generics.is_empty() {
-            return quote! {};
-        }
-
-        let return_attr = match msg_ty {
-            MsgType::Query => quote! { #[returns((#(#used_generics,)*))] },
-            _ => quote! {},
-        };
-
-        quote! {
-            #[serde(skip)]
-            #return_attr
-            _Phantom(std::marker::PhantomData<( #(#used_generics,)* )>),
-        }
-    }
-}
-
-/// Representation of single message variant field
-#[derive(Debug)]
-pub struct MsgField<'a> {
-    name: &'a Ident,
-    ty: &'a Type,
-    stripped_ty: Type,
-    attrs: &'a Vec<Attribute>,
-}
-
-impl<'a> MsgField<'a> {
-    /// Creates new field from trait method argument
-    pub fn new<Generic>(
-        item: &'a PatType,
-        generics_checker: &mut CheckGenerics<Generic>,
-    ) -> Option<MsgField<'a>>
-    where
-        Generic: GetPath + PartialEq,
-    {
-        let name = match &*item.pat {
-            Pat::Ident(p) => Some(&p.ident),
-            pat => {
-                // TODO: Support pattern arguments, when decorated with argument with item
-                // name
-                //
-                // Eg.
-                //
-                // ```
-                // fn exec_foo(&self, ctx: Ctx, #[sv::msg(name=metadata)] SomeData { addr, sender }: SomeData);
-                // ```
-                //
-                // should expand to enum variant:
-                //
-                // ```
-                // ExecFoo {
-                //   metadata: SomeDaa
-                // }
-                // ```
-                emit_error!(pat.span(), "Expected argument name, pattern occurred");
-                None
-            }
-        }?;
-
-        let ty = &item.ty;
-        let stripped_ty = StripSelfPath.fold_type((*item.ty).clone());
-        let attrs = &item.attrs;
-        generics_checker.visit_type(&stripped_ty);
-
-        Some(Self {
-            name,
-            ty,
-            stripped_ty,
-            attrs,
-        })
-    }
-
-    /// Emits message field
-    pub fn emit(&self) -> TokenStream {
-        let Self {
-            name,
-            stripped_ty,
-            attrs,
-            ..
-        } = self;
-
-        quote! {
-            #(#attrs)*
-            #name: #stripped_ty
-        }
-    }
-
-    /// Emits struct field
-    pub fn emit_pub(&self) -> TokenStream {
-        let Self {
-            name,
-            stripped_ty,
-            attrs,
-            ..
-        } = self;
-
-        quote! {
-            #(#attrs)*
-            pub #name: #stripped_ty
-        }
-    }
-
-    /// Emits method field
-    pub fn emit_method_field(&self) -> TokenStream {
-        let Self {
-            name, stripped_ty, ..
-        } = self;
-
-        quote! {
-            #name: #stripped_ty
-        }
-    }
-
-    pub fn emit_method_field_folded(&self) -> TokenStream {
-        let Self { name, ty, .. } = self;
-
-        quote! {
-            #name: #ty
-        }
-    }
-
-    pub fn name(&self) -> &'a Ident {
-        self.name
-    }
-}
-
-/// Glue message is the message composing Exec/Query messages from several traits
-#[derive(Debug)]
-pub struct GlueMessage<'a> {
-    source: &'a ItemImpl,
-    contract: &'a Type,
-    msg_ty: MsgType,
-    error: &'a ContractErrorAttr,
-    custom: &'a Custom,
-    interfaces: &'a Interfaces,
-}
-
-impl<'a> GlueMessage<'a> {
-    pub fn new(
-        source: &'a ItemImpl,
-        msg_ty: MsgType,
-        error: &'a ContractErrorAttr,
-        custom: &'a Custom,
-        interfaces: &'a Interfaces,
-    ) -> Self {
-        GlueMessage {
-            source,
-            contract: &source.self_ty,
-            msg_ty,
-            error,
-            custom,
-            interfaces,
-        }
-    }
-
-    pub fn emit(&self) -> TokenStream {
-        let sylvia = crate_module();
-        let Self {
-            source,
-            contract,
-            msg_ty,
-            error,
-            custom,
-            interfaces,
-            ..
-        } = self;
-
-        let generics: Vec<_> = source.generics.params.iter().collect();
-        let full_where_clause = &source.generics.where_clause;
-        let bracketed_wrapper_generics = emit_bracketed_generics(&generics);
-
-        let contract_enum_name = msg_ty.emit_msg_wrapper_name();
-        let enum_accessor = msg_ty.as_accessor_name();
-        let contract_name = StripGenerics.fold_type((*contract).clone());
-
-        let variants = interfaces.emit_glue_message_variants(msg_ty, contract);
-        let types = interfaces.emit_glue_message_types(msg_ty, contract);
-
-        let ep_name = msg_ty.emit_ep_name();
-        let messages_fn_name = Ident::new(&format!("{}_messages", ep_name), contract.span());
-        let contract_variant = quote! { #contract_name ( <#contract as #sylvia ::types::ContractApi> :: #enum_accessor ) };
-        let mut messages_call = interfaces.emit_messages_call(msg_ty);
-        messages_call.push(quote! { &#messages_fn_name() });
-
-        let variants_cnt = messages_call.len();
-
-        let dispatch_arms = interfaces.emit_dispatch_arms(msg_ty);
-
-        let dispatch_arm =
-            quote! {#contract_enum_name :: #contract_name (msg) => msg.dispatch(contract, ctx)};
-
-        let interfaces_deserialization_attempts = interfaces.emit_deserialization_attempts(msg_ty);
-
-        let contract_deserialization_attempt = quote! {
-            let msgs = &#messages_fn_name();
-            if msgs.into_iter().any(|msg| msg == &recv_msg_name) {
-                match val.deserialize_into() {
-                    Ok(msg) => return Ok(Self:: #contract_name (msg)),
-                    Err(err) => return Err(D::Error::custom(err)).map(Self:: #contract_name )
-                };
-            }
-        };
-
-        let ctx_type = msg_ty.emit_ctx_type(&custom.query_or_default());
-        let ret_type = msg_ty.emit_result_type(&custom.msg_or_default(), &error.error);
-
-        let mut response_schemas_calls = interfaces.emit_response_schemas_calls(msg_ty, contract);
-        response_schemas_calls
-            .push(quote! {<#contract as #sylvia ::types::ContractApi> :: #enum_accessor ::response_schemas_impl()});
-
-        let response_schemas = match msg_ty {
-            MsgType::Query => {
-                quote! {
-                    #[cfg(not(target_arch = "wasm32"))]
-                    impl #bracketed_wrapper_generics #sylvia ::cw_schema::QueryResponses for #contract_enum_name #bracketed_wrapper_generics #full_where_clause {
-                        fn response_schemas_impl() -> std::collections::BTreeMap<String, #sylvia ::schemars::schema::RootSchema> {
-                            let responses = [#(#response_schemas_calls),*];
-                            responses.into_iter().flatten().collect()
-                        }
-                    }
-                }
-            }
-            _ => {
-                quote! {}
-            }
-        };
-
-        let modules_names = interfaces.variants_modules();
-        let variants_names = interfaces.variants_names();
-
-        quote! {
-            #[allow(clippy::derive_partial_eq_without_eq)]
-            #[derive(#sylvia ::serde::Serialize, Clone, Debug, PartialEq)]
-            #[serde(rename_all="snake_case", untagged)]
-            pub enum #contract_enum_name #bracketed_wrapper_generics #full_where_clause {
-                #(#variants,)*
-                #contract_variant
-            }
-
-            // `schemars` v0.8.16 requires every generic type to implement JsonSchema in
-            // order to use derive JsonSchema macro. The goal of that trait bound is to
-            // generate schema_name. Currently there's no way to provide such a name in an
-            // attribute, so Sylvia needs to implement this trait manually:
-            //
-            impl #bracketed_wrapper_generics #sylvia ::schemars::JsonSchema
-                for #contract_enum_name #bracketed_wrapper_generics #full_where_clause {
-
-                fn schema_name() -> std::string::String {
-                    {
-                        let res = format!(
-                                "{0}",
-                                std::any::type_name::<Self>()
-                        );
-                        res
-                    }
-                }
-
-                fn json_schema(
-                    gen: &mut #sylvia ::schemars::gen::SchemaGenerator,
-                ) -> #sylvia ::schemars::schema::Schema {
-                    #sylvia ::schemars::schema::Schema::Object( #sylvia ::schemars::schema::SchemaObject {
-                        subschemas: Some(
-                            Box::new( #sylvia ::schemars::schema::SubschemaValidation {
-                                any_of: Some(
-                                    <[_]>::into_vec(
-                                        Box::new([
-                                            #(gen.subschema_for::<#types>(),)*
-                                            gen.subschema_for::< <#contract as #sylvia ::types::ContractApi> :: #enum_accessor >(),
-                                        ]),
-                                    ),
-                                ),
-                                ..Default::default()
-                            }),
-                        ),
-                        ..Default::default()
-                    })
-                }
-            }
-
-            impl #bracketed_wrapper_generics #contract_enum_name #bracketed_wrapper_generics #full_where_clause {
-                pub fn dispatch (
-                    self,
-                    contract: &#contract,
-                    ctx: #ctx_type,
-                ) -> #ret_type #full_where_clause {
-                    const _: () = {
-                        let msgs: [&[&str]; #variants_cnt] = [#(#messages_call),*];
-                        #sylvia ::utils::assert_no_intersection(msgs);
-                    };
-
-                    match self {
-                        #(#dispatch_arms,)*
-                        #dispatch_arm
-                    }
-                }
-            }
-
-            #response_schemas
-
-            impl<'sv_de, #(#generics,)* > serde::Deserialize<'sv_de> for #contract_enum_name #bracketed_wrapper_generics #full_where_clause {
-                fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
-                    where D: serde::Deserializer<'sv_de>,
-                {
-                    use serde::de::Error;
-
-                    let val = #sylvia ::serde_value::Value::deserialize(deserializer)?;
-                    let map = match &val {
-                        #sylvia ::serde_value::Value::Map(map) => map,
-                        _ => return Err(D::Error::custom("Wrong message format!"))
-                    };
-                    if map.len() != 1 {
-                        return Err(D::Error::custom(format!("Expected exactly one message. Received {}", map.len())))
-                    }
-
-                    // Due to earlier size check of map this unwrap is safe
-                    let recv_msg_name = map.into_iter().next().unwrap();
-
-                    if let #sylvia ::serde_value::Value::String(recv_msg_name) = &recv_msg_name .0 {
-                        #(#interfaces_deserialization_attempts)*
-                        #contract_deserialization_attempt
-                    }
-
-                    let msgs: [&[&str]; #variants_cnt] = [#(#messages_call),*];
-                    let mut err_msg = msgs.into_iter().flatten().fold(
-                        // It might be better to forward the error or serialization, but we just
-                        // deserialized it from JSON, not reason to expect failure here.
-                        format!(
-                            "Unsupported message received: {}. Messages supported by this contract: ",
-                            #sylvia ::serde_json::to_string(&val).unwrap_or_else(|_| String::new())
-                        ),
-                        |mut acc, message| acc + message + ", ",
-                    );
-                    err_msg.truncate(err_msg.len() - 2);
-                    Err(D::Error::custom(err_msg))
-                }
-            }
-
-            impl #bracketed_wrapper_generics From<<#contract as #sylvia ::types::ContractApi>:: #enum_accessor>
-                for #contract_enum_name #bracketed_wrapper_generics #full_where_clause {
-                fn from(a: <#contract as #sylvia ::types::ContractApi>:: #enum_accessor ) -> Self {
-                    Self:: #contract_name (a)
-                }
-            }
-
-            #(
-            impl #bracketed_wrapper_generics From<<#contract as #modules_names ::sv::InterfaceMessagesApi>:: #enum_accessor>
-                for #contract_enum_name #bracketed_wrapper_generics #full_where_clause {
-                fn from(a: <#contract as #modules_names ::sv::InterfaceMessagesApi>:: #enum_accessor ) -> Self {
-                    Self:: #variants_names (a)
-                }
-            }
-            )*
-        }
-    }
-}
-
-pub struct ContractApi<'a> {
-    source: &'a ItemImpl,
-    exec_variants: MsgVariants<'a, GenericParam>,
-    query_variants: MsgVariants<'a, GenericParam>,
-    instantiate_variants: MsgVariants<'a, GenericParam>,
-    migrate_variants: MsgVariants<'a, GenericParam>,
-    sudo_variants: MsgVariants<'a, GenericParam>,
-    generics: &'a [&'a GenericParam],
-    custom: &'a Custom,
-}
-
-impl<'a> ContractApi<'a> {
-    pub fn new(source: &'a ItemImpl, generics: &'a [&'a GenericParam], custom: &'a Custom) -> Self {
-        let exec_variants = MsgVariants::new(
-            source.as_variants(),
-            MsgType::Exec,
-            generics,
-            &source.generics.where_clause,
-        );
-
-        let query_variants = MsgVariants::new(
-            source.as_variants(),
-            MsgType::Query,
-            generics,
-            &source.generics.where_clause,
-        );
-
-        let instantiate_variants = MsgVariants::new(
-            source.as_variants(),
-            MsgType::Instantiate,
-            generics,
-            &source.generics.where_clause,
-        );
-
-        let migrate_variants = MsgVariants::new(
-            source.as_variants(),
-            MsgType::Migrate,
-            generics,
-            &source.generics.where_clause,
-        );
-
-        let sudo_variants = MsgVariants::new(
-            source.as_variants(),
-            MsgType::Sudo,
-            generics,
-            &source.generics.where_clause,
-        );
-
-        Self {
-            source,
-            exec_variants,
-            query_variants,
-            instantiate_variants,
-            migrate_variants,
-            sudo_variants,
-            generics,
-            custom,
-        }
-    }
-
-    pub fn emit(&self) -> TokenStream {
-        let sylvia = crate_module();
-        let Self {
-            source,
-            exec_variants,
-            query_variants,
-            instantiate_variants,
-            migrate_variants,
-            sudo_variants,
-            generics,
-            custom,
-            ..
-        } = self;
-
-        let where_clause = &source.generics.where_clause;
-        let contract_name = &source.self_ty;
-        let exec_generics = &exec_variants.used_generics;
-        let query_generics = &query_variants.used_generics;
-        let instantiate_generics = &instantiate_variants.used_generics;
-        let migrate_generics = &migrate_variants.used_generics;
-        let sudo_generics = &sudo_variants.used_generics;
-
-        let bracket_generics = emit_bracketed_generics(generics);
-        let exec_bracketed_generics = emit_bracketed_generics(exec_generics);
-        let query_bracketed_generics = emit_bracketed_generics(query_generics);
-        let sudo_bracketed_generics = emit_bracketed_generics(sudo_generics);
-        let instantiate_bracketed_generics = emit_bracketed_generics(instantiate_generics);
-        let migrate_bracketed_generics = emit_bracketed_generics(migrate_generics);
-
-        let migrate_type = if migrate_variants.variants().count() != 0 {
-            quote! { type Migrate = MigrateMsg #migrate_bracketed_generics; }
-        } else {
-            quote! { type Migrate = #sylvia ::cw_std::Empty; }
-        };
-        let custom_msg = custom.msg_or_default();
-        let custom_query = custom.query_or_default();
-
-        quote! {
-            impl #bracket_generics #sylvia ::types::ContractApi for #contract_name #where_clause {
-                type ContractExec = ContractExecMsg #bracket_generics;
-                type ContractQuery = ContractQueryMsg #bracket_generics;
-                type ContractSudo = ContractSudoMsg #bracket_generics;
-                type Exec = ExecMsg #exec_bracketed_generics;
-                type Query = QueryMsg #query_bracketed_generics;
-                type Sudo = SudoMsg #sudo_bracketed_generics;
-                type Instantiate = InstantiateMsg #instantiate_bracketed_generics;
-                #migrate_type
-                type Remote<'remote> = #sylvia ::types::Remote<'remote, Self >;
-                type Querier<'querier> = #sylvia ::types::BoundQuerier<'querier, #custom_query, Self >;
-                type CustomMsg = #custom_msg;
-                type CustomQuery = #custom_query;
-            }
-        }
-    }
-}
-
-pub struct InterfaceApi<'a> {
-    source: &'a ItemTrait,
-    custom: &'a Custom,
-    associated_types: &'a AssociatedTypes<'a>,
-}
-
-impl<'a> InterfaceApi<'a> {
-    pub fn new(
-        source: &'a ItemTrait,
-        associated_types: &'a AssociatedTypes<'a>,
-        custom: &'a Custom,
-    ) -> Self {
-        Self {
-            source,
-            custom,
-            associated_types,
-        }
-    }
-
-    pub fn emit(&self) -> TokenStream {
-        let sylvia = crate_module();
-        let Self {
-            source,
-            custom,
-            associated_types,
-        } = self;
-
-        let interface_name = &source.ident;
-        let generics: Vec<_> = associated_types
-            .without_special()
-            .map(ItemType::as_name)
-            .collect();
-        let exec_variants = MsgVariants::new(
-            source.as_variants(),
-            MsgType::Exec,
-            &generics,
-            &source.generics.where_clause,
-        );
-        let query_variants = MsgVariants::new(
-            source.as_variants(),
-            MsgType::Query,
-            &generics,
-            &source.generics.where_clause,
-        );
-        let sudo_variants = MsgVariants::new(
-            source.as_variants(),
-            MsgType::Sudo,
-            &generics,
-            &source.generics.where_clause,
-        );
-
-        let where_clause = &self.associated_types.as_where_clause();
-        let custom_query = custom.query_or_default();
-        let exec_generics = &exec_variants.used_generics;
-        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 >;
-            }
-
-
-            pub struct Api < #(#generics,)* > {
-                #phantom
-            }
-
-            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 >;
-            }
-        }
-    }
-}
-
-pub struct EntryPoints<'a> {
-    source: &'a ItemImpl,
-    name: Type,
-    error: Type,
-    reply: Option<Ident>,
-    override_entry_points: Vec<OverrideEntryPoint>,
-    generics: Vec<&'a GenericParam>,
-    where_clause: &'a Option<WhereClause>,
-    attrs: &'a EntryPointArgs,
-}
-
-impl<'a> EntryPoints<'a> {
-    pub fn new(source: &'a ItemImpl, attrs: &'a EntryPointArgs) -> Self {
-        let name = StripGenerics.fold_type(*source.self_ty.clone());
-        let parsed_attrs = ParsedSylviaAttributes::new(source.attrs.iter());
-        let override_entry_points = parsed_attrs.override_entry_point_attrs;
-
-        let error = parsed_attrs.error_attrs.unwrap_or_default().error;
-
-        let generics: Vec<_> = source.generics.params.iter().collect();
-        let where_clause = &source.generics.where_clause;
-
-        let reply =
-            MsgVariants::<GenericParam>::new(source.as_variants(), MsgType::Reply, &[], &None)
-                .variants()
-                .map(|variant| variant.function_name.clone())
-                .next();
-
-        Self {
-            source,
-            name,
-            error,
-            reply,
-            override_entry_points,
-            generics,
-            where_clause,
-            attrs,
-        }
-    }
-
-    pub fn emit(&self) -> TokenStream {
-        let Self {
-            source,
-            reply,
-            override_entry_points,
-            generics,
-            where_clause,
-            ..
-        } = self;
-
-        let entry_points = [
-            MsgType::Instantiate,
-            MsgType::Exec,
-            MsgType::Query,
-            MsgType::Sudo,
-        ]
-        .into_iter()
-        .map(
-            |msg_ty| match override_entry_points.get_entry_point(msg_ty) {
-                Some(_) => quote! {},
-                None => self.emit_default_entry_point(msg_ty),
-            },
-        );
-
-        let is_migrate = MsgVariants::new(
-            source.as_variants(),
-            MsgType::Migrate,
-            generics,
-            where_clause,
-        )
-        .get_only_variant()
-        .is_some();
-
-        let migrate_not_overridden = override_entry_points
-            .get_entry_point(MsgType::Migrate)
-            .is_none();
-
-        let migrate = if migrate_not_overridden && is_migrate {
-            self.emit_default_entry_point(MsgType::Migrate)
-        } else {
-            quote! {}
-        };
-
-        let reply_ep = override_entry_points
-            .get_entry_point(MsgType::Reply)
-            .map(|_| quote! {})
-            .unwrap_or_else(|| {
-                if reply.is_some() {
-                    self.emit_default_entry_point(MsgType::Reply)
-                } else {
-                    quote! {}
-                }
-            });
-
-        quote! {
-            pub mod entry_points {
-                use super::*;
-
-                #(#entry_points)*
-
-                #migrate
-
-                #reply_ep
-            }
-        }
-    }
-
-    pub fn emit_default_entry_point(&self, msg_ty: MsgType) -> TokenStream {
-        let Self {
-            name,
-            error,
-            attrs,
-            reply,
-            ..
-        } = self;
-        let sylvia = crate_module();
-
-        let attr_generics = &attrs.generics;
-        let (contract, contract_turbo) = if attr_generics.is_empty() {
-            (quote! { #name }, quote! { #name })
-        } else {
-            (
-                quote! { #name < #attr_generics > },
-                quote! { #name :: < #attr_generics > },
-            )
-        };
-
-        let custom_msg: Type =
-            parse_quote! { < #contract as #sylvia ::types::ContractApi > :: CustomMsg };
-        let custom_query: Type =
-            parse_quote! { < #contract as #sylvia ::types::ContractApi > :: CustomQuery };
-
-        let result = msg_ty.emit_result_type(&custom_msg, error);
-        let params = msg_ty.emit_ctx_params(&custom_query);
-        let values = msg_ty.emit_ctx_values();
-        let ep_name = msg_ty.emit_ep_name();
-        let associated_name = msg_ty.as_accessor_wrapper_name();
-        let msg = match msg_ty {
-            MsgType::Reply => quote! { msg: #sylvia ::cw_std::Reply },
-            _ => quote! { msg: < #contract as #sylvia ::types::ContractApi> :: #associated_name },
-        };
-        let dispatch = match msg_ty {
-            MsgType::Reply => quote! {
-                #contract_turbo ::new(). #reply((deps, env).into(), msg).map_err(Into::into)
-            },
-            _ => quote! {
-                msg.dispatch(& #contract_turbo ::new() , ( #values )).map_err(Into::into)
-            },
-        };
-
-        quote! {
-            #[#sylvia ::cw_std::entry_point]
-            pub fn #ep_name (
-                #params ,
-                #msg
-            ) -> #result {
-                #dispatch
-            }
-        }
-    }
-}
diff --git a/sylvia-derive/src/parser/attributes/messages.rs b/sylvia-derive/src/parser/attributes/messages.rs
index 138f9e0..e770821 100644
--- a/sylvia-derive/src/parser/attributes/messages.rs
+++ b/sylvia-derive/src/parser/attributes/messages.rs
@@ -7,7 +7,7 @@ use syn::{parenthesized, Error, Ident, MetaList, Path, Result, Token};
 
 use proc_macro_error::emit_error;
 
-use crate::strip_generics::StripGenerics;
+use crate::fold::StripGenerics;
 
 #[derive(Debug)]
 pub struct ContractMessageAttr {
diff --git a/sylvia-derive/src/check_generics.rs b/sylvia-derive/src/parser/check_generics.rs
similarity index 100%
rename from sylvia-derive/src/check_generics.rs
rename to sylvia-derive/src/parser/check_generics.rs
diff --git a/sylvia-derive/src/parser/interface.rs b/sylvia-derive/src/parser/interface.rs
new file mode 100644
index 0000000..f17cad0
--- /dev/null
+++ b/sylvia-derive/src/parser/interface.rs
@@ -0,0 +1,198 @@
+use communication::api::Api;
+use communication::enum_msg::EnumMessage;
+use communication::executor::Executor;
+use communication::querier::Querier;
+use mt::MtHelpers;
+use proc_macro2::TokenStream;
+use proc_macro_error::{emit_error, emit_warning};
+use quote::quote;
+use syn::{Ident, ItemTrait, TraitItem};
+
+use crate::parser::attributes::msg::MsgType;
+use crate::parser::variant_descs::AsVariantDescs;
+use crate::parser::{Custom, ParsedSylviaAttributes};
+use crate::types::associated_types::{AssociatedTypes, ItemType, EXEC_TYPE, QUERY_TYPE};
+use crate::types::msg_variant::MsgVariants;
+
+mod communication;
+mod mt;
+
+/// Preprocessed `interface` macro input
+pub struct InterfaceInput<'a> {
+    item: &'a ItemTrait,
+    custom: Custom,
+    associated_types: AssociatedTypes<'a>,
+}
+
+impl<'a> InterfaceInput<'a> {
+    pub fn new(item: &'a ItemTrait) -> Self {
+        if !item.generics.params.is_empty() {
+            emit_error!(
+                item.ident.span(), "Generics on traits are not supported. Use associated types instead.";
+                note = "Sylvia interfaces can be implemented only a single time per contract.";
+            );
+        }
+
+        if !item
+            .items
+            .iter()
+            .any(|item| matches!(item, TraitItem::Type(ty) if ty.ident == Ident::new("Error", ty.ident.span())))
+        {
+            emit_error!(
+                item.ident.span(), "Missing `Error` type defined for trait.";
+                note = "Error is an error type returned by generated types dispatch function. Messages handling function have to return an error type convertible to this Error type.";
+                note = "A trait error type should be bound to implement `From<cosmwasm_std::StdError>`.";
+            );
+        }
+
+        let custom = ParsedSylviaAttributes::new(item.attrs.iter())
+            .custom_attr
+            .unwrap_or_default();
+        let associated_types = AssociatedTypes::new(item);
+
+        if custom.msg.is_none()
+            && !associated_types
+                .all_names()
+                .any(|assoc_type| assoc_type == EXEC_TYPE)
+        {
+            emit_warning!(
+                item.ident.span(), "Missing both `{}` type and `#[sv::custom(msg=...)]` defined for the trait.", EXEC_TYPE;
+                note = "Implicitly it means that the trait could not be implemented for contracts that use CustomMsg different than `cosmwasm_std::Empty`";
+                note = "If this behaviour is intended, please add `#[sv::custom(msg=sylvia::cw_std::Empty]` attribute.";
+            );
+        }
+
+        if custom.query.is_none()
+            && !associated_types
+                .all_names()
+                .any(|assoc_type| assoc_type == QUERY_TYPE)
+        {
+            emit_warning!(
+                item.ident.span(), "Missing both `{}` type and `#[sv::custom(query=...)]` defined for the trait.", QUERY_TYPE;
+                note = "Implicitly it means that the trait could not be implemented for contracts that use CustomQuery different than `cosmwasm_std::Empty`";
+                note = "If this behaviour is intended, please add `#[sv::custom(query=sylvia::cw_std::Empty]` attribute.";
+            );
+        }
+
+        Self {
+            item,
+            custom,
+            associated_types,
+        }
+    }
+
+    pub fn process(&self) -> TokenStream {
+        let Self {
+            associated_types,
+            item,
+            custom,
+        } = self;
+        let messages = self.emit_messages();
+        let associated_names: Vec<_> = associated_types.as_filtered_names().collect();
+
+        let executor_variants =
+            MsgVariants::new(item.as_variants(), MsgType::Exec, &associated_names, &None);
+        let query_variants =
+            MsgVariants::new(item.as_variants(), MsgType::Query, &associated_names, &None);
+        let executor =
+            Executor::new(&executor_variants, associated_types, &item.ident).emit_executor_trait();
+        let querier =
+            Querier::new(&query_variants, associated_types, &item.ident).emit_querier_trait();
+
+        let interface_messages = Api::new(item, associated_types, custom).emit();
+
+        let multitest_helpers = self.emit_multitest_helpers();
+
+        quote! {
+            pub mod sv {
+                use super::*;
+                #messages
+
+                #querier
+
+                #executor
+
+                #interface_messages
+
+                #multitest_helpers
+            }
+        }
+    }
+
+    fn emit_messages(&self) -> TokenStream {
+        let exec = self.emit_msg(MsgType::Exec);
+        let query = self.emit_msg(MsgType::Query);
+        let sudo = self.emit_msg(MsgType::Sudo);
+
+        let instantiate = MsgVariants::new(
+            self.item.as_variants(),
+            MsgType::Instantiate,
+            &[] as &[&Ident],
+            &None,
+        );
+
+        if let Some(msg_variant) = instantiate.variants().next() {
+            emit_error!(
+                msg_variant.name().span(), "The message attribute `instantiate` is not supported in interfaces.";
+                note = "Contracts need to implement `instantiate` method within their `impl` block.";
+            );
+        }
+
+        let migrate = MsgVariants::new(
+            self.item.as_variants(),
+            MsgType::Migrate,
+            &[] as &[&Ident],
+            &None,
+        );
+
+        if let Some(msg_variant) = migrate.variants().next() {
+            emit_error!(
+                msg_variant.name().span(), "The message attribute `migrate` is not supported in interfaces";
+                note = "Contracts need to implement `migrate` method within their `impl` block.";
+            );
+        }
+
+        quote! {
+            #exec
+
+            #query
+
+            #sudo
+        }
+    }
+
+    fn emit_msg(&self, msg_ty: MsgType) -> TokenStream {
+        let where_clause = &self.associated_types.as_where_clause();
+        let associated_names: Vec<_> = self
+            .associated_types
+            .without_error()
+            .map(ItemType::as_name)
+            .collect();
+        let variants = MsgVariants::new(
+            self.item.as_variants(),
+            msg_ty,
+            &associated_names,
+            where_clause,
+        );
+
+        EnumMessage::new(
+            self.item,
+            msg_ty,
+            &self.custom,
+            variants,
+            &self.associated_types,
+        )
+        .emit()
+    }
+
+    fn emit_multitest_helpers(&self) -> TokenStream {
+        if !cfg!(feature = "mt") {
+            return quote! {};
+        }
+
+        let Self { item, .. } = self;
+        let associated_types = &self.associated_types;
+
+        MtHelpers::new(item, associated_types).emit()
+    }
+}
diff --git a/sylvia-derive/src/parser/mod.rs b/sylvia-derive/src/parser/mod.rs
index 329e9f6..6500207 100644
--- a/sylvia-derive/src/parser/mod.rs
+++ b/sylvia-derive/src/parser/mod.rs
@@ -1,5 +1,7 @@
 pub mod attributes;
+pub mod check_generics;
 pub mod entry_point;
+pub mod variant_descs;
 
 pub use attributes::{
     ContractErrorAttr, ContractMessageAttr, Custom, Customs, FilteredOverrideEntryPoints, MsgAttr,
diff --git a/sylvia-derive/src/variant_descs.rs b/sylvia-derive/src/parser/variant_descs.rs
similarity index 100%
rename from sylvia-derive/src/variant_descs.rs
rename to sylvia-derive/src/parser/variant_descs.rs
diff --git a/sylvia-derive/src/strip_generics.rs b/sylvia-derive/src/strip_generics.rs
deleted file mode 100644
index 7681d51..0000000
--- a/sylvia-derive/src/strip_generics.rs
+++ /dev/null
@@ -1,10 +0,0 @@
-use syn::fold::Fold;
-
-/// Removes all generics from type assumning default values for it
-pub struct StripGenerics;
-
-impl Fold for StripGenerics {
-    fn fold_path_arguments(&mut self, _: syn::PathArguments) -> syn::PathArguments {
-        syn::PathArguments::None
-    }
-}
diff --git a/sylvia-derive/src/strip_self_path.rs b/sylvia-derive/src/strip_self_path.rs
deleted file mode 100644
index 93657ce..0000000
--- a/sylvia-derive/src/strip_self_path.rs
+++ /dev/null
@@ -1,14 +0,0 @@
-use syn::fold::Fold;
-use syn::Path;
-pub struct StripSelfPath;
-
-impl Fold for StripSelfPath {
-    fn fold_path(&mut self, path: Path) -> Path {
-        let segments = path
-            .segments
-            .into_iter()
-            .filter(|segment| segment.ident != "Self")
-            .collect();
-        syn::fold::fold_path(self, Path { segments, ..path })
-    }
-}
diff --git a/sylvia-derive/src/associated_types.rs b/sylvia-derive/src/types/associated_types.rs
similarity index 100%
rename from sylvia-derive/src/associated_types.rs
rename to sylvia-derive/src/types/associated_types.rs
diff --git a/sylvia-derive/src/interfaces.rs b/sylvia-derive/src/types/interfaces.rs
similarity index 100%
rename from sylvia-derive/src/interfaces.rs
rename to sylvia-derive/src/types/interfaces.rs
diff --git a/sylvia-derive/src/types/mod.rs b/sylvia-derive/src/types/mod.rs
new file mode 100644
index 0000000..a9d0650
--- /dev/null
+++ b/sylvia-derive/src/types/mod.rs
@@ -0,0 +1,5 @@
+pub mod associated_types;
+pub mod interfaces;
+pub mod msg_field;
+pub mod msg_type;
+pub mod msg_variant;
diff --git a/sylvia-derive/src/types/msg_field.rs b/sylvia-derive/src/types/msg_field.rs
new file mode 100644
index 0000000..14f26de
--- /dev/null
+++ b/sylvia-derive/src/types/msg_field.rs
@@ -0,0 +1,118 @@
+use crate::fold::StripSelfPath;
+use crate::parser::check_generics::{CheckGenerics, GetPath};
+use proc_macro2::TokenStream;
+use proc_macro_error::emit_error;
+use quote::quote;
+use syn::fold::Fold;
+use syn::spanned::Spanned;
+use syn::visit::Visit;
+use syn::{Attribute, Ident, Pat, PatType, Type};
+
+/// Representation of single message variant field
+#[derive(Debug)]
+pub struct MsgField<'a> {
+    name: &'a Ident,
+    ty: &'a Type,
+    stripped_ty: Type,
+    attrs: &'a Vec<Attribute>,
+}
+
+impl<'a> MsgField<'a> {
+    /// Creates new field from trait method argument
+    pub fn new<Generic>(
+        item: &'a PatType,
+        generics_checker: &mut CheckGenerics<Generic>,
+    ) -> Option<MsgField<'a>>
+    where
+        Generic: GetPath + PartialEq,
+    {
+        let name = match &*item.pat {
+            Pat::Ident(p) => Some(&p.ident),
+            pat => {
+                // TODO: Support pattern arguments, when decorated with argument with item
+                // name
+                //
+                // Eg.
+                //
+                // ```
+                // fn exec_foo(&self, ctx: Ctx, #[sv::msg(name=metadata)] SomeData { addr, sender }: SomeData);
+                // ```
+                //
+                // should expand to enum variant:
+                //
+                // ```
+                // ExecFoo {
+                //   metadata: SomeDaa
+                // }
+                // ```
+                emit_error!(pat.span(), "Expected argument name, pattern occurred");
+                None
+            }
+        }?;
+
+        let ty = &item.ty;
+        let stripped_ty = StripSelfPath.fold_type((*item.ty).clone());
+        let attrs = &item.attrs;
+        generics_checker.visit_type(&stripped_ty);
+
+        Some(Self {
+            name,
+            ty,
+            stripped_ty,
+            attrs,
+        })
+    }
+
+    /// Emits message field
+    pub fn emit(&self) -> TokenStream {
+        let Self {
+            name,
+            stripped_ty,
+            attrs,
+            ..
+        } = self;
+
+        quote! {
+            #(#attrs)*
+            #name: #stripped_ty
+        }
+    }
+
+    /// Emits struct field
+    pub fn emit_pub(&self) -> TokenStream {
+        let Self {
+            name,
+            stripped_ty,
+            attrs,
+            ..
+        } = self;
+
+        quote! {
+            #(#attrs)*
+            pub #name: #stripped_ty
+        }
+    }
+
+    /// Emits method field
+    pub fn emit_method_field(&self) -> TokenStream {
+        let Self {
+            name, stripped_ty, ..
+        } = self;
+
+        quote! {
+            #name: #stripped_ty
+        }
+    }
+
+    pub fn emit_method_field_folded(&self) -> TokenStream {
+        let Self { name, ty, .. } = self;
+
+        quote! {
+            #name: #ty
+        }
+    }
+
+    pub fn name(&self) -> &'a Ident {
+        self.name
+    }
+}
diff --git a/sylvia-derive/src/message_type.rs b/sylvia-derive/src/types/msg_type.rs
similarity index 99%
rename from sylvia-derive/src/message_type.rs
rename to sylvia-derive/src/types/msg_type.rs
index a80f006..a2c0d49 100644
--- a/sylvia-derive/src/message_type.rs
+++ b/sylvia-derive/src/types/msg_type.rs
@@ -5,9 +5,9 @@ use syn::fold::Fold;
 use syn::{parse_quote, GenericParam, Ident, Type};
 
 use crate::crate_module;
+use crate::fold::StripSelfPath;
 use crate::parser::attributes::msg::MsgType;
 use crate::parser::Customs;
-use crate::strip_self_path::StripSelfPath;
 
 impl MsgType {
     pub fn emit_ctx_type(self, query_type: &Type) -> TokenStream {
diff --git a/sylvia-derive/src/types/msg_variant.rs b/sylvia-derive/src/types/msg_variant.rs
new file mode 100644
index 0000000..c8a106f
--- /dev/null
+++ b/sylvia-derive/src/types/msg_variant.rs
@@ -0,0 +1,309 @@
+use crate::crate_module;
+use crate::fold::StripSelfPath;
+use crate::parser::attributes::VariantAttrForwarding;
+use crate::parser::check_generics::{CheckGenerics, GetPath};
+use crate::parser::variant_descs::VariantDescs;
+use crate::parser::{MsgAttr, MsgType};
+use crate::utils::{extract_return_type, filter_wheres, process_fields, SvCasing};
+use convert_case::{Case, Casing};
+use proc_macro2::TokenStream;
+use quote::{quote, ToTokens};
+use syn::fold::Fold;
+use syn::visit::Visit;
+use syn::{parse_quote, Ident, Signature, Type, WhereClause, WherePredicate};
+
+use super::msg_field::MsgField;
+
+/// Representation of whole message variant
+#[derive(Debug)]
+pub struct MsgVariant<'a> {
+    name: Ident,
+    function_name: &'a Ident,
+    fields: Vec<MsgField<'a>>,
+    /// Type extracted only in case of `Query` and used in `cosmwasm_schema::QueryResponses`
+    /// `returns` attribute.
+    return_type: Option<Type>,
+    msg_type: MsgType,
+    attrs_to_forward: Vec<VariantAttrForwarding>,
+}
+
+impl<'a> MsgVariant<'a> {
+    /// Creates new message variant from trait method
+    pub fn new<Generic>(
+        sig: &'a Signature,
+        generics_checker: &mut CheckGenerics<Generic>,
+        msg_attr: MsgAttr,
+        attrs_to_forward: Vec<VariantAttrForwarding>,
+    ) -> MsgVariant<'a>
+    where
+        Generic: GetPath + PartialEq,
+    {
+        let function_name = &sig.ident;
+
+        let name = function_name.to_case(Case::UpperCamel);
+        let fields = process_fields(sig, generics_checker);
+        let msg_type = msg_attr.msg_type();
+
+        let return_type = if let MsgAttr::Query { resp_type, .. } = msg_attr {
+            match resp_type {
+                Some(resp_type) => {
+                    let resp_type = parse_quote! { #resp_type };
+                    generics_checker.visit_type(&resp_type);
+                    Some(resp_type)
+                }
+                None => {
+                    let return_type = extract_return_type(&sig.output);
+                    let stripped_return_type = StripSelfPath.fold_path(return_type.clone());
+                    generics_checker.visit_path(&stripped_return_type);
+                    Some(parse_quote! { #return_type })
+                }
+            }
+        } else {
+            None
+        };
+
+        Self {
+            name,
+            function_name,
+            fields,
+            return_type,
+            msg_type,
+            attrs_to_forward,
+        }
+    }
+
+    /// Emits message variant
+    pub fn emit(&self) -> TokenStream {
+        let Self {
+            name,
+            fields,
+            msg_type,
+            return_type,
+            attrs_to_forward,
+            ..
+        } = self;
+        let fields = fields.iter().map(MsgField::emit);
+        let returns_attribute = msg_type.emit_returns_attribute(return_type);
+        let attrs_to_forward = attrs_to_forward.iter().map(|attr| &attr.attrs);
+
+        quote! {
+            #returns_attribute
+            #( #[ #attrs_to_forward ] )*
+            #name {
+                #(#fields,)*
+            }
+        }
+    }
+
+    /// Emits match leg dispatching against this variant. Assumes enum variants are imported into the
+    /// scope. Dispatching is performed by calling the function this variant is build from on the
+    /// `contract` variable, with `ctx` as its first argument - both of them should be in scope.
+    pub fn emit_dispatch_leg(&self) -> TokenStream {
+        let Self {
+            name,
+            fields,
+            function_name,
+            msg_type,
+            ..
+        } = self;
+
+        let args: Vec<_> = fields
+            .iter()
+            .zip(1..)
+            .map(|(field, num)| Ident::new(&format!("field{}", num), field.name().span()))
+            .collect();
+
+        let fields = fields
+            .iter()
+            .map(MsgField::name)
+            .zip(args.clone())
+            .map(|(field, num_field)| quote!(#field : #num_field));
+
+        let method_call = msg_type.emit_dispatch_leg(function_name, &args);
+
+        quote! {
+            #name {
+                #(#fields,)*
+            } => #method_call
+        }
+    }
+
+    /// Emits variants constructors. Constructors names are variants names in snake_case.
+    pub fn emit_variants_constructors(&self) -> TokenStream {
+        let Self { name, fields, .. } = self;
+
+        let method_name = name.to_case(Case::Snake);
+        let parameters = fields.iter().map(MsgField::emit_method_field);
+        let arguments = fields.iter().map(MsgField::name);
+
+        quote! {
+            pub fn #method_name( #(#parameters),*) -> Self {
+                Self :: #name { #(#arguments),* }
+            }
+        }
+    }
+
+    pub fn as_fields_names(&self) -> Vec<&Ident> {
+        self.fields.iter().map(MsgField::name).collect()
+    }
+
+    pub fn emit_method_field(&self) -> Vec<TokenStream> {
+        self.fields
+            .iter()
+            .map(MsgField::emit_method_field)
+            .collect()
+    }
+
+    pub fn name(&self) -> &Ident {
+        &self.name
+    }
+
+    pub fn function_name(&self) -> &Ident {
+        self.function_name
+    }
+
+    pub fn fields(&self) -> &Vec<MsgField> {
+        &self.fields
+    }
+
+    pub fn msg_type(&self) -> &MsgType {
+        &self.msg_type
+    }
+
+    pub fn return_type(&self) -> &Option<Type> {
+        &self.return_type
+    }
+}
+
+#[derive(Debug)]
+pub struct MsgVariants<'a, Generic> {
+    variants: Vec<MsgVariant<'a>>,
+    used_generics: Vec<&'a Generic>,
+    unused_generics: Vec<&'a Generic>,
+    where_predicates: Vec<&'a WherePredicate>,
+    msg_ty: MsgType,
+}
+
+impl<'a, Generic> MsgVariants<'a, Generic>
+where
+    Generic: GetPath + PartialEq + ToTokens,
+{
+    pub fn new(
+        source: VariantDescs<'a>,
+        msg_ty: MsgType,
+        all_generics: &'a [&'a Generic],
+        unfiltered_where_clause: &'a Option<WhereClause>,
+    ) -> Self {
+        let mut generics_checker = CheckGenerics::new(all_generics);
+        let variants: Vec<_> = source
+            .filter_map(|variant_desc| {
+                let msg_attr: MsgAttr = variant_desc.attr_msg()?;
+                let attrs_to_forward = variant_desc.attrs_to_forward();
+
+                if msg_attr.msg_type() != msg_ty {
+                    return None;
+                }
+
+                Some(MsgVariant::new(
+                    variant_desc.into_sig(),
+                    &mut generics_checker,
+                    msg_attr,
+                    attrs_to_forward,
+                ))
+            })
+            .collect();
+
+        let (used_generics, unused_generics) = generics_checker.used_unused();
+        let where_predicates = filter_wheres(unfiltered_where_clause, all_generics, &used_generics);
+
+        Self {
+            variants,
+            used_generics,
+            unused_generics,
+            where_predicates,
+            msg_ty,
+        }
+    }
+
+    pub fn where_clause(&self) -> Option<WhereClause> {
+        let where_predicates = &self.where_predicates;
+        if !where_predicates.is_empty() {
+            Some(parse_quote! { where #(#where_predicates),* })
+        } else {
+            None
+        }
+    }
+
+    pub fn variants(&self) -> impl Iterator<Item = &MsgVariant> {
+        self.variants.iter()
+    }
+
+    pub fn used_generics(&self) -> &Vec<&'a Generic> {
+        &self.used_generics
+    }
+
+    pub fn unused_generics(&self) -> &Vec<&'a Generic> {
+        &self.unused_generics
+    }
+
+    pub fn emit_phantom_match_arm(&self) -> TokenStream {
+        let sylvia = crate_module();
+        let Self { used_generics, .. } = self;
+        if used_generics.is_empty() {
+            return quote! {};
+        }
+        quote! {
+            _Phantom(_) => Err(#sylvia ::cw_std::StdError::generic_err("Phantom message should not be constructed.")).map_err(Into::into),
+        }
+    }
+
+    pub fn emit_dispatch_legs(&self) -> impl Iterator<Item = TokenStream> + '_ {
+        self.variants
+            .iter()
+            .map(|variant| variant.emit_dispatch_leg())
+    }
+
+    pub fn as_names_snake_cased(&self) -> Vec<String> {
+        self.variants
+            .iter()
+            .map(|variant| variant.name.to_string().to_case(Case::Snake))
+            .collect()
+    }
+
+    pub fn emit_constructors(&self) -> impl Iterator<Item = TokenStream> + '_ {
+        self.variants
+            .iter()
+            .map(MsgVariant::emit_variants_constructors)
+    }
+
+    pub fn emit(&self) -> impl Iterator<Item = TokenStream> + '_ {
+        self.variants.iter().map(MsgVariant::emit)
+    }
+
+    pub fn get_only_variant(&self) -> Option<&MsgVariant> {
+        self.variants.first()
+    }
+
+    pub fn emit_phantom_variant(&self) -> TokenStream {
+        let Self {
+            msg_ty,
+            used_generics,
+            ..
+        } = self;
+
+        if used_generics.is_empty() {
+            return quote! {};
+        }
+
+        let return_attr = match msg_ty {
+            MsgType::Query => quote! { #[returns((#(#used_generics,)*))] },
+            _ => quote! {},
+        };
+
+        quote! {
+            #[serde(skip)]
+            #return_attr
+            _Phantom(std::marker::PhantomData<( #(#used_generics,)* )>),
+        }
+    }
+}
diff --git a/sylvia-derive/src/utils.rs b/sylvia-derive/src/utils.rs
index c15b9a2..3fa5a19 100644
--- a/sylvia-derive/src/utils.rs
+++ b/sylvia-derive/src/utils.rs
@@ -9,8 +9,8 @@ use syn::{
     WhereClause, WherePredicate,
 };
 
-use crate::check_generics::{CheckGenerics, GetPath};
-use crate::message::MsgField;
+use crate::parser::check_generics::{CheckGenerics, GetPath};
+use crate::types::msg_field::MsgField;
 
 pub fn filter_wheres<'a, Generic: GetPath + PartialEq>(
     clause: &'a Option<WhereClause>,


Test patch:
diff --git a/sylvia-derive/src/multitest.rs b/sylvia-derive/src/contract/mt.rs
similarity index 80%
rename from sylvia-derive/src/multitest.rs
rename to sylvia-derive/src/contract/mt.rs
index 2440513..4d374c2 100644
--- a/sylvia-derive/src/multitest.rs
+++ b/sylvia-derive/src/contract/mt.rs
@@ -1,17 +1,16 @@
 use convert_case::Case;
 use proc_macro2::{Ident, TokenStream};
 use quote::quote;
-use syn::{parse_quote, GenericParam, ItemImpl, ItemTrait, TraitItem, Type};
+use syn::{parse_quote, GenericParam, ItemImpl, Type};
 
-use crate::associated_types::AssociatedTypes;
 use crate::crate_module;
-use crate::message::{MsgVariant, MsgVariants};
 use crate::parser::attributes::msg::MsgType;
+use crate::parser::variant_descs::AsVariantDescs;
 use crate::parser::{
     Custom, FilteredOverrideEntryPoints, OverrideEntryPoint, ParsedSylviaAttributes,
 };
+use crate::types::msg_variant::{MsgVariant, MsgVariants};
 use crate::utils::{emit_bracketed_generics, SvCasing};
-use crate::variant_descs::AsVariantDescs;
 
 fn get_ident_from_type(contract_name: &Type) -> &Ident {
     let Type::Path(type_path) = contract_name else {
@@ -23,7 +22,7 @@ fn get_ident_from_type(contract_name: &Type) -> &Ident {
     &segment.ident
 }
 
-pub struct ContractMtHelpers<'a> {
+pub struct MtHelpers<'a> {
     error_type: Type,
     contract_name: &'a Type,
     source: &'a ItemImpl,
@@ -39,7 +38,7 @@ pub struct ContractMtHelpers<'a> {
     sudo_variants: MsgVariants<'a, GenericParam>,
 }
 
-impl<'a> ContractMtHelpers<'a> {
+impl<'a> MtHelpers<'a> {
     pub fn new(
         source: &'a ItemImpl,
         generic_params: &'a [&'a GenericParam],
@@ -607,165 +606,6 @@ impl<'a> ContractMtHelpers<'a> {
     }
 }
 
-pub struct TraitMtHelpers<'a> {
-    source: &'a ItemTrait,
-    error_type: Type,
-    associated_types: &'a AssociatedTypes<'a>,
-    exec_variants: MsgVariants<'a, GenericParam>,
-    query_variants: MsgVariants<'a, GenericParam>,
-    sudo_variants: MsgVariants<'a, GenericParam>,
-    where_clause: &'a Option<syn::WhereClause>,
-}
-
-impl<'a> TraitMtHelpers<'a> {
-    pub fn new(source: &'a ItemTrait, associated_types: &'a AssociatedTypes) -> Self {
-        let where_clause = &source.generics.where_clause;
-        let exec_variants =
-            MsgVariants::new(source.as_variants(), MsgType::Exec, &[], where_clause);
-        let query_variants =
-            MsgVariants::new(source.as_variants(), MsgType::Query, &[], where_clause);
-        let sudo_variants =
-            MsgVariants::new(source.as_variants(), MsgType::Sudo, &[], where_clause);
-        let associated_error = source.items.iter().find_map(|item| match item {
-            TraitItem::Type(ty) if ty.ident == "Error" => Some(&ty.ident),
-            _ => None,
-        });
-        let error_type: Type = match associated_error {
-            Some(error) => parse_quote!(#error),
-            // This should never happen as the `interface` macro requires the trait to have an associated `Error` type
-            None => unreachable!(),
-        };
-
-        Self {
-            error_type,
-            source,
-            associated_types,
-            where_clause,
-            exec_variants,
-            query_variants,
-            sudo_variants,
-        }
-    }
-
-    pub fn emit(&self) -> TokenStream {
-        let Self {
-            error_type,
-            source,
-            associated_types,
-            where_clause,
-            exec_variants,
-            query_variants,
-            sudo_variants,
-        } = self;
-
-        let sylvia = crate_module();
-
-        let interface_name = &source.ident;
-        let trait_name = Ident::new(&format!("{}Proxy", interface_name), interface_name.span());
-
-        let custom_msg: Type = parse_quote! { CustomMsgT };
-        let prefixed_error_type: Type = parse_quote! { Self:: #error_type };
-
-        let mt_app = parse_quote! {
-            #sylvia ::cw_multi_test::App<
-                BankT,
-                ApiT,
-                StorageT,
-                CustomT,
-                WasmT,
-                StakingT,
-                DistrT,
-                IbcT,
-                GovT,
-            >
-        };
-
-        let associated_args: Vec<_> = associated_types
-            .without_error()
-            .map(|associated| &associated.ident)
-            .collect();
-
-        let associated_args_for_api: Vec<_> = associated_types
-            .without_special()
-            .map(|associated| {
-                let assoc = &associated.ident;
-                quote! { Self:: #assoc }
-            })
-            .collect();
-
-        let bracketed_generics = emit_bracketed_generics(&associated_args_for_api);
-        let api = quote! { < Api #bracketed_generics as #sylvia ::types::InterfaceApi> };
-
-        let associated_types_declaration = associated_types.without_error();
-
-        let exec_methods = exec_variants.variants().map(|variant| {
-            variant.emit_mt_method_definition(&custom_msg, &mt_app, &prefixed_error_type, &api)
-        });
-        let query_methods = query_variants.variants().map(|variant| {
-            variant.emit_mt_method_definition(&custom_msg, &mt_app, &prefixed_error_type, &api)
-        });
-        let sudo_methods = sudo_variants.variants().map(|variant| {
-            variant.emit_mt_method_definition(&custom_msg, &mt_app, &prefixed_error_type, &api)
-        });
-
-        let exec_methods_declarations = exec_variants.variants().map(|variant| {
-            variant.emit_mt_method_declaration(&custom_msg, &prefixed_error_type, &api)
-        });
-        let query_methods_declarations = query_variants.variants().map(|variant| {
-            variant.emit_mt_method_declaration(&custom_msg, &prefixed_error_type, &api)
-        });
-        let sudo_methods_declarations = sudo_variants.variants().map(|variant| {
-            variant.emit_mt_method_declaration(&custom_msg, &prefixed_error_type, &api)
-        });
-
-        let where_predicates = where_clause
-            .as_ref()
-            .map(|where_clause| &where_clause.predicates);
-
-        quote! {
-            pub mod mt {
-                use super::*;
-
-                pub trait #trait_name <MtApp, #custom_msg > #where_clause {
-                    type #error_type: std::fmt::Debug + std::fmt::Display + Send + Sync + 'static;
-                    #(#associated_types_declaration)*
-
-                    #(#query_methods_declarations)*
-                    #(#exec_methods_declarations)*
-                    #(#sudo_methods_declarations)*
-                }
-
-                impl<BankT, ApiT, StorageT, CustomT, WasmT, StakingT, DistrT, IbcT, GovT, #custom_msg, ContractT: super:: #interface_name > #trait_name < #mt_app, #custom_msg > for #sylvia ::multitest::Proxy<'_, #mt_app, ContractT >
-                where
-                    ContractT:: #error_type : std::fmt::Debug + std::fmt::Display + Send + Sync + 'static,
-                    #custom_msg: #sylvia ::types::CustomMsg + 'static,
-                    CustomT: #sylvia ::cw_multi_test::Module,
-                    WasmT: #sylvia ::cw_multi_test::Wasm<CustomT::ExecT, CustomT::QueryT>,
-                    BankT: #sylvia ::cw_multi_test::Bank,
-                    ApiT: #sylvia ::cw_std::Api,
-                    StorageT: #sylvia ::cw_std::Storage,
-                    CustomT: #sylvia ::cw_multi_test::Module,
-                    StakingT: #sylvia ::cw_multi_test::Staking,
-                    DistrT: #sylvia ::cw_multi_test::Distribution,
-                    IbcT: #sylvia ::cw_multi_test::Ibc,
-                    GovT: #sylvia ::cw_multi_test::Gov,
-                    CustomT::ExecT: #sylvia ::types::CustomMsg + 'static,
-                    CustomT::QueryT: #sylvia:: types::CustomQuery + 'static,
-                    #mt_app : #sylvia ::cw_multi_test::Executor< #custom_msg >,
-                    #where_predicates
-                {
-                    type #error_type = <ContractT as super:: #interface_name>:: #error_type ;
-                    #(type #associated_args = <ContractT as super:: #interface_name>:: #associated_args ;)*
-
-                    #(#query_methods)*
-                    #(#exec_methods)*
-                    #(#sudo_methods)*
-                }
-            }
-        }
-    }
-}
-
 fn emit_default_dispatch(msg_ty: &MsgType, contract_name: &Type) -> TokenStream {
     let sylvia = crate_module();