cosm_utils/modules/cosmwasm/
api.rs1use async_trait::async_trait;
2use serde::Serialize;
3
4use crate::chain::request::TxOptions;
5use crate::clients::client::{ClientTxCommit, GetEvents};
6use crate::config::cfg::ChainConfig;
7use crate::prelude::ClientAbciQuery;
8use cosmrs::proto::cosmwasm::wasm::v1::{
9 QuerySmartContractStateRequest, QuerySmartContractStateResponse,
10};
11
12use crate::modules::auth::model::Address;
13use crate::signing_key::key::SigningKey;
14
15use super::model::{
16 ExecRequest, InstantiateBatchResponse, InstantiateRequest, MigrateRequest,
17 StoreCodeBatchResponse, StoreCodeRequest,
18};
19use super::{
20 error::CosmwasmError,
21 model::{InstantiateResponse, StoreCodeResponse},
22};
23
24impl<T> CosmwasmTxCommit for T where T: ClientTxCommit + ClientAbciQuery {}
25
26#[async_trait]
27pub trait CosmwasmTxCommit: ClientTxCommit + ClientAbciQuery {
28 async fn wasm_store_commit(
29 &self,
30 chain_cfg: &ChainConfig,
31 req: StoreCodeRequest,
32 key: &SigningKey,
33 tx_options: &TxOptions,
34 ) -> Result<StoreCodeResponse<<Self as ClientTxCommit>::Response>, CosmwasmError> {
35 let mut res = self
36 .wasm_store_batch_commit(chain_cfg, vec![req], key, tx_options)
37 .await?;
38
39 Ok(StoreCodeResponse {
40 code_id: res.code_ids.remove(0),
41 res: res.res,
42 })
43 }
44
45 async fn wasm_store_batch_commit<I>(
46 &self,
47 chain_cfg: &ChainConfig,
48 reqs: I,
49 key: &SigningKey,
50 tx_options: &TxOptions,
51 ) -> Result<StoreCodeBatchResponse<<Self as ClientTxCommit>::Response>, CosmwasmError>
52 where
53 I: IntoIterator<Item = StoreCodeRequest> + Send,
54 {
55 let sender_addr = key
56 .to_addr(&chain_cfg.prefix, &chain_cfg.derivation_path)
57 .await?;
58
59 let msgs = reqs
60 .into_iter()
61 .map(|r| r.to_proto(sender_addr.clone()))
62 .collect::<Result<Vec<_>, _>>()?;
63
64 let tx_raw = self.tx_sign(chain_cfg, msgs, key, tx_options).await?;
65
66 let res = self.broadcast_tx_commit(&tx_raw).await?;
67
68 let code_ids = res
69 .find_event_tags("store_code".to_string(), "code_id".to_string())
70 .into_iter()
71 .map(|x| x.value.parse::<u64>())
72 .collect::<Result<Vec<_>, _>>()
73 .map_err(|_| CosmwasmError::MissingEvent)?;
74
75 Ok(StoreCodeBatchResponse { code_ids, res })
76 }
77
78 async fn wasm_instantiate_commit<S>(
79 &self,
80 chain_cfg: &ChainConfig,
81 req: InstantiateRequest<S>,
82 key: &SigningKey,
83 tx_options: &TxOptions,
84 ) -> Result<InstantiateResponse<<Self as ClientTxCommit>::Response>, CosmwasmError>
85 where
86 S: Serialize + Send,
87 {
88 let mut res = self
89 .wasm_instantiate_batch_commit(chain_cfg, vec![req], key, tx_options)
90 .await?;
91
92 Ok(InstantiateResponse {
93 address: res.addresses.remove(0),
94 res: res.res,
95 })
96 }
97
98 async fn wasm_instantiate_batch_commit<S, I>(
99 &self,
100 chain_cfg: &ChainConfig,
101 reqs: I,
102 key: &SigningKey,
103 tx_options: &TxOptions,
104 ) -> Result<InstantiateBatchResponse<<Self as ClientTxCommit>::Response>, CosmwasmError>
105 where
106 S: Serialize + Send,
107 I: IntoIterator<Item = InstantiateRequest<S>> + Send,
108 {
109 let sender_addr = key
110 .to_addr(&chain_cfg.prefix, &chain_cfg.derivation_path)
111 .await?;
112
113 let msgs = reqs
114 .into_iter()
115 .map(|r| r.to_proto(sender_addr.clone()))
116 .collect::<Result<Vec<_>, _>>()?;
117
118 let tx_raw = self.tx_sign(chain_cfg, msgs, key, tx_options).await?;
119
120 let res = self.broadcast_tx_commit(&tx_raw).await?;
121
122 let events =
123 res.find_event_tags("instantiate".to_string(), "_contract_address".to_string());
124
125 if events.is_empty() {
126 return Err(CosmwasmError::MissingEvent);
127 }
128
129 let addrs = events
130 .into_iter()
131 .map(|e| e.value.parse())
132 .collect::<Result<Vec<_>, _>>()?;
133
134 Ok(InstantiateBatchResponse {
135 addresses: addrs,
136 res,
137 })
138 }
139
140 async fn wasm_execute_commit<S>(
141 &self,
142 chain_cfg: &ChainConfig,
143 req: ExecRequest<S>,
144 key: &SigningKey,
145 tx_options: &TxOptions,
146 ) -> Result<<Self as ClientTxCommit>::Response, CosmwasmError>
147 where
148 S: Serialize + Send,
149 {
150 self.wasm_execute_batch_commit(chain_cfg, vec![req], key, tx_options)
151 .await
152 }
153
154 async fn wasm_execute_batch_commit<S, I>(
155 &self,
156 chain_cfg: &ChainConfig,
157 reqs: I,
158 key: &SigningKey,
159 tx_options: &TxOptions,
160 ) -> Result<<Self as ClientTxCommit>::Response, CosmwasmError>
161 where
162 S: Serialize + Send,
163 I: IntoIterator<Item = ExecRequest<S>> + Send,
164 {
165 let sender_addr = key
166 .to_addr(&chain_cfg.prefix, &chain_cfg.derivation_path)
167 .await?;
168
169 let msgs = reqs
170 .into_iter()
171 .map(|r| r.to_proto(sender_addr.clone()))
172 .collect::<Result<Vec<_>, _>>()?;
173
174 let tx_raw = self.tx_sign(chain_cfg, msgs, key, tx_options).await?;
175
176 let res = self.broadcast_tx_commit(&tx_raw).await?;
177
178 Ok(res)
179 }
180
181 async fn wasm_migrate_commit<S>(
182 &self,
183 chain_cfg: &ChainConfig,
184 req: MigrateRequest<S>,
185 key: &SigningKey,
186 tx_options: &TxOptions,
187 ) -> Result<<Self as ClientTxCommit>::Response, CosmwasmError>
188 where
189 S: Serialize + Send,
190 {
191 self.wasm_migrate_batch_commit(chain_cfg, vec![req], key, tx_options)
192 .await
193 }
194
195 async fn wasm_migrate_batch_commit<S, I>(
196 &self,
197 chain_cfg: &ChainConfig,
198 reqs: I,
199 key: &SigningKey,
200 tx_options: &TxOptions,
201 ) -> Result<<Self as ClientTxCommit>::Response, CosmwasmError>
202 where
203 S: Serialize + Send,
204 I: IntoIterator<Item = MigrateRequest<S>> + Send,
205 {
206 let sender_addr = key
207 .to_addr(&chain_cfg.prefix, &chain_cfg.derivation_path)
208 .await?;
209
210 let msgs = reqs
211 .into_iter()
212 .map(|r| r.to_proto(sender_addr.clone()))
213 .collect::<Result<Vec<_>, _>>()?;
214
215 let tx_raw = self.tx_sign(chain_cfg, msgs, key, tx_options).await?;
216
217 let res = self.broadcast_tx_commit(&tx_raw).await?;
218
219 Ok(res)
220 }
221}
222
223impl<T> CosmwasmQuery for T where T: ClientAbciQuery {}
224
225#[async_trait]
226pub trait CosmwasmQuery: ClientAbciQuery {
227 async fn wasm_query<S: Serialize + Sync>(
228 &self,
229 address: Address,
230 msg: &S,
231 ) -> Result<QuerySmartContractStateResponse, CosmwasmError> {
232 let payload = serde_json::to_vec(msg).map_err(CosmwasmError::json)?;
233
234 let req = QuerySmartContractStateRequest {
235 address: address.into(),
236 query_data: payload,
237 };
238
239 let res = self
240 .query::<_, QuerySmartContractStateResponse>(
241 req,
242 "/cosmwasm.wasm.v1.Query/SmartContractState",
243 )
244 .await?;
245
246 Ok(res)
247 }
248}