cosmwasm_std/testing/
mock.rs

1use alloc::collections::BTreeMap;
2use bech32::{encode, ToBase32, Variant};
3use core::marker::PhantomData;
4#[cfg(feature = "cosmwasm_1_3")]
5use core::ops::Bound;
6use serde::de::DeserializeOwned;
7#[cfg(feature = "stargate")]
8use serde::Serialize;
9use sha2::{Digest, Sha256};
10#[cfg(feature = "cosmwasm_1_3")]
11use std::collections::BTreeSet;
12use std::collections::HashMap;
13
14use crate::addresses::{Addr, CanonicalAddr};
15use crate::binary::Binary;
16use crate::coin::Coin;
17use crate::deps::OwnedDeps;
18use crate::errors::{RecoverPubkeyError, StdError, StdResult, SystemError, VerificationError};
19#[cfg(feature = "stargate")]
20use crate::ibc::{
21    IbcAcknowledgement, IbcChannel, IbcChannelCloseMsg, IbcChannelConnectMsg, IbcChannelOpenMsg,
22    IbcEndpoint, IbcOrder, IbcPacket, IbcPacketAckMsg, IbcPacketReceiveMsg, IbcPacketTimeoutMsg,
23    IbcTimeoutBlock,
24};
25use crate::math::Uint128;
26#[cfg(feature = "cosmwasm_1_1")]
27use crate::query::SupplyResponse;
28use crate::query::{
29    AllBalanceResponse, BalanceResponse, BankQuery, CustomQuery, QueryRequest, WasmQuery,
30};
31#[cfg(feature = "staking")]
32use crate::query::{
33    AllDelegationsResponse, AllValidatorsResponse, BondedDenomResponse, DelegationResponse,
34    FullDelegation, StakingQuery, Validator, ValidatorResponse,
35};
36#[cfg(feature = "cosmwasm_1_3")]
37use crate::query::{DelegatorWithdrawAddressResponse, DistributionQuery};
38use crate::results::{ContractResult, Empty, SystemResult};
39use crate::serde::{from_json, to_json_binary};
40use crate::storage::MemoryStorage;
41use crate::timestamp::Timestamp;
42use crate::traits::{Api, Querier, QuerierResult};
43use crate::types::{BlockInfo, ContractInfo, Env, MessageInfo, TransactionInfo};
44#[cfg(feature = "cosmwasm_1_3")]
45use crate::{
46    query::{AllDenomMetadataResponse, DecCoin, DenomMetadataResponse},
47    PageRequest,
48};
49use crate::{Attribute, DenomMetadata};
50#[cfg(feature = "stargate")]
51use crate::{ChannelResponse, IbcQuery, ListChannelsResponse, PortIdResponse};
52#[cfg(feature = "cosmwasm_1_4")]
53use crate::{Decimal256, DelegationRewardsResponse, DelegatorValidatorsResponse};
54
55use super::riffle_shuffle;
56
57pub const MOCK_CONTRACT_ADDR: &str = "cosmos2contract";
58
59/// Creates all external requirements that can be injected for unit tests.
60///
61/// See also [`mock_dependencies_with_balance`] and [`mock_dependencies_with_balances`]
62/// if you want to start with some initial balances.
63pub fn mock_dependencies() -> OwnedDeps<MockStorage, MockApi, MockQuerier, Empty> {
64    OwnedDeps {
65        storage: MockStorage::default(),
66        api: MockApi::default(),
67        querier: MockQuerier::default(),
68        custom_query_type: PhantomData,
69    }
70}
71
72/// Creates all external requirements that can be injected for unit tests.
73///
74/// It sets the given balance for the contract itself, nothing else.
75pub fn mock_dependencies_with_balance(
76    contract_balance: &[Coin],
77) -> OwnedDeps<MockStorage, MockApi, MockQuerier, Empty> {
78    mock_dependencies_with_balances(&[(MOCK_CONTRACT_ADDR, contract_balance)])
79}
80
81/// Initializes the querier along with the mock_dependencies.
82/// Sets all balances provided (you must explicitly set contract balance if desired).
83pub fn mock_dependencies_with_balances(
84    balances: &[(&str, &[Coin])],
85) -> OwnedDeps<MockStorage, MockApi, MockQuerier> {
86    OwnedDeps {
87        storage: MockStorage::default(),
88        api: MockApi::default(),
89        querier: MockQuerier::new(balances),
90        custom_query_type: PhantomData,
91    }
92}
93
94// Use MemoryStorage implementation (which is valid in non-testcode)
95// We can later make simplifications here if needed
96pub type MockStorage = MemoryStorage;
97
98/// Length of canonical addresses created with this API. Contracts should not make any assumptions
99/// what this value is.
100///
101/// The mock API can only canonicalize and humanize addresses up to this length. So it must be
102/// long enough to store common bech32 addresses.
103///
104/// The value here must be restorable with `SHUFFLES_ENCODE` + `SHUFFLES_DECODE` in-shuffles.
105/// See <https://oeis.org/A002326/list> for a table of those values.
106const CANONICAL_LENGTH: usize = 90; // n = 45
107
108const SHUFFLES_ENCODE: usize = 10;
109const SHUFFLES_DECODE: usize = 2;
110
111/// Default prefix used when creating Bech32 encoded address.
112const BECH32_PREFIX: &str = "cosmwasm";
113
114// MockApi zero pads all human addresses to make them fit the canonical_length
115// it trims off zeros for the reverse operation.
116// not really smart, but allows us to see a difference (and consistent length for canonical addresses)
117#[derive(Copy, Clone)]
118pub struct MockApi {
119    /// Length of canonical addresses created with this API. Contracts should not make any assumptions
120    /// what this value is.
121    canonical_length: usize,
122    /// Prefix used for creating addresses in Bech32 encoding.
123    bech32_prefix: &'static str,
124}
125
126impl Default for MockApi {
127    fn default() -> Self {
128        MockApi {
129            canonical_length: CANONICAL_LENGTH,
130            bech32_prefix: BECH32_PREFIX,
131        }
132    }
133}
134
135impl Api for MockApi {
136    fn addr_validate(&self, input: &str) -> StdResult<Addr> {
137        let canonical = self.addr_canonicalize(input)?;
138        let normalized = self.addr_humanize(&canonical)?;
139        if input != normalized {
140            return Err(StdError::generic_err(
141                "Invalid input: address not normalized",
142            ));
143        }
144
145        Ok(Addr::unchecked(input))
146    }
147
148    fn addr_canonicalize(&self, input: &str) -> StdResult<CanonicalAddr> {
149        // Dummy input validation. This is more sophisticated for formats like bech32, where format and checksum are validated.
150        let min_length = 3;
151        let max_length = self.canonical_length;
152        if input.len() < min_length {
153            return Err(StdError::generic_err(
154                format!("Invalid input: human address too short for this mock implementation (must be >= {min_length})."),
155            ));
156        }
157        if input.len() > max_length {
158            return Err(StdError::generic_err(
159                format!("Invalid input: human address too long for this mock implementation (must be <= {max_length})."),
160            ));
161        }
162
163        // mimics formats like hex or bech32 where different casings are valid for one address
164        let normalized = input.to_lowercase();
165
166        let mut out = Vec::from(normalized);
167
168        // pad to canonical length with NULL bytes
169        out.resize(self.canonical_length, 0x00);
170        // content-dependent rotate followed by shuffle to destroy
171        // the most obvious structure (https://github.com/CosmWasm/cosmwasm/issues/552)
172        let rotate_by = digit_sum(&out) % self.canonical_length;
173        out.rotate_left(rotate_by);
174        for _ in 0..SHUFFLES_ENCODE {
175            out = riffle_shuffle(&out);
176        }
177        Ok(out.into())
178    }
179
180    fn addr_humanize(&self, canonical: &CanonicalAddr) -> StdResult<Addr> {
181        if canonical.len() != self.canonical_length {
182            return Err(StdError::generic_err(
183                "Invalid input: canonical address length not correct",
184            ));
185        }
186
187        let mut tmp: Vec<u8> = canonical.clone().into();
188        // Shuffle two more times which restored the original value (24 elements are back to original after 20 rounds)
189        for _ in 0..SHUFFLES_DECODE {
190            tmp = riffle_shuffle(&tmp);
191        }
192        // Rotate back
193        let rotate_by = digit_sum(&tmp) % self.canonical_length;
194        tmp.rotate_right(rotate_by);
195        // Remove NULL bytes (i.e. the padding)
196        let trimmed = tmp.into_iter().filter(|&x| x != 0x00).collect();
197        // decode UTF-8 bytes into string
198        let human = String::from_utf8(trimmed)?;
199        Ok(Addr::unchecked(human))
200    }
201
202    fn secp256k1_verify(
203        &self,
204        message_hash: &[u8],
205        signature: &[u8],
206        public_key: &[u8],
207    ) -> Result<bool, VerificationError> {
208        Ok(cosmwasm_crypto::secp256k1_verify(
209            message_hash,
210            signature,
211            public_key,
212        )?)
213    }
214
215    fn secp256k1_recover_pubkey(
216        &self,
217        message_hash: &[u8],
218        signature: &[u8],
219        recovery_param: u8,
220    ) -> Result<Vec<u8>, RecoverPubkeyError> {
221        let pubkey =
222            cosmwasm_crypto::secp256k1_recover_pubkey(message_hash, signature, recovery_param)?;
223        Ok(pubkey.to_vec())
224    }
225
226    fn ed25519_verify(
227        &self,
228        message: &[u8],
229        signature: &[u8],
230        public_key: &[u8],
231    ) -> Result<bool, VerificationError> {
232        Ok(cosmwasm_crypto::ed25519_verify(
233            message, signature, public_key,
234        )?)
235    }
236
237    fn ed25519_batch_verify(
238        &self,
239        messages: &[&[u8]],
240        signatures: &[&[u8]],
241        public_keys: &[&[u8]],
242    ) -> Result<bool, VerificationError> {
243        Ok(cosmwasm_crypto::ed25519_batch_verify(
244            messages,
245            signatures,
246            public_keys,
247        )?)
248    }
249
250    fn debug(&self, message: &str) {
251        println!("{message}");
252    }
253}
254
255impl MockApi {
256    /// Returns [MockApi] with Bech32 prefix set to provided value.
257    ///
258    /// Bech32 prefix must not be empty.
259    ///
260    /// # Example
261    ///
262    /// ```
263    /// # use cosmwasm_std::Addr;
264    /// # use cosmwasm_std::testing::MockApi;
265    /// #
266    /// let mock_api = MockApi::default().with_prefix("juno");
267    /// let addr = mock_api.addr_make("creator");
268    ///
269    /// assert_eq!(addr.to_string(), "juno1h34lmpywh4upnjdg90cjf4j70aee6z8qqfspugamjp42e4q28kqsksmtyp");
270    /// ```
271    pub fn with_prefix(mut self, prefix: &'static str) -> Self {
272        self.bech32_prefix = prefix;
273        self
274    }
275
276    /// Returns an address built from provided input string.
277    ///
278    /// # Example
279    ///
280    /// ```
281    /// # use cosmwasm_std::Addr;
282    /// # use cosmwasm_std::testing::MockApi;
283    /// #
284    /// let mock_api = MockApi::default();
285    /// let addr = mock_api.addr_make("creator");
286    ///
287    /// assert_eq!(addr.to_string(), "cosmwasm1h34lmpywh4upnjdg90cjf4j70aee6z8qqfspugamjp42e4q28kqs8s7vcp");
288    /// ```
289    ///
290    /// # Panics
291    ///
292    /// This function panics when generating a valid address is not possible,
293    /// especially when Bech32 prefix set in function [with_prefix](Self::with_prefix) is empty.
294    ///
295    pub fn addr_make(&self, input: &str) -> Addr {
296        let digest = Sha256::digest(input).to_vec();
297        match encode(self.bech32_prefix, digest.to_base32(), Variant::Bech32) {
298            Ok(address) => Addr::unchecked(address),
299            Err(reason) => panic!("Generating address failed with reason: {reason}"),
300        }
301    }
302}
303
304/// Returns a default enviroment with height, time, chain_id, and contract address
305/// You can submit as is to most contracts, or modify height/time if you want to
306/// test for expiration.
307///
308/// This is intended for use in test code only.
309pub fn mock_env() -> Env {
310    Env {
311        block: BlockInfo {
312            height: 12_345,
313            time: Timestamp::from_nanos(1_571_797_419_879_305_533),
314            chain_id: "cosmos-testnet-14002".to_string(),
315        },
316        transaction: Some(TransactionInfo { index: 3 }),
317        contract: ContractInfo {
318            address: Addr::unchecked(MOCK_CONTRACT_ADDR),
319        },
320    }
321}
322
323/// Just set sender and funds for the message.
324/// This is intended for use in test code only.
325pub fn mock_info(sender: &str, funds: &[Coin]) -> MessageInfo {
326    MessageInfo {
327        sender: Addr::unchecked(sender),
328        funds: funds.to_vec(),
329    }
330}
331
332/// Creates an IbcChannel for testing. You set a few key parameters for handshaking,
333/// If you want to set more, use this as a default and mutate other fields
334#[cfg(feature = "stargate")]
335pub fn mock_ibc_channel(my_channel_id: &str, order: IbcOrder, version: &str) -> IbcChannel {
336    IbcChannel {
337        endpoint: IbcEndpoint {
338            port_id: "my_port".to_string(),
339            channel_id: my_channel_id.to_string(),
340        },
341        counterparty_endpoint: IbcEndpoint {
342            port_id: "their_port".to_string(),
343            channel_id: "channel-7".to_string(),
344        },
345        order,
346        version: version.to_string(),
347        connection_id: "connection-2".to_string(),
348    }
349}
350
351/// Creates a IbcChannelOpenMsg::OpenInit for testing ibc_channel_open.
352#[cfg(feature = "stargate")]
353pub fn mock_ibc_channel_open_init(
354    my_channel_id: &str,
355    order: IbcOrder,
356    version: &str,
357) -> IbcChannelOpenMsg {
358    IbcChannelOpenMsg::new_init(mock_ibc_channel(my_channel_id, order, version))
359}
360
361/// Creates a IbcChannelOpenMsg::OpenTry for testing ibc_channel_open.
362#[cfg(feature = "stargate")]
363pub fn mock_ibc_channel_open_try(
364    my_channel_id: &str,
365    order: IbcOrder,
366    version: &str,
367) -> IbcChannelOpenMsg {
368    IbcChannelOpenMsg::new_try(mock_ibc_channel(my_channel_id, order, version), version)
369}
370
371/// Creates a IbcChannelConnectMsg::ConnectAck for testing ibc_channel_connect.
372#[cfg(feature = "stargate")]
373pub fn mock_ibc_channel_connect_ack(
374    my_channel_id: &str,
375    order: IbcOrder,
376    version: &str,
377) -> IbcChannelConnectMsg {
378    IbcChannelConnectMsg::new_ack(mock_ibc_channel(my_channel_id, order, version), version)
379}
380
381/// Creates a IbcChannelConnectMsg::ConnectConfirm for testing ibc_channel_connect.
382#[cfg(feature = "stargate")]
383pub fn mock_ibc_channel_connect_confirm(
384    my_channel_id: &str,
385    order: IbcOrder,
386    version: &str,
387) -> IbcChannelConnectMsg {
388    IbcChannelConnectMsg::new_confirm(mock_ibc_channel(my_channel_id, order, version))
389}
390
391/// Creates a IbcChannelCloseMsg::CloseInit for testing ibc_channel_close.
392#[cfg(feature = "stargate")]
393pub fn mock_ibc_channel_close_init(
394    my_channel_id: &str,
395    order: IbcOrder,
396    version: &str,
397) -> IbcChannelCloseMsg {
398    IbcChannelCloseMsg::new_init(mock_ibc_channel(my_channel_id, order, version))
399}
400
401/// Creates a IbcChannelCloseMsg::CloseConfirm for testing ibc_channel_close.
402#[cfg(feature = "stargate")]
403pub fn mock_ibc_channel_close_confirm(
404    my_channel_id: &str,
405    order: IbcOrder,
406    version: &str,
407) -> IbcChannelCloseMsg {
408    IbcChannelCloseMsg::new_confirm(mock_ibc_channel(my_channel_id, order, version))
409}
410
411/// Creates a IbcPacketReceiveMsg for testing ibc_packet_receive. You set a few key parameters that are
412/// often parsed. If you want to set more, use this as a default and mutate other fields
413#[cfg(feature = "stargate")]
414pub fn mock_ibc_packet_recv(
415    my_channel_id: &str,
416    data: &impl Serialize,
417) -> StdResult<IbcPacketReceiveMsg> {
418    Ok(IbcPacketReceiveMsg::new(
419        IbcPacket {
420            data: to_json_binary(data)?,
421            src: IbcEndpoint {
422                port_id: "their-port".to_string(),
423                channel_id: "channel-1234".to_string(),
424            },
425            dest: IbcEndpoint {
426                port_id: "our-port".to_string(),
427                channel_id: my_channel_id.into(),
428            },
429            sequence: 27,
430            timeout: IbcTimeoutBlock {
431                revision: 1,
432                height: 12345678,
433            }
434            .into(),
435        },
436        #[cfg(feature = "ibc3")]
437        Addr::unchecked("relayer"),
438    ))
439}
440
441/// Creates a IbcPacket for testing ibc_packet_{ack,timeout}. You set a few key parameters that are
442/// often parsed. If you want to set more, use this as a default and mutate other fields.
443/// The difference from mock_ibc_packet_recv is if `my_channel_id` is src or dest.
444#[cfg(feature = "stargate")]
445fn mock_ibc_packet(my_channel_id: &str, data: &impl Serialize) -> StdResult<IbcPacket> {
446    Ok(IbcPacket {
447        data: to_json_binary(data)?,
448        src: IbcEndpoint {
449            port_id: "their-port".to_string(),
450            channel_id: my_channel_id.into(),
451        },
452        dest: IbcEndpoint {
453            port_id: "our-port".to_string(),
454            channel_id: "channel-1234".to_string(),
455        },
456        sequence: 29,
457        timeout: IbcTimeoutBlock {
458            revision: 1,
459            height: 432332552,
460        }
461        .into(),
462    })
463}
464
465/// Creates a IbcPacketAckMsg for testing ibc_packet_ack. You set a few key parameters that are
466/// often parsed. If you want to set more, use this as a default and mutate other fields.
467/// The difference from mock_ibc_packet_recv is if `my_channel_id` is src or dest.
468#[cfg(feature = "stargate")]
469pub fn mock_ibc_packet_ack(
470    my_channel_id: &str,
471    data: &impl Serialize,
472    ack: IbcAcknowledgement,
473) -> StdResult<IbcPacketAckMsg> {
474    let packet = mock_ibc_packet(my_channel_id, data)?;
475
476    Ok(IbcPacketAckMsg::new(
477        ack,
478        packet,
479        #[cfg(feature = "ibc3")]
480        Addr::unchecked("relayer"),
481    ))
482}
483
484/// Creates a IbcPacketTimeoutMsg for testing ibc_packet_timeout. You set a few key parameters that are
485/// often parsed. If you want to set more, use this as a default and mutate other fields.
486/// The difference from mock_ibc_packet_recv is if `my_channel_id` is src or dest./
487#[cfg(feature = "stargate")]
488pub fn mock_ibc_packet_timeout(
489    my_channel_id: &str,
490    data: &impl Serialize,
491) -> StdResult<IbcPacketTimeoutMsg> {
492    let packet = mock_ibc_packet(my_channel_id, data)?;
493    Ok(IbcPacketTimeoutMsg::new(
494        packet,
495        #[cfg(feature = "ibc3")]
496        Addr::unchecked("relayer"),
497    ))
498}
499
500/// The same type as cosmwasm-std's QuerierResult, but easier to reuse in
501/// cosmwasm-vm. It might diverge from QuerierResult at some point.
502pub type MockQuerierCustomHandlerResult = SystemResult<ContractResult<Binary>>;
503
504/// MockQuerier holds an immutable table of bank balances
505/// and configurable handlers for Wasm queries and custom queries.
506pub struct MockQuerier<C: DeserializeOwned = Empty> {
507    bank: BankQuerier,
508    #[cfg(feature = "staking")]
509    staking: StakingQuerier,
510    #[cfg(feature = "cosmwasm_1_3")]
511    distribution: DistributionQuerier,
512    wasm: WasmQuerier,
513    #[cfg(feature = "stargate")]
514    ibc: IbcQuerier,
515    /// A handler to handle custom queries. This is set to a dummy handler that
516    /// always errors by default. Update it via `with_custom_handler`.
517    ///
518    /// Use box to avoid the need of another generic type
519    custom_handler: Box<dyn for<'a> Fn(&'a C) -> MockQuerierCustomHandlerResult>,
520}
521
522impl<C: DeserializeOwned> MockQuerier<C> {
523    pub fn new(balances: &[(&str, &[Coin])]) -> Self {
524        MockQuerier {
525            bank: BankQuerier::new(balances),
526            #[cfg(feature = "cosmwasm_1_3")]
527            distribution: DistributionQuerier::default(),
528            #[cfg(feature = "staking")]
529            staking: StakingQuerier::default(),
530            wasm: WasmQuerier::default(),
531            #[cfg(feature = "stargate")]
532            ibc: IbcQuerier::default(),
533            // strange argument notation suggested as a workaround here: https://github.com/rust-lang/rust/issues/41078#issuecomment-294296365
534            custom_handler: Box::from(|_: &_| -> MockQuerierCustomHandlerResult {
535                SystemResult::Err(SystemError::UnsupportedRequest {
536                    kind: "custom".to_string(),
537                })
538            }),
539        }
540    }
541
542    // set a new balance for the given address and return the old balance
543    pub fn update_balance(
544        &mut self,
545        addr: impl Into<String>,
546        balance: Vec<Coin>,
547    ) -> Option<Vec<Coin>> {
548        self.bank.update_balance(addr, balance)
549    }
550
551    pub fn set_denom_metadata(&mut self, denom_metadata: &[DenomMetadata]) {
552        self.bank.set_denom_metadata(denom_metadata);
553    }
554
555    #[cfg(feature = "cosmwasm_1_3")]
556    pub fn set_withdraw_address(
557        &mut self,
558        delegator_address: impl Into<String>,
559        withdraw_address: impl Into<String>,
560    ) {
561        self.distribution
562            .set_withdraw_address(delegator_address, withdraw_address);
563    }
564
565    /// Sets multiple withdraw addresses.
566    ///
567    /// This allows passing multiple tuples of `(delegator_address, withdraw_address)`.
568    /// It does not overwrite existing entries.
569    #[cfg(feature = "cosmwasm_1_3")]
570    pub fn set_withdraw_addresses(
571        &mut self,
572        withdraw_addresses: impl IntoIterator<Item = (impl Into<String>, impl Into<String>)>,
573    ) {
574        self.distribution.set_withdraw_addresses(withdraw_addresses);
575    }
576
577    #[cfg(feature = "cosmwasm_1_3")]
578    pub fn clear_withdraw_addresses(&mut self) {
579        self.distribution.clear_withdraw_addresses();
580    }
581
582    #[cfg(feature = "staking")]
583    pub fn update_staking(
584        &mut self,
585        denom: &str,
586        validators: &[crate::query::Validator],
587        delegations: &[crate::query::FullDelegation],
588    ) {
589        self.staking = StakingQuerier::new(denom, validators, delegations);
590    }
591
592    #[cfg(feature = "stargate")]
593    pub fn update_ibc(&mut self, port_id: &str, channels: &[IbcChannel]) {
594        self.ibc = IbcQuerier::new(port_id, channels);
595    }
596
597    pub fn update_wasm<WH: 'static>(&mut self, handler: WH)
598    where
599        WH: Fn(&WasmQuery) -> QuerierResult,
600    {
601        self.wasm.update_handler(handler)
602    }
603
604    pub fn with_custom_handler<CH: 'static>(mut self, handler: CH) -> Self
605    where
606        CH: Fn(&C) -> MockQuerierCustomHandlerResult,
607    {
608        self.custom_handler = Box::from(handler);
609        self
610    }
611}
612
613impl Default for MockQuerier {
614    fn default() -> Self {
615        MockQuerier::new(&[])
616    }
617}
618
619impl<C: CustomQuery + DeserializeOwned> Querier for MockQuerier<C> {
620    fn raw_query(&self, bin_request: &[u8]) -> QuerierResult {
621        let request: QueryRequest<C> = match from_json(bin_request) {
622            Ok(v) => v,
623            Err(e) => {
624                return SystemResult::Err(SystemError::InvalidRequest {
625                    error: format!("Parsing query request: {e}"),
626                    request: bin_request.into(),
627                })
628            }
629        };
630        self.handle_query(&request)
631    }
632}
633
634impl<C: CustomQuery + DeserializeOwned> MockQuerier<C> {
635    pub fn handle_query(&self, request: &QueryRequest<C>) -> QuerierResult {
636        match &request {
637            QueryRequest::Bank(bank_query) => self.bank.query(bank_query),
638            QueryRequest::Custom(custom_query) => (*self.custom_handler)(custom_query),
639            #[cfg(feature = "staking")]
640            QueryRequest::Staking(staking_query) => self.staking.query(staking_query),
641            #[cfg(feature = "cosmwasm_1_3")]
642            QueryRequest::Distribution(distribution_query) => {
643                self.distribution.query(distribution_query)
644            }
645            QueryRequest::Wasm(msg) => self.wasm.query(msg),
646            #[cfg(feature = "stargate")]
647            QueryRequest::Stargate { .. } => SystemResult::Err(SystemError::UnsupportedRequest {
648                kind: "Stargate".to_string(),
649            }),
650            #[cfg(feature = "stargate")]
651            QueryRequest::Ibc(msg) => self.ibc.query(msg),
652        }
653    }
654}
655
656struct WasmQuerier {
657    /// A handler to handle Wasm queries. This is set to a dummy handler that
658    /// always errors by default. Update it via `with_custom_handler`.
659    ///
660    /// Use box to avoid the need of generic type.
661    handler: Box<dyn for<'a> Fn(&'a WasmQuery) -> QuerierResult>,
662}
663
664impl WasmQuerier {
665    fn new(handler: Box<dyn for<'a> Fn(&'a WasmQuery) -> QuerierResult>) -> Self {
666        Self { handler }
667    }
668
669    fn update_handler<WH: 'static>(&mut self, handler: WH)
670    where
671        WH: Fn(&WasmQuery) -> QuerierResult,
672    {
673        self.handler = Box::from(handler)
674    }
675
676    fn query(&self, request: &WasmQuery) -> QuerierResult {
677        (*self.handler)(request)
678    }
679}
680
681impl Default for WasmQuerier {
682    fn default() -> Self {
683        let handler = Box::from(|request: &WasmQuery| -> QuerierResult {
684            let err = match request {
685                WasmQuery::Smart { contract_addr, .. } => SystemError::NoSuchContract {
686                    addr: contract_addr.clone(),
687                },
688                WasmQuery::Raw { contract_addr, .. } => SystemError::NoSuchContract {
689                    addr: contract_addr.clone(),
690                },
691                WasmQuery::ContractInfo { contract_addr, .. } => SystemError::NoSuchContract {
692                    addr: contract_addr.clone(),
693                },
694                #[cfg(feature = "cosmwasm_1_2")]
695                WasmQuery::CodeInfo { code_id, .. } => {
696                    SystemError::NoSuchCode { code_id: *code_id }
697                }
698            };
699            SystemResult::Err(err)
700        });
701        Self::new(handler)
702    }
703}
704
705#[derive(Clone, Default)]
706pub struct BankQuerier {
707    #[allow(dead_code)]
708    /// HashMap<denom, amount>
709    supplies: HashMap<String, Uint128>,
710    /// HashMap<address, coins>
711    balances: HashMap<String, Vec<Coin>>,
712    /// Vec<Metadata>
713    denom_metadata: BTreeMap<Vec<u8>, DenomMetadata>,
714}
715
716impl BankQuerier {
717    pub fn new(balances: &[(&str, &[Coin])]) -> Self {
718        let balances: HashMap<_, _> = balances
719            .iter()
720            .map(|(s, c)| (s.to_string(), c.to_vec()))
721            .collect();
722
723        BankQuerier {
724            supplies: Self::calculate_supplies(&balances),
725            balances,
726            denom_metadata: BTreeMap::new(),
727        }
728    }
729
730    pub fn update_balance(
731        &mut self,
732        addr: impl Into<String>,
733        balance: Vec<Coin>,
734    ) -> Option<Vec<Coin>> {
735        let result = self.balances.insert(addr.into(), balance);
736        self.supplies = Self::calculate_supplies(&self.balances);
737
738        result
739    }
740
741    pub fn set_denom_metadata(&mut self, denom_metadata: &[DenomMetadata]) {
742        self.denom_metadata = denom_metadata
743            .iter()
744            .map(|d| (d.base.as_bytes().to_vec(), d.clone()))
745            .collect();
746    }
747
748    fn calculate_supplies(balances: &HashMap<String, Vec<Coin>>) -> HashMap<String, Uint128> {
749        let mut supplies = HashMap::new();
750
751        let all_coins = balances.iter().flat_map(|(_, coins)| coins);
752
753        for coin in all_coins {
754            *supplies
755                .entry(coin.denom.clone())
756                .or_insert_with(Uint128::zero) += coin.amount;
757        }
758
759        supplies
760    }
761
762    pub fn query(&self, request: &BankQuery) -> QuerierResult {
763        let contract_result: ContractResult<Binary> = match request {
764            #[cfg(feature = "cosmwasm_1_1")]
765            BankQuery::Supply { denom } => {
766                let amount = self
767                    .supplies
768                    .get(denom)
769                    .cloned()
770                    .unwrap_or_else(Uint128::zero);
771                let bank_res = SupplyResponse {
772                    amount: Coin {
773                        amount,
774                        denom: denom.to_string(),
775                    },
776                };
777                to_json_binary(&bank_res).into()
778            }
779            BankQuery::Balance { address, denom } => {
780                // proper error on not found, serialize result on found
781                let amount = self
782                    .balances
783                    .get(address)
784                    .and_then(|v| v.iter().find(|c| &c.denom == denom).map(|c| c.amount))
785                    .unwrap_or_default();
786                let bank_res = BalanceResponse {
787                    amount: Coin {
788                        amount,
789                        denom: denom.to_string(),
790                    },
791                };
792                to_json_binary(&bank_res).into()
793            }
794            BankQuery::AllBalances { address } => {
795                // proper error on not found, serialize result on found
796                let bank_res = AllBalanceResponse {
797                    amount: self.balances.get(address).cloned().unwrap_or_default(),
798                };
799                to_json_binary(&bank_res).into()
800            }
801            #[cfg(feature = "cosmwasm_1_3")]
802            BankQuery::DenomMetadata { denom } => {
803                let denom_metadata = self.denom_metadata.get(denom.as_bytes());
804                match denom_metadata {
805                    Some(m) => {
806                        let metadata_res = DenomMetadataResponse {
807                            metadata: m.clone(),
808                        };
809                        to_json_binary(&metadata_res).into()
810                    }
811                    None => return SystemResult::Err(SystemError::Unknown {}),
812                }
813            }
814            #[cfg(feature = "cosmwasm_1_3")]
815            BankQuery::AllDenomMetadata { pagination } => {
816                let default_pagination = PageRequest {
817                    key: None,
818                    limit: 100,
819                    reverse: false,
820                };
821                let pagination = pagination.as_ref().unwrap_or(&default_pagination);
822
823                // range of all denoms after the given key (or until the key for reverse)
824                let range = match (pagination.reverse, &pagination.key) {
825                    (_, None) => (Bound::Unbounded, Bound::Unbounded),
826                    (true, Some(key)) => (Bound::Unbounded, Bound::Included(key.as_slice())),
827                    (false, Some(key)) => (Bound::Included(key.as_slice()), Bound::Unbounded),
828                };
829                let iter = self.denom_metadata.range::<[u8], _>(range);
830                // using dynamic dispatch here to reduce code duplication and since this is only testing code
831                let iter: Box<dyn Iterator<Item = _>> = if pagination.reverse {
832                    Box::new(iter.rev())
833                } else {
834                    Box::new(iter)
835                };
836
837                let mut metadata: Vec<_> = iter
838                    // take the requested amount + 1 to get the next key
839                    .take((pagination.limit.saturating_add(1)) as usize)
840                    .map(|(_, m)| m.clone())
841                    .collect();
842
843                // if we took more than requested, remove the last element (the next key),
844                // otherwise this is the last batch
845                let next_key = if metadata.len() > pagination.limit as usize {
846                    metadata.pop().map(|m| Binary::from(m.base.as_bytes()))
847                } else {
848                    None
849                };
850
851                let metadata_res = AllDenomMetadataResponse { metadata, next_key };
852                to_json_binary(&metadata_res).into()
853            }
854        };
855        // system result is always ok in the mock implementation
856        SystemResult::Ok(contract_result)
857    }
858}
859
860#[cfg(feature = "stargate")]
861#[derive(Clone, Default)]
862pub struct IbcQuerier {
863    port_id: String,
864    channels: Vec<IbcChannel>,
865}
866
867#[cfg(feature = "stargate")]
868impl IbcQuerier {
869    /// Create a mock querier where:
870    /// - port_id is the port the "contract" is bound to
871    /// - channels are a list of ibc channels
872    pub fn new(port_id: &str, channels: &[IbcChannel]) -> Self {
873        IbcQuerier {
874            port_id: port_id.to_string(),
875            channels: channels.to_vec(),
876        }
877    }
878
879    pub fn query(&self, request: &IbcQuery) -> QuerierResult {
880        let contract_result: ContractResult<Binary> = match request {
881            IbcQuery::Channel {
882                channel_id,
883                port_id,
884            } => {
885                let channel = self
886                    .channels
887                    .iter()
888                    .find(|c| match port_id {
889                        Some(p) => c.endpoint.channel_id.eq(channel_id) && c.endpoint.port_id.eq(p),
890                        None => {
891                            c.endpoint.channel_id.eq(channel_id)
892                                && c.endpoint.port_id == self.port_id
893                        }
894                    })
895                    .cloned();
896                let res = ChannelResponse { channel };
897                to_json_binary(&res).into()
898            }
899            IbcQuery::ListChannels { port_id } => {
900                let channels = self
901                    .channels
902                    .iter()
903                    .filter(|c| match port_id {
904                        Some(p) => c.endpoint.port_id.eq(p),
905                        None => c.endpoint.port_id == self.port_id,
906                    })
907                    .cloned()
908                    .collect();
909                let res = ListChannelsResponse { channels };
910                to_json_binary(&res).into()
911            }
912            IbcQuery::PortId {} => {
913                let res = PortIdResponse {
914                    port_id: self.port_id.clone(),
915                };
916                to_json_binary(&res).into()
917            }
918        };
919        // system result is always ok in the mock implementation
920        SystemResult::Ok(contract_result)
921    }
922}
923
924#[cfg(feature = "staking")]
925#[derive(Clone, Default)]
926pub struct StakingQuerier {
927    denom: String,
928    validators: Vec<Validator>,
929    delegations: Vec<FullDelegation>,
930}
931
932#[cfg(feature = "staking")]
933impl StakingQuerier {
934    pub fn new(denom: &str, validators: &[Validator], delegations: &[FullDelegation]) -> Self {
935        StakingQuerier {
936            denom: denom.to_string(),
937            validators: validators.to_vec(),
938            delegations: delegations.to_vec(),
939        }
940    }
941
942    pub fn query(&self, request: &StakingQuery) -> QuerierResult {
943        let contract_result: ContractResult<Binary> = match request {
944            StakingQuery::BondedDenom {} => {
945                let res = BondedDenomResponse {
946                    denom: self.denom.clone(),
947                };
948                to_json_binary(&res).into()
949            }
950            StakingQuery::AllValidators {} => {
951                let res = AllValidatorsResponse {
952                    validators: self.validators.clone(),
953                };
954                to_json_binary(&res).into()
955            }
956            StakingQuery::Validator { address } => {
957                let validator: Option<Validator> = self
958                    .validators
959                    .iter()
960                    .find(|validator| validator.address == *address)
961                    .cloned();
962                let res = ValidatorResponse { validator };
963                to_json_binary(&res).into()
964            }
965            StakingQuery::AllDelegations { delegator } => {
966                let delegations: Vec<_> = self
967                    .delegations
968                    .iter()
969                    .filter(|d| d.delegator.as_str() == delegator)
970                    .cloned()
971                    .map(|d| d.into())
972                    .collect();
973                let res = AllDelegationsResponse { delegations };
974                to_json_binary(&res).into()
975            }
976            StakingQuery::Delegation {
977                delegator,
978                validator,
979            } => {
980                let delegation = self
981                    .delegations
982                    .iter()
983                    .find(|d| d.delegator.as_str() == delegator && d.validator == *validator);
984                let res = DelegationResponse {
985                    delegation: delegation.cloned(),
986                };
987                to_json_binary(&res).into()
988            }
989        };
990        // system result is always ok in the mock implementation
991        SystemResult::Ok(contract_result)
992    }
993}
994
995#[cfg(feature = "cosmwasm_1_3")]
996#[derive(Clone, Default)]
997pub struct DistributionQuerier {
998    withdraw_addresses: HashMap<String, String>,
999    /// Mock of accumulated rewards, indexed first by delegator and then validator address.
1000    rewards: BTreeMap<String, BTreeMap<String, Vec<DecCoin>>>,
1001    /// Mock of validators that a delegator has bonded to.
1002    validators: BTreeMap<String, BTreeSet<String>>,
1003}
1004
1005#[cfg(feature = "cosmwasm_1_3")]
1006impl DistributionQuerier {
1007    pub fn new(withdraw_addresses: HashMap<String, String>) -> Self {
1008        DistributionQuerier {
1009            withdraw_addresses,
1010            ..Default::default()
1011        }
1012    }
1013
1014    pub fn set_withdraw_address(
1015        &mut self,
1016        delegator_address: impl Into<String>,
1017        withdraw_address: impl Into<String>,
1018    ) {
1019        self.withdraw_addresses
1020            .insert(delegator_address.into(), withdraw_address.into());
1021    }
1022
1023    /// Sets multiple withdraw addresses.
1024    ///
1025    /// This allows passing multiple tuples of `(delegator_address, withdraw_address)`.
1026    /// It does not overwrite existing entries.
1027    pub fn set_withdraw_addresses(
1028        &mut self,
1029        withdraw_addresses: impl IntoIterator<Item = (impl Into<String>, impl Into<String>)>,
1030    ) {
1031        for (d, w) in withdraw_addresses {
1032            self.set_withdraw_address(d, w);
1033        }
1034    }
1035
1036    pub fn clear_withdraw_addresses(&mut self) {
1037        self.withdraw_addresses.clear();
1038    }
1039
1040    /// Sets accumulated rewards for a given validator and delegator pair.
1041    pub fn set_rewards(
1042        &mut self,
1043        validator: impl Into<String>,
1044        delegator: impl Into<String>,
1045        rewards: Vec<DecCoin>,
1046    ) {
1047        self.rewards
1048            .entry(delegator.into())
1049            .or_default()
1050            .insert(validator.into(), rewards);
1051    }
1052
1053    /// Sets the validators a given delegator has bonded to.
1054    pub fn set_validators(
1055        &mut self,
1056        delegator: impl Into<String>,
1057        validators: impl IntoIterator<Item = impl Into<String>>,
1058    ) {
1059        self.validators.insert(
1060            delegator.into(),
1061            validators.into_iter().map(Into::into).collect(),
1062        );
1063    }
1064
1065    pub fn query(&self, request: &DistributionQuery) -> QuerierResult {
1066        let contract_result: ContractResult<Binary> = match request {
1067            DistributionQuery::DelegatorWithdrawAddress { delegator_address } => {
1068                let res = DelegatorWithdrawAddressResponse {
1069                    withdraw_address: Addr::unchecked(
1070                        self.withdraw_addresses
1071                            .get(delegator_address)
1072                            .unwrap_or(delegator_address),
1073                    ),
1074                };
1075                to_json_binary(&res).into()
1076            }
1077            #[cfg(feature = "cosmwasm_1_4")]
1078            DistributionQuery::DelegationRewards {
1079                delegator_address,
1080                validator_address,
1081            } => {
1082                let res = DelegationRewardsResponse {
1083                    rewards: self
1084                        .rewards
1085                        .get(delegator_address)
1086                        .and_then(|v| v.get(validator_address))
1087                        .cloned()
1088                        .unwrap_or_default(),
1089                };
1090                to_json_binary(&res).into()
1091            }
1092            #[cfg(feature = "cosmwasm_1_4")]
1093            DistributionQuery::DelegationTotalRewards { delegator_address } => {
1094                let validator_rewards = self
1095                    .validator_rewards(delegator_address)
1096                    .unwrap_or_default();
1097                let res = crate::DelegationTotalRewardsResponse {
1098                    total: validator_rewards
1099                        .iter()
1100                        .fold(BTreeMap::<&str, DecCoin>::new(), |mut acc, rewards| {
1101                            for coin in &rewards.reward {
1102                                acc.entry(&coin.denom)
1103                                    .or_insert_with(|| DecCoin {
1104                                        denom: coin.denom.clone(),
1105                                        amount: Decimal256::zero(),
1106                                    })
1107                                    .amount += coin.amount;
1108                            }
1109
1110                            acc
1111                        })
1112                        .into_values()
1113                        .collect(),
1114                    rewards: validator_rewards,
1115                };
1116                to_json_binary(&res).into()
1117            }
1118            #[cfg(feature = "cosmwasm_1_4")]
1119            DistributionQuery::DelegatorValidators { delegator_address } => {
1120                let res = DelegatorValidatorsResponse {
1121                    validators: self
1122                        .validators
1123                        .get(delegator_address)
1124                        .map(|set| set.iter().cloned().collect())
1125                        .unwrap_or_default(),
1126                };
1127                to_json_binary(&res).into()
1128            }
1129        };
1130        // system result is always ok in the mock implementation
1131        SystemResult::Ok(contract_result)
1132    }
1133
1134    /// Helper method to get all rewards for a given delegator.
1135    #[cfg(feature = "cosmwasm_1_4")]
1136    fn validator_rewards(&self, delegator_address: &str) -> Option<Vec<crate::DelegatorReward>> {
1137        let validator_rewards = self.rewards.get(delegator_address)?;
1138
1139        Some(
1140            validator_rewards
1141                .iter()
1142                .map(|(validator, rewards)| crate::DelegatorReward {
1143                    validator_address: validator.clone(),
1144                    reward: rewards.clone(),
1145                })
1146                .collect(),
1147        )
1148    }
1149}
1150
1151pub fn digit_sum(input: &[u8]) -> usize {
1152    input.iter().fold(0, |sum, val| sum + (*val as usize))
1153}
1154
1155/// Only for test code. This bypasses assertions in new, allowing us to create _*
1156/// Attributes to simulate responses from the blockchain
1157pub fn mock_wasmd_attr(key: impl Into<String>, value: impl Into<String>) -> Attribute {
1158    Attribute {
1159        key: key.into(),
1160        value: value.into(),
1161    }
1162}
1163
1164#[cfg(test)]
1165mod tests {
1166    use super::*;
1167    #[cfg(feature = "cosmwasm_1_3")]
1168    use crate::DenomUnit;
1169    use crate::{coin, coins, from_json, to_json_binary, ContractInfoResponse, Response};
1170    #[cfg(feature = "staking")]
1171    use crate::{Decimal, Delegation};
1172    use hex_literal::hex;
1173    use serde::Deserialize;
1174
1175    const SECP256K1_MSG_HASH_HEX: &str =
1176        "5ae8317d34d1e595e3fa7247db80c0af4320cce1116de187f8f7e2e099c0d8d0";
1177    const SECP256K1_SIG_HEX: &str = "207082eb2c3dfa0b454e0906051270ba4074ac93760ba9e7110cd9471475111151eb0dbbc9920e72146fb564f99d039802bf6ef2561446eb126ef364d21ee9c4";
1178    const SECP256K1_PUBKEY_HEX: &str = "04051c1ee2190ecfb174bfe4f90763f2b4ff7517b70a2aec1876ebcfd644c4633fb03f3cfbd94b1f376e34592d9d41ccaf640bb751b00a1fadeb0c01157769eb73";
1179
1180    const ED25519_MSG_HEX: &str = "72";
1181    const ED25519_SIG_HEX: &str = "92a009a9f0d4cab8720e820b5f642540a2b27b5416503f8fb3762223ebdb69da085ac1e43e15996e458f3613d0f11d8c387b2eaeb4302aeeb00d291612bb0c00";
1182    const ED25519_PUBKEY_HEX: &str =
1183        "3d4017c3e843895a92b70aa74d1b7ebc9c982ccf2ec4968cc0cd55f12af4660c";
1184
1185    #[test]
1186    fn mock_info_works() {
1187        let info = mock_info("my name", &coins(100, "atom"));
1188        assert_eq!(
1189            info,
1190            MessageInfo {
1191                sender: Addr::unchecked("my name"),
1192                funds: vec![Coin {
1193                    amount: 100u128.into(),
1194                    denom: "atom".into(),
1195                }]
1196            }
1197        );
1198    }
1199
1200    #[test]
1201    fn addr_validate_works() {
1202        let api = MockApi::default();
1203
1204        // valid
1205        let addr = api.addr_validate("foobar123").unwrap();
1206        assert_eq!(addr, "foobar123");
1207
1208        // invalid: too short
1209        api.addr_validate("").unwrap_err();
1210        // invalid: not normalized
1211        api.addr_validate("Foobar123").unwrap_err();
1212        api.addr_validate("FOOBAR123").unwrap_err();
1213    }
1214
1215    #[test]
1216    fn addr_canonicalize_works() {
1217        let api = MockApi::default();
1218
1219        api.addr_canonicalize("foobar123").unwrap();
1220
1221        // is case insensitive
1222        let data1 = api.addr_canonicalize("foo123").unwrap();
1223        let data2 = api.addr_canonicalize("FOO123").unwrap();
1224        assert_eq!(data1, data2);
1225    }
1226
1227    #[test]
1228    fn canonicalize_and_humanize_restores_original() {
1229        let api = MockApi::default();
1230
1231        // simple
1232        let original = String::from("shorty");
1233        let canonical = api.addr_canonicalize(&original).unwrap();
1234        let recovered = api.addr_humanize(&canonical).unwrap();
1235        assert_eq!(recovered, original);
1236
1237        // normalizes input
1238        let original = String::from("CosmWasmChef");
1239        let canonical = api.addr_canonicalize(&original).unwrap();
1240        let recovered = api.addr_humanize(&canonical).unwrap();
1241        assert_eq!(recovered, "cosmwasmchef");
1242
1243        // Long input (Juno contract address)
1244        let original =
1245            String::from("juno1v82su97skv6ucfqvuvswe0t5fph7pfsrtraxf0x33d8ylj5qnrysdvkc95");
1246        let canonical = api.addr_canonicalize(&original).unwrap();
1247        let recovered = api.addr_humanize(&canonical).unwrap();
1248        assert_eq!(recovered, original);
1249    }
1250
1251    #[test]
1252    fn addr_canonicalize_min_input_length() {
1253        let api = MockApi::default();
1254        let human = String::from("1");
1255        let err = api.addr_canonicalize(&human).unwrap_err();
1256        assert!(err
1257            .to_string()
1258            .contains("human address too short for this mock implementation (must be >= 3)"));
1259    }
1260
1261    #[test]
1262    fn addr_canonicalize_max_input_length() {
1263        let api = MockApi::default();
1264        let human =
1265            String::from("some-extremely-long-address-not-supported-by-this-api-longer-than-supported------------------------");
1266        let err = api.addr_canonicalize(&human).unwrap_err();
1267        assert!(err
1268            .to_string()
1269            .contains("human address too long for this mock implementation (must be <= 90)"));
1270    }
1271
1272    #[test]
1273    #[should_panic(expected = "length not correct")]
1274    fn addr_humanize_input_length() {
1275        let api = MockApi::default();
1276        let input = CanonicalAddr::from(vec![61; 11]);
1277        api.addr_humanize(&input).unwrap();
1278    }
1279
1280    // Basic "works" test. Exhaustive tests on VM's side (packages/vm/src/imports.rs)
1281    #[test]
1282    fn secp256k1_verify_works() {
1283        let api = MockApi::default();
1284
1285        let hash = hex::decode(SECP256K1_MSG_HASH_HEX).unwrap();
1286        let signature = hex::decode(SECP256K1_SIG_HEX).unwrap();
1287        let public_key = hex::decode(SECP256K1_PUBKEY_HEX).unwrap();
1288
1289        assert!(api
1290            .secp256k1_verify(&hash, &signature, &public_key)
1291            .unwrap());
1292    }
1293
1294    // Basic "fails" test. Exhaustive tests on VM's side (packages/vm/src/imports.rs)
1295    #[test]
1296    fn secp256k1_verify_fails() {
1297        let api = MockApi::default();
1298
1299        let mut hash = hex::decode(SECP256K1_MSG_HASH_HEX).unwrap();
1300        // alter hash
1301        hash[0] ^= 0x01;
1302        let signature = hex::decode(SECP256K1_SIG_HEX).unwrap();
1303        let public_key = hex::decode(SECP256K1_PUBKEY_HEX).unwrap();
1304
1305        assert!(!api
1306            .secp256k1_verify(&hash, &signature, &public_key)
1307            .unwrap());
1308    }
1309
1310    // Basic "errors" test. Exhaustive tests on VM's side (packages/vm/src/imports.rs)
1311    #[test]
1312    fn secp256k1_verify_errs() {
1313        let api = MockApi::default();
1314
1315        let hash = hex::decode(SECP256K1_MSG_HASH_HEX).unwrap();
1316        let signature = hex::decode(SECP256K1_SIG_HEX).unwrap();
1317        let public_key = vec![];
1318
1319        let res = api.secp256k1_verify(&hash, &signature, &public_key);
1320        assert_eq!(res.unwrap_err(), VerificationError::InvalidPubkeyFormat);
1321    }
1322
1323    #[test]
1324    fn secp256k1_recover_pubkey_works() {
1325        let api = MockApi::default();
1326
1327        // https://gist.github.com/webmaster128/130b628d83621a33579751846699ed15
1328        let hash = hex!("5ae8317d34d1e595e3fa7247db80c0af4320cce1116de187f8f7e2e099c0d8d0");
1329        let signature = hex!("45c0b7f8c09a9e1f1cea0c25785594427b6bf8f9f878a8af0b1abbb48e16d0920d8becd0c220f67c51217eecfd7184ef0732481c843857e6bc7fc095c4f6b788");
1330        let recovery_param = 1;
1331        let expected = hex!("044a071e8a6e10aada2b8cf39fa3b5fb3400b04e99ea8ae64ceea1a977dbeaf5d5f8c8fbd10b71ab14cd561f7df8eb6da50f8a8d81ba564342244d26d1d4211595");
1332
1333        let pubkey = api
1334            .secp256k1_recover_pubkey(&hash, &signature, recovery_param)
1335            .unwrap();
1336        assert_eq!(pubkey, expected);
1337    }
1338
1339    #[test]
1340    fn secp256k1_recover_pubkey_fails_for_wrong_recovery_param() {
1341        let api = MockApi::default();
1342
1343        // https://gist.github.com/webmaster128/130b628d83621a33579751846699ed15
1344        let hash = hex!("5ae8317d34d1e595e3fa7247db80c0af4320cce1116de187f8f7e2e099c0d8d0");
1345        let signature = hex!("45c0b7f8c09a9e1f1cea0c25785594427b6bf8f9f878a8af0b1abbb48e16d0920d8becd0c220f67c51217eecfd7184ef0732481c843857e6bc7fc095c4f6b788");
1346        let _recovery_param = 1;
1347        let expected = hex!("044a071e8a6e10aada2b8cf39fa3b5fb3400b04e99ea8ae64ceea1a977dbeaf5d5f8c8fbd10b71ab14cd561f7df8eb6da50f8a8d81ba564342244d26d1d4211595");
1348
1349        // Wrong recovery param leads to different pubkey
1350        let pubkey = api.secp256k1_recover_pubkey(&hash, &signature, 0).unwrap();
1351        assert_eq!(pubkey.len(), 65);
1352        assert_ne!(pubkey, expected);
1353
1354        // Invalid recovery param leads to error
1355        let result = api.secp256k1_recover_pubkey(&hash, &signature, 42);
1356        match result.unwrap_err() {
1357            RecoverPubkeyError::InvalidRecoveryParam => {}
1358            err => panic!("Unexpected error: {err:?}"),
1359        }
1360    }
1361
1362    #[test]
1363    fn secp256k1_recover_pubkey_fails_for_wrong_hash() {
1364        let api = MockApi::default();
1365
1366        // https://gist.github.com/webmaster128/130b628d83621a33579751846699ed15
1367        let hash = hex!("5ae8317d34d1e595e3fa7247db80c0af4320cce1116de187f8f7e2e099c0d8d0");
1368        let signature = hex!("45c0b7f8c09a9e1f1cea0c25785594427b6bf8f9f878a8af0b1abbb48e16d0920d8becd0c220f67c51217eecfd7184ef0732481c843857e6bc7fc095c4f6b788");
1369        let recovery_param = 1;
1370        let expected = hex!("044a071e8a6e10aada2b8cf39fa3b5fb3400b04e99ea8ae64ceea1a977dbeaf5d5f8c8fbd10b71ab14cd561f7df8eb6da50f8a8d81ba564342244d26d1d4211595");
1371
1372        // Wrong hash
1373        let mut corrupted_hash = hash;
1374        corrupted_hash[0] ^= 0x01;
1375        let pubkey = api
1376            .secp256k1_recover_pubkey(&corrupted_hash, &signature, recovery_param)
1377            .unwrap();
1378        assert_eq!(pubkey.len(), 65);
1379        assert_ne!(pubkey, expected);
1380
1381        // Malformed hash
1382        let mut malformed_hash = hash.to_vec();
1383        malformed_hash.push(0x8a);
1384        let result = api.secp256k1_recover_pubkey(&malformed_hash, &signature, recovery_param);
1385        match result.unwrap_err() {
1386            RecoverPubkeyError::InvalidHashFormat => {}
1387            err => panic!("Unexpected error: {err:?}"),
1388        }
1389    }
1390
1391    // Basic "works" test. Exhaustive tests on VM's side (packages/vm/src/imports.rs)
1392    #[test]
1393    fn ed25519_verify_works() {
1394        let api = MockApi::default();
1395
1396        let msg = hex::decode(ED25519_MSG_HEX).unwrap();
1397        let signature = hex::decode(ED25519_SIG_HEX).unwrap();
1398        let public_key = hex::decode(ED25519_PUBKEY_HEX).unwrap();
1399
1400        assert!(api.ed25519_verify(&msg, &signature, &public_key).unwrap());
1401    }
1402
1403    // Basic "fails" test. Exhaustive tests on VM's side (packages/vm/src/imports.rs)
1404    #[test]
1405    fn ed25519_verify_fails() {
1406        let api = MockApi::default();
1407
1408        let mut msg = hex::decode(ED25519_MSG_HEX).unwrap();
1409        // alter msg
1410        msg[0] ^= 0x01;
1411        let signature = hex::decode(ED25519_SIG_HEX).unwrap();
1412        let public_key = hex::decode(ED25519_PUBKEY_HEX).unwrap();
1413
1414        assert!(!api.ed25519_verify(&msg, &signature, &public_key).unwrap());
1415    }
1416
1417    // Basic "errors" test. Exhaustive tests on VM's side (packages/vm/src/imports.rs)
1418    #[test]
1419    fn ed25519_verify_errs() {
1420        let api = MockApi::default();
1421
1422        let msg = hex::decode(ED25519_MSG_HEX).unwrap();
1423        let signature = hex::decode(ED25519_SIG_HEX).unwrap();
1424        let public_key = vec![];
1425
1426        let res = api.ed25519_verify(&msg, &signature, &public_key);
1427        assert_eq!(res.unwrap_err(), VerificationError::InvalidPubkeyFormat);
1428    }
1429
1430    // Basic "works" test.
1431    #[test]
1432    fn ed25519_batch_verify_works() {
1433        let api = MockApi::default();
1434
1435        let msg = hex::decode(ED25519_MSG_HEX).unwrap();
1436        let signature = hex::decode(ED25519_SIG_HEX).unwrap();
1437        let public_key = hex::decode(ED25519_PUBKEY_HEX).unwrap();
1438
1439        let msgs: Vec<&[u8]> = vec![&msg];
1440        let signatures: Vec<&[u8]> = vec![&signature];
1441        let public_keys: Vec<&[u8]> = vec![&public_key];
1442
1443        assert!(api
1444            .ed25519_batch_verify(&msgs, &signatures, &public_keys)
1445            .unwrap());
1446    }
1447
1448    // Basic "fails" test.
1449    #[test]
1450    fn ed25519_batch_verify_fails() {
1451        let api = MockApi::default();
1452
1453        let mut msg = hex::decode(ED25519_MSG_HEX).unwrap();
1454        // alter msg
1455        msg[0] ^= 0x01;
1456        let signature = hex::decode(ED25519_SIG_HEX).unwrap();
1457        let public_key = hex::decode(ED25519_PUBKEY_HEX).unwrap();
1458
1459        let msgs: Vec<&[u8]> = vec![&msg];
1460        let signatures: Vec<&[u8]> = vec![&signature];
1461        let public_keys: Vec<&[u8]> = vec![&public_key];
1462
1463        assert!(!api
1464            .ed25519_batch_verify(&msgs, &signatures, &public_keys)
1465            .unwrap());
1466    }
1467
1468    // Basic "errors" test.
1469    #[test]
1470    fn ed25519_batch_verify_errs() {
1471        let api = MockApi::default();
1472
1473        let msg = hex::decode(ED25519_MSG_HEX).unwrap();
1474        let signature = hex::decode(ED25519_SIG_HEX).unwrap();
1475        let public_key: Vec<u8> = vec![0u8; 0];
1476
1477        let msgs: Vec<&[u8]> = vec![msg.as_slice()];
1478        let signatures: Vec<&[u8]> = vec![signature.as_slice()];
1479        let public_keys: Vec<&[u8]> = vec![&public_key];
1480
1481        let res = api.ed25519_batch_verify(&msgs, &signatures, &public_keys);
1482        assert_eq!(res.unwrap_err(), VerificationError::InvalidPubkeyFormat);
1483    }
1484
1485    #[cfg(feature = "cosmwasm_1_1")]
1486    #[test]
1487    fn bank_querier_supply() {
1488        let addr1 = String::from("foo");
1489        let balance1 = vec![coin(123, "ELF"), coin(777, "FLY")];
1490
1491        let addr2 = String::from("bar");
1492        let balance2 = coins(321, "ELF");
1493
1494        let bank = BankQuerier::new(&[(&addr1, &balance1), (&addr2, &balance2)]);
1495
1496        let elf = bank
1497            .query(&BankQuery::Supply {
1498                denom: "ELF".to_string(),
1499            })
1500            .unwrap()
1501            .unwrap();
1502        let res: SupplyResponse = from_json(elf).unwrap();
1503        assert_eq!(res.amount, coin(444, "ELF"));
1504
1505        let fly = bank
1506            .query(&BankQuery::Supply {
1507                denom: "FLY".to_string(),
1508            })
1509            .unwrap()
1510            .unwrap();
1511        let res: SupplyResponse = from_json(fly).unwrap();
1512        assert_eq!(res.amount, coin(777, "FLY"));
1513
1514        // if a denom does not exist, should return zero amount, instead of throwing an error
1515        let atom = bank
1516            .query(&BankQuery::Supply {
1517                denom: "ATOM".to_string(),
1518            })
1519            .unwrap()
1520            .unwrap();
1521        let res: SupplyResponse = from_json(atom).unwrap();
1522        assert_eq!(res.amount, coin(0, "ATOM"));
1523    }
1524
1525    #[test]
1526    fn bank_querier_all_balances() {
1527        let addr = String::from("foobar");
1528        let balance = vec![coin(123, "ELF"), coin(777, "FLY")];
1529        let bank = BankQuerier::new(&[(&addr, &balance)]);
1530
1531        let all = bank
1532            .query(&BankQuery::AllBalances { address: addr })
1533            .unwrap()
1534            .unwrap();
1535        let res: AllBalanceResponse = from_json(all).unwrap();
1536        assert_eq!(&res.amount, &balance);
1537    }
1538
1539    #[test]
1540    fn bank_querier_one_balance() {
1541        let addr = String::from("foobar");
1542        let balance = vec![coin(123, "ELF"), coin(777, "FLY")];
1543        let bank = BankQuerier::new(&[(&addr, &balance)]);
1544
1545        // one match
1546        let fly = bank
1547            .query(&BankQuery::Balance {
1548                address: addr.clone(),
1549                denom: "FLY".to_string(),
1550            })
1551            .unwrap()
1552            .unwrap();
1553        let res: BalanceResponse = from_json(fly).unwrap();
1554        assert_eq!(res.amount, coin(777, "FLY"));
1555
1556        // missing denom
1557        let miss = bank
1558            .query(&BankQuery::Balance {
1559                address: addr,
1560                denom: "MISS".to_string(),
1561            })
1562            .unwrap()
1563            .unwrap();
1564        let res: BalanceResponse = from_json(miss).unwrap();
1565        assert_eq!(res.amount, coin(0, "MISS"));
1566    }
1567
1568    #[test]
1569    fn bank_querier_missing_account() {
1570        let addr = String::from("foobar");
1571        let balance = vec![coin(123, "ELF"), coin(777, "FLY")];
1572        let bank = BankQuerier::new(&[(&addr, &balance)]);
1573
1574        // all balances on empty account is empty vec
1575        let all = bank
1576            .query(&BankQuery::AllBalances {
1577                address: String::from("elsewhere"),
1578            })
1579            .unwrap()
1580            .unwrap();
1581        let res: AllBalanceResponse = from_json(all).unwrap();
1582        assert_eq!(res.amount, vec![]);
1583
1584        // any denom on balances on empty account is empty coin
1585        let miss = bank
1586            .query(&BankQuery::Balance {
1587                address: String::from("elsewhere"),
1588                denom: "ELF".to_string(),
1589            })
1590            .unwrap()
1591            .unwrap();
1592        let res: BalanceResponse = from_json(miss).unwrap();
1593        assert_eq!(res.amount, coin(0, "ELF"));
1594    }
1595
1596    #[cfg(feature = "cosmwasm_1_3")]
1597    #[test]
1598    fn bank_querier_metadata_works() {
1599        let mut bank = BankQuerier::new(&[]);
1600        bank.set_denom_metadata(
1601            &(0..100)
1602                .map(|i| DenomMetadata {
1603                    symbol: format!("FOO{i}"),
1604                    name: "Foo".to_string(),
1605                    description: "Foo coin".to_string(),
1606                    denom_units: vec![DenomUnit {
1607                        denom: "ufoo".to_string(),
1608                        exponent: 8,
1609                        aliases: vec!["microfoo".to_string(), "foobar".to_string()],
1610                    }],
1611                    display: "FOO".to_string(),
1612                    base: format!("ufoo{i}"),
1613                    uri: "https://foo.bar".to_string(),
1614                    uri_hash: "foo".to_string(),
1615                })
1616                .collect::<Vec<_>>(),
1617        );
1618
1619        // querying first 10 should work
1620        let res = bank
1621            .query(&BankQuery::AllDenomMetadata {
1622                pagination: Some(PageRequest {
1623                    key: None,
1624                    limit: 10,
1625                    reverse: false,
1626                }),
1627            })
1628            .unwrap()
1629            .unwrap();
1630        let res: AllDenomMetadataResponse = from_json(res).unwrap();
1631        assert_eq!(res.metadata.len(), 10);
1632        assert!(res.next_key.is_some());
1633
1634        // querying next 10 should also work
1635        let res2 = bank
1636            .query(&BankQuery::AllDenomMetadata {
1637                pagination: Some(PageRequest {
1638                    key: res.next_key,
1639                    limit: 10,
1640                    reverse: false,
1641                }),
1642            })
1643            .unwrap()
1644            .unwrap();
1645        let res2: AllDenomMetadataResponse = from_json(res2).unwrap();
1646        assert_eq!(res2.metadata.len(), 10);
1647        assert_ne!(res.metadata.last(), res2.metadata.first());
1648        // should have no overlap
1649        for m in res.metadata {
1650            assert!(!res2.metadata.contains(&m));
1651        }
1652
1653        // querying all 100 should work
1654        let res = bank
1655            .query(&BankQuery::AllDenomMetadata {
1656                pagination: Some(PageRequest {
1657                    key: None,
1658                    limit: 100,
1659                    reverse: true,
1660                }),
1661            })
1662            .unwrap()
1663            .unwrap();
1664        let res: AllDenomMetadataResponse = from_json(res).unwrap();
1665        assert_eq!(res.metadata.len(), 100);
1666        assert!(res.next_key.is_none(), "no more data should be available");
1667        assert_eq!(res.metadata[0].symbol, "FOO99", "should have been reversed");
1668
1669        let more_res = bank
1670            .query(&BankQuery::AllDenomMetadata {
1671                pagination: Some(PageRequest {
1672                    key: res.next_key,
1673                    limit: u32::MAX,
1674                    reverse: true,
1675                }),
1676            })
1677            .unwrap()
1678            .unwrap();
1679        let more_res: AllDenomMetadataResponse = from_json(more_res).unwrap();
1680        assert_eq!(
1681            more_res.metadata, res.metadata,
1682            "should be same as previous query"
1683        );
1684    }
1685
1686    #[cfg(feature = "cosmwasm_1_3")]
1687    #[test]
1688    fn distribution_querier_delegator_withdraw_address() {
1689        let mut distribution = DistributionQuerier::default();
1690        distribution.set_withdraw_address("addr0", "withdraw0");
1691
1692        let query = DistributionQuery::DelegatorWithdrawAddress {
1693            delegator_address: "addr0".to_string(),
1694        };
1695
1696        let res = distribution.query(&query).unwrap().unwrap();
1697        let res: DelegatorWithdrawAddressResponse = from_json(res).unwrap();
1698        assert_eq!(res.withdraw_address, "withdraw0");
1699
1700        let query = DistributionQuery::DelegatorWithdrawAddress {
1701            delegator_address: "addr1".to_string(),
1702        };
1703
1704        let res = distribution.query(&query).unwrap().unwrap();
1705        let res: DelegatorWithdrawAddressResponse = from_json(res).unwrap();
1706        assert_eq!(res.withdraw_address, "addr1");
1707    }
1708
1709    #[cfg(feature = "cosmwasm_1_4")]
1710    #[test]
1711    fn distribution_querier_delegator_validators() {
1712        let mut distribution = DistributionQuerier::default();
1713        distribution.set_validators("addr0", ["valoper1", "valoper2"]);
1714
1715        let query = DistributionQuery::DelegatorValidators {
1716            delegator_address: "addr0".to_string(),
1717        };
1718
1719        let res = distribution.query(&query).unwrap().unwrap();
1720        let res: DelegatorValidatorsResponse = from_json(res).unwrap();
1721        assert_eq!(res.validators, ["valoper1", "valoper2"]);
1722
1723        let query = DistributionQuery::DelegatorValidators {
1724            delegator_address: "addr1".to_string(),
1725        };
1726
1727        let res = distribution.query(&query).unwrap().unwrap();
1728        let res: DelegatorValidatorsResponse = from_json(res).unwrap();
1729        assert_eq!(res.validators, ([] as [String; 0]));
1730    }
1731
1732    #[cfg(feature = "cosmwasm_1_4")]
1733    #[test]
1734    fn distribution_querier_delegation_rewards() {
1735        use crate::{Decimal256, DelegationTotalRewardsResponse, DelegatorReward};
1736
1737        let mut distribution = DistributionQuerier::default();
1738        let valoper0_rewards = vec![
1739            DecCoin::new(Decimal256::from_atomics(1234u128, 0).unwrap(), "uatom"),
1740            DecCoin::new(Decimal256::from_atomics(56781234u128, 4).unwrap(), "utest"),
1741        ];
1742        distribution.set_rewards("valoper0", "addr0", valoper0_rewards.clone());
1743
1744        // both exist / are set
1745        let query = DistributionQuery::DelegationRewards {
1746            delegator_address: "addr0".to_string(),
1747            validator_address: "valoper0".to_string(),
1748        };
1749        let res = distribution.query(&query).unwrap().unwrap();
1750        let res: DelegationRewardsResponse = from_json(res).unwrap();
1751        assert_eq!(res.rewards, valoper0_rewards);
1752
1753        // delegator does not exist
1754        let query = DistributionQuery::DelegationRewards {
1755            delegator_address: "nonexistent".to_string(),
1756            validator_address: "valoper0".to_string(),
1757        };
1758        let res = distribution.query(&query).unwrap().unwrap();
1759        let res: DelegationRewardsResponse = from_json(res).unwrap();
1760        assert_eq!(res.rewards.len(), 0);
1761
1762        // validator does not exist
1763        let query = DistributionQuery::DelegationRewards {
1764            delegator_address: "addr0".to_string(),
1765            validator_address: "valopernonexistent".to_string(),
1766        };
1767        let res = distribution.query(&query).unwrap().unwrap();
1768        let res: DelegationRewardsResponse = from_json(res).unwrap();
1769        assert_eq!(res.rewards.len(), 0);
1770
1771        // add one more validator
1772        let valoper1_rewards = vec![DecCoin::new(Decimal256::one(), "uatom")];
1773        distribution.set_rewards("valoper1", "addr0", valoper1_rewards.clone());
1774
1775        // total rewards
1776        let query = DistributionQuery::DelegationTotalRewards {
1777            delegator_address: "addr0".to_string(),
1778        };
1779        let res = distribution.query(&query).unwrap().unwrap();
1780        let res: DelegationTotalRewardsResponse = from_json(res).unwrap();
1781        assert_eq!(
1782            res.rewards,
1783            vec![
1784                DelegatorReward {
1785                    validator_address: "valoper0".into(),
1786                    reward: valoper0_rewards
1787                },
1788                DelegatorReward {
1789                    validator_address: "valoper1".into(),
1790                    reward: valoper1_rewards
1791                },
1792            ]
1793        );
1794        assert_eq!(
1795            res.total,
1796            [
1797                DecCoin::new(
1798                    Decimal256::from_atomics(1234u128, 0).unwrap() + Decimal256::one(),
1799                    "uatom"
1800                ),
1801                // total for utest should still be the same
1802                DecCoin::new(Decimal256::from_atomics(56781234u128, 4).unwrap(), "utest")
1803            ]
1804        );
1805    }
1806
1807    #[cfg(feature = "stargate")]
1808    #[test]
1809    fn ibc_querier_channel_existing() {
1810        let chan1 = mock_ibc_channel("channel-0", IbcOrder::Ordered, "ibc");
1811        let chan2 = mock_ibc_channel("channel-1", IbcOrder::Ordered, "ibc");
1812
1813        let ibc = IbcQuerier::new("myport", &[chan1.clone(), chan2]);
1814
1815        // query existing
1816        let query = &IbcQuery::Channel {
1817            channel_id: "channel-0".to_string(),
1818            port_id: Some("my_port".to_string()),
1819        };
1820        let raw = ibc.query(query).unwrap().unwrap();
1821        let chan: ChannelResponse = from_json(raw).unwrap();
1822        assert_eq!(chan.channel, Some(chan1));
1823    }
1824
1825    #[cfg(feature = "stargate")]
1826    #[test]
1827    fn ibc_querier_channel_existing_no_port() {
1828        let chan1 = IbcChannel {
1829            endpoint: IbcEndpoint {
1830                port_id: "myport".to_string(),
1831                channel_id: "channel-0".to_string(),
1832            },
1833            counterparty_endpoint: IbcEndpoint {
1834                port_id: "their_port".to_string(),
1835                channel_id: "channel-7".to_string(),
1836            },
1837            order: IbcOrder::Ordered,
1838            version: "ibc".to_string(),
1839            connection_id: "connection-2".to_string(),
1840        };
1841        let chan2 = mock_ibc_channel("channel-1", IbcOrder::Ordered, "ibc");
1842
1843        let ibc = IbcQuerier::new("myport", &[chan1.clone(), chan2]);
1844
1845        // query existing
1846        let query = &IbcQuery::Channel {
1847            channel_id: "channel-0".to_string(),
1848            port_id: Some("myport".to_string()),
1849        };
1850        let raw = ibc.query(query).unwrap().unwrap();
1851        let chan: ChannelResponse = from_json(raw).unwrap();
1852        assert_eq!(chan.channel, Some(chan1));
1853    }
1854
1855    #[cfg(feature = "stargate")]
1856    #[test]
1857    fn ibc_querier_channel_none() {
1858        let chan1 = mock_ibc_channel("channel-0", IbcOrder::Ordered, "ibc");
1859        let chan2 = mock_ibc_channel("channel-1", IbcOrder::Ordered, "ibc");
1860
1861        let ibc = IbcQuerier::new("myport", &[chan1, chan2]);
1862
1863        // query non-existing
1864        let query = &IbcQuery::Channel {
1865            channel_id: "channel-0".to_string(),
1866            port_id: None,
1867        };
1868        let raw = ibc.query(query).unwrap().unwrap();
1869        let chan: ChannelResponse = from_json(raw).unwrap();
1870        assert_eq!(chan.channel, None);
1871    }
1872
1873    #[cfg(feature = "stargate")]
1874    #[test]
1875    fn ibc_querier_channels_matching() {
1876        let chan1 = mock_ibc_channel("channel-0", IbcOrder::Ordered, "ibc");
1877        let chan2 = mock_ibc_channel("channel-1", IbcOrder::Ordered, "ibc");
1878
1879        let ibc = IbcQuerier::new("myport", &[chan1.clone(), chan2.clone()]);
1880
1881        // query channels matching "my_port" (should match both above)
1882        let query = &IbcQuery::ListChannels {
1883            port_id: Some("my_port".to_string()),
1884        };
1885        let raw = ibc.query(query).unwrap().unwrap();
1886        let res: ListChannelsResponse = from_json(raw).unwrap();
1887        assert_eq!(res.channels, vec![chan1, chan2]);
1888    }
1889
1890    #[cfg(feature = "stargate")]
1891    #[test]
1892    fn ibc_querier_channels_no_matching() {
1893        let chan1 = mock_ibc_channel("channel-0", IbcOrder::Ordered, "ibc");
1894        let chan2 = mock_ibc_channel("channel-1", IbcOrder::Ordered, "ibc");
1895
1896        let ibc = IbcQuerier::new("myport", &[chan1, chan2]);
1897
1898        // query channels matching "myport" (should be none)
1899        let query = &IbcQuery::ListChannels { port_id: None };
1900        let raw = ibc.query(query).unwrap().unwrap();
1901        let res: ListChannelsResponse = from_json(raw).unwrap();
1902        assert_eq!(res.channels, vec![]);
1903    }
1904
1905    #[cfg(feature = "stargate")]
1906    #[test]
1907    fn ibc_querier_port() {
1908        let chan1 = mock_ibc_channel("channel-0", IbcOrder::Ordered, "ibc");
1909
1910        let ibc = IbcQuerier::new("myport", &[chan1]);
1911
1912        // query channels matching "myport" (should be none)
1913        let query = &IbcQuery::PortId {};
1914        let raw = ibc.query(query).unwrap().unwrap();
1915        let res: PortIdResponse = from_json(raw).unwrap();
1916        assert_eq!(res.port_id, "myport");
1917    }
1918
1919    #[cfg(feature = "staking")]
1920    #[test]
1921    fn staking_querier_all_validators() {
1922        let val1 = Validator {
1923            address: String::from("validator-one"),
1924            commission: Decimal::percent(1),
1925            max_commission: Decimal::percent(3),
1926            max_change_rate: Decimal::percent(1),
1927        };
1928        let val2 = Validator {
1929            address: String::from("validator-two"),
1930            commission: Decimal::permille(15),
1931            max_commission: Decimal::permille(40),
1932            max_change_rate: Decimal::permille(5),
1933        };
1934
1935        let staking = StakingQuerier::new("ustake", &[val1.clone(), val2.clone()], &[]);
1936
1937        // one match
1938        let raw = staking
1939            .query(&StakingQuery::AllValidators {})
1940            .unwrap()
1941            .unwrap();
1942        let vals: AllValidatorsResponse = from_json(raw).unwrap();
1943        assert_eq!(vals.validators, vec![val1, val2]);
1944    }
1945
1946    #[cfg(feature = "staking")]
1947    #[test]
1948    fn staking_querier_validator() {
1949        let address1 = String::from("validator-one");
1950        let address2 = String::from("validator-two");
1951        let address_non_existent = String::from("wannabe-validator");
1952
1953        let val1 = Validator {
1954            address: address1.clone(),
1955            commission: Decimal::percent(1),
1956            max_commission: Decimal::percent(3),
1957            max_change_rate: Decimal::percent(1),
1958        };
1959        let val2 = Validator {
1960            address: address2.clone(),
1961            commission: Decimal::permille(15),
1962            max_commission: Decimal::permille(40),
1963            max_change_rate: Decimal::permille(5),
1964        };
1965
1966        let staking = StakingQuerier::new("ustake", &[val1.clone(), val2.clone()], &[]);
1967
1968        // query 1
1969        let raw = staking
1970            .query(&StakingQuery::Validator { address: address1 })
1971            .unwrap()
1972            .unwrap();
1973        let res: ValidatorResponse = from_json(raw).unwrap();
1974        assert_eq!(res.validator, Some(val1));
1975
1976        // query 2
1977        let raw = staking
1978            .query(&StakingQuery::Validator { address: address2 })
1979            .unwrap()
1980            .unwrap();
1981        let res: ValidatorResponse = from_json(raw).unwrap();
1982        assert_eq!(res.validator, Some(val2));
1983
1984        // query non-existent
1985        let raw = staking
1986            .query(&StakingQuery::Validator {
1987                address: address_non_existent,
1988            })
1989            .unwrap()
1990            .unwrap();
1991        let res: ValidatorResponse = from_json(raw).unwrap();
1992        assert_eq!(res.validator, None);
1993    }
1994
1995    #[cfg(feature = "staking")]
1996    // gets delegators from query or panic
1997    fn get_all_delegators(
1998        staking: &StakingQuerier,
1999        delegator: impl Into<String>,
2000    ) -> Vec<Delegation> {
2001        let raw = staking
2002            .query(&StakingQuery::AllDelegations {
2003                delegator: delegator.into(),
2004            })
2005            .unwrap()
2006            .unwrap();
2007        let dels: AllDelegationsResponse = from_json(raw).unwrap();
2008        dels.delegations
2009    }
2010
2011    #[cfg(feature = "staking")]
2012    // gets full delegators from query or panic
2013    fn get_delegator(
2014        staking: &StakingQuerier,
2015        delegator: impl Into<String>,
2016        validator: impl Into<String>,
2017    ) -> Option<FullDelegation> {
2018        let raw = staking
2019            .query(&StakingQuery::Delegation {
2020                delegator: delegator.into(),
2021                validator: validator.into(),
2022            })
2023            .unwrap()
2024            .unwrap();
2025        let dels: DelegationResponse = from_json(raw).unwrap();
2026        dels.delegation
2027    }
2028
2029    #[cfg(feature = "staking")]
2030    #[test]
2031    fn staking_querier_delegations() {
2032        let val1 = String::from("validator-one");
2033        let val2 = String::from("validator-two");
2034
2035        let user_a = Addr::unchecked("investor");
2036        let user_b = Addr::unchecked("speculator");
2037        let user_c = Addr::unchecked("hodler");
2038
2039        // we need multiple validators per delegator, so the queries provide different results
2040        let del1a = FullDelegation {
2041            delegator: user_a.clone(),
2042            validator: val1.clone(),
2043            amount: coin(100, "ustake"),
2044            can_redelegate: coin(100, "ustake"),
2045            accumulated_rewards: coins(5, "ustake"),
2046        };
2047        let del2a = FullDelegation {
2048            delegator: user_a.clone(),
2049            validator: val2.clone(),
2050            amount: coin(500, "ustake"),
2051            can_redelegate: coin(500, "ustake"),
2052            accumulated_rewards: coins(20, "ustake"),
2053        };
2054
2055        // note we cannot have multiple delegations on one validator, they are collapsed into one
2056        let del1b = FullDelegation {
2057            delegator: user_b.clone(),
2058            validator: val1.clone(),
2059            amount: coin(500, "ustake"),
2060            can_redelegate: coin(0, "ustake"),
2061            accumulated_rewards: coins(0, "ustake"),
2062        };
2063
2064        // and another one on val2
2065        let del2c = FullDelegation {
2066            delegator: user_c.clone(),
2067            validator: val2.clone(),
2068            amount: coin(8888, "ustake"),
2069            can_redelegate: coin(4567, "ustake"),
2070            accumulated_rewards: coins(900, "ustake"),
2071        };
2072
2073        let staking = StakingQuerier::new(
2074            "ustake",
2075            &[],
2076            &[del1a.clone(), del1b.clone(), del2a.clone(), del2c.clone()],
2077        );
2078
2079        // get all for user a
2080        let dels = get_all_delegators(&staking, user_a.clone());
2081        assert_eq!(dels, vec![del1a.clone().into(), del2a.clone().into()]);
2082
2083        // get all for user b
2084        let dels = get_all_delegators(&staking, user_b.clone());
2085        assert_eq!(dels, vec![del1b.clone().into()]);
2086
2087        // get all for user c
2088        let dels = get_all_delegators(&staking, user_c.clone());
2089        assert_eq!(dels, vec![del2c.clone().into()]);
2090
2091        // for user with no delegations...
2092        let dels = get_all_delegators(&staking, String::from("no one"));
2093        assert_eq!(dels, vec![]);
2094
2095        // filter a by validator (1 and 1)
2096        let dels = get_delegator(&staking, user_a.clone(), val1.clone());
2097        assert_eq!(dels, Some(del1a));
2098        let dels = get_delegator(&staking, user_a, val2.clone());
2099        assert_eq!(dels, Some(del2a));
2100
2101        // filter b by validator (2 and 0)
2102        let dels = get_delegator(&staking, user_b.clone(), val1.clone());
2103        assert_eq!(dels, Some(del1b));
2104        let dels = get_delegator(&staking, user_b, val2.clone());
2105        assert_eq!(dels, None);
2106
2107        // filter c by validator (0 and 1)
2108        let dels = get_delegator(&staking, user_c.clone(), val1);
2109        assert_eq!(dels, None);
2110        let dels = get_delegator(&staking, user_c, val2);
2111        assert_eq!(dels, Some(del2c));
2112    }
2113
2114    #[test]
2115    fn wasm_querier_works() {
2116        let mut querier = WasmQuerier::default();
2117
2118        let any_addr = "foo".to_string();
2119
2120        // By default, querier errors for WasmQuery::Raw
2121        let system_err = querier
2122            .query(&WasmQuery::Raw {
2123                contract_addr: any_addr.clone(),
2124                key: b"the key".into(),
2125            })
2126            .unwrap_err();
2127        match system_err {
2128            SystemError::NoSuchContract { addr } => assert_eq!(addr, any_addr),
2129            err => panic!("Unexpected error: {err:?}"),
2130        }
2131
2132        // By default, querier errors for WasmQuery::Smart
2133        let system_err = querier
2134            .query(&WasmQuery::Smart {
2135                contract_addr: any_addr.clone(),
2136                msg: b"{}".into(),
2137            })
2138            .unwrap_err();
2139        match system_err {
2140            SystemError::NoSuchContract { addr } => assert_eq!(addr, any_addr),
2141            err => panic!("Unexpected error: {err:?}"),
2142        }
2143
2144        // By default, querier errors for WasmQuery::ContractInfo
2145        let system_err = querier
2146            .query(&WasmQuery::ContractInfo {
2147                contract_addr: any_addr.clone(),
2148            })
2149            .unwrap_err();
2150        match system_err {
2151            SystemError::NoSuchContract { addr } => assert_eq!(addr, any_addr),
2152            err => panic!("Unexpected error: {err:?}"),
2153        }
2154
2155        #[cfg(feature = "cosmwasm_1_2")]
2156        {
2157            // By default, querier errors for WasmQuery::CodeInfo
2158            let system_err = querier
2159                .query(&WasmQuery::CodeInfo { code_id: 4 })
2160                .unwrap_err();
2161            match system_err {
2162                SystemError::NoSuchCode { code_id } => assert_eq!(code_id, 4),
2163                err => panic!("Unexpected error: {err:?}"),
2164            }
2165        }
2166
2167        querier.update_handler(|request| {
2168            let constract1 = Addr::unchecked("contract1");
2169            let mut storage1 = HashMap::<Binary, Binary>::default();
2170            storage1.insert(b"the key".into(), b"the value".into());
2171
2172            match request {
2173                WasmQuery::Raw { contract_addr, key } => {
2174                    if *contract_addr == constract1 {
2175                        if let Some(value) = storage1.get(key) {
2176                            SystemResult::Ok(ContractResult::Ok(value.clone()))
2177                        } else {
2178                            SystemResult::Ok(ContractResult::Ok(Binary::default()))
2179                        }
2180                    } else {
2181                        SystemResult::Err(SystemError::NoSuchContract {
2182                            addr: contract_addr.clone(),
2183                        })
2184                    }
2185                }
2186                WasmQuery::Smart { contract_addr, msg } => {
2187                    if *contract_addr == constract1 {
2188                        #[derive(Deserialize)]
2189                        struct MyMsg {}
2190                        let _msg: MyMsg = match from_json(msg) {
2191                            Ok(msg) => msg,
2192                            Err(err) => {
2193                                return SystemResult::Ok(ContractResult::Err(err.to_string()))
2194                            }
2195                        };
2196                        let response: Response = Response::new().set_data(b"good");
2197                        SystemResult::Ok(ContractResult::Ok(to_json_binary(&response).unwrap()))
2198                    } else {
2199                        SystemResult::Err(SystemError::NoSuchContract {
2200                            addr: contract_addr.clone(),
2201                        })
2202                    }
2203                }
2204                WasmQuery::ContractInfo { contract_addr } => {
2205                    if *contract_addr == constract1 {
2206                        let response = ContractInfoResponse {
2207                            code_id: 4,
2208                            creator: "lalala".into(),
2209                            admin: None,
2210                            pinned: false,
2211                            ibc_port: None,
2212                        };
2213                        SystemResult::Ok(ContractResult::Ok(to_json_binary(&response).unwrap()))
2214                    } else {
2215                        SystemResult::Err(SystemError::NoSuchContract {
2216                            addr: contract_addr.clone(),
2217                        })
2218                    }
2219                }
2220                #[cfg(feature = "cosmwasm_1_2")]
2221                WasmQuery::CodeInfo { code_id } => {
2222                    use crate::{CodeInfoResponse, HexBinary};
2223                    let code_id = *code_id;
2224                    if code_id == 4 {
2225                        let response = CodeInfoResponse {
2226                            code_id,
2227                            creator: "lalala".into(),
2228                            checksum: HexBinary::from_hex(
2229                                "84cf20810fd429caf58898c3210fcb71759a27becddae08dbde8668ea2f4725d",
2230                            )
2231                            .unwrap(),
2232                        };
2233                        SystemResult::Ok(ContractResult::Ok(to_json_binary(&response).unwrap()))
2234                    } else {
2235                        SystemResult::Err(SystemError::NoSuchCode { code_id })
2236                    }
2237                }
2238            }
2239        });
2240
2241        // WasmQuery::Raw
2242        let result = querier.query(&WasmQuery::Raw {
2243            contract_addr: "contract1".into(),
2244            key: b"the key".into(),
2245        });
2246        match result {
2247            SystemResult::Ok(ContractResult::Ok(value)) => assert_eq!(value, b"the value" as &[u8]),
2248            res => panic!("Unexpected result: {res:?}"),
2249        }
2250        let result = querier.query(&WasmQuery::Raw {
2251            contract_addr: "contract1".into(),
2252            key: b"other key".into(),
2253        });
2254        match result {
2255            SystemResult::Ok(ContractResult::Ok(value)) => assert_eq!(value, b"" as &[u8]),
2256            res => panic!("Unexpected result: {res:?}"),
2257        }
2258
2259        // WasmQuery::Smart
2260        let result = querier.query(&WasmQuery::Smart {
2261            contract_addr: "contract1".into(),
2262            msg: b"{}".into(),
2263        });
2264        match result {
2265            SystemResult::Ok(ContractResult::Ok(value)) => assert_eq!(
2266                value,
2267                br#"{"messages":[],"attributes":[],"events":[],"data":"Z29vZA=="}"# as &[u8]
2268            ),
2269            res => panic!("Unexpected result: {res:?}"),
2270        }
2271        let result = querier.query(&WasmQuery::Smart {
2272            contract_addr: "contract1".into(),
2273            msg: b"a broken request".into(),
2274        });
2275        match result {
2276            SystemResult::Ok(ContractResult::Err(err)) => {
2277                assert_eq!(err, "Error parsing into type cosmwasm_std::testing::mock::tests::wasm_querier_works::{{closure}}::MyMsg: Invalid type")
2278            }
2279            res => panic!("Unexpected result: {res:?}"),
2280        }
2281
2282        // WasmQuery::ContractInfo
2283        let result = querier.query(&WasmQuery::ContractInfo {
2284            contract_addr: "contract1".into(),
2285        });
2286        match result {
2287            SystemResult::Ok(ContractResult::Ok(value)) => assert_eq!(
2288                value,
2289                br#"{"code_id":4,"creator":"lalala","admin":null,"pinned":false,"ibc_port":null}"#
2290                    as &[u8]
2291            ),
2292            res => panic!("Unexpected result: {res:?}"),
2293        }
2294
2295        // WasmQuery::ContractInfo
2296        #[cfg(feature = "cosmwasm_1_2")]
2297        {
2298            let result = querier.query(&WasmQuery::CodeInfo { code_id: 4 });
2299            match result {
2300                SystemResult::Ok(ContractResult::Ok(value)) => assert_eq!(
2301                    value,
2302                    br#"{"code_id":4,"creator":"lalala","checksum":"84cf20810fd429caf58898c3210fcb71759a27becddae08dbde8668ea2f4725d"}"#
2303                ),
2304                res => panic!("Unexpected result: {res:?}"),
2305            }
2306        }
2307    }
2308
2309    #[test]
2310    fn digit_sum_works() {
2311        assert_eq!(digit_sum(&[]), 0);
2312        assert_eq!(digit_sum(&[0]), 0);
2313        assert_eq!(digit_sum(&[0, 0]), 0);
2314        assert_eq!(digit_sum(&[0, 0, 0]), 0);
2315
2316        assert_eq!(digit_sum(&[1, 0, 0]), 1);
2317        assert_eq!(digit_sum(&[0, 1, 0]), 1);
2318        assert_eq!(digit_sum(&[0, 0, 1]), 1);
2319
2320        assert_eq!(digit_sum(&[1, 2, 3]), 6);
2321
2322        assert_eq!(digit_sum(&[255, 1]), 256);
2323    }
2324
2325    #[test]
2326    fn making_an_address_works() {
2327        let mock_api = MockApi::default();
2328
2329        assert_eq!(
2330            mock_api.addr_make("creator").to_string(),
2331            "cosmwasm1h34lmpywh4upnjdg90cjf4j70aee6z8qqfspugamjp42e4q28kqs8s7vcp",
2332        );
2333
2334        assert_eq!(
2335            mock_api.addr_make("").to_string(),
2336            "cosmwasm1uwcvgs5clswpfxhm7nyfjmaeysn6us0yvjdexn9yjkv3k7zjhp2sly4xh9",
2337        );
2338
2339        let mock_api = MockApi::default().with_prefix("juno");
2340        assert_eq!(
2341            mock_api.addr_make("creator").to_string(),
2342            "juno1h34lmpywh4upnjdg90cjf4j70aee6z8qqfspugamjp42e4q28kqsksmtyp",
2343        );
2344    }
2345
2346    #[test]
2347    #[should_panic(expected = "Generating address failed with reason: invalid length")]
2348    fn making_an_address_with_empty_prefix_should_panic() {
2349        MockApi::default().with_prefix("").addr_make("creator");
2350    }
2351}