cosmwasm_std/query/
wasm.rs

1use schemars::JsonSchema;
2use serde::{Deserialize, Serialize};
3
4use crate::prelude::*;
5#[cfg(all(feature = "cosmwasm_3_0", feature = "iterator"))]
6use crate::storage_keys::{range_to_bounds, ToByteVec};
7use crate::{Addr, Binary, Checksum};
8#[cfg(all(feature = "cosmwasm_3_0", feature = "iterator"))]
9use core::ops::RangeBounds;
10
11use super::query_response::QueryResponseType;
12
13use crate::utils::impl_hidden_constructor;
14
15#[non_exhaustive]
16#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
17#[serde(rename_all = "snake_case")]
18pub enum WasmQuery {
19    /// this queries the public API of another contract at a known address (with known ABI)
20    /// Return value is whatever the contract returns (caller should know), wrapped in a
21    /// ContractResult that is JSON encoded.
22    Smart {
23        contract_addr: String,
24        /// msg is the json-encoded QueryMsg struct
25        msg: Binary,
26    },
27    /// this queries the raw kv-store of the contract.
28    /// returns the raw, unparsed data stored at that key, which may be an empty vector if not present
29    Raw {
30        contract_addr: String,
31        /// Key is the raw key used in the contracts Storage
32        key: Binary,
33    },
34    /// Returns a [`ContractInfoResponse`] with metadata on the contract from the runtime
35    ContractInfo { contract_addr: String },
36    /// Returns a [`CodeInfoResponse`] with metadata of the code
37    #[cfg(feature = "cosmwasm_1_2")]
38    CodeInfo { code_id: u64 },
39    /// Queries a range of keys from the storage of a (different) contract,
40    /// returning a [`RawRangeResponse`].
41    ///
42    /// This is a low-level query that allows you to query the storage of another contract.
43    /// Please keep in mind that the contract you are querying might change its storage layout using
44    /// migrations, which could break your queries, so it is recommended to only use this for
45    /// contracts you control.
46    #[cfg(all(feature = "cosmwasm_3_0", feature = "iterator"))]
47    RawRange {
48        /// The address of the contract to query
49        contract_addr: String,
50        /// Inclusive start bound. This is the first key you would like to get data for.
51        ///
52        /// If `start` is lexicographically greater than or equal to `end`,
53        /// an empty range is described, mo matter of the order.
54        start: Option<Binary>,
55        /// Exclusive end bound. This is the key after the last key you would like to get data for.
56        end: Option<Binary>,
57        /// Maximum number of elements to return.
58        ///
59        /// Make sure to set a reasonable limit to avoid running out of memory or into
60        /// the deserialization limits of the VM. Also keep in mind that these limitations depend
61        /// on the full JSON size of the response type.
62        limit: u16,
63        /// The order in which you want to receive the key-value pairs.
64        order: crate::Order,
65    },
66}
67
68impl WasmQuery {
69    /// Creates a new [`WasmQuery::RawRange`] from the given parameters.
70    ///
71    /// This takes a [`RangeBounds`] to allow for specifying the range in a more idiomatic way.
72    #[cfg(all(feature = "cosmwasm_3_0", feature = "iterator"))]
73    pub fn raw_range<'a, R, B>(
74        contract_addr: impl Into<String>,
75        range: R,
76        limit: u16,
77        order: crate::Order,
78    ) -> Self
79    where
80        R: RangeBounds<&'a B>,
81        B: ToByteVec + ?Sized + 'a,
82    {
83        let (start, end) = range_to_bounds(&range);
84
85        WasmQuery::RawRange {
86            contract_addr: contract_addr.into(),
87            start: start.map(Binary::new),
88            end: end.map(Binary::new),
89            limit,
90            order,
91        }
92    }
93}
94
95#[non_exhaustive]
96#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
97pub struct ContractInfoResponse {
98    pub code_id: u64,
99    /// address that instantiated this contract
100    pub creator: Addr,
101    /// admin who can run migrations (if any)
102    pub admin: Option<Addr>,
103    /// if set, the contract is pinned to the cache, and thus uses less gas when called
104    pub pinned: bool,
105    /// set if this contract has bound an IBC port
106    pub ibc_port: Option<String>,
107    /// set if this contract has bound an Ibc2 port
108    pub ibc2_port: Option<String>,
109}
110
111impl QueryResponseType for ContractInfoResponse {}
112
113impl_hidden_constructor!(
114    ContractInfoResponse,
115    code_id: u64,
116    creator: Addr,
117    admin: Option<Addr>,
118    pinned: bool,
119    ibc_port: Option<String>,
120    ibc2_port: Option<String>
121);
122
123/// The essential data from wasmd's [CodeInfo]/[CodeInfoResponse].
124///
125/// `code_hash`/`data_hash` was renamed to `checksum` to follow the CosmWasm
126/// convention and naming in `instantiate2_address`.
127///
128/// [CodeInfo]: https://github.com/CosmWasm/wasmd/blob/v0.30.0/proto/cosmwasm/wasm/v1/types.proto#L62-L72
129/// [CodeInfoResponse]: https://github.com/CosmWasm/wasmd/blob/v0.30.0/proto/cosmwasm/wasm/v1/query.proto#L184-L199
130#[non_exhaustive]
131#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
132pub struct CodeInfoResponse {
133    pub code_id: u64,
134    /// The address that initially stored the code
135    pub creator: Addr,
136    /// The hash of the Wasm blob
137    pub checksum: Checksum,
138}
139
140impl_hidden_constructor!(
141    CodeInfoResponse,
142    code_id: u64,
143    creator: Addr,
144    checksum: Checksum
145);
146
147impl QueryResponseType for CodeInfoResponse {}
148
149#[non_exhaustive]
150#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
151pub struct RawRangeResponse {
152    /// The key-value pairs
153    pub data: Vec<RawRangeEntry>,
154    /// `None` if there are no more key-value pairs within the given key range.
155    pub next_key: Option<Binary>,
156}
157
158impl_hidden_constructor!(
159    RawRangeResponse,
160    data: Vec<RawRangeEntry>,
161    next_key: Option<Binary>
162);
163
164pub type RawRangeEntry = (Binary, Binary);
165
166#[cfg(test)]
167mod tests {
168    use super::*;
169    use crate::to_json_binary;
170
171    #[test]
172    fn wasm_query_contract_info_serialization() {
173        let query = WasmQuery::ContractInfo {
174            contract_addr: "aabbccdd456".into(),
175        };
176        let json = to_json_binary(&query).unwrap();
177        assert_eq!(
178            String::from_utf8_lossy(&json),
179            r#"{"contract_info":{"contract_addr":"aabbccdd456"}}"#,
180        );
181    }
182
183    #[test]
184    #[cfg(feature = "cosmwasm_1_2")]
185    fn wasm_query_code_info_serialization() {
186        let query = WasmQuery::CodeInfo { code_id: 70 };
187        let json = to_json_binary(&query).unwrap();
188        assert_eq!(
189            String::from_utf8_lossy(&json),
190            r#"{"code_info":{"code_id":70}}"#,
191        );
192    }
193
194    #[test]
195    fn contract_info_response_serialization() {
196        let response = ContractInfoResponse {
197            code_id: 67,
198            creator: Addr::unchecked("jane"),
199            admin: Some(Addr::unchecked("king")),
200            pinned: true,
201            ibc_port: Some("wasm.123".to_string()),
202            ibc2_port: Some("wasm.123".to_string()),
203        };
204        let json = to_json_binary(&response).unwrap();
205        assert_eq!(
206            String::from_utf8_lossy(&json),
207            r#"{"code_id":67,"creator":"jane","admin":"king","pinned":true,"ibc_port":"wasm.123","ibc2_port":"wasm.123"}"#,
208        );
209    }
210
211    #[test]
212    #[cfg(feature = "cosmwasm_1_2")]
213    fn code_info_response_serialization() {
214        use crate::Checksum;
215
216        let response = CodeInfoResponse {
217            code_id: 67,
218            creator: Addr::unchecked("jane"),
219            checksum: Checksum::from_hex(
220                "f7bb7b18fb01bbf425cf4ed2cd4b7fb26a019a7fc75a4dc87e8a0b768c501f00",
221            )
222            .unwrap(),
223        };
224        let json = to_json_binary(&response).unwrap();
225        assert_eq!(
226            String::from_utf8_lossy(&json),
227            r#"{"code_id":67,"creator":"jane","checksum":"f7bb7b18fb01bbf425cf4ed2cd4b7fb26a019a7fc75a4dc87e8a0b768c501f00"}"#,
228        );
229    }
230
231    #[test]
232    #[cfg(all(feature = "cosmwasm_3_0", feature = "iterator"))]
233    fn raw_range_constructor_works() {
234        use crate::Order;
235
236        let query = WasmQuery::raw_range(
237            "contract_addr",
238            &b"asdf"[..]..&b"asdz"[..],
239            100,
240            Order::Ascending,
241        );
242
243        assert_eq!(
244            query,
245            WasmQuery::RawRange {
246                contract_addr: "contract_addr".to_string(),
247                start: Some(Binary::from(b"asdf")),
248                end: Some(Binary::from(b"asdz")),
249                limit: 100,
250                order: Order::Ascending,
251            }
252        );
253
254        let query = WasmQuery::raw_range("contract_addr", b"asdf"..=b"asdz", 100, Order::Ascending);
255        assert_eq!(
256            query,
257            WasmQuery::RawRange {
258                contract_addr: "contract_addr".to_string(),
259                start: Some(Binary::from(b"asdf")),
260                end: Some(Binary::from(b"asdz\0")),
261                limit: 100,
262                order: Order::Ascending,
263            }
264        );
265    }
266
267    #[test]
268    fn raw_range_response_serialization() {
269        let response = RawRangeResponse {
270            data: vec![
271                (Binary::from(b"key"), Binary::from(b"value")),
272                (Binary::from(b"foo"), Binary::from(b"bar")),
273            ],
274            next_key: Some(Binary::from(b"next")),
275        };
276        let json = to_json_binary(&response).unwrap();
277        assert_eq!(
278            String::from_utf8_lossy(&json),
279            r#"{"data":[["a2V5","dmFsdWU="],["Zm9v","YmFy"]],"next_key":"bmV4dA=="}"#,
280        );
281    }
282}