use std::hash::{Hash, Hasher};
use std::ops::Deref;
use multiversx_sc::api::ManagedTypeApi;
use multiversx_sc::types::ManagedAddress;
use multiversx_sc_codec::{DecodeError, TopDecode, TopDecodeInput};
use multiversx_sc_scenario::api::StaticApi;
use multiversx_sc_scenario::scenario_model::AddressValue;
use multiversx_sdk::data::address::Address as SDKAddress;
use serde::{Deserialize, Deserializer, Serialize};
use serde::de::Error;
use crate::error::AddressError;
use crate::error::DataError;
use crate::types::managed::ManagedConvertible;
use crate::types::native::NativeConvertible;
#[derive(Serialize, Clone, Debug)]
pub struct Address(SDKAddress);
impl PartialEq for Address {
fn eq(&self, other: &Self) -> bool {
self.to_bytes() == other.to_bytes()
}
}
impl Address {
pub fn from_bech32_string(bech32: &str) -> Result<Address, DataError> {
let Ok(address) = SDKAddress::from_bech32_string(bech32) else { return Err(AddressError::InvalidBech32String { invalid_value: bech32.to_string() }.into()) };
Ok(Address(address))
}
pub fn from_bytes(bytes: [u8; 32]) -> Address {
Address(SDKAddress::from_bytes(bytes))
}
pub fn to_bech32_string(&self) -> Result<String, DataError> {
let Ok(string) = self.0.to_bech32_string() else {
return Err(AddressError::CannotConvertToBech32String.into())
};
Ok(string)
}
pub fn to_bytes(&self) -> [u8; 32] {
self.0.to_bytes()
}
}
impl Deref for Address {
type Target = multiversx_sdk::data::address::Address;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl Hash for Address {
fn hash<H: Hasher>(&self, state: &mut H) {
self.0.to_bytes().hash(state)
}
}
impl<M: ManagedTypeApi> NativeConvertible for ManagedAddress<M> {
type Native = Address;
fn to_native(&self) -> Self::Native {
Address(SDKAddress::from_bytes(self.to_byte_array()))
}
}
impl NativeConvertible for Address {
type Native = Self;
fn to_native(&self) -> Self::Native {
self.clone()
}
}
impl ManagedConvertible<ManagedAddress<StaticApi>> for Address {
fn to_managed(&self) -> ManagedAddress<StaticApi> {
ManagedAddress::from_address(&multiversx_sc::types::Address::from(self.to_bytes()))
}
}
impl TopDecode for Address {
fn top_decode<I>(input: I) -> Result<Self, DecodeError> where I: TopDecodeInput {
let bytes = ManagedAddress::<StaticApi>::top_decode(input)?.to_byte_array();
Ok(Address(SDKAddress::from_bytes(bytes)))
}
}
impl From<&Address> for AddressValue {
fn from(value: &Address) -> Self {
(&multiversx_sc::types::Address::from(value.0.to_bytes())).into()
}
}
impl From<SDKAddress> for Address {
fn from(value: SDKAddress) -> Self {
Address::from_bytes(value.to_bytes())
}
}
impl From<&SDKAddress> for Address {
fn from(value: &SDKAddress) -> Self {
Address::from_bytes(value.to_bytes())
}
}
impl From<&multiversx_sc::types::Address> for Address {
fn from(value: &multiversx_sc::types::Address) -> Self {
Address::from_bytes(*value.as_array())
}
}
impl From<multiversx_sc::types::Address> for Address {
fn from(value: multiversx_sc::types::Address) -> Self {
Address::from_bytes(*value.as_array())
}
}
impl From<Address> for multiversx_sc::types::Address {
fn from(value: Address) -> Self {
multiversx_sc::types::Address::from(value.to_bytes())
}
}
impl From<&str> for Address {
fn from(value: &str) -> Self {
if value.starts_with("erd1") {
Address::from_bech32_string(value).unwrap()
} else {
(&AddressValue::from(value).value).into()
}
}
}
impl From<&String> for Address {
fn from(value: &String) -> Self {
From::<&str>::from(value)
}
}
impl<'a> Deserialize<'a> for Address {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'a> {
let string = String::deserialize(deserializer)?;
let Ok(address) = Address::from_bech32_string(&string) else {
return Err(D::Error::custom(format!("Cannot parse bech32 address : {string}")))
};
Ok(address)
}
}
#[cfg(test)]
mod tests {
use multiversx_sc::types::ManagedAddress;
use multiversx_sc_scenario::api::StaticApi;
use crate::{Address, AddressError, DataError};
use crate::types::managed::ManagedConvertible;
use crate::types::native::NativeConvertible;
#[test]
fn test_managed_address_to_native() {
let expected = Address::from_bech32_string("erd1qqqqqqqqqqqqqpgq7ykazrzd905zvnlr88dpfw06677lxe9w0n4suz00uh").unwrap();
let managed_address: ManagedAddress<StaticApi> = ManagedAddress::from(expected.to_bytes());
let native = managed_address.to_native();
assert_eq!(
native.to_bytes(),
expected.to_bytes()
)
}
#[test]
fn test_managed_address_to_managed() {
let address = Address::from_bech32_string("erd1qqqqqqqqqqqqqpgq7ykazrzd905zvnlr88dpfw06677lxe9w0n4suz00uh").unwrap();
let managed = address.to_managed();
assert_eq!(
address.to_bytes(),
managed.to_byte_array()
)
}
#[test]
fn test_from_bech32_string_valid_address() {
Address::from_bech32_string("erd1an4xpn58j7ymd58m2jznr32t0vmas75egrdfa8mta6fzvqn9tkxq4jvghn").unwrap();
}
#[test]
fn test_from_bech32_string_invalid_address() {
let str = "erd1an4xpn58j7ymd58m2jznr32t0vmas75egrdfa8mta6fzvqn9tkxq4jvghm";
let error = Address::from_bech32_string(str).unwrap_err();
let expected = DataError::Address(AddressError::InvalidBech32String { invalid_value: str.to_string() });
assert_eq!(error, expected);
}
#[test]
fn test_from_bech32_string_invalid_address_bad_length() {
let str = "erd1an4xpn58j7ymd58m2jznr32t";
let error = Address::from_bech32_string(str).unwrap_err();
let expected = DataError::Address(AddressError::InvalidBech32String { invalid_value: str.to_string() });
assert_eq!(error, expected);
}
}