hpl_interface/types/
bech32.rs1use bech32::{FromBase32, ToBase32};
2use cosmwasm_std::{Addr, StdError, StdResult};
3
4pub fn bech32_to_h256(target: &str) -> StdResult<[u8; 32]> {
5 let raw_addr = bech32_decode(target)?;
6
7 let mut addr = [0u8; 32];
8 addr[32 - raw_addr.len()..].copy_from_slice(&raw_addr);
9
10 Ok(addr)
11}
12
13pub fn bech32_decode(target: &str) -> StdResult<Vec<u8>> {
14 let (_, raw_addr_u5, _) = bech32::decode(target)
15 .map_err(|e| StdError::generic_err(format!("invalid bech32 bytes. err: {e}")))?;
16
17 let raw_addr = Vec::<u8>::from_base32(&raw_addr_u5)
18 .map_err(|e| StdError::generic_err(format!("failed to parse [u5] to [u8]. err: {e}")))?;
19
20 Ok(raw_addr)
21}
22
23pub fn bech32_encode(hrp: &str, raw_addr: &[u8]) -> StdResult<Addr> {
24 if raw_addr.len() != 32 && raw_addr.len() != 20 {
25 return Err(StdError::generic_err(format!(
26 "invalid raw address length. expected: 32 or 20. got: {}",
27 raw_addr.len()
28 )));
29 }
30
31 if raw_addr.len() == 32 {
32 let mut bz = 0u128.to_be_bytes();
33 bz[4..].copy_from_slice(&raw_addr[0..12]);
34 let check = u128::from_be_bytes(bz);
35
36 if check == 0 {
37 return bech32_encode(hrp, &raw_addr[12..]);
38 }
39 }
40
41 let enc_addr = bech32::encode(hrp, raw_addr.to_base32(), bech32::Variant::Bech32)
42 .map_err(|e| StdError::generic_err(format!("invalid bech32 address. err: {e}")))?;
43
44 Ok(Addr::unchecked(enc_addr))
45}
46
47#[cfg(test)]
48mod tests {
49 use cosmwasm_std::HexBinary;
50 use rstest::rstest;
51
52 use crate::types::bech32_to_h256;
53
54 use super::{bech32_decode, bech32_encode};
55
56 #[test]
57 fn addr_conv() {
58 println!(
59 "{}",
60 bech32_encode(
61 "neutron",
62 &bech32_decode("osmo1mhnkm6fwaq53yzu7c0r3khhy60v04vse4c6gk5").unwrap(),
63 )
64 .unwrap()
65 );
66 }
67
68 #[test]
69 fn conv() {
70 let addr = "dual1dwnrgwsf5c9vqjxsax04pdm0mx007yrraj2dgn";
71 let addr_bin = bech32_decode(addr).unwrap();
72 let addr_hex = HexBinary::from(addr_bin).to_hex();
73
74 println!("{}", addr_hex);
75 }
76
77 #[test]
78 fn conv_rev() {
79 let addr_hex = "f3aa0d652226e21ae35cd9035c492ae41725edc9036edf0d6a48701b153b90a0";
80 let addr_bin = HexBinary::from_hex(addr_hex).unwrap();
81 let addr = bech32_encode("dual", &addr_bin).unwrap();
82
83 println!("{}", addr);
84 }
85
86 #[rstest]
87 #[case(
88 "osmo",
89 "osmo1466nf3zuxpya8q9emxukd7vftaf6h4psr0a07srl5zw74zh84yjqkk0zfx"
90 )]
91 #[case("osmo", "osmo14n3a65fnqz9jve85l23al6m3pjugf0atvrfqh5")]
92 #[case(
93 "neutron",
94 "neutron1gajw625kz8el4ayk8fwpy7r6ew0m7zrg9jdd6grg85fle39shuxqezuz2c"
95 )]
96 #[case("neutron", "neutron1xle8l3h0wkcp6tsxmkc6n4vqyfkhwnukevwwsk")]
97 fn test_decode_encode(#[case] hrp: &str, #[case] src_addr: &str) {
98 let dec_addr = bech32_to_h256(src_addr).unwrap();
99 let enc_addr = bech32_encode(hrp, &dec_addr).unwrap();
100
101 assert_eq!(src_addr, enc_addr.as_str());
102 }
103
104 #[rstest]
105 #[case("osmo", "osmo1d6a3j0kkpc8eac0j8h6ypyevfz8hd3qnuqjrc5")]
106 #[case("neutron", "neutron1d6a3j0kkpc8eac0j8h6ypyevfz8hd3qnsyg35p")]
107 fn test_decode_encode_acc(#[case] hrp: &str, #[case] src_addr: &str) {
108 let dec_addr = bech32_decode(src_addr).unwrap();
109 let enc_addr = bech32_encode(hrp, &dec_addr).unwrap();
110
111 assert_eq!(src_addr, enc_addr.as_str());
112 }
113
114 #[rstest]
115 #[case(&[
116 "cosmos1d6a3j0kkpc8eac0j8h6ypyevfz8hd3qn5mpnwx",
117 "axelar1d6a3j0kkpc8eac0j8h6ypyevfz8hd3qns4hm98",
118 "osmo1d6a3j0kkpc8eac0j8h6ypyevfz8hd3qnuqjrc5",
119 "neutron1d6a3j0kkpc8eac0j8h6ypyevfz8hd3qnsyg35p"
120 ])]
121 fn test_acc_cross(#[case] addrs: &[&str]) {
122 for (i, test_target_addr) in addrs.iter().enumerate() {
123 let mut test_addr_group = addrs.to_vec();
124 test_addr_group.remove(i);
125
126 let test_target_addr_bin = bech32_decode(test_target_addr).unwrap();
127
128 for test_addr in test_addr_group {
129 let hrp = test_addr.split('1').collect::<Vec<_>>()[0];
130
131 let encoded = bech32_encode(hrp, &test_target_addr_bin).unwrap();
132 assert_eq!(test_addr, encoded.as_str());
133 }
134 }
135 }
136}