use std::fmt;
use std::str::FromStr;
use crate::{
caip2::ChainId,
caip10::AccountId,
did::DidParseError,
};
#[derive(Clone, Debug, PartialEq)]
pub struct DidPkh {
account_id: AccountId,
}
impl DidPkh {
pub(super) const METHOD: &'static str = "pkh";
pub(super) fn account_id(&self) -> &AccountId {
&self.account_id
}
pub fn address(&self) -> String {
self.account_id.address.clone()
}
pub fn from_ethereum_address(address: &str) -> Self {
let chain_id = ChainId::ethereum_mainnet();
let account_id = AccountId {
chain_id,
address: address.to_lowercase(),
};
Self { account_id }
}
pub fn chain_id(&self) -> ChainId {
self.account_id.chain_id.clone()
}
pub fn verification_method_id(&self) -> String {
format!("{self}#blockchainAccountId")
}
}
impl fmt::Display for DidPkh {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(formatter, "did:{}:{}", Self::METHOD, self.account_id)
}
}
impl FromStr for DidPkh {
type Err = DidParseError;
fn from_str(value: &str) -> Result<Self, Self::Err> {
let account_id_str = value.strip_prefix("did:pkh:")
.ok_or(DidParseError)?;
let account_id: AccountId = account_id_str.parse()
.map_err(|_| DidParseError)?;
Ok(Self { account_id })
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_from_ethereum_address() {
let address = "0xB9C5714089478a327F09197987f16f9E5d936E8a";
let did = DidPkh::from_ethereum_address(address);
assert_eq!(did.chain_id(), ChainId::ethereum_mainnet());
assert_eq!(did.address(), address.to_lowercase());
assert_eq!(
did.verification_method_id(),
"did:pkh:eip155:1:0xb9c5714089478a327f09197987f16f9e5d936e8a#blockchainAccountId",
);
}
#[test]
fn test_did_pkh_string_conversion() {
let address = "0xB9C5714089478a327F09197987f16f9E5d936E8a";
let did = DidPkh::from_ethereum_address(address);
let did_str = did.to_string();
assert_eq!(
did_str,
"did:pkh:eip155:1:0xb9c5714089478a327f09197987f16f9e5d936e8a",
);
let did: DidPkh = did_str.parse().unwrap();
assert_eq!(did.address(), address.to_lowercase());
}
#[test]
fn test_parse_invalid_did_pkh() {
let did_str = "eip155:1:0xb9c5714089478a327f09197987f16f9e5d936e8a";
let error = did_str.parse::<DidPkh>().err().unwrap();
assert_eq!(error.to_string(), "DID parse error");
}
}