sv::msg attribute

Use the sv::msg attribute to mark methods as specific message types.

Macros

List of macros supporting the sv::msg attribute:

💡

interface macro supports the sv::msg attribute only with exec, query or sudo value.

Usage

pub struct CounterContract;
 
#[cw_serde]
pub struct SomeResponse;
 
#[cfg_attr(feature = "library", sylvia::entry_points)]
#[contract]
impl CounterContract {
    pub const fn new() -> Self {
        Self
    }
 
    #[sv::msg(instantiate)]
    fn instantiate(&self, ctx: InstantiateCtx) -> StdResult<Response> {
        Ok(Response::new())
    }
 
    #[sv::msg(exec)]
    fn some_exec(&self, ctx: ExecCtx) -> StdResult<Response> {
        Ok(Response::new())
    }
 
    #[sv::msg(query)]
    fn some_query(&self, ctx: QueryCtx) -> StdResult<SomeResponse> {
        Ok(SomeResponse)
    }
 
    #[sv::msg(sudo)]
    fn some_sudo(&self, ctx: SudoCtx) -> StdResult<Response> {
        Ok(Response::new())
    }
 
    #[sv::msg(migrate)]
    fn some_migrate(&self, ctx: MigrateCtx) -> StdResult<Response> {
        Ok(Response::new())
    }
 
    #[sv::msg(reply)]
    fn some_reply(&self, ctx: ReplyCtx, reply: Reply) -> StdResult<Response> {
        Ok(Response::new())
    }
}

Notice that each message type has its context type, like InstantiateCtx (opens in a new tab). You are required to use the appropriate type. Otherwise, the dispatch will fail to compile.

Each message type except for query expects the result type generic over Response (opens in a new tab).

Aliasing

It is possible to use aliases for types in message signatures. In case of query return type it requires however additional action. Due to QueryResponses (opens in a new tab) macro derive on generated query message, we have to explicitly provide the return type, as the macro wouldn't be able to deduce that from the alias.

#[sv::msg(query, resp=SomeResponse)]
fn some_query(&self, ctx: QueryCtx) -> SomeResult {
    Ok(SomeResponse)
}

Handling replies

💡

To use attributes present in this paragraph pre-Sylvia 2.0.0, you need to enable the replies feature using the sv::features attribute.

You can use additional parameters handlers and reply_on in the #[sv::msg(reply)] attribute.

#[sv::msg(reply, handlers=[remote_instantiated], reply_on=success)]
fn store_remote_address(
    &self,
    ctx: ReplyCtx,
    #[sv::data(instantiate, opt)] data: Option<MsgInstantiateContractResponse>,
    payload: Option<String>
) -> StdResult<Response> {
    Ok(Response::new())
}
💡

This approach requires the use of sylvia::ctx::ReplyCtx instead of sylvia::types::ReplyCtx due to additional fields added to this type.

The handlers parameter

The handlers parameter allows the list of names of the reply handlers that would be supported by the contract to be specified. Sylvia takes every unique handler name from across every reply message and generates the reply IDs, dispatching and SubMsg building methods for them. If the handlers parameter is not used, the method name is used as the handler name.

#[sv::msg(reply, handlers=[tokens_transfered, tokens_staked])]
fn update_state(
    &self,
    ctx: ReplyCtx,
    result: SubMsgResult,
    #[sv::payload(raw)] payload: Binary,
) -> StdResult<Response> {
    Ok(Response::new())
}

The reply_on parameter

The reply_on parameter specifies in which scenario should the reply method be called. It reflects the cosmwasm_std::ReplyOn (opens in a new tab) and it supports values: success, error and always. The ReplyOn::Never is not reflected since creating a reply method that would never be called is counterproductive. If the reply_on parameter is not used, the default value is always.

The same handler name can be used twice across the methods only if one has reply_on=Success and the other one reply_on=Error. This way, we can have different handling for success and error for the same reply ID.

#[sv::msg(reply, handlers=[tokens_transfered], reply_on=success)]
fn update_state(
    &self,
    ctx: ReplyCtx,
    #[sv::data(raw)] data: Binary,
    #[sv::payload(raw)] payload: Binary,
) -> StdResult<Response> {
    Ok(Response::new())
}
 
#[sv::msg(reply, handlers=[tokens_transfered], reply_on=error)]
fn revert_state(
    &self,
    ctx: ReplyCtx,
    error: String,
    #[sv::payload(raw)] payload: Binary,
) -> StdResult<Response> {
    Ok(Response::new())
}
 
#[sv::msg(reply, reply_on=always)]
fn update_or_revert_state(
    &self,
    ctx: ReplyCtx,
    result: SubMsgResult,
    #[sv::payload(raw)] payload: Binary,
) -> StdResult<Response> {
    Ok(Response::new())
}

Notice different method parameters depending on the reply_on value. On: