1use crate::{contract::ContractInstance, error::CosmScriptError, CosmTxResponse};
2use async_trait::async_trait;
3use cosmrs::Coin;
4use serde::{de::DeserializeOwned, Serialize};
5
6#[derive(Debug, Clone, Serialize)]
7pub struct NotImplemented(String);
8
9impl Default for NotImplemented {
10 fn default() -> Self {
12 Self("Stupid Workaround".into())
13 }
14}
15
16pub trait Instance {
18 fn instance(&self) -> &ContractInstance;
19}
20
21pub trait Interface {
23 type Init: Serialize;
24 type Exec: Serialize;
25 type Query: Serialize;
26 type Migrate: Serialize;
27}
28
29#[async_trait(?Send)]
31pub trait WasmExecute {
32 type E: Serialize;
33
34 async fn exec<'a>(
35 &self,
36 execute_msg: &'a Self::E,
37 coins: Option<&[Coin]>,
38 ) -> Result<CosmTxResponse, CosmScriptError>;
39}
40
41#[async_trait(?Send)]
42impl<T: Interface + Instance> WasmExecute for T {
43 type E = <T as Interface>::Exec;
44
45 async fn exec<'a>(
46 &self,
47 execute_msg: &'a Self::E,
48 coins: Option<&[Coin]>,
49 ) -> Result<CosmTxResponse, CosmScriptError> {
50 assert_implemented(&execute_msg)?;
51 self.instance()
52 .execute(&execute_msg, coins.unwrap_or(&[]))
53 .await
54 }
55}
56
57#[async_trait(?Send)]
60pub trait WasmInstantiate {
61 type I: Serialize;
62
63 async fn init(
64 &self,
65 instantiate_msg: Self::I,
66 admin: Option<String>,
67 coins: Option<&[Coin]>,
68 ) -> Result<CosmTxResponse, CosmScriptError>;
69}
70
71#[async_trait(?Send)]
72impl<T: Interface + Instance> WasmInstantiate for T {
73 type I = <T as Interface>::Init;
74
75 async fn init(
76 &self,
77 instantiate_msg: Self::I,
78 admin: Option<String>,
79 coins: Option<&[Coin]>,
80 ) -> Result<CosmTxResponse, CosmScriptError> {
81 assert_implemented(&instantiate_msg)?;
82 self.instance()
83 .instantiate(instantiate_msg, admin, coins.unwrap_or_default())
84 .await
85 }
86}
87
88#[async_trait(?Send)]
91pub trait WasmQuery {
92 type Q: Serialize;
93
94 async fn query<G: Serialize + DeserializeOwned>(
95 &self,
96 query_msg: Self::Q,
97 ) -> Result<G, CosmScriptError>;
98}
99
100#[async_trait(?Send)]
101impl<T: Interface + Instance> WasmQuery for T {
102 type Q = <T as Interface>::Query;
103
104 async fn query<G: Serialize + DeserializeOwned>(
105 &self,
106 query_msg: Self::Q,
107 ) -> Result<G, CosmScriptError> {
108 assert_implemented(&query_msg)?;
109 self.instance().query(query_msg).await
110 }
111}
112
113#[async_trait(?Send)]
116pub trait WasmMigrate {
117 type M: Serialize;
118
119 async fn migrate(
120 &self,
121 migrate_msg: Self::M,
122 new_code_id: u64,
123 ) -> Result<CosmTxResponse, CosmScriptError>;
124}
125
126#[async_trait(?Send)]
127impl<T: Interface + Instance> WasmMigrate for T {
128 type M = <T as Interface>::Migrate;
129
130 async fn migrate(
131 &self,
132 migrate_msg: Self::M,
133 new_code_id: u64,
134 ) -> Result<CosmTxResponse, CosmScriptError> {
135 assert_implemented(&migrate_msg)?;
136 self.instance().migrate(migrate_msg, new_code_id).await
137 }
138}
139
140#[async_trait(?Send)]
143pub trait WasmUpload {
144 async fn upload(&self, path: &str) -> Result<CosmTxResponse, CosmScriptError>;
145}
146
147#[async_trait(?Send)]
148impl<T: Instance> WasmUpload for T {
149 async fn upload(&self, path: &str) -> Result<CosmTxResponse, CosmScriptError> {
150 self.instance().upload(path).await
151 }
152}
153
154fn assert_implemented<E: Serialize>(msg: &E) -> Result<(), CosmScriptError> {
156 if serde_json::to_string(msg)? == serde_json::to_string(&NotImplemented::default())? {
157 return Err(CosmScriptError::NotImplemented);
158 }
159 Ok(())
160}
161
162