chia_sdk_utils/
address.rs1use bech32::{u5, Variant};
2use chia_protocol::Bytes32;
3use thiserror::Error;
4
5#[derive(Error, Debug, Clone, Copy, PartialEq, Eq)]
6pub enum AddressError {
7 #[error("encoding is not bech32m")]
8 InvalidFormat,
9
10 #[error("wrong length, expected 32 bytes but found {0}")]
11 WrongLength(usize),
12
13 #[error("error when decoding address: {0}")]
14 Decode(#[from] bech32::Error),
15}
16
17#[derive(Debug, Clone, PartialEq, Eq)]
18pub struct Address {
19 pub puzzle_hash: Bytes32,
20 pub prefix: String,
21}
22
23impl Address {
24 pub fn new(puzzle_hash: Bytes32, prefix: String) -> Self {
25 Self {
26 puzzle_hash,
27 prefix,
28 }
29 }
30
31 pub fn decode(address: &str) -> Result<Self, AddressError> {
32 let (hrp, data, variant) = bech32::decode(address)?;
33
34 if variant != Variant::Bech32m {
35 return Err(AddressError::InvalidFormat);
36 }
37
38 let data = bech32::convert_bits(&data, 5, 8, false)?;
39 let length = data.len();
40 let puzzle_hash = data
41 .try_into()
42 .map_err(|_| AddressError::WrongLength(length))?;
43
44 Ok(Self {
45 puzzle_hash,
46 prefix: hrp,
47 })
48 }
49
50 pub fn encode(&self) -> Result<String, AddressError> {
51 let data = bech32::convert_bits(&self.puzzle_hash, 8, 5, true)
52 .unwrap()
53 .into_iter()
54 .map(u5::try_from_u8)
55 .collect::<Result<Vec<_>, bech32::Error>>()?;
56 Ok(bech32::encode(&self.prefix, data, Variant::Bech32m)?)
57 }
58}
59
60#[cfg(test)]
61mod tests {
62 use super::*;
63
64 fn check_addr(expected: &str) {
65 let info = Address::decode(expected).unwrap();
66 let actual = info.encode().unwrap();
67 assert_eq!(actual, expected);
68 }
69
70 #[test]
71 fn test_addresses() {
72 check_addr("xch1a0t57qn6uhe7tzjlxlhwy2qgmuxvvft8gnfzmg5detg0q9f3yc3s2apz0h");
73 check_addr("xch1ftxk2v033kv94ueucp0a34sgt9398vle7l7g3q9k4leedjmmdysqvv6q96");
74 check_addr("xch1ay273ctc9c6nxmzmzsup28scrce8ney84j4nlewdlaxqs22v53ksxgf38f");
75 check_addr("xch1avnwmy2fuesq7h2jnxehlrs9msrad9uuvrhms35k2pqwmjv56y5qk7zm6v");
76 }
77
78 #[test]
79 fn test_invalid_addresses() {
80 assert_eq!(
81 Address::decode("hello there!"),
82 Err(AddressError::Decode(bech32::Error::MissingSeparator))
83 );
84 assert_eq!(
85 Address::decode("bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq"),
86 Err(AddressError::InvalidFormat)
87 );
88 }
89}