cosmwasm_std/
addresses.rs

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