aimo_core/
token_map.rs

1use std::{str::FromStr, sync::OnceLock};
2
3use solana_sdk::pubkey::Pubkey;
4
5static DEVNET_TOKEN_MAP: OnceLock<TokenMap> = OnceLock::new();
6static MAINNET_TOKEN_MAP: OnceLock<TokenMap> = OnceLock::new();
7
8pub fn devnet_token_map() -> &'static TokenMap {
9    DEVNET_TOKEN_MAP.get_or_init(|| TokenMap::new(true))
10}
11
12pub fn mainnet_token_map() -> &'static TokenMap {
13    MAINNET_TOKEN_MAP.get_or_init(|| TokenMap::new(false))
14}
15
16pub fn token_map(devnet_tokens: bool) -> &'static TokenMap {
17    if devnet_tokens {
18        devnet_token_map()
19    } else {
20        mainnet_token_map()
21    }
22}
23
24pub type TokenType = &'static Token;
25
26#[derive(Debug, Clone)]
27pub struct Token {
28    pub mint: Pubkey,
29    pub symbol: &'static str,
30    pub decimals: u32,
31}
32
33impl Token {
34    /// Human-readable amount in f64
35    pub fn ui_amount(&self, amount: u64) -> f64 {
36        amount as f64 / 10f64.powf(self.decimals as f64)
37    }
38}
39
40#[derive(Debug, Clone)]
41pub struct TokenMap {
42    /// "USDC" token, use a custom token on devnet
43    pub usdc: Token,
44
45    /// Custom "USDC" token used internally with 9 decimals
46    pub usdc_9: Token,
47}
48
49impl TokenMap {
50    pub fn new(devnet_tokens: bool) -> Self {
51        if devnet_tokens {
52            // Devnet token metadata
53            Self {
54                usdc: Token {
55                    mint: solana_sdk::pubkey!("DGFhnr4oofkJ3K1vtNWhwfLGTDz6vJWoUcXkpwXe1X78"),
56                    symbol: "USDC",
57                    decimals: 6,
58                },
59                usdc_9: Token {
60                    mint: solana_sdk::pubkey!("BR5T9y8RwtNjMSsz9SzzJsSveVc476ujSJzrzQfcWFz3"),
61                    symbol: "USDC_9",
62                    decimals: 9,
63                },
64            }
65        } else {
66            // Mainnet token metadata
67            Self {
68                usdc: Token {
69                    mint: solana_sdk::pubkey!("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"),
70                    symbol: "USDC",
71                    decimals: 6,
72                },
73                usdc_9: Token {
74                    mint: solana_sdk::pubkey!("BR5T9y8RwtNjMSsz9SzzJsSveVc476ujSJzrzQfcWFz3"),
75                    symbol: "USDC_9",
76                    decimals: 9,
77                },
78            }
79        }
80    }
81
82    /// Find a supported token either by name or by pubkey string.
83    ///
84    /// Returns `None` if the token is not supported.
85    ///
86    /// # Examples
87    /// ```
88    /// use aimo_core::token_map::token_map;
89    ///
90    /// let token_map = token_map(false);
91    ///
92    /// // Find by symbol
93    /// let usdc_by_symbol = token_map.find("USDC");
94    ///
95    /// // Find by mint address  
96    /// let usdc_by_mint = token_map.find("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v");
97    /// ```
98    pub fn find(&'static self, token: &str) -> Option<TokenType> {
99        match token.to_ascii_uppercase().as_str() {
100            "USDC" => Some(&self.usdc),
101            "USDC_9" => Some(&self.usdc_9),
102
103            // match other token names here:
104            // "USDT": => xxxx
105
106            // Fallback to token mint pubkey
107            _ => {
108                Pubkey::from_str(token).ok().and_then(|mint| {
109                    [
110                        // List other tokens here
111                        &self.usdc,
112                        &self.usdc_9,
113                    ]
114                    .iter()
115                    .find(|t| t.mint == mint)
116                    .map(|v| &**v)
117                })
118            }
119        }
120    }
121}