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, "e_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}