use std::fmt::Display;
use alloy::primitives::Address;
use serde::{Deserialize, Deserializer};
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum TokenIdentifier {
ERC20 { address: Address },
Fiat { symbol: String },
Native,
}
impl From<Address> for TokenIdentifier {
fn from(address: Address) -> Self {
TokenIdentifier::ERC20 { address }
}
}
impl TryFrom<String> for TokenIdentifier {
type Error = crate::error::EthPricesError;
fn try_from(input: String) -> Result<Self, Self::Error> {
if input == "native" {
Ok(TokenIdentifier::Native)
} else if input.starts_with("fiat:") {
let symbol = input
.split("fiat:")
.nth(1)
.ok_or(crate::error::EthPricesError::InvalidFiatSymbol)?
.to_string();
Ok(TokenIdentifier::Fiat { symbol })
} else if input.starts_with("0x") {
let address = input
.parse::<Address>()
.map_err(|e| crate::error::EthPricesError::InvalidAddress(e.to_string()))?;
Ok(TokenIdentifier::ERC20 { address })
} else {
Err(crate::error::EthPricesError::TokenNotFound(input))
}
}
}
impl Display for TokenIdentifier {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
TokenIdentifier::ERC20 { address } => write!(f, "{}", address),
TokenIdentifier::Fiat { symbol } => write!(f, "fiat:{}", symbol),
TokenIdentifier::Native => write!(f, "native"),
}
}
}
impl<'de> Deserialize<'de> for TokenIdentifier {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
TokenIdentifier::try_from(s).map_err(serde::de::Error::custom)
}
}