cosmwasm_std/
addresses.rs

1use alloc::{borrow::Cow, string::String, vec::Vec};
2use core::fmt;
3use core::ops::Deref;
4use serde::{Deserialize, Serialize};
5use sha2::{
6    digest::{Digest, Update},
7    Sha256,
8};
9
10use crate::Binary;
11use crate::{HexBinary, __internal::forward_ref_partial_eq};
12
13/// A human readable address.
14///
15/// In Cosmos, this is typically bech32 encoded. But for multi-chain smart contracts no
16/// assumptions should be made other than being UTF-8 encoded and of reasonable length.
17///
18/// This type represents a validated address. It can be created in the following ways
19/// 1. Use `Addr::unchecked(input)`
20/// 2. Use `let checked: Addr = deps.api.addr_validate(input)?`
21/// 3. Use `let checked: Addr = deps.api.addr_humanize(canonical_addr)?`
22/// 4. Deserialize from JSON. This must only be done from JSON that was validated before
23///    such as a contract's state. `Addr` must not be used in messages sent by the user
24///    because this would result in unvalidated instances.
25///
26/// This type is immutable. If you really need to mutate it (Really? Are you sure?), create
27/// a mutable copy using `let mut mutable = Addr::to_string()` and operate on that `String`
28/// instance.
29#[derive(
30    Serialize, Deserialize, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, schemars::JsonSchema,
31)]
32pub struct Addr(String);
33
34forward_ref_partial_eq!(Addr, Addr);
35
36impl Addr {
37    /// Creates a new `Addr` instance from the given input without checking the validity
38    /// of the input. Since `Addr` must always contain valid addresses, the caller is
39    /// responsible for ensuring the input is valid.
40    ///
41    /// Use this in cases where the address was validated before or in test code.
42    /// If you see this in contract code, it should most likely be replaced with
43    /// `let checked: Addr = deps.api.addr_humanize(canonical_addr)?`.
44    ///
45    /// ## Examples
46    ///
47    /// ```
48    /// # use cosmwasm_std::{Addr};
49    /// let address = Addr::unchecked("foobar");
50    /// assert_eq!(address.as_str(), "foobar");
51    /// ```
52    pub fn unchecked(input: impl Into<String>) -> Addr {
53        Addr(input.into())
54    }
55
56    #[inline]
57    pub fn as_str(&self) -> &str {
58        self.0.as_str()
59    }
60
61    /// Returns the UTF-8 encoded address string as a byte array.
62    ///
63    /// This is equivalent to `address.as_str().as_bytes()`.
64    #[inline]
65    pub fn as_bytes(&self) -> &[u8] {
66        self.0.as_bytes()
67    }
68
69    /// Utility for explicit conversion to `String`.
70    #[inline]
71    pub fn into_string(self) -> String {
72        self.0
73    }
74}
75
76impl fmt::Display for Addr {
77    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
78        write!(f, "{}", &self.0)
79    }
80}
81
82impl AsRef<str> for Addr {
83    #[inline]
84    fn as_ref(&self) -> &str {
85        self.as_str()
86    }
87}
88
89// Addr->String is a safe conversion.
90// However, the opposite direction is unsafe and must not be implemented.
91
92impl From<Addr> for String {
93    fn from(addr: Addr) -> Self {
94        addr.0
95    }
96}
97
98impl From<&Addr> for String {
99    fn from(addr: &Addr) -> Self {
100        addr.0.clone()
101    }
102}
103
104impl From<Addr> for Cow<'_, Addr> {
105    fn from(addr: Addr) -> Self {
106        Cow::Owned(addr)
107    }
108}
109
110impl<'a> From<&'a Addr> for Cow<'a, Addr> {
111    fn from(addr: &'a Addr) -> Self {
112        Cow::Borrowed(addr)
113    }
114}
115
116/// A blockchain address in its binary form.
117///
118/// The specific implementation is up to the underlying chain and CosmWasm as well as
119/// contracts should not make assumptions on that data. In Ethereum for example, an
120/// `Addr` would contain a user visible address like 0x14d3cc818735723ab86eaf9502376e847a64ddad
121/// and the corresponding `CanonicalAddr` would store the 20 bytes 0x14, 0xD3, ..., 0xAD.
122/// In Cosmos, the bech32 format is used for `Addr`s and the `CanonicalAddr` holds the
123/// encoded bech32 data without the checksum. Typical sizes are 20 bytes for externally
124/// owned addresses and 32 bytes for module addresses (such as x/wasm contract addresses).
125/// That being said, a chain might decide to use any size other than 20 or 32 bytes.
126///
127/// The safe way to obtain a valid `CanonicalAddr` is using `Api::addr_canonicalize`. In
128/// addition to that there are many unsafe ways to convert any binary data into an instance.
129/// So the type should be treated as a marker to express the intended data type, not as
130/// a validity guarantee of any sort.
131#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, Hash, schemars::JsonSchema)]
132pub struct CanonicalAddr(Binary);
133
134/// Implement `CanonicalAddr == Binary`
135impl PartialEq<Binary> for CanonicalAddr {
136    fn eq(&self, rhs: &Binary) -> bool {
137        &self.0 == rhs
138    }
139}
140
141/// Implement `Binary == CanonicalAddr`
142impl PartialEq<CanonicalAddr> for Binary {
143    fn eq(&self, rhs: &CanonicalAddr) -> bool {
144        self == &rhs.0
145    }
146}
147
148/// Implement `CanonicalAddr == HexBinary`
149impl PartialEq<HexBinary> for CanonicalAddr {
150    fn eq(&self, rhs: &HexBinary) -> bool {
151        self.as_slice() == rhs.as_slice()
152    }
153}
154
155/// Implement `HexBinary == CanonicalAddr`
156impl PartialEq<CanonicalAddr> for HexBinary {
157    fn eq(&self, rhs: &CanonicalAddr) -> bool {
158        self.as_slice() == rhs.0.as_slice()
159    }
160}
161
162impl From<&[u8]> for CanonicalAddr {
163    fn from(source: &[u8]) -> Self {
164        Self(source.into())
165    }
166}
167
168// Array reference
169impl<const LENGTH: usize> From<&[u8; LENGTH]> for CanonicalAddr {
170    fn from(source: &[u8; LENGTH]) -> Self {
171        Self(source.into())
172    }
173}
174
175// Owned array
176impl<const LENGTH: usize> From<[u8; LENGTH]> for CanonicalAddr {
177    fn from(source: [u8; LENGTH]) -> Self {
178        Self(source.into())
179    }
180}
181
182// Owned vector -> CanonicalAddr
183impl From<Vec<u8>> for CanonicalAddr {
184    fn from(source: Vec<u8>) -> Self {
185        Self(source.into())
186    }
187}
188
189// CanonicalAddr -> Owned vector
190impl From<CanonicalAddr> for Vec<u8> {
191    fn from(source: CanonicalAddr) -> Vec<u8> {
192        source.0.into()
193    }
194}
195
196// Owned Binary -> CanonicalAddr
197impl From<Binary> for CanonicalAddr {
198    fn from(source: Binary) -> Self {
199        Self(source)
200    }
201}
202
203// CanonicalAddr -> Owned Binary
204impl From<CanonicalAddr> for Binary {
205    fn from(source: CanonicalAddr) -> Binary {
206        source.0
207    }
208}
209
210// Owned HexBinary -> CanonicalAddr
211impl From<HexBinary> for CanonicalAddr {
212    fn from(source: HexBinary) -> Self {
213        Self(source.into())
214    }
215}
216
217// CanonicalAddr -> Owned HexBinary
218impl From<CanonicalAddr> for HexBinary {
219    fn from(source: CanonicalAddr) -> HexBinary {
220        source.0.into()
221    }
222}
223
224/// Just like Vec<u8>, CanonicalAddr is a smart pointer to [u8].
225/// This implements `*canonical_address` for us and allows us to
226/// do `&*canonical_address`, returning a `&[u8]` from a `&CanonicalAddr`.
227/// With [deref coercions](https://doc.rust-lang.org/1.22.1/book/first-edition/deref-coercions.html#deref-coercions),
228/// this allows us to use `&canonical_address` whenever a `&[u8]` is required.
229impl Deref for CanonicalAddr {
230    type Target = [u8];
231
232    fn deref(&self) -> &Self::Target {
233        self.as_slice()
234    }
235}
236
237impl CanonicalAddr {
238    pub fn as_slice(&self) -> &[u8] {
239        self.0.as_slice()
240    }
241}
242
243impl fmt::Display for CanonicalAddr {
244    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
245        for byte in self.0.as_slice() {
246            write!(f, "{byte:02X}")?;
247        }
248        Ok(())
249    }
250}
251
252#[derive(Debug, PartialEq, Eq, thiserror::Error)]
253pub enum Instantiate2AddressError {
254    /// Checksum must be 32 bytes
255    InvalidChecksumLength,
256    /// Salt must be between 1 and 64 bytes
257    InvalidSaltLength,
258}
259
260impl fmt::Display for Instantiate2AddressError {
261    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
262        match self {
263            Instantiate2AddressError::InvalidChecksumLength => write!(f, "invalid checksum length"),
264            Instantiate2AddressError::InvalidSaltLength => write!(f, "invalid salt length"),
265        }
266    }
267}
268
269/// Creates a contract address using the predictable address format introduced with
270/// wasmd 0.29. When using instantiate2, this is a way to precompute the address.
271/// When using instantiate, the contract address will use a different algorithm and
272/// cannot be pre-computed as it contains inputs from the chain's state at the time of
273/// message execution.
274///
275/// The predicable address format of instantiate2 is stable. But bear in mind this is
276/// a powerful tool that requires multiple software components to work together smoothly.
277/// It should be used carefully and tested thoroughly to avoid the loss of funds.
278///
279/// This method operates on [`CanonicalAddr`] to be implemented without chain interaction.
280/// The typical usage looks like this:
281///
282/// ```
283/// # use cosmwasm_std::{
284/// #     HexBinary,
285/// #     Storage, Api, Querier, DepsMut, Deps, entry_point, Env, StdError, MessageInfo,
286/// #     Response, QueryResponse,
287/// # };
288/// # type ExecuteMsg = ();
289/// use cosmwasm_std::instantiate2_address;
290///
291/// #[entry_point]
292/// pub fn execute(
293///     deps: DepsMut,
294///     env: Env,
295///     info: MessageInfo,
296///     msg: ExecuteMsg,
297/// ) -> Result<Response, StdError> {
298///     let canonical_creator = deps.api.addr_canonicalize(env.contract.address.as_str())?;
299///     let checksum = HexBinary::from_hex("9af782a3a1bcbcd22dbb6a45c751551d9af782a3a1bcbcd22dbb6a45c751551d")?;
300///     let salt = b"instance 1231";
301///     let canonical_addr = instantiate2_address(&checksum, &canonical_creator, salt)
302///         .map_err(|_| StdError::generic_err("Could not calculate addr"))?;
303///     let addr = deps.api.addr_humanize(&canonical_addr)?;
304///
305/// #   Ok(Default::default())
306/// }
307/// ```
308pub fn instantiate2_address(
309    checksum: &[u8],
310    creator: &CanonicalAddr,
311    salt: &[u8],
312) -> Result<CanonicalAddr, Instantiate2AddressError> {
313    // Non-empty msg values are discouraged.
314    // See https://medium.com/cosmwasm/dev-note-3-limitations-of-instantiate2-and-how-to-deal-with-them-a3f946874230.
315    let msg = b"";
316    instantiate2_address_impl(checksum, creator, salt, msg)
317}
318
319/// The instantiate2 address derivation implementation. This API is used for
320/// testing purposes only. The `msg` field is discouraged and should not be used.
321/// Use [`instantiate2_address`].
322#[doc(hidden)]
323fn instantiate2_address_impl(
324    checksum: &[u8],
325    creator: &CanonicalAddr,
326    salt: &[u8],
327    msg: &[u8],
328) -> Result<CanonicalAddr, Instantiate2AddressError> {
329    if checksum.len() != 32 {
330        return Err(Instantiate2AddressError::InvalidChecksumLength);
331    }
332
333    if salt.is_empty() || salt.len() > 64 {
334        return Err(Instantiate2AddressError::InvalidSaltLength);
335    };
336
337    let mut key = Vec::<u8>::new();
338    key.extend_from_slice(b"wasm\0");
339    key.extend_from_slice(&(checksum.len() as u64).to_be_bytes());
340    key.extend_from_slice(checksum);
341    key.extend_from_slice(&(creator.len() as u64).to_be_bytes());
342    key.extend_from_slice(creator);
343    key.extend_from_slice(&(salt.len() as u64).to_be_bytes());
344    key.extend_from_slice(salt);
345    key.extend_from_slice(&(msg.len() as u64).to_be_bytes());
346    key.extend_from_slice(msg);
347    let address_data = hash("module", &key);
348    Ok(address_data.into())
349}
350
351/// The "Basic Address" Hash from
352/// https://github.com/cosmos/cosmos-sdk/blob/v0.45.8/docs/architecture/adr-028-public-key-addresses.md
353fn hash(ty: &str, key: &[u8]) -> Vec<u8> {
354    let inner = Sha256::digest(ty.as_bytes());
355    Sha256::new().chain(inner).chain(key).finalize().to_vec()
356}
357
358#[cfg(test)]
359mod tests {
360    use super::*;
361    use crate::assert_hash_works;
362    use crate::HexBinary;
363
364    use hex_literal::hex;
365
366    #[test]
367    fn addr_unchecked_works() {
368        let a = Addr::unchecked("123");
369        let aa = Addr::unchecked(String::from("123"));
370        let b = Addr::unchecked("be");
371        assert_eq!(a, aa);
372        assert_ne!(a, b);
373    }
374
375    #[test]
376    fn addr_as_str_works() {
377        let addr = Addr::unchecked("literal-string");
378        assert_eq!(addr.as_str(), "literal-string");
379    }
380
381    #[test]
382    fn addr_as_bytes_works() {
383        let addr = Addr::unchecked("literal-string");
384        assert_eq!(
385            addr.as_bytes(),
386            [108, 105, 116, 101, 114, 97, 108, 45, 115, 116, 114, 105, 110, 103]
387        );
388    }
389
390    #[test]
391    fn addr_implements_display() {
392        let addr = Addr::unchecked("cos934gh9034hg04g0h134");
393        let embedded = format!("Address: {addr}");
394        assert_eq!(embedded, "Address: cos934gh9034hg04g0h134");
395        assert_eq!(addr.to_string(), "cos934gh9034hg04g0h134");
396    }
397
398    #[test]
399    fn addr_implements_as_ref_for_str() {
400        let addr = Addr::unchecked("literal-string");
401        assert_eq!(addr.as_ref(), "literal-string");
402    }
403
404    #[test]
405    fn addr_implements_partial_eq_addr_ref() {
406        let addr = Addr::unchecked("cos934gh9034hg04g0h134");
407        let addr_ref = &addr;
408        let addr_ref2 = &addr;
409
410        // `Addr == &Addr`
411        assert_eq!(addr, addr_ref);
412        // `&Addr == Addr`
413        assert_eq!(addr_ref, addr);
414        // `&Addr == &Addr`
415        assert_eq!(addr_ref, addr_ref2);
416    }
417
418    #[test]
419    fn addr_implements_into_string() {
420        // owned Addr
421        let addr = Addr::unchecked("cos934gh9034hg04g0h134");
422        let string: String = addr.into();
423        assert_eq!(string, "cos934gh9034hg04g0h134");
424
425        // &Addr
426        let addr = Addr::unchecked("cos934gh9034hg04g0h134");
427        let addr_ref = &addr;
428        let string: String = addr_ref.into();
429        assert_eq!(string, "cos934gh9034hg04g0h134");
430    }
431
432    // Test CanonicalAddr as_slice() for each CanonicalAddr::from input type
433    #[test]
434    fn canonical_addr_from_slice() {
435        // slice
436        let bytes: &[u8] = &[0u8, 187, 61, 11, 250, 0];
437        let canonical_addr_slice = CanonicalAddr::from(bytes);
438        assert_eq!(canonical_addr_slice.as_slice(), &[0u8, 187, 61, 11, 250, 0]);
439
440        // Vector
441        let bytes: Vec<u8> = vec![0u8, 187, 61, 11, 250, 0];
442        let canonical_addr_vec = CanonicalAddr::from(bytes);
443        assert_eq!(canonical_addr_vec.as_slice(), &[0u8, 187, 61, 11, 250, 0]);
444    }
445
446    #[test]
447    fn canonical_addr_implements_partial_eq_with_binary() {
448        let addr = CanonicalAddr::from([1, 2, 3]);
449        let bin1 = Binary::from([1, 2, 3]);
450        let bin2 = Binary::from([42, 43]);
451
452        assert_eq!(addr, bin1);
453        assert_eq!(bin1, addr);
454        assert_ne!(addr, bin2);
455        assert_ne!(bin2, addr);
456    }
457
458    #[test]
459    fn canonical_addr_implements_partial_eq_with_hex_binary() {
460        let addr = CanonicalAddr::from([1, 2, 3]);
461        let bin1 = HexBinary::from([1, 2, 3]);
462        let bin2 = HexBinary::from([42, 43]);
463
464        assert_eq!(addr, bin1);
465        assert_eq!(bin1, addr);
466        assert_ne!(addr, bin2);
467        assert_ne!(bin2, addr);
468    }
469
470    #[test]
471    fn canonical_addr_implements_from_array() {
472        let array = [1, 2, 3];
473        let addr = CanonicalAddr::from(array);
474        assert_eq!(addr.as_slice(), [1, 2, 3]);
475
476        let array_ref = b"foo";
477        let addr = CanonicalAddr::from(array_ref);
478        assert_eq!(addr.as_slice(), [0x66, 0x6f, 0x6f]);
479    }
480
481    #[test]
482    fn canonical_addr_implements_from_and_to_vector() {
483        // Into<CanonicalAddr> for Vec<u8>
484        // This test is a bit pointless because we get Into from the From implementation
485        let original = vec![0u8, 187, 61, 11, 250, 0];
486        let original_ptr = original.as_ptr();
487        let addr: CanonicalAddr = original.into();
488        assert_eq!(addr.as_slice(), [0u8, 187, 61, 11, 250, 0]);
489        assert_eq!(
490            (addr.0).as_slice().as_ptr(),
491            original_ptr,
492            "must not be copied"
493        );
494
495        // From<Vec<u8>> for CanonicalAddr
496        let original = vec![0u8, 187, 61, 11, 250, 0];
497        let original_ptr = original.as_ptr();
498        let addr = CanonicalAddr::from(original);
499        assert_eq!(addr.as_slice(), [0u8, 187, 61, 11, 250, 0]);
500        assert_eq!(
501            (addr.0).as_slice().as_ptr(),
502            original_ptr,
503            "must not be copied"
504        );
505
506        // Into<Vec<u8>> for CanonicalAddr
507        // This test is a bit pointless because we get Into from the From implementation
508        let original = CanonicalAddr::from(vec![0u8, 187, 61, 11, 250, 0]);
509        let original_ptr = (original.0).as_slice().as_ptr();
510        let vec: Vec<u8> = original.into();
511        assert_eq!(vec.as_slice(), [0u8, 187, 61, 11, 250, 0]);
512        assert_eq!(vec.as_ptr(), original_ptr, "must not be copied");
513
514        // From<CanonicalAddr> for Vec<u8>
515        let original = CanonicalAddr::from(vec![7u8, 35, 49, 101, 0, 255]);
516        let original_ptr = (original.0).as_slice().as_ptr();
517        let vec = Vec::<u8>::from(original);
518        assert_eq!(vec.as_slice(), [7u8, 35, 49, 101, 0, 255]);
519        assert_eq!(vec.as_ptr(), original_ptr, "must not be copied");
520    }
521
522    #[test]
523    fn canonical_addr_implements_from_and_to_binary() {
524        // From<Binary> for CanonicalAddr
525        let original = Binary::from([0u8, 187, 61, 11, 250, 0]);
526        let original_ptr = original.as_ptr();
527        let addr = CanonicalAddr::from(original);
528        assert_eq!(addr.as_slice(), [0u8, 187, 61, 11, 250, 0]);
529        assert_eq!(
530            (addr.0).as_slice().as_ptr(),
531            original_ptr,
532            "must not be copied"
533        );
534
535        // From<CanonicalAddr> for Binary
536        let original = CanonicalAddr::from(vec![7u8, 35, 49, 101, 0, 255]);
537        let original_ptr = (original.0).as_slice().as_ptr();
538        let bin = Binary::from(original);
539        assert_eq!(bin.as_slice(), [7u8, 35, 49, 101, 0, 255]);
540        assert_eq!(bin.as_ptr(), original_ptr, "must not be copied");
541    }
542
543    #[test]
544    fn canonical_addr_implements_from_and_to_hex_binary() {
545        // From<HexBinary> for CanonicalAddr
546        let original = HexBinary::from([0u8, 187, 61, 11, 250, 0]);
547        let original_ptr = original.as_ptr();
548        let addr = CanonicalAddr::from(original);
549        assert_eq!(addr.as_slice(), [0u8, 187, 61, 11, 250, 0]);
550        assert_eq!(
551            (addr.0).as_slice().as_ptr(),
552            original_ptr,
553            "must not be copied"
554        );
555
556        // From<CanonicalAddr> for HexBinary
557        let original = CanonicalAddr::from(vec![7u8, 35, 49, 101, 0, 255]);
558        let original_ptr = (original.0).as_slice().as_ptr();
559        let bin = HexBinary::from(original);
560        assert_eq!(bin.as_slice(), [7u8, 35, 49, 101, 0, 255]);
561        assert_eq!(bin.as_ptr(), original_ptr, "must not be copied");
562    }
563
564    #[test]
565    fn canonical_addr_len() {
566        let bytes: &[u8] = &[0u8, 187, 61, 11, 250, 0];
567        let canonical_addr = CanonicalAddr::from(bytes);
568        assert_eq!(canonical_addr.len(), bytes.len());
569    }
570
571    #[test]
572    fn canonical_addr_is_empty() {
573        let bytes: &[u8] = &[0u8, 187, 61, 11, 250, 0];
574        let canonical_addr = CanonicalAddr::from(bytes);
575        assert!(!canonical_addr.is_empty());
576        let empty_canonical_addr = CanonicalAddr::from(vec![]);
577        assert!(empty_canonical_addr.is_empty());
578    }
579
580    #[test]
581    fn canonical_addr_implements_display() {
582        let bytes: &[u8] = &[
583            0x12, // two hex digits
584            0x03, // small values must be padded to two digits
585            0xab, // ensure we get upper case
586            0x00, // always test extreme values
587            0xff,
588        ];
589        let address = CanonicalAddr::from(bytes);
590        let embedded = format!("Address: {address}");
591        assert_eq!(embedded, "Address: 1203AB00FF");
592        assert_eq!(address.to_string(), "1203AB00FF");
593    }
594
595    #[test]
596    fn canonical_addr_implements_deref() {
597        // Dereference to [u8]
598        let bytes: &[u8] = &[0u8, 187, 61, 11, 250, 0];
599        let canonical_addr = CanonicalAddr::from(bytes);
600        assert_eq!(*canonical_addr, [0u8, 187, 61, 11, 250, 0]);
601
602        // This checks deref coercions from &CanonicalAddr to &[u8] works
603        let bytes: &[u8] = &[0u8, 187, 61, 11, 250, 0];
604        let canonical_addr = CanonicalAddr::from(bytes);
605        assert_eq!(canonical_addr.len(), 6);
606        let canonical_addr_slice: &[u8] = &canonical_addr;
607        assert_eq!(canonical_addr_slice, &[0u8, 187, 61, 11, 250, 0]);
608    }
609
610    /// Tests that `CanonicalAddr` implements `EQ` and `Hash` correctly and thus
611    /// can be used with hash maps and sets.
612    #[test]
613    fn canonical_addr_implements_hash_eq() {
614        let alice = CanonicalAddr::from([0, 187, 61, 11, 250, 0]);
615        let bob = CanonicalAddr::from([16, 21, 33, 0, 255, 9]);
616        assert_hash_works!(alice, bob);
617    }
618
619    // helper to show we can handle Addr and &Addr equally
620    fn flexible<'a>(a: impl Into<Cow<'a, Addr>>) -> String {
621        a.into().into_owned().to_string()
622    }
623
624    #[test]
625    fn addr_into_cow() {
626        // owned Addr
627        let value = "wasmeucn0ur0ncny2308ry";
628        let addr = Addr::unchecked(value);
629
630        // pass by ref
631        assert_eq!(value, &flexible(&addr));
632        // pass by value
633        assert_eq!(value, &flexible(addr));
634    }
635
636    #[test]
637    fn instantiate2_address_impl_works() {
638        let checksum1 =
639            HexBinary::from_hex("13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a5")
640                .unwrap();
641        let creator1 = CanonicalAddr::from(hex!("9999999999aaaaaaaaaabbbbbbbbbbcccccccccc"));
642        let salt1 = hex!("61");
643        let salt2 = hex!("aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae");
644        let msg1: &[u8] = b"";
645        let msg2: &[u8] = b"{}";
646        let msg3: &[u8] = b"{\"some\":123,\"structure\":{\"nested\":[\"ok\",true]}}";
647
648        // No msg
649        let expected = CanonicalAddr::from(hex!(
650            "5e865d3e45ad3e961f77fd77d46543417ced44d924dc3e079b5415ff6775f847"
651        ));
652        assert_eq!(
653            instantiate2_address_impl(&checksum1, &creator1, &salt1, msg1).unwrap(),
654            expected
655        );
656
657        // With msg
658        let expected = CanonicalAddr::from(hex!(
659            "0995499608947a5281e2c7ebd71bdb26a1ad981946dad57f6c4d3ee35de77835"
660        ));
661        assert_eq!(
662            instantiate2_address_impl(&checksum1, &creator1, &salt1, msg2).unwrap(),
663            expected
664        );
665
666        // Long msg
667        let expected = CanonicalAddr::from(hex!(
668            "83326e554723b15bac664ceabc8a5887e27003abe9fbd992af8c7bcea4745167"
669        ));
670        assert_eq!(
671            instantiate2_address_impl(&checksum1, &creator1, &salt1, msg3).unwrap(),
672            expected
673        );
674
675        // Long salt
676        let expected = CanonicalAddr::from(hex!(
677            "9384c6248c0bb171e306fd7da0993ec1e20eba006452a3a9e078883eb3594564"
678        ));
679        assert_eq!(
680            instantiate2_address_impl(&checksum1, &creator1, &salt2, b"").unwrap(),
681            expected
682        );
683
684        // Salt too short or too long
685        let empty = Vec::<u8>::new();
686        assert!(matches!(
687            instantiate2_address_impl(&checksum1, &creator1, &empty, b"").unwrap_err(),
688            Instantiate2AddressError::InvalidSaltLength
689        ));
690        let too_long = vec![0x11; 65];
691        assert!(matches!(
692            instantiate2_address_impl(&checksum1, &creator1, &too_long, b"").unwrap_err(),
693            Instantiate2AddressError::InvalidSaltLength
694        ));
695
696        // invalid checksum length
697        let broken_cs = hex!("13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2");
698        assert!(matches!(
699            instantiate2_address_impl(&broken_cs, &creator1, &salt1, b"").unwrap_err(),
700            Instantiate2AddressError::InvalidChecksumLength
701        ));
702        let broken_cs = hex!("");
703        assert!(matches!(
704            instantiate2_address_impl(&broken_cs, &creator1, &salt1, b"").unwrap_err(),
705            Instantiate2AddressError::InvalidChecksumLength
706        ));
707        let broken_cs = hex!("13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2aaaa");
708        assert!(matches!(
709            instantiate2_address_impl(&broken_cs, &creator1, &salt1, b"").unwrap_err(),
710            Instantiate2AddressError::InvalidChecksumLength
711        ));
712    }
713
714    #[test]
715    fn instantiate2_address_impl_works_for_cosmjs_test_vectors() {
716        // Test data from https://github.com/cosmos/cosmjs/pull/1253
717        const COSMOS_ED25519_TESTS_JSON: &str = "./testdata/instantiate2_addresses.json";
718
719        #[derive(Deserialize, Debug)]
720        #[serde(rename_all = "camelCase")]
721        #[allow(dead_code)]
722        struct In {
723            checksum: HexBinary,
724            creator: String,
725            creator_data: HexBinary,
726            salt: HexBinary,
727            msg: Option<String>,
728        }
729
730        #[derive(Deserialize, Debug)]
731        #[serde(rename_all = "camelCase")]
732        #[allow(dead_code)]
733        struct Intermediate {
734            key: HexBinary,
735            address_data: HexBinary,
736        }
737
738        #[derive(Deserialize, Debug)]
739        #[serde(rename_all = "camelCase")]
740        #[allow(dead_code)]
741        struct Out {
742            address: String,
743        }
744
745        #[derive(Deserialize, Debug)]
746        #[allow(dead_code)]
747        struct Row {
748            #[serde(rename = "in")]
749            input: In,
750            intermediate: Intermediate,
751            out: Out,
752        }
753
754        fn read_tests() -> Vec<Row> {
755            use std::fs::File;
756            use std::io::BufReader;
757
758            // Open the file in read-only mode with buffer.
759            let file = File::open(COSMOS_ED25519_TESTS_JSON).unwrap();
760            let reader = BufReader::new(file);
761
762            serde_json::from_reader(reader).unwrap()
763        }
764
765        for Row {
766            input,
767            intermediate,
768            out: _,
769        } in read_tests()
770        {
771            let msg = input.msg.map(|msg| msg.into_bytes()).unwrap_or_default();
772            let addr = instantiate2_address_impl(
773                &input.checksum,
774                &input.creator_data.into(),
775                &input.salt,
776                &msg,
777            )
778            .unwrap();
779            assert_eq!(addr, intermediate.address_data);
780        }
781    }
782
783    #[test]
784    fn hash_works() {
785        // Test case from https://github.com/cosmos/cosmos-sdk/blob/v0.47.0-alpha1/types/address/hash_test.go#L19-L24
786        let expected = [
787            195, 235, 23, 251, 9, 99, 177, 195, 81, 122, 182, 124, 36, 113, 245, 156, 76, 188, 221,
788            83, 181, 192, 227, 82, 100, 177, 161, 133, 240, 160, 5, 25,
789        ];
790        assert_eq!(hash("1", &[1]), expected);
791    }
792}