cosm_utils/modules/cosmwasm/
api.rs

1use 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}