Attribute Macro sylvia::contract

source ·
#[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 one
  • exec - execute message variant
  • query - query message variant
  • migrate - migrate message variant
  • reply - reply message variant
  • sudo - 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 {
}