Override_entry_point

sv::override_entry_point attribute

Use sv::override_entry_point if you want to define an entry point of your contract yourself. This way, the sv::entry_points macro won't generate it for you. The entry point will also be used as a dispatch method in the MultiTest helpers generated by the contract macro.

💡

Use this attribute if you provide some custom logic in the entry points. Otherwise, the MultiTest helpers won't cover that logic, and thus you will miss the coverage.

Macros

List of macros supporting the sv::override_entry_point attribute:

Usage

use sylvia::contract;
use sylvia::cw_schema::cw_serde;
use sylvia::cw_std::{Response, StdResult};
use sylvia::types::InstantiateCtx;
 
pub mod entrypoints {
    use sylvia::cw_std::{entry_point, DepsMut, Env, MessageInfo};
 
    use super::sv::ContractExecMsg;
 
    use super::*;
 
    #[cfg_attr(not(feature = "library"), entry_point)]
    pub fn execute(
        deps: DepsMut,
        env: Env,
        info: MessageInfo,
        msg: ContractExecMsg,
    ) -> StdResult<Response> {
        msg.dispatch(&CounterContract, (deps, env, info))
    }
}
 
pub struct CounterContract;
 
#[cw_serde]
pub struct SomeResponse;
 
#[cfg_attr(feature = "library", sylvia::entry_points)]
#[contract]
#[sv::override_entry_point(exec=entrypoints::execute(ContractExecMsg))]
impl CounterContract {
    pub const fn new() -> Self {
        Self
    }
 
    #[sv::msg(instantiate)]
    fn instantiate(&self, ctx: InstantiateCtx) -> StdResult<Response> {
        Ok(Response::new())
    }
}

First, the sv::override_entry_point attribute expects the entry point type to override. Supported types are:

  • instantiate
  • exec
  • query
  • sudo
  • migrate
  • reply

Next, we have to provide the path to the new entry point method prefixed with the = character.

Lastly, this attribute expects the message type the entry point expects. This allows customization of the message used by the contract. If, for example your contract functionality would be extended by another contract stored as its field, it would be possible to wrap both contract messages and use that in the entry point.

An example of such an approach:

use sylvia::contract;
use sylvia::cw_schema::cw_serde;
use sylvia::cw_std::{Response, StdResult};
use sylvia::types::{ExecCtx, InstantiateCtx};
 
use self::sv::ContractExecMsg;
 
pub mod entrypoints {
    use sylvia::cw_std::{entry_point, DepsMut, Env, MessageInfo};
 
    use super::*;
 
    #[cfg_attr(not(feature = "library"), entry_point)]
    pub fn execute(
        deps: DepsMut,
        env: Env,
        info: MessageInfo,
        msg: WrapperExecMsg,
    ) -> StdResult<Response> {
        msg.dispatch(&CounterContract, (deps, env, info).into())
    }
}
 
/// ExecMsg from an external contract
#[cw_serde]
pub enum ExternalExecMsg {
    MsgVariant {},
}
 
/// Wrapper around local and external contracts ExecMsgs
#[cw_serde]
pub enum WrapperExecMsg {
    Local(ContractExecMsg),
    External(ExternalExecMsg),
}
 
/// Custom dispatch to local or external contract
impl WrapperExecMsg {
    pub fn dispatch(&self, contract: &CounterContract, ctx: ExecCtx) -> StdResult<Response> {
        match self {
            WrapperExecMsg::Local(_) => todo!(),
            WrapperExecMsg::External(_) => todo!(),
        }
    }
}
 
pub struct CounterContract;
 
#[cw_serde]
pub struct SomeResponse;
 
#[contract]
#[sv::override_entry_point(exec=entrypoints::execute(WrapperExecMsg))]
impl CounterContract {
    pub const fn new() -> Self {
        Self
    }
 
    #[sv::msg(instantiate)]
    fn instantiate(&self, ctx: InstantiateCtx) -> StdResult<Response> {
        Ok(Response::new())
    }
}