1use std::sync::OnceLock;
2
3use solana_sdk::{address_lookup_table::AddressLookupTableAccount, pubkey::Pubkey};
4
5use crate::{
6 drift_idl::accounts::{PerpMarket, SpotMarket},
7 types::Context,
8 MarketId, MarketType, OracleSource,
9};
10
11pub const SYSVAR_INSTRUCTIONS_PUBKEY: Pubkey =
13 solana_sdk::pubkey!("Sysvar1nstructions1111111111111111111111111");
14
15pub const PROGRAM_ID: Pubkey = solana_sdk::pubkey!("dRiftyHA39MWEi3m9aunc5MzRF1JYuBsbn6VPcn33UH");
17
18pub const VAULT_PROGRAM_ID: Pubkey =
20 solana_sdk::pubkey!("vAuLTsyrvSfZRuRB3XgvkPwNGgYSs9YRYymVebLKoxR");
21
22pub const JIT_PROXY_ID: Pubkey =
24 solana_sdk::pubkey!("J1TnP8zvVxbtF5KFp5xRmWuvG9McnhzmBd9XGfCyuxFP");
25pub const DEFAULT_PUBKEY: Pubkey = solana_sdk::pubkey!("11111111111111111111111111111111");
27
28static STATE_ACCOUNT: OnceLock<Pubkey> = OnceLock::new();
29
30pub const TOKEN_PROGRAM_ID: Pubkey =
31 solana_sdk::pubkey!("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA");
32
33pub const LUTS_DEVNET: &[Pubkey] = &[solana_sdk::pubkey!(
35 "FaMS3U4uBojvGn5FSDEPimddcXsCfwkKsFgMVVnDdxGb"
36)];
37pub const LUTS_MAINNET: &[Pubkey] = &[
39 solana_sdk::pubkey!("Fpys8GRa5RBWfyeN7AaDUwFGD1zkDCA4z3t4CJLV8dfL"),
40 solana_sdk::pubkey!("EiWSskK5HXnBTptiS5DH6gpAJRVNQ3cAhTKBGaiaysAb"),
41];
42
43pub fn state_account() -> &'static Pubkey {
45 STATE_ACCOUNT.get_or_init(|| {
46 let (state_account, _seed) =
47 Pubkey::find_program_address(&[&b"drift_state"[..]], &PROGRAM_ID);
48 state_account
49 })
50}
51
52pub fn derive_spot_market_account(market_index: u16) -> Pubkey {
54 let (account, _seed) = Pubkey::find_program_address(
55 &[&b"spot_market"[..], &market_index.to_le_bytes()],
56 &PROGRAM_ID,
57 );
58 account
59}
60
61pub fn derive_perp_market_account(market_index: u16) -> Pubkey {
63 let (account, _seed) = Pubkey::find_program_address(
64 &[&b"perp_market"[..], &market_index.to_le_bytes()],
65 &PROGRAM_ID,
66 );
67 account
68}
69
70pub fn derive_spot_market_vault(market_index: u16) -> Pubkey {
72 let (account, _seed) = Pubkey::find_program_address(
73 &[&b"spot_market_vault"[..], &market_index.to_le_bytes()],
74 &PROGRAM_ID,
75 );
76 account
77}
78
79pub fn derive_drift_signer() -> Pubkey {
81 let (account, _seed) = Pubkey::find_program_address(&[&b"drift_signer"[..]], &PROGRAM_ID);
82 account
83}
84
85pub trait MarketExt {
87 fn market_type(&self) -> &'static str;
88 fn symbol(&self) -> &str;
89}
90
91impl MarketExt for PerpMarket {
92 fn market_type(&self) -> &'static str {
93 "perp"
94 }
95 fn symbol(&self) -> &str {
96 unsafe { core::str::from_utf8_unchecked(&self.name) }.trim_end()
97 }
98}
99
100impl MarketExt for SpotMarket {
101 fn market_type(&self) -> &'static str {
102 "spot"
103 }
104 fn symbol(&self) -> &str {
105 unsafe { core::str::from_utf8_unchecked(&self.name) }.trim_end()
106 }
107}
108
109#[derive(Clone)]
116pub struct ProgramData {
117 spot_markets: &'static [SpotMarket],
118 perp_markets: &'static [PerpMarket],
119 pub lookup_tables: &'static [AddressLookupTableAccount],
120}
121
122impl ProgramData {
123 pub const fn uninitialized() -> Self {
125 Self {
126 spot_markets: &[],
127 perp_markets: &[],
128 lookup_tables: &[],
129 }
130 }
131 pub fn new(
133 mut spot: Vec<SpotMarket>,
134 mut perp: Vec<PerpMarket>,
135 lookup_tables: Vec<AddressLookupTableAccount>,
136 ) -> Self {
137 spot.sort_by(|a, b| a.market_index.cmp(&b.market_index));
138 perp.sort_by(|a, b| a.market_index.cmp(&b.market_index));
139 assert!(
141 spot.iter()
142 .enumerate()
143 .all(|(idx, x)| idx == x.market_index as usize),
144 "spot indexes unaligned"
145 );
146 assert!(
147 perp.iter()
148 .enumerate()
149 .all(|(idx, x)| idx == x.market_index as usize),
150 "perp indexes unaligned"
151 );
152
153 Self {
154 spot_markets: Box::leak(spot.into_boxed_slice()),
155 perp_markets: Box::leak(perp.into_boxed_slice()),
156 lookup_tables: Box::leak(lookup_tables.into_boxed_slice()),
157 }
158 }
159
160 pub fn spot_market_configs(&self) -> &'static [SpotMarket] {
162 self.spot_markets
163 }
164
165 pub fn perp_market_configs(&self) -> &'static [PerpMarket] {
167 self.perp_markets
168 }
169
170 pub fn spot_market_config_by_index(&self, market_index: u16) -> Option<&'static SpotMarket> {
172 self.spot_markets.get(market_index as usize)
173 }
174
175 pub fn perp_market_config_by_index(&self, market_index: u16) -> Option<&'static PerpMarket> {
177 self.perp_markets.get(market_index as usize)
178 }
179
180 pub fn markets_to_accounts(&self, markets: &[MarketId]) -> Vec<Pubkey> {
182 let accounts: Vec<Pubkey> = markets
183 .iter()
184 .filter_map(|x| match x.kind() {
185 MarketType::Spot => self
186 .spot_market_config_by_index(x.index())
187 .map(|x| x.pubkey),
188 MarketType::Perp => self
189 .perp_market_config_by_index(x.index())
190 .map(|x| x.pubkey),
191 })
192 .collect();
193
194 accounts
195 }
196}
197
198pub fn oracle_source_to_owner(context: Context, source: OracleSource) -> Pubkey {
200 match source {
201 OracleSource::Pyth
202 | OracleSource::Pyth1K
203 | OracleSource::Pyth1M
204 | OracleSource::PythStableCoin => context.pyth(),
205 OracleSource::PythPull
206 | OracleSource::Pyth1KPull
207 | OracleSource::Pyth1MPull
208 | OracleSource::PythStableCoinPull => ids::drift_oracle_receiver_program::ID,
209 OracleSource::Switchboard => ids::switchboard_program::ID,
210 OracleSource::SwitchboardOnDemand => ids::switchboard_on_demand::ID,
211 OracleSource::QuoteAsset => DEFAULT_PUBKEY,
212 OracleSource::Prelaunch
213 | OracleSource::PythLazer
214 | OracleSource::PythLazer1K
215 | OracleSource::PythLazer1M
216 | OracleSource::PythLazerStableCoin => PROGRAM_ID,
217 }
218}
219
220pub mod ids {
221 pub mod pyth_program {
222 use solana_sdk::pubkey::Pubkey;
223 pub const ID: Pubkey = solana_sdk::pubkey!("FsJ3A3u2vn5cTVofAjvy6y5kwABJAqYWpe4975bi2epH");
224 pub const ID_DEVNET: Pubkey =
225 solana_sdk::pubkey!("gSbePebfvPy7tRqimPoVecS2UsBvYv46ynrzWocc92s");
226 }
227
228 pub mod wormhole_program {
229 use solana_sdk::pubkey::Pubkey;
230
231 pub const ID: Pubkey = solana_sdk::pubkey!("HDwcJBJXjL9FpJ7UBsYBtaDjsBUhuLCUYoz3zr8SWWaQ");
232 }
233
234 pub mod drift_oracle_receiver_program {
235 use solana_sdk::pubkey::Pubkey;
236
237 pub const ID: Pubkey = solana_sdk::pubkey!("G6EoTTTgpkNBtVXo96EQp2m6uwwVh2Kt6YidjkmQqoha");
238 }
239
240 pub mod switchboard_program {
241 use solana_sdk::pubkey::Pubkey;
242
243 pub const ID: Pubkey = solana_sdk::pubkey!("SW1TCH7qEPTdLsDHRgPuMQjbQxKdH2aBStViMFnt64f");
244 }
245
246 pub mod switchboard_on_demand {
247 use solana_sdk::pubkey::Pubkey;
248
249 pub const ID: Pubkey = solana_sdk::pubkey!("SBondMDrcV3K4kxZR1HNVT7osZxAHVHgYXL5Ze1oMUv");
250 }
251
252 pub mod bonk_oracle {
253 use solana_sdk::pubkey::Pubkey;
254
255 pub const ID: Pubkey = solana_sdk::pubkey!("8ihFLu5FimgTQ1Unh4dVyEHUGodJ5gJQCrQf4KUVB9bN");
256 }
257
258 pub mod bonk_pull_oracle {
259 use solana_sdk::pubkey::Pubkey;
260
261 pub const ID: Pubkey = solana_sdk::pubkey!("GojbSnJuPdKDT1ZuHuAM5t9oz6bxTo1xhUKpTua2F72p");
262 }
263
264 pub mod pepe_oracle {
265 use solana_sdk::pubkey::Pubkey;
266
267 pub const ID: Pubkey = solana_sdk::pubkey!("FSfxunDmjjbDV2QxpyxFCAPKmYJHSLnLuvQXDLkMzLBm");
268 }
269
270 pub mod pepe_pull_oracle {
271 use solana_sdk::pubkey::Pubkey;
272
273 pub const ID: Pubkey = solana_sdk::pubkey!("CLxofhtzvLiErpn25wvUzpZXEqBhuZ6WMEckEraxyuGt");
274 }
275
276 pub mod wen_oracle {
277 use solana_sdk::pubkey::Pubkey;
278
279 pub const ID: Pubkey = solana_sdk::pubkey!("6Uo93N83iF5U9KwC8eQpogx4XptMT4wSKfje7hB1Ufko");
280 }
281
282 pub mod wen_pull_oracle {
283 use solana_sdk::pubkey::Pubkey;
284
285 pub const ID: Pubkey = solana_sdk::pubkey!("F47c7aJgYkfKXQ9gzrJaEpsNwUKHprysregTWXrtYLFp");
286 }
287
288 pub mod usdc_oracle {
289 use solana_sdk::pubkey::Pubkey;
290
291 pub const ID: Pubkey = solana_sdk::pubkey!("Gnt27xtC473ZT2Mw5u8wZ68Z3gULkSTb5DuxJy7eJotD");
292 }
293
294 pub mod usdc_pull_oracle {
295 use solana_sdk::pubkey::Pubkey;
296
297 pub const ID: Pubkey = solana_sdk::pubkey!("En8hkHLkRe9d9DraYmBTrus518BvmVH448YcvmrFM6Ce");
298 }
299
300 pub mod jupiter_mainnet_6 {
301 use solana_sdk::pubkey::Pubkey;
302
303 pub const ID: Pubkey = solana_sdk::pubkey!("JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4");
304 }
305 pub mod jupiter_mainnet_4 {
306 use solana_sdk::pubkey::Pubkey;
307
308 pub const ID: Pubkey = solana_sdk::pubkey!("JUP4Fb2cqiRUcaTHdrPC8h2gNsA2ETXiPDD33WcGuJB");
309 }
310 pub mod jupiter_mainnet_3 {
311 use solana_sdk::pubkey::Pubkey;
312
313 pub const ID: Pubkey = solana_sdk::pubkey!("JUP3c2Uh3WA4Ng34tw6kPd2G4C5BB21Xo36Je1s32Ph");
314 }
315
316 pub mod marinade_mainnet {
317 use solana_sdk::pubkey::Pubkey;
318
319 pub const ID: Pubkey = solana_sdk::pubkey!("MarBmsSgKXdrN1egZf5sqe1TMai9K1rChYNDJgjq7aD");
320 }
321
322 pub mod usdt_oracle {
323 use solana_sdk::pubkey::Pubkey;
324
325 pub const ID: Pubkey = solana_sdk::pubkey!("3vxLXJqLqF3JG5TCbYycbKWRBbCJQLxQmBGCkyqEEefL");
326 }
327
328 pub mod usdt_pull_oracle {
329 use solana_sdk::pubkey::Pubkey;
330
331 pub const ID: Pubkey = solana_sdk::pubkey!("BekJ3P5G3iFeC97sXHuKnUHofCFj9Sbo7uyF2fkKwvit");
332 }
333
334 pub mod admin_hot_wallet {
335 use solana_sdk::pubkey::Pubkey;
336
337 pub const ID: Pubkey = solana_sdk::pubkey!("5hMjmxexWu954pX9gB9jkHxMqdjpxArQS2XdvkaevRax");
338 }
339}