use cosmwasm_std::{
to_binary, Attribute, Binary, Deps, DepsMut, Empty, Env, Event, MessageInfo, Reply, Response,
StdError, SubMsg, SubMsgResponse, SubMsgResult,
};
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use crate::{test_helpers::EmptyMsg, Contract, ContractWrapper};
use schemars::JsonSchema;
use std::fmt::Debug;
use cw_utils::{parse_execute_response_data, parse_instantiate_response_data};
use derivative::Derivative;
pub(crate) const EXECUTE_REPLY_BASE_ID: u64 = i64::MAX as u64;
#[derive(Debug, Clone, Serialize, Deserialize, Derivative)]
#[derivative(Default(bound = "", new = "true"))]
pub struct Message<ExecC>
where
ExecC: Debug + PartialEq + Clone + JsonSchema + 'static,
{
pub data: Option<String>,
pub sub_msg: Vec<SubMsg<ExecC>>,
pub attributes: Vec<Attribute>,
pub events: Vec<Event>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Derivative)]
#[derivative(Default(bound = "", new = "true"))]
pub struct InitMessage<ExecC>
where
ExecC: Debug + PartialEq + Clone + JsonSchema + 'static,
{
pub data: Option<String>,
pub sub_msg: Option<Vec<SubMsg<ExecC>>>,
}
#[allow(clippy::unnecessary_wraps)]
fn instantiate<ExecC>(
_deps: DepsMut,
_env: Env,
_info: MessageInfo,
msg: InitMessage<ExecC>,
) -> Result<Response<ExecC>, StdError>
where
ExecC: Debug + PartialEq + Clone + JsonSchema + 'static,
{
let mut res = Response::new();
if let Some(data) = msg.data {
res = res.set_data(data.into_bytes());
}
if let Some(msgs) = msg.sub_msg {
res = res.add_submessages(msgs);
}
Ok(res)
}
#[allow(clippy::unnecessary_wraps)]
fn execute<ExecC>(
_deps: DepsMut,
_env: Env,
_info: MessageInfo,
msg: Message<ExecC>,
) -> Result<Response<ExecC>, StdError>
where
ExecC: Debug + PartialEq + Clone + JsonSchema + 'static,
{
let mut resp = Response::new();
if let Some(data) = msg.data {
resp = resp.set_data(data.into_bytes());
}
Ok(resp
.add_submessages(msg.sub_msg)
.add_attributes(msg.attributes)
.add_events(msg.events))
}
fn query(_deps: Deps, _env: Env, msg: EmptyMsg) -> Result<Binary, StdError> {
to_binary(&msg)
}
#[allow(clippy::unnecessary_wraps)]
fn reply<ExecC>(_deps: DepsMut, _env: Env, msg: Reply) -> Result<Response<ExecC>, StdError>
where
ExecC: Debug + PartialEq + Clone + JsonSchema + 'static,
{
let res = Response::new();
if let Reply {
id,
result: SubMsgResult::Ok(SubMsgResponse {
data: Some(data), ..
}),
} = msg
{
let parsed_data = if id < EXECUTE_REPLY_BASE_ID {
parse_instantiate_response_data(data.as_slice())
.map_err(|e| StdError::generic_err(e.to_string()))?
.data
} else {
parse_execute_response_data(data.as_slice())
.map_err(|e| StdError::generic_err(e.to_string()))?
.data
};
if let Some(data) = parsed_data {
Ok(res.set_data(data))
} else {
Ok(res)
}
} else {
Ok(res)
}
}
pub fn contract() -> Box<dyn Contract<Empty>> {
let contract = ContractWrapper::new(execute::<Empty>, instantiate::<Empty>, query)
.with_reply(reply::<Empty>);
Box::new(contract)
}
pub fn custom_contract<C>() -> Box<dyn Contract<C>>
where
C: Clone + Debug + PartialEq + JsonSchema + DeserializeOwned + 'static,
{
let contract =
ContractWrapper::new(execute::<C>, instantiate::<C>, query).with_reply(reply::<C>);
Box::new(contract)
}