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