use alloc::string::String;
use alloc::vec::Vec;
use core::fmt;
use miden_protocol::Felt;
use miden_protocol::account::AccountId;
use super::address::{AddressConversionError, EthAddress};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct EthEmbeddedAccountId(AccountId);
impl EthEmbeddedAccountId {
pub fn new(bytes: [u8; 20]) -> Result<Self, AddressConversionError> {
Self::try_from_eth_address(EthAddress::new(bytes))
}
pub fn from_hex(hex_str: &str) -> Result<Self, AddressConversionError> {
let addr = EthAddress::from_hex(hex_str)?;
Self::try_from_eth_address(addr)
}
pub const fn from_account_id(account_id: AccountId) -> Self {
Self(account_id)
}
pub fn try_from_eth_address(addr: EthAddress) -> Result<Self, AddressConversionError> {
let bytes = addr.into_bytes();
let (prefix, suffix) = bytes20_to_prefix_suffix(bytes)?;
let prefix_felt =
Felt::try_from(prefix).map_err(|_| AddressConversionError::FeltOutOfField)?;
let suffix_felt =
Felt::try_from(suffix).map_err(|_| AddressConversionError::FeltOutOfField)?;
let account_id = AccountId::try_from_elements(suffix_felt, prefix_felt)
.map_err(|_| AddressConversionError::InvalidAccountId)?;
Ok(Self(account_id))
}
pub const fn to_account_id(&self) -> &AccountId {
&self.0
}
pub const fn into_account_id(self) -> AccountId {
self.0
}
pub fn to_eth_address(&self) -> EthAddress {
let mut out = [0u8; 20];
out[4..12].copy_from_slice(&self.0.prefix().as_u64().to_be_bytes());
out[12..20].copy_from_slice(&self.0.suffix().as_canonical_u64().to_be_bytes());
EthAddress::new(out)
}
pub fn to_bytes(&self) -> [u8; 20] {
self.to_eth_address().into_bytes()
}
pub fn to_bytes32(&self) -> [u8; 32] {
let mut out = [0u8; 32];
out[12..32].copy_from_slice(&self.to_bytes());
out
}
pub fn to_hex(&self) -> String {
self.to_eth_address().to_hex()
}
pub fn to_elements(&self) -> Vec<Felt> {
self.to_eth_address().to_elements()
}
}
impl fmt::Display for EthEmbeddedAccountId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.to_eth_address())
}
}
impl TryFrom<EthAddress> for EthEmbeddedAccountId {
type Error = AddressConversionError;
fn try_from(addr: EthAddress) -> Result<Self, Self::Error> {
Self::try_from_eth_address(addr)
}
}
impl From<EthEmbeddedAccountId> for EthAddress {
fn from(embedded: EthEmbeddedAccountId) -> Self {
embedded.to_eth_address()
}
}
impl TryFrom<[u8; 20]> for EthEmbeddedAccountId {
type Error = AddressConversionError;
fn try_from(bytes: [u8; 20]) -> Result<Self, Self::Error> {
Self::new(bytes)
}
}
impl From<EthEmbeddedAccountId> for [u8; 20] {
fn from(embedded: EthEmbeddedAccountId) -> Self {
embedded.to_bytes()
}
}
impl From<AccountId> for EthEmbeddedAccountId {
fn from(account_id: AccountId) -> Self {
EthEmbeddedAccountId::from_account_id(account_id)
}
}
impl From<EthEmbeddedAccountId> for AccountId {
fn from(embedded: EthEmbeddedAccountId) -> Self {
embedded.0
}
}
fn bytes20_to_prefix_suffix(bytes: [u8; 20]) -> Result<(u64, u64), AddressConversionError> {
if bytes[0..4] != [0, 0, 0, 0] {
return Err(AddressConversionError::NonZeroBytePrefix);
}
let prefix = u64::from_be_bytes(bytes[4..12].try_into().unwrap());
let suffix = u64::from_be_bytes(bytes[12..20].try_into().unwrap());
Ok((prefix, suffix))
}