1#[macro_use]
16mod log;
17pub mod program;
18pub mod quantities;
19mod shank_structs;
21pub mod state;
22
23use crate::program::processor::*;
24
25use borsh::BorshSerialize;
26use ellipsis_macros::declare_id;
28use solana_program::{program::set_return_data, pubkey::Pubkey};
29
30use program::{
31 assert_with_msg, event_recorder::EventRecorder, PhoenixInstruction, PhoenixLogContext,
32 PhoenixMarketContext,
33};
34use solana_program::{
35 account_info::{next_account_info, AccountInfo},
36 entrypoint::ProgramResult,
37 program_error::ProgramError,
38};
39use state::markets::MarketEvent;
40
41#[cfg(not(feature = "no-entrypoint"))]
42use solana_security_txt::security_txt;
43
44#[cfg(not(feature = "no-entrypoint"))]
45security_txt! {
46 name: "Phoenix V1",
48 project_url: "https://ellipsislabs.xyz/",
49 contacts: "email:maintainers@ellipsislabs.xyz",
50 policy: "https://github.com/Ellipsis-Labs/phoenix-v1/blob/master/SECURITY.md",
51 preferred_languages: "en",
53 source_code: "https://github.com/Ellipsis-Labs/phoenix-v1",
54 auditors: "contact@osec.io"
55}
56
57declare_id!("PhoeNiXZ8ByJGLkxNfZRnkUfjvmuYqLR89jjFHGqdXY");
58
59pub mod phoenix_log_authority {
62 use ellipsis_macros::declare_pda;
64 use solana_program::pubkey::Pubkey;
65
66 declare_pda!(
70 "7aDTsspkQNGKmrexAN7FLx9oxU3iPczSSvHNggyuqYkR",
71 "PhoeNiXZ8ByJGLkxNfZRnkUfjvmuYqLR89jjFHGqdXY",
72 "log"
73 );
74
75 #[test]
76 fn check_pda() {
77 use crate::phoenix_log_authority;
78 use solana_program::pubkey::Pubkey;
79 assert_eq!(
80 phoenix_log_authority::ID,
81 Pubkey::create_program_address(
82 &["log".as_ref(), &[phoenix_log_authority::bump()]],
83 &super::id()
84 )
85 .unwrap()
86 );
87 }
88}
89
90#[cfg(not(feature = "no-entrypoint"))]
91solana_program::entrypoint!(process_instruction);
92
93pub fn process_instruction(
94 program_id: &Pubkey,
95 accounts: &[AccountInfo],
96 instruction_data: &[u8],
97) -> ProgramResult {
98 let (tag, data) = instruction_data
99 .split_first()
100 .ok_or(ProgramError::InvalidInstructionData)?;
101
102 let instruction =
103 PhoenixInstruction::try_from(*tag).or(Err(ProgramError::InvalidInstructionData))?;
104
105 if let PhoenixInstruction::Log = instruction {
113 let authority = next_account_info(&mut accounts.iter())?;
114 assert_with_msg(
115 authority.is_signer,
116 ProgramError::MissingRequiredSignature,
117 "Log authority must sign through CPI",
118 )?;
119 assert_with_msg(
120 authority.key == &phoenix_log_authority::id(),
121 ProgramError::InvalidArgument,
122 "Invalid log authority",
123 )?;
124 return Ok(());
125 }
126
127 let (program_accounts, accounts) = accounts.split_at(4);
128 let accounts_iter = &mut program_accounts.iter();
129 let phoenix_log_context = PhoenixLogContext::load(accounts_iter)?;
130 let market_context = if instruction == PhoenixInstruction::InitializeMarket {
131 PhoenixMarketContext::load_init(accounts_iter)?
132 } else {
133 PhoenixMarketContext::load(accounts_iter)?
134 };
135
136 let mut event_recorder = EventRecorder::new(phoenix_log_context, &market_context, instruction)?;
137
138 let mut record_event_fn = |e: MarketEvent<Pubkey>| event_recorder.add_event(e);
139 let mut order_ids = Vec::new();
140
141 match instruction {
142 PhoenixInstruction::InitializeMarket => {
143 phoenix_log!("PhoenixInstruction::Initialize");
144 initialize::process_initialize_market(program_id, &market_context, accounts, data)?
145 }
146 PhoenixInstruction::Swap => {
147 phoenix_log!("PhoenixInstruction::Swap");
148 new_order::process_swap(
149 program_id,
150 &market_context,
151 accounts,
152 data,
153 &mut record_event_fn,
154 )?;
155 }
156 PhoenixInstruction::SwapWithFreeFunds => {
157 phoenix_log!("PhoenixInstruction::SwapWithFreeFunds");
158 new_order::process_swap_with_free_funds(
159 program_id,
160 &market_context,
161 accounts,
162 data,
163 &mut record_event_fn,
164 )?;
165 }
166 PhoenixInstruction::PlaceLimitOrder => {
167 phoenix_log!("PhoenixInstruction::PlaceLimitOrder");
168 new_order::process_place_limit_order(
169 program_id,
170 &market_context,
171 accounts,
172 data,
173 &mut record_event_fn,
174 &mut order_ids,
175 )?
176 }
177 PhoenixInstruction::PlaceLimitOrderWithFreeFunds => {
178 phoenix_log!("PhoenixInstruction::PlaceLimitOrderWithFreeFunds");
179 new_order::process_place_limit_order_with_free_funds(
180 program_id,
181 &market_context,
182 accounts,
183 data,
184 &mut record_event_fn,
185 &mut order_ids,
186 )?;
187 }
188 PhoenixInstruction::PlaceMultiplePostOnlyOrders => {
189 phoenix_log!("PhoenixInstruction::PlaceMultiplePostOnlyOrders");
190 new_order::process_place_multiple_post_only_orders(
191 program_id,
192 &market_context,
193 accounts,
194 data,
195 &mut record_event_fn,
196 &mut order_ids,
197 )?;
198 }
199 PhoenixInstruction::PlaceMultiplePostOnlyOrdersWithFreeFunds => {
200 phoenix_log!("PhoenixInstruction::PlaceMultiplePostOnlyOrdersWithFreeFunds");
201 new_order::process_place_multiple_post_only_orders_with_free_funds(
202 program_id,
203 &market_context,
204 accounts,
205 data,
206 &mut record_event_fn,
207 &mut order_ids,
208 )?;
209 }
210 PhoenixInstruction::ReduceOrder => {
211 phoenix_log!("PhoenixInstruction::ReduceOrder");
212 reduce_order::process_reduce_order(
213 program_id,
214 &market_context,
215 accounts,
216 data,
217 true,
218 &mut record_event_fn,
219 )?
220 }
221 PhoenixInstruction::ReduceOrderWithFreeFunds => {
222 phoenix_log!("PhoenixInstruction::ReduceOrderWithFreeFunds");
223 reduce_order::process_reduce_order(
224 program_id,
225 &market_context,
226 accounts,
227 data,
228 false,
229 &mut record_event_fn,
230 )?
231 }
232 PhoenixInstruction::CancelAllOrders => {
233 phoenix_log!("PhoenixInstruction::CancelAllOrders");
234 cancel_multiple_orders::process_cancel_all_orders(
235 program_id,
236 &market_context,
237 accounts,
238 data,
239 true,
240 &mut record_event_fn,
241 )?
242 }
243 PhoenixInstruction::CancelAllOrdersWithFreeFunds => {
244 phoenix_log!("PhoenixInstruction::CancelAllOrdersWithFreeFunds");
245 cancel_multiple_orders::process_cancel_all_orders(
246 program_id,
247 &market_context,
248 accounts,
249 data,
250 false,
251 &mut record_event_fn,
252 )?
253 }
254 PhoenixInstruction::CancelUpTo => {
255 phoenix_log!("PhoenixInstruction::CancelMultipleOrders");
256 cancel_multiple_orders::process_cancel_up_to(
257 program_id,
258 &market_context,
259 accounts,
260 data,
261 true,
262 &mut record_event_fn,
263 )?
264 }
265 PhoenixInstruction::CancelUpToWithFreeFunds => {
266 phoenix_log!("PhoenixInstruction::CancelUpToWithFreeFunds");
267 cancel_multiple_orders::process_cancel_up_to(
268 program_id,
269 &market_context,
270 accounts,
271 data,
272 false,
273 &mut record_event_fn,
274 )?
275 }
276 PhoenixInstruction::CancelMultipleOrdersById => {
277 phoenix_log!("PhoenixInstruction::CancelMultipleOrdersById");
278 cancel_multiple_orders::process_cancel_multiple_orders_by_id(
279 program_id,
280 &market_context,
281 accounts,
282 data,
283 true,
284 &mut record_event_fn,
285 )?
286 }
287 PhoenixInstruction::CancelMultipleOrdersByIdWithFreeFunds => {
288 phoenix_log!("PhoenixInstruction::CancelMultipleOrdersByIdWithFreeFunds");
289 cancel_multiple_orders::process_cancel_multiple_orders_by_id(
290 program_id,
291 &market_context,
292 accounts,
293 data,
294 false,
295 &mut record_event_fn,
296 )?
297 }
298 PhoenixInstruction::WithdrawFunds => {
299 phoenix_log!("PhoenixInstruction::WithdrawFunds");
300 withdraw::process_withdraw_funds(program_id, &market_context, accounts, data)?;
301 }
302 PhoenixInstruction::DepositFunds => {
303 phoenix_log!("PhoenixInstruction::DepositFunds");
304 deposit::process_deposit_funds(program_id, &market_context, accounts, data)?
305 }
306 PhoenixInstruction::ForceCancelOrders => {
307 phoenix_log!("PhoenixInstruction::ForceCancelOrders");
308 governance::process_force_cancel_orders(
309 program_id,
310 &market_context,
311 accounts,
312 data,
313 &mut record_event_fn,
314 )?
315 }
316 PhoenixInstruction::EvictSeat => {
317 phoenix_log!("PhoenixInstruction::EvictSeat");
318 governance::process_evict_seat(program_id, &market_context, accounts, data)?
319 }
320 PhoenixInstruction::ClaimAuthority => {
321 phoenix_log!("PhoenixInstruction::ClaimAuthority");
322 governance::process_claim_authority(program_id, &market_context, data)?
323 }
324 PhoenixInstruction::NameSuccessor => {
325 phoenix_log!("PhoenixInstruction::NameSuccessor");
326 governance::process_name_successor(program_id, &market_context, data)?
327 }
328 PhoenixInstruction::ChangeMarketStatus => {
329 phoenix_log!("PhoenixInstruction::ChangeMarketStatus");
330 governance::process_change_market_status(program_id, &market_context, accounts, data)?
331 }
332 PhoenixInstruction::RequestSeatAuthorized => {
333 phoenix_log!("PhoenixInstruction::RequestSeatAuthorized");
334 manage_seat::process_request_seat_authorized(
335 program_id,
336 &market_context,
337 accounts,
338 data,
339 )?
340 }
341 PhoenixInstruction::RequestSeat => {
342 phoenix_log!("PhoenixInstruction::RequestSeat");
343 manage_seat::process_request_seat(program_id, &market_context, accounts, data)?
344 }
345 PhoenixInstruction::ChangeSeatStatus => {
346 phoenix_log!("PhoenixInstruction::ChangeSeatStatus");
347 manage_seat::process_change_seat_status(program_id, &market_context, accounts, data)?;
348 }
349 PhoenixInstruction::CollectFees => {
350 phoenix_log!("PhoenixInstruction::CollectFees");
351 fees::process_collect_fees(
352 program_id,
353 &market_context,
354 accounts,
355 data,
356 &mut record_event_fn,
357 )?
358 }
359 PhoenixInstruction::ChangeFeeRecipient => {
360 phoenix_log!("PhoenixInstruction::ChangeFeeRecipient");
361 fees::process_change_fee_recipient(program_id, &market_context, accounts, data)?
362 }
363 _ => unreachable!(),
364 }
365 event_recorder.increment_market_sequence_number_and_flush(market_context.market_info)?;
366 if !order_ids.is_empty() {
369 set_return_data(order_ids.try_to_vec()?.as_ref());
370 }
371 Ok(())
372}