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#[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 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 #[inline]
66 pub fn as_bytes(&self) -> &[u8] {
67 self.0.as_bytes()
68 }
69
70 #[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
90impl PartialEq<&str> for Addr {
95 fn eq(&self, rhs: &&str) -> bool {
96 self.0 == *rhs
97 }
98}
99
100impl PartialEq<Addr> for &str {
105 fn eq(&self, rhs: &Addr) -> bool {
106 *self == rhs.0
107 }
108}
109
110impl PartialEq<String> for Addr {
115 fn eq(&self, rhs: &String) -> bool {
116 &self.0 == rhs
117 }
118}
119
120impl PartialEq<Addr> for String {
125 fn eq(&self, rhs: &Addr) -> bool {
126 self == &rhs.0
127 }
128}
129
130impl 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#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, Hash, JsonSchema)]
173pub struct CanonicalAddr(pub Binary);
174
175impl PartialEq<Binary> for CanonicalAddr {
177 fn eq(&self, rhs: &Binary) -> bool {
178 &self.0 == rhs
179 }
180}
181
182impl PartialEq<CanonicalAddr> for Binary {
184 fn eq(&self, rhs: &CanonicalAddr) -> bool {
185 self == &rhs.0
186 }
187}
188
189impl PartialEq<HexBinary> for CanonicalAddr {
191 fn eq(&self, rhs: &HexBinary) -> bool {
192 self.as_slice() == rhs.as_slice()
193 }
194}
195
196impl 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
209impl<const LENGTH: usize> From<&[u8; LENGTH]> for CanonicalAddr {
211 fn from(source: &[u8; LENGTH]) -> Self {
212 Self(source.into())
213 }
214}
215
216impl<const LENGTH: usize> From<[u8; LENGTH]> for CanonicalAddr {
218 fn from(source: [u8; LENGTH]) -> Self {
219 Self(source.into())
220 }
221}
222
223impl From<Vec<u8>> for CanonicalAddr {
225 fn from(source: Vec<u8>) -> Self {
226 Self(source.into())
227 }
228}
229
230impl From<CanonicalAddr> for Vec<u8> {
232 fn from(source: CanonicalAddr) -> Vec<u8> {
233 source.0.into()
234 }
235}
236
237impl From<Binary> for CanonicalAddr {
239 fn from(source: Binary) -> Self {
240 Self(source)
241 }
242}
243
244impl From<CanonicalAddr> for Binary {
246 fn from(source: CanonicalAddr) -> Binary {
247 source.0
248 }
249}
250
251impl From<HexBinary> for CanonicalAddr {
253 fn from(source: HexBinary) -> Self {
254 Self(source.into())
255 }
256}
257
258impl From<CanonicalAddr> for HexBinary {
260 fn from(source: CanonicalAddr) -> HexBinary {
261 source.0.into()
262 }
263}
264
265impl 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 InvalidChecksumLength,
297 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
310pub fn instantiate2_address(
350 checksum: &[u8],
351 creator: &CanonicalAddr,
352 salt: &[u8],
353) -> Result<CanonicalAddr, Instantiate2AddressError> {
354 let msg = b"";
357 instantiate2_address_impl(checksum, creator, salt, msg)
358}
359
360#[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
392fn 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 #[test]
446 fn addr_implements_partial_eq_with_str_and_string() {
447 let addr = Addr::unchecked("cos934gh9034hg04g0h134");
448
449 assert_eq!(addr, "cos934gh9034hg04g0h134");
451 assert_eq!("cos934gh9034hg04g0h134", addr);
453 assert_eq!(addr, String::from("cos934gh9034hg04g0h134"));
455 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 assert_eq!(addr, addr_ref);
467 assert_eq!(addr_ref, addr);
469 assert_eq!(addr_ref, addr_ref2);
471 }
472
473 #[test]
474 fn addr_implements_into_string() {
475 let addr = Addr::unchecked("cos934gh9034hg04g0h134");
477 let string: String = addr.into();
478 assert_eq!(string, "cos934gh9034hg04g0h134");
479
480 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]
489 fn canonical_addr_from_slice() {
490 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 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 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 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 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 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 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 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 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 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, 0x03, 0xab, 0x00, 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 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 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 #[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 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 let value = "wasmeucn0ur0ncny2308ry";
667 let addr = Addr::unchecked(value);
668
669 assert_eq!(value, &flexible(&addr));
671 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 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 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 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 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 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 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 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 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 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}