hpl_interface/types/
bech32.rs

1use 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}