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}