phoenix/program/instruction_builders/
market_instructions.rs

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        &quote_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        &quote_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        &quote_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        &quote_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        &quote_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        &quote_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        &quote_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        &quote_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        &quote_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}