use sp_core::crypto::{AccountId32, Ss58Codec};
use std::str;
use crate::keypair::Keypair;
pub(crate) const SS58_FORMAT: u8 = 42;
pub fn get_ss58_format(ss58_address: &str) -> Result<u16, &'static str> {
match <AccountId32 as Ss58Codec>::from_ss58check_with_version(ss58_address) {
Ok((_, format)) => Ok(u16::from(format)),
Err(_) => Err("Invalid SS58 address."),
}
}
pub fn is_valid_ss58_address(address: &str) -> bool {
if address.is_empty() {
return false;
}
sp_core::sr25519::Public::from_ss58check(address).is_ok()
}
pub fn is_string_valid_ed25519_pubkey(public_key: &str) -> bool {
if public_key.len() != 64 && public_key.len() != 66 {
return false;
}
let pub_key_var = Some(public_key.to_string());
let keypair_result = Keypair::new(None, pub_key_var, None, SS58_FORMAT, None, 1);
match keypair_result {
Ok(keypair) => keypair.ss58_address().is_some(),
Err(_) => false,
}
}
pub fn are_bytes_valid_ed25519_pubkey(public_key: &[u8]) -> bool {
if public_key.len() != 32 {
return false;
}
let pub_key_var = Some(hex::encode(public_key));
let keypair_result = Keypair::new(None, pub_key_var, None, SS58_FORMAT, None, 1);
match keypair_result {
Ok(keypair) => keypair.ss58_address().is_some(),
Err(_) => false,
}
}
pub fn is_valid_bittensor_address_or_public_key(address: &str) -> bool {
if address.starts_with("0x") {
if let Ok(bytes) = hex::decode(&address[2..]) {
are_bytes_valid_ed25519_pubkey(&bytes)
} else {
is_valid_ss58_address(address)
}
} else {
is_valid_ss58_address(address)
}
}
#[cfg(not(feature = "python-bindings"))]
pub fn print(s: String) {
use std::io::{self, Write};
print!("{}", s);
io::stdout().flush().unwrap();
}
#[cfg(feature = "python-bindings")]
pub fn print(s: String) {
use pyo3::types::{PyDict, PyDictMethods};
use std::ffi::CString;
pyo3::Python::attach(|py| {
let locals = PyDict::new(py);
locals.set_item("s", s).unwrap();
let code = CString::new(
r#"
import sys
print(s, end='')
sys.stdout.flush()
"#,
)
.unwrap();
py.run(&code, None, Some(&locals)).unwrap();
});
}
pub fn prompt(prompt: String) -> Option<String> {
use std::io::{self, Write};
print!("{}", prompt);
io::stdout().flush().ok()?;
let mut input = String::new();
match io::stdin().read_line(&mut input) {
Ok(_) => Some(input.trim().to_string()),
Err(_) => None,
}
}
pub fn prompt_password(prompt: String) -> Option<String> {
use rpassword::read_password;
use std::io::{self, Write};
print!("{}", prompt);
io::stdout().flush().ok()?;
match read_password() {
Ok(password) => Some(password.trim().to_string()),
Err(_) => None,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_get_ss58_format_success() {
let test_address = "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty";
assert!(is_valid_ss58_address(test_address));
}
}