cosmwasm_std/testing/
mock.rs

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