use crate::error::AddressError;
use crate::utils::contains_non_hex_chars;
use crate::utils::hex_str_to_bytes;
use crate::utils::ArrayString;
use bech32::{self, FromBase32};
use bech32::{ToBase32, Variant};
use core::fmt::Display;
use serde::Deserialize;
use serde::Deserializer;
use serde::Serialize;
use serde::Serializer;
use std::fmt;
use std::fmt::{Debug, Formatter};
use std::str::FromStr;
pub const DEFAULT_PREFIX: &str = "cosmos";
#[derive(PartialEq, Eq, Copy, Clone, Hash)]
pub enum Address {
Base(BaseAddress),
Derived(DerivedAddress),
}
impl Serialize for Address {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(&self.to_string())
}
}
impl<'de> Deserialize<'de> for Address {
fn deserialize<D>(deserializer: D) -> Result<Address, D::Error>
where
D: Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
let decoded = Address::from_bech32(s);
match decoded {
Ok(d) => Ok(d),
Err(e) => Err(serde::de::Error::custom(e.to_string())),
}
}
}
#[derive(PartialEq, Eq, Copy, Clone, Hash, Deserialize, Serialize)]
pub struct BaseAddress {
bytes: [u8; 20],
prefix: ArrayString,
}
#[derive(PartialEq, Eq, Copy, Clone, Hash, Deserialize, Serialize)]
pub struct DerivedAddress {
bytes: [u8; 32],
prefix: ArrayString,
}
impl Address {
pub fn from_slice<T: Into<String>>(bytes: &[u8], prefix: T) -> Result<Self, AddressError> {
match bytes.len() {
20 => {
let mut result = [0u8; 20];
result.copy_from_slice(bytes);
Ok(Address::Base(BaseAddress::from_bytes(result, prefix)?))
}
32 => {
let mut result = [0u8; 32];
result.copy_from_slice(bytes);
Ok(Address::Derived(DerivedAddress::from_bytes(
result, prefix,
)?))
}
_ => Err(AddressError::BytesDecodeErrorWrongLength),
}
}
pub fn from_bech32(s: String) -> Result<Self, AddressError> {
let (hrp, data, _) = match bech32::decode(&s) {
Ok(val) => val,
Err(e) => {
println!("{:?}", e);
return Err(AddressError::Bech32InvalidEncoding);
}
};
let vec: Vec<u8> = match FromBase32::from_base32(&data) {
Ok(val) => val,
Err(_e) => return Err(AddressError::Bech32InvalidBase32),
};
match vec.len() {
20 => {
let mut addr = [0u8; 20];
addr.copy_from_slice(&vec);
Ok(Address::Base(BaseAddress::from_bytes(addr, &hrp)?))
}
32 => {
let mut addr = [0u8; 32];
addr.copy_from_slice(&vec);
Ok(Address::Derived(DerivedAddress::from_bytes(addr, &hrp)?))
}
_ => Err(AddressError::Bech32WrongLength),
}
}
pub fn to_bech32<T: Into<String>>(&self, hrp: T) -> Result<String, AddressError> {
let bech32 = bech32::encode(&hrp.into(), self.get_bytes().to_base32(), Variant::Bech32)?;
Ok(bech32)
}
pub fn change_prefix<T: Into<String>>(&mut self, prefix: T) -> Result<(), AddressError> {
match self {
Address::Base(base_address) => {
base_address.prefix = ArrayString::new(&prefix.into())?;
}
Address::Derived(derived_address) => {
derived_address.prefix = ArrayString::new(&prefix.into())?;
}
}
Ok(())
}
pub fn get_bytes(&self) -> &[u8] {
match self {
Address::Base(base_address) => &base_address.bytes,
Address::Derived(derived_address) => &derived_address.bytes,
}
}
pub fn to_vec(&self) -> Vec<u8> {
self.get_bytes().to_vec()
}
pub fn get_prefix(&self) -> String {
match self {
Address::Base(base_address) => base_address.prefix,
Address::Derived(derived_address) => derived_address.prefix,
}
.to_string()
}
}
impl FromStr for Address {
type Err = AddressError;
fn from_str(s: &str) -> Result<Self, AddressError> {
if contains_non_hex_chars(s) {
Address::from_bech32(s.to_string())
} else {
match hex_str_to_bytes(s) {
Ok(bytes) => Address::from_slice(&bytes, DEFAULT_PREFIX),
Err(e) => Err(AddressError::HexDecodeError(e)),
}
}
}
}
impl Display for Address {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let display = self.to_bech32(self.get_prefix()).unwrap();
write!(f, "{}", display).expect("Unable to write");
Ok(())
}
}
impl Debug for Address {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.to_bech32(self.get_prefix()).unwrap())
}
}
impl BaseAddress {
pub fn from_bytes<T: Into<String>>(bytes: [u8; 20], prefix: T) -> Result<Self, AddressError> {
Ok(Self {
bytes,
prefix: ArrayString::new(&prefix.into())?,
})
}
}
impl DerivedAddress {
pub fn from_bytes<T: Into<String>>(bytes: [u8; 32], prefix: T) -> Result<Self, AddressError> {
Ok(Self {
bytes,
prefix: ArrayString::new(&prefix.into())?,
})
}
}
#[test]
fn test_bech32() {
let address = Address::from_slice(&[0; 20], "cosmos").unwrap();
assert_eq!(
address.to_bech32("cosmos").unwrap(),
"cosmos1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqnrql8a"
);
let decoded = Address::from_bech32("cosmos1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqnrql8a".to_string())
.expect("Unable to decode");
assert_eq!(address, decoded);
Address::from_bech32("cosmos1vlms2r8f6x7yxjh3ynyzc7ckarqd8a96ckjvrp".to_string())
.expect("Failed to decode");
}
#[test]
fn test_default_prefix() {
Address::from_slice(&[0; 20], DEFAULT_PREFIX).unwrap();
}
#[test]
fn test_parse() {
let address = Address::from_slice(&[0; 20], "cosmos").unwrap();
let decoded = "cosmos1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqnrql8a"
.parse()
.expect("Unable to decode");
assert_eq!(address, decoded);
let _test: Address = "cosmos1vlms2r8f6x7yxjh3ynyzc7ckarqd8a96ckjvrp"
.parse()
.unwrap();
}