1use bech32::Variant::Bech32;
2use bech32::{FromBase32, ToBase32, Variant};
3use sha2::Digest;
4
5use cosmwasm_std::{Addr, Binary, CanonicalAddr, CustomQuery, QueryRequest, WasmQuery};
6
7use error::StakingApiError;
8
9pub mod btc_staking_api;
10pub mod error;
11pub mod finality_api;
12mod validate;
13
14pub type Bytes = Vec<u8>;
15
16pub use validate::Validate;
17
18pub fn encode_raw_query<T: Into<Binary>, Q: CustomQuery>(addr: &Addr, key: T) -> QueryRequest<Q> {
19 WasmQuery::Raw {
20 contract_addr: addr.into(),
21 key: key.into(),
22 }
23 .into()
24}
25
26pub fn to_canonical_addr(addr: &str, prefix: &str) -> Result<CanonicalAddr, StakingApiError> {
29 let decode_result = bech32::decode(addr);
31 if let Err(e) = decode_result {
32 return Err(StakingApiError::InvalidAddressString(e.to_string()));
33 }
34 let (decoded_prefix, decoded_data, variant) = decode_result.unwrap();
35 if decoded_prefix != prefix {
37 return Err(StakingApiError::InvalidAddressString(
38 "wrong bech32 prefix".to_string(),
39 ));
40 }
41 if variant == Variant::Bech32m {
43 return Err(StakingApiError::InvalidAddressString(
44 "wrong bech32 variant".to_string(),
45 ));
46 }
47 let bytes = Vec::<u8>::from_base32(&decoded_data)
49 .map_err(|_| StakingApiError::InvalidAddressString("invalid bech32 data".to_string()))?;
50 if bytes.is_empty() || bytes.len() > 255 {
51 return Err(StakingApiError::InvalidAddressString(
52 "Invalid canonical address length".to_string(),
53 ));
54 }
55 Ok(bytes.into())
57}
58
59fn hash(namespace: &str, input: &[u8]) -> Vec<u8> {
61 let mut hasher = sha2::Sha256::new();
62 sha2::digest::Update::update(&mut hasher, namespace.as_bytes());
63 sha2::digest::Update::update(&mut hasher, input);
64 hasher.finalize().to_vec()
65}
66
67pub fn to_module_canonical_addr(module_name: &str) -> CanonicalAddr {
69 CanonicalAddr::from(hash("", module_name.as_bytes()))
70}
71
72pub fn to_bech32_addr(prefix: &str, addr: &CanonicalAddr) -> Result<Addr, StakingApiError> {
75 let bech32_addr = bech32::encode(prefix, &addr.as_slice().to_base32()[..32], Bech32)
76 .map_err(|e| StakingApiError::InvalidAddressString(e.to_string()))?;
77 Ok(Addr::unchecked(bech32_addr))
78}