use crate::{contract::ContractInstance, error::BootError, CosmTxResponse};
use async_trait::async_trait;
use cosmrs::Coin;
use serde::{de::DeserializeOwned, Serialize};
#[derive(Debug, Clone, Serialize)]
pub struct NotImplemented(String);
impl Default for NotImplemented {
fn default() -> Self {
Self("Stupid Workaround".into())
}
}
pub trait Instance {
fn instance(&self) -> &ContractInstance;
}
pub trait Interface {
type Init: Serialize;
type Exec: Serialize;
type Query: Serialize;
type Migrate: Serialize;
}
#[async_trait(?Send)]
pub trait WasmExecute {
type E: Serialize;
async fn exec<'a>(
&self,
execute_msg: &'a Self::E,
coins: Option<&[Coin]>,
) -> Result<CosmTxResponse, BootError>;
}
#[async_trait(?Send)]
impl<T: Interface + Instance> WasmExecute for T {
type E = <T as Interface>::Exec;
async fn exec<'a>(
&self,
execute_msg: &'a Self::E,
coins: Option<&[Coin]>,
) -> Result<CosmTxResponse, BootError> {
assert_implemented(&execute_msg)?;
self.instance()
.execute(&execute_msg, coins.unwrap_or(&[]))
.await
}
}
#[async_trait(?Send)]
pub trait WasmInstantiate {
type I: Serialize;
async fn init(
&self,
instantiate_msg: Self::I,
admin: Option<String>,
coins: Option<&[Coin]>,
) -> Result<CosmTxResponse, BootError>;
}
#[async_trait(?Send)]
impl<T: Interface + Instance> WasmInstantiate for T {
type I = <T as Interface>::Init;
async fn init(
&self,
instantiate_msg: Self::I,
admin: Option<String>,
coins: Option<&[Coin]>,
) -> Result<CosmTxResponse, BootError> {
assert_implemented(&instantiate_msg)?;
self.instance()
.instantiate(instantiate_msg, admin, coins.unwrap_or_default())
.await
}
}
#[async_trait(?Send)]
pub trait WasmQuery {
type Q: Serialize;
async fn query<G: Serialize + DeserializeOwned>(
&self,
query_msg: Self::Q,
) -> Result<G, BootError>;
}
#[async_trait(?Send)]
impl<T: Interface + Instance> WasmQuery for T {
type Q = <T as Interface>::Query;
async fn query<G: Serialize + DeserializeOwned>(
&self,
query_msg: Self::Q,
) -> Result<G, BootError> {
assert_implemented(&query_msg)?;
self.instance().query(query_msg).await
}
}
#[async_trait(?Send)]
pub trait WasmMigrate {
type M: Serialize;
async fn migrate(
&self,
migrate_msg: Self::M,
new_code_id: u64,
) -> Result<CosmTxResponse, BootError>;
}
#[async_trait(?Send)]
impl<T: Interface + Instance> WasmMigrate for T {
type M = <T as Interface>::Migrate;
async fn migrate(
&self,
migrate_msg: Self::M,
new_code_id: u64,
) -> Result<CosmTxResponse, BootError> {
assert_implemented(&migrate_msg)?;
self.instance().migrate(migrate_msg, new_code_id).await
}
}
#[async_trait(?Send)]
pub trait WasmUpload {
async fn upload(&self, path: &str) -> Result<CosmTxResponse, BootError>;
}
#[async_trait(?Send)]
impl<T: Instance> WasmUpload for T {
async fn upload(&self, path: &str) -> Result<CosmTxResponse, BootError> {
self.instance().upload(path).await
}
}
fn assert_implemented<E: Serialize>(msg: &E) -> Result<(), BootError> {
if serde_json::to_string(msg)? == serde_json::to_string(&NotImplemented::default())? {
return Err(BootError::NotImplemented);
}
Ok(())
}