Interface

Interface

Use the interface (opens in a new tab) macro to abstract semantical parts of your contracts.

💡
Use interface macro only on Rust traits.

Usage

use cosmwasm_schema::cw_serde;
use sylvia::cw_std::{Response, StdError, StdResult};
use sylvia::interface;
use sylvia::types::{ExecCtx, QueryCtx};
 
#[cw_serde]
pub struct InterfaceQueryResp {}
 
#[interface]
pub trait Interface {
    type Error: From<StdError>;
 
    #[sv::msg(exec)]
    fn interface_exec(&self, ctx: ExecCtx) -> Result<Response, Self::Error>;
 
    #[sv::msg(query)]
    fn interface_query(&self, ctx: QueryCtx) -> Result<InterfaceQueryResp, Self::Error>;
 
    #[sv::msg(sudo)]
    fn interface_sudo(&self, ctx: SudoCtx) -> Result<Response, Self::Error>;
}

As mentioned earlier interface macro is used attached to the Rust traits.

We define the Error associated type. Thanks to that, future contracts implementing this interface will be able to assign their error type to it and have wider range of errors than the StdError.

💡

Error associated type is the only mandatory thing to be defined for the interface macro.

Then we can define our messages signatures. We do that by marking the methods with the sv::msg attribute.

Custom types

You can construct your interface to work with some specific custom types with the sv::custom attribute. Use of sv::custom restricts the interface to work with the predefined custom types.

If you want to allow the users to use the interface with their own specified custom types, you can declare ExecC and QueryC associated types, where ExecC specifies the CustomMsg and QueryC the CustomQuery.

use cosmwasm_schema::cw_serde;
use sylvia::cw_std::{Response, StdError, StdResult};
use sylvia::interface;
use sylvia::types::{CustomMsg, CustomQuery, ExecCtx, QueryCtx, SudoCtx};
 
#[cw_serde]
pub struct InterfaceQueryResp {}
 
#[interface]
pub trait Interface {
    type Error: From<StdError>;
    type ExecC: CustomMsg;
    type QueryC: CustomQuery;
 
    #[sv::msg(exec)]
    fn interface_exec(&self, ctx: ExecCtx<Self::QueryC>) -> StdResult<Response<Self::ExecC>>;
 
    #[sv::msg(query)]
    fn interface_query(&self, ctx: QueryCtx<Self::QueryC>) -> StdResult<InterfaceQueryResp>;
 
    #[sv::msg(sudo)]
    fn interface_sudo(&self, ctx: SudoCtx<Self::QueryC>) -> StdResult<Response<Self::ExecC>>;
}
💡
Remember to pass the associated types to context and Response types.

Generic types

The interface macro does not support generics. Instead, you can provide generic functionality using the associated types. It's because Sylvia interfaces can be implemented only once per contract, and in such a case, associated types are semantically correct in Rust.

#[interface]
pub trait Interface {
    type Error: From<StdError>;
    type MyType: CustomMsg;
 
    #[sv::msg(exec)]
    fn interface_exec(&self, ctx: ExecCtx, param: Self::MyType) -> StdResult<Response>;
}

Forwarding attributes to fields

The interface (opens in a new tab) macro can forward attributes to the fields of the messages.

#[sv::msg(exec)]
fn exec(
    &self,
    ctx: ExecCtx,
    #[serde(default)] value: String,
) -> Result<Response, Self::Error>;

The output of the above code will be:

pub enum MyInterfaceExecMsg {
    Exec {
        #[serde(default)]
        value: String,
    },
}