use std::{fmt::Display, sync::Arc};
use alloy_primitives::Address;
use serde::{Deserialize, Serialize};
use crate::defi::chain::SharedChain;
#[cfg_attr(
feature = "python",
pyo3::pyclass(module = "nautilus_trader.core.nautilus_pyo3.model", from_py_object)
)]
#[cfg_attr(
feature = "python",
pyo3_stub_gen::derive::gen_stub_pyclass(module = "nautilus_trader.model")
)]
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Token {
pub chain: SharedChain,
pub address: Address,
pub name: String,
pub symbol: String,
pub decimals: u8,
}
pub type SharedToken = Arc<Token>;
impl Token {
#[must_use]
pub fn new(
chain: SharedChain,
address: Address,
name: String,
symbol: String,
decimals: u8,
) -> Self {
Self {
chain,
address,
name,
symbol,
decimals,
}
}
pub fn is_stablecoin(&self) -> bool {
matches!(
self.symbol.as_str(),
"USDC"
| "USDT"
| "DAI"
| "BUSD"
| "FRAX"
| "LUSD"
| "TUSD"
| "USDP"
| "GUSD"
| "SUSD"
| "UST"
| "USDD"
| "CUSD"
| "EUROC"
| "EURT"
| "EURS"
| "AGEUR"
| "MIM"
| "FEI"
| "OUSD"
| "USDB"
)
}
pub fn is_native_currency(&self) -> bool {
matches!(
self.symbol.as_str(),
"WETH"
| "ETH"
| "WMATIC"
| "MATIC"
| "WBNB"
| "BNB"
| "WAVAX"
| "AVAX"
| "WFTM"
| "FTM"
)
}
pub fn get_token_priority(&self) -> u8 {
if self.is_stablecoin() {
1
} else if self.is_native_currency() {
2
} else {
3
}
}
}
impl Display for Token {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Token(symbol={}, name={})", self.symbol, self.name)
}
}
#[cfg(test)]
mod tests {
use std::sync::Arc;
use rstest::rstest;
use super::*;
use crate::defi::{chain::chains, stubs::weth};
#[rstest]
fn test_token_constructor(weth: Token) {
assert_eq!(weth.chain.chain_id, chains::ARBITRUM.chain_id);
assert_eq!(weth.name, "Wrapped Ether");
assert_eq!(weth.symbol, "WETH");
assert_eq!(weth.decimals, 18);
assert!(weth.is_native_currency());
}
#[rstest]
fn test_token_display_with_special_characters() {
let chain = Arc::new(chains::ETHEREUM.clone());
let token = Token::new(
chain,
"0xA0b86a33E6441b936662bb6B5d1F8Fb0E2b57A5D"
.parse()
.unwrap(),
"Test Token (with parentheses)".to_string(),
"TEST-1".to_string(),
18,
);
let display = token.to_string();
assert_eq!(
display,
"Token(symbol=TEST-1, name=Test Token (with parentheses))"
);
assert!(!token.is_native_currency());
assert!(!token.is_stablecoin());
assert_eq!(token.get_token_priority(), 3);
}
}