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#[derive(
30 Serialize, Deserialize, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, schemars::JsonSchema,
31)]
32pub struct Addr(String);
33
34forward_ref_partial_eq!(Addr, Addr);
35
36impl Addr {
37 pub fn unchecked(input: impl Into<String>) -> Addr {
53 Addr(input.into())
54 }
55
56 #[inline]
57 pub fn as_str(&self) -> &str {
58 self.0.as_str()
59 }
60
61 #[inline]
65 pub fn as_bytes(&self) -> &[u8] {
66 self.0.as_bytes()
67 }
68
69 #[inline]
71 pub fn into_string(self) -> String {
72 self.0
73 }
74}
75
76impl fmt::Display for Addr {
77 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
78 write!(f, "{}", &self.0)
79 }
80}
81
82impl AsRef<str> for Addr {
83 #[inline]
84 fn as_ref(&self) -> &str {
85 self.as_str()
86 }
87}
88
89impl From<Addr> for String {
93 fn from(addr: Addr) -> Self {
94 addr.0
95 }
96}
97
98impl From<&Addr> for String {
99 fn from(addr: &Addr) -> Self {
100 addr.0.clone()
101 }
102}
103
104impl From<Addr> for Cow<'_, Addr> {
105 fn from(addr: Addr) -> Self {
106 Cow::Owned(addr)
107 }
108}
109
110impl<'a> From<&'a Addr> for Cow<'a, Addr> {
111 fn from(addr: &'a Addr) -> Self {
112 Cow::Borrowed(addr)
113 }
114}
115
116#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, Hash, schemars::JsonSchema)]
132pub struct CanonicalAddr(Binary);
133
134impl PartialEq<Binary> for CanonicalAddr {
136 fn eq(&self, rhs: &Binary) -> bool {
137 &self.0 == rhs
138 }
139}
140
141impl PartialEq<CanonicalAddr> for Binary {
143 fn eq(&self, rhs: &CanonicalAddr) -> bool {
144 self == &rhs.0
145 }
146}
147
148impl PartialEq<HexBinary> for CanonicalAddr {
150 fn eq(&self, rhs: &HexBinary) -> bool {
151 self.as_slice() == rhs.as_slice()
152 }
153}
154
155impl PartialEq<CanonicalAddr> for HexBinary {
157 fn eq(&self, rhs: &CanonicalAddr) -> bool {
158 self.as_slice() == rhs.0.as_slice()
159 }
160}
161
162impl From<&[u8]> for CanonicalAddr {
163 fn from(source: &[u8]) -> Self {
164 Self(source.into())
165 }
166}
167
168impl<const LENGTH: usize> From<&[u8; LENGTH]> for CanonicalAddr {
170 fn from(source: &[u8; LENGTH]) -> Self {
171 Self(source.into())
172 }
173}
174
175impl<const LENGTH: usize> From<[u8; LENGTH]> for CanonicalAddr {
177 fn from(source: [u8; LENGTH]) -> Self {
178 Self(source.into())
179 }
180}
181
182impl From<Vec<u8>> for CanonicalAddr {
184 fn from(source: Vec<u8>) -> Self {
185 Self(source.into())
186 }
187}
188
189impl From<CanonicalAddr> for Vec<u8> {
191 fn from(source: CanonicalAddr) -> Vec<u8> {
192 source.0.into()
193 }
194}
195
196impl From<Binary> for CanonicalAddr {
198 fn from(source: Binary) -> Self {
199 Self(source)
200 }
201}
202
203impl From<CanonicalAddr> for Binary {
205 fn from(source: CanonicalAddr) -> Binary {
206 source.0
207 }
208}
209
210impl From<HexBinary> for CanonicalAddr {
212 fn from(source: HexBinary) -> Self {
213 Self(source.into())
214 }
215}
216
217impl From<CanonicalAddr> for HexBinary {
219 fn from(source: CanonicalAddr) -> HexBinary {
220 source.0.into()
221 }
222}
223
224impl Deref for CanonicalAddr {
230 type Target = [u8];
231
232 fn deref(&self) -> &Self::Target {
233 self.as_slice()
234 }
235}
236
237impl CanonicalAddr {
238 pub fn as_slice(&self) -> &[u8] {
239 self.0.as_slice()
240 }
241}
242
243impl fmt::Display for CanonicalAddr {
244 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
245 for byte in self.0.as_slice() {
246 write!(f, "{byte:02X}")?;
247 }
248 Ok(())
249 }
250}
251
252#[derive(Debug, PartialEq, Eq, thiserror::Error)]
253pub enum Instantiate2AddressError {
254 InvalidChecksumLength,
256 InvalidSaltLength,
258}
259
260impl fmt::Display for Instantiate2AddressError {
261 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
262 match self {
263 Instantiate2AddressError::InvalidChecksumLength => write!(f, "invalid checksum length"),
264 Instantiate2AddressError::InvalidSaltLength => write!(f, "invalid salt length"),
265 }
266 }
267}
268
269pub fn instantiate2_address(
309 checksum: &[u8],
310 creator: &CanonicalAddr,
311 salt: &[u8],
312) -> Result<CanonicalAddr, Instantiate2AddressError> {
313 let msg = b"";
316 instantiate2_address_impl(checksum, creator, salt, msg)
317}
318
319#[doc(hidden)]
323fn instantiate2_address_impl(
324 checksum: &[u8],
325 creator: &CanonicalAddr,
326 salt: &[u8],
327 msg: &[u8],
328) -> Result<CanonicalAddr, Instantiate2AddressError> {
329 if checksum.len() != 32 {
330 return Err(Instantiate2AddressError::InvalidChecksumLength);
331 }
332
333 if salt.is_empty() || salt.len() > 64 {
334 return Err(Instantiate2AddressError::InvalidSaltLength);
335 };
336
337 let mut key = Vec::<u8>::new();
338 key.extend_from_slice(b"wasm\0");
339 key.extend_from_slice(&(checksum.len() as u64).to_be_bytes());
340 key.extend_from_slice(checksum);
341 key.extend_from_slice(&(creator.len() as u64).to_be_bytes());
342 key.extend_from_slice(creator);
343 key.extend_from_slice(&(salt.len() as u64).to_be_bytes());
344 key.extend_from_slice(salt);
345 key.extend_from_slice(&(msg.len() as u64).to_be_bytes());
346 key.extend_from_slice(msg);
347 let address_data = hash("module", &key);
348 Ok(address_data.into())
349}
350
351fn hash(ty: &str, key: &[u8]) -> Vec<u8> {
354 let inner = Sha256::digest(ty.as_bytes());
355 Sha256::new().chain(inner).chain(key).finalize().to_vec()
356}
357
358#[cfg(test)]
359mod tests {
360 use super::*;
361 use crate::assert_hash_works;
362 use crate::HexBinary;
363
364 use hex_literal::hex;
365
366 #[test]
367 fn addr_unchecked_works() {
368 let a = Addr::unchecked("123");
369 let aa = Addr::unchecked(String::from("123"));
370 let b = Addr::unchecked("be");
371 assert_eq!(a, aa);
372 assert_ne!(a, b);
373 }
374
375 #[test]
376 fn addr_as_str_works() {
377 let addr = Addr::unchecked("literal-string");
378 assert_eq!(addr.as_str(), "literal-string");
379 }
380
381 #[test]
382 fn addr_as_bytes_works() {
383 let addr = Addr::unchecked("literal-string");
384 assert_eq!(
385 addr.as_bytes(),
386 [108, 105, 116, 101, 114, 97, 108, 45, 115, 116, 114, 105, 110, 103]
387 );
388 }
389
390 #[test]
391 fn addr_implements_display() {
392 let addr = Addr::unchecked("cos934gh9034hg04g0h134");
393 let embedded = format!("Address: {addr}");
394 assert_eq!(embedded, "Address: cos934gh9034hg04g0h134");
395 assert_eq!(addr.to_string(), "cos934gh9034hg04g0h134");
396 }
397
398 #[test]
399 fn addr_implements_as_ref_for_str() {
400 let addr = Addr::unchecked("literal-string");
401 assert_eq!(addr.as_ref(), "literal-string");
402 }
403
404 #[test]
405 fn addr_implements_partial_eq_addr_ref() {
406 let addr = Addr::unchecked("cos934gh9034hg04g0h134");
407 let addr_ref = &addr;
408 let addr_ref2 = &addr;
409
410 assert_eq!(addr, addr_ref);
412 assert_eq!(addr_ref, addr);
414 assert_eq!(addr_ref, addr_ref2);
416 }
417
418 #[test]
419 fn addr_implements_into_string() {
420 let addr = Addr::unchecked("cos934gh9034hg04g0h134");
422 let string: String = addr.into();
423 assert_eq!(string, "cos934gh9034hg04g0h134");
424
425 let addr = Addr::unchecked("cos934gh9034hg04g0h134");
427 let addr_ref = &addr;
428 let string: String = addr_ref.into();
429 assert_eq!(string, "cos934gh9034hg04g0h134");
430 }
431
432 #[test]
434 fn canonical_addr_from_slice() {
435 let bytes: &[u8] = &[0u8, 187, 61, 11, 250, 0];
437 let canonical_addr_slice = CanonicalAddr::from(bytes);
438 assert_eq!(canonical_addr_slice.as_slice(), &[0u8, 187, 61, 11, 250, 0]);
439
440 let bytes: Vec<u8> = vec![0u8, 187, 61, 11, 250, 0];
442 let canonical_addr_vec = CanonicalAddr::from(bytes);
443 assert_eq!(canonical_addr_vec.as_slice(), &[0u8, 187, 61, 11, 250, 0]);
444 }
445
446 #[test]
447 fn canonical_addr_implements_partial_eq_with_binary() {
448 let addr = CanonicalAddr::from([1, 2, 3]);
449 let bin1 = Binary::from([1, 2, 3]);
450 let bin2 = Binary::from([42, 43]);
451
452 assert_eq!(addr, bin1);
453 assert_eq!(bin1, addr);
454 assert_ne!(addr, bin2);
455 assert_ne!(bin2, addr);
456 }
457
458 #[test]
459 fn canonical_addr_implements_partial_eq_with_hex_binary() {
460 let addr = CanonicalAddr::from([1, 2, 3]);
461 let bin1 = HexBinary::from([1, 2, 3]);
462 let bin2 = HexBinary::from([42, 43]);
463
464 assert_eq!(addr, bin1);
465 assert_eq!(bin1, addr);
466 assert_ne!(addr, bin2);
467 assert_ne!(bin2, addr);
468 }
469
470 #[test]
471 fn canonical_addr_implements_from_array() {
472 let array = [1, 2, 3];
473 let addr = CanonicalAddr::from(array);
474 assert_eq!(addr.as_slice(), [1, 2, 3]);
475
476 let array_ref = b"foo";
477 let addr = CanonicalAddr::from(array_ref);
478 assert_eq!(addr.as_slice(), [0x66, 0x6f, 0x6f]);
479 }
480
481 #[test]
482 fn canonical_addr_implements_from_and_to_vector() {
483 let original = vec![0u8, 187, 61, 11, 250, 0];
486 let original_ptr = original.as_ptr();
487 let addr: CanonicalAddr = original.into();
488 assert_eq!(addr.as_slice(), [0u8, 187, 61, 11, 250, 0]);
489 assert_eq!(
490 (addr.0).as_slice().as_ptr(),
491 original_ptr,
492 "must not be copied"
493 );
494
495 let original = vec![0u8, 187, 61, 11, 250, 0];
497 let original_ptr = original.as_ptr();
498 let addr = CanonicalAddr::from(original);
499 assert_eq!(addr.as_slice(), [0u8, 187, 61, 11, 250, 0]);
500 assert_eq!(
501 (addr.0).as_slice().as_ptr(),
502 original_ptr,
503 "must not be copied"
504 );
505
506 let original = CanonicalAddr::from(vec![0u8, 187, 61, 11, 250, 0]);
509 let original_ptr = (original.0).as_slice().as_ptr();
510 let vec: Vec<u8> = original.into();
511 assert_eq!(vec.as_slice(), [0u8, 187, 61, 11, 250, 0]);
512 assert_eq!(vec.as_ptr(), original_ptr, "must not be copied");
513
514 let original = CanonicalAddr::from(vec![7u8, 35, 49, 101, 0, 255]);
516 let original_ptr = (original.0).as_slice().as_ptr();
517 let vec = Vec::<u8>::from(original);
518 assert_eq!(vec.as_slice(), [7u8, 35, 49, 101, 0, 255]);
519 assert_eq!(vec.as_ptr(), original_ptr, "must not be copied");
520 }
521
522 #[test]
523 fn canonical_addr_implements_from_and_to_binary() {
524 let original = Binary::from([0u8, 187, 61, 11, 250, 0]);
526 let original_ptr = original.as_ptr();
527 let addr = CanonicalAddr::from(original);
528 assert_eq!(addr.as_slice(), [0u8, 187, 61, 11, 250, 0]);
529 assert_eq!(
530 (addr.0).as_slice().as_ptr(),
531 original_ptr,
532 "must not be copied"
533 );
534
535 let original = CanonicalAddr::from(vec![7u8, 35, 49, 101, 0, 255]);
537 let original_ptr = (original.0).as_slice().as_ptr();
538 let bin = Binary::from(original);
539 assert_eq!(bin.as_slice(), [7u8, 35, 49, 101, 0, 255]);
540 assert_eq!(bin.as_ptr(), original_ptr, "must not be copied");
541 }
542
543 #[test]
544 fn canonical_addr_implements_from_and_to_hex_binary() {
545 let original = HexBinary::from([0u8, 187, 61, 11, 250, 0]);
547 let original_ptr = original.as_ptr();
548 let addr = CanonicalAddr::from(original);
549 assert_eq!(addr.as_slice(), [0u8, 187, 61, 11, 250, 0]);
550 assert_eq!(
551 (addr.0).as_slice().as_ptr(),
552 original_ptr,
553 "must not be copied"
554 );
555
556 let original = CanonicalAddr::from(vec![7u8, 35, 49, 101, 0, 255]);
558 let original_ptr = (original.0).as_slice().as_ptr();
559 let bin = HexBinary::from(original);
560 assert_eq!(bin.as_slice(), [7u8, 35, 49, 101, 0, 255]);
561 assert_eq!(bin.as_ptr(), original_ptr, "must not be copied");
562 }
563
564 #[test]
565 fn canonical_addr_len() {
566 let bytes: &[u8] = &[0u8, 187, 61, 11, 250, 0];
567 let canonical_addr = CanonicalAddr::from(bytes);
568 assert_eq!(canonical_addr.len(), bytes.len());
569 }
570
571 #[test]
572 fn canonical_addr_is_empty() {
573 let bytes: &[u8] = &[0u8, 187, 61, 11, 250, 0];
574 let canonical_addr = CanonicalAddr::from(bytes);
575 assert!(!canonical_addr.is_empty());
576 let empty_canonical_addr = CanonicalAddr::from(vec![]);
577 assert!(empty_canonical_addr.is_empty());
578 }
579
580 #[test]
581 fn canonical_addr_implements_display() {
582 let bytes: &[u8] = &[
583 0x12, 0x03, 0xab, 0x00, 0xff,
588 ];
589 let address = CanonicalAddr::from(bytes);
590 let embedded = format!("Address: {address}");
591 assert_eq!(embedded, "Address: 1203AB00FF");
592 assert_eq!(address.to_string(), "1203AB00FF");
593 }
594
595 #[test]
596 fn canonical_addr_implements_deref() {
597 let bytes: &[u8] = &[0u8, 187, 61, 11, 250, 0];
599 let canonical_addr = CanonicalAddr::from(bytes);
600 assert_eq!(*canonical_addr, [0u8, 187, 61, 11, 250, 0]);
601
602 let bytes: &[u8] = &[0u8, 187, 61, 11, 250, 0];
604 let canonical_addr = CanonicalAddr::from(bytes);
605 assert_eq!(canonical_addr.len(), 6);
606 let canonical_addr_slice: &[u8] = &canonical_addr;
607 assert_eq!(canonical_addr_slice, &[0u8, 187, 61, 11, 250, 0]);
608 }
609
610 #[test]
613 fn canonical_addr_implements_hash_eq() {
614 let alice = CanonicalAddr::from([0, 187, 61, 11, 250, 0]);
615 let bob = CanonicalAddr::from([16, 21, 33, 0, 255, 9]);
616 assert_hash_works!(alice, bob);
617 }
618
619 fn flexible<'a>(a: impl Into<Cow<'a, Addr>>) -> String {
621 a.into().into_owned().to_string()
622 }
623
624 #[test]
625 fn addr_into_cow() {
626 let value = "wasmeucn0ur0ncny2308ry";
628 let addr = Addr::unchecked(value);
629
630 assert_eq!(value, &flexible(&addr));
632 assert_eq!(value, &flexible(addr));
634 }
635
636 #[test]
637 fn instantiate2_address_impl_works() {
638 let checksum1 =
639 HexBinary::from_hex("13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a5")
640 .unwrap();
641 let creator1 = CanonicalAddr::from(hex!("9999999999aaaaaaaaaabbbbbbbbbbcccccccccc"));
642 let salt1 = hex!("61");
643 let salt2 = hex!("aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae");
644 let msg1: &[u8] = b"";
645 let msg2: &[u8] = b"{}";
646 let msg3: &[u8] = b"{\"some\":123,\"structure\":{\"nested\":[\"ok\",true]}}";
647
648 let expected = CanonicalAddr::from(hex!(
650 "5e865d3e45ad3e961f77fd77d46543417ced44d924dc3e079b5415ff6775f847"
651 ));
652 assert_eq!(
653 instantiate2_address_impl(&checksum1, &creator1, &salt1, msg1).unwrap(),
654 expected
655 );
656
657 let expected = CanonicalAddr::from(hex!(
659 "0995499608947a5281e2c7ebd71bdb26a1ad981946dad57f6c4d3ee35de77835"
660 ));
661 assert_eq!(
662 instantiate2_address_impl(&checksum1, &creator1, &salt1, msg2).unwrap(),
663 expected
664 );
665
666 let expected = CanonicalAddr::from(hex!(
668 "83326e554723b15bac664ceabc8a5887e27003abe9fbd992af8c7bcea4745167"
669 ));
670 assert_eq!(
671 instantiate2_address_impl(&checksum1, &creator1, &salt1, msg3).unwrap(),
672 expected
673 );
674
675 let expected = CanonicalAddr::from(hex!(
677 "9384c6248c0bb171e306fd7da0993ec1e20eba006452a3a9e078883eb3594564"
678 ));
679 assert_eq!(
680 instantiate2_address_impl(&checksum1, &creator1, &salt2, b"").unwrap(),
681 expected
682 );
683
684 let empty = Vec::<u8>::new();
686 assert!(matches!(
687 instantiate2_address_impl(&checksum1, &creator1, &empty, b"").unwrap_err(),
688 Instantiate2AddressError::InvalidSaltLength
689 ));
690 let too_long = vec![0x11; 65];
691 assert!(matches!(
692 instantiate2_address_impl(&checksum1, &creator1, &too_long, b"").unwrap_err(),
693 Instantiate2AddressError::InvalidSaltLength
694 ));
695
696 let broken_cs = hex!("13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2");
698 assert!(matches!(
699 instantiate2_address_impl(&broken_cs, &creator1, &salt1, b"").unwrap_err(),
700 Instantiate2AddressError::InvalidChecksumLength
701 ));
702 let broken_cs = hex!("");
703 assert!(matches!(
704 instantiate2_address_impl(&broken_cs, &creator1, &salt1, b"").unwrap_err(),
705 Instantiate2AddressError::InvalidChecksumLength
706 ));
707 let broken_cs = hex!("13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2aaaa");
708 assert!(matches!(
709 instantiate2_address_impl(&broken_cs, &creator1, &salt1, b"").unwrap_err(),
710 Instantiate2AddressError::InvalidChecksumLength
711 ));
712 }
713
714 #[test]
715 fn instantiate2_address_impl_works_for_cosmjs_test_vectors() {
716 const COSMOS_ED25519_TESTS_JSON: &str = "./testdata/instantiate2_addresses.json";
718
719 #[derive(Deserialize, Debug)]
720 #[serde(rename_all = "camelCase")]
721 #[allow(dead_code)]
722 struct In {
723 checksum: HexBinary,
724 creator: String,
725 creator_data: HexBinary,
726 salt: HexBinary,
727 msg: Option<String>,
728 }
729
730 #[derive(Deserialize, Debug)]
731 #[serde(rename_all = "camelCase")]
732 #[allow(dead_code)]
733 struct Intermediate {
734 key: HexBinary,
735 address_data: HexBinary,
736 }
737
738 #[derive(Deserialize, Debug)]
739 #[serde(rename_all = "camelCase")]
740 #[allow(dead_code)]
741 struct Out {
742 address: String,
743 }
744
745 #[derive(Deserialize, Debug)]
746 #[allow(dead_code)]
747 struct Row {
748 #[serde(rename = "in")]
749 input: In,
750 intermediate: Intermediate,
751 out: Out,
752 }
753
754 fn read_tests() -> Vec<Row> {
755 use std::fs::File;
756 use std::io::BufReader;
757
758 let file = File::open(COSMOS_ED25519_TESTS_JSON).unwrap();
760 let reader = BufReader::new(file);
761
762 serde_json::from_reader(reader).unwrap()
763 }
764
765 for Row {
766 input,
767 intermediate,
768 out: _,
769 } in read_tests()
770 {
771 let msg = input.msg.map(|msg| msg.into_bytes()).unwrap_or_default();
772 let addr = instantiate2_address_impl(
773 &input.checksum,
774 &input.creator_data.into(),
775 &input.salt,
776 &msg,
777 )
778 .unwrap();
779 assert_eq!(addr, intermediate.address_data);
780 }
781 }
782
783 #[test]
784 fn hash_works() {
785 let expected = [
787 195, 235, 23, 251, 9, 99, 177, 195, 81, 122, 182, 124, 36, 113, 245, 156, 76, 188, 221,
788 83, 181, 192, 227, 82, 100, 177, 161, 133, 240, 160, 5, 25,
789 ];
790 assert_eq!(hash("1", &[1]), expected);
791 }
792}