use anyhow::anyhow;
use cosmwasm_std::{
CustomMsg, CustomQuery, DepsMut, Empty, Env, Ibc3ChannelOpenResponse, IbcBasicResponse,
IbcChannelCloseMsg, IbcChannelConnectMsg, IbcChannelOpenMsg, IbcPacketAckMsg,
IbcPacketReceiveMsg, IbcPacketTimeoutMsg, IbcReceiveResponse, Never,
};
use cw_multi_test::{Contract, ContractWrapper};
use serde::de::DeserializeOwned;
use std::fmt::{Debug, Display};
use crate::error::AppResult;
use self::closures::{
IbcChannelCloseClosure, IbcChannelCloseFn, IbcChannelConnectClosure, IbcChannelConnectFn,
IbcChannelOpenClosure, IbcChannelOpenFn, IbcPacketAckClosure, IbcPacketAckFn,
IbcPacketReceiveClosure, IbcPacketReceiveFn, IbcPacketTimeoutClosure, IbcPacketTimeoutFn,
};
use cw_multi_test::error::AnyError;
#[rustfmt::skip]
mod closures {
use cosmwasm_std::{Ibc3ChannelOpenResponse, IbcReceiveResponse};
use super::*;
pub type IbcChannelOpenFn<E, Q> = fn(DepsMut<Q>, Env, IbcChannelOpenMsg) -> Result<Option<Ibc3ChannelOpenResponse>, E>;
pub type IbcChannelCloseFn<E, Q, C> = fn(DepsMut<Q>, Env, IbcChannelCloseMsg) -> Result<IbcBasicResponse<C>, E>;
pub type IbcChannelConnectFn<E, Q, C> = fn(DepsMut<Q>, Env, IbcChannelConnectMsg) -> Result<IbcBasicResponse<C>, E>;
pub type IbcPacketReceiveFn<Q, C> = fn(DepsMut<Q>, Env, IbcPacketReceiveMsg) -> Result<IbcReceiveResponse<C>, Never>;
pub type IbcPacketAckFn<E, Q, C> = fn(DepsMut<Q>, Env, IbcPacketAckMsg) -> Result<IbcBasicResponse<C>, E>;
pub type IbcPacketTimeoutFn<E, Q, C> = fn(DepsMut<Q>, Env, IbcPacketTimeoutMsg) -> Result<IbcBasicResponse<C>, E>;
pub type IbcChannelOpenClosure<E, Q> = Box<dyn Fn(DepsMut<Q>, Env, IbcChannelOpenMsg) -> Result<Option<Ibc3ChannelOpenResponse>, E>>;
pub type IbcChannelCloseClosure<E, Q, C> = Box<dyn Fn(DepsMut<Q>, Env, IbcChannelCloseMsg) -> Result<IbcBasicResponse<C>, E>>;
pub type IbcChannelConnectClosure<E, Q, C> = Box<dyn Fn(DepsMut<Q>, Env, IbcChannelConnectMsg) -> Result<IbcBasicResponse<C>, E>>;
pub type IbcPacketReceiveClosure<Q, C> = Box<dyn Fn(DepsMut<Q>, Env, IbcPacketReceiveMsg) -> Result<IbcReceiveResponse<C>, Never>>;
pub type IbcPacketAckClosure<E, Q, C> = Box<dyn Fn(DepsMut<Q>, Env, IbcPacketAckMsg) -> Result<IbcBasicResponse<C>, E>>;
pub type IbcPacketTimeoutClosure<E, Q, C> = Box<dyn Fn(DepsMut<Q>, Env, IbcPacketTimeoutMsg) -> Result<IbcBasicResponse<C>, E>>;
}
pub struct IbcClosures<E1, E2, E3, E4, E5, C, Q = Empty>
where
Q: CustomQuery,
C: CustomMsg,
{
pub fn_ibc_channel_open: IbcChannelOpenClosure<E1, Q>,
pub fn_ibc_channel_close: IbcChannelCloseClosure<E2, Q, C>,
pub fn_ibc_channel_connect: IbcChannelConnectClosure<E3, Q, C>,
pub fn_ibc_packet_receive: IbcPacketReceiveClosure<Q, C>,
pub fn_ibc_packet_ack: IbcPacketAckClosure<E4, Q, C>,
pub fn_ibc_packet_timeout: IbcPacketTimeoutClosure<E5, Q, C>,
}
impl<E1, E2, E3, E4, E5, C, Q> IbcClosures<E1, E2, E3, E4, E5, C, Q>
where
Q: CustomQuery + 'static,
C: CustomMsg + 'static,
E1: Display + Debug + Send + Sync + 'static,
E2: Display + Debug + Send + Sync + 'static,
E3: Display + Debug + Send + Sync + 'static,
E4: Display + Debug + Send + Sync + 'static,
E5: Display + Debug + Send + Sync + 'static,
{
pub fn new(
fn_ibc_channel_open: IbcChannelOpenFn<E1, Q>,
fn_ibc_channel_close: IbcChannelCloseFn<E2, Q, C>,
fn_ibc_channel_connect: IbcChannelConnectFn<E3, Q, C>,
fn_ibc_packet_receive: IbcPacketReceiveFn<Q, C>,
fn_ibc_packet_ack: IbcPacketAckFn<E4, Q, C>,
fn_ibc_packet_timeout: IbcPacketTimeoutFn<E5, Q, C>,
) -> IbcClosures<E1, E2, E3, E4, E5, C, Q> {
IbcClosures {
fn_ibc_channel_open: Box::new(fn_ibc_channel_open),
fn_ibc_channel_close: Box::new(fn_ibc_channel_close),
fn_ibc_channel_connect: Box::new(fn_ibc_channel_connect),
fn_ibc_packet_receive: Box::new(fn_ibc_packet_receive),
fn_ibc_packet_ack: Box::new(fn_ibc_packet_ack),
fn_ibc_packet_timeout: Box::new(fn_ibc_packet_timeout),
}
}
pub fn new_as_ibc_contract(
fn_ibc_channel_open: IbcChannelOpenFn<E1, Q>,
fn_ibc_channel_close: IbcChannelCloseFn<E2, Q, C>,
fn_ibc_channel_connect: IbcChannelConnectFn<E3, Q, C>,
fn_ibc_packet_receive: IbcPacketReceiveFn<Q, C>,
fn_ibc_packet_ack: IbcPacketAckFn<E4, Q, C>,
fn_ibc_packet_timeout: IbcPacketTimeoutFn<E5, Q, C>,
) -> Box<dyn IbcContract<C, Q>> {
Box::new(IbcClosures {
fn_ibc_channel_open: Box::new(fn_ibc_channel_open),
fn_ibc_channel_close: Box::new(fn_ibc_channel_close),
fn_ibc_channel_connect: Box::new(fn_ibc_channel_connect),
fn_ibc_packet_receive: Box::new(fn_ibc_packet_receive),
fn_ibc_packet_ack: Box::new(fn_ibc_packet_ack),
fn_ibc_packet_timeout: Box::new(fn_ibc_packet_timeout),
}) as Box<dyn IbcContract<C, Q>>
}
}
pub struct IperContract<C, Q = Empty>
where
C: CustomMsg,
Q: CustomQuery,
{
pub base: Box<dyn Contract<C, Q>>,
pub ibc: Option<Box<dyn IbcContract<C, Q>>>,
}
impl<C, Q> IperContract<C, Q>
where
C: CustomMsg,
Q: CustomQuery,
{
pub fn new(
base: Box<dyn Contract<C, Q>>,
ibc: Option<Box<dyn IbcContract<C, Q>>>,
) -> IperContract<C, Q> {
Self { base, ibc }
}
}
pub trait IbcContract<C, Q = Empty>
where
C: CustomMsg,
Q: CustomQuery,
{
fn ibc_channel_open(
&self,
deps: DepsMut<Q>,
env: Env,
msg: IbcChannelOpenMsg,
) -> AppResult<Option<Ibc3ChannelOpenResponse>>;
fn ibc_channel_close(
&self,
deps: DepsMut<Q>,
env: Env,
msg: IbcChannelCloseMsg,
) -> AppResult<IbcBasicResponse<C>>;
fn ibc_channel_connect(
&self,
deps: DepsMut<Q>,
env: Env,
msg: IbcChannelConnectMsg,
) -> AppResult<IbcBasicResponse<C>>;
fn ibc_packet_receive(
&self,
deps: DepsMut<Q>,
env: Env,
msg: IbcPacketReceiveMsg,
) -> AppResult<IbcReceiveResponse<C>>;
fn ibc_packet_ack(
&self,
deps: DepsMut<Q>,
env: Env,
msg: IbcPacketAckMsg,
) -> AppResult<IbcBasicResponse<C>>;
fn ibc_packet_timeout(
&self,
deps: DepsMut<Q>,
env: Env,
msg: IbcPacketTimeoutMsg,
) -> AppResult<IbcBasicResponse<C>>;
}
impl<E1, E2, E3, E4, E5, C: CustomMsg, Q: CustomQuery> IbcContract<C, Q>
for IbcClosures<E1, E2, E3, E4, E5, C, Q>
where
E1: Display + Debug + Send + Sync + 'static, E2: Display + Debug + Send + Sync + 'static, E3: Display + Debug + Send + Sync + 'static, E4: Display + Debug + Send + Sync + 'static, E5: Display + Debug + Send + Sync + 'static, {
fn ibc_channel_open(
&self,
deps: DepsMut<Q>,
env: Env,
msg: IbcChannelOpenMsg,
) -> AppResult<Option<Ibc3ChannelOpenResponse>> {
(self.fn_ibc_channel_open)(deps, env, msg).map_err(|err| anyhow!(err))
}
fn ibc_channel_close(
&self,
deps: DepsMut<Q>,
env: Env,
msg: IbcChannelCloseMsg,
) -> AppResult<IbcBasicResponse<C>> {
(self.fn_ibc_channel_close)(deps, env, msg).map_err(|err| anyhow!(err))
}
fn ibc_channel_connect(
&self,
deps: DepsMut<Q>,
env: Env,
msg: IbcChannelConnectMsg,
) -> AppResult<IbcBasicResponse<C>> {
(self.fn_ibc_channel_connect)(deps, env, msg).map_err(|err| anyhow!(err))
}
fn ibc_packet_receive(
&self,
deps: DepsMut<Q>,
env: Env,
msg: IbcPacketReceiveMsg,
) -> AppResult<IbcReceiveResponse<C>> {
(self.fn_ibc_packet_receive)(deps, env, msg).map_err(|err| anyhow!(err))
}
fn ibc_packet_ack(
&self,
deps: DepsMut<Q>,
env: Env,
msg: IbcPacketAckMsg,
) -> AppResult<IbcBasicResponse<C>> {
(self.fn_ibc_packet_ack)(deps, env, msg).map_err(|err| anyhow!(err))
}
fn ibc_packet_timeout(
&self,
deps: DepsMut<Q>,
env: Env,
msg: IbcPacketTimeoutMsg,
) -> AppResult<IbcBasicResponse<C>> {
(self.fn_ibc_packet_timeout)(deps, env, msg).map_err(|err| anyhow!(err))
}
}
pub trait ContractWrapperExt<
T1,
T2,
T3,
E1,
E2,
E3,
C = Empty,
Q = Empty,
T4 = Empty,
E4 = AnyError,
E5 = AnyError,
T6 = Empty,
E6 = AnyError,
> where
T1: DeserializeOwned, T2: DeserializeOwned, T3: DeserializeOwned, T4: DeserializeOwned, T6: DeserializeOwned, E1: Display + Debug + Send + Sync, E2: Display + Debug + Send + Sync, E3: Display + Debug + Send + Sync, E4: Display + Debug + Send + Sync, E5: Display + Debug + Send + Sync, E6: Display + Debug + Send + Sync, C: CustomMsg, Q: CustomQuery + DeserializeOwned,
{
fn to_contract(self) -> Box<dyn Contract<C, Q>>;
}
impl<T1, T2, T3, E1, E2, E3, C, Q, T4, E4, E5, T6, E6>
ContractWrapperExt<T1, T2, T3, E1, E2, E3, C, Q, T4, E4, E5, T6, E6>
for ContractWrapper<T1, T2, T3, E1, E2, E3, C, Q, T4, E4, E5, T6, E6>
where
T1: DeserializeOwned + 'static, T2: DeserializeOwned + 'static, T3: DeserializeOwned + 'static, T4: DeserializeOwned + 'static, T6: DeserializeOwned + 'static, E1: Display + Debug + Send + Sync + 'static, E2: Display + Debug + Send + Sync + 'static, E3: Display + Debug + Send + Sync + 'static, E4: Display + Debug + Send + Sync + 'static, E5: Display + Debug + Send + Sync + 'static, E6: Display + Debug + Send + Sync + 'static, C: CustomMsg + 'static, Q: CustomQuery + DeserializeOwned + 'static, {
fn to_contract(self) -> Box<dyn Contract<C, Q>> {
Box::new(self) as Box<dyn Contract<C, Q>>
}
}