#[contract]
Expand description
Procedural macro generating messages from contract impl block.
Generates instantiate
, migrate
, reply
, sudo
, exec
and query
enum messages to be later used in contract implementation.
§Example usage
pub struct SvContract {
data: Item<ContractData>,
}
#[sylvia::contract]
#[sv::error(ContractError)]
impl SvContract {
pub const fn new() -> Self {
Self {
data: Item::new("data"),
}
}
#[sv::msg(instantiate)]
fn instantiate(&self, ctx: InstantiateCtx, admin: Option<String>) -> Result<Response, ContractError> {
}
#[sv::msg(exec)]
fn execute(&self, ctx: ExecCtx) -> Result<Response, ContractError> {
}
#[sv::msg(query)]
fn query(&self, ctx: QueryCtx) -> Result<Response, ContractError> {
}
#[sv::msg(migrate)]
fn migrate(&self, ctx: MigrateCtx) -> Result<Response, ContractError> {
}
#[sv::msg(reply)]
fn reply(&self, ctx: ReplyCtx, reply: Reply) -> Result<Response, ContractError> {
}
#[sv::msg(sudo)]
fn sudo(&self, ctx: SudoCtx) -> Result<Response, ContractError> {
}
}
This would generate output like:
pub mod sv {
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(
sylvia::serde::Serialize,
sylvia::serde::Deserialize,
Clone,
Debug,
PartialEq,
sylvia::schemars::JsonSchema,
)]
#[serde(rename_all = "snake_case")]
pub struct InstantiateMsg {
pub admin: Option<String>,
}
impl InstantiateMsg {
pub fn new(admin: Option<String>) -> Self {
Self { admin }
}
pub fn dispatch(
self,
contract: &SvContract,
ctx: (
sylvia::cw_std::DepsMut<sylvia::cw_std::Empty>,
sylvia::cw_std::Env,
sylvia::cw_std::MessageInfo,
),
) -> Result<Response, ContractError> {
let Self { admin } = self;
contract
.instantiate(Into::into(ctx), admin)
.map_err(Into::into)
}
}
}
And appropriate messages for exec
, query
, migrate
, reply
and sudo
variants.
§Attributes
Contract
macro supports multiple attributes to customize the behavior of generated messages.
§sv::msg(...)
Message structures are generated based on specific implemented methods attributed with
#[sv::msg(msg_type)]
. Msg attribute takes as its first argument type of message it is
supposed to handle:
instantiate
- instantiation message handler. There should be always exactly oneexec
- execute message variantquery
- query message variantmigrate
- migrate message variantreply
- reply message variantsudo
- sudo message variant
In the case of a query, it is possible to pass a second argument which is its ResponseType
.
This is required in case of aliased results wrapping their ResponseType
to properly
implement QueryResponses
.
pub struct SvContract {
data: Item<ContractData>,
}
#[sylvia::contract]
#[sv::error(ContractError)]
impl SvContract {
pub const fn new() -> Self {
Self {
data: Item::new("data"),
}
}
#[sv::msg(instantiate)]
fn instantiate(&self, ctx: InstantiateCtx, admin: Option<String>) -> Result<Response, ContractError> {
Ok(Response::new())
}
#[sv::msg(query, resp=QueryResponse)]
fn query(&self, ctx: QueryCtx) -> Result<QueryResponse, ContractError> {
// Some query implementation
}
}
§sv::custom(msg=..., query=...)
Allows restricting interface to use specific
custom message and query types. If used with ExecC
and QueryC
associated
types sv::custom(...)
attribute has priority in defining custom types.
§sv::error(error_type)
Allows specifing custom error type for the contract. Default is cosmwasm_std::StdError
.
§sv::override_entry_point(entry_point_type=<path_to_entry_point(msg_path)>
Allows overriding default entry point for specific message type.
Used in case there is a need to provide some custom functionality inside the entry point.
Specified entry point will be used in generated multitest
helpers
pub struct SvContract;
#[cw_serde]
pub enum CustomExecMsg {}
#[entry_point]
pub fn execute(
deps: DepsMut,
env: Env,
info: MessageInfo,
msg: CustomExecMsg,
) -> StdResult<Response> {
}
#[sylvia::contract]
#[sv::override_entry_point(exec=execute(CustomExecMsg))]
impl SvContract {
}
§sv::messages(path_to_interface)
Used to declare interfaces implemented on the contract. Required for the contract to be able to handle an interface message.
pub mod sv_interface {
#[sylvia::interface]
pub trait SvInterface {
type Error: From<StdError>;
}
}
impl sv_interface::SvInterface for SvContract {
type Error = StdError;
}
pub struct SvContract;
#[sylvia::contract]
#[sv::messages(sv_interface)]
impl SvContract {
}
In case an interface has different name than a module in which its defined you have to pass the name of an interface as below:
pub mod interface {
#[sylvia::interface]
pub trait SvInterface {
type Error: From<StdError>;
}
}
impl interface::SvInterface for SvContract {
type Error = StdError;
}
pub struct SvContract;
#[sylvia::contract]
#[sv::messages(interface as SvInterface)]
impl SvContract {
}