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