Skip to main content

bonfida_utils/
tokens.rs

1use solana_program::program_error::ProgramError;
2use solana_program::pubkey;
3use solana_program::pubkey::Pubkey;
4
5#[derive(Debug, Clone, Copy)]
6pub enum SupportedToken {
7    USDC,
8    USDT,
9    Sol,
10    Fida,
11    MSol,
12    Bonk,
13    BAT,
14    Pyth,
15    BSol,
16    Inj,
17    Trump,
18}
19
20const USDC_MINT: Pubkey = pubkey!("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v");
21const USDT_MINT: Pubkey = pubkey!("Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB");
22const SOL_MINT: Pubkey = pubkey!("So11111111111111111111111111111111111111112");
23const FIDA_MINT: Pubkey = pubkey!("EchesyfXePKdLtoiZSL8pBe8Myagyy8ZRqsACNCFGnvp");
24const MSOL_MINT: Pubkey = pubkey!("mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So");
25const BONK_MINT: Pubkey = pubkey!("DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263");
26const BAT_MINT: Pubkey = pubkey!("EPeUFDgHRxs9xxEPVaL6kfGQvCon7jmAWKVUHuux1Tpz");
27const PYTH_MINT: Pubkey = pubkey!("HZ1JovNiVvGrGNiiYvEozEVgZ58xaU3RKwX8eACQBCt3");
28const BSOL_MINT: Pubkey = pubkey!("bSo13r4TkiE4KumL71LsHTPpL2euBYLFx6h9HP3piy1");
29const INJ_MINT: Pubkey = pubkey!("6McPRfPV6bY1e9hLxWyG54W9i9Epq75QBvXg2oetBVTB");
30const TRUMP_MINT: Pubkey = pubkey!("6p6xgHyF7AeE6TZkSmFsko444wqoP15icUSqi2jfGiPN");
31
32impl SupportedToken {
33    pub const fn mint(self) -> Pubkey {
34        match self {
35            SupportedToken::USDC => USDC_MINT,
36            SupportedToken::USDT => USDT_MINT,
37            SupportedToken::Sol => SOL_MINT,
38            SupportedToken::Fida => FIDA_MINT,
39            SupportedToken::MSol => MSOL_MINT,
40            SupportedToken::Bonk => BONK_MINT,
41            SupportedToken::BAT => BAT_MINT,
42            SupportedToken::Pyth => PYTH_MINT,
43            SupportedToken::BSol => BSOL_MINT,
44            SupportedToken::Inj => INJ_MINT,
45            SupportedToken::Trump => TRUMP_MINT,
46        }
47    }
48
49    pub const fn from_mint(mint: &Pubkey) -> Result<Self, ProgramError> {
50        Ok(match *mint {
51            USDC_MINT => SupportedToken::USDC,
52            USDT_MINT => SupportedToken::USDT,
53            SOL_MINT => SupportedToken::Sol,
54            FIDA_MINT => SupportedToken::Fida,
55            MSOL_MINT => SupportedToken::MSol,
56            BONK_MINT => SupportedToken::Bonk,
57            BAT_MINT => SupportedToken::BAT,
58            PYTH_MINT => SupportedToken::Pyth,
59            BSOL_MINT => SupportedToken::BSol,
60            INJ_MINT => SupportedToken::Inj,
61            TRUMP_MINT => SupportedToken::Trump,
62            _ => return Err(ProgramError::InvalidArgument),
63        })
64    }
65
66    pub const fn decimals(self) -> u8 {
67        match self {
68            SupportedToken::Sol | SupportedToken::MSol | SupportedToken::BSol => 9,
69            SupportedToken::Bonk => 5,
70            SupportedToken::BAT | SupportedToken::Inj => 8,
71            SupportedToken::USDC
72            | SupportedToken::USDT
73            | SupportedToken::Fida
74            | SupportedToken::Pyth
75            | SupportedToken::Trump => 6,
76        }
77    }
78
79    pub const fn price_feed_account_key(self) -> Pubkey {
80        match self {
81            SupportedToken::USDC => pubkey!("Dpw1EAVrSB1ibxiDQyTAW6Zip3J4Btk2x4SgApQCeFbX"),
82            SupportedToken::USDT => pubkey!("HT2PLQBcG5EiCcNSaMHAjSgd9F98ecpATbk4Sk5oYuM"),
83            SupportedToken::Sol => pubkey!("7UVimffxr9ow1uXYxsr4LHAcV58mLzhmwaeKvJ1pjLiE"),
84            SupportedToken::Fida => pubkey!("2cfmeuVBf7bvBJcjKBQgAwfvpUvdZV7K8NZxUEuccrub"),
85            SupportedToken::MSol => pubkey!("5CKzb9j4ChgLUt8Gfm5CNGLN6khXKiqMbnGAW4cgXgxK"),
86            SupportedToken::Bonk => pubkey!("DBE3N8uNjhKPRHfANdwGvCZghWXyLPdqdSbEW2XFwBiX"),
87            SupportedToken::BAT => pubkey!("EHH5mjVUsBUF7jD9nFcvB5TnG1fi6U54hRRphAxsVAWQ"),
88            SupportedToken::Pyth => pubkey!("8vjchtMuJNY4oFQdTi8yCe6mhCaNBFaUbktT482TpLPS"),
89            SupportedToken::BSol => pubkey!("5cN76Xm2Dtx9MnrQqBDeZZRsWruTTcw37UruznAdSvvE"),
90            SupportedToken::Inj => pubkey!("GwXYEfmPdgHcowF9GZwbb1WiTGTn1fuT3hbSLneoBKK6"),
91            SupportedToken::Trump => pubkey!("9vNb2tQoZ8bB4vzMbQLWViGwNaDJVtct13AGgno1wazp"),
92        }
93    }
94
95    pub const fn price_feed(self) -> [u8; 32] {
96        match self {
97            SupportedToken::USDC => [
98                234, 160, 32, 198, 28, 196, 121, 113, 40, 19, 70, 28, 225, 83, 137, 74, 150, 166,
99                192, 11, 33, 237, 12, 252, 39, 152, 209, 249, 169, 233, 201, 74,
100            ],
101            SupportedToken::USDT => [
102                43, 137, 185, 220, 143, 223, 159, 52, 112, 154, 91, 16, 107, 71, 47, 15, 57, 187,
103                108, 169, 206, 4, 176, 253, 127, 46, 151, 22, 136, 226, 229, 59,
104            ],
105            SupportedToken::Sol => [
106                239, 13, 139, 111, 218, 44, 235, 164, 29, 161, 93, 64, 149, 209, 218, 57, 42, 13,
107                47, 142, 208, 198, 199, 188, 15, 76, 250, 200, 194, 128, 181, 109,
108            ],
109            SupportedToken::Fida => [
110                200, 6, 87, 183, 246, 243, 234, 194, 114, 24, 208, 157, 90, 78, 84, 228, 123, 37,
111                118, 141, 159, 94, 16, 172, 21, 254, 44, 249, 0, 136, 20, 0,
112            ],
113            SupportedToken::MSol => [
114                194, 40, 154, 106, 67, 210, 206, 145, 198, 245, 92, 174, 195, 112, 244, 172, 195,
115                138, 46, 212, 119, 245, 136, 19, 51, 76, 109, 3, 116, 159, 242, 164,
116            ],
117            SupportedToken::Bonk => [
118                114, 176, 33, 33, 124, 163, 254, 104, 146, 42, 25, 170, 249, 144, 16, 156, 185,
119                216, 78, 154, 208, 4, 180, 210, 2, 90, 214, 245, 41, 49, 68, 25,
120            ],
121            SupportedToken::BAT => [
122                142, 134, 15, 183, 78, 96, 229, 115, 107, 69, 93, 130, 246, 11, 55, 40, 4, 156, 52,
123                142, 148, 150, 26, 221, 95, 150, 27, 2, 253, 238, 37, 53,
124            ],
125            SupportedToken::Pyth => [
126                11, 191, 40, 233, 168, 65, 161, 204, 120, 143, 106, 54, 27, 23, 202, 7, 45, 14,
127                163, 9, 138, 30, 93, 241, 195, 146, 45, 6, 113, 149, 121, 255,
128            ],
129            SupportedToken::BSol => [
130                137, 135, 83, 121, 231, 15, 143, 186, 220, 23, 174, 243, 21, 173, 243, 168, 213,
131                209, 96, 184, 17, 67, 85, 55, 224, 60, 151, 232, 170, 201, 125, 156,
132            ],
133            SupportedToken::Inj => [
134                122, 91, 193, 210, 181, 106, 208, 41, 4, 140, 214, 57, 100, 179, 173, 39, 118, 234,
135                223, 129, 46, 220, 26, 67, 163, 20, 6, 203, 84, 191, 245, 146,
136            ],
137            SupportedToken::Trump => [
138                135, 149, 81, 2, 24, 83, 238, 199, 167, 220, 130, 117, 120, 232, 230, 157, 167,
139                228, 250, 129, 72, 51, 154, 160, 211, 213, 41, 100, 5, 190, 75, 26,
140            ],
141        }
142    }
143}
144
145#[cfg(test)]
146mod test {
147    use crate::pyth::get_pyth_feed_account_key;
148    use crate::tokens::SupportedToken;
149
150    #[test]
151    fn test_price_feed_account_key() {
152        assert_eq!(
153            SupportedToken::USDC.price_feed_account_key(),
154            get_pyth_feed_account_key(0, &SupportedToken::USDC.price_feed())
155        );
156        assert_eq!(
157            SupportedToken::USDT.price_feed_account_key(),
158            get_pyth_feed_account_key(0, &SupportedToken::USDT.price_feed())
159        );
160        assert_eq!(
161            SupportedToken::Sol.price_feed_account_key(),
162            get_pyth_feed_account_key(0, &SupportedToken::Sol.price_feed())
163        );
164        assert_eq!(
165            SupportedToken::Fida.price_feed_account_key(),
166            get_pyth_feed_account_key(0, &SupportedToken::Fida.price_feed())
167        );
168        assert_eq!(
169            SupportedToken::MSol.price_feed_account_key(),
170            get_pyth_feed_account_key(0, &SupportedToken::MSol.price_feed())
171        );
172        assert_eq!(
173            SupportedToken::Bonk.price_feed_account_key(),
174            get_pyth_feed_account_key(0, &SupportedToken::Bonk.price_feed())
175        );
176        assert_eq!(
177            SupportedToken::BAT.price_feed_account_key(),
178            get_pyth_feed_account_key(0, &SupportedToken::BAT.price_feed())
179        );
180        assert_eq!(
181            SupportedToken::Pyth.price_feed_account_key(),
182            get_pyth_feed_account_key(0, &SupportedToken::Pyth.price_feed())
183        );
184        assert_eq!(
185            SupportedToken::BSol.price_feed_account_key(),
186            get_pyth_feed_account_key(0, &SupportedToken::BSol.price_feed())
187        );
188        assert_eq!(
189            SupportedToken::Inj.price_feed_account_key(),
190            get_pyth_feed_account_key(0, &SupportedToken::Inj.price_feed())
191        );
192        assert_eq!(
193            SupportedToken::Trump.price_feed_account_key(),
194            get_pyth_feed_account_key(0, &SupportedToken::Trump.price_feed())
195        )
196    }
197
198    #[test]
199    fn test_feed_id() {
200        // https://pyth.network/developers/price-feed-ids
201        assert_eq!(
202            SupportedToken::USDC.price_feed(),
203            hex::decode("eaa020c61cc479712813461ce153894a96a6c00b21ed0cfc2798d1f9a9e9c94a")
204                .unwrap()
205                .as_slice()
206        );
207        assert_eq!(
208            SupportedToken::USDT.price_feed(),
209            hex::decode("2b89b9dc8fdf9f34709a5b106b472f0f39bb6ca9ce04b0fd7f2e971688e2e53b")
210                .unwrap()
211                .as_slice()
212        );
213        assert_eq!(
214            SupportedToken::Sol.price_feed(),
215            hex::decode("ef0d8b6fda2ceba41da15d4095d1da392a0d2f8ed0c6c7bc0f4cfac8c280b56d")
216                .unwrap()
217                .as_slice()
218        );
219        assert_eq!(
220            SupportedToken::Fida.price_feed(),
221            hex::decode("c80657b7f6f3eac27218d09d5a4e54e47b25768d9f5e10ac15fe2cf900881400")
222                .unwrap()
223                .as_slice()
224        );
225        assert_eq!(
226            SupportedToken::MSol.price_feed(),
227            hex::decode("c2289a6a43d2ce91c6f55caec370f4acc38a2ed477f58813334c6d03749ff2a4")
228                .unwrap()
229                .as_slice()
230        );
231        assert_eq!(
232            SupportedToken::Bonk.price_feed(),
233            hex::decode("72b021217ca3fe68922a19aaf990109cb9d84e9ad004b4d2025ad6f529314419")
234                .unwrap()
235                .as_slice()
236        );
237        assert_eq!(
238            SupportedToken::BAT.price_feed(),
239            hex::decode("8e860fb74e60e5736b455d82f60b3728049c348e94961add5f961b02fdee2535")
240                .unwrap()
241                .as_slice()
242        );
243        assert_eq!(
244            SupportedToken::Pyth.price_feed(),
245            hex::decode("0bbf28e9a841a1cc788f6a361b17ca072d0ea3098a1e5df1c3922d06719579ff")
246                .unwrap()
247                .as_slice()
248        );
249        assert_eq!(
250            SupportedToken::BSol.price_feed(),
251            hex::decode("89875379e70f8fbadc17aef315adf3a8d5d160b811435537e03c97e8aac97d9c")
252                .unwrap()
253                .as_slice()
254        );
255        assert_eq!(
256            SupportedToken::Inj.price_feed(),
257            hex::decode("7a5bc1d2b56ad029048cd63964b3ad2776eadf812edc1a43a31406cb54bff592")
258                .unwrap()
259                .as_slice()
260        );
261        assert_eq!(
262            SupportedToken::Trump.price_feed(),
263            hex::decode("879551021853eec7a7dc827578e8e69da7e4fa8148339aa0d3d5296405be4b1a")
264                .unwrap()
265                .as_slice()
266        );
267    }
268}