phoenix/program/instruction_builders/
market_authority_instructions.rs

1use crate::phoenix_log_authority;
2use crate::program::status::{MarketStatus, SeatApprovalStatus};
3use crate::program::{
4    get_market_size, processor::*, MarketHeader, MarketSizeParams, PhoenixInstruction,
5};
6use crate::state::Side;
7use borsh::BorshSerialize;
8use solana_program::{
9    instruction::{AccountMeta, Instruction},
10    program_error::ProgramError,
11    pubkey::Pubkey,
12    rent::Rent,
13    system_instruction, system_program,
14};
15use spl_associated_token_account::get_associated_token_address;
16
17use crate::program::loaders::get_vault_address;
18use crate::program::validation::loaders::get_seat_address;
19
20#[allow(clippy::too_many_arguments)]
21pub fn create_initialize_market_instructions(
22    market: &Pubkey,
23    base: &Pubkey,
24    quote: &Pubkey,
25    market_creator: &Pubkey,
26    header_params: MarketSizeParams,
27    num_quote_lots_per_quote_unit: u64,
28    num_base_lots_per_base_unit: u64,
29    tick_size_in_quote_lots_per_base_unit: u64,
30    taker_fee_bps: u16,
31    fee_collector: &Pubkey,
32    raw_base_units_per_base_unit: Option<u32>,
33) -> Result<Vec<Instruction>, ProgramError> {
34    let space = std::mem::size_of::<MarketHeader>() + get_market_size(&header_params)?;
35    Ok(vec![
36        system_instruction::create_account(
37            market_creator,
38            market,
39            Rent::default().minimum_balance(space),
40            space as u64,
41            &crate::id(),
42        ),
43        create_initialize_market_instruction(
44            market,
45            base,
46            quote,
47            market_creator,
48            header_params,
49            num_quote_lots_per_quote_unit,
50            num_base_lots_per_base_unit,
51            tick_size_in_quote_lots_per_base_unit,
52            taker_fee_bps,
53            fee_collector,
54            raw_base_units_per_base_unit,
55        ),
56    ])
57}
58
59#[allow(clippy::too_many_arguments)]
60pub fn create_initialize_market_instructions_default(
61    market: &Pubkey,
62    base: &Pubkey,
63    quote: &Pubkey,
64    market_creator: &Pubkey,
65    header_params: MarketSizeParams,
66    num_quote_lots_per_quote_unit: u64,
67    num_base_lots_per_base_unit: u64,
68    tick_size_in_quote_lots_per_base_unit: u64,
69    taker_fee_bps: u16,
70    raw_base_units_per_base_unit: Option<u32>,
71) -> Result<Vec<Instruction>, ProgramError> {
72    let space = std::mem::size_of::<MarketHeader>() + get_market_size(&header_params)?;
73    Ok(vec![
74        system_instruction::create_account(
75            market_creator,
76            market,
77            Rent::default().minimum_balance(space),
78            space as u64,
79            &crate::id(),
80        ),
81        create_initialize_market_instruction(
82            market,
83            base,
84            quote,
85            market_creator,
86            header_params,
87            num_quote_lots_per_quote_unit,
88            num_base_lots_per_base_unit,
89            tick_size_in_quote_lots_per_base_unit,
90            taker_fee_bps,
91            market_creator,
92            raw_base_units_per_base_unit,
93        ),
94    ])
95}
96
97#[allow(clippy::too_many_arguments)]
98pub fn create_initialize_market_instruction(
99    market: &Pubkey,
100    base: &Pubkey,
101    quote: &Pubkey,
102    market_creator: &Pubkey,
103    header_params: MarketSizeParams,
104    num_quote_lots_per_quote_unit: u64,
105    num_base_lots_per_base_unit: u64,
106    tick_size_in_quote_lots_per_base_unit: u64,
107    taker_fee_bps: u16,
108    fee_collector: &Pubkey,
109    raw_base_units_per_base_unit: Option<u32>,
110) -> Instruction {
111    let (base_vault, _) = get_vault_address(market, base);
112    let (quote_vault, _) = get_vault_address(market, quote);
113    Instruction {
114        program_id: crate::id(),
115        accounts: vec![
116            AccountMeta::new_readonly(crate::id(), false),
117            AccountMeta::new_readonly(phoenix_log_authority::id(), false),
118            AccountMeta::new(*market, false),
119            AccountMeta::new(*market_creator, true),
120            AccountMeta::new_readonly(*base, false),
121            AccountMeta::new_readonly(*quote, false),
122            AccountMeta::new(base_vault, false),
123            AccountMeta::new(quote_vault, false),
124            AccountMeta::new_readonly(system_program::id(), false),
125            AccountMeta::new_readonly(spl_token::id(), false),
126        ],
127        data: [
128            PhoenixInstruction::InitializeMarket.to_vec(),
129            InitializeParams {
130                market_size_params: header_params,
131                num_quote_lots_per_quote_unit,
132                num_base_lots_per_base_unit,
133                tick_size_in_quote_lots_per_base_unit,
134                taker_fee_bps,
135                fee_collector: *fee_collector,
136                raw_base_units_per_base_unit,
137            }
138            .try_to_vec()
139            .unwrap(),
140        ]
141        .concat(),
142    }
143}
144
145pub fn create_evict_seat_instruction(
146    authority: &Pubkey,
147    market: &Pubkey,
148    trader: &Pubkey,
149    base: &Pubkey,
150    quote: &Pubkey,
151) -> Instruction {
152    let base_account = get_associated_token_address(trader, base);
153    let quote_account = get_associated_token_address(trader, quote);
154    let (seat, _) = get_seat_address(market, trader);
155    let (base_vault, _) = get_vault_address(market, base);
156    let (quote_vault, _) = get_vault_address(market, quote);
157    Instruction {
158        program_id: crate::id(),
159        accounts: vec![
160            AccountMeta::new_readonly(crate::id(), false),
161            AccountMeta::new_readonly(phoenix_log_authority::id(), false),
162            AccountMeta::new(*market, false),
163            AccountMeta::new_readonly(*authority, true),
164            AccountMeta::new_readonly(*trader, false),
165            AccountMeta::new_readonly(seat, false),
166            AccountMeta::new(base_account, false),
167            AccountMeta::new(quote_account, false),
168            AccountMeta::new(base_vault, false),
169            AccountMeta::new(quote_vault, false),
170            AccountMeta::new_readonly(spl_token::id(), false),
171        ],
172        data: PhoenixInstruction::EvictSeat.to_vec(),
173    }
174}
175
176pub fn create_claim_authority_instruction(authority: &Pubkey, market: &Pubkey) -> Instruction {
177    Instruction {
178        program_id: crate::id(),
179        accounts: vec![
180            AccountMeta::new_readonly(crate::id(), false),
181            AccountMeta::new_readonly(phoenix_log_authority::id(), false),
182            AccountMeta::new(*market, false),
183            AccountMeta::new_readonly(*authority, true),
184        ],
185        data: PhoenixInstruction::ClaimAuthority.to_vec(),
186    }
187}
188
189pub fn create_name_successor_instruction(
190    authority: &Pubkey,
191    market: &Pubkey,
192    successor: &Pubkey,
193) -> Instruction {
194    Instruction {
195        program_id: crate::id(),
196        accounts: vec![
197            AccountMeta::new_readonly(crate::id(), false),
198            AccountMeta::new_readonly(phoenix_log_authority::id(), false),
199            AccountMeta::new(*market, false),
200            AccountMeta::new_readonly(*authority, true),
201        ],
202        data: [
203            PhoenixInstruction::NameSuccessor.to_vec(),
204            successor.try_to_vec().unwrap(),
205        ]
206        .concat(),
207    }
208}
209
210pub fn create_change_market_status_instruction(
211    authority: &Pubkey,
212    market: &Pubkey,
213    status: MarketStatus,
214) -> Instruction {
215    Instruction {
216        program_id: crate::id(),
217        accounts: vec![
218            AccountMeta::new_readonly(crate::id(), false),
219            AccountMeta::new_readonly(phoenix_log_authority::id(), false),
220            AccountMeta::new(*market, false),
221            AccountMeta::new(*authority, true),
222        ],
223        data: [
224            PhoenixInstruction::ChangeMarketStatus.to_vec(),
225            status.try_to_vec().unwrap(),
226        ]
227        .concat(),
228    }
229}
230
231pub fn create_request_seat_authorized_instruction(
232    authority: &Pubkey,
233    payer: &Pubkey,
234    market: &Pubkey,
235    trader: &Pubkey,
236) -> Instruction {
237    let (seat, _) = get_seat_address(market, trader);
238    Instruction {
239        program_id: crate::id(),
240        accounts: vec![
241            AccountMeta::new_readonly(crate::id(), false),
242            AccountMeta::new_readonly(phoenix_log_authority::id(), false),
243            AccountMeta::new(*market, false),
244            AccountMeta::new_readonly(*authority, true),
245            AccountMeta::new(*payer, true),
246            AccountMeta::new_readonly(*trader, false),
247            AccountMeta::new(seat, false),
248            AccountMeta::new_readonly(system_program::id(), false),
249        ],
250        data: PhoenixInstruction::RequestSeatAuthorized.to_vec(),
251    }
252}
253
254pub fn create_change_seat_status_instruction(
255    authority: &Pubkey,
256    market: &Pubkey,
257    trader: &Pubkey,
258    status: SeatApprovalStatus,
259) -> Instruction {
260    let (seat, _) = get_seat_address(market, trader);
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(*authority, true),
268            AccountMeta::new(seat, false),
269        ],
270        data: [
271            PhoenixInstruction::ChangeSeatStatus.to_vec(),
272            status.try_to_vec().unwrap(),
273        ]
274        .concat(),
275    }
276}
277
278pub fn create_collect_fees_instruction_default(
279    market: &Pubkey,
280    sweeper: &Pubkey,
281    fee_collector: &Pubkey,
282    quote_mint: &Pubkey,
283) -> Instruction {
284    let quote_account = get_associated_token_address(fee_collector, quote_mint);
285    create_collect_fees_instruction(market, sweeper, &quote_account, quote_mint)
286}
287
288pub fn create_collect_fees_instruction(
289    market: &Pubkey,
290    sweeper: &Pubkey,
291    quote_account: &Pubkey,
292    quote_mint: &Pubkey,
293) -> Instruction {
294    let (quote_vault, _) = get_vault_address(market, quote_mint);
295    Instruction {
296        program_id: crate::id(),
297        accounts: vec![
298            AccountMeta::new_readonly(crate::id(), false),
299            AccountMeta::new_readonly(phoenix_log_authority::id(), false),
300            AccountMeta::new(*market, false),
301            AccountMeta::new_readonly(*sweeper, true),
302            AccountMeta::new(*quote_account, false),
303            AccountMeta::new(quote_vault, false),
304            AccountMeta::new_readonly(spl_token::id(), false),
305        ],
306        data: PhoenixInstruction::CollectFees.to_vec(),
307    }
308}
309
310pub fn create_change_fee_recipient_instruction(
311    authority: &Pubkey,
312    market: &Pubkey,
313    new_fee_recipient: &Pubkey,
314) -> Instruction {
315    Instruction {
316        program_id: crate::id(),
317        accounts: vec![
318            AccountMeta::new_readonly(crate::id(), false),
319            AccountMeta::new_readonly(phoenix_log_authority::id(), false),
320            AccountMeta::new(*market, false),
321            AccountMeta::new_readonly(*authority, true),
322            AccountMeta::new_readonly(*new_fee_recipient, false),
323        ],
324        data: [PhoenixInstruction::ChangeFeeRecipient.to_vec()].concat(),
325    }
326}
327
328pub fn create_change_fee_recipient_with_unclaimed_fees_instruction(
329    authority: &Pubkey,
330    market: &Pubkey,
331    new_fee_recipient: &Pubkey,
332    current_fee_recipient: &Pubkey,
333) -> Instruction {
334    Instruction {
335        program_id: crate::id(),
336        accounts: vec![
337            AccountMeta::new_readonly(crate::id(), false),
338            AccountMeta::new_readonly(phoenix_log_authority::id(), false),
339            AccountMeta::new(*market, false),
340            AccountMeta::new_readonly(*authority, true),
341            AccountMeta::new_readonly(*new_fee_recipient, false),
342            AccountMeta::new_readonly(*current_fee_recipient, true),
343        ],
344        data: [PhoenixInstruction::ChangeFeeRecipient.to_vec()].concat(),
345    }
346}
347
348pub fn create_force_cancel_orders_instructions(
349    market: &Pubkey,
350    trader: &Pubkey,
351    market_authority: &Pubkey,
352    base: &Pubkey,
353    quote: &Pubkey,
354) -> Vec<Instruction> {
355    vec![
356        create_force_cancel_orders_instruction(
357            market,
358            trader,
359            market_authority,
360            base,
361            quote,
362            Side::Bid,
363        ),
364        create_force_cancel_orders_instruction(
365            market,
366            trader,
367            market_authority,
368            base,
369            quote,
370            Side::Ask,
371        ),
372    ]
373}
374
375fn create_force_cancel_orders_instruction(
376    market: &Pubkey,
377    trader: &Pubkey,
378    market_authority: &Pubkey,
379    base: &Pubkey,
380    quote: &Pubkey,
381    side: Side,
382) -> Instruction {
383    let (base_vault, _) = get_vault_address(market, base);
384    let (quote_vault, _) = get_vault_address(market, quote);
385    let base_account = get_associated_token_address(trader, base);
386    let quote_account = get_associated_token_address(trader, quote);
387    let (seat, _) = get_seat_address(market, trader);
388    Instruction {
389        program_id: crate::id(),
390        accounts: vec![
391            AccountMeta::new_readonly(crate::id(), false),
392            AccountMeta::new_readonly(phoenix_log_authority::id(), false),
393            AccountMeta::new(*market, false),
394            AccountMeta::new_readonly(*market_authority, true),
395            AccountMeta::new_readonly(*trader, false),
396            AccountMeta::new_readonly(seat, false),
397            AccountMeta::new(base_account, false),
398            AccountMeta::new(quote_account, false),
399            AccountMeta::new(base_vault, false),
400            AccountMeta::new(quote_vault, false),
401            AccountMeta::new_readonly(spl_token::id(), false),
402        ],
403        data: [
404            PhoenixInstruction::ForceCancelOrders.to_vec(),
405            CancelUpToParams {
406                side,
407                tick_limit: None,
408                num_orders_to_cancel: None,
409                num_orders_to_search: None,
410            }
411            .try_to_vec()
412            .unwrap(),
413        ]
414        .concat(),
415    }
416}