secret_cosmwasm_std/
traits.rs

1use serde::{de::DeserializeOwned, Serialize};
2
3#[cfg(feature = "random")]
4use serde::Deserialize;
5
6use std::marker::PhantomData;
7use std::ops::Deref;
8
9use crate::addresses::{Addr, CanonicalAddr};
10use crate::binary::Binary;
11use crate::coin::Coin;
12use crate::errors::{RecoverPubkeyError, SigningError, StdError, StdResult, VerificationError};
13#[cfg(feature = "iterator")]
14use crate::iterator::{Order, Record};
15#[cfg(feature = "cosmwasm_1_1")]
16use crate::query::SupplyResponse;
17use crate::query::{
18    AllBalanceResponse, BalanceResponse, BankQuery, CustomQuery, QueryRequest, WasmQuery,
19};
20#[cfg(feature = "staking")]
21use crate::query::{
22    AllDelegationsResponse, AllValidatorsResponse, BondedDenomResponse, Delegation,
23    DelegationResponse, FullDelegation, StakingQuery, Validator, ValidatorResponse,
24};
25use crate::results::{ContractResult, Empty, SystemResult};
26use crate::serde::{from_binary, to_binary, to_vec};
27
28/// Storage provides read and write access to a persistent storage.
29/// If you only want to provide read access, provide `&Storage`
30pub trait Storage {
31    /// Returns None when key does not exist.
32    /// Returns Some(Vec<u8>) when key exists.
33    ///
34    /// Note: Support for differentiating between a non-existent key and a key with empty value
35    /// is not great yet and might not be possible in all backends. But we're trying to get there.
36    fn get(&self, key: &[u8]) -> Option<Vec<u8>>;
37
38    #[cfg(feature = "iterator")]
39    /// Allows iteration over a set of key/value pairs, either forwards or backwards.
40    ///
41    /// The bound `start` is inclusive and `end` is exclusive.
42    ///
43    /// If `start` is lexicographically greater than or equal to `end`, an empty range is described, mo matter of the order.
44    fn range<'a>(
45        &'a self,
46        start: Option<&[u8]>,
47        end: Option<&[u8]>,
48        order: Order,
49    ) -> Box<dyn Iterator<Item = Record> + 'a>;
50
51    fn set(&mut self, key: &[u8], value: &[u8]);
52
53    /// Removes a database entry at `key`.
54    ///
55    /// The current interface does not allow to differentiate between a key that existed
56    /// before and one that didn't exist. See https://github.com/CosmWasm/cosmwasm/issues/290
57    fn remove(&mut self, key: &[u8]);
58}
59
60/// Api are callbacks to system functions implemented outside of the wasm modules.
61/// Currently it just supports address conversion but we could add eg. crypto functions here.
62///
63/// This is a trait to allow mocks in the test code. Its members have a read-only
64/// reference to the Api instance to allow accessing configuration.
65/// Implementations must not have mutable state, such that an instance can freely
66/// be copied and shared between threads without affecting the behaviour.
67/// Given an Api instance, all members should return the same value when called with the same
68/// arguments. In particular this means the result must not depend in the state of the chain.
69/// If you need to access chaim state, you probably want to use the Querier.
70/// Side effects (such as logging) are allowed.
71///
72/// We can use feature flags to opt-in to non-essential methods
73/// for backwards compatibility in systems that don't have them all.
74pub trait Api {
75    /// Takes a human readable address and validates if it is valid.
76    /// If it the validation succeeds, a `Addr` containing the same data as the input is returned.
77    ///
78    /// This validation checks two things:
79    /// 1. The address is valid in the sense that it can be converted to a canonical representation by the backend.
80    /// 2. The address is normalized, i.e. `humanize(canonicalize(input)) == input`.
81    ///
82    /// Check #2 is typically needed for upper/lower case representations of the same
83    /// address that are both valid according to #1. This way we ensure uniqueness
84    /// of the human readable address. Clients should perform the normalization before sending
85    /// the addresses to the CosmWasm stack. But please note that the definition of normalized
86    /// depends on the backend.
87    ///
88    /// ## Examples
89    ///
90    /// ```
91    /// # use secret_cosmwasm_std::{Api, Addr};
92    /// # use secret_cosmwasm_std::testing::MockApi;
93    /// # let api = MockApi::default();
94    /// let input = "what-users-provide";
95    /// let validated: Addr = api.addr_validate(input).unwrap();
96    /// assert_eq!(validated, input);
97    /// ```
98    fn addr_validate(&self, human: &str) -> StdResult<Addr>;
99
100    /// Takes a human readable address and returns a canonical binary representation of it.
101    /// This can be used when a compact representation is needed.
102    ///
103    /// Please note that the length of the resulting address is defined by the chain and
104    /// can vary from address to address. On Cosmos chains 20 and 32 bytes are typically used.
105    /// But that might change. So your contract should not make assumptions on the size.
106    fn addr_canonicalize(&self, human: &str) -> StdResult<CanonicalAddr>;
107
108    /// Takes a canonical address and returns a human readble address.
109    /// This is the inverse of [`addr_canonicalize`].
110    ///
111    /// [`addr_canonicalize`]: Api::addr_canonicalize
112    fn addr_humanize(&self, canonical: &CanonicalAddr) -> StdResult<Addr>;
113
114    /// ECDSA secp256k1 signature verification.
115    ///
116    /// This function verifies message hashes (hashed unsing SHA-256) against a signature,
117    /// with the public key of the signer, using the secp256k1 elliptic curve digital signature
118    /// parametrization / algorithm.
119    ///
120    /// The signature and public key are in "Cosmos" format:
121    /// - signature:  Serialized "compact" signature (64 bytes).
122    /// - public key: [Serialized according to SEC 2](https://www.oreilly.com/library/view/programming-bitcoin/9781492031482/ch04.html)
123    fn secp256k1_verify(
124        &self,
125        message_hash: &[u8],
126        signature: &[u8],
127        public_key: &[u8],
128    ) -> Result<bool, VerificationError>;
129
130    /// Recovers a public key from a message hash and a signature.
131    ///
132    /// This is required when working with Ethereum where public keys
133    /// are not stored on chain directly.
134    ///
135    /// `recovery_param` must be 0 or 1. The values 2 and 3 are unsupported by this implementation,
136    /// which is the same restriction as Ethereum has (https://github.com/ethereum/go-ethereum/blob/v1.9.25/internal/ethapi/api.go#L466-L469).
137    /// All other values are invalid.
138    ///
139    /// Returns the recovered pubkey in compressed form, which can be used
140    /// in secp256k1_verify directly.
141    fn secp256k1_recover_pubkey(
142        &self,
143        message_hash: &[u8],
144        signature: &[u8],
145        recovery_param: u8,
146    ) -> Result<Vec<u8>, RecoverPubkeyError>;
147
148    /// EdDSA ed25519 signature verification.
149    ///
150    /// This function verifies messages against a signature, with the public key of the signer,
151    /// using the ed25519 elliptic curve digital signature parametrization / algorithm.
152    ///
153    /// The maximum currently supported message length is 4096 bytes.
154    /// The signature and public key are in [Tendermint](https://docs.tendermint.com/v0.32/spec/blockchain/encoding.html#public-key-cryptography)
155    /// format:
156    /// - signature: raw ED25519 signature (64 bytes).
157    /// - public key: raw ED25519 public key (32 bytes).
158    fn ed25519_verify(
159        &self,
160        message: &[u8],
161        signature: &[u8],
162        public_key: &[u8],
163    ) -> Result<bool, VerificationError>;
164
165    /// Performs batch Ed25519 signature verification.
166    ///
167    /// Batch verification asks whether all signatures in some set are valid, rather than asking whether
168    /// each of them is valid. This allows sharing computations among all signature verifications,
169    /// performing less work overall, at the cost of higher latency (the entire batch must complete),
170    /// complexity of caller code (which must assemble a batch of signatures across work-items),
171    /// and loss of the ability to easily pinpoint failing signatures.
172    ///
173    /// This batch verification implementation is adaptive, in the sense that it detects multiple
174    /// signatures created with the same verification key, and automatically coalesces terms
175    /// in the final verification equation.
176    ///
177    /// In the limiting case where all signatures in the batch are made with the same verification key,
178    /// coalesced batch verification runs twice as fast as ordinary batch verification.
179    ///
180    /// Three Variants are suppported in the input for convenience:
181    ///  - Equal number of messages, signatures, and public keys: Standard, generic functionality.
182    ///  - One message, and an equal number of signatures and public keys: Multiple digital signature
183    /// (multisig) verification of a single message.
184    ///  - One public key, and an equal number of messages and signatures: Verification of multiple
185    /// messages, all signed with the same private key.
186    ///
187    /// Any other variants of input vectors result in an error.
188    ///
189    /// Notes:
190    ///  - The "one-message, with zero signatures and zero public keys" case, is considered the empty case.
191    ///  - The "one-public key, with zero messages and zero signatures" case, is considered the empty case.
192    ///  - The empty case (no messages, no signatures and no public keys) returns true.
193    fn ed25519_batch_verify(
194        &self,
195        messages: &[&[u8]],
196        signatures: &[&[u8]],
197        public_keys: &[&[u8]],
198    ) -> Result<bool, VerificationError>;
199
200    /// Emits a debugging message that is handled depending on the environment (typically printed to console or ignored).
201    /// Those messages are not persisted to chain.
202    fn debug(&self, message: &str);
203
204    /// ECDSA secp256k1 signing.
205    ///
206    /// This function signs a message with a private key using the secp256k1 elliptic curve digital signature parametrization / algorithm.
207    ///
208    /// - message: Arbitrary message.
209    /// - private key: Raw secp256k1 private key (32 bytes)
210    fn secp256k1_sign(&self, message: &[u8], private_key: &[u8]) -> Result<Vec<u8>, SigningError>;
211
212    /// EdDSA Ed25519 signing.
213    ///
214    /// This function signs a message with a private key using the ed25519 elliptic curve digital signature parametrization / algorithm.
215    ///
216    /// - message: Arbitrary message.
217    /// - private key: Raw ED25519 private key (32 bytes)
218    fn ed25519_sign(&self, message: &[u8], private_key: &[u8]) -> Result<Vec<u8>, SigningError>;
219
220    /// Check Gas.
221    ///
222    /// This function will return the amount of gas currently used by the contract.
223    fn check_gas(&self) -> StdResult<u64>;
224
225    /// Gas evaporation.
226    ///
227    /// This function will burn a evaporate a precise and reproducible amount of sdk gas.
228    ///
229    ///  - evaporate: Amount of SDK gas to evaporate.
230    fn gas_evaporate(&self, evaporate: u32) -> StdResult<()>;
231}
232
233/// A short-hand alias for the two-level query result (1. accessing the contract, 2. executing query in the contract)
234pub type QuerierResult = SystemResult<ContractResult<Binary>>;
235
236pub trait Querier {
237    /// raw_query is all that must be implemented for the Querier.
238    /// This allows us to pass through binary queries from one level to another without
239    /// knowing the custom format, or we can decode it, with the knowledge of the allowed
240    /// types. People using the querier probably want one of the simpler auto-generated
241    /// helper methods
242    fn raw_query(&self, bin_request: &[u8]) -> QuerierResult;
243}
244
245#[derive(Clone)]
246pub struct QuerierWrapper<'a, C: CustomQuery = Empty> {
247    querier: &'a dyn Querier,
248    custom_query_type: PhantomData<C>,
249}
250
251// Use custom implementation on order to implement Copy in case `C` is not `Copy`.
252// See "There is a small difference between the two: the derive strategy will also
253// place a Copy bound on type parameters, which isn’t always desired."
254// https://doc.rust-lang.org/std/marker/trait.Copy.html
255impl<'a, C: CustomQuery> Copy for QuerierWrapper<'a, C> {}
256
257/// This allows us to use self.raw_query to access the querier.
258/// It also allows external callers to access the querier easily.
259impl<'a, C: CustomQuery> Deref for QuerierWrapper<'a, C> {
260    type Target = dyn Querier + 'a;
261
262    fn deref(&self) -> &Self::Target {
263        self.querier
264    }
265}
266
267impl<'a, C: CustomQuery> QuerierWrapper<'a, C> {
268    pub fn new(querier: &'a dyn Querier) -> Self {
269        QuerierWrapper {
270            querier,
271            custom_query_type: PhantomData,
272        }
273    }
274
275    /// Makes the query and parses the response.
276    ///
277    /// Any error (System Error, Error or called contract, or Parse Error) are flattened into
278    /// one level. Only use this if you don't need to check the SystemError
279    /// eg. If you don't differentiate between contract missing and contract returned error
280    pub fn query<U: DeserializeOwned>(&self, request: &QueryRequest<C>) -> StdResult<U> {
281        let raw = to_vec(request).map_err(|serialize_err| {
282            StdError::generic_err(format!("Serializing QueryRequest: {}", serialize_err))
283        })?;
284        match self.raw_query(&raw) {
285            SystemResult::Err(system_err) => Err(StdError::generic_err(format!(
286                "Querier system error: {}",
287                system_err
288            ))),
289            SystemResult::Ok(ContractResult::Err(contract_err)) => Err(StdError::generic_err(
290                format!("Querier contract error: {}", contract_err),
291            )),
292            SystemResult::Ok(ContractResult::Ok(value)) => from_binary(&value),
293        }
294    }
295
296    #[cfg(feature = "cosmwasm_1_1")]
297    pub fn query_supply(&self, denom: impl Into<String>) -> StdResult<Coin> {
298        let request = BankQuery::Supply {
299            denom: denom.into(),
300        }
301        .into();
302        let res: SupplyResponse = self.query(&request)?;
303        Ok(res.amount)
304    }
305
306    pub fn query_balance(
307        &self,
308        address: impl Into<String>,
309        denom: impl Into<String>,
310    ) -> StdResult<Coin> {
311        let request = BankQuery::Balance {
312            address: address.into(),
313            denom: denom.into(),
314        }
315        .into();
316        let res: BalanceResponse = self.query(&request)?;
317        Ok(res.amount)
318    }
319
320    pub fn query_all_balances(&self, address: impl Into<String>) -> StdResult<Vec<Coin>> {
321        let request = BankQuery::AllBalances {
322            address: address.into(),
323        }
324        .into();
325        let res: AllBalanceResponse = self.query(&request)?;
326        Ok(res.amount)
327    }
328
329    // this queries another wasm contract. You should know a priori the proper types for T and U
330    // (response and request) based on the contract API
331    pub fn query_wasm_smart<T: DeserializeOwned>(
332        &self,
333        code_hash: impl Into<String>,
334        contract_addr: impl Into<String>,
335        msg: &impl Serialize,
336    ) -> StdResult<T> {
337        let request = WasmQuery::Smart {
338            contract_addr: contract_addr.into(),
339            code_hash: code_hash.into(),
340            msg: to_binary(msg)?,
341        }
342        .into();
343        self.query(&request)
344    }
345
346    #[cfg(feature = "staking")]
347    pub fn query_all_validators(&self) -> StdResult<Vec<Validator>> {
348        let request = StakingQuery::AllValidators {}.into();
349        let res: AllValidatorsResponse = self.query(&request)?;
350        Ok(res.validators)
351    }
352
353    #[cfg(feature = "staking")]
354    pub fn query_validator(&self, address: impl Into<String>) -> StdResult<Option<Validator>> {
355        let request = StakingQuery::Validator {
356            address: address.into(),
357        }
358        .into();
359        let res: ValidatorResponse = self.query(&request)?;
360        Ok(res.validator)
361    }
362
363    #[cfg(feature = "staking")]
364    pub fn query_bonded_denom(&self) -> StdResult<String> {
365        let request = StakingQuery::BondedDenom {}.into();
366        let res: BondedDenomResponse = self.query(&request)?;
367        Ok(res.denom)
368    }
369
370    #[cfg(feature = "staking")]
371    pub fn query_all_delegations(
372        &self,
373        delegator: impl Into<String>,
374    ) -> StdResult<Vec<Delegation>> {
375        let request = StakingQuery::AllDelegations {
376            delegator: delegator.into(),
377        }
378        .into();
379        let res: AllDelegationsResponse = self.query(&request)?;
380        Ok(res.delegations)
381    }
382
383    #[cfg(feature = "staking")]
384    pub fn query_delegation(
385        &self,
386        delegator: impl Into<String>,
387        validator: impl Into<String>,
388    ) -> StdResult<Option<FullDelegation>> {
389        let request = StakingQuery::Delegation {
390            delegator: delegator.into(),
391            validator: validator.into(),
392        }
393        .into();
394        let res: DelegationResponse = self.query(&request)?;
395        Ok(res.delegation)
396    }
397}
398
399#[cfg(test)]
400mod tests {
401    use super::*;
402    use crate::testing::MockQuerier;
403    use crate::{coins, from_slice, Uint128};
404
405    // this is a simple demo helper to prove we can use it
406    fn demo_helper(_querier: &dyn Querier) -> u64 {
407        2
408    }
409
410    // this just needs to compile to prove we can use it
411    #[test]
412    fn use_querier_wrapper_as_querier() {
413        let querier: MockQuerier<Empty> = MockQuerier::new(&[]);
414        let wrapper = QuerierWrapper::<Empty>::new(&querier);
415
416        // call with deref shortcut
417        let res = demo_helper(&*wrapper);
418        assert_eq!(2, res);
419
420        // call with explicit deref
421        let res = demo_helper(wrapper.deref());
422        assert_eq!(2, res);
423    }
424
425    #[test]
426    fn auto_deref_raw_query() {
427        let acct = String::from("foobar");
428        let querier: MockQuerier<Empty> = MockQuerier::new(&[(&acct, &coins(5, "BTC"))]);
429        let wrapper = QuerierWrapper::<Empty>::new(&querier);
430        let query = QueryRequest::<Empty>::Bank(BankQuery::Balance {
431            address: acct,
432            denom: "BTC".to_string(),
433        });
434
435        let raw = wrapper
436            .raw_query(&to_vec(&query).unwrap())
437            .unwrap()
438            .unwrap();
439        let balance: BalanceResponse = from_slice(&raw).unwrap();
440        assert_eq!(balance.amount.amount, Uint128::new(5));
441    }
442
443    #[cfg(feature = "cosmwasm_1_1")]
444    #[test]
445    fn bank_query_helpers_work() {
446        use crate::coin;
447
448        let querier: MockQuerier<Empty> = MockQuerier::new(&[
449            ("foo", &[coin(123, "ELF"), coin(777, "FLY")]),
450            ("bar", &[coin(321, "ELF")]),
451        ]);
452        let wrapper = QuerierWrapper::<Empty>::new(&querier);
453
454        let supply = wrapper.query_supply("ELF").unwrap();
455        assert_eq!(supply, coin(444, "ELF"));
456
457        let balance = wrapper.query_balance("foo", "ELF").unwrap();
458        assert_eq!(balance, coin(123, "ELF"));
459
460        let all_balances = wrapper.query_all_balances("foo").unwrap();
461        assert_eq!(all_balances, vec![coin(123, "ELF"), coin(777, "FLY")]);
462    }
463}