1use super::checkers::{
12 phoenix_checkers::{MarketAccountInfo, SeatAccountInfo},
13 MintAccountInfo, TokenAccountInfo, PDA,
14};
15use crate::{
16 phoenix_log_authority,
17 program::{
18 validation::checkers::{EmptyAccount, Program, Signer},
19 MarketHeader, TokenParams,
20 },
21};
22use core::slice::Iter;
23use solana_program::{
24 account_info::{next_account_info, AccountInfo},
25 program_error::ProgramError,
26 pubkey::Pubkey,
27 system_program,
28};
29use static_assertions::const_assert_eq;
30
31pub fn get_vault_address(market: &Pubkey, mint: &Pubkey) -> (Pubkey, u8) {
32 Pubkey::find_program_address(&[b"vault", market.as_ref(), mint.as_ref()], &crate::ID)
33}
34
35pub fn get_seat_address(market: &Pubkey, trader: &Pubkey) -> (Pubkey, u8) {
36 Pubkey::find_program_address(&[b"seat", market.as_ref(), trader.as_ref()], &crate::ID)
37}
38
39pub(crate) struct PhoenixLogContext<'a, 'info> {
40 pub(crate) phoenix_program: Program<'a, 'info>,
41 pub(crate) log_authority: PDA<'a, 'info>,
42}
43
44impl<'a, 'info> PhoenixLogContext<'a, 'info> {
45 pub(crate) fn load(
46 account_iter: &mut Iter<'a, AccountInfo<'info>>,
47 ) -> Result<Self, ProgramError> {
48 Ok(Self {
49 phoenix_program: Program::new(next_account_info(account_iter)?, &crate::id())?,
50 log_authority: PDA::new(
51 next_account_info(account_iter)?,
52 &phoenix_log_authority::id(),
53 )?,
54 })
55 }
56}
57
58pub(crate) struct PhoenixMarketContext<'a, 'info> {
59 pub(crate) market_info: MarketAccountInfo<'a, 'info>,
60 pub(crate) signer: Signer<'a, 'info>,
61}
62
63impl<'a, 'info> PhoenixMarketContext<'a, 'info> {
64 pub(crate) fn load(
65 account_iter: &mut Iter<'a, AccountInfo<'info>>,
66 ) -> Result<Self, ProgramError> {
67 const_assert_eq!(std::mem::size_of::<MarketHeader>(), 576);
68 Ok(Self {
69 market_info: MarketAccountInfo::new(next_account_info(account_iter)?)?,
70 signer: Signer::new(next_account_info(account_iter)?)?,
71 })
72 }
73
74 pub(crate) fn load_init(
75 account_iter: &mut Iter<'a, AccountInfo<'info>>,
76 ) -> Result<Self, ProgramError> {
77 const_assert_eq!(std::mem::size_of::<MarketHeader>(), 576);
78 Ok(Self {
79 market_info: MarketAccountInfo::new_init(next_account_info(account_iter)?)?,
80 signer: Signer::new(next_account_info(account_iter)?)?,
81 })
82 }
83}
84
85pub(crate) struct PhoenixVaultContext<'a, 'info> {
87 pub(crate) base_account: TokenAccountInfo<'a, 'info>,
88 pub(crate) quote_account: TokenAccountInfo<'a, 'info>,
89 pub(crate) base_vault: TokenAccountInfo<'a, 'info>,
90 pub(crate) quote_vault: TokenAccountInfo<'a, 'info>,
91 pub(crate) token_program: Program<'a, 'info>,
92}
93
94impl<'a, 'info> PhoenixVaultContext<'a, 'info> {
95 pub(crate) fn load_from_iter(
96 account_iter: &mut Iter<'a, AccountInfo<'info>>,
97 base_params: &TokenParams,
98 quote_params: &TokenParams,
99 trader_key: &Pubkey,
100 ) -> Result<Self, ProgramError> {
101 Ok(Self {
102 base_account: TokenAccountInfo::new_with_owner(
103 next_account_info(account_iter)?,
104 &base_params.mint_key,
105 trader_key,
106 )?,
107 quote_account: TokenAccountInfo::new_with_owner(
108 next_account_info(account_iter)?,
109 "e_params.mint_key,
110 trader_key,
111 )?,
112 base_vault: TokenAccountInfo::new_with_owner_and_key(
113 next_account_info(account_iter)?,
114 &base_params.mint_key,
115 &base_params.vault_key,
116 &base_params.vault_key,
117 )?,
118 quote_vault: TokenAccountInfo::new_with_owner_and_key(
119 next_account_info(account_iter)?,
120 "e_params.mint_key,
121 "e_params.vault_key,
122 "e_params.vault_key,
123 )?,
124 token_program: Program::new(next_account_info(account_iter)?, &spl_token::id())?,
125 })
126 }
127}
128
129pub(crate) struct InitializeMarketContext<'a, 'info> {
130 pub(crate) base_mint: MintAccountInfo<'a, 'info>,
131 pub(crate) quote_mint: MintAccountInfo<'a, 'info>,
132 pub(crate) base_vault: EmptyAccount<'a, 'info>,
133 pub(crate) quote_vault: EmptyAccount<'a, 'info>,
134 pub(crate) system_program: Program<'a, 'info>,
135 pub(crate) token_program: Program<'a, 'info>,
136}
137
138impl<'a, 'info> InitializeMarketContext<'a, 'info> {
139 pub(crate) fn load(accounts: &'a [AccountInfo<'info>]) -> Result<Self, ProgramError> {
140 let account_iter = &mut accounts.iter();
141 let ctx = Self {
142 base_mint: MintAccountInfo::new(next_account_info(account_iter)?)?,
143 quote_mint: MintAccountInfo::new(next_account_info(account_iter)?)?,
144 base_vault: EmptyAccount::new(next_account_info(account_iter)?)?,
145 quote_vault: EmptyAccount::new(next_account_info(account_iter)?)?,
146 system_program: Program::new(next_account_info(account_iter)?, &system_program::id())?,
147 token_program: Program::new(next_account_info(account_iter)?, &spl_token::id())?,
148 };
149 Ok(ctx)
150 }
151}
152
153pub(crate) struct NewOrderContext<'a, 'info> {
154 pub(crate) seat_option: Option<SeatAccountInfo<'a, 'info>>,
156 pub(crate) vault_context: Option<PhoenixVaultContext<'a, 'info>>,
157}
158
159impl<'a, 'info> NewOrderContext<'a, 'info> {
160 pub(crate) fn load_post_allowed(
161 market_context: &PhoenixMarketContext<'a, 'info>,
162 accounts: &'a [AccountInfo<'info>],
163 only_free_funds: bool,
164 ) -> Result<Self, ProgramError> {
165 let PhoenixMarketContext {
166 market_info,
167 signer: trader,
168 } = market_context;
169 market_info.assert_post_allowed()?;
170 let account_iter = &mut accounts.iter();
171 let seat_option = Some(SeatAccountInfo::new_with_context(
172 next_account_info(account_iter)?,
173 market_info.key,
174 trader.key,
175 true,
176 )?);
177 let new_order_token_account_ctx = if only_free_funds {
178 None
179 } else {
180 let (base_params, quote_params) = {
181 let header = market_info.get_header()?;
182 (header.base_params, header.quote_params)
183 };
184 Some(PhoenixVaultContext::load_from_iter(
185 account_iter,
186 &base_params,
187 "e_params,
188 trader.key,
189 )?)
190 };
191 Ok(Self {
192 seat_option,
193 vault_context: new_order_token_account_ctx,
194 })
195 }
196
197 pub(crate) fn load_cross_only(
198 market_context: &PhoenixMarketContext<'a, 'info>,
199 accounts: &'a [AccountInfo<'info>],
200 only_free_funds: bool,
201 ) -> Result<Self, ProgramError> {
202 let PhoenixMarketContext {
203 market_info,
204 signer: trader,
205 } = market_context;
206 market_info.assert_cross_allowed()?;
207 let account_iter = &mut accounts.iter();
208 let seat_option = if only_free_funds {
209 Some(SeatAccountInfo::new_with_context(
210 next_account_info(account_iter)?,
211 market_info.key,
212 trader.key,
213 true,
214 )?)
215 } else {
216 None
217 };
218 let new_order_token_account_ctx = if only_free_funds {
219 None
220 } else {
221 let (base_params, quote_params) = {
222 let header = market_info.get_header()?;
223 (header.base_params, header.quote_params)
224 };
225 Some(PhoenixVaultContext::load_from_iter(
226 account_iter,
227 &base_params,
228 "e_params,
229 trader.key,
230 )?)
231 };
232 Ok(Self {
233 seat_option,
234 vault_context: new_order_token_account_ctx,
235 })
236 }
237}
238
239pub(crate) struct CancelOrWithdrawContext<'a, 'info> {
240 pub(crate) vault_context: PhoenixVaultContext<'a, 'info>,
241}
242
243impl<'a, 'info> CancelOrWithdrawContext<'a, 'info> {
244 pub(crate) fn load(
245 market_context: &PhoenixMarketContext<'a, 'info>,
246 accounts: &'a [AccountInfo<'info>],
247 ) -> Result<Self, ProgramError> {
248 let PhoenixMarketContext {
249 market_info,
250 signer: trader,
251 } = market_context;
252 market_info.assert_reduce_allowed()?;
253 let account_iter = &mut accounts.iter();
254 let trader_key = trader.key;
255 let (base_params, quote_params) = {
256 let header = market_info.get_header()?;
257 (header.base_params, header.quote_params)
258 };
259 let ctx = Self {
260 vault_context: PhoenixVaultContext::load_from_iter(
261 account_iter,
262 &base_params,
263 "e_params,
264 trader_key,
265 )?,
266 };
267 Ok(ctx)
268 }
269}
270
271pub(crate) struct DepositContext<'a, 'info> {
272 _seat: SeatAccountInfo<'a, 'info>,
273 pub(crate) vault_context: PhoenixVaultContext<'a, 'info>,
274}
275
276impl<'a, 'info> DepositContext<'a, 'info> {
277 pub(crate) fn load(
278 market_context: &PhoenixMarketContext<'a, 'info>,
279 accounts: &'a [AccountInfo<'info>],
280 ) -> Result<Self, ProgramError> {
281 let PhoenixMarketContext {
282 market_info,
283 signer: trader,
284 } = market_context;
285 market_info.assert_post_allowed()?;
286 let account_iter = &mut accounts.iter();
287 let market_key = market_info.key;
288 let trader_key = trader.key;
289 let (base_params, quote_params) = {
290 let header = market_info.get_header()?;
291 (header.base_params, header.quote_params)
292 };
293 let ctx = Self {
294 _seat: SeatAccountInfo::new_with_context(
295 next_account_info(account_iter)?,
296 market_key,
297 trader_key,
298 true,
299 )?,
300 vault_context: PhoenixVaultContext::load_from_iter(
301 account_iter,
302 &base_params,
303 "e_params,
304 trader_key,
305 )?,
306 };
307 Ok(ctx)
308 }
309}
310
311pub(crate) struct AuthorizedActionContext<'a, 'info> {
312 pub(crate) trader: &'a AccountInfo<'info>,
313 _seat: SeatAccountInfo<'a, 'info>,
314 pub(crate) vault_context: PhoenixVaultContext<'a, 'info>,
315}
316
317impl<'a, 'info> AuthorizedActionContext<'a, 'info> {
318 pub(crate) fn load(
319 market_context: &PhoenixMarketContext<'a, 'info>,
320 accounts: &'a [AccountInfo<'info>],
321 ) -> Result<Self, ProgramError> {
322 let PhoenixMarketContext {
323 market_info,
324 signer: authority,
325 } = market_context;
326 market_info.assert_valid_authority(authority.key)?;
327 let (base_params, quote_params) = {
328 let header = market_info.get_header()?;
329 (header.base_params, header.quote_params)
330 };
331 let market_key = *market_info.key;
332
333 let account_iter = &mut accounts.iter();
334 let trader_info = next_account_info(account_iter)?;
335
336 let ctx = Self {
337 trader: trader_info,
338 _seat: SeatAccountInfo::new_with_context(
339 next_account_info(account_iter)?,
340 &market_key,
341 trader_info.key,
342 false,
343 )?,
344 vault_context: PhoenixVaultContext::load_from_iter(
345 account_iter,
346 &base_params,
347 "e_params,
348 trader_info.key,
349 )?,
350 };
351
352 Ok(ctx)
353 }
354}
355
356pub(crate) struct ChangeMarketStatusContext<'a, 'info> {
357 pub(crate) receiver: Option<&'a AccountInfo<'info>>,
358}
359
360impl<'a, 'info> ChangeMarketStatusContext<'a, 'info> {
361 pub(crate) fn load(accounts: &'a [AccountInfo<'info>]) -> Result<Self, ProgramError> {
362 let account_iter = &mut accounts.iter();
363 let ctx = Self {
364 receiver: next_account_info(account_iter).ok(),
365 };
366 Ok(ctx)
367 }
368}
369
370pub(crate) struct AuthorizedSeatRequestContext<'a, 'info> {
371 pub(crate) payer: Signer<'a, 'info>,
372 pub(crate) trader: &'a AccountInfo<'info>,
373 pub(crate) seat: EmptyAccount<'a, 'info>,
374 pub(crate) system_program: Program<'a, 'info>,
375}
376
377impl<'a, 'info> AuthorizedSeatRequestContext<'a, 'info> {
378 pub(crate) fn load(
379 market_context: &PhoenixMarketContext<'a, 'info>,
380 accounts: &'a [AccountInfo<'info>],
381 ) -> Result<Self, ProgramError> {
382 let PhoenixMarketContext {
383 market_info,
384 signer: authority,
385 } = market_context;
386 market_info.assert_valid_authority(authority.key)?;
387
388 let account_iter = &mut accounts.iter();
389 let ctx = Self {
390 payer: Signer::new_payer(next_account_info(account_iter)?)?,
391 trader: next_account_info(account_iter)?,
392 seat: EmptyAccount::new(next_account_info(account_iter)?)?,
393 system_program: Program::new(next_account_info(account_iter)?, &system_program::id())?,
394 };
395 Ok(ctx)
396 }
397}
398
399pub(crate) struct RequestSeatContext<'a, 'info> {
400 pub(crate) seat: EmptyAccount<'a, 'info>,
401 pub(crate) system_program: Program<'a, 'info>,
402}
403
404impl<'a, 'info> RequestSeatContext<'a, 'info> {
405 pub(crate) fn load(
406 market_context: &PhoenixMarketContext<'a, 'info>,
407 accounts: &'a [AccountInfo<'info>],
408 ) -> Result<Self, ProgramError> {
409 let PhoenixMarketContext { market_info, .. } = market_context;
410 market_info.assert_post_allowed()?;
411
412 let account_iter = &mut accounts.iter();
413 let ctx = Self {
414 seat: EmptyAccount::new(next_account_info(account_iter)?)?,
415 system_program: Program::new(next_account_info(account_iter)?, &system_program::id())?,
416 };
417 Ok(ctx)
418 }
419}
420
421pub(crate) struct ModifySeatContext<'a, 'info> {
422 pub(crate) seat: SeatAccountInfo<'a, 'info>,
423}
424
425impl<'a, 'info> ModifySeatContext<'a, 'info> {
426 pub(crate) fn load(
427 market_context: &PhoenixMarketContext<'a, 'info>,
428 accounts: &'a [AccountInfo<'info>],
429 ) -> Result<Self, ProgramError> {
430 let PhoenixMarketContext {
431 market_info,
432 signer: authority,
433 } = market_context;
434 market_info.assert_valid_authority(authority.key)?;
435
436 let account_iter = &mut accounts.iter();
437 let ctx = Self {
438 seat: SeatAccountInfo::new(next_account_info(account_iter)?, market_info.key)?,
439 };
440 Ok(ctx)
441 }
442}
443
444pub(crate) struct CollectFeesContext<'a, 'info> {
445 pub(crate) fee_recipient_token_account: TokenAccountInfo<'a, 'info>,
446 pub(crate) quote_vault: TokenAccountInfo<'a, 'info>,
447 pub(crate) token_program: Program<'a, 'info>,
448}
449
450impl<'a, 'info> CollectFeesContext<'a, 'info> {
451 pub(crate) fn load(
452 market_context: &PhoenixMarketContext<'a, 'info>,
453 accounts: &'a [AccountInfo<'info>],
454 ) -> Result<Self, ProgramError> {
455 let (quote_params, fee_recipient) = {
456 let header = market_context.market_info.get_header()?;
457 (header.quote_params, header.fee_recipient)
458 };
459 let account_iter = &mut accounts.iter();
460 let ctx = Self {
461 fee_recipient_token_account: TokenAccountInfo::new_with_owner(
462 next_account_info(account_iter)?,
463 "e_params.mint_key,
464 &fee_recipient,
465 )?,
466 quote_vault: TokenAccountInfo::new_with_owner_and_key(
467 next_account_info(account_iter)?,
468 "e_params.mint_key,
469 "e_params.vault_key,
470 "e_params.vault_key,
471 )?,
472 token_program: Program::new(next_account_info(account_iter)?, &spl_token::id())?,
473 };
474 Ok(ctx)
475 }
476}
477
478pub(crate) struct ChangeFeeRecipientContext<'a, 'info> {
479 pub(crate) new_fee_recipient: AccountInfo<'info>,
480 pub(crate) previous_fee_recipient: Option<Signer<'a, 'info>>,
481}
482
483impl<'a, 'info> ChangeFeeRecipientContext<'a, 'info> {
484 pub(crate) fn load(
485 market_context: &PhoenixMarketContext<'a, 'info>,
486 accounts: &'a [AccountInfo<'info>],
487 ) -> Result<Self, ProgramError> {
488 let PhoenixMarketContext {
489 market_info,
490 signer: authority,
491 } = market_context;
492 market_info.assert_valid_authority(authority.key)?;
493 let current_fee_recipient = {
494 let header = market_info.get_header()?;
495 header.fee_recipient
496 };
497 let account_iter = &mut accounts.iter();
498 let ctx = Self {
499 new_fee_recipient: next_account_info(account_iter)?.clone(),
500 previous_fee_recipient: next_account_info(account_iter)
501 .and_then(|a| Signer::new_with_key(a, ¤t_fee_recipient))
502 .ok(),
503 };
504 Ok(ctx)
505 }
506}