use std::collections::HashMap;
use crypto::{
hashes::{blake2b::Blake2b256, Digest},
keys::{bip39::wordlist, slip10::Seed},
utils,
};
use zeroize::Zeroize;
use super::Client;
use crate::{
client::{Error, Result},
types::block::{
address::{Address, Ed25519Address},
output::{AliasId, NftId},
payload::TaggedDataPayload,
},
};
pub fn bech32_to_hex(bech32: &str) -> Result<String> {
let address = Address::try_from_bech32(bech32)?;
let hex_string = match address {
Address::Ed25519(ed) => ed.to_string(),
Address::Alias(alias) => alias.to_string(),
Address::Nft(nft) => nft.to_string(),
};
Ok(hex_string)
}
pub fn hex_to_bech32(hex: &str, bech32_hrp: &str) -> Result<String> {
let address: Ed25519Address = hex.parse::<Ed25519Address>()?;
Ok(Address::Ed25519(address).to_bech32(bech32_hrp))
}
pub fn hex_public_key_to_bech32_address(hex: &str, bech32_hrp: &str) -> Result<String> {
let public_key: [u8; Ed25519Address::LENGTH] = prefix_hex::decode(hex)?;
let address = Blake2b256::digest(public_key)
.try_into()
.map_err(|_e| Error::Blake2b256("hashing the public key failed."))?;
let address: Ed25519Address = Ed25519Address::new(address);
Ok(Address::Ed25519(address).to_bech32(bech32_hrp))
}
pub fn generate_mnemonic() -> Result<String> {
let mut entropy = [0u8; 32];
utils::rand::fill(&mut entropy)?;
let mnemonic = wordlist::encode(&entropy, &crypto::keys::bip39::wordlist::ENGLISH)
.map_err(|e| crate::client::Error::InvalidMnemonic(format!("{e:?}")))?;
entropy.zeroize();
Ok(mnemonic)
}
pub fn mnemonic_to_hex_seed(mnemonic: &str) -> Result<String> {
let mnemonic = mnemonic.trim();
verify_mnemonic(mnemonic)?;
let mut mnemonic_seed = [0u8; 64];
crypto::keys::bip39::mnemonic_to_seed(mnemonic, "", &mut mnemonic_seed);
Ok(prefix_hex::encode(mnemonic_seed))
}
pub fn mnemonic_to_seed(mnemonic: &str) -> Result<Seed> {
let mnemonic = mnemonic.trim();
verify_mnemonic(mnemonic)?;
let mut mnemonic_seed = [0u8; 64];
crypto::keys::bip39::mnemonic_to_seed(mnemonic, "", &mut mnemonic_seed);
Ok(Seed::from_bytes(&mnemonic_seed))
}
pub fn verify_mnemonic(mnemonic: &str) -> Result<()> {
crypto::keys::bip39::wordlist::verify(mnemonic, &crypto::keys::bip39::wordlist::ENGLISH)
.map_err(|e| crate::client::Error::InvalidMnemonic(format!("{e:?}")))?;
Ok(())
}
pub async fn request_funds_from_faucet(url: &str, bech32_address: &str) -> Result<String> {
let mut map = HashMap::new();
map.insert("address", bech32_address);
let client = reqwest::Client::new();
let faucet_response = client.post(url).json(&map).send().await?.text().await?;
Ok(faucet_response)
}
impl Client {
pub fn bech32_to_hex(bech32: &str) -> crate::client::Result<String> {
bech32_to_hex(bech32)
}
pub async fn hex_to_bech32(&self, hex: &str, bech32_hrp: Option<&str>) -> crate::client::Result<String> {
match bech32_hrp {
Some(hrp) => Ok(hex_to_bech32(hex, hrp)?),
None => Ok(hex_to_bech32(hex, &self.get_bech32_hrp().await?)?),
}
}
pub async fn alias_id_to_bech32(
&self,
alias_id: AliasId,
bech32_hrp: Option<&str>,
) -> crate::client::Result<String> {
match bech32_hrp {
Some(hrp) => Ok(alias_id.to_bech32(hrp)),
None => Ok(alias_id.to_bech32(&self.get_bech32_hrp().await?)),
}
}
pub async fn nft_id_to_bech32(&self, nft_id: NftId, bech32_hrp: Option<&str>) -> crate::client::Result<String> {
match bech32_hrp {
Some(hrp) => Ok(nft_id.to_bech32(hrp)),
None => Ok(nft_id.to_bech32(&self.get_bech32_hrp().await?)),
}
}
pub async fn hex_public_key_to_bech32_address(
&self,
hex: &str,
bech32_hrp: Option<&str>,
) -> crate::client::Result<String> {
match bech32_hrp {
Some(hrp) => Ok(hex_public_key_to_bech32_address(hex, hrp)?),
None => Ok(hex_public_key_to_bech32_address(hex, &self.get_bech32_hrp().await?)?),
}
}
pub fn generate_mnemonic() -> Result<String> {
generate_mnemonic()
}
pub fn mnemonic_to_seed(mnemonic: &str) -> Result<Seed> {
mnemonic_to_seed(mnemonic)
}
pub fn mnemonic_to_hex_seed(mnemonic: &str) -> Result<String> {
mnemonic_to_hex_seed(mnemonic)
}
pub fn tag_to_utf8(payload: &TaggedDataPayload) -> Result<String> {
String::from_utf8(payload.tag().to_vec()).map_err(|_| Error::TaggedData("found invalid UTF-8".to_string()))
}
pub fn data_to_utf8(payload: &TaggedDataPayload) -> Result<String> {
String::from_utf8(payload.data().to_vec()).map_err(|_| Error::TaggedData("found invalid UTF-8".to_string()))
}
pub fn tagged_data_to_utf8(payload: &TaggedDataPayload) -> Result<(String, String)> {
Ok((Self::tag_to_utf8(payload)?, Self::data_to_utf8(payload)?))
}
}