cosmwasm_std/
addresses.rs

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