croncat_mod_generic/
contract.rs

1#[cfg(not(feature = "library"))]
2use cosmwasm_std::entry_point;
3use cosmwasm_std::{
4    to_binary, Binary, Deps, DepsMut, Env, MessageInfo, Response, StdError, StdResult, WasmQuery,
5};
6use cw2::set_contract_version;
7use mod_sdk::types::QueryResponse;
8use serde_cw_value::Value;
9
10use crate::helpers::{bin_to_value, query_wasm_smart_raw};
11use crate::msg::{ExecuteMsg, InstantiateMsg, QueryMsg};
12use crate::types::{CosmosQuery, GenericQuery};
13use crate::ContractError;
14
15// version info for migration info
16const CONTRACT_NAME: &str = "crate:croncat-mod-generic";
17const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION");
18
19#[cfg_attr(not(feature = "library"), entry_point)]
20pub fn instantiate(
21    deps: DepsMut,
22    _env: Env,
23    _info: MessageInfo,
24    msg: InstantiateMsg,
25) -> Result<Response, StdError> {
26    let contract_version = msg.version.unwrap_or_else(|| CONTRACT_VERSION.to_string());
27    set_contract_version(deps.storage, CONTRACT_NAME, &contract_version)?;
28
29    Ok(Response::new().add_attribute("action", "instantiate"))
30}
31
32#[cfg_attr(not(feature = "library"), entry_point)]
33pub fn execute(
34    _deps: DepsMut,
35    _env: Env,
36    _info: MessageInfo,
37    _msg: ExecuteMsg,
38) -> Result<Response, ContractError> {
39    Err(ContractError::Noop)
40}
41
42#[cfg_attr(not(feature = "library"), entry_point)]
43pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult<Binary> {
44    match msg {
45        QueryMsg::GenericQuery(query) => to_binary(&generic_query(deps, query)?),
46        QueryMsg::BatchQuery { queries } => to_binary(&batch_query(deps, queries)?),
47    }
48}
49
50/// Query: GenericQuery
51/// Used for creating generic queries
52/// Parses the query result to receive the value according to the path, defined by `gets`
53/// Compares this result with a pre-defined value
54/// ValueOrdering allows several options for comparison:
55/// Equal, Not Equal, Greater Than, Greater Than Equal To, Less Than, Less Than Equal To
56///
57/// Response: QueryResponse
58/// Returns true if the pre-defined ordering is satisfied
59/// Data contains the value which we received by querying
60fn generic_query(deps: Deps, query: GenericQuery) -> StdResult<QueryResponse> {
61    let mut json_val = query_wasm_smart_raw(deps, query.contract_addr, query.msg)
62        .and_then(|bin| bin_to_value(bin.as_slice()))?;
63    let json_rhs = cosmwasm_std::from_slice(query.value.as_slice())
64        .map_err(|e| StdError::parse_err(std::any::type_name::<serde_cw_value::Value>(), e))?;
65    let value = query.path_to_value.find_value(&mut json_val)?;
66
67    let result = query.ordering.val_cmp(value, &json_rhs)?;
68    Ok(QueryResponse {
69        result,
70        data: to_binary(&value)?,
71    })
72}
73
74/// Query an ordered set of cosmos queries
75///
76/// Response: QueryResponse
77/// Returns true if the pre-defined ordering is satisfied across ALL queries
78/// Data contains the array of values we received by querying
79fn batch_query(deps: Deps, queries: Vec<CosmosQuery>) -> StdResult<QueryResponse> {
80    // Optional here so we preserve request indexed responses
81    let mut responses: Vec<Option<Binary>> = Vec::with_capacity(queries.len());
82    let mut result = true;
83
84    for query in &queries {
85        match query {
86            CosmosQuery::Croncat(q) => {
87                let res: mod_sdk::types::QueryResponse = deps.querier.query(
88                    &WasmQuery::Smart {
89                        contract_addr: q.contract_addr.clone(),
90                        msg: q.msg.clone(),
91                    }
92                    .into(),
93                )?;
94                // Collect all the dataz we canz
95                responses.push(Some(res.data));
96
97                // Only stop this train if a query result is false
98                if q.check_result && !res.result {
99                    result = res.result;
100                    break;
101                }
102            }
103            CosmosQuery::Wasm(wq) => {
104                // Cover all native wasm query types
105                match wq {
106                    WasmQuery::Smart { contract_addr, msg } => {
107                        let data: Result<Value, StdError> = deps.querier.query(
108                            &WasmQuery::Smart {
109                                contract_addr: contract_addr.clone().to_string(),
110                                msg: msg.clone(),
111                            }
112                            .into(),
113                        );
114                        match data {
115                            Err(..) => responses.push(None),
116                            Ok(d) => {
117                                responses.push(Some(to_binary(&d)?));
118                            }
119                        }
120                    }
121                    WasmQuery::Raw { contract_addr, key } => {
122                        let res: Result<Option<Vec<u8>>, StdError> =
123                            deps.querier.query_wasm_raw(contract_addr, key.clone());
124
125                        match res {
126                            Err(..) => responses.push(None),
127                            Ok(d) => {
128                                // Optimistically respond
129                                if let Some(r) = d {
130                                    responses.push(Some(to_binary(&r)?));
131                                } else {
132                                    responses.push(None);
133                                };
134                            }
135                        }
136                    }
137                    WasmQuery::ContractInfo { contract_addr } => {
138                        let res = deps
139                            .querier
140                            .query_wasm_contract_info(contract_addr.clone().to_string());
141                        match res {
142                            Err(..) => responses.push(None),
143                            Ok(d) => {
144                                responses.push(Some(to_binary(&d)?));
145                            }
146                        }
147                    }
148                    // // NOTE: This is dependent on features = ["cosmwasm_1_2"]
149                    // WasmQuery::CodeInfo { code_id } => {
150                    //     let res = deps.querier.query_wasm_code_info(*code_id);
151                    //     match res {
152                    //         Err(..) => responses.push(None),
153                    //         Ok(d) => {
154                    //             responses.push(Some(to_binary(&d)?));
155                    //         }
156                    //     }
157                    // }
158                    _ => {
159                        return Err(StdError::GenericErr {
160                            msg: "Unknown Query Type".to_string(),
161                        });
162                    }
163                }
164            }
165        }
166    }
167
168    Ok(QueryResponse {
169        result,
170        data: to_binary(&responses)?,
171    })
172}