secret_cosmwasm_std/
addresses.rs

1use schemars::JsonSchema;
2use serde::{Deserialize, Serialize};
3use std::borrow::Cow;
4use std::fmt;
5use std::ops::Deref;
6
7use crate::{binary::Binary, HexBinary};
8
9/// A human readable address.
10///
11/// In Cosmos, this is typically bech32 encoded. But for multi-chain smart contracts no
12/// assumptions should be made other than being UTF-8 encoded and of reasonable length.
13///
14/// This type represents a validated address. It can be created in the following ways
15/// 1. Use `Addr::unchecked(input)`
16/// 2. Use `let checked: Addr = deps.api.addr_validate(input)?`
17/// 3. Use `let checked: Addr = deps.api.addr_humanize(canonical_addr)?`
18/// 4. Deserialize from JSON. This must only be done from JSON that was validated before
19///    such as a contract's state. `Addr` must not be used in messages sent by the user
20///    because this would result in unvalidated instances.
21///
22/// This type is immutable. If you really need to mutate it (Really? Are you sure?), create
23/// a mutable copy using `let mut mutable = Addr::to_string()` and operate on that `String`
24/// instance.
25#[derive(
26    Serialize, Deserialize, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, JsonSchema,
27)]
28pub struct Addr(String);
29
30impl Addr {
31    /// Creates a new `Addr` instance from the given input without checking the validity
32    /// of the input. Since `Addr` must always contain valid addresses, the caller is
33    /// responsible for ensuring the input is valid.
34    ///
35    /// Use this in cases where the address was validated before or in test code.
36    /// If you see this in contract code, it should most likely be replaced with
37    /// `let checked: Addr = deps.api.addr_humanize(canonical_addr)?`.
38    ///
39    /// ## Examples
40    ///
41    /// ```
42    /// # use secret_cosmwasm_std::{Addr};
43    /// let address = Addr::unchecked("foobar");
44    /// assert_eq!(address, "foobar");
45    /// ```
46    pub fn unchecked(input: impl Into<String>) -> Addr {
47        Addr(input.into())
48    }
49
50    #[inline]
51    pub fn as_str(&self) -> &str {
52        self.0.as_str()
53    }
54
55    /// Returns the UTF-8 encoded address string as a byte array.
56    ///
57    /// This is equivalent to `address.as_str().as_bytes()`.
58    #[inline]
59    pub fn as_bytes(&self) -> &[u8] {
60        self.0.as_bytes()
61    }
62
63    /// Utility for explicit conversion to `String`.
64    #[inline]
65    pub fn into_string(self) -> String {
66        self.0
67    }
68}
69
70impl fmt::Display for Addr {
71    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
72        write!(f, "{}", &self.0)
73    }
74}
75
76impl AsRef<str> for Addr {
77    #[inline]
78    fn as_ref(&self) -> &str {
79        self.as_str()
80    }
81}
82
83/// Implement `Addr == &str`
84impl PartialEq<&str> for Addr {
85    fn eq(&self, rhs: &&str) -> bool {
86        self.0 == *rhs
87    }
88}
89
90/// Implement `&str == Addr`
91impl PartialEq<Addr> for &str {
92    fn eq(&self, rhs: &Addr) -> bool {
93        *self == rhs.0
94    }
95}
96
97/// Implement `Addr == String`
98impl PartialEq<String> for Addr {
99    fn eq(&self, rhs: &String) -> bool {
100        &self.0 == rhs
101    }
102}
103
104/// Implement `String == Addr`
105impl PartialEq<Addr> for String {
106    fn eq(&self, rhs: &Addr) -> bool {
107        self == &rhs.0
108    }
109}
110
111// Addr->String is a safe conversion.
112// However, the opposite direction is unsafe and must not be implemented.
113
114impl From<Addr> for String {
115    fn from(addr: Addr) -> Self {
116        addr.0
117    }
118}
119
120impl From<&Addr> for String {
121    fn from(addr: &Addr) -> Self {
122        addr.0.clone()
123    }
124}
125
126impl From<Addr> for Cow<'_, Addr> {
127    fn from(addr: Addr) -> Self {
128        Cow::Owned(addr)
129    }
130}
131
132impl<'a> From<&'a Addr> for Cow<'a, Addr> {
133    fn from(addr: &'a Addr) -> Self {
134        Cow::Borrowed(addr)
135    }
136}
137
138/// A blockchain address in its binary form.
139///
140/// The specific implementation is up to the underlying chain and CosmWasm as well as
141/// contracts should not make assumptions on that data. In Ethereum for example, an
142/// `Addr` would contain a user visible address like 0x14d3cc818735723ab86eaf9502376e847a64ddad
143/// and the corresponding `CanonicalAddr` would store the 20 bytes 0x14, 0xD3, ..., 0xAD.
144/// In Cosmos, the bech32 format is used for `Addr`s and the `CanonicalAddr` holds the
145/// encoded bech32 data without the checksum. Typical sizes are 20 bytes for externally
146/// owned addresses and 32 bytes for module addresses (such as x/wasm contract addresses).
147/// That being said, a chain might decide to use any size other than 20 or 32 bytes.
148///
149/// The safe way to obtain a valid `CanonicalAddr` is using `Api::addr_canonicalize`. In
150/// addition to that there are many unsafe ways to convert any binary data into an instance.
151/// So the type shoud be treated as a marker to express the intended data type, not as
152/// a validity guarantee of any sort.
153#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, Hash, JsonSchema)]
154pub struct CanonicalAddr(pub Binary);
155
156/// Implement `CanonicalAddr == Binary`
157impl PartialEq<Binary> for CanonicalAddr {
158    fn eq(&self, rhs: &Binary) -> bool {
159        &self.0 == rhs
160    }
161}
162
163/// Implement `Binary == CanonicalAddr`
164impl PartialEq<CanonicalAddr> for Binary {
165    fn eq(&self, rhs: &CanonicalAddr) -> bool {
166        self == &rhs.0
167    }
168}
169
170/// Implement `CanonicalAddr == HexBinary`
171impl PartialEq<HexBinary> for CanonicalAddr {
172    fn eq(&self, rhs: &HexBinary) -> bool {
173        self.as_slice() == rhs.as_slice()
174    }
175}
176
177/// Implement `HexBinary == CanonicalAddr`
178impl PartialEq<CanonicalAddr> for HexBinary {
179    fn eq(&self, rhs: &CanonicalAddr) -> bool {
180        self.as_slice() == rhs.0.as_slice()
181    }
182}
183
184impl From<&[u8]> for CanonicalAddr {
185    fn from(source: &[u8]) -> Self {
186        Self(source.into())
187    }
188}
189
190// Array reference
191impl<const LENGTH: usize> From<&[u8; LENGTH]> for CanonicalAddr {
192    fn from(source: &[u8; LENGTH]) -> Self {
193        Self(source.into())
194    }
195}
196
197// Owned array
198impl<const LENGTH: usize> From<[u8; LENGTH]> for CanonicalAddr {
199    fn from(source: [u8; LENGTH]) -> Self {
200        Self(source.into())
201    }
202}
203
204// Owned vector -> CanonicalAddr
205impl From<Vec<u8>> for CanonicalAddr {
206    fn from(source: Vec<u8>) -> Self {
207        Self(source.into())
208    }
209}
210
211// CanonicalAddr -> Owned vector
212impl From<CanonicalAddr> for Vec<u8> {
213    fn from(source: CanonicalAddr) -> Vec<u8> {
214        source.0.into()
215    }
216}
217
218// Owned Binary -> CanonicalAddr
219impl From<Binary> for CanonicalAddr {
220    fn from(source: Binary) -> Self {
221        Self(source)
222    }
223}
224
225// CanonicalAddr -> Owned Binary
226impl From<CanonicalAddr> for Binary {
227    fn from(source: CanonicalAddr) -> Binary {
228        source.0
229    }
230}
231
232// Owned HexBinary -> CanonicalAddr
233impl From<HexBinary> for CanonicalAddr {
234    fn from(source: HexBinary) -> Self {
235        Self(source.into())
236    }
237}
238
239// CanonicalAddr -> Owned HexBinary
240impl From<CanonicalAddr> for HexBinary {
241    fn from(source: CanonicalAddr) -> HexBinary {
242        source.0.into()
243    }
244}
245
246/// Just like Vec<u8>, CanonicalAddr is a smart pointer to [u8].
247/// This implements `*canonical_address` for us and allows us to
248/// do `&*canonical_address`, returning a `&[u8]` from a `&CanonicalAddr`.
249/// With [deref coercions](https://doc.rust-lang.org/1.22.1/book/first-edition/deref-coercions.html#deref-coercions),
250/// this allows us to use `&canonical_address` whenever a `&[u8]` is required.
251impl Deref for CanonicalAddr {
252    type Target = [u8];
253
254    fn deref(&self) -> &Self::Target {
255        self.as_slice()
256    }
257}
258
259impl CanonicalAddr {
260    pub fn as_slice(&self) -> &[u8] {
261        self.0.as_slice()
262    }
263}
264
265impl fmt::Display for CanonicalAddr {
266    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
267        for byte in self.0.as_slice() {
268            write!(f, "{:02X}", byte)?;
269        }
270        Ok(())
271    }
272}
273
274#[cfg(test)]
275mod tests {
276    use super::*;
277    use std::collections::hash_map::DefaultHasher;
278    use std::collections::HashSet;
279    use std::hash::{Hash, Hasher};
280
281    #[test]
282    fn addr_unchecked_works() {
283        let a = Addr::unchecked("123");
284        let aa = Addr::unchecked(String::from("123"));
285        let b = Addr::unchecked("be");
286        assert_eq!(a, aa);
287        assert_ne!(a, b);
288    }
289
290    #[test]
291    fn addr_as_str_works() {
292        let addr = Addr::unchecked("literal-string");
293        assert_eq!(addr.as_str(), "literal-string");
294    }
295
296    #[test]
297    fn addr_as_bytes_works() {
298        let addr = Addr::unchecked("literal-string");
299        assert_eq!(
300            addr.as_bytes(),
301            [108, 105, 116, 101, 114, 97, 108, 45, 115, 116, 114, 105, 110, 103]
302        );
303    }
304
305    #[test]
306    fn addr_implements_display() {
307        let addr = Addr::unchecked("cos934gh9034hg04g0h134");
308        let embedded = format!("Address: {}", addr);
309        assert_eq!(embedded, "Address: cos934gh9034hg04g0h134");
310        assert_eq!(addr.to_string(), "cos934gh9034hg04g0h134");
311    }
312
313    #[test]
314    fn addr_implements_as_ref_for_str() {
315        let addr = Addr::unchecked("literal-string");
316        assert_eq!(addr.as_ref(), "literal-string");
317    }
318
319    #[test]
320    fn addr_implements_partial_eq_with_str() {
321        let addr = Addr::unchecked("cos934gh9034hg04g0h134");
322
323        // `Addr == &str`
324        assert_eq!(addr, "cos934gh9034hg04g0h134");
325        // `&str == Addr`
326        assert_eq!("cos934gh9034hg04g0h134", addr);
327    }
328
329    #[test]
330    fn addr_implements_partial_eq_with_string() {
331        let addr = Addr::unchecked("cos934gh9034hg04g0h134");
332
333        // `Addr == String`
334        assert_eq!(addr, String::from("cos934gh9034hg04g0h134"));
335        // `String == Addr`
336        assert_eq!(String::from("cos934gh9034hg04g0h134"), addr);
337    }
338
339    #[test]
340    fn addr_implements_into_string() {
341        // owned Addr
342        let addr = Addr::unchecked("cos934gh9034hg04g0h134");
343        let string: String = addr.into();
344        assert_eq!(string, "cos934gh9034hg04g0h134");
345
346        // &Addr
347        let addr = Addr::unchecked("cos934gh9034hg04g0h134");
348        let addr_ref = &addr;
349        let string: String = addr_ref.into();
350        assert_eq!(string, "cos934gh9034hg04g0h134");
351    }
352
353    // Test CanonicalAddr as_slice() for each CanonicalAddr::from input type
354    #[test]
355    fn canonical_addr_from_slice() {
356        // slice
357        let bytes: &[u8] = &[0u8, 187, 61, 11, 250, 0];
358        let canonical_addr_slice = CanonicalAddr::from(bytes);
359        assert_eq!(canonical_addr_slice.as_slice(), &[0u8, 187, 61, 11, 250, 0]);
360
361        // Vector
362        let bytes: Vec<u8> = vec![0u8, 187, 61, 11, 250, 0];
363        let canonical_addr_vec = CanonicalAddr::from(bytes);
364        assert_eq!(canonical_addr_vec.as_slice(), &[0u8, 187, 61, 11, 250, 0]);
365    }
366
367    #[test]
368    fn canonical_addr_implements_partial_eq_with_binary() {
369        let addr = CanonicalAddr::from([1, 2, 3]);
370        let bin1 = Binary::from([1, 2, 3]);
371        let bin2 = Binary::from([42, 43]);
372
373        assert_eq!(addr, bin1);
374        assert_eq!(bin1, addr);
375        assert_ne!(addr, bin2);
376        assert_ne!(bin2, addr);
377    }
378
379    #[test]
380    fn canonical_addr_implements_partial_eq_with_hex_binary() {
381        let addr = CanonicalAddr::from([1, 2, 3]);
382        let bin1 = HexBinary::from([1, 2, 3]);
383        let bin2 = HexBinary::from([42, 43]);
384
385        assert_eq!(addr, bin1);
386        assert_eq!(bin1, addr);
387        assert_ne!(addr, bin2);
388        assert_ne!(bin2, addr);
389    }
390
391    #[test]
392    fn canonical_addr_implements_from_array() {
393        let array = [1, 2, 3];
394        let addr = CanonicalAddr::from(array);
395        assert_eq!(addr.as_slice(), [1, 2, 3]);
396
397        let array_ref = b"foo";
398        let addr = CanonicalAddr::from(array_ref);
399        assert_eq!(addr.as_slice(), [0x66, 0x6f, 0x6f]);
400    }
401
402    #[test]
403    fn canonical_addr_implements_from_and_to_vector() {
404        // Into<CanonicalAddr> for Vec<u8>
405        // This test is a bit pointless because we get Into from the From implementation
406        let original = vec![0u8, 187, 61, 11, 250, 0];
407        let original_ptr = original.as_ptr();
408        let addr: CanonicalAddr = original.into();
409        assert_eq!(addr.as_slice(), [0u8, 187, 61, 11, 250, 0]);
410        assert_eq!((addr.0).0.as_ptr(), original_ptr, "must not be copied");
411
412        // From<Vec<u8>> for CanonicalAddr
413        let original = vec![0u8, 187, 61, 11, 250, 0];
414        let original_ptr = original.as_ptr();
415        let addr = CanonicalAddr::from(original);
416        assert_eq!(addr.as_slice(), [0u8, 187, 61, 11, 250, 0]);
417        assert_eq!((addr.0).0.as_ptr(), original_ptr, "must not be copied");
418
419        // Into<Vec<u8>> for CanonicalAddr
420        // This test is a bit pointless because we get Into from the From implementation
421        let original = CanonicalAddr::from(vec![0u8, 187, 61, 11, 250, 0]);
422        let original_ptr = (original.0).0.as_ptr();
423        let vec: Vec<u8> = original.into();
424        assert_eq!(vec.as_slice(), [0u8, 187, 61, 11, 250, 0]);
425        assert_eq!(vec.as_ptr(), original_ptr, "must not be copied");
426
427        // From<CanonicalAddr> for Vec<u8>
428        let original = CanonicalAddr::from(vec![7u8, 35, 49, 101, 0, 255]);
429        let original_ptr = (original.0).0.as_ptr();
430        let vec = Vec::<u8>::from(original);
431        assert_eq!(vec.as_slice(), [7u8, 35, 49, 101, 0, 255]);
432        assert_eq!(vec.as_ptr(), original_ptr, "must not be copied");
433    }
434
435    #[test]
436    fn canonical_addr_implements_from_and_to_binary() {
437        // From<Binary> for CanonicalAddr
438        let original = Binary::from([0u8, 187, 61, 11, 250, 0]);
439        let original_ptr = original.as_ptr();
440        let addr = CanonicalAddr::from(original);
441        assert_eq!(addr.as_slice(), [0u8, 187, 61, 11, 250, 0]);
442        assert_eq!((addr.0).0.as_ptr(), original_ptr, "must not be copied");
443
444        // From<CanonicalAddr> for Binary
445        let original = CanonicalAddr::from(vec![7u8, 35, 49, 101, 0, 255]);
446        let original_ptr = (original.0).0.as_ptr();
447        let bin = Binary::from(original);
448        assert_eq!(bin.as_slice(), [7u8, 35, 49, 101, 0, 255]);
449        assert_eq!(bin.as_ptr(), original_ptr, "must not be copied");
450    }
451
452    #[test]
453    fn canonical_addr_implements_from_and_to_hex_binary() {
454        // From<HexBinary> for CanonicalAddr
455        let original = HexBinary::from([0u8, 187, 61, 11, 250, 0]);
456        let original_ptr = original.as_ptr();
457        let addr = CanonicalAddr::from(original);
458        assert_eq!(addr.as_slice(), [0u8, 187, 61, 11, 250, 0]);
459        assert_eq!((addr.0).0.as_ptr(), original_ptr, "must not be copied");
460
461        // From<CanonicalAddr> for HexBinary
462        let original = CanonicalAddr::from(vec![7u8, 35, 49, 101, 0, 255]);
463        let original_ptr = (original.0).0.as_ptr();
464        let bin = HexBinary::from(original);
465        assert_eq!(bin.as_slice(), [7u8, 35, 49, 101, 0, 255]);
466        assert_eq!(bin.as_ptr(), original_ptr, "must not be copied");
467    }
468
469    #[test]
470    fn canonical_addr_len() {
471        let bytes: &[u8] = &[0u8, 187, 61, 11, 250, 0];
472        let canonical_addr = CanonicalAddr::from(bytes);
473        assert_eq!(canonical_addr.len(), bytes.len());
474    }
475
476    #[test]
477    fn canonical_addr_is_empty() {
478        let bytes: &[u8] = &[0u8, 187, 61, 11, 250, 0];
479        let canonical_addr = CanonicalAddr::from(bytes);
480        assert!(!canonical_addr.is_empty());
481        let empty_canonical_addr = CanonicalAddr::from(vec![]);
482        assert!(empty_canonical_addr.is_empty());
483    }
484
485    #[test]
486    fn canonical_addr_implements_display() {
487        let bytes: &[u8] = &[
488            0x12, // two hex digits
489            0x03, // small values must be padded to two digits
490            0xab, // ensure we get upper case
491            0x00, // always test extreme values
492            0xff,
493        ];
494        let address = CanonicalAddr::from(bytes);
495        let embedded = format!("Address: {}", address);
496        assert_eq!(embedded, "Address: 1203AB00FF");
497        assert_eq!(address.to_string(), "1203AB00FF");
498    }
499
500    #[test]
501    fn canonical_addr_implements_deref() {
502        // Dereference to [u8]
503        let bytes: &[u8] = &[0u8, 187, 61, 11, 250, 0];
504        let canonical_addr = CanonicalAddr::from(bytes);
505        assert_eq!(*canonical_addr, [0u8, 187, 61, 11, 250, 0]);
506
507        // This checks deref coercions from &CanonicalAddr to &[u8] works
508        let bytes: &[u8] = &[0u8, 187, 61, 11, 250, 0];
509        let canonical_addr = CanonicalAddr::from(bytes);
510        assert_eq!(canonical_addr.len(), 6);
511        let canonical_addr_slice: &[u8] = &canonical_addr;
512        assert_eq!(canonical_addr_slice, &[0u8, 187, 61, 11, 250, 0]);
513    }
514
515    #[test]
516    fn canonical_addr_implements_hash() {
517        let alice1 = CanonicalAddr::from([0, 187, 61, 11, 250, 0]);
518        let mut hasher = DefaultHasher::new();
519        alice1.hash(&mut hasher);
520        let alice1_hash = hasher.finish();
521
522        let alice2 = CanonicalAddr::from([0, 187, 61, 11, 250, 0]);
523        let mut hasher = DefaultHasher::new();
524        alice2.hash(&mut hasher);
525        let alice2_hash = hasher.finish();
526
527        let bob = CanonicalAddr::from([16, 21, 33, 0, 255, 9]);
528        let mut hasher = DefaultHasher::new();
529        bob.hash(&mut hasher);
530        let bob_hash = hasher.finish();
531
532        assert_eq!(alice1_hash, alice2_hash);
533        assert_ne!(alice1_hash, bob_hash);
534    }
535
536    /// This requires Hash and Eq to be implemented
537    #[test]
538    fn canonical_addr_can_be_used_in_hash_set() {
539        let alice1 = CanonicalAddr::from([0, 187, 61, 11, 250, 0]);
540        let alice2 = CanonicalAddr::from([0, 187, 61, 11, 250, 0]);
541        let bob = CanonicalAddr::from([16, 21, 33, 0, 255, 9]);
542
543        let mut set = HashSet::new();
544        set.insert(alice1.clone());
545        set.insert(alice2.clone());
546        set.insert(bob.clone());
547        assert_eq!(set.len(), 2);
548
549        let set1 = HashSet::<CanonicalAddr>::from_iter(vec![bob.clone(), alice1.clone()]);
550        let set2 = HashSet::from_iter(vec![alice1, alice2, bob]);
551        assert_eq!(set1, set2);
552    }
553
554    // helper to show we can handle Addr and &Addr equally
555    fn flexible<'a>(a: impl Into<Cow<'a, Addr>>) -> String {
556        a.into().into_owned().to_string()
557    }
558
559    #[test]
560    fn addr_into_cow() {
561        // owned Addr
562        let value = "wasmeucn0ur0ncny2308ry";
563        let addr = Addr::unchecked(value);
564
565        // pass by ref
566        assert_eq!(value, &flexible(&addr));
567        // pass by value
568        assert_eq!(value, &flexible(addr));
569    }
570}