Repository: CosmWasm/sylvia
Pull request #310 (2024-02-23 11:43:19)

feat: Add support for `#[sv::]` attributes for all sylvia attribtues.
This PR adds the requirement for `sv::` prefix for all attributes handled by sylvia. Attributes wihtout `sv::` prefix are not supported and are not handled by the macro.

Other than that, this change also introduces refactoring commits - the parser has been split into a multi-file module, and the interface has been unified.

codecov[bot]: ## [Codecov](https://app.codecov.io/gh/CosmWasm/sylvia/pull/310?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 `70.00000%` with `9 lines` in your changes are missing coverage. Please review.
> Project coverage is 86.65%. Comparing base [(`a555c24`)](https://app.codecov.io/gh/CosmWasm/sylvia/commit/a555c24fc53869332d80af7f02dfec2c8e2f40f3?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=CosmWasm) to head [(`69f668c`)](https://app.codecov.io/gh/CosmWasm/sylvia/pull/310?src=pr&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/310?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/parser.rs](https://app.codecov.io/gh/CosmWasm/sylvia/pull/310?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=CosmWasm#diff-c3lsdmlhLWRlcml2ZS9zcmMvcGFyc2VyLnJz) | 75.00% | [6 Missing :warning: ](https://app.codecov.io/gh/CosmWasm/sylvia/pull/310?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=CosmWasm) |
| [sylvia-derive/src/interfaces.rs](https://app.codecov.io/gh/CosmWasm/sylvia/pull/310?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=CosmWasm#diff-c3lsdmlhLWRlcml2ZS9zcmMvaW50ZXJmYWNlcy5ycw==) | 33.33% | [2 Missing :warning: ](https://app.codecov.io/gh/CosmWasm/sylvia/pull/310?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=CosmWasm) |
| [sylvia-derive/src/message.rs](https://app.codecov.io/gh/CosmWasm/sylvia/pull/310?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=CosmWasm#diff-c3lsdmlhLWRlcml2ZS9zcmMvbWVzc2FnZS5ycw==) | 0.00% | [1 Missing :warning: ](https://app.codecov.io/gh/CosmWasm/sylvia/pull/310?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             @@
##             main     #310      +/-   ##
==========================================
- Coverage   86.66%   86.65%   -0.02%     
==========================================
  Files          28       28              
  Lines        2055     2060       +5     
==========================================
+ Hits         1781     1785       +4     
- Misses        274      275       +1     
```



</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/CosmWasm/sylvia/pull/310?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/CHANGELOG.md b/CHANGELOG.md
index 6b41078..be3f257 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -84,12 +84,12 @@ and this project adheres to
 
 ## [0.4.2] - 2023-05-24
 
-- Added support of `#[msg(reply)]` defining handler for reply messages,
+- Added support of `#[sv::msg(reply)]` defining handler for reply messages,
   currently only in the form of
   `fn reply(&self, _ctx: ReplyCtx, _msg: Reply) -> Result<Response, Err>`
-- Added generation of reply entrypoint forwarding to the `#[msg(reply)]`
+- Added generation of reply entrypoint forwarding to the `#[sv::msg(reply)]`
   handler
-- Added generation of reply implementation forwarding to `#[msg(reply)]`
+- Added generation of reply implementation forwarding to `#[sv::msg(reply)]`
   handler in multitest helpers
 
 ## [0.4.1] - 2023-05-23
@@ -127,7 +127,7 @@ and this project adheres to
 
 - Fix: Generate Migrate as struct
 - Cw20 implementation in sylvia
-- Removed `#[msg(reply)]`
+- Removed `#[sv::msg(reply)]`
 
 ## [0.2.1] - 2022-10-19
 
diff --git a/README.md b/README.md
index 3e13ba1..8fc6694 100644
--- a/README.md
+++ b/README.md
@@ -105,7 +105,7 @@ use sylvia::cw_std::{StdResult, Response};
 
 #[contract]
 impl MyContract {
-    #[msg(instantiate)]
+    #[sv::msg(instantiate)]
     pub fn instantiate(&self, _ctx: InstantiateCtx) -> StdResult<Response> {
         Ok(Response::new())
     }
@@ -132,7 +132,7 @@ use sylvia::cw_std::{StdResult, Response};
 #[entry_points]
 #[contract]
 impl MyContract {
-    #[msg(instantiate)]
+    #[sv::msg(instantiate)]
     pub fn instantiate(&self, _ctx: InstantiateCtx) -> StdResult<Response> {
         Ok(Response::new())
     }
@@ -179,7 +179,7 @@ impl MyContract<'_> {
         }
     }
 
-    #[msg(instantiate)]
+    #[sv::msg(instantiate)]
     pub fn instantiate(&self, ctx: InstantiateCtx) -> StdResult<Response> {
         self.counter.save(ctx.deps.storage, &0)?;
 
@@ -201,7 +201,7 @@ Now let's pass the initial counter state as a function argument:
 ```rust
 #[contract]
 impl MyContract<'_> {
-    #[msg(instantiate)]
+    #[sv::msg(instantiate)]
     pub fn instantiate(&self, ctx: InstantiateCtx, counter: u64) -> StdResult<Response> {
         self.counter.save(ctx.deps.storage, &counter)?;
 
@@ -226,7 +226,7 @@ Now let's add an execution message to the contract:
 ```rust
 #[contract]
 impl MyContract<'_> {
-    #[msg(exec)]
+    #[sv::msg(exec)]
     pub fn increment(&self, ctx: ExecCtx) -> StdResult<Response> {
         let counter = self.counter.load(ctx.deps.storage)?;
         self.counter.save(ctx.deps.storage, &(counter + 1))?;
@@ -261,9 +261,9 @@ it is very easy to do:
 use sylvia::cw_std::ensure;
 
 #[contract]
-#[error(ContractError)]
+#[sv::error(ContractError)]
 impl MyContract<'_> {
-    #[msg(exec)]
+    #[sv::msg(exec)]
     pub fn increment(&self, ctx: ExecCtx) -> Result<Response, ContractError> {
         let counter = self.counter.load(ctx.deps.storage)?;
 
@@ -291,9 +291,9 @@ pub struct CounterResp {
 }
 
 #[contract]
-#[error(ContractError)]
+#[sv::error(ContractError)]
 impl MyContract<'_> {
-    #[msg(query)]
+    #[sv::msg(query)]
     pub fn counter(&self, ctx: QueryCtx) -> StdResult<CounterResp> {
         self
             .counter
@@ -333,10 +333,10 @@ pub mod group {
     pub trait Group {
         type Error: From<StdError>;
 
-        #[msg(exec)]
+        #[sv::msg(exec)]
         fn add_member(&self, ctx: ExecCtx, member: String) -> Result<Response, Self::Error>;
 
-        #[msg(query)]
+        #[sv::msg(query)]
         fn is_member(&self, ctx: QueryCtx, member: String) -> Result<IsMemberResp, Self::Error>;
     }
 }
@@ -355,23 +355,23 @@ pub struct MyContract<'a> {
 }
 
 #[contract]
-#[messages(group as Group)]
+#[sv::messages(group as Group)]
 // Alternatively:
 // It's not needed to provide the interface's
 // name if it corresponds to the last segment
 // of the module path:
-// #[messages(group)]
+// #[sv::messages(group)]
 impl group::Group for MyContract<'_> {
     type Error = ContractError;
 
-    #[msg(exec)]
+    #[sv::msg(exec)]
     fn add_member(&self, ctx: ExecCtx, member: String) -> Result<Response, ContractError> {
         let member = ctx.deps.api.addr_validate(&member)?;
         self.members.save(ctx.deps.storage, &member, &Empty {})?;
         Ok(Response::new())
     }
 
-    #[msg(query)]
+    #[sv::msg(query)]
     fn is_member(&self, ctx: QueryCtx, member: String) -> Result<group::IsMemberResp, ContractError> {
         let is_member = self.members.has(ctx.deps.storage, &Addr::unchecked(&member));
         let resp = group::IsMemberResp {
@@ -383,7 +383,7 @@ impl group::Group for MyContract<'_> {
 }
 
 #[contract]
-#[messages(group as Group)]
+#[sv::messages(group as Group)]
 impl MyContract<'_> {
     // Nothing changed here
 }
@@ -398,7 +398,7 @@ in its own `cross_staking` module (note the underscore). This is a requirement r
 now - Sylvia generates all the messages and boilerplate in this module and will try
 to access them through this module. If the interface's name is a camel-case
 version of the last module path's segment, the `as InterfaceName` can be omitted.
-F.e. `#[messages(cw1 as Cw1)]` can be reduced to `#[messages(cw1)]`
+F.e. `#[sv::messages(cw1 as Cw1)]` can be reduced to `#[sv::messages(cw1)]`
 
 
 Then there is the `Error` type embedded in the trait - it is also needed there,
@@ -406,20 +406,20 @@ and the trait bound here has to be at least `From<StdError>`, as Sylvia might
 generate code returning an `StdError` in deserialization/dispatching implementation.
 The trait can be more strict - this is the minimum.
 
-Another thing to remember is that the `#[msg(...)]` attributes become part of the
+Another thing to remember is that the `#[sv::msg(...)]` attributes become part of the
 function signature - they must be the same for the trait and later implementation.
 
 Finally, every implementation block has an additional
-`#[messages(module as Identifier)]` attribute. Sylvia needs it to generate the dispatching
+`#[sv::messages(module as Identifier)]` attribute. Sylvia needs it to generate the dispatching
 properly - there is the limitation that every macro has access only to its local
 scope. In particular - we cannot see all traits implemented by a type and their
 implementation from the `#[contract]` crate.
 
-To solve this issue, we put this `#[messages(...)]` attribute pointing to Sylvia
+To solve this issue, we put this `#[sv::messages(...)]` attribute pointing to Sylvia
 what is the module name where the interface is defined, and giving a unique name
 for this interface (it would be used in generated code to provide proper enum variant).
 
-The impl-block with trait implementation also contains the `#[messages]` attribute,
+The impl-block with trait implementation also contains the `#[sv::messages]` attribute,
 but only one - the one with info about the trait being implemented.
 
 ## Macro attributes
@@ -440,7 +440,7 @@ scope this attribute can and should be omitted.
 ```rust
 #[entry_point]
 #[contract]
-#[error(ContractError)]
+#[sv::error(ContractError)]
 impl MyContract {
 ...
 }
@@ -451,13 +451,13 @@ error is being used by your contract. If omitted generated code will use `StdErr
 
 ```rust
 #[contract]
-#[messages(interface as Interface)]
+#[sv::messages(interface as Interface)]
 impl MyContract {
 ...
 }
 
 #[contract]
-#[messages(interface as Interface)]
+#[sv::messages(interface as Interface)]
 impl Interface for MyContract {
 ...
 }
@@ -614,7 +614,7 @@ pub struct MyContract<'a> {
     remote: Item<'a, Remote<'static>>,
 }
 
-#[msg(exec)]
+#[sv::msg(exec)]
 pub fn evaluate_member(&self, ctx: ExecCtx, ...) -> StdResult<Response> {
     let is_member = self
         .remote
@@ -647,8 +647,8 @@ use sylvia::cw_std::{DepsMut, Env, Reply, Response};
 
 #[contract]
 #[entry_point]
-#[error(ContractError)]
-#[messages(group as Group)]
+#[sv::error(ContractError)]
+#[sv::messages(group as Group)]
 impl MyContract<'_> {
     fn reply(&self, deps: DepsMut, env: Env, reply: Reply) -> Result<Response, ContractError> {
         todo!()
@@ -932,7 +932,7 @@ impl AssociatedInterface for crate::MyContract {
     type ExecC = MyMsg;
     type QueryC = MyQuery;
 
-    #[msg(exec)]
+    #[sv::msg(exec)]
     fn associated_exec(&self, _ctx: ExecCtx<Self::QueryC>) -> StdResult<Response<Self::ExecC>> {
         Ok(Response::default())
     }
@@ -965,14 +965,14 @@ pub trait Generic
     type QueryParam: CustomMsg;
     type RetType: CustomMsg;
 
-    #[msg(exec)]
+    #[sv::msg(exec)]
     fn generic_exec(
         &self,
         ctx: ExecCtx,
         msgs: Vec<CosmosMsg<Self::ExecParam>>,
     ) -> Result<Response, Self::Error>;
 
-    #[msg(query)]
+    #[sv::msg(query)]
     fn generic_query(&self, ctx: QueryCtx, param: Self::QueryParam) -> Result<Self::RetType, Self::Error>;
 }
 ```
@@ -1012,7 +1012,7 @@ where
         }
     }
 
-    #[msg(instantiate)]
+    #[sv::msg(instantiate)]
     pub fn instantiate(
         &self,
         _ctx: InstantiateCtx,
@@ -1021,7 +1021,7 @@ where
         Ok(Response::new())
     }
 
-    #[msg(exec)]
+    #[sv::msg(exec)]
     pub fn contract_execute(
         &self,
         _ctx: ExecCtx,
@@ -1039,7 +1039,7 @@ We can either use some concrete types here or forward the generics defined on co
 
 ```rust
 #[contract(module = crate::contract)]
-#[messages(generic as Generic)]
+#[sv::messages(generic as Generic)]
 #[sv::custom(msg=SvCustomMsg)]
 impl<InstantiateParam, ExecParam, FieldType>
     Generic
@@ -1054,7 +1054,7 @@ impl<InstantiateParam, ExecParam, FieldType>
     type QueryParam: SvCustomMsg;
     type RetType = SvCustomMsg;
 
-    #[msg(exec)]
+    #[sv::msg(exec)]
     fn generic_exec(
         &self,
         _ctx: ExecCtx,
@@ -1063,7 +1063,7 @@ impl<InstantiateParam, ExecParam, FieldType>
         Ok(Response::new())
     }
 
-    #[msg(query)]
+    #[sv::msg(query)]
     fn generic_query(
         &self,
         _ctx: QueryCtx,
@@ -1079,7 +1079,7 @@ interface in the main `contract` macro call:
 
 ```rust
 #[contract]
-#[messages(generic<ExecParam, SvCustomMsg, SvCustomMsg> as Generic)]
+#[sv::messages(generic<ExecParam, SvCustomMsg, SvCustomMsg> as Generic)]
 impl<InstantiateParam, ExecParam, FieldType>
     GenericContract<InstantiateParam, ExecParam, FieldType>
 where
diff --git a/examples/contracts/custom/src/contract.rs b/examples/contracts/custom/src/contract.rs
index 4890aa2..55a16d6 100644
--- a/examples/contracts/custom/src/contract.rs
+++ b/examples/contracts/custom/src/contract.rs
@@ -14,7 +14,7 @@ pub struct CustomContract {
 
 #[cfg_attr(not(feature = "library"), entry_points)]
 #[contract]
-#[messages(cw1 as Cw1: custom(msg, query))]
+#[sv::messages(cw1 as Cw1: custom(msg, query))]
 #[sv::custom(query=CounterQuery, msg=CounterMsg)]
 impl CustomContract {
     pub const fn new() -> Self {
@@ -23,7 +23,7 @@ impl CustomContract {
         }
     }
 
-    #[msg(instantiate)]
+    #[sv::msg(instantiate)]
     pub fn instantiate(
         &self,
         ctx: InstantiateCtx<CounterQuery>,
@@ -32,14 +32,14 @@ impl CustomContract {
         Ok(Response::default())
     }
 
-    #[msg(exec)]
+    #[sv::msg(exec)]
     pub fn send_custom(&self, _ctx: ExecCtx<CounterQuery>) -> StdResult<Response<CounterMsg>> {
         let msg = CosmosMsg::Custom(CounterMsg::Increment {});
         let resp = Response::default().add_message(msg);
         Ok(resp)
     }
 
-    #[msg(query)]
+    #[sv::msg(query)]
     pub fn query_custom(&self, ctx: QueryCtx<CounterQuery>) -> StdResult<CountResponse> {
         let resp = ctx
             .deps
@@ -49,14 +49,14 @@ impl CustomContract {
         Ok(resp)
     }
 
-    #[msg(query)]
+    #[sv::msg(query)]
     pub fn sudo_counter(&self, ctx: QueryCtx<CounterQuery>) -> StdResult<CountResponse> {
         let count = self.sudo_counter.load(ctx.deps.storage)?;
 
         Ok(CountResponse { count })
     }
 
-    #[msg(sudo)]
+    #[sv::msg(sudo)]
     pub fn increment_sudo_counter(
         &self,
         ctx: SudoCtx<CounterQuery>,
diff --git a/examples/contracts/custom/src/cw1.rs b/examples/contracts/custom/src/cw1.rs
index a7abbda..4a82f94 100644
--- a/examples/contracts/custom/src/cw1.rs
+++ b/examples/contracts/custom/src/cw1.rs
@@ -7,17 +7,17 @@ use sylvia::types::{ExecCtx, QueryCtx};
 use crate::contract::CustomContract;
 
 #[contract(module=crate::contract)]
-#[messages(cw1 as Cw1)]
+#[sv::messages(cw1 as Cw1)]
 #[sv::custom(query=CounterQuery, msg=CounterMsg)]
 impl Cw1 for CustomContract {
     type Error = StdError;
 
-    #[msg(exec)]
+    #[sv::msg(exec)]
     fn execute(&self, _ctx: ExecCtx, _msgs: Vec<CosmosMsg>) -> StdResult<Response> {
         Ok(Response::new())
     }
 
-    #[msg(query)]
+    #[sv::msg(query)]
     fn can_execute(
         &self,
         _ctx: QueryCtx,
diff --git a/examples/contracts/cw1-subkeys/src/contract.rs b/examples/contracts/cw1-subkeys/src/contract.rs
index 5bd9b49..4e7d8fc 100644
--- a/examples/contracts/cw1-subkeys/src/contract.rs
+++ b/examples/contracts/cw1-subkeys/src/contract.rs
@@ -33,9 +33,9 @@ pub struct Cw1SubkeysContract<'a> {
 
 #[cfg_attr(not(feature = "library"), entry_points)]
 #[contract]
-#[error(ContractError)]
-#[messages(cw1 as Cw1)]
-#[messages(whitelist as Whitelist)]
+#[sv::error(ContractError)]
+#[sv::messages(cw1 as Cw1)]
+#[sv::messages(whitelist as Whitelist)]
 impl Cw1SubkeysContract<'_> {
     pub const fn new() -> Self {
         Self {
@@ -45,7 +45,7 @@ impl Cw1SubkeysContract<'_> {
         }
     }
 
-    #[msg(instantiate)]
+    #[sv::msg(instantiate)]
     pub fn instantiate(
         &self,
         mut ctx: InstantiateCtx,
@@ -57,7 +57,7 @@ impl Cw1SubkeysContract<'_> {
         Ok(result)
     }
 
-    #[msg(exec)]
+    #[sv::msg(exec)]
     pub fn increase_allowance(
         &self,
         ctx: ExecCtx,
@@ -107,7 +107,7 @@ impl Cw1SubkeysContract<'_> {
         Ok(res)
     }
 
-    #[msg(exec)]
+    #[sv::msg(exec)]
     pub fn decrease_allowance(
         &self,
         ctx: ExecCtx,
@@ -158,7 +158,7 @@ impl Cw1SubkeysContract<'_> {
         Ok(res)
     }
 
-    #[msg(exec)]
+    #[sv::msg(exec)]
     pub fn set_permissions(
         &self,
         ctx: ExecCtx,
@@ -183,7 +183,7 @@ impl Cw1SubkeysContract<'_> {
         Ok(res)
     }
 
-    #[msg(query)]
+    #[sv::msg(query)]
     pub fn allowance(&self, ctx: QueryCtx, spender: String) -> StdResult<Allowance> {
         // we can use unchecked here as it is a query - bad value means a miss, we never write it
         let spender = Addr::unchecked(spender);
@@ -196,7 +196,7 @@ impl Cw1SubkeysContract<'_> {
         Ok(allow)
     }
 
-    #[msg(query)]
+    #[sv::msg(query)]
     pub fn permissions(&self, ctx: QueryCtx, spender: String) -> StdResult<Permissions> {
         let spender = Addr::unchecked(spender);
         let permissions = self
@@ -207,7 +207,7 @@ impl Cw1SubkeysContract<'_> {
         Ok(permissions)
     }
 
-    #[msg(query)]
+    #[sv::msg(query)]
     pub fn all_allowances(
         &self,
         ctx: QueryCtx,
@@ -243,7 +243,7 @@ impl Cw1SubkeysContract<'_> {
         })
     }
 
-    #[msg(query)]
+    #[sv::msg(query)]
     pub fn all_permissions(
         &self,
         ctx: QueryCtx,
diff --git a/examples/contracts/cw1-subkeys/src/cw1.rs b/examples/contracts/cw1-subkeys/src/cw1.rs
index 9e217aa..7ce96fd 100644
--- a/examples/contracts/cw1-subkeys/src/cw1.rs
+++ b/examples/contracts/cw1-subkeys/src/cw1.rs
@@ -7,11 +7,11 @@ use crate::contract::Cw1SubkeysContract;
 use crate::error::ContractError;
 
 #[contract(module=crate::contract)]
-#[messages(cw1 as Cw1)]
+#[sv::messages(cw1 as Cw1)]
 impl Cw1 for Cw1SubkeysContract<'_> {
     type Error = ContractError;
 
-    #[msg(exec)]
+    #[sv::msg(exec)]
     fn execute(
         &self,
         ctx: ExecCtx,
@@ -30,7 +30,7 @@ impl Cw1 for Cw1SubkeysContract<'_> {
         Ok(res)
     }
 
-    #[msg(query)]
+    #[sv::msg(query)]
     fn can_execute(
         &self,
         ctx: QueryCtx,
diff --git a/examples/contracts/cw1-subkeys/src/whitelist.rs b/examples/contracts/cw1-subkeys/src/whitelist.rs
index eb29e84..3c96592 100644
--- a/examples/contracts/cw1-subkeys/src/whitelist.rs
+++ b/examples/contracts/cw1-subkeys/src/whitelist.rs
@@ -10,23 +10,23 @@ use crate::error::ContractError;
 // This can be skipped by tarpaulin as it's covered in cw1-whitelist
 #[cfg(not(tarpaulin_include))]
 #[contract(module=crate::contract)]
-#[messages(whitelist as Whitelist)]
+#[sv::messages(whitelist as Whitelist)]
 impl Whitelist for Cw1SubkeysContract<'_> {
     type Error = ContractError;
 
-    #[msg(exec)]
+    #[sv::msg(exec)]
     fn freeze(&self, ctx: ExecCtx) -> Result<Response, Self::Error> {
         self.whitelist.freeze(ctx).map_err(From::from)
     }
 
-    #[msg(exec)]
+    #[sv::msg(exec)]
     fn update_admins(&self, ctx: ExecCtx, admins: Vec<String>) -> Result<Response, Self::Error> {
         self.whitelist
             .update_admins(ctx, admins)
             .map_err(From::from)
     }
 
-    #[msg(query)]
+    #[sv::msg(query)]
     fn admin_list(&self, ctx: QueryCtx) -> StdResult<AdminListResponse> {
         self.whitelist.admin_list(ctx)
     }
diff --git a/examples/contracts/cw1-whitelist/src/contract.rs b/examples/contracts/cw1-whitelist/src/contract.rs
index 78baf56..1d11375 100644
--- a/examples/contracts/cw1-whitelist/src/contract.rs
+++ b/examples/contracts/cw1-whitelist/src/contract.rs
@@ -19,9 +19,9 @@ pub struct Cw1WhitelistContract<'a> {
 
 #[cfg_attr(not(feature = "library"), entry_points)]
 #[contract]
-#[error(ContractError)]
-#[messages(cw1 as Cw1)]
-#[messages(whitelist as Whitelist)]
+#[sv::error(ContractError)]
+#[sv::messages(cw1 as Cw1)]
+#[sv::messages(whitelist as Whitelist)]
 impl Cw1WhitelistContract<'_> {
     pub const fn new() -> Self {
         Self {
@@ -29,7 +29,7 @@ impl Cw1WhitelistContract<'_> {
             mutable: Item::new("mutable"),
         }
     }
-    #[msg(instantiate)]
+    #[sv::msg(instantiate)]
     pub fn instantiate(
         &self,
         ctx: InstantiateCtx,
diff --git a/examples/contracts/cw1-whitelist/src/cw1.rs b/examples/contracts/cw1-whitelist/src/cw1.rs
index ba00b58..b8f3a3a 100644
--- a/examples/contracts/cw1-whitelist/src/cw1.rs
+++ b/examples/contracts/cw1-whitelist/src/cw1.rs
@@ -7,11 +7,11 @@ use crate::contract::Cw1WhitelistContract;
 use crate::error::ContractError;
 
 #[contract(module=crate::contract)]
-#[messages(cw1 as Cw1)]
+#[sv::messages(cw1 as Cw1)]
 impl Cw1 for Cw1WhitelistContract<'_> {
     type Error = ContractError;
 
-    #[msg(exec)]
+    #[sv::msg(exec)]
     fn execute(&self, ctx: ExecCtx, msgs: Vec<CosmosMsg>) -> Result<Response, ContractError> {
         if !self.is_admin(ctx.deps.as_ref(), &ctx.info.sender) {
             return Err(ContractError::Unauthorized);
@@ -23,7 +23,7 @@ impl Cw1 for Cw1WhitelistContract<'_> {
         Ok(resp)
     }
 
-    #[msg(query)]
+    #[sv::msg(query)]
     fn can_execute(
         &self,
         ctx: QueryCtx,
diff --git a/examples/contracts/cw1-whitelist/src/whitelist.rs b/examples/contracts/cw1-whitelist/src/whitelist.rs
index 156a4af..5080755 100644
--- a/examples/contracts/cw1-whitelist/src/whitelist.rs
+++ b/examples/contracts/cw1-whitelist/src/whitelist.rs
@@ -8,11 +8,11 @@ use crate::contract::Cw1WhitelistContract;
 use crate::error::ContractError;
 
 #[contract(module=crate::contract)]
-#[messages(whitelist as Whitelist)]
+#[sv::messages(whitelist as Whitelist)]
 impl Whitelist for Cw1WhitelistContract<'_> {
     type Error = ContractError;
 
-    #[msg(exec)]
+    #[sv::msg(exec)]
     fn freeze(&self, ctx: ExecCtx) -> Result<Response, ContractError> {
         if !self.is_admin(ctx.deps.as_ref(), &ctx.info.sender) {
             return Err(ContractError::Unauthorized);
@@ -24,7 +24,7 @@ impl Whitelist for Cw1WhitelistContract<'_> {
         Ok(resp)
     }
 
-    #[msg(exec)]
+    #[sv::msg(exec)]
     fn update_admins(
         &self,
         ctx: ExecCtx,
@@ -84,7 +84,7 @@ impl Whitelist for Cw1WhitelistContract<'_> {
         Ok(resp)
     }
 
-    #[msg(query)]
+    #[sv::msg(query)]
     fn admin_list(&self, ctx: QueryCtx) -> StdResult<AdminListResponse> {
         let admins: Result<_, _> = self
             .admins
diff --git a/examples/contracts/cw20-base/src/allowances.rs b/examples/contracts/cw20-base/src/allowances.rs
index d73d244..be4c98d 100644
--- a/examples/contracts/cw20-base/src/allowances.rs
+++ b/examples/contracts/cw20-base/src/allowances.rs
@@ -18,13 +18,13 @@ const MAX_LIMIT: u32 = 30;
 const DEFAULT_LIMIT: u32 = 10;
 
 #[contract(module=crate::contract)]
-#[messages(cw20_allowances as Cw20Allowances)]
+#[sv::messages(cw20_allowances as Cw20Allowances)]
 impl Cw20Allowances for Cw20Base<'_> {
     type Error = ContractError;
 
     /// Allows spender to access an additional amount tokens from the owner's (env.sender) account.
     /// If expires is Some(), overwrites current allowance expiration with this one.
-    #[msg(exec)]
+    #[sv::msg(exec)]
     fn increase_allowance(
         &self,
         ctx: ExecCtx,
@@ -69,7 +69,7 @@ impl Cw20Allowances for Cw20Base<'_> {
 
     /// Lowers the spender's access of tokens from the owner's (env.sender) account by amount.
     /// If expires is Some(), overwrites current allowance expiration with this one.
-    #[msg(exec)]
+    #[sv::msg(exec)]
     fn decrease_allowance(
         &self,
         ctx: ExecCtx,
@@ -119,7 +119,7 @@ impl Cw20Allowances for Cw20Base<'_> {
 
     /// Transfers amount tokens from owner -> recipient
     /// if `env.sender` has sufficient pre-approval.
-    #[msg(exec)]
+    #[sv::msg(exec)]
     fn transfer_from(
         &self,
         ctx: ExecCtx,
@@ -176,7 +176,7 @@ impl Cw20Allowances for Cw20Base<'_> {
 
     /// Sends amount tokens from owner -> contract
     /// if `env.sender` has sufficient pre-approval.
-    #[msg(exec)]
+    #[sv::msg(exec)]
     fn send_from(
         &self,
         ctx: ExecCtx,
@@ -231,7 +231,7 @@ impl Cw20Allowances for Cw20Base<'_> {
     }
 
     /// Destroys amount of tokens forever
-    #[msg(exec)]
+    #[sv::msg(exec)]
     fn burn_from(
         &self,
         ctx: ExecCtx,
@@ -273,7 +273,7 @@ impl Cw20Allowances for Cw20Base<'_> {
     }
 
     /// Returns how much spender can use from owner account, 0 if unset.
-    #[msg(query)]
+    #[sv::msg(query)]
     fn allowance(
         &self,
         ctx: QueryCtx,
@@ -290,7 +290,7 @@ impl Cw20Allowances for Cw20Base<'_> {
     }
 
     /// Returns all allowances this owner has approved. Supports pagination.
-    #[msg(query)]
+    #[sv::msg(query)]
     fn all_allowances(
         &self,
         ctx: QueryCtx,
@@ -319,7 +319,7 @@ impl Cw20Allowances for Cw20Base<'_> {
     }
 
     /// Returns all allowances this spender has been granted. Supports pagination.
-    #[msg(query)]
+    #[sv::msg(query)]
     fn all_spender_allowances(
         &self,
         ctx: QueryCtx,
@@ -349,7 +349,7 @@ impl Cw20Allowances for Cw20Base<'_> {
     }
 
     /// Returns all allowances this spender has been granted. Supports pagination.
-    #[msg(query)]
+    #[sv::msg(query)]
     fn all_accounts(
         &self,
         ctx: QueryCtx,
diff --git a/examples/contracts/cw20-base/src/contract.rs b/examples/contracts/cw20-base/src/contract.rs
index 03668bc..bf974f0 100644
--- a/examples/contracts/cw20-base/src/contract.rs
+++ b/examples/contracts/cw20-base/src/contract.rs
@@ -74,10 +74,10 @@ pub struct Cw20Base<'a> {
 
 #[cfg_attr(not(feature = "library"), entry_points)]
 #[contract]
-#[error(ContractError)]
-#[messages(cw20_allowances as Allowances)]
-#[messages(cw20_marketing as Marketing)]
-#[messages(cw20_minting as Minting)]
+#[sv::error(ContractError)]
+#[sv::messages(cw20_allowances as Allowances)]
+#[sv::messages(cw20_marketing as Marketing)]
+#[sv::messages(cw20_minting as Minting)]
 impl Cw20Base<'_> {
     pub const fn new() -> Self {
         Self {
@@ -137,7 +137,7 @@ impl Cw20Base<'_> {
             .update(storage, (spender, owner), update_fn)
     }
 
-    #[msg(instantiate)]
+    #[sv::msg(instantiate)]
     pub fn instantiate(
         &self,
         mut ctx: InstantiateCtx,
@@ -212,7 +212,7 @@ impl Cw20Base<'_> {
     }
 
     /// Transfer is a base message to move tokens to another account without triggering actions
-    #[msg(exec)]
+    #[sv::msg(exec)]
     fn transfer(
         &self,
         ctx: ExecCtx,
@@ -241,7 +241,7 @@ impl Cw20Base<'_> {
     }
 
     /// Burn is a base message to destroy tokens forever
-    #[msg(exec)]
+    #[sv::msg(exec)]
     fn burn(&self, ctx: ExecCtx, amount: Uint128) -> Result<Response, ContractError> {
         ensure!(amount != Uint128::zero(), ContractError::InvalidZeroAmount);
 
@@ -266,7 +266,7 @@ impl Cw20Base<'_> {
 
     /// Send is a base message to transfer tokens to a contract and trigger an action
     /// on the receiving contract.
-    #[msg(exec)]
+    #[sv::msg(exec)]
     fn send(
         &self,
         ctx: ExecCtx,
@@ -305,7 +305,7 @@ impl Cw20Base<'_> {
     }
 
     /// Returns the current balance of the given address, 0 if unset.
-    #[msg(query)]
+    #[sv::msg(query)]
     fn balance(&self, ctx: QueryCtx, address: String) -> StdResult<BalanceResponse> {
         let address = ctx.deps.api.addr_validate(&address)?;
         let balance = self
@@ -316,7 +316,7 @@ impl Cw20Base<'_> {
     }
 
     /// Returns metadata on the contract - name, decimals, supply, etc.
-    #[msg(query)]
+    #[sv::msg(query)]
     fn token_info(&self, ctx: QueryCtx) -> StdResult<TokenInfoResponse> {
         let info = self.token_info.load(ctx.deps.storage)?;
         let res = TokenInfoResponse {
@@ -328,7 +328,7 @@ impl Cw20Base<'_> {
         Ok(res)
     }
 
-    #[msg(migrate)]
+    #[sv::msg(migrate)]
     fn migrate(&self, ctx: MigrateCtx) -> Result<Response, ContractError> {
         let original_version =
             ensure_from_older_version(ctx.deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?;
diff --git a/examples/contracts/cw20-base/src/marketing.rs b/examples/contracts/cw20-base/src/marketing.rs
index e71ad09..b0b6880 100644
--- a/examples/contracts/cw20-base/src/marketing.rs
+++ b/examples/contracts/cw20-base/src/marketing.rs
@@ -8,11 +8,11 @@ use sylvia::contract;
 use sylvia::types::{ExecCtx, QueryCtx};
 
 #[contract(module=crate::contract)]
-#[messages(cw20_marketing as Cw20Marketing)]
+#[sv::messages(cw20_marketing as Cw20Marketing)]
 impl Cw20Marketing for Cw20Base<'_> {
     type Error = ContractError;
 
-    #[msg(exec)]
+    #[sv::msg(exec)]
     fn update_marketing(
         &self,
         ctx: ExecCtx,
@@ -69,7 +69,7 @@ impl Cw20Marketing for Cw20Base<'_> {
         Ok(res)
     }
 
-    #[msg(exec)]
+    #[sv::msg(exec)]
     fn upload_logo(&self, ctx: ExecCtx, logo: Logo) -> Result<Response, Self::Error> {
         let mut marketing_info = self
             .marketing_info
@@ -102,7 +102,7 @@ impl Cw20Marketing for Cw20Base<'_> {
         Ok(res)
     }
 
-    #[msg(query)]
+    #[sv::msg(query)]
     fn marketing_info(&self, ctx: QueryCtx) -> StdResult<MarketingInfoResponse> {
         Ok(self
             .marketing_info
@@ -110,7 +110,7 @@ impl Cw20Marketing for Cw20Base<'_> {
             .unwrap_or_default())
     }
 
-    #[msg(query)]
+    #[sv::msg(query)]
     fn download_logo(&self, ctx: QueryCtx) -> StdResult<DownloadLogoResponse> {
         let logo = self.logo.load(ctx.deps.storage)?;
         match logo {
diff --git a/examples/contracts/cw20-base/src/minting.rs b/examples/contracts/cw20-base/src/minting.rs
index 75d8d97..f89fa0a 100644
--- a/examples/contracts/cw20-base/src/minting.rs
+++ b/examples/contracts/cw20-base/src/minting.rs
@@ -7,11 +7,11 @@ use sylvia::contract;
 use sylvia::types::{ExecCtx, QueryCtx};
 
 #[contract(module=crate::contract)]
-#[messages(cw20_minting as Cw20Minting)]
+#[sv::messages(cw20_minting as Cw20Minting)]
 impl Cw20Minting for Cw20Base<'_> {
     type Error = ContractError;
 
-    #[msg(exec)]
+    #[sv::msg(exec)]
     fn mint(
         &self,
         ctx: ExecCtx,
@@ -61,7 +61,7 @@ impl Cw20Minting for Cw20Base<'_> {
         Ok(res)
     }
 
-    #[msg(exec)]
+    #[sv::msg(exec)]
     fn update_minter(
         &self,
         ctx: ExecCtx,
@@ -101,7 +101,7 @@ impl Cw20Minting for Cw20Base<'_> {
         Ok(resp)
     }
 
-    #[msg(query)]
+    #[sv::msg(query)]
     fn minter(&self, ctx: QueryCtx) -> StdResult<Option<MinterResponse>> {
         let meta = self.token_info.load(ctx.deps.storage)?;
         let minter = match meta.mint {
diff --git a/examples/contracts/entry-points-overriding/src/bin/schema.rs b/examples/contracts/entry-points-overriding/src/bin/schema.rs
index 6d5bd4e..2275f11 100644
--- a/examples/contracts/entry-points-overriding/src/bin/schema.rs
+++ b/examples/contracts/entry-points-overriding/src/bin/schema.rs
@@ -1,8 +1,7 @@
 use cosmwasm_schema::write_api;
 
 use entry_points_overriding::contract::sv::{ContractQueryMsg, InstantiateMsg};
-use entry_points_overriding::messages::CustomExecMsg;
-use entry_points_overriding::messages::SudoMsg;
+use entry_points_overriding::messages::{CustomExecMsg, SudoMsg};
 
 #[cfg(not(tarpaulin_include))]
 fn main() {
diff --git a/examples/contracts/entry-points-overriding/src/contract.rs b/examples/contracts/entry-points-overriding/src/contract.rs
index 962891d..5bd2175 100644
--- a/examples/contracts/entry-points-overriding/src/contract.rs
+++ b/examples/contracts/entry-points-overriding/src/contract.rs
@@ -23,19 +23,19 @@ impl CounterContract {
         }
     }
 
-    #[msg(instantiate)]
+    #[sv::msg(instantiate)]
     pub fn instantiate(&self, ctx: InstantiateCtx) -> StdResult<Response> {
         self.counter.save(ctx.deps.storage, &0)?;
         Ok(Response::new())
     }
 
-    #[msg(query)]
+    #[sv::msg(query)]
     pub fn count(&self, ctx: QueryCtx) -> StdResult<CountResponse> {
         let count = self.counter.load(ctx.deps.storage)?;
         Ok(CountResponse { count })
     }
 
-    #[msg(exec)]
+    #[sv::msg(exec)]
     pub fn increase_by_two(&self, ctx: ExecCtx) -> StdResult<Response> {
         self.counter
             .update(ctx.deps.storage, |count| -> Result<u32, StdError> {
diff --git a/examples/contracts/generic_contract/src/contract.rs b/examples/contracts/generic_contract/src/contract.rs
index 3ae7bad..3dfbf65 100644
--- a/examples/contracts/generic_contract/src/contract.rs
+++ b/examples/contracts/generic_contract/src/contract.rs
@@ -44,9 +44,9 @@ pub struct GenericContract<
 
 #[cfg_attr(not(feature = "library"), entry_points(generics<SvCustomMsg, SvCustomMsg, SvCustomMsg, SvCustomMsg, SvCustomMsg, SvCustomMsg, SvCustomMsg, SvCustomMsg, SvCustomMsg, SvCustomMsg, sylvia::types::SvCustomMsg, String>))]
 #[contract]
-#[messages(cw1 as Cw1: custom(msg, query))]
-#[messages(generic<SvCustomMsg, SvCustomMsg, SvCustomMsg, SvCustomMsg, SvCustomMsg, SvCustomMsg, SvCustomMsg, SvCustomMsg, SvCustomMsg, SvCustomMsg> as Generic: custom(msg, query))]
-#[messages(custom_and_generic<SvCustomMsg, SvCustomMsg, SvCustomMsg, SvCustomMsg, SvCustomMsg, SvCustomMsg, SvCustomMsg, SvCustomMsg, SvCustomMsg, SvCustomMsg> as CustomAndGeneric)]
+#[sv::messages(cw1 as Cw1: custom(msg, query))]
+#[sv::messages(generic<SvCustomMsg, SvCustomMsg, SvCustomMsg, SvCustomMsg, SvCustomMsg, SvCustomMsg, SvCustomMsg, SvCustomMsg, SvCustomMsg, SvCustomMsg> as Generic: custom(msg, query))]
+#[sv::messages(custom_and_generic<SvCustomMsg, SvCustomMsg, SvCustomMsg, SvCustomMsg, SvCustomMsg, SvCustomMsg, SvCustomMsg, SvCustomMsg, SvCustomMsg, SvCustomMsg> as CustomAndGeneric)]
 #[sv::custom(msg=SvCustomMsg, query=SvCustomQuery)]
 impl<
         InstantiateT,
@@ -97,7 +97,7 @@ where
         }
     }
 
-    #[msg(instantiate)]
+    #[sv::msg(instantiate)]
     pub fn instantiate(
         &self,
         _ctx: InstantiateCtx<SvCustomQuery>,
@@ -106,7 +106,7 @@ where
         Ok(Response::new())
     }
 
-    #[msg(exec)]
+    #[sv::msg(exec)]
     pub fn contract_execute_one(
         &self,
         _ctx: ExecCtx<SvCustomQuery>,
@@ -116,7 +116,7 @@ where
         Ok(Response::new())
     }
 
-    #[msg(exec)]
+    #[sv::msg(exec)]
     pub fn contract_execute_two(
         &self,
         _ctx: ExecCtx<SvCustomQuery>,
@@ -126,7 +126,7 @@ where
         Ok(Response::new())
     }
 
-    #[msg(query)]
+    #[sv::msg(query)]
     pub fn contract_query_one(
         &self,
         _ctx: QueryCtx<SvCustomQuery>,
@@ -136,7 +136,7 @@ where
         Ok(String::default())
     }
 
-    #[msg(query)]
+    #[sv::msg(query)]
     pub fn contract_query_two(
         &self,
         _ctx: QueryCtx<SvCustomQuery>,
@@ -146,7 +146,7 @@ where
         Ok(String::default())
     }
 
-    #[msg(sudo)]
+    #[sv::msg(sudo)]
     fn contract_sudo_one(
         &self,
         _ctx: SudoCtx<SvCustomQuery>,
@@ -156,7 +156,7 @@ where
         Ok(Response::new())
     }
 
-    #[msg(sudo)]
+    #[sv::msg(sudo)]
     fn contract_sudo_two(
         &self,
         _ctx: SudoCtx<SvCustomQuery>,
@@ -166,7 +166,7 @@ where
         Ok(Response::new())
     }
 
-    #[msg(migrate)]
+    #[sv::msg(migrate)]
     pub fn migrate(
         &self,
         _ctx: MigrateCtx<SvCustomQuery>,
@@ -176,7 +176,7 @@ where
     }
 
     #[allow(dead_code)]
-    #[msg(reply)]
+    #[sv::msg(reply)]
     fn reply(
         &self,
         _ctx: ReplyCtx<SvCustomQuery>,
diff --git a/examples/contracts/generic_contract/src/custom_and_generic.rs b/examples/contracts/generic_contract/src/custom_and_generic.rs
index f1a74e9..be0a8fc 100644
--- a/examples/contracts/generic_contract/src/custom_and_generic.rs
+++ b/examples/contracts/generic_contract/src/custom_and_generic.rs
@@ -4,7 +4,7 @@ use sylvia::contract;
 use sylvia::types::{ExecCtx, QueryCtx, SudoCtx, SvCustomMsg, SvCustomQuery};
 
 #[contract(module = crate::contract)]
-#[messages(custom_and_generic as CustomAndGeneric)]
+#[sv::messages(custom_and_generic as CustomAndGeneric)]
 #[sv::custom(msg=SvCustomMsg, query=SvCustomQuery)]
 impl<
         InstantiateT,
@@ -49,7 +49,7 @@ impl<
     type QueryC = SvCustomQuery;
     type RetT = SvCustomMsg;
 
-    #[msg(exec)]
+    #[sv::msg(exec)]
     fn custom_generic_execute_one(
         &self,
         _ctx: ExecCtx<Self::QueryC>,
@@ -59,7 +59,7 @@ impl<
         Ok(Response::new())
     }
 
-    #[msg(exec)]
+    #[sv::msg(exec)]
     fn custom_generic_execute_two(
         &self,
         _ctx: ExecCtx<Self::QueryC>,
@@ -69,7 +69,7 @@ impl<
         Ok(Response::new())
     }
 
-    #[msg(query)]
+    #[sv::msg(query)]
     fn custom_generic_query_one(
         &self,
         _ctx: QueryCtx<Self::QueryC>,
@@ -79,7 +79,7 @@ impl<
         Ok(SvCustomMsg {})
     }
 
-    #[msg(query)]
+    #[sv::msg(query)]
     fn custom_generic_query_two(
         &self,
         _ctx: QueryCtx<Self::QueryC>,
@@ -89,7 +89,7 @@ impl<
         Ok(SvCustomMsg {})
     }
 
-    #[msg(sudo)]
+    #[sv::msg(sudo)]
     fn custom_generic_sudo_one(
         &self,
         _ctx: SudoCtx<Self::QueryC>,
@@ -99,7 +99,7 @@ impl<
         Ok(Response::new())
     }
 
-    #[msg(sudo)]
+    #[sv::msg(sudo)]
     fn custom_generic_sudo_two(
         &self,
         _ctx: SudoCtx<Self::QueryC>,
@@ -114,10 +114,8 @@ impl<
 mod tests {
     use super::sv::test_utils::CustomAndGeneric;
     use crate::contract::sv::multitest_utils::CodeId;
-    use sylvia::{
-        multitest::App,
-        types::{SvCustomMsg, SvCustomQuery},
-    };
+    use sylvia::multitest::App;
+    use sylvia::types::{SvCustomMsg, SvCustomQuery};
 
     #[test]
     fn proxy_methods() {
diff --git a/examples/contracts/generic_contract/src/cw1.rs b/examples/contracts/generic_contract/src/cw1.rs
index e6cb285..54948b6 100644
--- a/examples/contracts/generic_contract/src/cw1.rs
+++ b/examples/contracts/generic_contract/src/cw1.rs
@@ -4,7 +4,7 @@ use sylvia::contract;
 use sylvia::types::{ExecCtx, QueryCtx};
 
 #[contract(module = crate::contract)]
-#[messages(cw1 as Cw1)]
+#[sv::messages(cw1 as Cw1)]
 #[sv::custom(msg=sylvia::types::SvCustomMsg, query=sylvia::types::SvCustomQuery)]
 impl<
         InstantiateT,
@@ -37,12 +37,12 @@ impl<
 {
     type Error = StdError;
 
-    #[msg(exec)]
+    #[sv::msg(exec)]
     fn execute(&self, _ctx: ExecCtx, _msgs: Vec<CosmosMsg>) -> StdResult<Response> {
         Ok(Response::new())
     }
 
-    #[msg(query)]
+    #[sv::msg(query)]
     fn can_execute(
         &self,
         _ctx: QueryCtx,
@@ -58,10 +58,8 @@ mod tests {
     use super::sv::test_utils::Cw1;
     use crate::contract::sv::multitest_utils::CodeId;
     use cosmwasm_std::{CosmosMsg, Empty};
-    use sylvia::{
-        multitest::App,
-        types::{SvCustomMsg, SvCustomQuery},
-    };
+    use sylvia::multitest::App;
+    use sylvia::types::{SvCustomMsg, SvCustomQuery};
 
     #[test]
     fn proxy_methods() {
diff --git a/examples/contracts/generic_contract/src/generic.rs b/examples/contracts/generic_contract/src/generic.rs
index 4c3c25a..3ee3431 100644
--- a/examples/contracts/generic_contract/src/generic.rs
+++ b/examples/contracts/generic_contract/src/generic.rs
@@ -5,7 +5,7 @@ use sylvia::contract;
 use sylvia::types::{CustomMsg, ExecCtx, QueryCtx, SudoCtx, SvCustomMsg};
 
 #[contract(module = crate::contract)]
-#[messages(generic as Generic)]
+#[sv::messages(generic as Generic)]
 #[sv::custom(msg=SvCustomMsg, query=SvCustomQuery)]
 impl<
         InstantiateT,
@@ -61,7 +61,7 @@ where
     type Sudo3T = SvCustomMsg;
     type RetT = SvCustomMsg;
 
-    #[msg(exec)]
+    #[sv::msg(exec)]
     fn generic_exec_one(
         &self,
         _ctx: ExecCtx,
@@ -71,7 +71,7 @@ where
         Ok(Response::new())
     }
 
-    #[msg(exec)]
+    #[sv::msg(exec)]
     fn generic_exec_two(
         &self,
         _ctx: ExecCtx,
@@ -81,7 +81,7 @@ where
         Ok(Response::new())
     }
 
-    #[msg(query)]
+    #[sv::msg(query)]
     fn generic_query_one(
         &self,
         _ctx: QueryCtx,
@@ -91,7 +91,7 @@ where
         Ok(SvCustomMsg {})
     }
 
-    #[msg(query)]
+    #[sv::msg(query)]
     fn generic_query_two(
         &self,
         _ctx: QueryCtx,
@@ -101,7 +101,7 @@ where
         Ok(SvCustomMsg {})
     }
 
-    #[msg(sudo)]
+    #[sv::msg(sudo)]
     fn generic_sudo_one(
         &self,
         _ctx: SudoCtx,
@@ -111,7 +111,7 @@ where
         Ok(Response::new())
     }
 
-    #[msg(sudo)]
+    #[sv::msg(sudo)]
     fn generic_sudo_two(
         &self,
         _ctx: SudoCtx,
diff --git a/examples/contracts/generic_iface_on_contract/src/contract.rs b/examples/contracts/generic_iface_on_contract/src/contract.rs
index e1253cf..214f6d1 100644
--- a/examples/contracts/generic_iface_on_contract/src/contract.rs
+++ b/examples/contracts/generic_iface_on_contract/src/contract.rs
@@ -9,9 +9,9 @@ pub struct NonGenericContract;
 
 #[cfg_attr(not(feature = "library"), entry_points)]
 #[contract]
-#[messages(generic<SvCustomMsg, SvCustomMsg, SvCustomMsg, SvCustomMsg, SvCustomMsg, SvCustomMsg, SvCustomMsg, SvCustomMsg, SvCustomMsg, SvCustomMsg> as Generic: custom(msg, query))]
-#[messages(custom_and_generic<SvCustomMsg, SvCustomMsg, SvCustomMsg, SvCustomMsg, SvCustomMsg, SvCustomMsg, SvCustomMsg, SvCustomMsg, SvCustomMsg, SvCustomMsg> as CustomAndGeneric)]
-#[messages(cw1 as Cw1: custom(msg, query))]
+#[sv::messages(generic<SvCustomMsg, SvCustomMsg, SvCustomMsg, SvCustomMsg, SvCustomMsg, SvCustomMsg, SvCustomMsg, SvCustomMsg, SvCustomMsg, SvCustomMsg> as Generic: custom(msg, query))]
+#[sv::messages(custom_and_generic<SvCustomMsg, SvCustomMsg, SvCustomMsg, SvCustomMsg, SvCustomMsg, SvCustomMsg, SvCustomMsg, SvCustomMsg, SvCustomMsg, SvCustomMsg> as CustomAndGeneric)]
+#[sv::messages(cw1 as Cw1: custom(msg, query))]
 /// Required if interface returns generic `Response`
 #[sv::custom(msg=SvCustomMsg, query=SvCustomQuery)]
 impl NonGenericContract {
@@ -19,7 +19,7 @@ impl NonGenericContract {
         Self
     }
 
-    #[msg(instantiate)]
+    #[sv::msg(instantiate)]
     pub fn instantiate(
         &self,
         _ctx: InstantiateCtx<SvCustomQuery>,
@@ -31,8 +31,8 @@ impl NonGenericContract {
 #[cfg(test)]
 mod tests {
     use cosmwasm_std::{CosmosMsg, Empty};
-    use sylvia::types::SvCustomQuery;
-    use sylvia::{multitest::App, types::SvCustomMsg};
+    use sylvia::multitest::App;
+    use sylvia::types::{SvCustomMsg, SvCustomQuery};
 
     use super::NonGenericContract;
     use crate::custom_and_generic::sv::test_utils::CustomAndGeneric;
diff --git a/examples/contracts/generic_iface_on_contract/src/custom_and_generic.rs b/examples/contracts/generic_iface_on_contract/src/custom_and_generic.rs
index 78a4f98..ed1d6f7 100644
--- a/examples/contracts/generic_iface_on_contract/src/custom_and_generic.rs
+++ b/examples/contracts/generic_iface_on_contract/src/custom_and_generic.rs
@@ -4,7 +4,7 @@ use sylvia::contract;
 use sylvia::types::{ExecCtx, QueryCtx, SudoCtx, SvCustomMsg, SvCustomQuery};
 
 #[contract(module = crate::contract)]
-#[messages(custom_and_generic as CustomAndGeneric)]
+#[sv::messages(custom_and_generic as CustomAndGeneric)]
 #[sv::custom(msg=sylvia::types::SvCustomMsg, query=SvCustomQuery)]
 impl CustomAndGeneric for crate::contract::NonGenericContract {
     type Error = StdError;
@@ -21,7 +21,7 @@ impl CustomAndGeneric for crate::contract::NonGenericContract {
     type QueryC = SvCustomQuery;
     type RetT = SvCustomMsg;
 
-    #[msg(exec)]
+    #[sv::msg(exec)]
     fn custom_generic_execute_one(
         &self,
         _ctx: ExecCtx<Self::QueryC>,
@@ -31,7 +31,7 @@ impl CustomAndGeneric for crate::contract::NonGenericContract {
         Ok(Response::new())
     }
 
-    #[msg(exec)]
+    #[sv::msg(exec)]
     fn custom_generic_execute_two(
         &self,
         _ctx: ExecCtx<Self::QueryC>,
@@ -41,7 +41,7 @@ impl CustomAndGeneric for crate::contract::NonGenericContract {
         Ok(Response::new())
     }
 
-    #[msg(query)]
+    #[sv::msg(query)]
     fn custom_generic_query_one(
         &self,
         _ctx: QueryCtx<Self::QueryC>,
@@ -51,7 +51,7 @@ impl CustomAndGeneric for crate::contract::NonGenericContract {
         Ok(SvCustomMsg {})
     }
 
-    #[msg(query)]
+    #[sv::msg(query)]
     fn custom_generic_query_two(
         &self,
         _ctx: QueryCtx<Self::QueryC>,
@@ -61,7 +61,7 @@ impl CustomAndGeneric for crate::contract::NonGenericContract {
         Ok(SvCustomMsg {})
     }
 
-    #[msg(sudo)]
+    #[sv::msg(sudo)]
     fn custom_generic_sudo_one(
         &self,
         _ctx: SudoCtx<Self::QueryC>,
@@ -71,7 +71,7 @@ impl CustomAndGeneric for crate::contract::NonGenericContract {
         Ok(Response::new())
     }
 
-    #[msg(sudo)]
+    #[sv::msg(sudo)]
     fn custom_generic_sudo_two(
         &self,
         _ctx: SudoCtx<Self::QueryC>,
diff --git a/examples/contracts/generic_iface_on_contract/src/cw1.rs b/examples/contracts/generic_iface_on_contract/src/cw1.rs
index 8d45bc0..ffd9e61 100644
--- a/examples/contracts/generic_iface_on_contract/src/cw1.rs
+++ b/examples/contracts/generic_iface_on_contract/src/cw1.rs
@@ -4,17 +4,17 @@ use sylvia::contract;
 use sylvia::types::{ExecCtx, QueryCtx};
 
 #[contract(module = crate::contract)]
-#[messages(cw1 as Cw1)]
+#[sv::messages(cw1 as Cw1)]
 #[sv::custom(msg=sylvia::types::SvCustomMsg)]
 impl Cw1 for crate::contract::NonGenericContract {
     type Error = StdError;
 
-    #[msg(exec)]
+    #[sv::msg(exec)]
     fn execute(&self, _ctx: ExecCtx, _msgs: Vec<CosmosMsg>) -> StdResult<Response> {
         Ok(Response::new())
     }
 
-    #[msg(query)]
+    #[sv::msg(query)]
     fn can_execute(
         &self,
         _ctx: QueryCtx,
diff --git a/examples/contracts/generic_iface_on_contract/src/generic.rs b/examples/contracts/generic_iface_on_contract/src/generic.rs
index 52cab37..4830093 100644
--- a/examples/contracts/generic_iface_on_contract/src/generic.rs
+++ b/examples/contracts/generic_iface_on_contract/src/generic.rs
@@ -4,7 +4,7 @@ use sylvia::contract;
 use sylvia::types::{ExecCtx, QueryCtx, SudoCtx, SvCustomMsg};
 
 #[contract(module = crate::contract)]
-#[messages(generic as Generic)]
+#[sv::messages(generic as Generic)]
 #[sv::custom(msg = SvCustomMsg)]
 impl Generic for crate::contract::NonGenericContract {
     type Error = StdError;
@@ -19,7 +19,7 @@ impl Generic for crate::contract::NonGenericContract {
     type Sudo3T = SvCustomMsg;
     type RetT = SvCustomMsg;
 
-    #[msg(exec)]
+    #[sv::msg(exec)]
     fn generic_exec_one(
         &self,
         _ctx: ExecCtx,
@@ -29,7 +29,7 @@ impl Generic for crate::contract::NonGenericContract {
         Ok(Response::new())
     }
 
-    #[msg(exec)]
+    #[sv::msg(exec)]
     fn generic_exec_two(
         &self,
         _ctx: ExecCtx,
@@ -39,7 +39,7 @@ impl Generic for crate::contract::NonGenericContract {
         Ok(Response::new())
     }
 
-    #[msg(query)]
+    #[sv::msg(query)]
     fn generic_query_one(
         &self,
         _ctx: QueryCtx,
@@ -49,7 +49,7 @@ impl Generic for crate::contract::NonGenericContract {
         Ok(SvCustomMsg {})
     }
 
-    #[msg(query)]
+    #[sv::msg(query)]
     fn generic_query_two(
         &self,
         _ctx: QueryCtx,
@@ -59,7 +59,7 @@ impl Generic for crate::contract::NonGenericContract {
         Ok(SvCustomMsg {})
     }
 
-    #[msg(sudo)]
+    #[sv::msg(sudo)]
     fn generic_sudo_one(
         &self,
         _ctx: SudoCtx,
@@ -69,7 +69,7 @@ impl Generic for crate::contract::NonGenericContract {
         Ok(Response::new())
     }
 
-    #[msg(sudo)]
+    #[sv::msg(sudo)]
     fn generic_sudo_two(
         &self,
         _ctx: SudoCtx,
diff --git a/examples/contracts/generics_forwarded/src/contract.rs b/examples/contracts/generics_forwarded/src/contract.rs
index e1c4815..89aff24 100644
--- a/examples/contracts/generics_forwarded/src/contract.rs
+++ b/examples/contracts/generics_forwarded/src/contract.rs
@@ -47,9 +47,9 @@ pub struct GenericsForwardedContract<
 
 #[cfg_attr(not(feature = "library"), sylvia::entry_points(generics<SvCustomMsg, SvCustomMsg, SvCustomMsg, SvCustomMsg, SvCustomMsg, SvCustomMsg, SvCustomMsg, SvCustomMsg, SvCustomMsg, SvCustomMsg, SvCustomMsg, SvCustomMsg, SvCustomQuery, String>, custom(msg=SvCustomMsg, query=SvCustomQuery)))]
 #[contract]
-#[messages(generic<Exec1T, Exec2T, Exec3T, Query1T, Query2T, Query3T, Sudo1T, Sudo2T, Sudo3T, SvCustomMsg> as Generic: custom(msg, query))]
-#[messages(cw1 as Cw1: custom(msg, query))]
-#[messages(custom_and_generic<Exec1T, Exec2T, Exec3T, Query1T, Query2T, Query3T, Sudo1T, Sudo2T, Sudo3T, SvCustomMsg> as CustomAndGeneric)]
+#[sv::messages(generic<Exec1T, Exec2T, Exec3T, Query1T, Query2T, Query3T, Sudo1T, Sudo2T, Sudo3T, SvCustomMsg> as Generic: custom(msg, query))]
+#[sv::messages(cw1 as Cw1: custom(msg, query))]
+#[sv::messages(custom_and_generic<Exec1T, Exec2T, Exec3T, Query1T, Query2T, Query3T, Sudo1T, Sudo2T, Sudo3T, SvCustomMsg> as CustomAndGeneric)]
 #[sv::custom(msg=CustomMsgT, query=CustomQueryT)]
 impl<
         InstantiateT,
@@ -106,7 +106,7 @@ where
         }
     }
 
-    #[msg(instantiate)]
+    #[sv::msg(instantiate)]
     pub fn instantiate(
         &self,
         _ctx: InstantiateCtx<CustomQueryT>,
@@ -115,7 +115,7 @@ where
         Ok(Response::new())
     }
 
-    #[msg(exec)]
+    #[sv::msg(exec)]
     pub fn contract_execute_one(
         &self,
         _ctx: ExecCtx<CustomQueryT>,
@@ -125,7 +125,7 @@ where
         Ok(Response::new())
     }
 
-    #[msg(exec)]
+    #[sv::msg(exec)]
     pub fn contract_execute_two(
         &self,
         _ctx: ExecCtx<CustomQueryT>,
@@ -135,7 +135,7 @@ where
         Ok(Response::new())
     }
 
-    #[msg(query)]
+    #[sv::msg(query)]
     pub fn contract_query_one(
         &self,
         _ctx: QueryCtx<CustomQueryT>,
@@ -145,7 +145,7 @@ where
         Ok(String::default())
     }
 
-    #[msg(query)]
+    #[sv::msg(query)]
     pub fn contract_query_two(
         &self,
         _ctx: QueryCtx<CustomQueryT>,
@@ -155,7 +155,7 @@ where
         Ok(String::default())
     }
 
-    #[msg(sudo)]
+    #[sv::msg(sudo)]
     fn contract_sudo_one(
         &self,
         _ctx: SudoCtx<CustomQueryT>,
@@ -165,7 +165,7 @@ where
         Ok(Response::new())
     }
 
-    #[msg(sudo)]
+    #[sv::msg(sudo)]
     fn contract_sudo_two(
         &self,
         _ctx: SudoCtx<CustomQueryT>,
@@ -175,7 +175,7 @@ where
         Ok(Response::new())
     }
 
-    #[msg(migrate)]
+    #[sv::msg(migrate)]
     pub fn migrate(
         &self,
         _ctx: MigrateCtx<CustomQueryT>,
@@ -185,7 +185,7 @@ where
     }
 
     #[allow(dead_code)]
-    #[msg(reply)]
+    #[sv::msg(reply)]
     fn reply(
         &self,
         _ctx: ReplyCtx<CustomQueryT>,
diff --git a/examples/contracts/generics_forwarded/src/custom_and_generic.rs b/examples/contracts/generics_forwarded/src/custom_and_generic.rs
index a61d56f..8781e79 100644
--- a/examples/contracts/generics_forwarded/src/custom_and_generic.rs
+++ b/examples/contracts/generics_forwarded/src/custom_and_generic.rs
@@ -5,7 +5,7 @@ use sylvia::contract;
 use sylvia::types::{CustomMsg, CustomQuery, ExecCtx, QueryCtx, SudoCtx, SvCustomMsg};
 
 #[contract(module = crate::contract)]
-#[messages(custom_and_generic as CustomAndGeneric)]
+#[sv::messages(custom_and_generic as CustomAndGeneric)]
 impl<
         InstantiateT,
         Exec1T,
@@ -68,7 +68,7 @@ where
     type QueryC = CustomQueryT;
     type RetT = SvCustomMsg;
 
-    #[msg(exec)]
+    #[sv::msg(exec)]
     fn custom_generic_execute_one(
         &self,
         _ctx: ExecCtx<Self::QueryC>,
@@ -78,7 +78,7 @@ where
         Ok(Response::new())
     }
 
-    #[msg(exec)]
+    #[sv::msg(exec)]
     fn custom_generic_execute_two(
         &self,
         _ctx: ExecCtx<Self::QueryC>,
@@ -88,7 +88,7 @@ where
         Ok(Response::new())
     }
 
-    #[msg(query)]
+    #[sv::msg(query)]
     fn custom_generic_query_one(
         &self,
         _ctx: QueryCtx<Self::QueryC>,
@@ -98,7 +98,7 @@ where
         Ok(SvCustomMsg {})
     }
 
-    #[msg(query)]
+    #[sv::msg(query)]
     fn custom_generic_query_two(
         &self,
         _ctx: QueryCtx<Self::QueryC>,
@@ -108,7 +108,7 @@ where
         Ok(SvCustomMsg {})
     }
 
-    #[msg(sudo)]
+    #[sv::msg(sudo)]
     fn custom_generic_sudo_one(
         &self,
         _ctx: SudoCtx<Self::QueryC>,
@@ -118,7 +118,7 @@ where
         Ok(Response::new())
     }
 
-    #[msg(sudo)]
+    #[sv::msg(sudo)]
     fn custom_generic_sudo_two(
         &self,
         _ctx: SudoCtx<Self::QueryC>,
diff --git a/examples/contracts/generics_forwarded/src/cw1.rs b/examples/contracts/generics_forwarded/src/cw1.rs
index 371a1a6..e2eb660 100644
--- a/examples/contracts/generics_forwarded/src/cw1.rs
+++ b/examples/contracts/generics_forwarded/src/cw1.rs
@@ -7,7 +7,7 @@ use sylvia::contract;
 use sylvia::types::{CustomQuery, ExecCtx, QueryCtx, SvCustomMsg};
 
 #[contract(module = crate::contract)]
-#[messages(cw1 as Cw1)]
+#[sv::messages(cw1 as Cw1)]
 #[sv::custom(msg=SvCustomMsg, query=SvCustomQuery)]
 impl<
         InstantiateT,
@@ -59,12 +59,12 @@ where
 {
     type Error = StdError;
 
-    #[msg(exec)]
+    #[sv::msg(exec)]
     fn execute(&self, _ctx: ExecCtx, _msgs: Vec<CosmosMsg>) -> StdResult<Response> {
         Ok(Response::new())
     }
 
-    #[msg(query)]
+    #[sv::msg(query)]
     fn can_execute(
         &self,
         _ctx: QueryCtx,
@@ -80,10 +80,8 @@ mod tests {
     use super::sv::test_utils::Cw1;
     use crate::contract::sv::multitest_utils::CodeId;
     use cosmwasm_std::{CosmosMsg, Empty};
-    use sylvia::{
-        multitest::App,
-        types::{SvCustomMsg, SvCustomQuery},
-    };
+    use sylvia::multitest::App;
+    use sylvia::types::{SvCustomMsg, SvCustomQuery};
 
     #[test]
     fn proxy_methods() {
diff --git a/examples/contracts/generics_forwarded/src/generic.rs b/examples/contracts/generics_forwarded/src/generic.rs
index 28a2359..baaf177 100644
--- a/examples/contracts/generics_forwarded/src/generic.rs
+++ b/examples/contracts/generics_forwarded/src/generic.rs
@@ -5,7 +5,7 @@ use sylvia::contract;
 use sylvia::types::{CustomMsg, CustomQuery, ExecCtx, QueryCtx, SudoCtx, SvCustomMsg};
 
 #[contract(module = crate::contract)]
-#[messages(generic as Generic)]
+#[sv::messages(generic as Generic)]
 #[sv::custom(msg=SvCustomMsg, query=SvCustomQuery)]
 impl<
         InstantiateT,
@@ -67,7 +67,7 @@ where
     type Sudo3T = Sudo3T;
     type RetT = SvCustomMsg;
 
-    #[msg(exec)]
+    #[sv::msg(exec)]
     fn generic_exec_one(
         &self,
         _ctx: ExecCtx,
@@ -77,7 +77,7 @@ where
         Ok(Response::new())
     }
 
-    #[msg(exec)]
+    #[sv::msg(exec)]
     fn generic_exec_two(
         &self,
         _ctx: ExecCtx,
@@ -87,7 +87,7 @@ where
         Ok(Response::new())
     }
 
-    #[msg(query)]
+    #[sv::msg(query)]
     fn generic_query_one(
         &self,
         _ctx: QueryCtx,
@@ -97,7 +97,7 @@ where
         Ok(SvCustomMsg {})
     }
 
-    #[msg(query)]
+    #[sv::msg(query)]
     fn generic_query_two(
         &self,
         _ctx: QueryCtx,
@@ -107,7 +107,7 @@ where
         Ok(SvCustomMsg {})
     }
 
-    #[msg(sudo)]
+    #[sv::msg(sudo)]
     fn generic_sudo_one(
         &self,
         _ctx: SudoCtx,
@@ -117,7 +117,7 @@ where
         Ok(Response::new())
     }
 
-    #[msg(sudo)]
+    #[sv::msg(sudo)]
     fn generic_sudo_two(
         &self,
         _ctx: SudoCtx,
diff --git a/examples/interfaces/custom-and-generic/src/lib.rs b/examples/interfaces/custom-and-generic/src/lib.rs
index ec13207..a06a6cb 100644
--- a/examples/interfaces/custom-and-generic/src/lib.rs
+++ b/examples/interfaces/custom-and-generic/src/lib.rs
@@ -19,7 +19,7 @@ pub trait CustomAndGeneric {
     type QueryC: CustomQuery + 'static;
     type RetT: CustomMsg;
 
-    #[msg(exec)]
+    #[sv::msg(exec)]
     fn custom_generic_execute_one(
         &self,
         ctx: ExecCtx<Self::QueryC>,
@@ -27,7 +27,7 @@ pub trait CustomAndGeneric {
         msgs2: Vec<CosmosMsg<Self::Exec2T>>,
     ) -> Result<Response<Self::ExecC>, Self::Error>;
 
-    #[msg(exec)]
+    #[sv::msg(exec)]
     fn custom_generic_execute_two(
         &self,
         ctx: ExecCtx<Self::QueryC>,
@@ -35,7 +35,7 @@ pub trait CustomAndGeneric {
         msgs2: Vec<CosmosMsg<Self::Exec3T>>,
     ) -> Result<Response<Self::ExecC>, Self::Error>;
 
-    #[msg(query)]
+    #[sv::msg(query)]
     fn custom_generic_query_one(
         &self,
         ctx: QueryCtx<Self::QueryC>,
@@ -43,7 +43,7 @@ pub trait CustomAndGeneric {
         param2: Self::Query2T,
     ) -> Result<Self::RetT, Self::Error>;
 
-    #[msg(query)]
+    #[sv::msg(query)]
     fn custom_generic_query_two(
         &self,
         ctx: QueryCtx<Self::QueryC>,
@@ -51,7 +51,7 @@ pub trait CustomAndGeneric {
         param2: Self::Query3T,
     ) -> Result<Self::RetT, Self::Error>;
 
-    #[msg(sudo)]
+    #[sv::msg(sudo)]
     fn custom_generic_sudo_one(
         &self,
         ctx: SudoCtx<Self::QueryC>,
@@ -59,7 +59,7 @@ pub trait CustomAndGeneric {
         msg2: CosmosMsg<Self::Sudo2T>,
     ) -> Result<Response<Self::ExecC>, Self::Error>;
 
-    #[msg(sudo)]
+    #[sv::msg(sudo)]
     fn custom_generic_sudo_two(
         &self,
         ctx: SudoCtx<Self::QueryC>,
diff --git a/examples/interfaces/cw1/src/lib.rs b/examples/interfaces/cw1/src/lib.rs
index af8472a..a32c94f 100644
--- a/examples/interfaces/cw1/src/lib.rs
+++ b/examples/interfaces/cw1/src/lib.rs
@@ -17,13 +17,13 @@ pub trait Cw1 {
     /// Execute requests the contract to re-dispatch all these messages with the
     /// contract's address as sender. Every implementation has it's own logic to
     /// determine in
-    #[msg(exec)]
+    #[sv::msg(exec)]
     fn execute(&self, ctx: ExecCtx, msgs: Vec<CosmosMsg>) -> Result<Response, Self::Error>;
 
     /// Checks permissions of the caller on this proxy.
     /// If CanExecute returns true then a call to `Execute` with the same message,
     /// from the given sender, before any further state changes, should also succeed.
-    #[msg(query)]
+    #[sv::msg(query)]
     fn can_execute(
         &self,
         ctx: QueryCtx,
diff --git a/examples/interfaces/cw20-allowances/src/lib.rs b/examples/interfaces/cw20-allowances/src/lib.rs
index 5fd0055..287c327 100644
--- a/examples/interfaces/cw20-allowances/src/lib.rs
+++ b/examples/interfaces/cw20-allowances/src/lib.rs
@@ -14,7 +14,7 @@ pub trait Cw20Allowances {
 
     /// Allows spender to access an additional amount tokens from the owner's (env.sender) account.
     /// If expires is Some(), overwrites current allowance expiration with this one.
-    #[msg(exec)]
+    #[sv::msg(exec)]
     fn increase_allowance(
         &self,
         ctx: ExecCtx,
@@ -25,7 +25,7 @@ pub trait Cw20Allowances {
 
     /// Lowers the spender's access of tokens from the owner's (env.sender) account by amount.
     /// If expires is Some(), overwrites current allowance expiration with this one.
-    #[msg(exec)]
+    #[sv::msg(exec)]
     fn decrease_allowance(
         &self,
         ctx: ExecCtx,
@@ -36,7 +36,7 @@ pub trait Cw20Allowances {
 
     /// Transfers amount tokens from owner -> recipient
     /// if `env.sender` has sufficient pre-approval.
-    #[msg(exec)]
+    #[sv::msg(exec)]
     fn transfer_from(
         &self,
         ctx: ExecCtx,
@@ -47,7 +47,7 @@ pub trait Cw20Allowances {
 
     /// Sends amount tokens from owner -> contract
     /// if `env.sender` has sufficient pre-approval.
-    #[msg(exec)]
+    #[sv::msg(exec)]
     fn send_from(
         &self,
         ctx: ExecCtx,
@@ -58,7 +58,7 @@ pub trait Cw20Allowances {
     ) -> Result<Response, Self::Error>;
 
     /// Destroys amount of tokens forever
-    #[msg(exec)]
+    #[sv::msg(exec)]
     fn burn_from(
         &self,
         ctx: ExecCtx,
@@ -67,7 +67,7 @@ pub trait Cw20Allowances {
     ) -> Result<Response, Self::Error>;
 
     /// Returns how much spender can use from owner account, 0 if unset.
-    #[msg(query)]
+    #[sv::msg(query)]
     fn allowance(
         &self,
         ctx: QueryCtx,
@@ -76,7 +76,7 @@ pub trait Cw20Allowances {
     ) -> StdResult<AllowanceResponse>;
 
     /// Returns all allowances this owner has approved. Supports pagination.
-    #[msg(query)]
+    #[sv::msg(query)]
     fn all_allowances(
         &self,
         ctx: QueryCtx,
@@ -86,7 +86,7 @@ pub trait Cw20Allowances {
     ) -> StdResult<AllAllowancesResponse>;
 
     /// Returns all allowances this spender has been granted. Supports pagination.
-    #[msg(query)]
+    #[sv::msg(query)]
     fn all_spender_allowances(
         &self,
         ctx: QueryCtx,
@@ -96,7 +96,7 @@ pub trait Cw20Allowances {
     ) -> StdResult<AllSpenderAllowancesResponse>;
 
     /// Returns all accounts that have balances. Supports pagination.
-    #[msg(query)]
+    #[sv::msg(query)]
     fn all_accounts(
         &self,
         ctx: QueryCtx,
diff --git a/examples/interfaces/cw20-marketing/src/lib.rs b/examples/interfaces/cw20-marketing/src/lib.rs
index df24b79..3d4675f 100644
--- a/examples/interfaces/cw20-marketing/src/lib.rs
+++ b/examples/interfaces/cw20-marketing/src/lib.rs
@@ -38,7 +38,7 @@ pub trait Cw20Marketing {
     /// `project` - A URL pointing to the project behind this token.
     /// `description` - A longer description of the token and it's utility. Designed for tooltips or such
     /// `marketing` - The address (if any) who can update this data structure
-    #[msg(exec)]
+    #[sv::msg(exec)]
     fn update_marketing(
         &self,
         ctx: ExecCtx,
@@ -48,16 +48,16 @@ pub trait Cw20Marketing {
     ) -> Result<Response, Self::Error>;
 
     /// If set as the "marketing" role on the contract, upload a new URL, SVG, or PNG for the token
-    #[msg(exec)]
+    #[sv::msg(exec)]
     fn upload_logo(&self, ctx: ExecCtx, logo: Logo) -> Result<Response, Self::Error>;
 
     /// Returns more metadata on the contract to display in the client:
     /// - description, logo, project url, etc.
-    #[msg(query)]
+    #[sv::msg(query)]
     fn marketing_info(&self, ctx: QueryCtx) -> StdResult<MarketingInfoResponse>;
 
     /// Downloads the embedded logo data (if stored on chain). Errors if no logo data is stored for this
     /// contract.
-    #[msg(query)]
+    #[sv::msg(query)]
     fn download_logo(&self, ctx: QueryCtx) -> StdResult<DownloadLogoResponse>;
 }
diff --git a/examples/interfaces/cw20-minting/src/lib.rs b/examples/interfaces/cw20-minting/src/lib.rs
index 5bd1eee..4f4bb6f 100644
--- a/examples/interfaces/cw20-minting/src/lib.rs
+++ b/examples/interfaces/cw20-minting/src/lib.rs
@@ -10,7 +10,7 @@ pub trait Cw20Minting {
     type Error: From<StdError>;
 
     /// If authorized, creates amount new tokens and adds to the recipient balance.
-    #[msg(exec)]
+    #[sv::msg(exec)]
     fn mint(
         &self,
         ctx: ExecCtx,
@@ -20,7 +20,7 @@ pub trait Cw20Minting {
 
     /// The current minter may set a new minter.
     /// Setting the minter to None will remove the token's minter forever.
-    #[msg(exec)]
+    #[sv::msg(exec)]
     fn update_minter(
         &self,
         ctx: ExecCtx,
@@ -28,6 +28,6 @@ pub trait Cw20Minting {
     ) -> Result<Response, Self::Error>;
 
     /// Returns who can mint and the hard cap on maximum tokens after minting.
-    #[msg(query)]
+    #[sv::msg(query)]
     fn minter(&self, ctx: QueryCtx) -> StdResult<Option<MinterResponse>>;
 }
diff --git a/examples/interfaces/cw4/src/lib.rs b/examples/interfaces/cw4/src/lib.rs
index 795f5b2..ab188c4 100644
--- a/examples/interfaces/cw4/src/lib.rs
+++ b/examples/interfaces/cw4/src/lib.rs
@@ -7,31 +7,31 @@ use sylvia::{interface, schemars};
 pub trait Cw4 {
     type Error: From<StdError>;
 
-    #[msg(exec)]
+    #[sv::msg(exec)]
     fn update_admin(&self, ctx: ExecCtx, admin: String) -> Result<Response, Self::Error>;
 
-    #[msg(exec)]
+    #[sv::msg(exec)]
     fn update_members(&self, ctx: ExecCtx, members: Vec<String>) -> Result<Response, Self::Error>;
 
-    #[msg(exec)]
+    #[sv::msg(exec)]
     fn add_hook(&self, ctx: ExecCtx, hook: String) -> Result<Response, Self::Error>;
 
-    #[msg(exec)]
+    #[sv::msg(exec)]
     fn remove_hook(&self, ctx: ExecCtx, hook: String) -> Result<Response, Self::Error>;
 
-    #[msg(query)]
+    #[sv::msg(query)]
     fn member(&self, ctx: QueryCtx, member: String) -> Result<Response, Self::Error>;
 
-    #[msg(query)]
+    #[sv::msg(query)]
     fn list_members(&self, ctx: QueryCtx) -> Result<Response, Self::Error>;
 
-    #[msg(query)]
+    #[sv::msg(query)]
     fn total_weight(&self, ctx: QueryCtx) -> Result<Response, Self::Error>;
 
-    #[msg(query)]
+    #[sv::msg(query)]
     fn admin(&self, ctx: QueryCtx) -> Result<Response, Self::Error>;
 
-    #[msg(query)]
+    #[sv::msg(query)]
     fn hooks(&self, ctx: QueryCtx) -> Result<Response, Self::Error>;
 }
 
diff --git a/examples/interfaces/generic/src/lib.rs b/examples/interfaces/generic/src/lib.rs
index 57adc2b..4bf9b40 100644
--- a/examples/interfaces/generic/src/lib.rs
+++ b/examples/interfaces/generic/src/lib.rs
@@ -17,7 +17,7 @@ pub trait Generic {
     type Sudo3T: CustomMsg;
     type RetT: CustomMsg;
 
-    #[msg(exec)]
+    #[sv::msg(exec)]
     fn generic_exec_one(
         &self,
         ctx: ExecCtx,
@@ -25,7 +25,7 @@ pub trait Generic {
         msgs2: Vec<CosmosMsg<Self::Exec2T>>,
     ) -> Result<Response, Self::Error>;
 
-    #[msg(exec)]
+    #[sv::msg(exec)]
     fn generic_exec_two(
         &self,
         ctx: ExecCtx,
@@ -33,7 +33,7 @@ pub trait Generic {
         msgs2: Vec<CosmosMsg<Self::Exec3T>>,
     ) -> Result<Response, Self::Error>;
 
-    #[msg(query)]
+    #[sv::msg(query)]
     fn generic_query_one(
         &self,
         ctx: QueryCtx,
@@ -41,7 +41,7 @@ pub trait Generic {
         param2: Self::Query2T,
     ) -> Result<Self::RetT, Self::Error>;
 
-    #[msg(query)]
+    #[sv::msg(query)]
     fn generic_query_two(
         &self,
         ctx: QueryCtx,
@@ -49,7 +49,7 @@ pub trait Generic {
         param2: Self::Query3T,
     ) -> Result<Self::RetT, Self::Error>;
 
-    #[msg(sudo)]
+    #[sv::msg(sudo)]
     fn generic_sudo_one(
         &self,
         ctx: SudoCtx,
@@ -57,7 +57,7 @@ pub trait Generic {
         msg2: CosmosMsg<Self::Sudo2T>,
     ) -> Result<Response, Self::Error>;
 
-    #[msg(sudo)]
+    #[sv::msg(sudo)]
     fn generic_sudo_two(
         &self,
         ctx: SudoCtx,
@@ -68,7 +68,8 @@ pub trait Generic {
 
 #[cfg(test)]
 mod tests {
-    use cosmwasm_std::{testing::mock_dependencies, Addr, CosmosMsg, Empty, QuerierWrapper};
+    use cosmwasm_std::testing::mock_dependencies;
+    use cosmwasm_std::{Addr, CosmosMsg, Empty, QuerierWrapper};
     use sylvia::types::{InterfaceApi, SvCustomMsg};
 
     use crate::sv::Querier;
diff --git a/examples/interfaces/whitelist/src/lib.rs b/examples/interfaces/whitelist/src/lib.rs
index 5015954..7fe9b62 100644
--- a/examples/interfaces/whitelist/src/lib.rs
+++ b/examples/interfaces/whitelist/src/lib.rs
@@ -9,13 +9,13 @@ pub mod responses;
 pub trait Whitelist {
     type Error: From<cosmwasm_std::StdError>;
 
-    #[msg(exec)]
+    #[sv::msg(exec)]
     fn freeze(&self, ctx: ExecCtx) -> Result<Response, Self::Error>;
 
-    #[msg(exec)]
+    #[sv::msg(exec)]
     fn update_admins(&self, ctx: ExecCtx, admins: Vec<String>) -> Result<Response, Self::Error>;
 
-    #[msg(query)]
+    #[sv::msg(query)]
     fn admin_list(&self, ctx: QueryCtx) -> StdResult<AdminListResponse>;
 }
 
diff --git a/sylvia-derive/src/input.rs b/sylvia-derive/src/input.rs
index 4c9de5f..6a2b2fb 100644
--- a/sylvia-derive/src/input.rs
+++ b/sylvia-derive/src/input.rs
@@ -10,7 +10,10 @@ use crate::message::{
     StructMessage,
 };
 use crate::multitest::{ContractMtHelpers, ImplMtHelpers};
-use crate::parser::{ContractArgs, ContractErrorAttr, Custom, MsgType, OverrideEntryPoints};
+use crate::parser::attributes::msg::MsgType;
+use crate::parser::{
+    ContractArgs, ContractErrorAttr, Custom, OverrideEntryPoint, ParsedSylviaAttributes,
+};
 use crate::querier::{ContractQuerier, ImplQuerier, TraitQuerier};
 use crate::remote::{ContractRemote, InterfaceRemote};
 use crate::utils::is_trait;
@@ -19,7 +22,7 @@ use crate::variant_descs::AsVariantDescs;
 /// Preprocessed `interface` macro input
 pub struct TraitInput<'a> {
     item: &'a ItemTrait,
-    custom: Custom<'a>,
+    custom: Custom,
     associated_types: AssociatedTypes<'a>,
 }
 
@@ -29,8 +32,8 @@ pub struct ImplInput<'a> {
     error: ContractErrorAttr,
     item: &'a ItemImpl,
     generics: Vec<&'a GenericParam>,
-    custom: Custom<'a>,
-    override_entry_points: OverrideEntryPoints,
+    custom: Custom,
+    override_entry_points: Vec<OverrideEntryPoint>,
     interfaces: Interfaces,
 }
 
@@ -56,7 +59,9 @@ impl<'a> TraitInput<'a> {
             );
         }
 
-        let custom = Custom::new(&item.attrs);
+        let custom = ParsedSylviaAttributes::new(item.attrs.iter())
+            .custom_attr
+            .unwrap_or_default();
         let associated_types = AssociatedTypes::new(item);
 
         Self {
@@ -144,9 +149,10 @@ impl<'a> TraitInput<'a> {
 impl<'a> ImplInput<'a> {
     pub fn new(attributes: &'a ContractArgs, item: &'a ItemImpl) -> Self {
         let generics = item.generics.params.iter().collect();
-        let error = ContractErrorAttr::new(item);
-        let custom = Custom::new(&item.attrs);
-        let override_entry_points = OverrideEntryPoints::new(&item.attrs);
+        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 {
@@ -308,7 +314,8 @@ impl<'a> ImplInput<'a> {
         if is_trait(item) {
             ImplMtHelpers::new(item, generic_params, custom, interfaces, &contract_module).emit()
         } else {
-            ContractMtHelpers::new(item, generic_params, custom, override_entry_points).emit()
+            ContractMtHelpers::new(item, generic_params, custom, override_entry_points.clone())
+                .emit()
         }
     }
 }
diff --git a/sylvia-derive/src/interfaces.rs b/sylvia-derive/src/interfaces.rs
index fc542da..cbed77c 100644
--- a/sylvia-derive/src/interfaces.rs
+++ b/sylvia-derive/src/interfaces.rs
@@ -1,12 +1,12 @@
 use proc_macro2::{Ident, TokenStream};
 use proc_macro_error::emit_error;
 use quote::quote;
-use syn::parse::{Parse, Parser};
 use syn::spanned::Spanned;
 use syn::{GenericArgument, GenericParam, ItemImpl};
 
 use crate::crate_module;
-use crate::parser::{ContractMessageAttr, MsgType};
+use crate::parser::attributes::msg::MsgType;
+use crate::parser::{ContractMessageAttr, ParsedSylviaAttributes};
 
 #[derive(Debug, Default)]
 pub struct Interfaces {
@@ -15,27 +15,7 @@ pub struct Interfaces {
 
 impl Interfaces {
     pub fn new(source: &ItemImpl) -> Self {
-        let interfaces: Vec<_> = source
-            .attrs
-            .iter()
-            .filter(|attr| attr.path().is_ident("messages"))
-            .filter_map(|attr| {
-                let interface = match attr
-                    .meta
-                    .require_list()
-                    .and_then(|meta| ContractMessageAttr::parse.parse2(meta.tokens.clone()))
-                {
-                    Ok(interface) => interface,
-                    Err(err) => {
-                        emit_error!(attr.span(), err);
-                        return None;
-                    }
-                };
-
-                Some(interface)
-            })
-            .collect();
-
+        let interfaces = ParsedSylviaAttributes::new(source.attrs.iter()).messages_attrs;
         Self { interfaces }
     }
 
@@ -202,9 +182,9 @@ impl Interfaces {
                 let first = &interfaces[0];
                 for redefined in &interfaces[1..] {
                     emit_error!(
-                        redefined.module, "The attribute `messages` is redefined";
-                        note = first.module.span() => "Previous definition of the attribute `messsages`";
-                        note = "Only one `messages` attribute can exist on an interface implementation on contract"
+                        redefined.module, "The attribute `sv::messages` is redefined";
+                        note = first.module.span() => "Previous definition of the attribute `sv::messages`";
+                        note = "Only one `sv::messages` attribute can exist on an interface implementation on contract"
                     );
                 }
                 None
diff --git a/sylvia-derive/src/lib.rs b/sylvia-derive/src/lib.rs
index ebe0a7b..25a5a95 100644
--- a/sylvia-derive/src/lib.rs
+++ b/sylvia-derive/src/lib.rs
@@ -11,6 +11,7 @@ pub(crate) mod check_generics;
 mod input;
 mod interfaces;
 mod message;
+mod message_type;
 mod multitest;
 mod parser;
 mod querier;
@@ -65,17 +66,17 @@ pub(crate) fn crate_module() -> Path {
 /// trait Cw4 {
 ///     type Error: From<StdError>;
 ///
-///     #[msg(exec)]
+///     #[sv::msg(exec)]
 ///     fn update_admin(&self, ctx: (DepsMut, Env, MessageInfo), admin: Option<String>) -> Result<Response, Self::Error>;
 ///
-///     #[msg(exec)]
+///     #[sv::msg(exec)]
 ///     fn update_members(&self, ctx: (DepsMut, Env, MessageInfo), remove: Vec<String>, add: Vec<Member>)
 ///         -> Result<Response, Self::Error>;
 ///
-///     #[msg(query)]
+///     #[sv::msg(query)]
 ///     fn admin(&self, ctx: (Deps, Env)) -> Result<AdminQueryResponse, Error>;
 ///
-///     #[msg(query)]
+///     #[sv::msg(query)]
 ///     fn member(&self, ctx: (Deps, Env), addr: String, at_height: Option<u64>) -> Result<MemberQueryResponse, Error>;
 /// }
 /// ```
@@ -120,7 +121,7 @@ pub(crate) fn crate_module() -> Path {
 /// ## Attributes
 ///
 /// Messages structures are generated basing on interface trait method attributed with
-/// `#[msg(msg_type, ...)`. Msg attribute takes as its first argument type of message it is
+/// `#[sv::msg(msg_type, ...)`. Msg attribute takes as its first argument type of message it is
 /// supposed to handle:
 ///   * `exec` - this is execute message variant
 ///   * `query` - this is query message variant
@@ -130,11 +131,11 @@ pub(crate) fn crate_module() -> Path {
 /// Example for member query
 ///
 /// ```ignore
-///     #[msg(query, resp=MemberQueryResponse)]
+///     #[sv::msg(query, resp=MemberQueryResponse)]
 ///     fn member(&self, ctx: (Deps, Env), addr: String, at_height: Option<u64>) -> Result<MemberQueryResponse, Error>;
 /// ```
 ///
-/// For now `#[msg(...)]` attribute doesn't support anymore data on `#[interface]`
+/// For now `#[sv::msg(...)]` attribute doesn't support anymore data on `#[interface]`
 /// elements, but it may be extended in future.
 #[cfg(not(tarpaulin_include))]
 #[proc_macro_error]
@@ -174,7 +175,7 @@ fn interface_impl(_attr: TokenStream2, item: TokenStream2) -> TokenStream2 {
 ///
 /// #[cw_derive::contract(module=msg)]
 /// impl Cw4Group {
-///     #[msg(instantiate, name="Instantiate")]
+///     #[sv::msg(instantiate, name="Instantiate")]
 ///     fn instantiate(&self, ctx: (DepsMut, Env, MessageInfo), admin: Option<String>)
 ///         -> Result<Response, Error>;
 /// }
@@ -212,7 +213,7 @@ fn interface_impl(_attr: TokenStream2, item: TokenStream2) -> TokenStream2 {
 /// ## Attributes
 ///
 /// Messages structures are generated basing on specific implemented methods attributed with
-/// `#[msg(msg_type, ...)`. Msg attribute takes as its first argument type of message it is
+/// `#[sv::msg(msg_type, ...)`. Msg attribute takes as its first argument type of message it is
 /// supposed to handle:
 /// * `instantiate` - this is instantiation message handler. There should be always exactly one
 /// * `exec` - this is execute message variant
@@ -224,7 +225,7 @@ fn interface_impl(_attr: TokenStream2, item: TokenStream2) -> TokenStream2 {
 /// Example for member query
 ///
 /// ```ignore
-///     #[msg(query, resp=MemberQueryResponse)]
+///     #[sv::msg(query, resp=MemberQueryResponse)]
 ///     fn member(&self, ctx: (Deps, Env), addr: String, at_height: Option<u64>) -> Result<MemberQueryResponse, Error>
 /// ```
 #[cfg(not(tarpaulin_include))]
diff --git a/sylvia-derive/src/message.rs b/sylvia-derive/src/message.rs
index 0ed9212..43e69ac 100644
--- a/sylvia-derive/src/message.rs
+++ b/sylvia-derive/src/message.rs
@@ -3,8 +3,8 @@ use crate::check_generics::{CheckGenerics, GetPath};
 use crate::crate_module;
 use crate::interfaces::Interfaces;
 use crate::parser::{
-    parse_associated_custom_type, parse_struct_message, ContractErrorAttr, Custom, EntryPointArgs,
-    MsgAttr, MsgType, OverrideEntryPoints,
+    parse_associated_custom_type, ContractErrorAttr, Custom, EntryPointArgs,
+    FilteredOverrideEntryPoints, MsgAttr, MsgType, OverrideEntryPoint, ParsedSylviaAttributes,
 };
 use crate::strip_generics::StripGenerics;
 use crate::strip_self_path::{AddSelfPath, ReplaceAssociatedType, StripSelfPath};
@@ -19,13 +19,13 @@ use proc_macro2::{Span, TokenStream};
 use proc_macro_error::emit_error;
 use quote::{quote, ToTokens};
 use syn::fold::Fold;
-use syn::parse::{Parse, Parser};
 use syn::punctuated::Punctuated;
 use syn::spanned::Spanned;
 use syn::visit::Visit;
 use syn::{
-    parse_quote, Attribute, GenericArgument, GenericParam, Ident, ImplItemType, ItemImpl,
-    ItemTrait, Pat, PatType, ReturnType, Signature, Token, Type, WhereClause, WherePredicate,
+    parse_quote, Attribute, GenericArgument, GenericParam, Ident, ImplItem, ImplItemFn,
+    ImplItemType, ItemImpl, ItemTrait, Pat, PatType, ReturnType, Signature, Token, Type,
+    WhereClause, WherePredicate,
 };
 
 /// Representation of single struct message
@@ -39,7 +39,7 @@ pub struct StructMessage<'a> {
     full_where: Option<&'a WhereClause>,
     result: &'a ReturnType,
     msg_attr: MsgAttr,
-    custom: &'a Custom<'a>,
+    custom: &'a Custom,
 }
 
 impl<'a> StructMessage<'a> {
@@ -54,7 +54,7 @@ impl<'a> StructMessage<'a> {
 
         let contract_type = &source.self_ty;
 
-        let parsed = parse_struct_message(source, ty);
+        let parsed = Self::parse_struct_message(source, ty);
         let Some((method, msg_attr)) = parsed else {
             return None;
         };
@@ -78,6 +78,37 @@ impl<'a> StructMessage<'a> {
         })
     }
 
+    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(), "No instantiation message");
+            }
+            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::*;
 
@@ -274,7 +305,7 @@ pub struct ContractEnumMessage<'a> {
     msg_ty: MsgType,
     contract: &'a Type,
     error: &'a ContractErrorAttr,
-    custom: &'a Custom<'a>,
+    custom: &'a Custom,
     where_clause: &'a Option<WhereClause>,
 }
 
@@ -819,27 +850,16 @@ where
         let mut generics_checker = CheckGenerics::new(all_generics);
         let variants: Vec<_> = source
             .filter_map(|variant_desc| {
-                let msg_attr = variant_desc.attr_msg()?;
-                let attr = match msg_attr
-                    .meta
-                    .require_list()
-                    .and_then(|meta| MsgAttr::parse.parse2(meta.tokens.clone()))
-                {
-                    Ok(attr) => attr,
-                    Err(err) => {
-                        emit_error!(variant_desc.span(), err);
-                        return None;
-                    }
-                };
+                let msg_attr: MsgAttr = variant_desc.attr_msg()?;
 
-                if attr.msg_type() != msg_ty {
+                if msg_attr.msg_type() != msg_ty {
                     return None;
                 }
 
                 Some(MsgVariant::new(
                     variant_desc.into_sig(),
                     &mut generics_checker,
-                    attr,
+                    msg_attr,
                 ))
             })
             .collect();
@@ -1065,7 +1085,7 @@ impl<'a> MsgField<'a> {
                 // Eg.
                 //
                 // ```
-                // fn exec_foo(&self, ctx: Ctx, #[msg(name=metadata)] SomeData { addr, sender }: SomeData);
+                // fn exec_foo(&self, ctx: Ctx, #[sv::msg(name=metadata)] SomeData { addr, sender }: SomeData);
                 // ```
                 //
                 // should expand to enum variant:
@@ -1155,7 +1175,7 @@ pub struct GlueMessage<'a> {
     contract: &'a Type,
     msg_ty: MsgType,
     error: &'a ContractErrorAttr,
-    custom: &'a Custom<'a>,
+    custom: &'a Custom,
     interfaces: &'a Interfaces,
     variants: MsgVariants<'a, GenericParam>,
 }
@@ -1367,7 +1387,7 @@ pub struct ContractApi<'a> {
     migrate_variants: MsgVariants<'a, GenericParam>,
     sudo_variants: MsgVariants<'a, GenericParam>,
     generics: &'a [&'a GenericParam],
-    custom: &'a Custom<'a>,
+    custom: &'a Custom,
     interfaces: &'a Interfaces,
 }
 
@@ -1375,7 +1395,7 @@ impl<'a> ContractApi<'a> {
     pub fn new(
         source: &'a ItemImpl,
         generics: &'a [&'a GenericParam],
-        custom: &'a Custom<'a>,
+        custom: &'a Custom,
         interfaces: &'a Interfaces,
     ) -> Self {
         let exec_variants = MsgVariants::new(
@@ -1502,7 +1522,7 @@ impl<'a> ContractApi<'a> {
 
 pub struct InterfaceApi<'a> {
     source: &'a ItemTrait,
-    custom: &'a Custom<'a>,
+    custom: &'a Custom,
     associated_types: &'a AssociatedTypes<'a>,
 }
 
@@ -1510,7 +1530,7 @@ impl<'a> InterfaceApi<'a> {
     pub fn new(
         source: &'a ItemTrait,
         associated_types: &'a AssociatedTypes<'a>,
-        custom: &'a Custom<'a>,
+        custom: &'a Custom,
     ) -> Self {
         Self {
             source,
@@ -1588,41 +1608,24 @@ pub struct EntryPoints<'a> {
     source: &'a ItemImpl,
     name: Type,
     error: Type,
-    custom: Custom<'a>,
-    override_entry_points: OverrideEntryPoints,
+    custom: Custom,
+    override_entry_points: Vec<OverrideEntryPoint>,
     generics: Vec<&'a GenericParam>,
     where_clause: &'a Option<WhereClause>,
-    attrs: EntryPointArgs<'a>,
+    attrs: EntryPointArgs,
 }
 
 impl<'a> EntryPoints<'a> {
-    pub fn new(source: &'a ItemImpl, attrs: EntryPointArgs<'a>) -> Self {
-        let sylvia = crate_module();
+    pub fn new(source: &'a ItemImpl, attrs: EntryPointArgs) -> Self {
         let name = StripGenerics.fold_type(*source.self_ty.clone());
-        let override_entry_points = OverrideEntryPoints::new(&source.attrs);
+        let parsed_attrs = ParsedSylviaAttributes::new(source.attrs.iter());
+        let override_entry_points = parsed_attrs.override_entry_point_attrs;
 
-        let error = source
-            .attrs
-            .iter()
-            .find(|attr| attr.path().is_ident("error"))
-            .and_then(|attr| {
-                match attr
-                    .meta
-                    .require_list()
-                    .and_then(|meta| ContractErrorAttr::parse.parse2(meta.tokens.clone()))
-                {
-                    Ok(error) => Some(error.error),
-                    Err(err) => {
-                        emit_error!(attr.span(), err);
-                        None
-                    }
-                }
-            })
-            .unwrap_or_else(|| parse_quote! { #sylvia ::cw_std::StdError });
+        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 custom = Custom::new(&source.attrs);
+        let custom = parsed_attrs.custom_attr.unwrap_or_default();
 
         Self {
             source,
@@ -1725,8 +1728,7 @@ impl<'a> EntryPoints<'a> {
                 quote! {}
             };
 
-            let reply_ep = override_entry_points
-                .get_entry_point(MsgType::Reply)
+            let reply_ep = override_entry_points.get_entry_point(MsgType::Reply)
                 .map(|_| quote! {})
                 .unwrap_or_else(|| match reply {
                     Some(reply) => quote! {
diff --git a/sylvia-derive/src/message_type.rs b/sylvia-derive/src/message_type.rs
new file mode 100644
index 0000000..30b9307
--- /dev/null
+++ b/sylvia-derive/src/message_type.rs
@@ -0,0 +1,166 @@
+use proc_macro2::TokenStream;
+use quote::quote;
+use syn::{parse_quote, GenericParam, Ident, Type};
+
+use crate::crate_module;
+use crate::parser::attributes::msg::MsgType;
+use crate::parser::Customs;
+
+impl MsgType {
+    pub fn emit_ctx_type(self, query_type: &Type) -> TokenStream {
+        use MsgType::*;
+
+        let sylvia = crate_module();
+
+        match self {
+            Exec | Instantiate => quote! {
+                (#sylvia ::cw_std::DepsMut< #query_type >, #sylvia ::cw_std::Env, #sylvia ::cw_std::MessageInfo)
+            },
+            Migrate | Reply | Sudo => quote! {
+                (#sylvia ::cw_std::DepsMut< #query_type >, #sylvia ::cw_std::Env)
+            },
+            Query => quote! {
+                (#sylvia ::cw_std::Deps< #query_type >, #sylvia ::cw_std::Env)
+            },
+        }
+    }
+
+    pub fn emit_ctx_dispatch_values(self, customs: &Customs) -> TokenStream {
+        use MsgType::*;
+
+        match (self, customs.has_query) {
+            (Exec, true) => quote! {
+                (ctx.0.into_empty(), ctx.1, ctx.2)
+            },
+            (Query, true) | (Sudo, true) => quote! {
+                (ctx.0.into_empty(), ctx.1)
+            },
+            _ => quote! { ctx },
+        }
+    }
+
+    #[cfg(not(tarpaulin_include))]
+    pub fn emit_ctx_params(self, query_type: &Type) -> TokenStream {
+        use MsgType::*;
+
+        let sylvia = crate_module();
+
+        match self {
+            Exec | Instantiate => quote! {
+                deps: #sylvia ::cw_std::DepsMut< #query_type>, env: #sylvia ::cw_std::Env, info: #sylvia ::cw_std::MessageInfo
+            },
+            Migrate | Reply | Sudo => quote! {
+                deps: #sylvia ::cw_std::DepsMut< #query_type>, env: #sylvia ::cw_std::Env
+            },
+            Query => quote! {
+                deps: #sylvia ::cw_std::Deps< #query_type>, env: #sylvia ::cw_std::Env
+            },
+        }
+    }
+
+    #[cfg(not(tarpaulin_include))]
+    pub fn emit_ep_name(self) -> Ident {
+        match self {
+            Self::Exec => parse_quote! { execute },
+            Self::Instantiate => parse_quote! { instantiate },
+            Self::Migrate => parse_quote! { migrate },
+            Self::Sudo => parse_quote! { sudo },
+            Self::Reply => parse_quote! { reply },
+            Self::Query => parse_quote! { query },
+        }
+    }
+
+    pub fn emit_ctx_values(self) -> TokenStream {
+        use MsgType::*;
+
+        match self {
+            Exec | Instantiate => quote! { deps, env, info },
+            Migrate | Reply | Query | Sudo => quote! { deps, env },
+        }
+    }
+
+    /// Emits type which should be returned by dispatch function for this kind of message
+    pub fn emit_result_type(self, msg_type: &Type, err_type: &Type) -> TokenStream {
+        use MsgType::*;
+
+        let sylvia = crate_module();
+
+        match self {
+            Exec | Instantiate | Migrate | Reply | Sudo => {
+                quote! {
+                    std::result::Result< #sylvia:: cw_std::Response <#msg_type>, #err_type>
+                }
+            }
+            Query => quote! {
+                std::result::Result<#sylvia ::cw_std::Binary, #err_type>
+            },
+        }
+    }
+
+    pub fn emit_msg_wrapper_name(&self) -> Ident {
+        match self {
+            MsgType::Exec => parse_quote! { ContractExecMsg },
+            MsgType::Query => parse_quote! { ContractQueryMsg },
+            MsgType::Sudo => parse_quote! { ContractSudoMsg },
+            _ => self.emit_msg_name(),
+        }
+    }
+
+    pub fn emit_msg_name(&self) -> Ident {
+        match self {
+            MsgType::Exec => parse_quote! { ExecMsg },
+            MsgType::Query => parse_quote! { QueryMsg },
+            MsgType::Instantiate => parse_quote! { InstantiateMsg },
+            MsgType::Migrate => parse_quote! { MigrateMsg },
+            MsgType::Reply => parse_quote! { ReplyMsg },
+            MsgType::Sudo => parse_quote! { SudoMsg },
+        }
+    }
+
+    pub fn as_accessor_wrapper_name(&self) -> Type {
+        match self {
+            MsgType::Exec => parse_quote! { ContractExec },
+            MsgType::Query => parse_quote! { ContractQuery },
+            MsgType::Sudo => parse_quote! { ContractSudo },
+            _ => self.as_accessor_name(),
+        }
+    }
+
+    pub fn as_accessor_name(&self) -> Type {
+        match self {
+            MsgType::Instantiate => parse_quote! { Instantiate },
+            MsgType::Exec => parse_quote! { Exec },
+            MsgType::Query => parse_quote! { Query },
+            MsgType::Migrate => parse_quote! { Migrate },
+            MsgType::Sudo => parse_quote! { Sudo },
+            MsgType::Reply => parse_quote! { Reply },
+        }
+    }
+
+    pub fn emit_phantom_variant(&self, generics: &[&GenericParam]) -> TokenStream {
+        match self {
+            _ if generics.is_empty() => quote! {},
+            MsgType::Query => quote! {
+                #[serde(skip)]
+                #[returns(( #(#generics,)* ))]
+                _Phantom(std::marker::PhantomData<( #(#generics,)* )>),
+            },
+            _ => quote! {
+                #[serde(skip)]
+                _Phantom(std::marker::PhantomData<( #(#generics,)* )>),
+            },
+        }
+    }
+
+    pub fn emit_derive_call(&self) -> TokenStream {
+        let sylvia = crate_module();
+        match self {
+            MsgType::Query => quote! {
+                #[derive(#sylvia ::serde::Serialize, #sylvia ::serde::Deserialize, Clone, Debug, PartialEq, #sylvia ::schemars::JsonSchema, #sylvia:: cw_schema::QueryResponses)]
+            },
+            _ => quote! {
+                #[derive(#sylvia ::serde::Serialize, #sylvia ::serde::Deserialize, Clone, Debug, PartialEq, #sylvia ::schemars::JsonSchema)]
+            },
+        }
+    }
+}
diff --git a/sylvia-derive/src/parser.rs b/sylvia-derive/src/parser.rs
deleted file mode 100644
index ea25d53..0000000
--- a/sylvia-derive/src/parser.rs
+++ /dev/null
@@ -1,757 +0,0 @@
-use convert_case::{Case, Casing};
-use proc_macro2::{Punct, TokenStream};
-use proc_macro_error::{emit_error, emit_warning};
-use quote::quote;
-use syn::fold::Fold;
-use syn::parse::{Error, Nothing, Parse, ParseBuffer, ParseStream, Parser};
-use syn::punctuated::Punctuated;
-use syn::spanned::Spanned;
-use syn::{
-    parenthesized, parse_quote, Attribute, GenericArgument, GenericParam, Ident, ImplItem,
-    ImplItemFn, ItemImpl, ItemTrait, Path, PathArguments, Result, Token, TraitItem, Type,
-};
-
-use crate::crate_module;
-use crate::strip_generics::StripGenerics;
-
-/// Parsed arguments for `contract` macro
-pub struct ContractArgs {
-    /// Module in which contract impl block is defined.
-    /// Used only while implementing `Interface` on `Contract`.
-    pub module: Option<Path>,
-}
-
-impl Parse for ContractArgs {
-    fn parse(input: ParseStream) -> Result<Self> {
-        let mut module = None;
-
-        while !input.is_empty() {
-            let attr: Ident = input.parse()?;
-            let _: Token![=] = input.parse()?;
-
-            if attr == "module" {
-                module = Some(input.parse()?);
-            } else {
-                return Err(Error::new(attr.span(), "expected `module`"));
-            }
-
-            if input.peek(Token![,]) {
-                let _: Token![,] = input.parse()?;
-            } else if !input.is_empty() {
-                return Err(input.error("Unexpected token, comma expected"));
-            }
-        }
-
-        let _: Nothing = input.parse()?;
-
-        Ok(ContractArgs { module })
-    }
-}
-
-/// Parsed arguments for `entry_points` macro
-#[derive(Default)]
-pub struct EntryPointArgs<'a> {
-    /// Types used in place of contracts generics.
-    pub generics: Option<Punctuated<GenericArgument, Token![,]>>,
-    /// Concrete custom msg/query used in place of contracts generic ones.
-    pub custom: Option<Custom<'a>>,
-}
-
-impl<'a> Parse for EntryPointArgs<'a> {
-    fn parse(input: ParseStream) -> Result<Self> {
-        let mut entry_points_args = Self::default();
-        if input.is_empty() {
-            return Ok(entry_points_args);
-        }
-
-        let generics: Path = input.parse()?;
-        match generics.segments.last() {
-            Some(segment) if segment.ident == "generics" => {
-                entry_points_args.generics = Some(extract_generics_from_path(&generics))
-            }
-            _ => return Err(Error::new(generics.span(), "Expected `generics`.")),
-        };
-
-        let comma: Option<Token![,]> = input.parse().ok();
-        if comma.is_none() {
-            return Ok(entry_points_args);
-        }
-
-        let custom: Option<Path> = input.parse().ok();
-        match custom {
-            Some(custom)
-                if custom.get_ident().map(|custom| custom.to_string())
-                    == Some("custom".to_owned()) =>
-            {
-                let content;
-                parenthesized!(content in input);
-                entry_points_args.custom = Some(Custom::parse.parse2(content.parse()?)?);
-            }
-            Some(attr) => return Err(Error::new(attr.span(), "Expected `custom`.")),
-            _ => (),
-        };
-
-        let _: Nothing = input.parse()?;
-
-        Ok(entry_points_args)
-    }
-}
-
-/// Type of message to be generated
-#[derive(PartialEq, Eq, Debug, Clone, Copy)]
-pub enum MsgType {
-    Exec,
-    Query,
-    Instantiate,
-    Migrate,
-    Reply,
-    Sudo,
-}
-
-/// `#[msg(...)]` attribute for `interface` macro
-pub enum MsgAttr {
-    Exec,
-    Query { resp_type: Option<Ident> },
-    Instantiate { name: Ident },
-    Migrate { name: Ident },
-    Reply,
-    Sudo,
-}
-
-impl MsgType {
-    pub fn emit_ctx_type(self, query_type: &Type) -> TokenStream {
-        use MsgType::*;
-
-        let sylvia = crate_module();
-
-        match self {
-            Exec | Instantiate => quote! {
-                (#sylvia ::cw_std::DepsMut< #query_type >, #sylvia ::cw_std::Env, #sylvia ::cw_std::MessageInfo)
-            },
-            Migrate | Reply | Sudo => quote! {
-                (#sylvia ::cw_std::DepsMut< #query_type >, #sylvia ::cw_std::Env)
-            },
-            Query => quote! {
-                (#sylvia ::cw_std::Deps< #query_type >, #sylvia ::cw_std::Env)
-            },
-        }
-    }
-
-    #[cfg(not(tarpaulin_include))]
-    pub fn emit_ctx_params(self, query_type: &Type) -> TokenStream {
-        use MsgType::*;
-
-        let sylvia = crate_module();
-
-        match self {
-            Exec | Instantiate => quote! {
-                deps: #sylvia ::cw_std::DepsMut< #query_type>, env: #sylvia ::cw_std::Env, info: #sylvia ::cw_std::MessageInfo
-            },
-            Migrate | Reply | Sudo => quote! {
-                deps: #sylvia ::cw_std::DepsMut< #query_type>, env: #sylvia ::cw_std::Env
-            },
-            Query => quote! {
-                deps: #sylvia ::cw_std::Deps< #query_type>, env: #sylvia ::cw_std::Env
-            },
-        }
-    }
-
-    #[cfg(not(tarpaulin_include))]
-    pub fn emit_ep_name(self) -> Ident {
-        use MsgType::*;
-
-        match self {
-            Exec => parse_quote! { execute },
-            Instantiate => parse_quote! { instantiate },
-            Migrate => parse_quote! { migrate },
-            Sudo => parse_quote! { sudo },
-            Reply => parse_quote! { reply },
-            Query => parse_quote! { query },
-        }
-    }
-
-    pub fn emit_ctx_values(self) -> TokenStream {
-        use MsgType::*;
-
-        match self {
-            Exec | Instantiate => quote! { deps, env, info },
-            Migrate | Reply | Query | Sudo => quote! { deps, env },
-        }
-    }
-
-    pub fn emit_ctx_dispatch_values(self, customs: &Customs) -> TokenStream {
-        use MsgType::*;
-
-        match (self, customs.has_query) {
-            (Exec, true) => quote! {
-                (ctx.0.into_empty(), ctx.1, ctx.2)
-            },
-            (Query, true) | (Sudo, true) => quote! {
-                (ctx.0.into_empty(), ctx.1)
-            },
-            _ => quote! { ctx },
-        }
-    }
-
-    /// Emits type which should be returned by dispatch function for this kind of message
-    pub fn emit_result_type(self, msg_type: &Type, err_type: &Type) -> TokenStream {
-        use MsgType::*;
-
-        let sylvia = crate_module();
-
-        match self {
-            Exec | Instantiate | Migrate | Reply | Sudo => {
-                quote! {
-                    std::result::Result< #sylvia:: cw_std::Response <#msg_type>, #err_type>
-                }
-            }
-            Query => quote! {
-                std::result::Result<#sylvia ::cw_std::Binary, #err_type>
-            },
-        }
-    }
-
-    pub fn emit_msg_wrapper_name(&self) -> Ident {
-        match self {
-            MsgType::Exec => parse_quote! { ContractExecMsg },
-            MsgType::Query => parse_quote! { ContractQueryMsg },
-            MsgType::Sudo => parse_quote! { ContractSudoMsg },
-            _ => self.emit_msg_name(),
-        }
-    }
-
-    pub fn emit_msg_name(&self) -> Ident {
-        match self {
-            MsgType::Exec => parse_quote! { ExecMsg },
-            MsgType::Query => parse_quote! { QueryMsg },
-            MsgType::Instantiate => parse_quote! { InstantiateMsg },
-            MsgType::Migrate => parse_quote! { MigrateMsg },
-            MsgType::Reply => parse_quote! { ReplyMsg },
-            MsgType::Sudo => parse_quote! { SudoMsg },
-        }
-    }
-
-    pub fn as_accessor_wrapper_name(&self) -> Type {
-        match self {
-            MsgType::Exec => parse_quote! { ContractExec },
-            MsgType::Query => parse_quote! { ContractQuery },
-            MsgType::Sudo => parse_quote! { ContractSudo },
-            _ => self.as_accessor_name(),
-        }
-    }
-
-    pub fn as_accessor_name(&self) -> Type {
-        match self {
-            MsgType::Instantiate => parse_quote! { Instantiate },
-            MsgType::Exec => parse_quote! { Exec },
-            MsgType::Query => parse_quote! { Query },
-            MsgType::Migrate => parse_quote! { Migrate },
-            MsgType::Sudo => parse_quote! { Sudo },
-            MsgType::Reply => parse_quote! { Reply },
-        }
-    }
-
-    pub fn emit_phantom_variant(&self, generics: &[&GenericParam]) -> TokenStream {
-        match self {
-            _ if generics.is_empty() => quote! {},
-            MsgType::Query => quote! {
-                #[serde(skip)]
-                #[returns(( #(#generics,)* ))]
-                _Phantom(std::marker::PhantomData<( #(#generics,)* )>),
-            },
-            _ => quote! {
-                #[serde(skip)]
-                _Phantom(std::marker::PhantomData<( #(#generics,)* )>),
-            },
-        }
-    }
-
-    pub fn emit_derive_call(&self) -> TokenStream {
-        let sylvia = crate_module();
-        match self {
-            MsgType::Query => quote! {
-                #[derive(#sylvia ::serde::Serialize, #sylvia ::serde::Deserialize, Clone, Debug, PartialEq, #sylvia ::schemars::JsonSchema, #sylvia:: cw_schema::QueryResponses)]
-            },
-            _ => quote! {
-                #[derive(#sylvia ::serde::Serialize, #sylvia ::serde::Deserialize, Clone, Debug, PartialEq, #sylvia ::schemars::JsonSchema)]
-            },
-        }
-    }
-}
-
-impl PartialEq<MsgType> for MsgAttr {
-    fn eq(&self, other: &MsgType) -> bool {
-        self.msg_type() == *other
-    }
-}
-
-impl MsgAttr {
-    fn parse_query(content: &ParseBuffer) -> Result<Self> {
-        if content.peek2(Ident) {
-            let _: Punct = content.parse()?;
-            let _: Ident = content.parse()?;
-            let _: Punct = content.parse()?;
-            let resp_type: Option<Ident> = Some(content.parse()?);
-            Ok(Self::Query { resp_type })
-        } else {
-            Ok(Self::Query { resp_type: None })
-        }
-    }
-
-    pub fn msg_type(&self) -> MsgType {
-        use MsgAttr::*;
-
-        match self {
-            Exec => MsgType::Exec,
-            Query { .. } => MsgType::Query,
-            Instantiate { .. } => MsgType::Instantiate,
-            Migrate { .. } => MsgType::Migrate,
-            Reply => MsgType::Reply,
-            Sudo => MsgType::Sudo,
-        }
-    }
-}
-
-impl Parse for MsgAttr {
-    fn parse(input: ParseStream) -> Result<Self> {
-        let ty: Ident = input.parse()?;
-
-        if ty == "exec" {
-            Ok(Self::Exec)
-        } else if ty == "query" {
-            Self::parse_query(input)
-        } else if ty == "instantiate" {
-            let name = Ident::new("InstantiateMsg", input.span());
-            Ok(Self::Instantiate { name })
-        } else if ty == "migrate" {
-            let name = Ident::new("MigrateMsg", input.span());
-            Ok(Self::Migrate { name })
-        } else if ty == "reply" {
-            Ok(Self::Reply)
-        } else if ty == "sudo" {
-            Ok(Self::Sudo)
-        } else {
-            Err(Error::new(
-                ty.span(),
-                "Invalid message type, expected one of: `exec`, `query`, `instantiate`, `migrate`, `reply` or `sudo`.",
-            ))
-        }
-    }
-}
-
-#[derive(Debug)]
-pub struct ContractErrorAttr {
-    pub error: Type,
-}
-
-impl ContractErrorAttr {
-    pub fn new(item: &ItemImpl) -> Self {
-        let sylvia = crate_module();
-
-        item.attrs
-            .iter()
-            .find(|attr| attr.path().is_ident("error"))
-            .and_then(|attr| {
-                match attr
-                    .meta
-                    .require_list()
-                    .and_then(|meta| ContractErrorAttr::parse.parse2(meta.tokens.clone()))
-                {
-                    Ok(error) => Some(error),
-                    Err(err) => {
-                        emit_error!(attr.span(), err);
-                        None
-                    }
-                }
-            })
-            .unwrap_or_else(|| {
-                parse_quote! { #sylvia ::cw_std::StdError }
-            })
-    }
-}
-
-#[cfg(not(tarpaulin_include))]
-// False negative. It is being called in closure
-impl Parse for ContractErrorAttr {
-    fn parse(input: ParseStream) -> Result<Self> {
-        input.parse().map(|error| Self { error })
-    }
-}
-
-#[derive(Debug)]
-pub struct Customs {
-    pub has_msg: bool,
-    pub has_query: bool,
-}
-
-#[derive(Debug)]
-pub struct ContractMessageAttr {
-    pub module: Path,
-    pub variant: Ident,
-    pub customs: Customs,
-    pub generics: Punctuated<GenericArgument, Token![,]>,
-}
-
-fn interface_has_custom(content: ParseStream) -> Result<Customs> {
-    let mut customs = Customs {
-        has_msg: false,
-        has_query: false,
-    };
-
-    if !content.peek(Token![:]) {
-        return Ok(customs);
-    }
-
-    let _: Token![:] = content.parse()?;
-    let attr: Ident = content.parse()?;
-    if attr != "custom" {
-        return Ok(customs);
-    }
-
-    let custom_content;
-    parenthesized!(custom_content in content);
-
-    while !custom_content.is_empty() {
-        let custom = custom_content.parse::<Path>()?;
-        match custom.get_ident() {
-            Some(ident) if ident == "msg" => customs.has_msg = true,
-            Some(ident) if ident == "query" => customs.has_query = true,
-            _ => {
-                return Err(Error::new(
-                    custom.span(),
-                    "Invalid custom attribute, expected one of: `msg`, `query`",
-                ))
-            }
-        }
-        if !custom_content.peek(Token![,]) {
-            break;
-        }
-        let _: Token![,] = custom_content.parse()?;
-    }
-    Ok(customs)
-}
-
-fn extract_generics_from_path(module: &Path) -> Punctuated<GenericArgument, Token![,]> {
-    let generics = module.segments.last().map(|segment| {
-        match segment.arguments.clone(){
-            PathArguments::AngleBracketed(generics) => {
-                generics.args
-            },
-            PathArguments::None => Default::default(),
-            PathArguments::Parenthesized(generics) => {
-                emit_error!(
-                    generics.span(), "Found paranthesis wrapping generics in `messages` attribute.";
-                    note = "Expected `messages` attribute to be in form `#[messages(Path<generics> as Type)]`"
-                );
-               Default::default()
-            }
-        }
-    }).unwrap_or_default();
-
-    generics
-}
-
-#[cfg(not(tarpaulin_include))]
-// False negative. It is being called in closure
-impl Parse for ContractMessageAttr {
-    fn parse(input: ParseStream) -> Result<Self> {
-        let module = input.parse()?;
-        let generics = extract_generics_from_path(&module);
-        let module = StripGenerics.fold_path(module);
-
-        let variant = if input.parse::<Token![as]>().is_ok() {
-            let variant: Ident = input.parse()?;
-            if Some(variant.to_string())
-                == module
-                    .segments
-                    .last()
-                    .map(|name| name.ident.to_string().to_case(Case::UpperCamel))
-            {
-                emit_warning!(
-                    variant.span(), "Redundant `as {}`.", variant;
-                    note = "Interface name is a camel case version of the path and can be auto deduced."
-                )
-            }
-            variant
-        } else if let Some(module_name) = &module.segments.last() {
-            let interface_name = module_name.ident.to_string().to_case(Case::UpperCamel);
-            syn::Ident::new(&interface_name, module.span())
-        } else {
-            Ident::new("", module.span())
-        };
-        let customs = interface_has_custom(input)?;
-        if !input.is_empty() {
-            return Err(Error::new(
-                input.span(),
-                "Unexpected token on the end of `messages` attribtue",
-            ));
-        }
-        Ok(Self {
-            module,
-            variant,
-            customs,
-            generics,
-        })
-    }
-}
-
-pub 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 msg_attr = method
-                .attrs
-                .iter()
-                .find(|attr| attr.path().is_ident("msg"))?;
-
-            let attr = match msg_attr
-                .meta
-                .require_list()
-                .and_then(|meta| MsgAttr::parse.parse2(meta.tokens.clone()))
-            {
-                Ok(attr) => attr,
-                Err(err) => {
-                    emit_error!(method.span(), err);
-                    return None;
-                }
-            };
-
-            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(), "No instantiation message");
-        }
-        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 parse_associated_custom_type(source: &ItemTrait, type_name: &str) -> Option<Type> {
-    let trait_name = &source.ident;
-    source.items.iter().find_map(|item| match item {
-        TraitItem::Type(ty) if ty.ident == type_name => {
-            let type_name = Ident::new(type_name, ty.span());
-            Some(parse_quote! { <ContractT as #trait_name>:: #type_name})
-        }
-        _ => None,
-    })
-}
-
-#[derive(Debug, Default)]
-pub struct Custom<'a> {
-    msg: Option<Type>,
-    query: Option<Type>,
-    input_attr: Option<&'a Attribute>,
-}
-
-impl<'a> Custom<'a> {
-    pub fn new(attrs: &'a [Attribute]) -> Self {
-        let mut customs = attrs
-            .iter()
-            .filter(|attr| match sylvia_attribute(attr) {
-                Some(attr) => attr == "custom",
-                None => false,
-            })
-            .filter_map(|attr| {
-                let custom = match attr
-                    .meta
-                    .require_list()
-                    .and_then(|meta| Custom::parse.parse2(meta.tokens.clone()))
-                {
-                    Ok(mut custom) => {
-                        custom.input_attr = Some(attr);
-                        custom
-                    }
-                    Err(err) => {
-                        emit_error!(attr.span(), err);
-                        return None;
-                    }
-                };
-
-                Some(custom)
-            });
-
-        let custom = customs.next().unwrap_or_default();
-
-        for redefined in customs {
-            let redefined = redefined.input_attr.unwrap();
-            emit_error!(
-              redefined, "The attribute `custom` is redefined";
-              note = custom.input_attr.span() => "Previous definition of the attribute `custom`";
-              note = "Only one `custom` attribute can exist on a single sylvia entity"
-            );
-        }
-
-        custom
-    }
-
-    pub fn msg_or_default(&self) -> Type {
-        self.msg.clone().unwrap_or_else(Self::default_type)
-    }
-
-    pub fn query_or_default(&self) -> Type {
-        self.query.clone().unwrap_or_else(Self::default_type)
-    }
-
-    pub fn msg(&self) -> Option<Type> {
-        self.msg.clone()
-    }
-
-    pub fn query(&self) -> Option<Type> {
-        self.query.clone()
-    }
-
-    pub fn default_type() -> Type {
-        let sylvia = crate_module();
-        parse_quote! { #sylvia ::cw_std::Empty }
-    }
-}
-
-#[cfg(not(tarpaulin_include))]
-// False negative. It is being called in closure
-impl Parse for Custom<'_> {
-    fn parse(input: ParseStream) -> Result<Self> {
-        let mut custom = Self::default();
-
-        while !input.is_empty() {
-            let ty: Ident = input.parse()?;
-            let _: Token![=] = input.parse()?;
-            if ty == "msg" {
-                custom.msg = Some(input.parse()?)
-            } else if ty == "query" {
-                custom.query = Some(input.parse()?)
-            } else {
-                return Err(Error::new(
-                    ty.span(),
-                    "Invalid custom type. Expected msg or query",
-                ));
-            };
-            if !input.peek(Token![,]) {
-                break;
-            }
-            let _: Token![,] = input.parse()?;
-        }
-
-        Ok(custom)
-    }
-}
-
-#[derive(Debug)]
-pub struct OverrideEntryPoint {
-    entry_point: Path,
-    msg_name: Type,
-    msg_type: MsgType,
-}
-
-impl OverrideEntryPoint {
-    pub fn emit_multitest_dispatch(&self) -> TokenStream {
-        let Self {
-            entry_point,
-            msg_name,
-            msg_type,
-            ..
-        } = self;
-
-        let sylvia = crate_module();
-        let values = msg_type.emit_ctx_values();
-
-        quote! {
-            #entry_point ( #values .into(), #sylvia ::cw_std::from_json::< #msg_name >(&msg)?)
-                .map_err(Into::into)
-        }
-    }
-}
-
-#[derive(Debug)]
-pub struct OverrideEntryPoints(Vec<OverrideEntryPoint>);
-
-impl OverrideEntryPoints {
-    pub fn new(attrs: &[Attribute]) -> Self {
-        let entry_points = attrs
-            .iter()
-            .filter(|attr| match sylvia_attribute(attr) {
-                Some(attr) => attr == "override_entry_point",
-                None => false,
-            })
-            .filter_map(|attr| {
-                match attr
-                    .meta
-                    .require_list()
-                    .and_then(|meta| OverrideEntryPoint::parse.parse2(meta.tokens.clone()))
-                {
-                    Ok(entry_point) => Some(entry_point),
-                    Err(err) => {
-                        emit_error!(attr.span(), err);
-                        None
-                    }
-                }
-            })
-            .collect();
-
-        Self(entry_points)
-    }
-
-    pub fn get_entry_point(&self, ty: MsgType) -> Option<&OverrideEntryPoint> {
-        self.0.iter().find(|entry_point| entry_point.msg_type == ty)
-    }
-}
-
-#[cfg(not(tarpaulin_include))]
-// False negative. It is being called in closure
-impl Parse for OverrideEntryPoint {
-    fn parse(input: ParseStream) -> Result<Self> {
-        let ty: Ident = input.parse()?;
-        let _: Token![=] = input.parse()?;
-        let entry_point = input.parse()?;
-
-        let msg_content;
-        parenthesized!(msg_content in input);
-
-        let msg_name = msg_content.parse()?;
-
-        let msg_type = match ty.to_string().as_str() {
-            "exec" =>  MsgType::Exec,
-            "instantiate" =>  MsgType::Instantiate,
-            "query" =>  MsgType::Instantiate,
-            "migrate" => MsgType::Migrate,
-            "reply" => MsgType::Reply,
-            "sudo" =>  MsgType::Sudo,
-            &_ => {
-                return Err(Error::new(
-                    ty.span(),
-                    "Invalid entry point. Expected exec, instantiate, query, migrate, reply or sudo. Found {ty}",
-                ))
-            }
-        };
-
-        Ok(Self {
-            entry_point,
-            msg_name,
-            msg_type,
-        })
-    }
-}
-
-pub fn sylvia_attribute(attr: &Attribute) -> Option<&Ident> {
-    if attr.path().segments.len() == 2 && attr.path().segments[0].ident == "sv" {
-        Some(&attr.path().segments[1].ident)
-    } else {
-        None
-    }
-}
diff --git a/sylvia-derive/src/parser/attributes/custom.rs b/sylvia-derive/src/parser/attributes/custom.rs
new file mode 100644
index 0000000..a809c87
--- /dev/null
+++ b/sylvia-derive/src/parser/attributes/custom.rs
@@ -0,0 +1,74 @@
+use proc_macro_error::emit_error;
+use syn::parse::{Error, Parse, ParseStream, Parser};
+use syn::spanned::Spanned;
+use syn::{parse_quote, Attribute, Ident, Result, Token, Type};
+
+use crate::crate_module;
+
+#[derive(Debug, Default)]
+pub struct Custom {
+    msg: Option<Type>,
+    query: Option<Type>,
+}
+
+impl Custom {
+    pub fn new(attr: &Attribute) -> Result<Self> {
+        attr.meta
+            .require_list()
+            .and_then(|meta| Custom::parse.parse2(meta.tokens.clone()))
+            .map_err(|err| {
+                emit_error!(attr.span(), err);
+                err
+            })
+    }
+
+    pub fn msg_or_default(&self) -> Type {
+        self.msg.clone().unwrap_or_else(Self::default_type)
+    }
+
+    pub fn query_or_default(&self) -> Type {
+        self.query.clone().unwrap_or_else(Self::default_type)
+    }
+
+    pub fn msg(&self) -> Option<Type> {
+        self.msg.clone()
+    }
+
+    pub fn query(&self) -> Option<Type> {
+        self.query.clone()
+    }
+
+    pub fn default_type() -> Type {
+        let sylvia = crate_module();
+        parse_quote! { #sylvia ::cw_std::Empty }
+    }
+}
+
+#[cfg(not(tarpaulin_include))]
+// False negative. It is being called in closure
+impl Parse for Custom {
+    fn parse(input: ParseStream) -> Result<Self> {
+        let mut custom = Self::default();
+
+        while !input.is_empty() {
+            let ty: Ident = input.parse()?;
+            let _: Token![=] = input.parse()?;
+            if ty == "msg" {
+                custom.msg = Some(input.parse()?)
+            } else if ty == "query" {
+                custom.query = Some(input.parse()?)
+            } else {
+                return Err(Error::new(
+                    ty.span(),
+                    "Invalid custom type. Expected msg or query",
+                ));
+            };
+            if !input.peek(Token![,]) {
+                break;
+            }
+            let _: Token![,] = input.parse()?;
+        }
+
+        Ok(custom)
+    }
+}
diff --git a/sylvia-derive/src/parser/attributes/error.rs b/sylvia-derive/src/parser/attributes/error.rs
new file mode 100644
index 0000000..a45ad01
--- /dev/null
+++ b/sylvia-derive/src/parser/attributes/error.rs
@@ -0,0 +1,40 @@
+use proc_macro_error::emit_error;
+use syn::parse::{Parse, ParseStream, Parser};
+use syn::spanned::Spanned;
+use syn::{parse_quote, Attribute, Result, Type};
+
+use crate::crate_module;
+
+#[derive(Debug)]
+pub struct ContractErrorAttr {
+    pub error: Type,
+}
+
+impl Default for ContractErrorAttr {
+    fn default() -> Self {
+        let sylvia = crate_module();
+        Self {
+            error: parse_quote! { #sylvia ::cw_std::StdError },
+        }
+    }
+}
+
+impl ContractErrorAttr {
+    pub fn new(attr: &Attribute) -> Result<Self> {
+        attr.meta
+            .require_list()
+            .and_then(|meta| ContractErrorAttr::parse.parse2(meta.tokens.clone()))
+            .map_err(|err| {
+                emit_error!(attr.span(), err);
+                err
+            })
+    }
+}
+
+#[cfg(not(tarpaulin_include))]
+// False negative. It is being called in closure
+impl Parse for ContractErrorAttr {
+    fn parse(input: ParseStream) -> Result<Self> {
+        input.parse().map(|error| Self { error })
+    }
+}
diff --git a/sylvia-derive/src/parser/attributes/messages.rs b/sylvia-derive/src/parser/attributes/messages.rs
new file mode 100644
index 0000000..fe0b066
--- /dev/null
+++ b/sylvia-derive/src/parser/attributes/messages.rs
@@ -0,0 +1,121 @@
+use convert_case::{Case, Casing};
+use proc_macro_error::emit_warning;
+use syn::fold::Fold;
+use syn::parse::{Error, Parse, ParseStream, Parser};
+use syn::punctuated::Punctuated;
+use syn::spanned::Spanned;
+use syn::{parenthesized, Attribute, GenericArgument, Ident, Path, Result, Token};
+
+use proc_macro_error::emit_error;
+
+use crate::parser::extract_generics_from_path;
+use crate::strip_generics::StripGenerics;
+
+#[derive(Debug)]
+pub struct ContractMessageAttr {
+    pub module: Path,
+    pub variant: Ident,
+    pub customs: Customs,
+    pub generics: Punctuated<GenericArgument, Token![,]>,
+}
+
+impl ContractMessageAttr {
+    pub fn new(attr: &Attribute) -> Result<Self> {
+        attr.meta
+            .require_list()
+            .and_then(|meta| ContractMessageAttr::parse.parse2(meta.tokens.clone()))
+            .map_err(|err| {
+                emit_error!(attr.span(), err);
+                err
+            })
+    }
+}
+
+#[derive(Debug)]
+pub struct Customs {
+    pub has_msg: bool,
+    pub has_query: bool,
+}
+
+fn interface_has_custom(content: ParseStream) -> Result<Customs> {
+    let mut customs = Customs {
+        has_msg: false,
+        has_query: false,
+    };
+
+    if !content.peek(Token![:]) {
+        return Ok(customs);
+    }
+
+    let _: Token![:] = content.parse()?;
+    let attr: Ident = content.parse()?;
+    if attr != "custom" {
+        return Ok(customs);
+    }
+
+    let custom_content;
+    parenthesized!(custom_content in content);
+
+    while !custom_content.is_empty() {
+        let custom = custom_content.parse::<Path>()?;
+        match custom.get_ident() {
+            Some(ident) if ident == "msg" => customs.has_msg = true,
+            Some(ident) if ident == "query" => customs.has_query = true,
+            _ => {
+                return Err(Error::new(
+                    custom.span(),
+                    "Invalid custom attribute, expected one of: `msg`, `query`",
+                ))
+            }
+        }
+        if !custom_content.peek(Token![,]) {
+            break;
+        }
+        let _: Token![,] = custom_content.parse()?;
+    }
+    Ok(customs)
+}
+
+#[cfg(not(tarpaulin_include))]
+// False negative. It is being called in closure
+impl Parse for ContractMessageAttr {
+    fn parse(input: ParseStream) -> Result<Self> {
+        let module = input.parse()?;
+        let generics = extract_generics_from_path(&module);
+        let module = StripGenerics.fold_path(module);
+
+        let variant = if input.parse::<Token![as]>().is_ok() {
+            let variant: Ident = input.parse()?;
+            if Some(variant.to_string())
+                == module
+                    .segments
+                    .last()
+                    .map(|name| name.ident.to_string().to_case(Case::UpperCamel))
+            {
+                emit_warning!(
+                    variant.span(), "Redundant `as {}`.", variant;
+                    note = "Interface name is a camel case version of the path and can be auto deduced."
+                )
+            }
+            variant
+        } else if let Some(module_name) = &module.segments.last() {
+            let interface_name = module_name.ident.to_string().to_case(Case::UpperCamel);
+            syn::Ident::new(&interface_name, module.span())
+        } else {
+            Ident::new("", module.span())
+        };
+        let customs = interface_has_custom(input)?;
+        if !input.is_empty() {
+            return Err(Error::new(
+                input.span(),
+                "Unexpected token on the end of `messages` attribtue",
+            ));
+        }
+        Ok(Self {
+            module,
+            variant,
+            customs,
+            generics,
+        })
+    }
+}
diff --git a/sylvia-derive/src/parser/attributes/mod.rs b/sylvia-derive/src/parser/attributes/mod.rs
new file mode 100644
index 0000000..e5f7b8c
--- /dev/null
+++ b/sylvia-derive/src/parser/attributes/mod.rs
@@ -0,0 +1,127 @@
+use proc_macro_error::emit_error;
+use syn::spanned::Spanned;
+use syn::{Attribute, PathSegment};
+
+pub mod custom;
+pub mod error;
+pub mod messages;
+pub mod msg;
+pub mod override_entry_point;
+
+pub use custom::Custom;
+pub use error::ContractErrorAttr;
+pub use messages::{ContractMessageAttr, Customs};
+pub use msg::{MsgAttr, MsgType};
+pub use override_entry_point::{FilteredOverrideEntryPoints, OverrideEntryPoint};
+
+/// This struct represents all possible attributes that
+/// are parsed and utilized by sylvia.
+///
+pub enum SylviaAttribute {
+    Custom,
+    Error,
+    Messages,
+    Msg,
+    OverrideEntryPoint,
+}
+
+impl SylviaAttribute {
+    pub fn new(attr: &Attribute) -> Option<Self> {
+        let segments = &attr.path().segments;
+        if segments.len() == 2 && segments[0].ident == "sv" {
+            Self::match_attribute(&segments[1])
+        } else {
+            None
+        }
+    }
+
+    fn match_attribute(segment: &PathSegment) -> Option<Self> {
+        match segment.ident.to_string().as_str() {
+            "custom" => Some(Self::Custom),
+            "error" => Some(Self::Error),
+            "messages" => Some(Self::Messages),
+            "msg" => Some(Self::Msg),
+            "override_entry_point" => Some(Self::OverrideEntryPoint),
+            _ => None,
+        }
+    }
+}
+
+/// The structure parses all attributes provided in `new` method
+/// and stores the one relevant for sylvia.
+///
+#[derive(Default)]
+pub struct ParsedSylviaAttributes {
+    pub custom_attr: Option<Custom>,
+    pub error_attrs: Option<ContractErrorAttr>,
+    pub messages_attrs: Vec<ContractMessageAttr>,
+    pub msg_attr: Option<MsgAttr>,
+    pub override_entry_point_attrs: Vec<OverrideEntryPoint>,
+}
+
+impl ParsedSylviaAttributes {
+    pub fn new<'a>(attrs: impl Iterator<Item = &'a Attribute>) -> Self {
+        let mut result = Self::default();
+        for attr in attrs {
+            let sylvia_attr = SylviaAttribute::new(attr);
+            if let Some(sylvia_attr) = sylvia_attr {
+                result.match_attribute(&sylvia_attr, attr);
+            }
+        }
+        result
+    }
+
+    fn match_attribute(&mut self, attribute_type: &SylviaAttribute, attr: &Attribute) {
+        match attribute_type {
+            SylviaAttribute::Custom => {
+                if self.custom_attr.is_none() {
+                    if let Ok(custom_attr) = Custom::new(attr) {
+                        self.custom_attr = Some(custom_attr);
+                    }
+                } else {
+                    emit_error!(
+                        attr, "The attribute `sv::custom` is redefined";
+                        note = attr.span() => "Previous definition of the attribute `sv::custom`";
+                        note = "Only one `sv::custom` attribute can exist on a single sylvia entity"
+                    );
+                }
+            }
+            SylviaAttribute::Error => {
+                if self.error_attrs.is_none() {
+                    if let Ok(error_attr) = ContractErrorAttr::new(attr) {
+                        self.error_attrs = Some(error_attr);
+                    }
+                } else {
+                    emit_error!(
+                        attr, "The attribute `sv::error` is redefined";
+                        note = attr.span() => "Previous definition of the attribute `sv::error`";
+                        note = "Only one `sv::error` attribute can exist on a single method"
+                    );
+                }
+            }
+            SylviaAttribute::Messages => {
+                if let Ok(contract) = ContractMessageAttr::new(attr) {
+                    self.messages_attrs.push(contract);
+                }
+            }
+            SylviaAttribute::Msg => {
+                if self.msg_attr.is_none() {
+                    if let Ok(msg_attr) = MsgAttr::new(attr) {
+                        self.msg_attr = Some(msg_attr);
+                    }
+                } else {
+                    emit_error!(
+                        attr, "The attribute `sv::msg` is redefined";
+                        note = attr.span() => "Previous definition of the attribute `sv::msg`";
+                        note = "Only one `sv::msg` attribute can exist on a single method"
+                    );
+                }
+            }
+            SylviaAttribute::OverrideEntryPoint => {
+                if let Ok(override_entry_point) = OverrideEntryPoint::new(attr) {
+                    self.override_entry_point_attrs.push(override_entry_point)
+                }
+            }
+        }
+    }
+}
diff --git a/sylvia-derive/src/parser/attributes/msg.rs b/sylvia-derive/src/parser/attributes/msg.rs
new file mode 100644
index 0000000..1ff0f00
--- /dev/null
+++ b/sylvia-derive/src/parser/attributes/msg.rs
@@ -0,0 +1,99 @@
+use proc_macro2::Punct;
+use syn::parse::{Error, Parse, ParseBuffer, ParseStream, Parser};
+use syn::spanned::Spanned;
+use syn::{Attribute, Ident, Result};
+
+use proc_macro_error::emit_error;
+
+/// Type of message to be generated
+#[derive(PartialEq, Eq, Debug, Clone, Copy)]
+pub enum MsgType {
+    Exec,
+    Query,
+    Instantiate,
+    Migrate,
+    Reply,
+    Sudo,
+}
+
+/// Parsed representation of `#[sv::msg(...)]` attribute.
+#[derive(Clone)]
+pub enum MsgAttr {
+    Exec,
+    Query { resp_type: Option<Ident> },
+    Instantiate { name: Ident },
+    Migrate { name: Ident },
+    Reply,
+    Sudo,
+}
+
+impl MsgAttr {
+    pub fn new(attr: &Attribute) -> Result<Self> {
+        attr.meta
+            .require_list()
+            .and_then(|meta| MsgAttr::parse.parse2(meta.tokens.clone()))
+            .map_err(|err| {
+                emit_error!(attr.span(), err);
+                err
+            })
+    }
+}
+
+impl PartialEq<MsgType> for MsgAttr {
+    fn eq(&self, other: &MsgType) -> bool {
+        self.msg_type() == *other
+    }
+}
+
+impl MsgAttr {
+    fn parse_query(content: &ParseBuffer) -> Result<Self> {
+        if content.peek2(Ident) {
+            let _: Punct = content.parse()?;
+            let _: Ident = content.parse()?;
+            let _: Punct = content.parse()?;
+            let resp_type: Option<Ident> = Some(content.parse()?);
+            Ok(Self::Query { resp_type })
+        } else {
+            Ok(Self::Query { resp_type: None })
+        }
+    }
+
+    pub fn msg_type(&self) -> MsgType {
+        MsgType::Exec.as_accessor_name();
+        match self {
+            Self::Exec => MsgType::Exec,
+            Self::Query { .. } => MsgType::Query,
+            Self::Instantiate { .. } => MsgType::Instantiate,
+            Self::Migrate { .. } => MsgType::Migrate,
+            Self::Reply => MsgType::Reply,
+            Self::Sudo => MsgType::Sudo,
+        }
+    }
+}
+
+impl Parse for MsgAttr {
+    fn parse(input: ParseStream) -> Result<Self> {
+        let ty: Ident = input.parse()?;
+
+        if ty == "exec" {
+            Ok(Self::Exec)
+        } else if ty == "query" {
+            Self::parse_query(input)
+        } else if ty == "instantiate" {
+            let name = Ident::new("InstantiateMsg", input.span());
+            Ok(Self::Instantiate { name })
+        } else if ty == "migrate" {
+            let name = Ident::new("MigrateMsg", input.span());
+            Ok(Self::Migrate { name })
+        } else if ty == "reply" {
+            Ok(Self::Reply)
+        } else if ty == "sudo" {
+            Ok(Self::Sudo)
+        } else {
+            Err(Error::new(
+                input.span(),
+                "Invalid message type, expected one of: `exec`, `query`, `instantiate`, `migrate`, `reply` or `sudo`.",
+            ))
+        }
+    }
+}
diff --git a/sylvia-derive/src/parser/attributes/override_entry_point.rs b/sylvia-derive/src/parser/attributes/override_entry_point.rs
new file mode 100644
index 0000000..7046837
--- /dev/null
+++ b/sylvia-derive/src/parser/attributes/override_entry_point.rs
@@ -0,0 +1,97 @@
+use proc_macro2::TokenStream;
+use proc_macro_error::emit_error;
+use quote::quote;
+use syn::parse::{Error, Parse, ParseStream, Parser};
+use syn::spanned::Spanned;
+use syn::{parenthesized, Attribute, Ident, Path, Result, Token, Type};
+
+use crate::crate_module;
+use crate::parser::MsgType;
+
+#[derive(Debug, Clone)]
+pub struct OverrideEntryPoint {
+    entry_point: Path,
+    msg_name: Type,
+    msg_type: MsgType,
+}
+
+impl OverrideEntryPoint {
+    pub fn new(attr: &Attribute) -> Result<Self> {
+        attr.meta
+            .require_list()
+            .and_then(|meta| OverrideEntryPoint::parse.parse2(meta.tokens.clone()))
+            .map_err(|err| {
+                emit_error!(attr.span(), err);
+                err
+            })
+    }
+
+    pub fn emit_multitest_dispatch(&self) -> TokenStream {
+        let Self {
+            entry_point,
+            msg_name,
+            msg_type,
+            ..
+        } = self;
+
+        let sylvia = crate_module();
+        let values = msg_type.emit_ctx_values();
+
+        quote! {
+            #entry_point ( #values .into(), #sylvia ::cw_std::from_json::< #msg_name >(&msg)?)
+                .map_err(Into::into)
+        }
+    }
+}
+
+pub trait FilteredOverrideEntryPoints {
+    fn get_entry_point(&self, ty: MsgType) -> Option<&OverrideEntryPoint>;
+}
+
+impl FilteredOverrideEntryPoints for &[OverrideEntryPoint] {
+    fn get_entry_point(&self, ty: MsgType) -> Option<&OverrideEntryPoint> {
+        self.iter().find(|entry_point| entry_point.msg_type == ty)
+    }
+}
+
+impl FilteredOverrideEntryPoints for &Vec<OverrideEntryPoint> {
+    fn get_entry_point(&self, ty: MsgType) -> Option<&OverrideEntryPoint> {
+        self.iter().find(|entry_point| entry_point.msg_type == ty)
+    }
+}
+
+#[cfg(not(tarpaulin_include))]
+// False negative. It is being called in closure
+impl Parse for OverrideEntryPoint {
+    fn parse(input: ParseStream) -> Result<Self> {
+        let ty: Ident = input.parse()?;
+        let _: Token![=] = input.parse()?;
+        let entry_point = input.parse()?;
+
+        let msg_content;
+        parenthesized!(msg_content in input);
+
+        let msg_name = msg_content.parse()?;
+
+        let msg_type = match ty.to_string().as_str() {
+            "exec" =>  MsgType::Exec,
+            "instantiate" =>  MsgType::Instantiate,
+            "query" =>  MsgType::Instantiate,
+            "migrate" => MsgType::Migrate,
+            "reply" => MsgType::Reply,
+            "sudo" =>  MsgType::Sudo,
+            &_ => {
+                return Err(Error::new(
+                    ty.span(),
+                    "Invalid entry point. Expected exec, instantiate, query, migrate, reply or sudo. Found {ty}",
+                ))
+            }
+        };
+
+        Ok(Self {
+            entry_point,
+            msg_name,
+            msg_type,
+        })
+    }
+}
diff --git a/sylvia-derive/src/parser/contract.rs b/sylvia-derive/src/parser/contract.rs
new file mode 100644
index 0000000..0a4e68a
--- /dev/null
+++ b/sylvia-derive/src/parser/contract.rs
@@ -0,0 +1,36 @@
+use syn::parse::{Error, Nothing, Parse, ParseStream};
+use syn::{Ident, Path, Result, Token};
+
+/// Parsed arguments for `contract` macro
+pub struct ContractArgs {
+    /// Module in which contract impl block is defined.
+    /// Used only while implementing `Interface` on `Contract`.
+    pub module: Option<Path>,
+}
+
+impl Parse for ContractArgs {
+    fn parse(input: ParseStream) -> Result<Self> {
+        let mut module = None;
+
+        while !input.is_empty() {
+            let attr: Ident = input.parse()?;
+            let _: Token![=] = input.parse()?;
+
+            if attr == "module" {
+                module = Some(input.parse()?);
+            } else {
+                return Err(Error::new(attr.span(), "expected `module`"));
+            }
+
+            if input.peek(Token![,]) {
+                let _: Token![,] = input.parse()?;
+            } else if !input.is_empty() {
+                return Err(input.error("Unexpected token, comma expected"));
+            }
+        }
+
+        let _: Nothing = input.parse()?;
+
+        Ok(ContractArgs { module })
+    }
+}
diff --git a/sylvia-derive/src/parser/entry_point.rs b/sylvia-derive/src/parser/entry_point.rs
new file mode 100644
index 0000000..8c32b56
--- /dev/null
+++ b/sylvia-derive/src/parser/entry_point.rs
@@ -0,0 +1,56 @@
+use syn::parse::{Error, Nothing, Parse, ParseStream, Parser};
+use syn::punctuated::Punctuated;
+use syn::spanned::Spanned;
+use syn::{parenthesized, GenericArgument, Path, Result, Token};
+
+use super::attributes::custom::Custom;
+use super::extract_generics_from_path;
+
+/// Parsed arguments for `entry_points` macro
+#[derive(Default)]
+pub struct EntryPointArgs {
+    /// Types used in place of contracts generics.
+    pub generics: Option<Punctuated<GenericArgument, Token![,]>>,
+    /// Concrete custom msg/query used in place of contracts generic ones.
+    pub custom: Option<Custom>,
+}
+
+impl Parse for EntryPointArgs {
+    fn parse(input: ParseStream) -> Result<Self> {
+        let mut entry_points_args = Self::default();
+        if input.is_empty() {
+            return Ok(entry_points_args);
+        }
+
+        let generics: Path = input.parse()?;
+        match generics.segments.last() {
+            Some(segment) if segment.ident == "generics" => {
+                entry_points_args.generics = Some(extract_generics_from_path(&generics))
+            }
+            _ => return Err(Error::new(generics.span(), "Expected `generics`.")),
+        };
+
+        let comma: Option<Token![,]> = input.parse().ok();
+        if comma.is_none() {
+            return Ok(entry_points_args);
+        }
+
+        let custom: Option<Path> = input.parse().ok();
+        match custom {
+            Some(custom)
+                if custom.get_ident().map(|custom| custom.to_string())
+                    == Some("custom".to_owned()) =>
+            {
+                let content;
+                parenthesized!(content in input);
+                entry_points_args.custom = Some(Custom::parse.parse2(content.parse()?)?);
+            }
+            Some(attr) => return Err(Error::new(attr.span(), "Expected `custom`.")),
+            _ => (),
+        };
+
+        let _: Nothing = input.parse()?;
+
+        Ok(entry_points_args)
+    }
+}
diff --git a/sylvia-derive/src/parser/mod.rs b/sylvia-derive/src/parser/mod.rs
new file mode 100644
index 0000000..5925ede
--- /dev/null
+++ b/sylvia-derive/src/parser/mod.rs
@@ -0,0 +1,48 @@
+pub mod attributes;
+pub mod contract;
+pub mod entry_point;
+
+pub use attributes::{
+    ContractErrorAttr, ContractMessageAttr, Custom, Customs, FilteredOverrideEntryPoints, MsgAttr,
+    MsgType, OverrideEntryPoint, ParsedSylviaAttributes, SylviaAttribute,
+};
+pub use contract::ContractArgs;
+pub use entry_point::EntryPointArgs;
+
+use proc_macro_error::emit_error;
+use syn::punctuated::Punctuated;
+use syn::spanned::Spanned;
+use syn::{
+    parse_quote, GenericArgument, Ident, ItemTrait, Path, PathArguments, Token, TraitItem, Type,
+};
+
+fn extract_generics_from_path(module: &Path) -> Punctuated<GenericArgument, Token![,]> {
+    let generics = module.segments.last().map(|segment| {
+        match segment.arguments.clone(){
+            PathArguments::AngleBracketed(generics) => {
+                generics.args
+            },
+            PathArguments::None => Default::default(),
+            PathArguments::Parenthesized(generics) => {
+                emit_error!(
+                    generics.span(), "Found paranthesis wrapping generics in `sv::messages` attribute.";
+                    note = "Expected `sv::messages` attribute to be in form `#[sv::messages(Path<generics> as Type)]`"
+                );
+               Default::default()
+            }
+        }
+    }).unwrap_or_default();
+
+    generics
+}
+
+pub fn parse_associated_custom_type(source: &ItemTrait, type_name: &str) -> Option<Type> {
+    let trait_name = &source.ident;
+    source.items.iter().find_map(|item| match item {
+        TraitItem::Type(ty) if ty.ident == type_name => {
+            let type_name = Ident::new(type_name, ty.span());
+            Some(parse_quote! { <ContractT as #trait_name>:: #type_name})
+        }
+        _ => None,
+    })
+}
diff --git a/sylvia-derive/src/querier.rs b/sylvia-derive/src/querier.rs
index a4c79a7..d70f5d7 100644
--- a/sylvia-derive/src/querier.rs
+++ b/sylvia-derive/src/querier.rs
@@ -1,6 +1,5 @@
 use proc_macro2::TokenStream;
-use quote::quote;
-use quote::ToTokens;
+use quote::{quote, ToTokens};
 use syn::{GenericParam, ItemImpl, Path};
 
 use crate::associated_types::{AssociatedTypes, EmitAssociated, ImplAssociatedTypes, ItemType};
@@ -8,7 +7,7 @@ use crate::check_generics::GetPath;
 use crate::crate_module;
 use crate::interfaces::Interfaces;
 use crate::message::MsgVariants;
-use crate::parser::MsgType;
+use crate::parser::attributes::msg::MsgType;
 use crate::variant_descs::AsVariantDescs;
 
 pub struct TraitQuerier<'a, Generic> {
diff --git a/sylvia-derive/src/strip_input.rs b/sylvia-derive/src/strip_input.rs
index 96fe1b1..19f47dd 100644
--- a/sylvia-derive/src/strip_input.rs
+++ b/sylvia-derive/src/strip_input.rs
@@ -4,7 +4,7 @@ use syn::{
     FnArg, ImplItemFn, ItemImpl, ItemTrait, PatType, Receiver, Signature, Token, TraitItemFn,
 };
 
-use crate::parser::sylvia_attribute;
+use crate::parser::SylviaAttribute;
 
 /// Utility for stripping all attributes from input before it is emitted
 pub struct StripInput;
@@ -37,7 +37,7 @@ impl Fold for StripInput {
         let attrs = i
             .attrs
             .into_iter()
-            .filter(|attr| !attr.path().is_ident("msg"))
+            .filter(|attr| SylviaAttribute::new(attr).is_none())
             .collect();
 
         let inputs = remove_input_attr(i.sig.inputs);
@@ -49,7 +49,7 @@ impl Fold for StripInput {
         let attrs = i
             .attrs
             .into_iter()
-            .filter(|attr| !attr.path().is_ident("msg"))
+            .filter(|attr| SylviaAttribute::new(attr).is_none())
             .collect();
 
         let inputs = remove_input_attr(i.sig.inputs);
@@ -61,7 +61,7 @@ impl Fold for StripInput {
         let attrs = i
             .attrs
             .into_iter()
-            .filter(|attr| sylvia_attribute(attr).is_none())
+            .filter(|attr| SylviaAttribute::new(attr).is_none())
             .collect();
 
         fold::fold_item_trait(self, ItemTrait { attrs, ..i })
@@ -71,11 +71,7 @@ impl Fold for StripInput {
         let attrs = i
             .attrs
             .into_iter()
-            .filter(|attr| {
-                !(attr.path().is_ident("messages")
-                    || attr.path().is_ident("error")
-                    || sylvia_attribute(attr).is_some())
-            })
+            .filter(|attr| SylviaAttribute::new(attr).is_none())
             .collect();
 
         fold::fold_item_impl(self, ItemImpl { attrs, ..i })
diff --git a/sylvia-derive/src/utils.rs b/sylvia-derive/src/utils.rs
index 0ff0b38..27132c0 100644
--- a/sylvia-derive/src/utils.rs
+++ b/sylvia-derive/src/utils.rs
@@ -98,7 +98,7 @@ pub fn extract_return_type(ret_type: &ReturnType) -> &Path {
             segment.span(),
             "Neither Result nor StdResult found in return type. \
                     You might be using aliased return type. \
-                    Please use #[msg(return_type=<your_return_type>)]"
+                    Please use #[sv::msg(return_type=<your_return_type>)]"
         );
     }
     let PathArguments::AngleBracketed(args) = &segments[0].arguments else {
diff --git a/sylvia-derive/src/variant_descs.rs b/sylvia-derive/src/variant_descs.rs
index 827421b..4f0a969 100644
--- a/sylvia-derive/src/variant_descs.rs
+++ b/sylvia-derive/src/variant_descs.rs
@@ -1,28 +1,23 @@
-use proc_macro2::Span;
-use syn::spanned::Spanned;
+use crate::parser::{MsgAttr, ParsedSylviaAttributes};
 use syn::{Attribute, ImplItem, ItemImpl, ItemTrait, Signature, TraitItem};
 
 pub struct VariantDesc<'a> {
-    attrs: &'a [Attribute],
+    msg_attr: Option<MsgAttr>,
     sig: &'a Signature,
-    span: Span,
 }
 
 impl<'a> VariantDesc<'a> {
-    pub fn new(attrs: &'a Vec<Attribute>, sig: &'a Signature, span: Span) -> Self {
-        Self { attrs, sig, span }
+    pub fn new(attrs: &'a [Attribute], sig: &'a Signature) -> Self {
+        let msg_attr = ParsedSylviaAttributes::new(attrs.iter()).msg_attr;
+        Self { msg_attr, sig }
     }
 
     pub fn into_sig(self) -> &'a Signature {
         self.sig
     }
 
-    pub fn attr_msg(&self) -> Option<&Attribute> {
-        self.attrs.iter().find(|attr| attr.path().is_ident("msg"))
-    }
-
-    pub fn span(&self) -> Span {
-        self.span
+    pub fn attr_msg(&self) -> Option<MsgAttr> {
+        self.msg_attr.clone()
     }
 }
 
@@ -44,9 +39,7 @@ impl AsVariantDescs for ItemImpl {
 
     fn as_variants(&self) -> Self::Iter<'_> {
         Box::new(self.items.iter().filter_map(|item| match item {
-            ImplItem::Fn(method) => {
-                Some(VariantDesc::new(&method.attrs, &method.sig, method.span()))
-            }
+            ImplItem::Fn(method) => Some(VariantDesc::new(&method.attrs, &method.sig)),
             _ => None,
         }))
     }
@@ -57,9 +50,7 @@ impl AsVariantDescs for ItemTrait {
 
     fn as_variants(&self) -> Self::Iter<'_> {
         Box::new(self.items.iter().filter_map(|item| match item {
-            TraitItem::Fn(method) => {
-                Some(VariantDesc::new(&method.attrs, &method.sig, method.span()))
-            }
+            TraitItem::Fn(method) => Some(VariantDesc::new(&method.attrs, &method.sig)),
             _ => None,
         }))
     }
diff --git a/sylvia/examples/basic.rs b/sylvia/examples/basic.rs
index 404aa66..52f9683 100644
--- a/sylvia/examples/basic.rs
+++ b/sylvia/examples/basic.rs
@@ -42,14 +42,14 @@ mod group {
     pub trait Group {
         type Error: From<StdError>;
 
-        #[msg(exec)]
+        #[sv::msg(exec)]
         fn update_admin(
             &self,
             ctx: ExecCtx,
             admin: Option<String>,
         ) -> Result<Response, Self::Error>;
 
-        #[msg(exec)]
+        #[sv::msg(exec)]
         fn update_members(
             &self,
             ctx: ExecCtx,
@@ -57,7 +57,7 @@ mod group {
             add: Vec<Member>,
         ) -> Result<Response, Self::Error>;
 
-        #[msg(query)]
+        #[sv::msg(query)]
         fn member(&self, ctx: QueryCtx, addr: String) -> Result<MemberResp, Self::Error>;
     }
 }
@@ -71,11 +71,11 @@ mod impl_group {
     use crate::{GroupContract, MemberResp};
 
     #[contract(module=crate)]
-    #[messages(crate::group as Group)]
+    #[sv::messages(crate::group as Group)]
     impl crate::group::Group for GroupContract {
         type Error = Error;
 
-        #[msg(exec)]
+        #[sv::msg(exec)]
         fn update_admin(
             &self,
             _ctx: ExecCtx,
@@ -84,7 +84,7 @@ mod impl_group {
             todo!()
         }
 
-        #[msg(exec)]
+        #[sv::msg(exec)]
         fn update_members(
             &self,
             _ctx: ExecCtx,
@@ -94,7 +94,7 @@ mod impl_group {
             todo!()
         }
 
-        #[msg(query)]
+        #[sv::msg(query)]
         fn member(&self, _ctx: QueryCtx, _addr: String) -> Result<MemberResp, Self::Error> {
             todo!()
         }
@@ -113,8 +113,8 @@ impl Default for GroupContract {
 }
 
 #[contract]
-#[error(Error)]
-#[messages(group as Group)]
+#[sv::error(Error)]
+#[sv::messages(group as Group)]
 impl GroupContract {
     pub const fn new() -> Self {
         Self {
@@ -123,7 +123,7 @@ impl GroupContract {
         }
     }
 
-    #[msg(instantiate)]
+    #[sv::msg(instantiate)]
     pub fn instantiate(
         &self,
         ctx: InstantiateCtx,
diff --git a/sylvia/src/lib.rs b/sylvia/src/lib.rs
index feedd89..52e2344 100644
--- a/sylvia/src/lib.rs
+++ b/sylvia/src/lib.rs
@@ -10,16 +10,14 @@ pub mod utils;
 
 #[cfg(feature = "mt")]
 pub use anyhow;
-pub use cosmwasm_schema as cw_schema;
-pub use cosmwasm_std as cw_std;
 #[cfg(feature = "mt")]
 pub use cw_multi_test;
 #[cfg(feature = "cosmwasm_1_2")]
 pub use cw_utils;
 #[cfg(feature = "mt")]
 pub use derivative;
-pub use schemars;
-pub use serde;
-pub use serde_cw_value as serde_value;
-pub use serde_json_wasm as serde_json;
 pub use sylvia_derive::{contract, entry_points, interface};
+pub use {
+    cosmwasm_schema as cw_schema, cosmwasm_std as cw_std, schemars, serde,
+    serde_cw_value as serde_value, serde_json_wasm as serde_json,
+};


Test patch:
diff --git a/examples/contracts/cw20-base/src/multitest/receiver.rs b/examples/contracts/cw20-base/src/multitest/receiver.rs
index 3a12723..bdc828f 100644
--- a/examples/contracts/cw20-base/src/multitest/receiver.rs
+++ b/examples/contracts/cw20-base/src/multitest/receiver.rs
@@ -6,7 +6,7 @@ use sylvia::{interface, schemars};
 pub trait Receiver {
     type Error: From<StdError>;
 
-    #[msg(exec)]
+    #[sv::msg(exec)]
     fn receive(
         &self,
         ctx: ExecCtx,
@@ -23,11 +23,11 @@ pub mod impl_receiver {
     use sylvia::types::ExecCtx;
 
     #[contract(module=crate::multitest::receiver_contract)]
-    #[messages(crate::multitest::receiver as Receiver)]
+    #[sv::messages(crate::multitest::receiver as Receiver)]
     impl super::Receiver for ReceiverContract {
         type Error = StdError;
 
-        #[msg(exec)]
+        #[sv::msg(exec)]
         fn receive(
             &self,
             _ctx: ExecCtx,
diff --git a/examples/contracts/cw20-base/src/multitest/receiver_contract.rs b/examples/contracts/cw20-base/src/multitest/receiver_contract.rs
index 9760fed..12caae2 100644
--- a/examples/contracts/cw20-base/src/multitest/receiver_contract.rs
+++ b/examples/contracts/cw20-base/src/multitest/receiver_contract.rs
@@ -1,16 +1,17 @@
 use cosmwasm_std::{Response, StdResult};
-use sylvia::{contract, schemars, types::InstantiateCtx};
+use sylvia::types::InstantiateCtx;
+use sylvia::{contract, schemars};
 
 use super::receiver;
 pub struct ReceiverContract {}
 
 #[contract]
-#[messages(receiver as Receiver)]
+#[sv::messages(receiver as Receiver)]
 impl ReceiverContract {
     pub const fn new() -> Self {
         Self {}
     }
-    #[msg(instantiate)]
+    #[sv::msg(instantiate)]
     pub fn instantiate(&self, _ctx: InstantiateCtx) -> StdResult<Response> {
         Ok(Response::new())
     }
diff --git a/sylvia-derive/src/multitest.rs b/sylvia-derive/src/multitest.rs
index 362952b..e7393f4 100644
--- a/sylvia-derive/src/multitest.rs
+++ b/sylvia-derive/src/multitest.rs
@@ -7,7 +7,10 @@ use crate::associated_types::ImplAssociatedTypes;
 use crate::crate_module;
 use crate::interfaces::Interfaces;
 use crate::message::{MsgVariant, MsgVariants};
-use crate::parser::{ContractErrorAttr, Custom, MsgType, OverrideEntryPoint, OverrideEntryPoints};
+use crate::parser::attributes::msg::MsgType;
+use crate::parser::{
+    Custom, FilteredOverrideEntryPoints, OverrideEntryPoint, ParsedSylviaAttributes,
+};
 use crate::utils::{emit_bracketed_generics, is_trait};
 use crate::variant_descs::AsVariantDescs;
 
@@ -42,8 +45,8 @@ pub struct ContractMtHelpers<'a> {
     where_clause: &'a Option<syn::WhereClause>,
     contract_name: &'a Ident,
     proxy_name: Ident,
-    custom: &'a Custom<'a>,
-    override_entry_points: &'a OverrideEntryPoints,
+    custom: &'a Custom,
+    override_entry_points: Vec<OverrideEntryPoint>,
     instantiate_variants: MsgVariants<'a, GenericParam>,
     exec_variants: MsgVariants<'a, GenericParam>,
     query_variants: MsgVariants<'a, GenericParam>,
@@ -57,7 +60,7 @@ impl<'a> ContractMtHelpers<'a> {
         source: &'a ItemImpl,
         generic_params: &'a [&'a GenericParam],
         custom: &'a Custom,
-        override_entry_points: &'a OverrideEntryPoints,
+        override_entry_points: Vec<OverrideEntryPoint>,
     ) -> Self {
         let where_clause = &source.generics.where_clause;
         let instantiate_variants = MsgVariants::new(
@@ -108,7 +111,10 @@ impl<'a> ContractMtHelpers<'a> {
                 None => unreachable!(),
             }
         } else {
-            let error = ContractErrorAttr::new(source).error;
+            let error = ParsedSylviaAttributes::new(source.attrs.iter())
+                .error_attrs
+                .unwrap_or_default()
+                .error;
             parse_quote! { #error }
         };
 
@@ -632,7 +638,7 @@ impl<'a> ContractMtHelpers<'a> {
 pub struct ImplMtHelpers<'a> {
     source: &'a ItemImpl,
     error_type: Type,
-    custom: &'a Custom<'a>,
+    custom: &'a Custom,
     interfaces: &'a Interfaces,
     generic_params: &'a [&'a GenericParam],
     exec_variants: MsgVariants<'a, GenericParam>,
diff --git a/sylvia/tests/api.rs b/sylvia/tests/api.rs
index a01ee8a..4f7da40 100644
--- a/sylvia/tests/api.rs
+++ b/sylvia/tests/api.rs
@@ -23,22 +23,22 @@ where
         }
     }
 
-    #[msg(instantiate)]
+    #[sv::msg(instantiate)]
     pub fn instantiate(&self, _ctx: InstantiateCtx, _param: Instantiate) -> StdResult<Response> {
         Ok(Response::new())
     }
 
-    #[msg(exec)]
+    #[sv::msg(exec)]
     pub fn exec(&self, _ctx: ExecCtx, _param: Exec) -> StdResult<Response> {
         Ok(Response::new())
     }
 
-    #[msg(query)]
+    #[sv::msg(query)]
     pub fn query(&self, _ctx: QueryCtx, _param: Query) -> StdResult<Response> {
         Ok(Response::new())
     }
 
-    #[msg(migrate)]
+    #[sv::msg(migrate)]
     pub fn migrate(&self, _ctx: MigrateCtx, _param: Migrate) -> StdResult<Response> {
         Ok(Response::new())
     }
@@ -47,7 +47,8 @@ where
 #[cfg(test)]
 mod tests {
     use crate::SomeContract;
-    use cosmwasm_std::{testing::mock_dependencies, Addr, QuerierWrapper};
+    use cosmwasm_std::testing::mock_dependencies;
+    use cosmwasm_std::{Addr, QuerierWrapper};
     use sylvia::types::{ContractApi, SvCustomMsg};
 
     #[test]
diff --git a/sylvia/tests/custom_msg.rs b/sylvia/tests/custom_msg.rs
index 061ea61..5615a89 100644
--- a/sylvia/tests/custom_msg.rs
+++ b/sylvia/tests/custom_msg.rs
@@ -32,15 +32,15 @@ mod some_interface {
         type Error: From<StdError>;
 
         #[cfg(not(tarpaulin_include))]
-        #[msg(query)]
+        #[sv::msg(query)]
         fn interface_query(&self, ctx: QueryCtx) -> StdResult<SomeResponse>;
 
         #[cfg(not(tarpaulin_include))]
-        #[msg(exec)]
+        #[sv::msg(exec)]
         fn interface_exec(&self, ctx: ExecCtx) -> StdResult<Response<MyMsg>>;
 
         #[cfg(not(tarpaulin_include))]
-        #[msg(sudo)]
+        #[sv::msg(sudo)]
         fn interface_sudo(&self, ctx: SudoCtx) -> StdResult<Response<MyMsg>>;
     }
 }
@@ -54,22 +54,22 @@ mod impl_some_interface {
     use crate::{MyMsg, SomeResponse};
 
     #[contract(module=crate)]
-    #[messages(crate::some_interface)]
+    #[sv::messages(crate::some_interface)]
     #[sv::custom(msg=MyMsg)]
     impl SomeInterface for crate::MyContract {
         type Error = StdError;
 
-        #[msg(query)]
+        #[sv::msg(query)]
         fn interface_query(&self, _ctx: QueryCtx) -> StdResult<SomeResponse> {
             Ok(SomeResponse)
         }
 
-        #[msg(exec)]
+        #[sv::msg(exec)]
         fn interface_exec(&self, _ctx: ExecCtx) -> StdResult<Response<MyMsg>> {
             Ok(Response::default())
         }
 
-        #[msg(sudo)]
+        #[sv::msg(sudo)]
         fn interface_sudo(&self, _ctx: SudoCtx) -> StdResult<Response<MyMsg>> {
             Ok(Response::new())
         }
@@ -90,15 +90,15 @@ mod interface {
         type ExecC: CustomMsg;
 
         #[cfg(not(tarpaulin_include))]
-        #[msg(exec)]
+        #[sv::msg(exec)]
         fn exec(&self, ctx: ExecCtx) -> StdResult<Response<MyMsg>>;
 
         #[cfg(not(tarpaulin_include))]
-        #[msg(query)]
+        #[sv::msg(query)]
         fn query(&self, ctx: QueryCtx) -> StdResult<Response<MyMsg>>;
 
         #[cfg(not(tarpaulin_include))]
-        #[msg(sudo)]
+        #[sv::msg(sudo)]
         fn sudo(&self, ctx: SudoCtx) -> StdResult<Response<MyMsg>>;
     }
 }
@@ -110,24 +110,24 @@ mod impl_interface {
     use sylvia::types::{ExecCtx, QueryCtx, SudoCtx};
 
     #[contract(module=crate)]
-    #[messages(crate::interface)]
+    #[sv::messages(crate::interface)]
     #[sv::custom(msg=MyMsg)]
     impl Interface for crate::MyContract {
         type Error = StdError;
         type ExecC = OtherMsg;
 
-        #[msg(exec)]
+        #[sv::msg(exec)]
         fn exec(&self, _ctx: ExecCtx) -> StdResult<Response<MyMsg>> {
             Ok(Response::default())
         }
 
-        #[msg(query)]
+        #[sv::msg(query)]
         fn query(&self, _ctx: QueryCtx) -> StdResult<Response<MyMsg>> {
             Ok(Response::new())
         }
 
         #[cfg(not(tarpaulin_include))]
-        #[msg(sudo)]
+        #[sv::msg(sudo)]
         fn sudo(&self, _ctx: SudoCtx) -> StdResult<Response<MyMsg>> {
             Ok(Response::new())
         }
@@ -144,15 +144,15 @@ mod other_interface {
         type Error: From<StdError>;
 
         #[cfg(not(tarpaulin_include))]
-        #[msg(exec)]
+        #[sv::msg(exec)]
         fn other_interface_exec(&self, ctx: ExecCtx) -> StdResult<Response>;
 
         #[cfg(not(tarpaulin_include))]
-        #[msg(sudo)]
+        #[sv::msg(sudo)]
         fn other_interface_sudo(&self, ctx: SudoCtx) -> StdResult<Response>;
 
         #[cfg(not(tarpaulin_include))]
-        #[msg(query)]
+        #[sv::msg(query)]
         fn other_interface_query(&self, ctx: QueryCtx) -> StdResult<Response>;
     }
 }
@@ -163,24 +163,24 @@ mod impl_other_interface {
     use sylvia::types::{ExecCtx, QueryCtx, SudoCtx};
 
     #[contract(module=crate)]
-    #[messages(crate::other_interface)]
+    #[sv::messages(crate::other_interface)]
     #[sv::custom(msg=crate::MyMsg)]
     impl OtherInterface for crate::MyContract {
         type Error = StdError;
 
-        #[msg(exec)]
+        #[sv::msg(exec)]
         fn other_interface_exec(&self, _ctx: ExecCtx) -> StdResult<Response> {
             Ok(Response::default())
         }
 
         #[cfg(not(tarpaulin_include))]
-        #[msg(sudo)]
+        #[sv::msg(sudo)]
         fn other_interface_sudo(&self, _ctx: SudoCtx) -> StdResult<Response> {
             Ok(Response::new())
         }
 
         #[cfg(not(tarpaulin_include))]
-        #[msg(query)]
+        #[sv::msg(query)]
         fn other_interface_query(&self, _ctx: QueryCtx) -> StdResult<Response> {
             Ok(Response::new())
         }
@@ -199,15 +199,15 @@ mod associated_interface {
         type ExecC: CustomMsg;
 
         #[cfg(not(tarpaulin_include))]
-        #[msg(exec)]
+        #[sv::msg(exec)]
         fn associated_exec(&self, ctx: ExecCtx) -> StdResult<Response<Self::ExecC>>;
 
         #[cfg(not(tarpaulin_include))]
-        #[msg(sudo)]
+        #[sv::msg(sudo)]
         fn associated_sudo(&self, ctx: SudoCtx) -> StdResult<Response<Self::ExecC>>;
 
         #[cfg(not(tarpaulin_include))]
-        #[msg(query)]
+        #[sv::msg(query)]
         fn associated_query(&self, ctx: QueryCtx) -> StdResult<SomeResponse>;
     }
 }
@@ -219,23 +219,23 @@ mod impl_associated_interface {
     use sylvia::types::{ExecCtx, QueryCtx, SudoCtx};
 
     #[contract(module=crate)]
-    #[messages(crate::associated_interface)]
+    #[sv::messages(crate::associated_interface)]
     #[sv::custom(msg=MyMsg)]
     impl AssociatedInterface for crate::MyContract {
         type Error = StdError;
         type ExecC = MyMsg;
 
-        #[msg(exec)]
+        #[sv::msg(exec)]
         fn associated_exec(&self, _ctx: ExecCtx) -> StdResult<Response<Self::ExecC>> {
             Ok(Response::default())
         }
 
-        #[msg(sudo)]
+        #[sv::msg(sudo)]
         fn associated_sudo(&self, _ctx: SudoCtx) -> StdResult<Response<Self::ExecC>> {
             Ok(Response::default())
         }
 
-        #[msg(query)]
+        #[sv::msg(query)]
         fn associated_query(&self, _ctx: QueryCtx) -> StdResult<SomeResponse> {
             Ok(SomeResponse {})
         }
@@ -243,10 +243,10 @@ mod impl_associated_interface {
 }
 
 #[contract]
-#[messages(some_interface)]
-#[messages(other_interface: custom(msg))]
-#[messages(associated_interface)]
-#[messages(interface)]
+#[sv::messages(some_interface)]
+#[sv::messages(other_interface: custom(msg))]
+#[sv::messages(associated_interface)]
+#[sv::messages(interface)]
 #[sv::custom(msg=MyMsg)]
 impl MyContract {
     #[allow(clippy::new_without_default)]
@@ -254,29 +254,29 @@ impl MyContract {
         Self {}
     }
 
-    #[msg(instantiate)]
+    #[sv::msg(instantiate)]
     pub fn instantiate(&self, _ctx: InstantiateCtx) -> StdResult<Response<MyMsg>> {
         Ok(Response::default())
     }
 
-    #[msg(exec)]
+    #[sv::msg(exec)]
     pub fn some_exec(&self, _ctx: ExecCtx) -> StdResult<Response<MyMsg>> {
         Ok(Response::default())
     }
 
-    #[msg(query)]
+    #[sv::msg(query)]
     pub fn some_query(&self, _ctx: QueryCtx) -> StdResult<SomeResponse> {
         Ok(SomeResponse)
     }
 
     #[cfg(not(tarpaulin_include))]
-    #[msg(migrate)]
+    #[sv::msg(migrate)]
     pub fn some_migrate(&self, _ctx: MigrateCtx) -> StdResult<Response<MyMsg>> {
         Ok(Response::default())
     }
 
     #[cfg(not(tarpaulin_include))]
-    #[msg(sudo)]
+    #[sv::msg(sudo)]
     pub fn some_sudo(&self, _ctx: SudoCtx) -> StdResult<Response<MyMsg>> {
         Ok(Response::default())
     }
@@ -288,8 +288,7 @@ mod tests {
     use crate::impl_interface::sv::test_utils::Interface;
     use crate::impl_other_interface::sv::test_utils::OtherInterface;
     use crate::impl_some_interface::sv::test_utils::SomeInterface;
-    use crate::MyContract;
-    use crate::MyMsg;
+    use crate::{MyContract, MyMsg};
     use sylvia::multitest::App;
 
     #[test]
diff --git a/sylvia/tests/custom_query.rs b/sylvia/tests/custom_query.rs
index 52b1d42..c2a3a12 100644
--- a/sylvia/tests/custom_query.rs
+++ b/sylvia/tests/custom_query.rs
@@ -32,15 +32,15 @@ mod interface {
         type QueryC: CustomQuery;
 
         #[cfg(not(tarpaulin_include))]
-        #[msg(query)]
+        #[sv::msg(query)]
         fn interface_query(&self, ctx: QueryCtx<MyQuery>) -> StdResult<SomeResponse>;
 
         #[cfg(not(tarpaulin_include))]
-        #[msg(exec)]
+        #[sv::msg(exec)]
         fn interface_exec(&self, ctx: ExecCtx<MyQuery>) -> StdResult<Response>;
 
         #[cfg(not(tarpaulin_include))]
-        #[msg(sudo)]
+        #[sv::msg(sudo)]
         fn interface_sudo(&self, ctx: SudoCtx<MyQuery>) -> StdResult<Response>;
     }
 }
@@ -53,23 +53,23 @@ mod impl_interface {
     use crate::{MyQuery, OtherQuery, SomeResponse};
 
     #[contract(module=crate)]
-    #[messages(crate::interface)]
+    #[sv::messages(crate::interface)]
     #[sv::custom(query=MyQuery)]
     impl crate::interface::Interface for crate::MyContract {
         type Error = StdError;
         type QueryC = OtherQuery;
 
-        #[msg(query)]
+        #[sv::msg(query)]
         fn interface_query(&self, _ctx: QueryCtx<MyQuery>) -> StdResult<SomeResponse> {
             Ok(SomeResponse)
         }
 
-        #[msg(exec)]
+        #[sv::msg(exec)]
         fn interface_exec(&self, _ctx: ExecCtx<MyQuery>) -> StdResult<Response> {
             Ok(Response::default())
         }
 
-        #[msg(sudo)]
+        #[sv::msg(sudo)]
         fn interface_sudo(&self, _ctx: SudoCtx<MyQuery>) -> StdResult<Response> {
             Ok(Response::default())
         }
@@ -89,15 +89,15 @@ mod some_interface {
         type Error: From<StdError>;
 
         #[cfg(not(tarpaulin_include))]
-        #[msg(query)]
+        #[sv::msg(query)]
         fn some_interface_query(&self, ctx: QueryCtx<MyQuery>) -> StdResult<SomeResponse>;
 
         #[cfg(not(tarpaulin_include))]
-        #[msg(exec)]
+        #[sv::msg(exec)]
         fn some_interface_exec(&self, ctx: ExecCtx<MyQuery>) -> StdResult<Response>;
 
         #[cfg(not(tarpaulin_include))]
-        #[msg(sudo)]
+        #[sv::msg(sudo)]
         fn some_interface_sudo(&self, ctx: SudoCtx<MyQuery>) -> StdResult<Response>;
     }
 }
@@ -110,22 +110,22 @@ mod impl_some_interface {
     use crate::{MyQuery, SomeResponse};
 
     #[contract(module=crate)]
-    #[messages(crate::some_interface)]
+    #[sv::messages(crate::some_interface)]
     #[sv::custom(query=MyQuery)]
     impl super::some_interface::SomeInterface for crate::MyContract {
         type Error = StdError;
 
-        #[msg(query)]
+        #[sv::msg(query)]
         fn some_interface_query(&self, _ctx: QueryCtx<MyQuery>) -> StdResult<SomeResponse> {
             Ok(SomeResponse)
         }
 
-        #[msg(exec)]
+        #[sv::msg(exec)]
         fn some_interface_exec(&self, _ctx: ExecCtx<MyQuery>) -> StdResult<Response> {
             Ok(Response::default())
         }
 
-        #[msg(sudo)]
+        #[sv::msg(sudo)]
         fn some_interface_sudo(&self, _ctx: SudoCtx<MyQuery>) -> StdResult<Response> {
             Ok(Response::default())
         }
@@ -145,42 +145,43 @@ mod associated_type_interface {
         type QueryC: CustomQuery;
 
         #[cfg(not(tarpaulin_include))]
-        #[msg(query)]
+        #[sv::msg(query)]
         fn associated_query(&self, ctx: QueryCtx<Self::QueryC>) -> StdResult<SomeResponse>;
 
         #[cfg(not(tarpaulin_include))]
-        #[msg(exec)]
+        #[sv::msg(exec)]
         fn associated_exec(&self, ctx: ExecCtx<Self::QueryC>) -> StdResult<Response>;
 
         #[cfg(not(tarpaulin_include))]
-        #[msg(sudo)]
+        #[sv::msg(sudo)]
         fn associated_sudo(&self, ctx: SudoCtx<Self::QueryC>) -> StdResult<Response>;
     }
 }
 
 mod impl_associated_type_interface {
-    use crate::{associated_type_interface::AssociatedTypeInterface, MyQuery, SomeResponse};
+    use crate::associated_type_interface::AssociatedTypeInterface;
+    use crate::{MyQuery, SomeResponse};
     use cosmwasm_std::{Response, StdError, StdResult};
     use sylvia::types::{ExecCtx, QueryCtx, SudoCtx};
     use sylvia_derive::contract;
 
     #[contract(module=crate)]
-    #[messages(crate::associated_type_interface)]
+    #[sv::messages(crate::associated_type_interface)]
     impl AssociatedTypeInterface for crate::MyContract {
         type Error = StdError;
         type QueryC = MyQuery;
 
-        #[msg(query)]
+        #[sv::msg(query)]
         fn associated_query(&self, _ctx: QueryCtx<Self::QueryC>) -> StdResult<SomeResponse> {
             Ok(SomeResponse)
         }
 
-        #[msg(exec)]
+        #[sv::msg(exec)]
         fn associated_exec(&self, _ctx: ExecCtx<Self::QueryC>) -> StdResult<Response> {
             Ok(Response::default())
         }
 
-        #[msg(sudo)]
+        #[sv::msg(sudo)]
         fn associated_sudo(&self, _ctx: SudoCtx<Self::QueryC>) -> StdResult<Response> {
             Ok(Response::default())
         }
@@ -199,42 +200,43 @@ mod default_query_interface {
         type Error: From<StdError>;
 
         #[cfg(not(tarpaulin_include))]
-        #[msg(query)]
+        #[sv::msg(query)]
         fn default_query(&self, ctx: QueryCtx) -> StdResult<SomeResponse>;
 
         #[cfg(not(tarpaulin_include))]
-        #[msg(exec)]
+        #[sv::msg(exec)]
         fn default_exec(&self, ctx: ExecCtx) -> StdResult<Response>;
 
         #[cfg(not(tarpaulin_include))]
-        #[msg(sudo)]
+        #[sv::msg(sudo)]
         fn default_sudo(&self, ctx: SudoCtx) -> StdResult<Response>;
     }
 }
 
 mod impl_default_query_interface {
-    use crate::{default_query_interface::DefaultQueryInterface, SomeResponse};
+    use crate::default_query_interface::DefaultQueryInterface;
+    use crate::SomeResponse;
     use cosmwasm_std::{Response, StdError, StdResult};
     use sylvia::types::{ExecCtx, QueryCtx, SudoCtx};
     use sylvia_derive::contract;
 
     #[contract(module=crate)]
-    #[messages(crate::default_query_interface)]
+    #[sv::messages(crate::default_query_interface)]
     #[sv::custom(query=MyQuery)]
     impl DefaultQueryInterface for crate::MyContract {
         type Error = StdError;
 
-        #[msg(query)]
+        #[sv::msg(query)]
         fn default_query(&self, _ctx: QueryCtx) -> StdResult<SomeResponse> {
             Ok(SomeResponse)
         }
 
-        #[msg(exec)]
+        #[sv::msg(exec)]
         fn default_exec(&self, _ctx: ExecCtx) -> StdResult<Response> {
             Ok(Response::default())
         }
 
-        #[msg(sudo)]
+        #[sv::msg(sudo)]
         fn default_sudo(&self, _ctx: SudoCtx) -> StdResult<Response> {
             Ok(Response::default())
         }
@@ -242,10 +244,10 @@ mod impl_default_query_interface {
 }
 
 #[contract]
-#[messages(some_interface)]
-#[messages(associated_type_interface)]
-#[messages(interface)]
-#[messages(default_query_interface: custom(query))]
+#[sv::messages(some_interface)]
+#[sv::messages(associated_type_interface)]
+#[sv::messages(interface)]
+#[sv::messages(default_query_interface: custom(query))]
 #[sv::custom(query=MyQuery)]
 impl MyContract {
     #[allow(clippy::new_without_default)]
@@ -253,27 +255,27 @@ impl MyContract {
         Self {}
     }
 
-    #[msg(instantiate)]
+    #[sv::msg(instantiate)]
     pub fn instantiate(&self, _ctx: InstantiateCtx<MyQuery>) -> StdResult<Response> {
         Ok(Response::default())
     }
 
-    #[msg(exec)]
+    #[sv::msg(exec)]
     pub fn some_exec(&self, _ctx: ExecCtx<MyQuery>) -> StdResult<Response> {
         Ok(Response::default())
     }
 
-    #[msg(query)]
+    #[sv::msg(query)]
     pub fn some_query(&self, _ctx: QueryCtx<MyQuery>) -> StdResult<SomeResponse> {
         Ok(SomeResponse)
     }
 
-    #[msg(migrate)]
+    #[sv::msg(migrate)]
     pub fn some_migrate(&self, _ctx: MigrateCtx<MyQuery>) -> StdResult<Response> {
         Ok(Response::default())
     }
 
-    #[msg(sudo)]
+    #[sv::msg(sudo)]
     pub fn some_sudo(&self, _ctx: SudoCtx<MyQuery>) -> StdResult<Response> {
         Ok(Response::default())
     }
diff --git a/sylvia/tests/dispatching.rs b/sylvia/tests/dispatching.rs
index 1ef09be..2f12750 100644
--- a/sylvia/tests/dispatching.rs
+++ b/sylvia/tests/dispatching.rs
@@ -27,10 +27,10 @@ mod interface {
     pub trait Interface {
         type Error: From<StdError>;
 
-        #[msg(exec)]
+        #[sv::msg(exec)]
         fn no_args_execution(&self, ctx: ExecCtx) -> Result<Response, Self::Error>;
 
-        #[msg(exec)]
+        #[sv::msg(exec)]
         fn argumented_execution(
             &self,
             ctx: ExecCtx,
@@ -39,17 +39,17 @@ mod interface {
             desc: String,
         ) -> Result<Response, Self::Error>;
 
-        #[msg(query)]
+        #[sv::msg(query)]
         fn no_args_query(&self, ctx: QueryCtx) -> Result<EmptyQueryResponse, Self::Error>;
 
-        #[msg(query)]
+        #[sv::msg(query)]
         fn argumented_query(&self, ctx: QueryCtx, user: Addr)
             -> Result<QueryResponse, Self::Error>;
 
-        #[msg(sudo)]
+        #[sv::msg(sudo)]
         fn no_args_sudo(&self, ctx: SudoCtx) -> Result<Response, Self::Error>;
 
-        #[msg(sudo)]
+        #[sv::msg(sudo)]
         fn argumented_sudo(&self, ctx: SudoCtx, user: Addr) -> Result<Response, Self::Error>;
     }
 }
@@ -61,11 +61,11 @@ mod impl_interface {
     use crate::{EmptyQueryResponse, QueryResponse};
 
     #[sylvia::contract(module = crate::contract)]
-    #[messages(crate::interface)]
+    #[sv::messages(crate::interface)]
     impl crate::interface::Interface for crate::contract::Contract {
         type Error = StdError;
 
-        #[msg(exec)]
+        #[sv::msg(exec)]
         fn no_args_execution(&self, ctx: ExecCtx) -> Result<Response, StdError> {
             self.execs
                 .update(ctx.deps.storage, |count| -> Result<u64, StdError> {
@@ -74,7 +74,7 @@ mod impl_interface {
             Ok(Response::new())
         }
 
-        #[msg(exec)]
+        #[sv::msg(exec)]
         fn argumented_execution(
             &self,
             ctx: ExecCtx,
@@ -92,13 +92,13 @@ mod impl_interface {
             Ok(Response::new())
         }
 
-        #[msg(query)]
+        #[sv::msg(query)]
         fn no_args_query(&self, _: QueryCtx) -> Result<EmptyQueryResponse, StdError> {
             *self.queries.borrow_mut() += 1;
             Ok(dbg!(EmptyQueryResponse {}))
         }
 
-        #[msg(query)]
+        #[sv::msg(query)]
         fn argumented_query(
             &self,
             ctx: QueryCtx,
@@ -108,7 +108,7 @@ mod impl_interface {
             Ok(self.data.load(ctx.deps.storage, user).unwrap())
         }
 
-        #[msg(sudo)]
+        #[sv::msg(sudo)]
         fn no_args_sudo(&self, ctx: SudoCtx) -> Result<Response, Self::Error> {
             self.sudos
                 .update(ctx.deps.storage, |count| -> Result<u64, StdError> {
@@ -117,7 +117,7 @@ mod impl_interface {
             Ok(Response::new())
         }
 
-        #[msg(sudo)]
+        #[sv::msg(sudo)]
         fn argumented_sudo(&self, ctx: SudoCtx, user: Addr) -> Result<Response, Self::Error> {
             self.sudos
                 .update(ctx.deps.storage, |count| -> Result<u64, StdError> {
@@ -151,7 +151,7 @@ mod contract {
     #[allow(dead_code)]
     #[cfg(not(tarpaulin_include))]
     #[contract]
-    #[messages(crate::interface)]
+    #[sv::messages(crate::interface)]
     impl Contract {
         pub fn new() -> Self {
             Self {
@@ -162,14 +162,14 @@ mod contract {
             }
         }
 
-        #[msg(instantiate)]
+        #[sv::msg(instantiate)]
         fn instanciate(&self, ctx: InstantiateCtx) -> StdResult<Response> {
             self.execs.save(ctx.deps.storage, &0)?;
             self.sudos.save(ctx.deps.storage, &0)?;
             Ok(Response::new())
         }
 
-        #[msg(sudo)]
+        #[sv::msg(sudo)]
         fn contract_sudo(&self, ctx: SudoCtx) -> StdResult<Response> {
             self.sudos
                 .update(ctx.deps.storage, |count| -> Result<u64, StdError> {
diff --git a/sylvia/tests/entry_points.rs b/sylvia/tests/entry_points.rs
index fb42aa8..1ba076d 100644
--- a/sylvia/tests/entry_points.rs
+++ b/sylvia/tests/entry_points.rs
@@ -163,7 +163,7 @@ mod contract {
             }
         }
 
-        #[msg(instantiate)]
+        #[sv::msg(instantiate)]
         pub fn instantiate(&self, ctx: InstantiateCtx) -> StdResult<Response> {
             self.execs.save(ctx.deps.storage, &0)?;
             self.migrates.save(ctx.deps.storage, &0)?;
@@ -171,12 +171,12 @@ mod contract {
             Ok(Response::new())
         }
 
-        #[msg(migrate)]
+        #[sv::msg(migrate)]
         pub fn migrate(&self, _ctx: MigrateCtx) -> StdResult<Response> {
             Ok(Response::new())
         }
 
-        #[msg(exec)]
+        #[sv::msg(exec)]
         pub fn increase_by_two(&self, ctx: ExecCtx) -> StdResult<Response> {
             self.execs
                 .update(ctx.deps.storage, |count| -> Result<u32, StdError> {
@@ -185,25 +185,25 @@ mod contract {
             Ok(Response::new())
         }
 
-        #[msg(query)]
+        #[sv::msg(query)]
         pub fn execs(&self, ctx: QueryCtx) -> StdResult<CountResponse> {
             let count = self.execs.load(ctx.deps.storage)?;
             Ok(CountResponse { count })
         }
 
-        #[msg(query)]
+        #[sv::msg(query)]
         pub fn sudos(&self, ctx: QueryCtx) -> StdResult<CountResponse> {
             let count = self.sudos.load(ctx.deps.storage)?;
             Ok(CountResponse { count })
         }
 
-        #[msg(query)]
+        #[sv::msg(query)]
         pub fn migrates(&self, ctx: QueryCtx) -> StdResult<CountResponse> {
             let count = self.migrates.load(ctx.deps.storage)?;
             Ok(CountResponse { count })
         }
 
-        #[msg(sudo)]
+        #[sv::msg(sudo)]
         pub fn sudo(&self, _ctx: SudoCtx) -> StdResult<Response> {
             Ok(Response::new())
         }
diff --git a/sylvia/tests/messages_generation.rs b/sylvia/tests/messages_generation.rs
index be1242c..35e74d9 100644
--- a/sylvia/tests/messages_generation.rs
+++ b/sylvia/tests/messages_generation.rs
@@ -23,10 +23,10 @@ mod interface {
     pub trait Interface {
         type Error: From<StdError>;
 
-        #[msg(exec)]
+        #[sv::msg(exec)]
         fn no_args_execution(&self, ctx: ExecCtx) -> Result<Response, Self::Error>;
 
-        #[msg(exec)]
+        #[sv::msg(exec)]
         fn argumented_execution(
             &self,
             ctx: ExecCtx,
@@ -35,16 +35,16 @@ mod interface {
             #[serde(default)] desc: String,
         ) -> Result<Response, Self::Error>;
 
-        #[msg(query)]
+        #[sv::msg(query)]
         fn no_args_query(&self, ctx: QueryCtx) -> Result<QueryResult, Self::Error>;
 
-        #[msg(query)]
+        #[sv::msg(query)]
         fn argumented_query(&self, ctx: QueryCtx, user: Addr) -> Result<QueryResult, Self::Error>;
 
-        #[msg(sudo)]
+        #[sv::msg(sudo)]
         fn no_args_sudo(&self, ctx: SudoCtx) -> Result<Response, Self::Error>;
 
-        #[msg(sudo)]
+        #[sv::msg(sudo)]
         fn argumented_sudo(&self, ctx: SudoCtx, user: Addr) -> Result<Response, Self::Error>;
     }
 }
@@ -71,22 +71,22 @@ mod contract {
             Self {}
         }
 
-        #[msg(instantiate)]
+        #[sv::msg(instantiate)]
         pub fn instantiate(&self, _ctx: InstantiateCtx<MyQuery>) -> StdResult<Response> {
             Ok(Response::new())
         }
 
-        #[msg(migrate)]
+        #[sv::msg(migrate)]
         pub fn migrate(&self, _ctx: MigrateCtx<MyQuery>) -> StdResult<Response> {
             Ok(Response::new())
         }
 
-        #[msg(exec)]
+        #[sv::msg(exec)]
         fn no_args_execution(&self, _ctx: ExecCtx<MyQuery>) -> StdResult<Response> {
             Ok(Response::new())
         }
 
-        #[msg(exec)]
+        #[sv::msg(exec)]
         fn argumented_execution(
             &self,
             _ctx: ExecCtx<MyQuery>,
@@ -97,27 +97,27 @@ mod contract {
             Ok(Response::new())
         }
 
-        #[msg(query)]
+        #[sv::msg(query)]
         fn no_args_query(&self, _ctx: QueryCtx<MyQuery>) -> StdResult<QueryResult> {
             Ok(QueryResult {})
         }
 
-        #[msg(query)]
+        #[sv::msg(query)]
         fn argumented_query(&self, _ctx: QueryCtx<MyQuery>, _user: Addr) -> StdResult<QueryResult> {
             Ok(QueryResult {})
         }
 
-        #[msg(reply)]
+        #[sv::msg(reply)]
         fn my_reply(&self, _ctx: ReplyCtx<MyQuery>, _reply: Reply) -> StdResult<Response> {
             Ok(Response::new())
         }
 
-        #[msg(sudo)]
+        #[sv::msg(sudo)]
         fn no_args_sudo(&self, _ctx: SudoCtx<MyQuery>) -> StdResult<Response> {
             Ok(Response::new())
         }
 
-        #[msg(sudo)]
+        #[sv::msg(sudo)]
         fn argumented_sudo(&self, _ctx: SudoCtx<MyQuery>, _user: Addr) -> StdResult<Response> {
             Ok(Response::new())
         }
diff --git a/sylvia/tests/multitest.rs b/sylvia/tests/multitest.rs
index 4c5a46c..6bd8003 100644
--- a/sylvia/tests/multitest.rs
+++ b/sylvia/tests/multitest.rs
@@ -21,7 +21,7 @@ where
         }
     }
 
-    #[msg(instantiate)]
+    #[sv::msg(instantiate)]
     pub fn instantiate(&self, _ctx: InstantiateCtx, _param: ParamT) -> StdResult<Response> {
         Ok(Response::new())
     }
diff --git a/sylvia/tests/querier.rs b/sylvia/tests/querier.rs
index f3d8583..b2bdced 100644
--- a/sylvia/tests/querier.rs
+++ b/sylvia/tests/querier.rs
@@ -23,16 +23,16 @@ pub mod counter {
     pub trait Counter {
         type Error: From<StdError>;
 
-        #[msg(query)]
+        #[sv::msg(query)]
         fn count(&self, ctx: QueryCtx) -> StdResult<CountResponse>;
 
-        #[msg(exec)]
+        #[sv::msg(exec)]
         fn copy_count(&self, ctx: ExecCtx) -> StdResult<Response>;
 
-        #[msg(exec)]
+        #[sv::msg(exec)]
         fn set_count(&self, ctx: ExecCtx, new_count: u64) -> StdResult<Response>;
 
-        #[msg(exec)]
+        #[sv::msg(exec)]
         fn decrease_by_count(&self, ctx: ExecCtx) -> StdResult<Response>;
     }
 }
@@ -46,23 +46,23 @@ pub mod impl_counter {
     use sylvia::types::{ExecCtx, QueryCtx};
 
     #[contract(module=crate)]
-    #[messages(crate::counter)]
+    #[sv::messages(crate::counter)]
     impl Counter for super::CounterContract<'_> {
         type Error = StdError;
 
-        #[msg(query)]
+        #[sv::msg(query)]
         fn count(&self, ctx: QueryCtx) -> StdResult<CountResponse> {
             let count = self.count.load(ctx.deps.storage)?;
             Ok(CountResponse { count })
         }
 
-        #[msg(exec)]
+        #[sv::msg(exec)]
         fn set_count(&self, ctx: ExecCtx, new_count: u64) -> StdResult<Response> {
             self.count.save(ctx.deps.storage, &new_count)?;
             Ok(Response::new())
         }
 
-        #[msg(exec)]
+        #[sv::msg(exec)]
         fn copy_count(&self, ctx: ExecCtx) -> StdResult<Response> {
             let other_count = self
                 .remote
@@ -75,7 +75,7 @@ pub mod impl_counter {
             Ok(Response::new())
         }
 
-        #[msg(exec)]
+        #[sv::msg(exec)]
         fn decrease_by_count(&self, ctx: ExecCtx) -> StdResult<Response> {
             let remote = self.remote.load(ctx.deps.storage)?;
             let other_count =
@@ -98,7 +98,7 @@ pub struct CounterContract<'a> {
 }
 
 #[contract]
-#[messages(counter)]
+#[sv::messages(counter)]
 impl CounterContract<'_> {
     #[allow(clippy::new_without_default)]
     pub fn new() -> Self {
@@ -108,7 +108,7 @@ impl CounterContract<'_> {
         }
     }
 
-    #[msg(instantiate)]
+    #[sv::msg(instantiate)]
     fn instantiate(&self, ctx: InstantiateCtx, remote_addr: Addr) -> StdResult<Response> {
         self.count.save(ctx.deps.storage, &0)?;
         self.remote
diff --git a/sylvia/tests/query_returns.rs b/sylvia/tests/query_returns.rs
index b85dd6a..614c095 100644
--- a/sylvia/tests/query_returns.rs
+++ b/sylvia/tests/query_returns.rs
@@ -19,7 +19,8 @@ type QueryResult<E> = Result<QueryResponse, E>;
 
 mod msg {
     use cosmwasm_std::StdError;
-    use sylvia::{interface, types::QueryCtx};
+    use sylvia::interface;
+    use sylvia::types::QueryCtx;
 
     use crate::{QueryResponse, QueryResult};
 
@@ -27,7 +28,7 @@ mod msg {
     pub trait Interface {
         type Error: From<StdError>;
 
-        #[msg(query, resp=QueryResponse)]
+        #[sv::msg(query, resp=QueryResponse)]
         fn query(&self, ctx: QueryCtx, #[serde(default)] name: String) -> QueryResult<Self::Error>;
     }
 }
@@ -35,18 +36,18 @@ mod msg {
 pub struct SomeContract {}
 
 #[contract]
-#[error(ContractError)]
+#[sv::error(ContractError)]
 impl SomeContract {
     #[allow(clippy::new_without_default)]
     pub const fn new() -> Self {
         Self {}
     }
-    #[msg(instantiate)]
+    #[sv::msg(instantiate)]
     pub fn instantiate(&self, _ctx: InstantiateCtx) -> StdResult<Response> {
         Ok(Response::new())
     }
 
-    #[msg(query, resp=QueryResponse)]
+    #[sv::msg(query, resp=QueryResponse)]
     fn contract_query(
         &self,
         _ctx: QueryCtx,
diff --git a/sylvia/tests/remote.rs b/sylvia/tests/remote.rs
index 6245d01..6021a28 100644
--- a/sylvia/tests/remote.rs
+++ b/sylvia/tests/remote.rs
@@ -20,14 +20,14 @@ pub mod some_interface {
 }
 
 #[contract]
-#[messages(some_interface)]
+#[sv::messages(some_interface)]
 impl SomeContract {
     #[allow(clippy::new_without_default)]
     pub fn new() -> Self {
         Self
     }
 
-    #[msg(instantiate)]
+    #[sv::msg(instantiate)]
     pub fn instantiate(&self, _ctx: InstantiateCtx) -> StdResult<Response> {
         Ok(Response::new())
     }
diff --git a/sylvia/tests/replies.rs b/sylvia/tests/replies.rs
index c283f43..ddeb85a 100644
--- a/sylvia/tests/replies.rs
+++ b/sylvia/tests/replies.rs
@@ -17,12 +17,12 @@ mod noop_contract {
             Self
         }
 
-        #[msg(instantiate)]
+        #[sv::msg(instantiate)]
         fn instantiate(&self, _ctx: InstantiateCtx) -> StdResult<Response> {
             Ok(Response::new())
         }
 
-        #[msg(exec)]
+        #[sv::msg(exec)]
         fn noop(&self, _ctx: ExecCtx) -> StdResult<Response> {
             Ok(Response::new())
         }
@@ -48,12 +48,12 @@ mod reply_contract {
             Self
         }
 
-        #[msg(instantiate)]
+        #[sv::msg(instantiate)]
         fn instantiate(&self, _ctx: InstantiateCtx) -> StdResult<Response> {
             Ok(Response::new())
         }
 
-        #[msg(exec)]
+        #[sv::msg(exec)]
         fn poke(&self, _ctx: ExecCtx, noop: String) -> StdResult<Response> {
             let msg = noop_contract::sv::ExecMsg::Noop {};
             let msg = WasmMsg::Execute {
@@ -67,7 +67,7 @@ mod reply_contract {
             Ok(resp)
         }
 
-        #[msg(reply)]
+        #[sv::msg(reply)]
         fn reply(&self, _ctx: ReplyCtx, _msg: Reply) -> StdResult<Response> {
             let resp = Response::new().set_data(to_json_binary("data")?);
             Ok(resp)