burnt_glue/
module.rs

1//! Traits for reusable, composable CosmWasm modules.
2
3use crate::response::Response;
4use cosmwasm_std::{Binary, Deps, DepsMut, Env, MessageInfo, StdError, StdResult};
5use serde::{Deserialize, Serialize};
6use serde_json::Value;
7use std::fmt::Display;
8
9/// A well typed CosmWasm module
10///
11/// A module must implement instantiate, execute, and query handlers.
12/// These handlers may, however, be no-ops.
13///
14/// Programmers looking to implement reusable CosmWasm modules should create
15/// structs that implement Module.
16pub trait Module {
17    /// The message sent to the module to instantiate its state.
18    type InstantiateMsg: for<'a> Deserialize<'a>;
19    /// The type of transaction messages this module can handle. For modules
20    /// that support multiple types of transaction, this will often times be
21    /// a sum type.
22    type ExecuteMsg: for<'a> Deserialize<'a>;
23    /// The type of query messages this module can handle. For modules that
24    /// support multiple queries, this will often times be a sum type.
25    type QueryMsg: for<'a> Deserialize<'a>;
26    /// The response to queries dispatched to the module.
27    type QueryResp: Serialize;
28    /// The type of errors this module can generate. This must implement
29    /// Display for easy stringification.
30    type Error: Display;
31
32    /// The instantiate handler for the module. When a Manager with this
33    /// module registered is instantiated, this method may be called.
34    fn instantiate(
35        &mut self,
36        deps: &mut DepsMut,
37        env: &Env,
38        info: &MessageInfo,
39        msg: Self::InstantiateMsg,
40    ) -> Result<Response, Self::Error>;
41    /// The transaction handler for this module. Messages to this contract
42    /// will be dispatched by the Manager.
43    fn execute(
44        &mut self,
45        deps: &mut DepsMut,
46        env: Env,
47        info: MessageInfo,
48        msg: Self::ExecuteMsg,
49    ) -> Result<Response, Self::Error>;
50    /// The query handler for this module. Messages to this contract will be
51    /// dispatched by the Manager.
52    fn query(
53        &self,
54        deps: &Deps,
55        env: Env,
56        msg: Self::QueryMsg,
57    ) -> Result<Self::QueryResp, Self::Error>;
58}
59
60/// A dynamically typed module.
61///
62/// GenericModules accept JSON values as their messages and return them as
63/// their results. Errors returned by GenericModules are strings. This trait
64/// was created to enable a simple dynamic dispatch of messages sent to the
65/// contract by the `Manager`.
66pub trait GenericModule {
67    /// A generic implementation of Module::instantiate
68    fn instantiate_value(
69        &mut self,
70        deps: &mut DepsMut,
71        env: &Env,
72        info: &MessageInfo,
73        msg: &Value,
74    ) -> Result<Response, String>;
75    /// A generic implementation of Module::execute
76    fn execute_value(
77        &mut self,
78        deps: &mut DepsMut,
79        env: Env,
80        info: MessageInfo,
81        msg: &Value,
82    ) -> Result<Response, String>;
83    /// A generic implementation of Module::query
84    fn query_value(&self, deps: &Deps, env: Env, msg: &Value) -> StdResult<Binary>;
85}
86
87/// An implementation of GenericModule for all valid implementations of Module.
88impl<T, A, B, C, D, E> GenericModule for T
89where
90    A: for<'de> Deserialize<'de>,
91    B: for<'de> Deserialize<'de>,
92    C: for<'de> Deserialize<'de>,
93    D: Serialize,
94    E: Display,
95    T: Module<InstantiateMsg = A, ExecuteMsg = B, QueryMsg = C, QueryResp = D, Error = E>,
96{
97    fn instantiate_value(
98        &mut self,
99        deps: &mut DepsMut,
100        env: &Env,
101        info: &MessageInfo,
102        msg: &Value,
103    ) -> Result<Response, String> {
104        let parsed_msg = serde_json::from_value(msg.clone()).map_err(|e| e.to_string())?;
105        self.instantiate(deps, env, info, parsed_msg)
106            .map_err(|e| e.to_string())
107    }
108
109    fn execute_value(
110        &mut self,
111        deps: &mut DepsMut,
112        env: Env,
113        info: MessageInfo,
114        msg: &Value,
115    ) -> Result<Response, String> {
116        let parsed_msg = serde_json::from_value(msg.clone()).map_err(|e| e.to_string())?;
117        self.execute(deps, env, info, parsed_msg)
118            .map_err(|e| e.to_string())
119    }
120
121    fn query_value(&self, deps: &Deps, env: Env, msg: &Value) -> StdResult<Binary> {
122        let parsed_msg = serde_json::from_value(msg.clone())
123            .map_err(|e| StdError::generic_err(e.to_string()))?;
124        let res = self
125            .query(deps, env, parsed_msg)
126            .map_err(|e| StdError::generic_err(e.to_string()))?;
127        cosmwasm_std::to_binary(&res)
128    }
129}