cw_multi_test/
api.rs

1use bech32::primitives::decode::CheckedHrpstring;
2use bech32::{encode, Bech32, Bech32m, Hrp};
3use cosmwasm_std::testing::MockApi;
4use cosmwasm_std::{
5    Addr, Api, CanonicalAddr, HashFunction, RecoverPubkeyError, StdError, StdResult,
6    VerificationError,
7};
8use sha2::{Digest, Sha256};
9
10pub struct MockApiBech<T> {
11    api: MockApi,
12    prefix: &'static str,
13    _phantom_data: std::marker::PhantomData<T>,
14}
15
16impl<T: bech32::Checksum> MockApiBech<T> {
17    /// Returns `Api` implementation that uses specified prefix
18    /// to generate addresses in `Bech32` or `Bech32m` format.
19    pub fn new(prefix: &'static str) -> Self {
20        Self {
21            api: MockApi::default(),
22            prefix,
23            _phantom_data: std::marker::PhantomData,
24        }
25    }
26}
27
28impl<T: bech32::Checksum + 'static> Api for MockApiBech<T> {
29    fn addr_validate(&self, input: &str) -> StdResult<Addr> {
30        self.addr_humanize(&self.addr_canonicalize(input)?)
31    }
32
33    fn addr_canonicalize(&self, input: &str) -> StdResult<CanonicalAddr> {
34        if let Ok(s) = CheckedHrpstring::new::<T>(input) {
35            if s.hrp().to_string() == self.prefix {
36                return Ok(s.byte_iter().collect::<Vec<u8>>().into());
37            }
38        }
39        Err(StdError::msg("Invalid input"))
40    }
41
42    fn addr_humanize(&self, canonical: &CanonicalAddr) -> StdResult<Addr> {
43        let hrp = Hrp::parse(self.prefix)?;
44        if let Ok(encoded) = encode::<T>(hrp, canonical.as_slice()) {
45            Ok(Addr::unchecked(encoded))
46        } else {
47            Err(StdError::msg("Invalid canonical address"))
48        }
49    }
50
51    fn secp256k1_verify(
52        &self,
53        message_hash: &[u8],
54        signature: &[u8],
55        public_key: &[u8],
56    ) -> Result<bool, VerificationError> {
57        self.api
58            .secp256k1_verify(message_hash, signature, public_key)
59    }
60
61    fn secp256k1_recover_pubkey(
62        &self,
63        message_hash: &[u8],
64        signature: &[u8],
65        recovery_param: u8,
66    ) -> Result<Vec<u8>, RecoverPubkeyError> {
67        self.api
68            .secp256k1_recover_pubkey(message_hash, signature, recovery_param)
69    }
70
71    fn bls12_381_aggregate_g1(&self, g1s: &[u8]) -> Result<[u8; 48], VerificationError> {
72        self.api.bls12_381_aggregate_g1(g1s)
73    }
74
75    fn bls12_381_aggregate_g2(&self, g2s: &[u8]) -> Result<[u8; 96], VerificationError> {
76        self.api.bls12_381_aggregate_g2(g2s)
77    }
78
79    fn bls12_381_pairing_equality(
80        &self,
81        ps: &[u8],
82        qs: &[u8],
83        r: &[u8],
84        s: &[u8],
85    ) -> Result<bool, VerificationError> {
86        self.api.bls12_381_pairing_equality(ps, qs, r, s)
87    }
88
89    fn bls12_381_hash_to_g1(
90        &self,
91        hash_function: HashFunction,
92        msg: &[u8],
93        dst: &[u8],
94    ) -> Result<[u8; 48], VerificationError> {
95        self.api.bls12_381_hash_to_g1(hash_function, msg, dst)
96    }
97
98    fn bls12_381_hash_to_g2(
99        &self,
100        hash_function: HashFunction,
101        msg: &[u8],
102        dst: &[u8],
103    ) -> Result<[u8; 96], VerificationError> {
104        self.api.bls12_381_hash_to_g2(hash_function, msg, dst)
105    }
106
107    fn secp256r1_verify(
108        &self,
109        message_hash: &[u8],
110        signature: &[u8],
111        public_key: &[u8],
112    ) -> Result<bool, VerificationError> {
113        self.api
114            .secp256r1_verify(message_hash, signature, public_key)
115    }
116
117    fn secp256r1_recover_pubkey(
118        &self,
119        message_hash: &[u8],
120        signature: &[u8],
121        recovery_param: u8,
122    ) -> Result<Vec<u8>, RecoverPubkeyError> {
123        self.api
124            .secp256r1_recover_pubkey(message_hash, signature, recovery_param)
125    }
126
127    fn ed25519_verify(
128        &self,
129        message: &[u8],
130        signature: &[u8],
131        public_key: &[u8],
132    ) -> Result<bool, VerificationError> {
133        self.api.ed25519_verify(message, signature, public_key)
134    }
135
136    fn ed25519_batch_verify(
137        &self,
138        messages: &[&[u8]],
139        signatures: &[&[u8]],
140        public_keys: &[&[u8]],
141    ) -> Result<bool, VerificationError> {
142        self.api
143            .ed25519_batch_verify(messages, signatures, public_keys)
144    }
145
146    fn debug(&self, message: &str) {
147        self.api.debug(message)
148    }
149}
150
151impl<T: bech32::Checksum> MockApiBech<T> {
152    /// Returns an address in `Bech32` or `Bech32m` format, built from provided input string.
153    ///
154    /// # Panics
155    ///
156    /// This function panics when generating a valid address in `Bech32` or `Bech32m`
157    /// format is not possible, especially when the prefix is too long or empty.
158    pub fn addr_make(&self, input: &str) -> Addr {
159        match Hrp::parse(self.prefix) {
160            Ok(hrp) => Addr::unchecked(encode::<T>(hrp, Sha256::digest(input).as_slice()).unwrap()),
161            Err(reason) => panic!("Generating address failed with reason: {reason}"),
162        }
163    }
164}
165
166/// Implementation of the `cosmwasm_std::Api` trait that uses [Bech32] format
167/// for humanizing canonical addresses.
168///
169/// [Bech32]: https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki
170pub type MockApiBech32 = MockApiBech<Bech32>;
171
172/// Implementation of the `cosmwasm_std::Api` trait that uses [Bech32m] format
173/// for humanizing canonical addresses.
174///
175/// [Bech32m]: https://github.com/bitcoin/bips/blob/master/bip-0350.mediawiki
176pub type MockApiBech32m = MockApiBech<Bech32m>;