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