babylon_apis/
lib.rs

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
26/// Converts a bech32 address to a canonical address
27/// ported from cosmwasm-std/testing/mock.rs
28pub fn to_canonical_addr(addr: &str, prefix: &str) -> Result<CanonicalAddr, StakingApiError> {
29    // decode bech32 address
30    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    // check bech32 prefix
36    if decoded_prefix != prefix {
37        return Err(StakingApiError::InvalidAddressString(
38            "wrong bech32 prefix".to_string(),
39        ));
40    }
41    // check bech32 variant
42    if variant == Variant::Bech32m {
43        return Err(StakingApiError::InvalidAddressString(
44            "wrong bech32 variant".to_string(),
45        ));
46    }
47    // check bech32 data
48    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    // return canonical address
56    Ok(bytes.into())
57}
58
59// Hash function to replace Cosmos SDK crypto.AddressHash and Hash.
60fn 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
67/// Generates a Cosmos SDK compatible module address from a module name
68pub fn to_module_canonical_addr(module_name: &str) -> CanonicalAddr {
69    CanonicalAddr::from(hash("", module_name.as_bytes()))
70}
71
72/// Converts a CanonicalAddr to a Cosmos SDK compatible Bech32 encoded Addr with
73/// the given prefix
74pub 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}