Skip to main content

cosm_tome/modules/cosmwasm/
model.rs

1use cosmrs::proto::cosmwasm::wasm::v1::MsgStoreCode;
2use cosmrs::proto::cosmwasm::wasm::v1::{
3    AccessConfig as ProtoAccessConfig, AccessType as ProtoAccessType, MsgExecuteContract,
4    MsgInstantiateContract, MsgMigrateContract, QuerySmartContractStateResponse,
5};
6use schemars::JsonSchema;
7use serde::{Deserialize, Serialize};
8
9use crate::chain::error::DeserializeError;
10use crate::chain::msg::Msg;
11use crate::{
12    chain::{
13        coin::Coin,
14        response::{ChainResponse, ChainTxResponse, Code},
15    },
16    modules::auth::model::Address,
17};
18
19use super::error::CosmwasmError;
20
21#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)]
22pub struct StoreCodeRequest {
23    pub wasm_data: Vec<u8>,
24    pub instantiate_perms: Option<AccessConfig>,
25}
26
27impl StoreCodeRequest {
28    pub fn to_proto(self, signer_addr: Address) -> Result<StoreCodeProto, CosmwasmError> {
29        Ok(StoreCodeProto {
30            signer_addr,
31            wasm_data: self.wasm_data,
32            instantiate_perms: self.instantiate_perms,
33        })
34    }
35}
36
37#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)]
38pub struct StoreCodeProto {
39    pub signer_addr: Address,
40    pub wasm_data: Vec<u8>,
41    pub instantiate_perms: Option<AccessConfig>,
42}
43
44impl Msg for StoreCodeProto {
45    type Proto = MsgStoreCode;
46    type Err = CosmwasmError;
47}
48
49impl TryFrom<MsgStoreCode> for StoreCodeProto {
50    type Error = CosmwasmError;
51
52    fn try_from(msg: MsgStoreCode) -> Result<Self, Self::Error> {
53        Ok(Self {
54            signer_addr: msg.sender.parse()?,
55            wasm_data: msg.wasm_byte_code,
56            instantiate_perms: msg
57                .instantiate_permission
58                .map(TryFrom::try_from)
59                .transpose()?,
60        })
61    }
62}
63
64impl TryFrom<StoreCodeProto> for MsgStoreCode {
65    type Error = CosmwasmError;
66
67    fn try_from(req: StoreCodeProto) -> Result<Self, Self::Error> {
68        Ok(Self {
69            sender: req.signer_addr.into(),
70            wasm_byte_code: req.wasm_data,
71            instantiate_permission: req.instantiate_perms.map(Into::into),
72        })
73    }
74}
75
76#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, Eq, PartialEq)]
77pub struct StoreCodeResponse {
78    pub code_id: u64,
79    pub res: ChainTxResponse,
80}
81
82impl StoreCodeResponse {
83    pub fn data<'a, T: Deserialize<'a>>(&'a self) -> Result<T, DeserializeError> {
84        self.res.res.data()
85    }
86}
87
88impl AsRef<ChainTxResponse> for StoreCodeResponse {
89    fn as_ref(&self) -> &ChainTxResponse {
90        &self.res
91    }
92}
93
94#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, Eq, PartialEq)]
95pub struct StoreCodeBatchResponse {
96    pub code_ids: Vec<u64>,
97    pub res: ChainTxResponse,
98}
99
100impl StoreCodeBatchResponse {
101    pub fn data<'a, T: Deserialize<'a>>(&'a self) -> Result<T, DeserializeError> {
102        self.res.res.data()
103    }
104}
105
106impl AsRef<ChainTxResponse> for StoreCodeBatchResponse {
107    fn as_ref(&self) -> &ChainTxResponse {
108        &self.res
109    }
110}
111
112#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)]
113pub struct InstantiateRequest<S: Serialize> {
114    pub code_id: u64,
115    pub msg: S,
116    pub label: String,
117    pub admin: Option<Address>,
118    pub funds: Vec<Coin>,
119}
120
121impl<S: Serialize> InstantiateRequest<S> {
122    pub fn to_proto(self, signer_addr: Address) -> Result<InstantiateRequestProto, CosmwasmError> {
123        let payload = serde_json::to_vec(&self.msg).map_err(CosmwasmError::json)?;
124
125        Ok(InstantiateRequestProto {
126            signer_addr,
127            code_id: self.code_id,
128            msg: payload,
129            label: self.label,
130            admin: self.admin,
131            funds: self.funds,
132        })
133    }
134}
135
136#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)]
137pub struct InstantiateRequestProto {
138    pub signer_addr: Address,
139    pub code_id: u64,
140    pub msg: Vec<u8>,
141    pub label: String,
142    pub admin: Option<Address>,
143    pub funds: Vec<Coin>,
144}
145
146impl Msg for InstantiateRequestProto {
147    type Proto = MsgInstantiateContract;
148    type Err = CosmwasmError;
149}
150
151impl TryFrom<MsgInstantiateContract> for InstantiateRequestProto {
152    type Error = CosmwasmError;
153
154    fn try_from(msg: MsgInstantiateContract) -> Result<Self, Self::Error> {
155        let admin = if msg.admin.is_empty() {
156            None
157        } else {
158            Some(msg.admin.parse()?)
159        };
160
161        Ok(Self {
162            signer_addr: msg.sender.parse()?,
163            code_id: msg.code_id,
164            msg: msg.msg,
165            label: msg.label,
166            admin,
167            funds: msg
168                .funds
169                .into_iter()
170                .map(TryInto::try_into)
171                .collect::<Result<Vec<_>, _>>()?,
172        })
173    }
174}
175
176impl TryFrom<InstantiateRequestProto> for MsgInstantiateContract {
177    type Error = CosmwasmError;
178
179    fn try_from(req: InstantiateRequestProto) -> Result<Self, Self::Error> {
180        Ok(Self {
181            sender: req.signer_addr.into(),
182            admin: req.admin.map(Into::into).unwrap_or_default(),
183            code_id: req.code_id,
184            label: req.label,
185            msg: req.msg,
186            funds: req.funds.into_iter().map(Into::into).collect(),
187        })
188    }
189}
190
191#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)]
192pub struct InstantiateResponse {
193    pub address: Address,
194    pub res: ChainTxResponse,
195}
196
197impl InstantiateResponse {
198    pub fn data<'a, T: Deserialize<'a>>(&'a self) -> Result<T, DeserializeError> {
199        self.res.res.data()
200    }
201}
202
203impl AsRef<ChainTxResponse> for InstantiateResponse {
204    fn as_ref(&self) -> &ChainTxResponse {
205        &self.res
206    }
207}
208
209#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)]
210pub struct InstantiateBatchResponse {
211    pub addresses: Vec<Address>,
212    pub res: ChainTxResponse,
213}
214
215impl InstantiateBatchResponse {
216    pub fn data<'a, T: Deserialize<'a>>(&'a self) -> Result<T, DeserializeError> {
217        self.res.res.data()
218    }
219}
220
221impl AsRef<ChainTxResponse> for InstantiateBatchResponse {
222    fn as_ref(&self) -> &ChainTxResponse {
223        &self.res
224    }
225}
226
227#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)]
228pub struct ExecRequest<S: Serialize> {
229    pub address: Address,
230    pub msg: S,
231    pub funds: Vec<Coin>,
232}
233
234impl<S: Serialize> ExecRequest<S> {
235    pub fn to_proto(self, signer_addr: Address) -> Result<ExecRequestProto, CosmwasmError> {
236        let payload = serde_json::to_vec(&self.msg).map_err(CosmwasmError::json)?;
237
238        Ok(ExecRequestProto {
239            signer_addr,
240            contract_addr: self.address,
241            msg: payload,
242            funds: self.funds,
243        })
244    }
245}
246
247#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)]
248pub struct ExecRequestProto {
249    pub signer_addr: Address,
250    pub contract_addr: Address,
251    pub msg: Vec<u8>,
252    pub funds: Vec<Coin>,
253}
254
255impl Msg for ExecRequestProto {
256    type Proto = MsgExecuteContract;
257    type Err = CosmwasmError;
258}
259
260impl TryFrom<MsgExecuteContract> for ExecRequestProto {
261    type Error = CosmwasmError;
262
263    fn try_from(msg: MsgExecuteContract) -> Result<Self, Self::Error> {
264        Ok(Self {
265            signer_addr: msg.sender.parse()?,
266            contract_addr: msg.contract.parse()?,
267            msg: msg.msg,
268            funds: msg
269                .funds
270                .into_iter()
271                .map(TryInto::try_into)
272                .collect::<Result<Vec<_>, _>>()?,
273        })
274    }
275}
276
277impl TryFrom<ExecRequestProto> for MsgExecuteContract {
278    type Error = CosmwasmError;
279
280    fn try_from(req: ExecRequestProto) -> Result<Self, Self::Error> {
281        Ok(Self {
282            sender: req.signer_addr.into(),
283            contract: req.contract_addr.into(),
284            msg: req.msg,
285            funds: req.funds.into_iter().map(Into::into).collect(),
286        })
287    }
288}
289
290#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, Eq, PartialEq)]
291pub struct ExecResponse {
292    pub res: ChainTxResponse,
293}
294
295impl ExecResponse {
296    pub fn data<'a, T: Deserialize<'a>>(&'a self) -> Result<T, DeserializeError> {
297        self.res.res.data()
298    }
299}
300
301impl AsRef<ChainTxResponse> for ExecResponse {
302    fn as_ref(&self) -> &ChainTxResponse {
303        &self.res
304    }
305}
306
307#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, Eq, PartialEq)]
308pub struct QueryResponse {
309    pub res: ChainResponse,
310}
311
312impl QueryResponse {
313    pub fn data<'a, T: Deserialize<'a>>(&'a self) -> Result<T, DeserializeError> {
314        self.res.data()
315    }
316}
317
318impl AsRef<ChainResponse> for QueryResponse {
319    fn as_ref(&self) -> &ChainResponse {
320        &self.res
321    }
322}
323
324#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)]
325pub struct MigrateRequest<S: Serialize> {
326    pub address: Address,
327    pub new_code_id: u64,
328    pub msg: S,
329}
330
331impl<S: Serialize> MigrateRequest<S> {
332    pub fn to_proto(self, signer_addr: Address) -> Result<MigrateRequestProto, CosmwasmError> {
333        let payload = serde_json::to_vec(&self.msg).map_err(CosmwasmError::json)?;
334
335        Ok(MigrateRequestProto {
336            signer_addr,
337            contract_addr: self.address,
338            new_code_id: self.new_code_id,
339            msg: payload,
340        })
341    }
342}
343
344#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)]
345pub struct MigrateRequestProto {
346    pub signer_addr: Address,
347    pub contract_addr: Address,
348    pub new_code_id: u64,
349    pub msg: Vec<u8>,
350}
351
352impl Msg for MigrateRequestProto {
353    type Proto = MsgMigrateContract;
354    type Err = CosmwasmError;
355}
356
357impl TryFrom<MsgMigrateContract> for MigrateRequestProto {
358    type Error = CosmwasmError;
359
360    fn try_from(msg: MsgMigrateContract) -> Result<Self, Self::Error> {
361        Ok(Self {
362            signer_addr: msg.sender.parse()?,
363            contract_addr: msg.contract.parse()?,
364            new_code_id: msg.code_id,
365            msg: msg.msg,
366        })
367    }
368}
369
370impl TryFrom<MigrateRequestProto> for MsgMigrateContract {
371    type Error = CosmwasmError;
372
373    fn try_from(req: MigrateRequestProto) -> Result<Self, Self::Error> {
374        Ok(Self {
375            sender: req.signer_addr.into(),
376            contract: req.contract_addr.into(),
377            code_id: req.new_code_id,
378            msg: req.msg,
379        })
380    }
381}
382
383#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, Eq, PartialEq)]
384pub struct MigrateResponse {
385    pub res: ChainTxResponse,
386}
387
388impl MigrateResponse {
389    pub fn data<'a, T: Deserialize<'a>>(&'a self) -> Result<T, DeserializeError> {
390        self.res.res.data()
391    }
392}
393
394impl AsRef<ChainTxResponse> for MigrateResponse {
395    fn as_ref(&self) -> &ChainTxResponse {
396        &self.res
397    }
398}
399
400impl From<QuerySmartContractStateResponse> for ChainResponse {
401    fn from(res: QuerySmartContractStateResponse) -> ChainResponse {
402        ChainResponse {
403            code: Code::Ok,
404            data: Some(res.data),
405            ..Default::default()
406        }
407    }
408}
409
410#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)]
411pub struct AccessConfig {
412    pub permission: AccessType,
413    pub account: Address,
414}
415
416impl From<AccessConfig> for cosmrs::cosmwasm::AccessConfig {
417    fn from(config: AccessConfig) -> Self {
418        Self {
419            permission: config.permission.into(),
420            address: config.account.into(),
421        }
422    }
423}
424
425impl From<cosmrs::cosmwasm::AccessConfig> for AccessConfig {
426    fn from(config: cosmrs::cosmwasm::AccessConfig) -> Self {
427        Self {
428            permission: config.permission.into(),
429            account: config.address.into(),
430        }
431    }
432}
433
434impl From<AccessConfig> for ProtoAccessConfig {
435    fn from(config: AccessConfig) -> Self {
436        Self {
437            permission: config.permission as i32,
438            address: config.account.into(),
439        }
440    }
441}
442
443impl TryFrom<ProtoAccessConfig> for AccessConfig {
444    type Error = CosmwasmError;
445
446    fn try_from(config: ProtoAccessConfig) -> Result<Self, Self::Error> {
447        Ok(Self {
448            permission: config.permission.try_into()?,
449            account: config.address.parse()?,
450        })
451    }
452}
453
454#[derive(
455    Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, Eq, PartialEq, Hash, PartialOrd, Ord,
456)]
457#[repr(i32)]
458pub enum AccessType {
459    /// ACCESS_TYPE_UNSPECIFIED placeholder for empty value
460    Unspecified = 0,
461    /// ACCESS_TYPE_NOBODY forbidden TODO: better comments that explains what it actually does like we do in BroadcastMode
462    Nobody = 1,
463    /// ACCESS_TYPE_ONLY_ADDRESS restricted to an address
464    OnlyAddress = 2,
465    /// ACCESS_TYPE_EVERYBODY unrestricted
466    Everybody = 3,
467}
468
469impl AsRef<str> for AccessType {
470    fn as_ref(&self) -> &str {
471        match self {
472            AccessType::Unspecified => "ACCESS_TYPE_UNSPECIFIED",
473            AccessType::Nobody => "ACCESS_TYPE_NOBODY",
474            AccessType::OnlyAddress => "ACCESS_TYPE_ONLY_ADDRESS",
475            AccessType::Everybody => "ACCESS_TYPE_EVERYBODY",
476        }
477    }
478}
479
480impl TryFrom<i32> for AccessType {
481    type Error = CosmwasmError;
482
483    fn try_from(v: i32) -> Result<Self, Self::Error> {
484        match v {
485            x if x == AccessType::Unspecified as i32 => Ok(AccessType::Unspecified),
486            x if x == AccessType::Nobody as i32 => Ok(AccessType::Nobody),
487            x if x == AccessType::OnlyAddress as i32 => Ok(AccessType::OnlyAddress),
488            x if x == AccessType::Everybody as i32 => Ok(AccessType::Everybody),
489            _ => Err(CosmwasmError::AccessType { i: v }),
490        }
491    }
492}
493
494impl From<AccessType> for ProtoAccessType {
495    fn from(perm: AccessType) -> Self {
496        match perm {
497            AccessType::Unspecified => ProtoAccessType::Unspecified,
498            AccessType::Nobody => ProtoAccessType::Nobody,
499            AccessType::OnlyAddress => ProtoAccessType::OnlyAddress,
500            AccessType::Everybody => ProtoAccessType::Everybody,
501        }
502    }
503}
504
505impl From<ProtoAccessType> for AccessType {
506    fn from(perm: ProtoAccessType) -> Self {
507        match perm {
508            ProtoAccessType::Unspecified => AccessType::Unspecified,
509            ProtoAccessType::Nobody => AccessType::Nobody,
510            ProtoAccessType::OnlyAddress => AccessType::OnlyAddress,
511            ProtoAccessType::Everybody => AccessType::Everybody,
512        }
513    }
514}