cosmwasm_std/
traits.rs

1use core::marker::PhantomData;
2use core::ops::Deref;
3use serde::{de::DeserializeOwned, Serialize};
4
5use crate::addresses::{Addr, CanonicalAddr};
6use crate::binary::Binary;
7use crate::coin::Coin;
8use crate::errors::{RecoverPubkeyError, StdError, StdResult, VerificationError};
9#[cfg(feature = "iterator")]
10use crate::iterator::{Order, Record};
11#[cfg(feature = "cosmwasm_1_2")]
12use crate::query::CodeInfoResponse;
13#[cfg(feature = "cosmwasm_1_1")]
14use crate::query::SupplyResponse;
15use crate::query::{
16    AllBalanceResponse, BalanceResponse, BankQuery, CustomQuery, QueryRequest, WasmQuery,
17};
18#[cfg(feature = "staking")]
19use crate::query::{
20    AllDelegationsResponse, AllValidatorsResponse, BondedDenomResponse, Delegation,
21    DelegationResponse, FullDelegation, StakingQuery, Validator, ValidatorResponse,
22};
23#[cfg(feature = "cosmwasm_1_3")]
24use crate::query::{
25    AllDenomMetadataResponse, DelegatorWithdrawAddressResponse, DenomMetadataResponse,
26    DistributionQuery,
27};
28use crate::results::{ContractResult, Empty, SystemResult};
29use crate::serde::{from_json, to_json_binary, to_json_vec};
30use crate::ContractInfoResponse;
31#[cfg(feature = "cosmwasm_1_3")]
32use crate::{DenomMetadata, PageRequest};
33
34/// Storage provides read and write access to a persistent storage.
35/// If you only want to provide read access, provide `&Storage`
36pub trait Storage {
37    /// Returns None when key does not exist.
38    /// Returns Some(Vec<u8>) when key exists.
39    ///
40    /// Note: Support for differentiating between a non-existent key and a key with empty value
41    /// is not great yet and might not be possible in all backends. But we're trying to get there.
42    fn get(&self, key: &[u8]) -> Option<Vec<u8>>;
43
44    /// Allows iteration over a set of key/value pairs, either forwards or backwards.
45    ///
46    /// The bound `start` is inclusive and `end` is exclusive.
47    /// If `start` is lexicographically greater than or equal to `end`, an empty range is described, mo matter of the order.
48    #[cfg(feature = "iterator")]
49    fn range<'a>(
50        &'a self,
51        start: Option<&[u8]>,
52        end: Option<&[u8]>,
53        order: Order,
54    ) -> Box<dyn Iterator<Item = Record> + 'a>;
55
56    /// Allows iteration over a set of keys, either forwards or backwards.
57    ///
58    /// The bound `start` is inclusive and `end` is exclusive.
59    /// If `start` is lexicographically greater than or equal to `end`, an empty range is described, mo matter of the order.
60    ///
61    /// The default implementation uses [`Storage::range`] and discards the values. More efficient
62    /// implementations might be possible depending on the storage.
63    #[cfg(feature = "iterator")]
64    fn range_keys<'a>(
65        &'a self,
66        start: Option<&[u8]>,
67        end: Option<&[u8]>,
68        order: Order,
69    ) -> Box<dyn Iterator<Item = Vec<u8>> + 'a> {
70        Box::new(self.range(start, end, order).map(|(k, _v)| k))
71    }
72
73    /// Allows iteration over a set of values, either forwards or backwards.
74    ///
75    /// The bound `start` is inclusive and `end` is exclusive.
76    /// If `start` is lexicographically greater than or equal to `end`, an empty range is described, mo matter of the order.
77    ///
78    /// The default implementation uses [`Storage::range`] and discards the keys. More efficient implementations
79    /// might be possible depending on the storage.
80    #[cfg(feature = "iterator")]
81    fn range_values<'a>(
82        &'a self,
83        start: Option<&[u8]>,
84        end: Option<&[u8]>,
85        order: Order,
86    ) -> Box<dyn Iterator<Item = Vec<u8>> + 'a> {
87        Box::new(self.range(start, end, order).map(|(_k, v)| v))
88    }
89
90    fn set(&mut self, key: &[u8], value: &[u8]);
91
92    /// Removes a database entry at `key`.
93    ///
94    /// The current interface does not allow to differentiate between a key that existed
95    /// before and one that didn't exist. See https://github.com/CosmWasm/cosmwasm/issues/290
96    fn remove(&mut self, key: &[u8]);
97}
98
99/// Api are callbacks to system functions implemented outside of the wasm modules.
100/// Currently it just supports address conversion but we could add eg. crypto functions here.
101///
102/// This is a trait to allow mocks in the test code. Its members have a read-only
103/// reference to the Api instance to allow accessing configuration.
104/// Implementations must not have mutable state, such that an instance can freely
105/// be copied and shared between threads without affecting the behaviour.
106/// Given an Api instance, all members should return the same value when called with the same
107/// arguments. In particular this means the result must not depend in the state of the chain.
108/// If you need to access chaim state, you probably want to use the Querier.
109/// Side effects (such as logging) are allowed.
110///
111/// We can use feature flags to opt-in to non-essential methods
112/// for backwards compatibility in systems that don't have them all.
113pub trait Api {
114    /// Takes a human readable address and validates if it is valid.
115    /// If it the validation succeeds, a `Addr` containing the same data as the input is returned.
116    ///
117    /// This validation checks two things:
118    /// 1. The address is valid in the sense that it can be converted to a canonical representation by the backend.
119    /// 2. The address is normalized, i.e. `humanize(canonicalize(input)) == input`.
120    ///
121    /// Check #2 is typically needed for upper/lower case representations of the same
122    /// address that are both valid according to #1. This way we ensure uniqueness
123    /// of the human readable address. Clients should perform the normalization before sending
124    /// the addresses to the CosmWasm stack. But please note that the definition of normalized
125    /// depends on the backend.
126    ///
127    /// ## Examples
128    ///
129    /// ```
130    /// # use cosmwasm_std::{Api, Addr};
131    /// # use cosmwasm_std::testing::MockApi;
132    /// # let api = MockApi::default();
133    /// let input = "what-users-provide";
134    /// let validated: Addr = api.addr_validate(input).unwrap();
135    /// assert_eq!(validated, input);
136    /// ```
137    fn addr_validate(&self, human: &str) -> StdResult<Addr>;
138
139    /// Takes a human readable address and returns a canonical binary representation of it.
140    /// This can be used when a compact representation is needed.
141    ///
142    /// Please note that the length of the resulting address is defined by the chain and
143    /// can vary from address to address. On Cosmos chains 20 and 32 bytes are typically used.
144    /// But that might change. So your contract should not make assumptions on the size.
145    fn addr_canonicalize(&self, human: &str) -> StdResult<CanonicalAddr>;
146
147    /// Takes a canonical address and returns a human readble address.
148    /// This is the inverse of [`addr_canonicalize`].
149    ///
150    /// [`addr_canonicalize`]: Api::addr_canonicalize
151    fn addr_humanize(&self, canonical: &CanonicalAddr) -> StdResult<Addr>;
152
153    fn secp256k1_verify(
154        &self,
155        message_hash: &[u8],
156        signature: &[u8],
157        public_key: &[u8],
158    ) -> Result<bool, VerificationError>;
159
160    fn secp256k1_recover_pubkey(
161        &self,
162        message_hash: &[u8],
163        signature: &[u8],
164        recovery_param: u8,
165    ) -> Result<Vec<u8>, RecoverPubkeyError>;
166
167    fn ed25519_verify(
168        &self,
169        message: &[u8],
170        signature: &[u8],
171        public_key: &[u8],
172    ) -> Result<bool, VerificationError>;
173
174    fn ed25519_batch_verify(
175        &self,
176        messages: &[&[u8]],
177        signatures: &[&[u8]],
178        public_keys: &[&[u8]],
179    ) -> Result<bool, VerificationError>;
180
181    /// Emits a debugging message that is handled depending on the environment (typically printed to console or ignored).
182    /// Those messages are not persisted to chain.
183    fn debug(&self, message: &str);
184}
185
186/// A short-hand alias for the two-level query result (1. accessing the contract, 2. executing query in the contract)
187pub type QuerierResult = SystemResult<ContractResult<Binary>>;
188
189pub trait Querier {
190    /// raw_query is all that must be implemented for the Querier.
191    /// This allows us to pass through binary queries from one level to another without
192    /// knowing the custom format, or we can decode it, with the knowledge of the allowed
193    /// types. People using the querier probably want one of the simpler auto-generated
194    /// helper methods
195    fn raw_query(&self, bin_request: &[u8]) -> QuerierResult;
196}
197
198#[derive(Clone)]
199pub struct QuerierWrapper<'a, C: CustomQuery = Empty> {
200    querier: &'a dyn Querier,
201    custom_query_type: PhantomData<C>,
202}
203
204// Use custom implementation on order to implement Copy in case `C` is not `Copy`.
205// See "There is a small difference between the two: the derive strategy will also
206// place a Copy bound on type parameters, which isn’t always desired."
207// https://doc.rust-lang.org/std/marker/trait.Copy.html
208impl<'a, C: CustomQuery> Copy for QuerierWrapper<'a, C> {}
209
210/// This allows us to use self.raw_query to access the querier.
211/// It also allows external callers to access the querier easily.
212impl<'a, C: CustomQuery> Deref for QuerierWrapper<'a, C> {
213    type Target = dyn Querier + 'a;
214
215    fn deref(&self) -> &Self::Target {
216        self.querier
217    }
218}
219
220impl<'a, C: CustomQuery> QuerierWrapper<'a, C> {
221    pub fn new(querier: &'a dyn Querier) -> Self {
222        QuerierWrapper {
223            querier,
224            custom_query_type: PhantomData,
225        }
226    }
227
228    /// This allows to convert any `QuerierWrapper` into a `QuerierWrapper` generic
229    /// over `Empty` custom query type.
230    pub fn into_empty(self) -> QuerierWrapper<'a, Empty> {
231        QuerierWrapper {
232            querier: self.querier,
233            custom_query_type: PhantomData,
234        }
235    }
236
237    /// Makes the query and parses the response.
238    ///
239    /// Any error (System Error, Error or called contract, or Parse Error) are flattened into
240    /// one level. Only use this if you don't need to check the SystemError
241    /// eg. If you don't differentiate between contract missing and contract returned error
242    pub fn query<U: DeserializeOwned>(&self, request: &QueryRequest<C>) -> StdResult<U> {
243        let raw = to_json_vec(request).map_err(|serialize_err| {
244            StdError::generic_err(format!("Serializing QueryRequest: {serialize_err}"))
245        })?;
246        match self.raw_query(&raw) {
247            SystemResult::Err(system_err) => Err(StdError::generic_err(format!(
248                "Querier system error: {system_err}"
249            ))),
250            SystemResult::Ok(ContractResult::Err(contract_err)) => Err(StdError::generic_err(
251                format!("Querier contract error: {contract_err}"),
252            )),
253            SystemResult::Ok(ContractResult::Ok(value)) => from_json(value),
254        }
255    }
256
257    #[cfg(feature = "cosmwasm_1_1")]
258    pub fn query_supply(&self, denom: impl Into<String>) -> StdResult<Coin> {
259        let request = BankQuery::Supply {
260            denom: denom.into(),
261        }
262        .into();
263        let res: SupplyResponse = self.query(&request)?;
264        Ok(res.amount)
265    }
266
267    pub fn query_balance(
268        &self,
269        address: impl Into<String>,
270        denom: impl Into<String>,
271    ) -> StdResult<Coin> {
272        let request = BankQuery::Balance {
273            address: address.into(),
274            denom: denom.into(),
275        }
276        .into();
277        let res: BalanceResponse = self.query(&request)?;
278        Ok(res.amount)
279    }
280
281    pub fn query_all_balances(&self, address: impl Into<String>) -> StdResult<Vec<Coin>> {
282        let request = BankQuery::AllBalances {
283            address: address.into(),
284        }
285        .into();
286        let res: AllBalanceResponse = self.query(&request)?;
287        Ok(res.amount)
288    }
289
290    #[cfg(feature = "cosmwasm_1_3")]
291    pub fn query_delegator_withdraw_address(
292        &self,
293        delegator: impl Into<String>,
294    ) -> StdResult<Addr> {
295        let request = DistributionQuery::DelegatorWithdrawAddress {
296            delegator_address: delegator.into(),
297        }
298        .into();
299        let res: DelegatorWithdrawAddressResponse = self.query(&request)?;
300        Ok(res.withdraw_address)
301    }
302
303    #[cfg(feature = "cosmwasm_1_3")]
304    pub fn query_denom_metadata(&self, denom: impl Into<String>) -> StdResult<DenomMetadata> {
305        let request = BankQuery::DenomMetadata {
306            denom: denom.into(),
307        }
308        .into();
309        let res: DenomMetadataResponse = self.query(&request)?;
310        Ok(res.metadata)
311    }
312
313    #[cfg(feature = "cosmwasm_1_3")]
314    pub fn query_all_denom_metadata(
315        &self,
316        pagination: PageRequest,
317    ) -> StdResult<AllDenomMetadataResponse> {
318        let request = BankQuery::AllDenomMetadata {
319            pagination: Some(pagination),
320        }
321        .into();
322        self.query(&request)
323    }
324
325    #[cfg(feature = "cosmwasm_1_4")]
326    pub fn query_delegation_rewards(
327        &self,
328        delegator: impl Into<String>,
329        validator: impl Into<String>,
330    ) -> StdResult<Vec<crate::DecCoin>> {
331        use crate::DelegationRewardsResponse;
332
333        let request = DistributionQuery::DelegationRewards {
334            delegator_address: delegator.into(),
335            validator_address: validator.into(),
336        }
337        .into();
338        let DelegationRewardsResponse { rewards } = self.query(&request)?;
339
340        Ok(rewards)
341    }
342
343    #[cfg(feature = "cosmwasm_1_4")]
344    pub fn query_delegation_total_rewards(
345        &self,
346        delegator: impl Into<String>,
347    ) -> StdResult<crate::DelegationTotalRewardsResponse> {
348        let request = DistributionQuery::DelegationTotalRewards {
349            delegator_address: delegator.into(),
350        }
351        .into();
352        self.query(&request)
353    }
354
355    #[cfg(feature = "cosmwasm_1_4")]
356    pub fn query_delegator_validators(
357        &self,
358        delegator: impl Into<String>,
359    ) -> StdResult<Vec<String>> {
360        use crate::DelegatorValidatorsResponse;
361
362        let request = DistributionQuery::DelegatorValidators {
363            delegator_address: delegator.into(),
364        }
365        .into();
366        let res: DelegatorValidatorsResponse = self.query(&request)?;
367        Ok(res.validators)
368    }
369
370    /// Queries another wasm contract. You should know a priori the proper types for T and U
371    /// (response and request) based on the contract API
372    pub fn query_wasm_smart<T: DeserializeOwned>(
373        &self,
374        contract_addr: impl Into<String>,
375        msg: &impl Serialize,
376    ) -> StdResult<T> {
377        let request = WasmQuery::Smart {
378            contract_addr: contract_addr.into(),
379            msg: to_json_binary(msg)?,
380        }
381        .into();
382        self.query(&request)
383    }
384
385    /// Queries the raw storage from another wasm contract.
386    ///
387    /// You must know the exact layout and are implementation dependent
388    /// (not tied to an interface like query_wasm_smart).
389    /// That said, if you are building a few contracts together, this is a much cheaper approach
390    ///
391    /// Similar return value to [`Storage::get`]. Returns `Some(val)` or `None` if the data is there.
392    /// It only returns error on some runtime issue, not on any data cases.
393    pub fn query_wasm_raw(
394        &self,
395        contract_addr: impl Into<String>,
396        key: impl Into<Binary>,
397    ) -> StdResult<Option<Vec<u8>>> {
398        let request: QueryRequest<Empty> = WasmQuery::Raw {
399            contract_addr: contract_addr.into(),
400            key: key.into(),
401        }
402        .into();
403        // we cannot use query, as it will try to parse the binary data, when we just want to return it,
404        // so a bit of code copy here...
405        let raw = to_json_vec(&request).map_err(|serialize_err| {
406            StdError::generic_err(format!("Serializing QueryRequest: {serialize_err}"))
407        })?;
408        match self.raw_query(&raw) {
409            SystemResult::Err(system_err) => Err(StdError::generic_err(format!(
410                "Querier system error: {system_err}"
411            ))),
412            SystemResult::Ok(ContractResult::Err(contract_err)) => Err(StdError::generic_err(
413                format!("Querier contract error: {contract_err}"),
414            )),
415            SystemResult::Ok(ContractResult::Ok(value)) => {
416                if value.is_empty() {
417                    Ok(None)
418                } else {
419                    Ok(Some(value.into()))
420                }
421            }
422        }
423    }
424
425    /// Given a contract address, query information about that contract.
426    pub fn query_wasm_contract_info(
427        &self,
428        contract_addr: impl Into<String>,
429    ) -> StdResult<ContractInfoResponse> {
430        let request = WasmQuery::ContractInfo {
431            contract_addr: contract_addr.into(),
432        }
433        .into();
434        self.query(&request)
435    }
436
437    /// Given a code ID, query information about that code.
438    #[cfg(feature = "cosmwasm_1_2")]
439    pub fn query_wasm_code_info(&self, code_id: u64) -> StdResult<CodeInfoResponse> {
440        let request = WasmQuery::CodeInfo { code_id }.into();
441        self.query(&request)
442    }
443
444    #[cfg(feature = "staking")]
445    pub fn query_all_validators(&self) -> StdResult<Vec<Validator>> {
446        let request = StakingQuery::AllValidators {}.into();
447        let res: AllValidatorsResponse = self.query(&request)?;
448        Ok(res.validators)
449    }
450
451    #[cfg(feature = "staking")]
452    pub fn query_validator(&self, address: impl Into<String>) -> StdResult<Option<Validator>> {
453        let request = StakingQuery::Validator {
454            address: address.into(),
455        }
456        .into();
457        let res: ValidatorResponse = self.query(&request)?;
458        Ok(res.validator)
459    }
460
461    #[cfg(feature = "staking")]
462    pub fn query_bonded_denom(&self) -> StdResult<String> {
463        let request = StakingQuery::BondedDenom {}.into();
464        let res: BondedDenomResponse = self.query(&request)?;
465        Ok(res.denom)
466    }
467
468    #[cfg(feature = "staking")]
469    pub fn query_all_delegations(
470        &self,
471        delegator: impl Into<String>,
472    ) -> StdResult<Vec<Delegation>> {
473        let request = StakingQuery::AllDelegations {
474            delegator: delegator.into(),
475        }
476        .into();
477        let res: AllDelegationsResponse = self.query(&request)?;
478        Ok(res.delegations)
479    }
480
481    #[cfg(feature = "staking")]
482    pub fn query_delegation(
483        &self,
484        delegator: impl Into<String>,
485        validator: impl Into<String>,
486    ) -> StdResult<Option<FullDelegation>> {
487        let request = StakingQuery::Delegation {
488            delegator: delegator.into(),
489            validator: validator.into(),
490        }
491        .into();
492        let res: DelegationResponse = self.query(&request)?;
493        Ok(res.delegation)
494    }
495}
496
497#[cfg(test)]
498mod tests {
499    use serde::Deserialize;
500
501    use super::*;
502    use crate::testing::MockQuerier;
503    use crate::{coins, from_json, Uint128};
504
505    // this is a simple demo helper to prove we can use it
506    fn demo_helper(_querier: &dyn Querier) -> u64 {
507        2
508    }
509
510    // this just needs to compile to prove we can use it
511    #[test]
512    fn use_querier_wrapper_as_querier() {
513        let querier: MockQuerier<Empty> = MockQuerier::new(&[]);
514        let wrapper = QuerierWrapper::<Empty>::new(&querier);
515
516        // call with deref shortcut
517        let res = demo_helper(&*wrapper);
518        assert_eq!(2, res);
519
520        // call with explicit deref
521        let res = demo_helper(wrapper.deref());
522        assert_eq!(2, res);
523    }
524
525    #[test]
526    fn auto_deref_raw_query() {
527        let acct = String::from("foobar");
528        let querier: MockQuerier<Empty> = MockQuerier::new(&[(&acct, &coins(5, "BTC"))]);
529        let wrapper = QuerierWrapper::<Empty>::new(&querier);
530        let query = QueryRequest::<Empty>::Bank(BankQuery::Balance {
531            address: acct,
532            denom: "BTC".to_string(),
533        });
534
535        let raw = wrapper
536            .raw_query(&to_json_vec(&query).unwrap())
537            .unwrap()
538            .unwrap();
539        let balance: BalanceResponse = from_json(raw).unwrap();
540        assert_eq!(balance.amount.amount, Uint128::new(5));
541    }
542
543    #[cfg(feature = "cosmwasm_1_1")]
544    #[test]
545    fn bank_query_helpers_work() {
546        use crate::coin;
547
548        let querier: MockQuerier<Empty> = MockQuerier::new(&[
549            ("foo", &[coin(123, "ELF"), coin(777, "FLY")]),
550            ("bar", &[coin(321, "ELF")]),
551        ]);
552        let wrapper = QuerierWrapper::<Empty>::new(&querier);
553
554        let supply = wrapper.query_supply("ELF").unwrap();
555        assert_eq!(supply, coin(444, "ELF"));
556
557        let balance = wrapper.query_balance("foo", "ELF").unwrap();
558        assert_eq!(balance, coin(123, "ELF"));
559
560        let all_balances = wrapper.query_all_balances("foo").unwrap();
561        assert_eq!(all_balances, vec![coin(123, "ELF"), coin(777, "FLY")]);
562    }
563
564    #[test]
565    fn contract_info() {
566        const ACCT: &str = "foobar";
567        fn mock_resp() -> ContractInfoResponse {
568            ContractInfoResponse {
569                code_id: 0,
570                creator: "creator".to_string(),
571                admin: None,
572                pinned: false,
573                ibc_port: None,
574            }
575        }
576
577        let mut querier: MockQuerier<Empty> = MockQuerier::new(&[(ACCT, &coins(5, "BTC"))]);
578        querier.update_wasm(|q| -> QuerierResult {
579            if q == &(WasmQuery::ContractInfo {
580                contract_addr: ACCT.to_string(),
581            }) {
582                SystemResult::Ok(ContractResult::Ok(to_json_binary(&mock_resp()).unwrap()))
583            } else {
584                SystemResult::Err(crate::SystemError::NoSuchContract {
585                    addr: ACCT.to_string(),
586                })
587            }
588        });
589        let wrapper = QuerierWrapper::<Empty>::new(&querier);
590
591        let contract_info = wrapper.query_wasm_contract_info(ACCT).unwrap();
592        assert_eq!(contract_info, mock_resp());
593    }
594
595    #[test]
596    fn contract_info_err() {
597        const ACCT: &str = "foobar";
598        fn mock_resp() -> ContractInfoResponse {
599            ContractInfoResponse {
600                code_id: 0,
601                creator: "creator".to_string(),
602                admin: None,
603                pinned: false,
604                ibc_port: None,
605            }
606        }
607
608        let mut querier: MockQuerier<Empty> = MockQuerier::new(&[(ACCT, &coins(5, "BTC"))]);
609        querier.update_wasm(|q| -> QuerierResult {
610            if q == &(WasmQuery::ContractInfo {
611                contract_addr: ACCT.to_string(),
612            }) {
613                SystemResult::Ok(ContractResult::Ok(to_json_binary(&mock_resp()).unwrap()))
614            } else {
615                SystemResult::Err(crate::SystemError::NoSuchContract {
616                    addr: ACCT.to_string(),
617                })
618            }
619        });
620        let wrapper = QuerierWrapper::<Empty>::new(&querier);
621
622        let err = wrapper.query_wasm_contract_info("unknown").unwrap_err();
623        assert!(matches!(
624            err,
625            StdError::GenericErr {
626                msg,
627                ..
628            } if msg == "Querier system error: No such contract: foobar"
629        ));
630    }
631
632    #[test]
633    fn querier_into_empty() {
634        #[derive(Clone, Serialize, Deserialize)]
635        struct MyQuery;
636        impl CustomQuery for MyQuery {}
637
638        let querier: MockQuerier<MyQuery> = MockQuerier::new(&[]);
639        let wrapper = QuerierWrapper::<MyQuery>::new(&querier);
640
641        let _: QuerierWrapper<Empty> = wrapper.into_empty();
642    }
643}