1use crate::phoenix_log_authority;
2use crate::program::new_order::MultipleOrderPacket;
3use crate::program::withdraw::WithdrawParams;
4use crate::program::{processor::*, PhoenixInstruction};
5use crate::state::{OrderPacket, OrderPacketMetadata};
6use borsh::BorshSerialize;
7use solana_program::{
8 instruction::{AccountMeta, Instruction},
9 pubkey::Pubkey,
10 system_program,
11};
12use spl_associated_token_account::get_associated_token_address;
13
14use crate::program::loaders::get_vault_address;
15use crate::program::processor::deposit::DepositParams;
16use crate::program::validation::loaders::get_seat_address;
17
18pub fn create_new_order_instruction(
19 market: &Pubkey,
20 trader: &Pubkey,
21 base: &Pubkey,
22 quote: &Pubkey,
23 order_packet: &OrderPacket,
24) -> Instruction {
25 let base_account = get_associated_token_address(trader, base);
26 let quote_account = get_associated_token_address(trader, quote);
27 create_new_order_instruction_with_custom_token_accounts(
28 market,
29 trader,
30 &base_account,
31 "e_account,
32 base,
33 quote,
34 order_packet,
35 )
36}
37
38pub fn create_new_order_instruction_with_custom_token_accounts(
39 market: &Pubkey,
40 trader: &Pubkey,
41 base_account: &Pubkey,
42 quote_account: &Pubkey,
43 base: &Pubkey,
44 quote: &Pubkey,
45 order_packet: &OrderPacket,
46) -> Instruction {
47 let (base_vault, _) = get_vault_address(market, base);
48 let (quote_vault, _) = get_vault_address(market, quote);
49 if order_packet.is_take_only() {
50 Instruction {
51 program_id: crate::id(),
52 accounts: vec![
53 AccountMeta::new_readonly(crate::id(), false),
54 AccountMeta::new_readonly(phoenix_log_authority::id(), false),
55 AccountMeta::new(*market, false),
56 AccountMeta::new_readonly(*trader, true),
57 AccountMeta::new(*base_account, false),
58 AccountMeta::new(*quote_account, false),
59 AccountMeta::new(base_vault, false),
60 AccountMeta::new(quote_vault, false),
61 AccountMeta::new_readonly(spl_token::id(), false),
62 ],
63 data: [
64 PhoenixInstruction::Swap.to_vec(),
65 order_packet.try_to_vec().unwrap(),
66 ]
67 .concat(),
68 }
69 } else {
70 let (seat, _) = get_seat_address(market, trader);
71 Instruction {
72 program_id: crate::id(),
73 accounts: vec![
74 AccountMeta::new_readonly(crate::id(), false),
75 AccountMeta::new_readonly(phoenix_log_authority::id(), false),
76 AccountMeta::new(*market, false),
77 AccountMeta::new_readonly(*trader, true),
78 AccountMeta::new_readonly(seat, false),
79 AccountMeta::new(*base_account, false),
80 AccountMeta::new(*quote_account, false),
81 AccountMeta::new(base_vault, false),
82 AccountMeta::new(quote_vault, false),
83 AccountMeta::new_readonly(spl_token::id(), false),
84 ],
85 data: [
86 PhoenixInstruction::PlaceLimitOrder.to_vec(),
87 order_packet.try_to_vec().unwrap(),
88 ]
89 .concat(),
90 }
91 }
92}
93
94pub fn create_new_order_with_free_funds_instruction(
95 market: &Pubkey,
96 trader: &Pubkey,
97 order_packet: &OrderPacket,
98) -> Instruction {
99 let (seat, _) = get_seat_address(market, trader);
100 Instruction {
101 program_id: crate::id(),
102 accounts: vec![
103 AccountMeta::new_readonly(crate::id(), false),
104 AccountMeta::new_readonly(phoenix_log_authority::id(), false),
105 AccountMeta::new(*market, false),
106 AccountMeta::new_readonly(*trader, true),
107 AccountMeta::new_readonly(seat, false),
108 ],
109 data: [
110 if order_packet.is_take_only() {
111 PhoenixInstruction::SwapWithFreeFunds.to_vec()
112 } else {
113 PhoenixInstruction::PlaceLimitOrderWithFreeFunds.to_vec()
114 },
115 order_packet.try_to_vec().unwrap(),
116 ]
117 .concat(),
118 }
119}
120
121pub fn create_new_multiple_order_instruction(
122 market: &Pubkey,
123 trader: &Pubkey,
124 base: &Pubkey,
125 quote: &Pubkey,
126 multiple_order_packet: &MultipleOrderPacket,
127) -> Instruction {
128 let base_account = get_associated_token_address(trader, base);
129 let quote_account = get_associated_token_address(trader, quote);
130 create_new_multiple_order_instruction_with_custom_token_accounts(
131 market,
132 trader,
133 &base_account,
134 "e_account,
135 base,
136 quote,
137 multiple_order_packet,
138 )
139}
140
141pub fn create_new_multiple_order_instruction_with_custom_token_accounts(
142 market: &Pubkey,
143 trader: &Pubkey,
144 base_account: &Pubkey,
145 quote_account: &Pubkey,
146 base: &Pubkey,
147 quote: &Pubkey,
148 multiple_order_packet: &MultipleOrderPacket,
149) -> Instruction {
150 let (base_vault, _) = get_vault_address(market, base);
151 let (quote_vault, _) = get_vault_address(market, quote);
152 let (seat, _) = get_seat_address(market, trader);
153 Instruction {
154 program_id: crate::id(),
155 accounts: vec![
156 AccountMeta::new_readonly(crate::id(), false),
157 AccountMeta::new_readonly(phoenix_log_authority::id(), false),
158 AccountMeta::new(*market, false),
159 AccountMeta::new_readonly(*trader, true),
160 AccountMeta::new_readonly(seat, false),
161 AccountMeta::new(*base_account, false),
162 AccountMeta::new(*quote_account, false),
163 AccountMeta::new(base_vault, false),
164 AccountMeta::new(quote_vault, false),
165 AccountMeta::new_readonly(spl_token::id(), false),
166 ],
167 data: [
168 PhoenixInstruction::PlaceMultiplePostOnlyOrders.to_vec(),
169 multiple_order_packet.try_to_vec().unwrap(),
170 ]
171 .concat(),
172 }
173}
174
175pub fn create_new_multiple_order_with_free_funds_instruction(
176 market: &Pubkey,
177 trader: &Pubkey,
178 multiple_order_packet: &MultipleOrderPacket,
179) -> Instruction {
180 let (seat, _) = get_seat_address(market, trader);
181 Instruction {
182 program_id: crate::id(),
183 accounts: vec![
184 AccountMeta::new_readonly(crate::id(), false),
185 AccountMeta::new_readonly(phoenix_log_authority::id(), false),
186 AccountMeta::new(*market, false),
187 AccountMeta::new_readonly(*trader, true),
188 AccountMeta::new_readonly(seat, false),
189 ],
190 data: [
191 PhoenixInstruction::PlaceMultiplePostOnlyOrdersWithFreeFunds.to_vec(),
192 multiple_order_packet.try_to_vec().unwrap(),
193 ]
194 .concat(),
195 }
196}
197
198pub fn create_cancel_all_order_with_free_funds_instruction(
199 market: &Pubkey,
200 trader: &Pubkey,
201) -> Instruction {
202 Instruction {
203 program_id: crate::id(),
204 accounts: vec![
205 AccountMeta::new_readonly(crate::id(), false),
206 AccountMeta::new_readonly(phoenix_log_authority::id(), false),
207 AccountMeta::new(*market, false),
208 AccountMeta::new_readonly(*trader, true),
209 ],
210 data: PhoenixInstruction::CancelAllOrdersWithFreeFunds.to_vec(),
211 }
212}
213
214pub fn create_cancel_up_to_with_free_funds_instruction(
215 market: &Pubkey,
216 trader: &Pubkey,
217 params: &CancelUpToParams,
218) -> Instruction {
219 Instruction {
220 program_id: crate::id(),
221 accounts: vec![
222 AccountMeta::new_readonly(crate::id(), false),
223 AccountMeta::new_readonly(phoenix_log_authority::id(), false),
224 AccountMeta::new(*market, false),
225 AccountMeta::new_readonly(*trader, true),
226 ],
227 data: [
228 PhoenixInstruction::CancelUpToWithFreeFunds.to_vec(),
229 params.try_to_vec().unwrap(),
230 ]
231 .concat(),
232 }
233}
234
235pub fn create_cancel_multiple_orders_by_id_with_free_funds_instruction(
236 market: &Pubkey,
237 trader: &Pubkey,
238 params: &CancelMultipleOrdersByIdParams,
239) -> Instruction {
240 Instruction {
241 program_id: crate::id(),
242 accounts: vec![
243 AccountMeta::new_readonly(crate::id(), false),
244 AccountMeta::new_readonly(phoenix_log_authority::id(), false),
245 AccountMeta::new(*market, false),
246 AccountMeta::new_readonly(*trader, true),
247 ],
248 data: [
249 PhoenixInstruction::CancelMultipleOrdersByIdWithFreeFunds.to_vec(),
250 params.try_to_vec().unwrap(),
251 ]
252 .concat(),
253 }
254}
255
256pub fn create_reduce_order_with_free_funds_instruction(
257 market: &Pubkey,
258 trader: &Pubkey,
259 params: &ReduceOrderParams,
260) -> Instruction {
261 Instruction {
262 program_id: crate::id(),
263 accounts: vec![
264 AccountMeta::new_readonly(crate::id(), false),
265 AccountMeta::new_readonly(phoenix_log_authority::id(), false),
266 AccountMeta::new(*market, false),
267 AccountMeta::new_readonly(*trader, true),
268 ],
269 data: [
270 PhoenixInstruction::ReduceOrderWithFreeFunds.to_vec(),
271 params.try_to_vec().unwrap(),
272 ]
273 .concat(),
274 }
275}
276
277pub fn create_deposit_funds_instruction(
278 market: &Pubkey,
279 trader: &Pubkey,
280 base: &Pubkey,
281 quote: &Pubkey,
282 params: &DepositParams,
283) -> Instruction {
284 let base_account = get_associated_token_address(trader, base);
285 let quote_account = get_associated_token_address(trader, quote);
286 let (seat, _) = get_seat_address(market, trader);
287 create_deposit_funds_instruction_with_custom_token_accounts(
288 market,
289 trader,
290 &seat,
291 &base_account,
292 "e_account,
293 base,
294 quote,
295 params,
296 )
297}
298
299#[allow(clippy::too_many_arguments)]
300pub fn create_deposit_funds_instruction_with_custom_token_accounts(
301 market: &Pubkey,
302 trader: &Pubkey,
303 seat: &Pubkey,
304 base_account: &Pubkey,
305 quote_account: &Pubkey,
306 base: &Pubkey,
307 quote: &Pubkey,
308 params: &DepositParams,
309) -> Instruction {
310 let (base_vault, _) = get_vault_address(market, base);
311 let (quote_vault, _) = get_vault_address(market, quote);
312 let ix_data = params.try_to_vec().unwrap();
313 Instruction {
314 program_id: crate::id(),
315 accounts: vec![
316 AccountMeta::new_readonly(crate::id(), false),
317 AccountMeta::new_readonly(phoenix_log_authority::id(), false),
318 AccountMeta::new(*market, false),
319 AccountMeta::new_readonly(*trader, true),
320 AccountMeta::new_readonly(*seat, false),
321 AccountMeta::new(*base_account, false),
322 AccountMeta::new(*quote_account, false),
323 AccountMeta::new(base_vault, false),
324 AccountMeta::new(quote_vault, false),
325 AccountMeta::new_readonly(spl_token::id(), false),
326 ],
327 data: [PhoenixInstruction::DepositFunds.to_vec(), ix_data].concat(),
328 }
329}
330
331#[allow(clippy::too_many_arguments)]
332fn _phoenix_instruction_template<T: BorshSerialize>(
333 market: &Pubkey,
334 trader: &Pubkey,
335 base_account: &Pubkey,
336 quote_account: &Pubkey,
337 base: &Pubkey,
338 quote: &Pubkey,
339 ix_id: PhoenixInstruction,
340 params: Option<&T>,
341) -> Instruction {
342 let (base_vault, _) = get_vault_address(market, base);
343 let (quote_vault, _) = get_vault_address(market, quote);
344 let ix_data = match params {
345 Some(i) => i.try_to_vec().unwrap(),
346 None => vec![],
347 };
348 Instruction {
349 program_id: crate::id(),
350 accounts: vec![
351 AccountMeta::new_readonly(crate::id(), false),
352 AccountMeta::new_readonly(phoenix_log_authority::id(), false),
353 AccountMeta::new(*market, false),
354 AccountMeta::new_readonly(*trader, true),
355 AccountMeta::new(*base_account, false),
356 AccountMeta::new(*quote_account, false),
357 AccountMeta::new(base_vault, false),
358 AccountMeta::new(quote_vault, false),
359 AccountMeta::new_readonly(spl_token::id(), false),
360 ],
361 data: [[ix_id as u8].to_vec(), ix_data].concat(),
362 }
363}
364
365fn _phoenix_instruction_template_no_param(
366 market: &Pubkey,
367 trader: &Pubkey,
368 base_account: &Pubkey,
369 quote_account: &Pubkey,
370 base: &Pubkey,
371 quote: &Pubkey,
372 ix_id: PhoenixInstruction,
373) -> Instruction {
374 let (base_vault, _) = get_vault_address(market, base);
375 let (quote_vault, _) = get_vault_address(market, quote);
376 Instruction {
377 program_id: crate::id(),
378 accounts: vec![
379 AccountMeta::new_readonly(crate::id(), false),
380 AccountMeta::new_readonly(phoenix_log_authority::id(), false),
381 AccountMeta::new(*market, false),
382 AccountMeta::new_readonly(*trader, true),
383 AccountMeta::new(*base_account, false),
384 AccountMeta::new(*quote_account, false),
385 AccountMeta::new(base_vault, false),
386 AccountMeta::new(quote_vault, false),
387 AccountMeta::new_readonly(spl_token::id(), false),
388 ],
389 data: [ix_id as u8].to_vec(),
390 }
391}
392
393pub fn reduce_order_instruction(
394 market: &Pubkey,
395 trader: &Pubkey,
396 base: &Pubkey,
397 quote: &Pubkey,
398 params: &ReduceOrderParams,
399) -> Instruction {
400 let base_account = get_associated_token_address(trader, base);
401 let quote_account = get_associated_token_address(trader, quote);
402 create_reduce_order_instruction_with_custom_token_accounts(
403 market,
404 trader,
405 &base_account,
406 "e_account,
407 base,
408 quote,
409 params,
410 )
411}
412
413pub fn create_reduce_order_instruction_with_custom_token_accounts(
414 market: &Pubkey,
415 trader: &Pubkey,
416 base_account: &Pubkey,
417 quote_account: &Pubkey,
418 base: &Pubkey,
419 quote: &Pubkey,
420 params: &ReduceOrderParams,
421) -> Instruction {
422 _phoenix_instruction_template::<ReduceOrderParams>(
423 market,
424 trader,
425 base_account,
426 quote_account,
427 base,
428 quote,
429 PhoenixInstruction::ReduceOrder,
430 Some(params),
431 )
432}
433
434pub fn create_cancel_all_orders_instruction(
435 market: &Pubkey,
436 trader: &Pubkey,
437 base: &Pubkey,
438 quote: &Pubkey,
439) -> Instruction {
440 let base_account = get_associated_token_address(trader, base);
441 let quote_account = get_associated_token_address(trader, quote);
442 create_cancel_all_orders_instruction_with_custom_token_accounts(
443 market,
444 trader,
445 &base_account,
446 "e_account,
447 base,
448 quote,
449 )
450}
451
452pub fn create_cancel_all_orders_instruction_with_custom_token_accounts(
453 market: &Pubkey,
454 trader: &Pubkey,
455 base_account: &Pubkey,
456 quote_account: &Pubkey,
457 base: &Pubkey,
458 quote: &Pubkey,
459) -> Instruction {
460 _phoenix_instruction_template_no_param(
461 market,
462 trader,
463 base_account,
464 quote_account,
465 base,
466 quote,
467 PhoenixInstruction::CancelAllOrders,
468 )
469}
470
471pub fn create_cancel_up_to_instruction(
472 market: &Pubkey,
473 trader: &Pubkey,
474 base: &Pubkey,
475 quote: &Pubkey,
476 params: &CancelUpToParams,
477) -> Instruction {
478 let base_account = get_associated_token_address(trader, base);
479 let quote_account = get_associated_token_address(trader, quote);
480 create_cancel_up_to_instruction_with_custom_token_accounts(
481 market,
482 trader,
483 &base_account,
484 "e_account,
485 base,
486 quote,
487 params,
488 )
489}
490
491pub fn create_cancel_up_to_instruction_with_custom_token_accounts(
492 market: &Pubkey,
493 trader: &Pubkey,
494 base_account: &Pubkey,
495 quote_account: &Pubkey,
496 base: &Pubkey,
497 quote: &Pubkey,
498 params: &CancelUpToParams,
499) -> Instruction {
500 _phoenix_instruction_template::<CancelUpToParams>(
501 market,
502 trader,
503 base_account,
504 quote_account,
505 base,
506 quote,
507 PhoenixInstruction::CancelUpTo,
508 Some(params),
509 )
510}
511
512pub fn create_cancel_multiple_orders_by_id_instruction(
513 market: &Pubkey,
514 trader: &Pubkey,
515 base: &Pubkey,
516 quote: &Pubkey,
517 params: &CancelMultipleOrdersByIdParams,
518) -> Instruction {
519 let base_account = get_associated_token_address(trader, base);
520 let quote_account = get_associated_token_address(trader, quote);
521 create_cancel_multiple_orders_by_id_instruction_with_custom_token_accounts(
522 market,
523 trader,
524 &base_account,
525 "e_account,
526 base,
527 quote,
528 params,
529 )
530}
531
532pub fn create_cancel_multiple_orders_by_id_instruction_with_custom_token_accounts(
533 market: &Pubkey,
534 trader: &Pubkey,
535 base_account: &Pubkey,
536 quote_account: &Pubkey,
537 base: &Pubkey,
538 quote: &Pubkey,
539 params: &CancelMultipleOrdersByIdParams,
540) -> Instruction {
541 _phoenix_instruction_template::<CancelMultipleOrdersByIdParams>(
542 market,
543 trader,
544 base_account,
545 quote_account,
546 base,
547 quote,
548 PhoenixInstruction::CancelMultipleOrdersById,
549 Some(params),
550 )
551}
552
553pub fn create_withdraw_funds_instruction(
554 market: &Pubkey,
555 trader: &Pubkey,
556 base: &Pubkey,
557 quote: &Pubkey,
558) -> Instruction {
559 let base_account = get_associated_token_address(trader, base);
560 let quote_account = get_associated_token_address(trader, quote);
561 create_withdraw_funds_instruction_with_custom_token_accounts(
562 market,
563 trader,
564 &base_account,
565 "e_account,
566 base,
567 quote,
568 )
569}
570
571pub fn create_withdraw_funds_instruction_with_custom_token_accounts(
572 market: &Pubkey,
573 trader: &Pubkey,
574 base_account: &Pubkey,
575 quote_account: &Pubkey,
576 base: &Pubkey,
577 quote: &Pubkey,
578) -> Instruction {
579 _phoenix_instruction_template::<WithdrawParams>(
580 market,
581 trader,
582 base_account,
583 quote_account,
584 base,
585 quote,
586 PhoenixInstruction::WithdrawFunds,
587 Some(&WithdrawParams {
588 quote_lots_to_withdraw: None,
589 base_lots_to_withdraw: None,
590 }),
591 )
592}
593
594pub fn create_withdraw_funds_with_custom_amounts_instruction(
595 market: &Pubkey,
596 trader: &Pubkey,
597 base: &Pubkey,
598 quote: &Pubkey,
599 base_lots: u64,
600 quote_lots: u64,
601) -> Instruction {
602 let base_account = get_associated_token_address(trader, base);
603 let quote_account = get_associated_token_address(trader, quote);
604 create_withdraw_funds_with_custom_amounts_instruction_with_custom_token_accounts(
605 market,
606 trader,
607 &base_account,
608 "e_account,
609 base,
610 quote,
611 &WithdrawParams {
612 quote_lots_to_withdraw: Some(quote_lots),
613 base_lots_to_withdraw: Some(base_lots),
614 },
615 )
616}
617
618pub fn create_withdraw_funds_with_custom_amounts_instruction_with_custom_token_accounts(
619 market: &Pubkey,
620 trader: &Pubkey,
621 base_account: &Pubkey,
622 quote_account: &Pubkey,
623 base: &Pubkey,
624 quote: &Pubkey,
625 params: &WithdrawParams,
626) -> Instruction {
627 _phoenix_instruction_template::<WithdrawParams>(
628 market,
629 trader,
630 base_account,
631 quote_account,
632 base,
633 quote,
634 PhoenixInstruction::WithdrawFunds,
635 Some(params),
636 )
637}
638
639pub fn create_request_seat_instruction(payer: &Pubkey, market: &Pubkey) -> Instruction {
640 let (seat, _) = get_seat_address(market, payer);
641 Instruction {
642 program_id: crate::id(),
643 accounts: vec![
644 AccountMeta::new_readonly(crate::id(), false),
645 AccountMeta::new_readonly(phoenix_log_authority::id(), false),
646 AccountMeta::new(*market, false),
647 AccountMeta::new(*payer, true),
648 AccountMeta::new(seat, false),
649 AccountMeta::new_readonly(system_program::id(), false),
650 ],
651 data: PhoenixInstruction::RequestSeat.to_vec(),
652 }
653}