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