1#![cfg_attr(not(feature = "program"), allow(unused))]
2use num_enum::TryFromPrimitive;
3use std::{
4 cell::RefMut, convert::identity, convert::TryInto, mem::size_of, num::NonZeroU64, ops::Deref,
5 ops::DerefMut,
6};
7
8use arrayref::{array_ref, array_refs, mut_array_refs};
9
10use bytemuck::{
11 bytes_of, bytes_of_mut, cast, cast_slice, cast_slice_mut, from_bytes_mut, try_cast_mut,
12 try_cast_slice_mut, try_from_bytes_mut, Pod, Zeroable,
13};
14use enumflags2::BitFlags;
15use num_traits::FromPrimitive;
16use safe_transmute::{self, to_bytes::transmute_to_bytes, trivial::TriviallyTransmutable};
17
18use solana_program::{
19 account_info::AccountInfo, program_error::ProgramError, program_pack::Pack, pubkey::Pubkey,
20 rent::Rent, sysvar::Sysvar,
21};
22use spl_token::error::TokenError;
23
24use crate::{
25 critbit::Slab,
26 error::{DexErrorCode, DexResult, SourceFileId},
27 fees::{self, FeeTier},
28 instruction::{
29 disable_authority, fee_sweeper, msrm_token, srm_token, CancelOrderInstructionV2,
30 InitializeMarketInstruction, MarketInstruction, NewOrderInstructionV3, SelfTradeBehavior,
31 SendTakeInstruction,
32 },
33 matching::{OrderBookState, OrderType, RequestProceeds, Side},
34};
35
36declare_check_assert_macros!(SourceFileId::State);
37
38pub trait ToAlignedBytes {
39 fn to_aligned_bytes(&self) -> [u64; 4];
40}
41
42impl ToAlignedBytes for Pubkey {
43 #[inline]
44 fn to_aligned_bytes(&self) -> [u64; 4] {
45 cast(self.to_bytes())
46 }
47}
48
49#[derive(Copy, Clone, BitFlags, Debug, Eq, PartialEq)]
50#[repr(u64)]
51pub enum AccountFlag {
52 Initialized = 1u64 << 0,
53 Market = 1u64 << 1,
54 OpenOrders = 1u64 << 2,
55 RequestQueue = 1u64 << 3,
56 EventQueue = 1u64 << 4,
57 Bids = 1u64 << 5,
58 Asks = 1u64 << 6,
59 Disabled = 1u64 << 7,
60 Closed = 1u64 << 8,
61 Permissioned = 1u64 << 9,
62 CrankAuthorityRequired = 1u64 << 10,
63}
64
65pub enum Market<'a> {
67 V1(RefMut<'a, MarketState>),
68 V2(RefMut<'a, MarketStateV2>),
69}
70
71impl<'a> Deref for Market<'a> {
72 type Target = MarketState;
73
74 fn deref(&self) -> &Self::Target {
75 match self {
76 Market::V1(v1) => v1.deref(),
77 Market::V2(v2) => v2.deref(),
78 }
79 }
80}
81
82impl<'a> DerefMut for Market<'a> {
83 fn deref_mut(&mut self) -> &mut Self::Target {
84 match self {
85 Market::V1(v1) => v1.deref_mut(),
86 Market::V2(v2) => v2.deref_mut(),
87 }
88 }
89}
90
91impl<'a> Market<'a> {
92 #[inline]
93 pub fn load(
94 market_account: &'a AccountInfo,
95 program_id: &Pubkey,
96 allow_disabled: bool,
98 ) -> DexResult<Self> {
99 let flags = Market::account_flags(&market_account.try_borrow_data()?)?;
100 if flags.intersects(AccountFlag::Permissioned) {
101 Ok(Market::V2(MarketStateV2::load(
102 market_account,
103 program_id,
104 allow_disabled,
105 )?))
106 } else {
107 Ok(Market::V1(MarketState::load(
108 market_account,
109 program_id,
110 allow_disabled,
111 )?))
112 }
113 }
114
115 pub fn account_flags(account_data: &[u8]) -> DexResult<BitFlags<AccountFlag>> {
116 let start = ACCOUNT_HEAD_PADDING.len();
117 let end = start + size_of::<AccountFlag>();
118 check_assert!(account_data.len() >= end)?;
119
120 let mut flag_bytes = [0u8; 8];
121 flag_bytes.copy_from_slice(&account_data[start..end]);
122
123 BitFlags::from_bits(u64::from_le_bytes(flag_bytes))
124 .map_err(|_| DexErrorCode::InvalidMarketFlags.into())
125 .map(Into::into)
126 }
127
128 pub fn open_orders_authority(&self) -> Option<&Pubkey> {
129 match &self {
130 Market::V1(_) => None,
131 Market::V2(state) => Some(&state.open_orders_authority),
132 }
133 }
134
135 pub fn prune_authority(&self) -> Option<&Pubkey> {
136 match &self {
137 Market::V1(_) => None,
138 Market::V2(state) => Some(&state.prune_authority),
139 }
140 }
141
142 pub fn consume_events_authority(&self) -> Option<&Pubkey> {
143 match &self {
144 Market::V1(_) => None,
145 Market::V2(state) => {
146 let flags = BitFlags::from_bits(state.inner.account_flags).unwrap();
147 if flags.intersects(AccountFlag::CrankAuthorityRequired) {
148 Some(&state.consume_events_authority)
149 } else {
150 None
151 }
152 }
153 }
154 }
155
156 pub fn load_orders_mut(
157 &self,
158 orders_account: &'a AccountInfo,
159 owner_account: Option<&AccountInfo>,
160 program_id: &Pubkey,
161 rent: Option<Rent>,
162 open_orders_authority: Option<account_parser::SignerAccount>,
163 ) -> DexResult<RefMut<'a, OpenOrders>> {
164 check_assert_eq!(orders_account.owner, program_id)?;
165 let mut open_orders: RefMut<'a, OpenOrders>;
166
167 let open_orders_data_len = orders_account.data_len();
168 let open_orders_lamports = orders_account.lamports();
169 let (_, data) = strip_header::<[u8; 0], u8>(orders_account, true)?;
170 open_orders = RefMut::map(data, |data| from_bytes_mut(data));
171
172 if open_orders.account_flags == 0 {
173 let oo_authority = open_orders_authority.map(|a| a.inner().key);
174 if oo_authority != self.open_orders_authority() {
175 return Err(DexErrorCode::InvalidOpenOrdersAuthority.into());
176 }
177
178 let rent = rent.ok_or(DexErrorCode::RentNotProvided)?;
179 let owner_account = owner_account.ok_or(DexErrorCode::OwnerAccountNotProvided)?;
180 if !rent.is_exempt(open_orders_lamports, open_orders_data_len) {
181 return Err(DexErrorCode::OrdersNotRentExempt)?;
182 }
183 open_orders.init(
184 &identity(self.own_address),
185 &owner_account.key.to_aligned_bytes(),
186 )?;
187 }
188
189 open_orders.check_flags()?;
190 check_assert_eq!(identity(open_orders.market), identity(self.own_address))
191 .map_err(|_| DexErrorCode::WrongOrdersAccount)?;
192 if let Some(owner) = owner_account {
193 check_assert_eq!(&identity(open_orders.owner), &owner.key.to_aligned_bytes())
194 .map_err(|_| DexErrorCode::WrongOrdersAccount)?;
195 }
196
197 Ok(open_orders)
198 }
199}
200
201#[derive(Copy, Clone)]
202#[cfg_attr(target_endian = "little", derive(Debug))]
203#[repr(packed)]
204pub struct MarketStateV2 {
205 pub inner: MarketState,
206 pub open_orders_authority: Pubkey,
207 pub prune_authority: Pubkey,
208 pub consume_events_authority: Pubkey,
209 padding: [u8; 992],
211}
212
213impl Deref for MarketStateV2 {
214 type Target = MarketState;
215
216 fn deref(&self) -> &Self::Target {
217 &self.inner
218 }
219}
220
221impl DerefMut for MarketStateV2 {
222 fn deref_mut(&mut self) -> &mut Self::Target {
223 &mut self.inner
224 }
225}
226
227impl MarketStateV2 {
228 #[inline]
229 pub fn load<'a>(
230 market_account: &'a AccountInfo,
231 program_id: &Pubkey,
232 allow_disabled: bool,
233 ) -> DexResult<RefMut<'a, Self>> {
234 check_assert_eq!(market_account.owner, program_id)?;
235
236 let mut account_data: RefMut<'a, [u8]>;
237 let state: RefMut<'a, Self>;
238
239 account_data = RefMut::map(market_account.try_borrow_mut_data()?, |data| *data);
240 check_account_padding(&mut account_data)?;
241
242 state = RefMut::map(account_data, |data| {
243 from_bytes_mut(cast_slice_mut(
244 check_account_padding(data).unwrap_or_else(|_| unreachable!()),
245 ))
246 });
247
248 state.check_flags(allow_disabled)?;
249 Ok(state)
250 }
251
252 #[inline]
253 pub fn check_flags(&self, allow_disabled: bool) -> DexResult {
254 let flags = BitFlags::from_bits(self.account_flags)
255 .map_err(|_| DexErrorCode::InvalidMarketFlags)?;
256
257 let required_flags =
258 AccountFlag::Initialized | AccountFlag::Market | AccountFlag::Permissioned;
259 let required_crank_flags = required_flags | AccountFlag::CrankAuthorityRequired;
260
261 if allow_disabled {
262 let disabled_flags = required_flags | AccountFlag::Disabled;
263 let disabled_crank_flags = required_crank_flags | AccountFlag::Disabled;
264 if flags != required_flags
265 && flags != required_crank_flags
266 && flags != disabled_flags
267 && flags != disabled_crank_flags
268 {
269 return Err(DexErrorCode::InvalidMarketFlags.into());
270 }
271 } else {
272 if flags != required_flags && flags != required_crank_flags {
273 return Err(DexErrorCode::InvalidMarketFlags.into());
274 }
275 }
276
277 Ok(())
278 }
279}
280
281#[cfg(target_endian = "little")]
282unsafe impl Zeroable for MarketStateV2 {}
283
284#[cfg(target_endian = "little")]
285unsafe impl Pod for MarketStateV2 {}
286
287#[cfg(target_endian = "little")]
288unsafe impl TriviallyTransmutable for MarketStateV2 {}
289
290#[derive(Copy, Clone)]
291#[cfg_attr(target_endian = "little", derive(Debug))]
292#[repr(packed)]
293pub struct MarketState {
294 pub account_flags: u64, pub own_address: [u64; 4],
299
300 pub vault_signer_nonce: u64,
302 pub coin_mint: [u64; 4],
304 pub pc_mint: [u64; 4],
306
307 pub coin_vault: [u64; 4],
309 pub coin_deposits_total: u64,
311 pub coin_fees_accrued: u64,
313
314 pub pc_vault: [u64; 4],
316 pub pc_deposits_total: u64,
318 pub pc_fees_accrued: u64,
320
321 pub pc_dust_threshold: u64,
323
324 pub req_q: [u64; 4],
326 pub event_q: [u64; 4],
328
329 pub bids: [u64; 4],
331 pub asks: [u64; 4],
333
334 pub coin_lot_size: u64,
336 pub pc_lot_size: u64,
338
339 pub fee_rate_bps: u64,
341 pub referrer_rebates_accrued: u64,
343}
344#[cfg(target_endian = "little")]
345unsafe impl Zeroable for MarketState {}
346#[cfg(target_endian = "little")]
347unsafe impl Pod for MarketState {}
348#[cfg(target_endian = "little")]
349unsafe impl TriviallyTransmutable for MarketState {}
350
351pub const ACCOUNT_HEAD_PADDING: &[u8; 5] = b"serum";
352pub const ACCOUNT_TAIL_PADDING: &[u8; 7] = b"padding";
353
354fn init_account_padding(data: &mut [u8]) -> DexResult<&mut [[u8; 8]]> {
355 check_assert!(data.len() >= 12)?;
356 let (head, data, tail) = mut_array_refs![data, 5; ..; 7];
357 *head = *ACCOUNT_HEAD_PADDING;
358 *tail = *ACCOUNT_TAIL_PADDING;
359 Ok(try_cast_slice_mut(data).or(check_unreachable!())?)
360}
361
362fn check_account_padding(data: &mut [u8]) -> DexResult<&mut [[u8; 8]]> {
363 check_assert!(data.len() >= 12)?;
364 let (head, data, tail) = mut_array_refs![data, 5; ..; 7];
365 check_assert_eq!(head, ACCOUNT_HEAD_PADDING)?;
366 check_assert_eq!(tail, ACCOUNT_TAIL_PADDING)?;
367 Ok(try_cast_slice_mut(data).or(check_unreachable!())?)
368}
369
370fn strip_account_padding(padded_data: &mut [u8], init_allowed: bool) -> DexResult<&mut [[u8; 8]]> {
371 if init_allowed {
372 init_account_padding(padded_data)
373 } else {
374 check_account_padding(padded_data)
375 }
376}
377
378pub fn strip_header<'a, H: Pod, D: Pod>(
379 account: &'a AccountInfo,
380 init_allowed: bool,
381) -> DexResult<(RefMut<'a, H>, RefMut<'a, [D]>)> {
382 let mut result = Ok(());
383 let (header, inner): (RefMut<'a, [H]>, RefMut<'a, [D]>) =
384 RefMut::map_split(account.try_borrow_mut_data()?, |padded_data| {
385 let dummy_value: (&mut [H], &mut [D]) = (&mut [], &mut []);
386 let padded_data: &mut [u8] = *padded_data;
387 let u64_data = match strip_account_padding(padded_data, init_allowed) {
388 Ok(u64_data) => u64_data,
389 Err(e) => {
390 result = Err(e);
391 return dummy_value;
392 }
393 };
394
395 let data: &mut [u8] = cast_slice_mut(u64_data);
396 let (header_bytes, inner_bytes) = data.split_at_mut(size_of::<H>());
397 let header: &mut H;
398 let inner: &mut [D];
399
400 header = match try_from_bytes_mut(header_bytes) {
401 Ok(h) => h,
402 Err(_e) => {
403 result = Err(assertion_error!().into());
404 return dummy_value;
405 }
406 };
407 inner = remove_slop_mut(inner_bytes);
408
409 (std::slice::from_mut(header), inner)
410 });
411 result?;
412 let header = RefMut::map(header, |s| s.first_mut().unwrap_or_else(|| unreachable!()));
413 Ok((header, inner))
414}
415
416impl MarketState {
417 #[inline]
418 pub fn load<'a>(
419 market_account: &'a AccountInfo,
420 program_id: &Pubkey,
421 allow_disabled: bool,
422 ) -> DexResult<RefMut<'a, Self>> {
423 check_assert_eq!(market_account.owner, program_id)?;
424 let mut account_data: RefMut<'a, [u8]>;
425 let state: RefMut<'a, Self>;
426
427 account_data = RefMut::map(market_account.try_borrow_mut_data()?, |data| *data);
428 check_account_padding(&mut account_data)?;
429 state = RefMut::map(account_data, |data| {
430 from_bytes_mut(cast_slice_mut(
431 check_account_padding(data).unwrap_or_else(|_| unreachable!()),
432 ))
433 });
434
435 state.check_flags(allow_disabled)?;
436 Ok(state)
437 }
438
439 #[inline]
440 pub fn check_flags(&self, allow_disabled: bool) -> DexResult {
441 let flags = BitFlags::from_bits(self.account_flags)
442 .map_err(|_| DexErrorCode::InvalidMarketFlags)?;
443 let required_flags = AccountFlag::Initialized | AccountFlag::Market;
444 if allow_disabled {
445 let disabled_flags = required_flags | AccountFlag::Disabled;
446 if flags != required_flags && flags != disabled_flags {
447 return Err(DexErrorCode::InvalidMarketFlags.into());
448 }
449 } else {
450 if flags != required_flags {
451 return Err(DexErrorCode::InvalidMarketFlags.into());
452 }
453 }
454 Ok(())
455 }
456
457 pub fn load_bids_mut<'a>(&self, bids: &'a AccountInfo) -> DexResult<RefMut<'a, Slab>> {
458 check_assert_eq!(&bids.key.to_aligned_bytes(), &identity(self.bids))
459 .map_err(|_| DexErrorCode::WrongBidsAccount)?;
460 let (header, buf) = strip_header::<OrderBookStateHeader, u8>(bids, false)?;
461 let flags = BitFlags::from_bits(header.account_flags).unwrap();
462 check_assert_eq!(&flags, &(AccountFlag::Initialized | AccountFlag::Bids))?;
463 Ok(RefMut::map(buf, Slab::new))
464 }
465
466 pub fn load_asks_mut<'a>(&self, asks: &'a AccountInfo) -> DexResult<RefMut<'a, Slab>> {
467 check_assert_eq!(&asks.key.to_aligned_bytes(), &identity(self.asks))
468 .map_err(|_| DexErrorCode::WrongAsksAccount)?;
469 let (header, buf) = strip_header::<OrderBookStateHeader, u8>(asks, false)?;
470 let flags = BitFlags::from_bits(header.account_flags).unwrap();
471 check_assert_eq!(&flags, &(AccountFlag::Initialized | AccountFlag::Asks))?;
472 Ok(RefMut::map(buf, Slab::new))
473 }
474
475 fn load_request_queue_mut<'a>(&self, queue: &'a AccountInfo) -> DexResult<RequestQueue<'a>> {
476 check_assert_eq!(&queue.key.to_aligned_bytes(), &identity(self.req_q))
477 .map_err(|_| DexErrorCode::WrongRequestQueueAccount)?;
478
479 let (header, buf) = strip_header::<RequestQueueHeader, Request>(queue, false)?;
480 let flags = BitFlags::from_bits(header.account_flags).unwrap();
481 check_assert_eq!(
482 &flags,
483 &(AccountFlag::Initialized | AccountFlag::RequestQueue)
484 )?;
485 Ok(Queue { header, buf })
486 }
487
488 fn load_event_queue_mut<'a>(&self, queue: &'a AccountInfo) -> DexResult<EventQueue<'a>> {
489 check_assert_eq!(&queue.key.to_aligned_bytes(), &identity(self.event_q))
490 .map_err(|_| DexErrorCode::WrongEventQueueAccount)?;
491 let (header, buf) = strip_header::<EventQueueHeader, Event>(queue, false)?;
492
493 let flags = BitFlags::from_bits(header.account_flags).unwrap();
494 check_assert_eq!(
495 &flags,
496 &(AccountFlag::Initialized | AccountFlag::EventQueue)
497 )?;
498 Ok(Queue { header, buf })
499 }
500
501 #[inline]
502 fn check_coin_vault(&self, vault: account_parser::TokenAccount) -> DexResult {
503 if identity(self.coin_vault) != vault.inner().key.to_aligned_bytes() {
504 Err(DexErrorCode::WrongCoinVault)?
505 }
506 Ok(())
507 }
508
509 #[inline]
510 fn check_pc_vault(&self, vault: account_parser::TokenAccount) -> DexResult {
511 if identity(self.pc_vault) != vault.inner().key.to_aligned_bytes() {
512 Err(DexErrorCode::WrongPcVault)?
513 }
514 Ok(())
515 }
516
517 #[inline]
518 fn check_coin_payer(&self, payer: account_parser::TokenAccount) -> DexResult {
519 if &payer.inner().try_borrow_data()?[..32] != transmute_to_bytes(&identity(self.coin_mint))
520 {
521 Err(DexErrorCode::WrongCoinMint)?
522 }
523 Ok(())
524 }
525
526 #[inline]
527 fn check_pc_payer(&self, payer: account_parser::TokenAccount) -> DexResult {
528 if &payer.inner().try_borrow_data()?[..32] != transmute_to_bytes(&identity(self.pc_mint)) {
529 Err(DexErrorCode::WrongPcMint)?
530 }
531 Ok(())
532 }
533
534 #[inline]
535 fn load_fee_tier(
536 &self,
537 expected_owner: &[u64; 4],
538 srm_or_msrm_account: Option<account_parser::TokenAccount>,
539 ) -> DexResult<FeeTier> {
540 let srm_or_msrm_account = match srm_or_msrm_account {
541 Some(a) => a,
542 None => return Ok(FeeTier::Base),
543 };
544 let data = srm_or_msrm_account.inner().try_borrow_data()?;
545
546 let mut aligned_data: [u64; 9] = Zeroable::zeroed();
547 bytes_of_mut(&mut aligned_data).copy_from_slice(&data[..72]);
548 let (mint, owner, &[balance]) = array_refs![&aligned_data, 4, 4, 1];
549
550 check_assert_eq!(owner, expected_owner)?;
551 if mint == &srm_token::ID.to_aligned_bytes() {
552 return Ok(FeeTier::from_srm_and_msrm_balances(balance, 0));
553 }
554
555 if mint == &msrm_token::ID.to_aligned_bytes() {
556 return Ok(FeeTier::from_srm_and_msrm_balances(0, balance));
557 }
558
559 Ok(FeeTier::from_srm_and_msrm_balances(0, 0))
560 }
561
562 fn check_enabled(&self) -> DexResult {
563 let flags = BitFlags::from_bits(self.account_flags).unwrap();
564 if flags.contains(AccountFlag::Disabled) {
565 return Err(DexErrorCode::MarketIsDisabled.into());
566 }
567 Ok(())
568 }
569
570 fn pubkey(&self) -> Pubkey {
571 Pubkey::new(cast_slice(&identity(self.own_address) as &[_]))
572 }
573}
574
575#[repr(packed)]
576#[derive(Copy, Clone)]
577#[cfg_attr(feature = "fuzz", derive(Debug))]
578pub struct OpenOrders {
579 pub account_flags: u64, pub market: [u64; 4],
581 pub owner: [u64; 4],
582
583 pub native_coin_free: u64,
584 pub native_coin_total: u64,
585
586 pub native_pc_free: u64,
587 pub native_pc_total: u64,
588
589 pub free_slot_bits: u128,
590 pub is_bid_bits: u128,
591 pub orders: [u128; 128],
592 pub client_order_ids: [u64; 128],
594 pub referrer_rebates_accrued: u64,
595}
596unsafe impl Pod for OpenOrders {}
597unsafe impl Zeroable for OpenOrders {}
598
599impl OpenOrders {
600 fn check_flags(&self) -> DexResult {
601 let flags = BitFlags::from_bits(self.account_flags)
602 .map_err(|_| DexErrorCode::InvalidMarketFlags)?;
603 let required_flags = AccountFlag::Initialized | AccountFlag::OpenOrders;
604 if flags != required_flags {
605 Err(DexErrorCode::WrongOrdersAccount)?
606 }
607 Ok(())
608 }
609
610 fn init(&mut self, market: &[u64; 4], owner: &[u64; 4]) -> DexResult<()> {
611 check_assert_eq!(self.account_flags, 0)?;
612 self.account_flags = (AccountFlag::Initialized | AccountFlag::OpenOrders).bits();
613 self.market = *market;
614 self.owner = *owner;
615 self.native_coin_total = 0;
616 self.native_coin_free = 0;
617 self.native_pc_total = 0;
618 self.native_pc_free = 0;
619 self.free_slot_bits = std::u128::MAX;
620 Ok(())
621 }
622
623 fn credit_locked_coin(&mut self, native_coin_amount: u64) {
624 self.native_coin_total = self
625 .native_coin_total
626 .checked_add(native_coin_amount)
627 .unwrap();
628 }
629
630 fn credit_locked_pc(&mut self, native_pc_amount: u64) {
631 self.native_pc_total = self.native_pc_total.checked_add(native_pc_amount).unwrap();
632 }
633
634 fn lock_free_coin(&mut self, native_coin_amount: u64) {
635 self.native_coin_free = self
636 .native_coin_free
637 .checked_sub(native_coin_amount)
638 .unwrap();
639 }
640
641 fn lock_free_pc(&mut self, native_pc_amount: u64) {
642 self.native_pc_free = self.native_pc_free.checked_sub(native_pc_amount).unwrap();
643 }
644
645 pub fn unlock_coin(&mut self, native_coin_amount: u64) {
646 self.native_coin_free = self
647 .native_coin_free
648 .checked_add(native_coin_amount)
649 .unwrap();
650 assert!(self.native_coin_free <= self.native_coin_total);
651 }
652
653 pub fn unlock_pc(&mut self, native_pc_amount: u64) {
654 self.native_pc_free = self.native_pc_free.checked_add(native_pc_amount).unwrap();
655 assert!(self.native_pc_free <= self.native_pc_total);
656 }
657
658 fn slot_is_free(&self, slot: u8) -> bool {
659 let slot_mask = 1u128 << slot;
660 self.free_slot_bits & slot_mask != 0
661 }
662
663 #[inline]
664 fn iter_filled_slots(&self) -> impl Iterator<Item = u8> {
665 struct Iter {
666 bits: u128,
667 }
668 impl Iterator for Iter {
669 type Item = u8;
670 #[inline(always)]
671 fn next(&mut self) -> Option<Self::Item> {
672 if self.bits == 0 {
673 None
674 } else {
675 let next = self.bits.trailing_zeros();
676 let mask = 1u128 << next;
677 self.bits &= !mask;
678 Some(next as u8)
679 }
680 }
681 }
682 Iter {
683 bits: !self.free_slot_bits,
684 }
685 }
686
687 #[inline]
688 fn orders_with_client_ids(&self) -> impl Iterator<Item = (NonZeroU64, u128, Side)> + '_ {
689 self.iter_filled_slots().filter_map(move |slot| {
690 let client_order_id = NonZeroU64::new(self.client_order_ids[slot as usize])?;
691 let order_id = self.orders[slot as usize];
692 let side = self.slot_side(slot).unwrap();
693 Some((client_order_id, order_id, side))
694 })
695 }
696
697 pub fn slot_side(&self, slot: u8) -> Option<Side> {
698 let slot_mask = 1u128 << slot;
699 if self.free_slot_bits & slot_mask != 0 {
700 None
701 } else if self.is_bid_bits & slot_mask != 0 {
702 Some(Side::Bid)
703 } else {
704 Some(Side::Ask)
705 }
706 }
707
708 pub fn remove_order(&mut self, slot: u8) -> DexResult {
709 check_assert!(slot < 128)?;
710 check_assert!(!self.slot_is_free(slot))?;
711
712 let slot_mask = 1u128 << slot;
713 self.orders[slot as usize] = 0;
714 self.client_order_ids[slot as usize] = 0;
715 self.free_slot_bits |= slot_mask;
716 self.is_bid_bits &= !slot_mask;
717
718 Ok(())
719 }
720
721 fn add_order(&mut self, id: u128, side: Side) -> DexResult<u8> {
722 if self.free_slot_bits == 0 {
723 Err(DexErrorCode::TooManyOpenOrders)?;
724 }
725 let slot = self.free_slot_bits.trailing_zeros();
726 check_assert!(self.slot_is_free(slot as u8))?;
727 let slot_mask = 1u128 << slot;
728 self.free_slot_bits &= !slot_mask;
729 match side {
730 Side::Bid => {
731 self.is_bid_bits |= slot_mask;
732 }
733 Side::Ask => {
734 self.is_bid_bits &= !slot_mask;
735 }
736 };
737 self.orders[slot as usize] = id;
738 Ok(slot as u8)
739 }
740}
741
742pub trait QueueHeader: Pod {
743 type Item: Pod + Copy;
744
745 fn head(&self) -> u64;
746 fn set_head(&mut self, value: u64);
747 fn count(&self) -> u64;
748 fn set_count(&mut self, value: u64);
749
750 fn incr_event_id(&mut self);
751 fn decr_event_id(&mut self, n: u64);
752}
753
754pub struct Queue<'a, H: QueueHeader> {
755 header: RefMut<'a, H>,
756 buf: RefMut<'a, [H::Item]>,
757}
758
759impl<'a, H: QueueHeader> Queue<'a, H> {
760 pub fn new(header: RefMut<'a, H>, buf: RefMut<'a, [H::Item]>) -> Self {
761 Self { header, buf }
762 }
763
764 #[inline]
765 pub fn len(&self) -> u64 {
766 self.header.count()
767 }
768
769 #[inline]
770 pub fn full(&self) -> bool {
771 self.header.count() as usize == self.buf.len()
772 }
773
774 #[inline]
775 pub fn empty(&self) -> bool {
776 self.header.count() == 0
777 }
778
779 #[inline]
780 pub fn push_back(&mut self, value: H::Item) -> Result<(), H::Item> {
781 if self.full() {
782 return Err(value);
783 }
784 let slot = ((self.header.head() + self.header.count()) as usize) % self.buf.len();
785 self.buf[slot] = value;
786
787 let count = self.header.count();
788 self.header.set_count(count + 1);
789
790 self.header.incr_event_id();
791 Ok(())
792 }
793
794 #[inline]
795 pub fn peek_front(&self) -> Option<&H::Item> {
796 if self.empty() {
797 return None;
798 }
799 Some(&self.buf[self.header.head() as usize])
800 }
801
802 #[inline]
803 pub fn peek_front_mut(&mut self) -> Option<&mut H::Item> {
804 if self.empty() {
805 return None;
806 }
807 Some(&mut self.buf[self.header.head() as usize])
808 }
809
810 #[inline]
811 pub fn pop_front(&mut self) -> Result<H::Item, ()> {
812 if self.empty() {
813 return Err(());
814 }
815 let value = self.buf[self.header.head() as usize];
816
817 let count = self.header.count();
818 self.header.set_count(count - 1);
819
820 let head = self.header.head();
821 self.header.set_head((head + 1) % self.buf.len() as u64);
822
823 Ok(value)
824 }
825
826 #[inline]
827 pub fn revert_pushes(&mut self, desired_len: u64) -> DexResult<()> {
828 check_assert!(desired_len <= self.header.count())?;
829 let len_diff = self.header.count() - desired_len;
830 self.header.set_count(desired_len);
831 self.header.decr_event_id(len_diff);
832 Ok(())
833 }
834
835 pub fn iter(&self) -> impl Iterator<Item = &H::Item> {
836 QueueIterator {
837 queue: self,
838 index: 0,
839 }
840 }
841}
842
843struct QueueIterator<'a, 'b, H: QueueHeader> {
844 queue: &'b Queue<'a, H>,
845 index: u64,
846}
847
848impl<'a, 'b, H: QueueHeader> Iterator for QueueIterator<'a, 'b, H> {
849 type Item = &'b H::Item;
850 fn next(&mut self) -> Option<Self::Item> {
851 if self.index == self.queue.len() {
852 None
853 } else {
854 let item = &self.queue.buf
855 [(self.queue.header.head() + self.index) as usize % self.queue.buf.len()];
856 self.index += 1;
857 Some(item)
858 }
859 }
860}
861
862#[derive(Copy, Clone, Debug)]
863#[repr(packed)]
864pub struct RequestQueueHeader {
865 account_flags: u64, head: u64,
867 count: u64,
868 next_seq_num: u64,
869}
870unsafe impl Zeroable for RequestQueueHeader {}
871unsafe impl Pod for RequestQueueHeader {}
872
873impl QueueHeader for RequestQueueHeader {
874 type Item = Request;
875
876 fn head(&self) -> u64 {
877 self.head
878 }
879 fn set_head(&mut self, value: u64) {
880 self.head = value;
881 }
882 fn count(&self) -> u64 {
883 self.count
884 }
885 fn set_count(&mut self, value: u64) {
886 self.count = value;
887 }
888 #[inline(always)]
889 fn incr_event_id(&mut self) {}
890 #[inline(always)]
891 fn decr_event_id(&mut self, _n: u64) {}
892}
893
894pub type RequestQueue<'a> = Queue<'a, RequestQueueHeader>;
895
896impl RequestQueue<'_> {
897 fn gen_order_id(&mut self, limit_price: u64, side: Side) -> u128 {
898 let seq_num = self.gen_seq_num();
899 let upper = (limit_price as u128) << 64;
900 let lower = match side {
901 Side::Bid => !seq_num,
902 Side::Ask => seq_num,
903 };
904 upper | (lower as u128)
905 }
906
907 fn gen_seq_num(&mut self) -> u64 {
908 let seq_num = self.header.next_seq_num;
909 self.header.next_seq_num += 1;
910 seq_num
911 }
912}
913
914#[derive(Copy, Clone, BitFlags, Debug)]
915#[repr(u8)]
916enum RequestFlag {
917 NewOrder = 0x01,
918 CancelOrder = 0x02,
919 Bid = 0x04,
920 PostOnly = 0x08,
921 ImmediateOrCancel = 0x10,
922 DecrementTakeOnSelfTrade = 0x20,
923}
924
925#[derive(Copy, Clone, Debug)]
926#[repr(packed)]
927pub struct Request {
928 request_flags: u8,
929 owner_slot: u8,
930 fee_tier: u8,
931 self_trade_behavior: u8,
932 padding: [u8; 4],
933 max_coin_qty_or_cancel_id: u64,
934 native_pc_qty_locked: u64,
935 order_id: u128,
936 owner: [u64; 4],
937 client_order_id: u64,
938}
939unsafe impl Zeroable for Request {}
940unsafe impl Pod for Request {}
941
942#[derive(Debug)]
943pub enum RequestView {
944 NewOrder {
945 side: Side,
946 order_type: OrderType,
947 owner_slot: u8,
948 fee_tier: FeeTier,
949 order_id: u128,
950 max_coin_qty: NonZeroU64,
951 native_pc_qty_locked: Option<NonZeroU64>,
952 owner: [u64; 4],
953 client_order_id: Option<NonZeroU64>,
954 self_trade_behavior: SelfTradeBehavior,
955 },
956 CancelOrder {
957 side: Side,
958 order_id: u128,
959 cancel_id: u64,
960 expected_owner_slot: u8,
961 expected_owner: [u64; 4],
962 client_order_id: Option<NonZeroU64>,
963 },
964}
965
966impl Request {
967 #[inline(always)]
968 pub fn new(view: RequestView) -> Self {
969 match view {
970 RequestView::NewOrder {
971 side,
972 order_type,
973 owner_slot,
974 fee_tier,
975 order_id,
976 owner,
977 max_coin_qty,
978 native_pc_qty_locked,
979 client_order_id,
980 self_trade_behavior,
981 } => {
982 let mut flags = BitFlags::from_flag(RequestFlag::NewOrder);
983 if side == Side::Bid {
984 flags.insert(RequestFlag::Bid);
985 }
986 match order_type {
987 OrderType::PostOnly => flags |= RequestFlag::PostOnly,
988 OrderType::ImmediateOrCancel => flags |= RequestFlag::ImmediateOrCancel,
989 OrderType::Limit => (),
990 };
991
992 Request {
993 request_flags: flags.bits(),
994 owner_slot,
995 fee_tier: fee_tier.into(),
996 self_trade_behavior: self_trade_behavior.into(),
997 padding: Zeroable::zeroed(),
998 order_id,
999 owner,
1000 max_coin_qty_or_cancel_id: max_coin_qty.get(),
1001 native_pc_qty_locked: native_pc_qty_locked.map_or(0, NonZeroU64::get),
1002 client_order_id: client_order_id.map_or(0, NonZeroU64::get),
1003 }
1004 }
1005 RequestView::CancelOrder {
1006 side,
1007 expected_owner_slot,
1008 order_id,
1009 expected_owner,
1010 cancel_id,
1011 client_order_id,
1012 } => {
1013 let mut flags = BitFlags::from_flag(RequestFlag::CancelOrder);
1014 if side == Side::Bid {
1015 flags.insert(RequestFlag::Bid);
1016 }
1017 Request {
1018 request_flags: flags.bits(),
1019 max_coin_qty_or_cancel_id: cancel_id,
1020 order_id,
1021 owner_slot: expected_owner_slot,
1022 fee_tier: 0,
1023 self_trade_behavior: 0,
1024 owner: expected_owner,
1025 native_pc_qty_locked: 0,
1026 padding: Zeroable::zeroed(),
1027 client_order_id: client_order_id.map_or(0, NonZeroU64::get),
1028 }
1029 }
1030 }
1031 }
1032
1033 #[inline(always)]
1034 pub fn as_view(&self) -> DexResult<RequestView> {
1035 let flags = BitFlags::from_bits(self.request_flags).unwrap();
1036 let side = if flags.contains(RequestFlag::Bid) {
1037 Side::Bid
1038 } else {
1039 Side::Ask
1040 };
1041 if flags.contains(RequestFlag::NewOrder) {
1042 let allowed_flags = {
1043 use RequestFlag::*;
1044 NewOrder | Bid | PostOnly | ImmediateOrCancel
1045 };
1046 check_assert!(allowed_flags.contains(flags))?;
1047 let post_only = flags.contains(RequestFlag::PostOnly);
1048 let ioc = flags.contains(RequestFlag::ImmediateOrCancel);
1049 let order_type = match (post_only, ioc) {
1050 (true, false) => OrderType::PostOnly,
1051 (false, true) => OrderType::ImmediateOrCancel,
1052 (false, false) => OrderType::Limit,
1053 (true, true) => unreachable!(),
1054 };
1055 let fee_tier = FeeTier::try_from_primitive(self.fee_tier).or(check_unreachable!())?;
1056 let self_trade_behavior =
1057 SelfTradeBehavior::try_from_primitive(self.self_trade_behavior)
1058 .or(check_unreachable!())?;
1059 Ok(RequestView::NewOrder {
1060 side,
1061 order_type,
1062 owner_slot: self.owner_slot,
1063 fee_tier,
1064 self_trade_behavior,
1065 order_id: self.order_id,
1066 owner: self.owner,
1067 max_coin_qty: NonZeroU64::new(self.max_coin_qty_or_cancel_id).unwrap(),
1068 native_pc_qty_locked: NonZeroU64::new(self.native_pc_qty_locked),
1069 client_order_id: NonZeroU64::new(self.client_order_id),
1070 })
1071 } else {
1072 check_assert!(flags.contains(RequestFlag::CancelOrder))?;
1073 let allowed_flags = {
1074 use RequestFlag::*;
1075 CancelOrder | Bid
1076 };
1077 check_assert!(allowed_flags.contains(flags))?;
1078 Ok(RequestView::CancelOrder {
1079 side,
1080 cancel_id: self.max_coin_qty_or_cancel_id,
1081 order_id: self.order_id,
1082 expected_owner_slot: self.owner_slot,
1083 expected_owner: self.owner,
1084 client_order_id: NonZeroU64::new(self.client_order_id),
1085 })
1086 }
1087 }
1088}
1089
1090#[derive(Copy, Clone, Debug)]
1091#[repr(packed)]
1092pub struct EventQueueHeader {
1093 account_flags: u64, head: u64,
1095 count: u64,
1096 seq_num: u64,
1097}
1098unsafe impl Zeroable for EventQueueHeader {}
1099unsafe impl Pod for EventQueueHeader {}
1100
1101unsafe impl TriviallyTransmutable for EventQueueHeader {}
1102unsafe impl TriviallyTransmutable for RequestQueueHeader {}
1103
1104impl QueueHeader for EventQueueHeader {
1105 type Item = Event;
1106
1107 fn head(&self) -> u64 {
1108 self.head
1109 }
1110 fn set_head(&mut self, value: u64) {
1111 self.head = value;
1112 }
1113 fn count(&self) -> u64 {
1114 self.count
1115 }
1116 fn set_count(&mut self, value: u64) {
1117 self.count = value;
1118 }
1119 fn incr_event_id(&mut self) {
1120 self.seq_num += 1;
1121 }
1122 fn decr_event_id(&mut self, n: u64) {
1123 self.seq_num -= n;
1124 }
1125}
1126
1127pub type EventQueue<'a> = Queue<'a, EventQueueHeader>;
1128
1129#[derive(Copy, Clone, BitFlags, Debug)]
1130#[repr(u8)]
1131enum EventFlag {
1132 Fill = 0x1,
1133 Out = 0x2,
1134 Bid = 0x4,
1135 Maker = 0x8,
1136 ReleaseFunds = 0x10,
1137}
1138
1139impl EventFlag {
1140 #[inline]
1141 fn from_side(side: Side) -> BitFlags<Self> {
1142 match side {
1143 Side::Bid => EventFlag::Bid.into(),
1144 Side::Ask => BitFlags::empty(),
1145 }
1146 }
1147
1148 #[inline]
1149 fn flags_to_side(flags: BitFlags<Self>) -> Side {
1150 if flags.contains(EventFlag::Bid) {
1151 Side::Bid
1152 } else {
1153 Side::Ask
1154 }
1155 }
1156}
1157
1158#[derive(Copy, Clone, Debug)]
1159#[repr(packed)]
1160pub struct Event {
1161 event_flags: u8,
1162 owner_slot: u8,
1163
1164 fee_tier: u8,
1165
1166 _padding: [u8; 5],
1167
1168 native_qty_released: u64,
1169 native_qty_paid: u64,
1170 native_fee_or_rebate: u64,
1171
1172 order_id: u128,
1173 pub owner: [u64; 4],
1174 client_order_id: u64,
1175}
1176unsafe impl Zeroable for Event {}
1177unsafe impl Pod for Event {}
1178
1179unsafe impl TriviallyTransmutable for Event {}
1180unsafe impl TriviallyTransmutable for Request {}
1181
1182impl Event {
1183 #[inline(always)]
1184 pub fn new(view: EventView) -> Self {
1185 match view {
1186 EventView::Fill {
1187 side,
1188 maker,
1189 native_qty_paid,
1190 native_qty_received,
1191 native_fee_or_rebate,
1192 order_id,
1193 owner,
1194 owner_slot,
1195 fee_tier,
1196 client_order_id,
1197 } => {
1198 let maker_flag = if maker {
1199 BitFlags::from_flag(EventFlag::Maker).bits()
1200 } else {
1201 0
1202 };
1203 let event_flags =
1204 (EventFlag::from_side(side) | EventFlag::Fill).bits() | maker_flag;
1205 Event {
1206 event_flags,
1207 owner_slot,
1208 fee_tier: fee_tier.into(),
1209
1210 _padding: Zeroable::zeroed(),
1211
1212 native_qty_released: native_qty_received,
1213 native_qty_paid,
1214 native_fee_or_rebate,
1215
1216 order_id,
1217 owner,
1218
1219 client_order_id: client_order_id.map_or(0, NonZeroU64::get),
1220 }
1221 }
1222
1223 EventView::Out {
1224 side,
1225 release_funds,
1226 native_qty_unlocked,
1227 native_qty_still_locked,
1228 order_id,
1229 owner,
1230 owner_slot,
1231 client_order_id,
1232 } => {
1233 let release_funds_flag = if release_funds {
1234 BitFlags::from_flag(EventFlag::ReleaseFunds).bits()
1235 } else {
1236 0
1237 };
1238 let event_flags =
1239 (EventFlag::from_side(side) | EventFlag::Out).bits() | release_funds_flag;
1240 Event {
1241 event_flags,
1242 owner_slot,
1243 fee_tier: 0,
1244
1245 _padding: Zeroable::zeroed(),
1246
1247 native_qty_released: native_qty_unlocked,
1248 native_qty_paid: native_qty_still_locked,
1249 native_fee_or_rebate: 0,
1250
1251 order_id,
1252 owner,
1253 client_order_id: client_order_id.map_or(0, NonZeroU64::get),
1254 }
1255 }
1256 }
1257 }
1258
1259 #[inline(always)]
1260 pub fn as_view(&self) -> DexResult<EventView> {
1261 let flags = BitFlags::from_bits(self.event_flags).unwrap();
1262 let side = EventFlag::flags_to_side(flags);
1263 let client_order_id = NonZeroU64::new(self.client_order_id);
1264 if flags.contains(EventFlag::Fill) {
1265 let allowed_flags = {
1266 use EventFlag::*;
1267 Fill | Bid | Maker
1268 };
1269 check_assert!(allowed_flags.contains(flags))?;
1270
1271 return Ok(EventView::Fill {
1272 side,
1273 maker: flags.contains(EventFlag::Maker),
1274 native_qty_paid: self.native_qty_paid,
1275 native_qty_received: self.native_qty_released,
1276 native_fee_or_rebate: self.native_fee_or_rebate,
1277
1278 order_id: self.order_id,
1279 owner: self.owner,
1280
1281 owner_slot: self.owner_slot,
1282 fee_tier: self.fee_tier.try_into().or(check_unreachable!())?,
1283 client_order_id,
1284 });
1285 }
1286 let allowed_flags = {
1287 use EventFlag::*;
1288 Out | Bid | ReleaseFunds
1289 };
1290 check_assert!(allowed_flags.contains(flags))?;
1291 Ok(EventView::Out {
1292 side,
1293 release_funds: flags.contains(EventFlag::ReleaseFunds),
1294 native_qty_unlocked: self.native_qty_released,
1295 native_qty_still_locked: self.native_qty_paid,
1296
1297 order_id: self.order_id,
1298 owner: self.owner,
1299
1300 owner_slot: self.owner_slot,
1301 client_order_id,
1302 })
1303 }
1304}
1305
1306#[derive(Debug)]
1307pub enum EventView {
1308 Fill {
1309 side: Side,
1310 maker: bool,
1311 native_qty_paid: u64,
1312 native_qty_received: u64,
1313 native_fee_or_rebate: u64,
1314 order_id: u128,
1315 owner: [u64; 4],
1316 owner_slot: u8,
1317 fee_tier: FeeTier,
1318 client_order_id: Option<NonZeroU64>,
1319 },
1320 Out {
1321 side: Side,
1322 release_funds: bool,
1323 native_qty_unlocked: u64,
1324 native_qty_still_locked: u64,
1325 order_id: u128,
1326 owner: [u64; 4],
1327 owner_slot: u8,
1328 client_order_id: Option<NonZeroU64>,
1329 },
1330}
1331
1332impl EventView {
1333 fn side(&self) -> Side {
1334 match self {
1335 &EventView::Fill { side, .. } | &EventView::Out { side, .. } => side,
1336 }
1337 }
1338}
1339
1340#[derive(Copy, Clone)]
1341#[repr(packed)]
1342struct OrderBookStateHeader {
1343 account_flags: u64, }
1345unsafe impl Zeroable for OrderBookStateHeader {}
1346unsafe impl Pod for OrderBookStateHeader {}
1347
1348pub enum State {}
1349
1350fn gen_vault_signer_seeds<'a>(nonce: &'a u64, market: &'a Pubkey) -> [&'a [u8]; 2] {
1351 [market.as_ref(), bytes_of(nonce)]
1352}
1353
1354#[cfg(not(any(test, feature = "fuzz")))]
1355#[inline]
1356pub fn gen_vault_signer_key(
1357 nonce: u64,
1358 market: &Pubkey,
1359 program_id: &Pubkey,
1360) -> Result<Pubkey, ProgramError> {
1361 let seeds = gen_vault_signer_seeds(&nonce, market);
1362 Ok(Pubkey::create_program_address(&seeds, program_id)?)
1363}
1364
1365#[cfg(any(test, feature = "fuzz"))]
1366pub fn gen_vault_signer_key(
1367 nonce: u64,
1368 market: &Pubkey,
1369 _program_id: &Pubkey,
1370) -> Result<Pubkey, ProgramError> {
1371 gen_vault_signer_seeds(&nonce, market);
1372 Ok(Pubkey::default())
1373}
1374
1375#[cfg(not(any(test, feature = "fuzz")))]
1376fn invoke_spl_token(
1377 instruction: &solana_program::instruction::Instruction,
1378 account_infos: &[AccountInfo],
1379 signers_seeds: &[&[&[u8]]],
1380) -> solana_program::entrypoint::ProgramResult {
1381 solana_program::program::invoke_signed(instruction, account_infos, signers_seeds)
1382}
1383
1384#[cfg(any(test, feature = "fuzz"))]
1385fn invoke_spl_token(
1386 instruction: &solana_program::instruction::Instruction,
1387 account_infos: &[AccountInfo],
1388 _signers_seeds: &[&[&[u8]]],
1389) -> solana_program::entrypoint::ProgramResult {
1390 assert_eq!(instruction.program_id, spl_token::ID);
1391 let account_infos: Vec<AccountInfo> = instruction
1392 .accounts
1393 .iter()
1394 .map(|meta| {
1395 account_infos
1396 .iter()
1397 .find(|info| *info.key == meta.pubkey)
1398 .unwrap()
1399 .clone()
1400 })
1401 .collect();
1402 spl_token::processor::Processor::process(
1403 &instruction.program_id,
1404 &account_infos,
1405 &instruction.data,
1406 )?;
1407 Ok(())
1408}
1409
1410#[cfg(feature = "program")]
1411fn send_from_vault<'a, 'b: 'a>(
1412 native_amount: u64,
1413 recipient: account_parser::TokenAccount<'a, 'b>,
1414 vault: account_parser::TokenAccount<'a, 'b>,
1415 spl_token_program: account_parser::SplTokenProgram<'a, 'b>,
1416 vault_signer: account_parser::VaultSigner<'a, 'b>,
1417 vault_signer_seeds: &[&[u8]],
1418) -> DexResult {
1419 let deposit_instruction = spl_token::instruction::transfer(
1420 &spl_token::ID,
1421 vault.inner().key,
1422 recipient.inner().key,
1423 &vault_signer.inner().key,
1424 &[],
1425 native_amount,
1426 )?;
1427 let accounts: &[AccountInfo] = &[
1428 vault.inner().clone(),
1429 recipient.inner().clone(),
1430 vault_signer.inner().clone(),
1431 spl_token_program.inner().clone(),
1432 ];
1433 invoke_spl_token(&deposit_instruction, &accounts[..], &[vault_signer_seeds])
1434 .map_err(|_| DexErrorCode::TransferFailed)?;
1435 Ok(())
1436}
1437
1438#[cfg(feature = "fuzz")]
1439pub mod fuzz_account_parser {
1440 pub use super::account_parser::SignerAccount;
1441}
1442
1443pub(crate) mod account_parser {
1444 use super::*;
1445
1446 macro_rules! declare_validated_account_wrapper {
1447 ($WrapperT:ident, $validate:expr $(, $a:ident : $t:ty)*) => {
1448 #[derive(Copy, Clone)]
1449 pub struct $WrapperT<'a, 'b: 'a>(&'a AccountInfo<'b>);
1450 impl<'a, 'b: 'a> $WrapperT<'a, 'b> {
1451 pub fn new(account: &'a AccountInfo<'b> $(,$a: $t)*) -> DexResult<Self> {
1452 let validate_result: DexResult = $validate(account $(,$a)*);
1453 validate_result?;
1454 Ok($WrapperT(account))
1455 }
1456
1457 #[inline(always)]
1458 #[allow(unused)]
1459 pub fn inner(self) -> &'a AccountInfo<'b> {
1460 self.0
1461 }
1462 }
1463 }
1464 }
1465
1466 declare_validated_account_wrapper!(SplTokenProgram, |account: &AccountInfo| {
1467 check_assert_eq!(*account.key, spl_token::ID)?;
1468 Ok(())
1469 });
1470
1471 declare_validated_account_wrapper!(TokenMint, |mint: &AccountInfo| {
1472 check_assert_eq!(*mint.owner, spl_token::ID)?;
1473 let data = mint.try_borrow_data()?;
1474 check_assert_eq!(data.len(), spl_token::state::Mint::LEN)?;
1475
1476 let is_initialized = data[0x2d];
1477 check_assert_eq!(is_initialized, 1u8)?;
1478 Ok(())
1479 });
1480
1481 declare_validated_account_wrapper!(TokenAccount, |account: &AccountInfo| {
1482 check_assert_eq!(*account.owner, spl_token::ID)?;
1483 let data = account.try_borrow_data()?;
1484 check_assert_eq!(data.len(), spl_token::state::Account::LEN)?;
1485
1486 let is_initialized = data[0x6c];
1487 check_assert_eq!(is_initialized, 1u8)?;
1488 Ok(())
1489 });
1490
1491 macro_rules! declare_validated_token_account_wrapper {
1492 ($WrapperT:ident, $validate:expr $(, $a:ident : $t:ty)*) => {
1493 #[derive(Copy, Clone)]
1494 pub struct $WrapperT<'a, 'b: 'a>(TokenAccount<'a, 'b>);
1495 impl<'a, 'b: 'a> $WrapperT<'a, 'b> {
1496 fn new(token_account: TokenAccount<'a, 'b> $(,$a: $t)*) -> DexResult<Self> {
1497 let validate_result: DexResult = $validate(token_account $(,$a)*);
1498 validate_result?;
1499 Ok($WrapperT(token_account))
1500 }
1501
1502 fn from_account(account: &'a AccountInfo<'b> $(,$a: $t)*) -> DexResult<Self> {
1503 let token_account = TokenAccount::new(account)?;
1504 Self::new(token_account $(,$a)*)
1505 }
1506
1507 #[inline(always)]
1508 pub fn token_account(self) -> TokenAccount<'a, 'b> {
1509 self.0
1510 }
1511
1512 #[inline(always)]
1513 #[allow(unused)]
1514 pub fn account(self) -> &'a AccountInfo<'b> {
1515 self.0.inner()
1516 }
1517 }
1518 }
1519 }
1520
1521 declare_validated_account_wrapper!(SignerAccount, |account: &AccountInfo| {
1522 check_assert!(account.is_signer)?;
1523 Ok(())
1524 });
1525
1526 declare_validated_account_wrapper!(SigningFeeSweeper, |account: &AccountInfo| {
1527 check_assert!(account.is_signer)?;
1528 check_assert_eq!(account.key, &fee_sweeper::ID)?;
1529 Ok(())
1530 });
1531
1532 declare_validated_account_wrapper!(SigningDisableAuthority, |account: &AccountInfo| {
1533 check_assert!(account.is_signer)?;
1534 check_assert_eq!(account.key, &disable_authority::ID)?;
1535 Ok(())
1536 });
1537
1538 declare_validated_token_account_wrapper!(
1539 CoinVault,
1540 |token_account: TokenAccount, market: &Market| { market.check_coin_vault(token_account) },
1541 market: &Market
1542 );
1543
1544 declare_validated_token_account_wrapper!(
1545 PcVault,
1546 |token_account: TokenAccount, market: &Market| { market.check_pc_vault(token_account) },
1547 market: &Market
1548 );
1549
1550 declare_validated_token_account_wrapper!(
1551 CoinWallet,
1552 |token_account: TokenAccount, market: &Market| { market.check_coin_payer(token_account) },
1553 market: &Market
1554 );
1555
1556 declare_validated_token_account_wrapper!(
1557 PcWallet,
1558 |token_account: TokenAccount, market: &Market| { market.check_pc_payer(token_account) },
1559 market: &Market
1560 );
1561
1562 declare_validated_account_wrapper!(
1563 VaultSigner,
1564 |account: &AccountInfo, market: &Market, program_id: &Pubkey| {
1565 let vault_signer_key =
1566 gen_vault_signer_key(market.vault_signer_nonce, &market.pubkey(), program_id)?;
1567 Ok(check_assert_eq!(&vault_signer_key, account.key)?)
1568 },
1569 market: &Market,
1570 program_id: &Pubkey
1571 );
1572
1573 impl<'a, 'b: 'a> TokenAccount<'a, 'b> {
1574 pub fn balance(self) -> DexResult<u64> {
1575 let data = self.inner().try_borrow_data()?;
1576 Ok(u64::from_le_bytes(*array_ref![data, 64, 8]))
1577 }
1578 }
1579
1580 #[derive(Copy, Clone)]
1581 pub struct TokenAccountAndMint<'a, 'b: 'a> {
1582 account: TokenAccount<'a, 'b>,
1583 mint: TokenMint<'a, 'b>,
1584 }
1585
1586 impl<'a, 'b: 'a> TokenAccountAndMint<'a, 'b> {
1587 fn new(account: TokenAccount<'a, 'b>, mint: TokenMint<'a, 'b>) -> DexResult<Self> {
1588 let account_data = account.0.try_borrow_data()?;
1589 check_assert_eq!(mint.0.key.as_ref(), &account_data[..32])?;
1590 Ok(TokenAccountAndMint { account, mint })
1591 }
1592
1593 pub fn get_account(self) -> TokenAccount<'a, 'b> {
1594 self.account
1595 }
1596
1597 pub fn get_mint(self) -> TokenMint<'a, 'b> {
1598 self.mint
1599 }
1600 }
1601
1602 pub struct InitializeMarketArgs<'a, 'b: 'a> {
1603 pub program_id: &'a Pubkey,
1604 pub instruction: &'a InitializeMarketInstruction,
1605 serum_dex_accounts: &'a [AccountInfo<'b>; 5],
1606 pub coin_vault_and_mint: TokenAccountAndMint<'a, 'b>,
1607 pub pc_vault_and_mint: TokenAccountAndMint<'a, 'b>,
1608 pub market_authority: Option<&'a AccountInfo<'b>>,
1609 pub prune_authority: Option<&'a AccountInfo<'b>>,
1610 pub consume_events_authority: Option<&'a AccountInfo<'b>>,
1611 }
1612
1613 impl<'a, 'b: 'a> InitializeMarketArgs<'a, 'b> {
1614 pub fn new(
1615 program_id: &'a Pubkey,
1616 instruction: &'a InitializeMarketInstruction,
1617 accounts: &'a [AccountInfo<'b>],
1618 ) -> DexResult<Self> {
1619 check_assert!(accounts.len() >= 10 && accounts.len() <= 13)?;
1620 let (
1621 unchecked_serum_dex_accounts,
1622 unchecked_vaults,
1623 unchecked_mints,
1624 unchecked_rent,
1625 remaining_accounts,
1626 ) = array_refs![accounts, 5, 2, 2, 1; .. ;];
1627
1628 let mut rem_iter = remaining_accounts.iter();
1629 let market_authority = rem_iter.next();
1630 let prune_authority = rem_iter.next();
1631 let consume_events_authority = rem_iter.next();
1632
1633 {
1634 #[cfg(any(test, feature = "fuzz"))]
1636 let rent = Rent::from_account_info(&unchecked_rent[0])?;
1637 #[cfg(not(any(test, feature = "fuzz")))]
1638 let rent = Rent::get()?;
1639
1640 let end_idx = accounts.len() - remaining_accounts.len() - 1;
1641 for account in &accounts[1..end_idx] {
1642 let data_len = account.data_len();
1643 let lamports = account.lamports();
1644 check_assert!(rent.is_exempt(lamports, data_len))?;
1645 }
1646 }
1647
1648 let mut checked_vaults = [None, None];
1649 for account in unchecked_serum_dex_accounts {
1650 check_assert_eq!(account.owner, program_id)?;
1651 let data = account.try_borrow_data()?;
1652 check_assert_eq!(data.len() % 8, 4)?;
1653 check_assert!(data.len() >= 20)?;
1654 let (padding5, header, _, padding7) = array_refs![&data, 5, 8; .. ; 7];
1655 check_assert_eq!(*padding5, [0u8; 5])?;
1656 check_assert_eq!(*header, [0u8; 8])?;
1657 check_assert_eq!(*padding7, [0u8; 7])?;
1658 }
1659 let serum_dex_accounts = unchecked_serum_dex_accounts;
1660 let vault_owner_key_bytes = gen_vault_signer_key(
1661 instruction.vault_signer_nonce,
1662 serum_dex_accounts[0].key,
1663 program_id,
1664 )?
1665 .to_bytes();
1666 for i in 0..=1 {
1667 let vault = TokenAccount::new(&unchecked_vaults[i])?;
1668 let mint = TokenMint::new(&unchecked_mints[i])?;
1669
1670 let vault_data = vault.0.try_borrow_data()?;
1672 let vault_owner = array_ref![vault_data, 0x20, 0x20];
1673 check_assert_eq!(vault_owner, &vault_owner_key_bytes)?;
1674
1675 let delegate_tag = array_ref![vault_data, 0x48, 0x4];
1677 check_assert_eq!(*delegate_tag, [0u8; 4])?;
1678
1679 checked_vaults[i] = Some(TokenAccountAndMint::new(vault, mint)?);
1680 }
1681 let [coin_vault_and_mint, pc_vault_and_mint] = match checked_vaults {
1682 [Some(cvm), Some(pvm)] => [cvm, pvm],
1683 _ => check_unreachable!()?,
1684 };
1685
1686 Ok(InitializeMarketArgs {
1687 program_id,
1688 instruction,
1689 serum_dex_accounts,
1690 coin_vault_and_mint,
1691 pc_vault_and_mint,
1692 market_authority,
1693 prune_authority,
1694 consume_events_authority,
1695 })
1696 }
1697
1698 pub fn get_market(&self) -> &'a AccountInfo<'b> {
1699 &self.serum_dex_accounts[0]
1700 }
1701
1702 pub fn get_req_q(&self) -> &'a AccountInfo<'b> {
1703 &self.serum_dex_accounts[1]
1704 }
1705
1706 pub fn get_event_q(&self) -> &'a AccountInfo<'b> {
1707 &self.serum_dex_accounts[2]
1708 }
1709
1710 pub fn get_bids(&self) -> &'a AccountInfo<'b> {
1711 &self.serum_dex_accounts[3]
1712 }
1713
1714 pub fn get_asks(&self) -> &'a AccountInfo<'b> {
1715 &self.serum_dex_accounts[4]
1716 }
1717 }
1718
1719 pub struct SendTakeArgs<'a, 'b: 'a> {
1720 pub instruction: &'a SendTakeInstruction,
1721 pub signer: SignerAccount<'a, 'b>,
1722 pub req_q: RequestQueue<'a>,
1723 pub event_q: EventQueue<'a>,
1724 pub order_book_state: OrderBookState<'a>,
1725 pub coin_wallet: CoinWallet<'a, 'b>,
1726 pub pc_wallet: PcWallet<'a, 'b>,
1727 pub coin_vault: CoinVault<'a, 'b>,
1728 pub pc_vault: PcVault<'a, 'b>,
1729 pub spl_token_program: SplTokenProgram<'a, 'b>,
1730 pub fee_tier: FeeTier,
1731 }
1732 impl<'a, 'b: 'a> SendTakeArgs<'a, 'b> {
1733 pub fn with_parsed_args<T>(
1734 program_id: &'a Pubkey,
1735 instruction: &'a SendTakeInstruction,
1736 accounts: &'a [AccountInfo<'b>],
1737 f: impl FnOnce(SendTakeArgs) -> DexResult<T>,
1738 ) -> DexResult<T> {
1739 const MIN_ACCOUNTS: usize = 11;
1740 check_assert!(accounts.len() == MIN_ACCOUNTS || accounts.len() == MIN_ACCOUNTS + 1)?;
1741 let (fixed_accounts, fee_discount_account): (
1742 &'a [AccountInfo<'b>; MIN_ACCOUNTS],
1743 &'a [AccountInfo<'b>],
1744 ) = array_refs![accounts, MIN_ACCOUNTS; .. ;];
1745 let &[
1746 ref market_acc,
1747 ref req_q_acc,
1748 ref event_q_acc,
1749 ref bids_acc,
1750 ref asks_acc,
1751 ref coin_wallet_acc,
1752 ref pc_wallet_acc,
1753 ref signer_acc,
1754 ref coin_vault_acc,
1755 ref pc_vault_acc,
1756 ref spl_token_program_acc,
1757 ]: &'a [AccountInfo<'b>; MIN_ACCOUNTS] = fixed_accounts;
1758 let srm_or_msrm_account = match fee_discount_account {
1759 &[] => None,
1760 &[ref account] => Some(TokenAccount::new(account)?),
1761 _ => check_unreachable!()?,
1762 };
1763
1764 let mut market = Market::load(market_acc, program_id, false)?;
1765
1766 let signer = SignerAccount::new(signer_acc)?;
1767 let fee_tier = market
1768 .load_fee_tier(&signer.inner().key.to_aligned_bytes(), srm_or_msrm_account)
1769 .or(check_unreachable!())?;
1770 let req_q = market.load_request_queue_mut(req_q_acc)?;
1771 let event_q = market.load_event_queue_mut(event_q_acc)?;
1772
1773 let coin_wallet = CoinWallet::from_account(coin_wallet_acc, &market)?;
1774 let pc_wallet = PcWallet::from_account(pc_wallet_acc, &market)?;
1775
1776 let coin_vault = CoinVault::from_account(coin_vault_acc, &market)?;
1777 let pc_vault = PcVault::from_account(pc_vault_acc, &market)?;
1778
1779 let spl_token_program = SplTokenProgram::new(spl_token_program_acc)?;
1780
1781 let mut bids = market.load_bids_mut(bids_acc).or(check_unreachable!())?;
1782 let mut asks = market.load_asks_mut(asks_acc).or(check_unreachable!())?;
1783
1784 let order_book_state = OrderBookState {
1785 bids: bids.deref_mut(),
1786 asks: asks.deref_mut(),
1787 market_state: market.deref_mut(),
1788 };
1789
1790 let args = SendTakeArgs {
1791 instruction,
1792 signer,
1793 req_q,
1794 event_q,
1795 fee_tier,
1796 coin_wallet,
1797 pc_wallet,
1798 coin_vault,
1799 pc_vault,
1800 order_book_state,
1801 spl_token_program,
1802 };
1803 f(args)
1804 }
1805 }
1806
1807 pub struct NewOrderV3Args<'a, 'b: 'a> {
1808 pub instruction: &'a NewOrderInstructionV3,
1809 pub open_orders: RefMut<'a, OpenOrders>,
1810 pub open_orders_address: [u64; 4],
1811 pub owner: SignerAccount<'a, 'b>,
1812 pub req_q: RequestQueue<'a>,
1813 pub event_q: EventQueue<'a>,
1814 pub order_book_state: OrderBookState<'a>,
1815 pub payer: TokenAccount<'a, 'b>,
1816 pub coin_vault: CoinVault<'a, 'b>,
1817 pub pc_vault: PcVault<'a, 'b>,
1818 pub spl_token_program: SplTokenProgram<'a, 'b>,
1819 pub fee_tier: FeeTier,
1820 }
1821 impl<'a, 'b: 'a> NewOrderV3Args<'a, 'b> {
1822 pub fn with_parsed_args<T>(
1823 program_id: &'a Pubkey,
1824 instruction: &'a NewOrderInstructionV3,
1825 accounts: &'a [AccountInfo<'b>],
1826 f: impl FnOnce(NewOrderV3Args) -> DexResult<T>,
1827 ) -> DexResult<T> {
1828 const MIN_ACCOUNTS: usize = 12;
1829 check_assert!(
1830 accounts.len() == MIN_ACCOUNTS
1831 || accounts.len() == MIN_ACCOUNTS + 1
1832 || accounts.len() == MIN_ACCOUNTS + 2
1833 )?;
1834 let (fixed_accounts, fee_discount_account): (
1835 &'a [AccountInfo<'b>; MIN_ACCOUNTS],
1836 &'a [AccountInfo<'b>],
1837 ) = array_refs![accounts, MIN_ACCOUNTS; .. ;];
1838 let &[
1839 ref market_acc,
1840 ref open_orders_acc,
1841 ref req_q_acc,
1842 ref event_q_acc,
1843 ref bids_acc,
1844 ref asks_acc,
1845 ref payer_acc,
1846 ref owner_acc,
1847 ref coin_vault_acc,
1848 ref pc_vault_acc,
1849 ref spl_token_program_acc,
1850 ref rent_sysvar_acc,
1851 ]: &'a [AccountInfo<'b>; MIN_ACCOUNTS] = fixed_accounts;
1852 let srm_or_msrm_account = match fee_discount_account {
1853 &[] => None,
1854 &[ref account] => Some(TokenAccount::new(account)?),
1855 _ => check_unreachable!()?,
1856 };
1857
1858 let mut market = Market::load(market_acc, program_id, false)?;
1859
1860 #[cfg(any(test, feature = "fuzz"))]
1862 let rent = Rent::from_account_info(rent_sysvar_acc)?;
1863 #[cfg(not(any(test, feature = "fuzz")))]
1864 let rent = Rent::get()?;
1865
1866 let owner = SignerAccount::new(owner_acc)?;
1867 let fee_tier =
1868 market.load_fee_tier(&owner.inner().key.to_aligned_bytes(), srm_or_msrm_account)?;
1869 let open_orders_address = open_orders_acc.key.to_aligned_bytes();
1870 let req_q = market.load_request_queue_mut(req_q_acc)?;
1871 let event_q = market.load_event_queue_mut(event_q_acc)?;
1872
1873 let payer = TokenAccount::new(payer_acc)?;
1874 match instruction.side {
1875 Side::Bid => market.check_pc_payer(payer).or(check_unreachable!())?,
1876 Side::Ask => market.check_coin_payer(payer).or(check_unreachable!())?,
1877 };
1878 let coin_vault = CoinVault::from_account(coin_vault_acc, &market)?;
1879 let pc_vault = PcVault::from_account(pc_vault_acc, &market)?;
1880 market.check_enabled()?;
1881 let spl_token_program = SplTokenProgram::new(spl_token_program_acc)?;
1882
1883 let mut bids = market.load_bids_mut(bids_acc).or(check_unreachable!())?;
1884 let mut asks = market.load_asks_mut(asks_acc).or(check_unreachable!())?;
1885
1886 let open_orders = market.load_orders_mut(
1887 open_orders_acc,
1888 Some(owner.inner()),
1889 program_id,
1890 Some(rent),
1891 None, )?;
1894 let order_book_state = OrderBookState {
1895 bids: bids.deref_mut(),
1896 asks: asks.deref_mut(),
1897 market_state: market.deref_mut(),
1898 };
1899
1900 let args = NewOrderV3Args {
1901 instruction,
1902 order_book_state,
1903 open_orders,
1904 open_orders_address,
1905 owner,
1906 req_q,
1907 event_q,
1908 payer,
1909 coin_vault,
1910 pc_vault,
1911 spl_token_program,
1912 fee_tier,
1913 };
1914 f(args)
1915 }
1916 }
1917
1918 pub struct ConsumeEventsArgs<'a, 'b: 'a> {
1919 pub limit: u16,
1920 pub program_id: &'a Pubkey,
1921 pub open_orders_accounts: &'a [AccountInfo<'b>],
1922 pub market: Market<'a>,
1923 pub event_q: EventQueue<'a>,
1924 }
1925 impl<'a, 'b: 'a> ConsumeEventsArgs<'a, 'b> {
1926 pub fn with_parsed_args<T>(
1927 program_id: &'a Pubkey,
1928 accounts: &'a [AccountInfo<'b>],
1929 limit: u16,
1930 f: impl FnOnce(ConsumeEventsArgs) -> DexResult<T>,
1931 ) -> DexResult<T> {
1932 check_assert!(accounts.len() >= 5)?;
1933 #[rustfmt::skip]
1934 let (
1935 &[],
1936 open_orders_accounts,
1937 &[
1938 ref market_acc,
1939 ref event_q_acc,
1940 ],
1941 _
1942 ) = array_refs![accounts, 0; .. ; 2, 2];
1943 let market = Market::load(market_acc, program_id, true)?;
1944 check_assert!(market.consume_events_authority().is_none())?;
1945 let event_q = market.load_event_queue_mut(event_q_acc)?;
1946 let args = ConsumeEventsArgs {
1947 limit,
1948 program_id,
1949 open_orders_accounts,
1950 market,
1951 event_q,
1952 };
1953 f(args)
1954 }
1955
1956 pub fn with_parsed_args_permissioned<T>(
1957 program_id: &'a Pubkey,
1958 accounts: &'a [AccountInfo<'b>],
1959 limit: u16,
1960 f: impl FnOnce(ConsumeEventsArgs) -> DexResult<T>,
1961 ) -> DexResult<T> {
1962 check_assert!(accounts.len() >= 4)?;
1963 #[rustfmt::skip]
1964 let (
1965 &[],
1966 open_orders_accounts,
1967 &[
1968 ref market_acc,
1969 ref event_q_acc,
1970 ref consume_events_auth,
1971 ]
1972 ) = array_refs![accounts, 0; .. ; 3];
1973 let market = Market::load(market_acc, program_id, true)?;
1974 check_assert!(consume_events_auth.is_signer)?;
1975 check_assert_eq!(
1976 Some(consume_events_auth.key),
1977 market.consume_events_authority()
1978 )?;
1979 let event_q = market.load_event_queue_mut(event_q_acc)?;
1980 let args = ConsumeEventsArgs {
1981 limit,
1982 program_id,
1983 open_orders_accounts,
1984 market,
1985 event_q,
1986 };
1987 f(args)
1988 }
1989 }
1990
1991 pub struct CancelOrderV2Args<'a, 'b: 'a> {
1992 pub instruction: &'a CancelOrderInstructionV2,
1993 pub open_orders_address: [u64; 4],
1994 pub open_orders: &'a mut OpenOrders,
1995 pub open_orders_signer: SignerAccount<'a, 'b>,
1996 pub order_book_state: OrderBookState<'a>,
1997 pub event_q: EventQueue<'a>,
1998 }
1999 impl<'a, 'b: 'a> CancelOrderV2Args<'a, 'b> {
2000 pub fn with_parsed_args<T>(
2001 program_id: &'a Pubkey,
2002 accounts: &'a [AccountInfo<'b>],
2003 instruction: &'a CancelOrderInstructionV2,
2004 f: impl FnOnce(CancelOrderV2Args) -> DexResult<T>,
2005 ) -> DexResult<T> {
2006 check_assert!(accounts.len() >= 6)?;
2007 #[rustfmt::skip]
2008 let &[
2009 ref market_acc,
2010 ref bids_acc,
2011 ref asks_acc,
2012 ref open_orders_acc,
2013 ref open_orders_signer_acc,
2014 ref event_q_acc,
2015 ] = array_ref![accounts, 0, 6];
2016
2017 let mut market = Market::load(market_acc, program_id, true).or(check_unreachable!())?;
2018
2019 let open_orders_signer = SignerAccount::new(open_orders_signer_acc)?;
2020 let mut open_orders = market.load_orders_mut(
2021 open_orders_acc,
2022 Some(open_orders_signer.inner()),
2023 program_id,
2024 None,
2025 None,
2026 )?;
2027 let open_orders_address = open_orders_acc.key.to_aligned_bytes();
2028
2029 let mut bids = market.load_bids_mut(bids_acc).or(check_unreachable!())?;
2030 let mut asks = market.load_asks_mut(asks_acc).or(check_unreachable!())?;
2031
2032 let event_q = market.load_event_queue_mut(event_q_acc)?;
2033
2034 let order_book_state = OrderBookState {
2035 bids: bids.deref_mut(),
2036 asks: asks.deref_mut(),
2037 market_state: market.deref_mut(),
2038 };
2039
2040 let args = CancelOrderV2Args {
2041 instruction,
2042 open_orders_address,
2043 open_orders: open_orders.deref_mut(),
2044 open_orders_signer,
2045 order_book_state,
2046 event_q,
2047 };
2048 f(args)
2049 }
2050 }
2051
2052 pub struct CancelOrderByClientIdV2Args<'a, 'b: 'a> {
2053 pub client_order_id: NonZeroU64,
2054 pub open_orders_address: [u64; 4],
2055 pub open_orders: &'a mut OpenOrders,
2056 pub open_orders_signer: SignerAccount<'a, 'b>,
2057 pub order_book_state: OrderBookState<'a>,
2058 pub event_q: EventQueue<'a>,
2059 }
2060 impl<'a, 'b: 'a> CancelOrderByClientIdV2Args<'a, 'b> {
2061 pub fn with_parsed_args<T>(
2062 program_id: &'a Pubkey,
2063 accounts: &'a [AccountInfo<'b>],
2064 client_order_id: u64,
2065 f: impl FnOnce(CancelOrderByClientIdV2Args) -> DexResult<T>,
2066 ) -> DexResult<T> {
2067 check_assert!(accounts.len() >= 6)?;
2068 #[rustfmt::skip]
2069 let &[
2070 ref market_acc,
2071 ref bids_acc,
2072 ref asks_acc,
2073 ref open_orders_acc,
2074 ref open_orders_signer_acc,
2075 ref event_q_acc,
2076 ] = array_ref![accounts, 0, 6];
2077
2078 let client_order_id = NonZeroU64::new(client_order_id).ok_or(assertion_error!())?;
2079
2080 let mut market = Market::load(market_acc, program_id, true).or(check_unreachable!())?;
2081
2082 let open_orders_signer = SignerAccount::new(open_orders_signer_acc)?;
2083 let mut open_orders = market.load_orders_mut(
2084 open_orders_acc,
2085 Some(open_orders_signer.inner()),
2086 program_id,
2087 None,
2088 None,
2089 )?;
2090 let open_orders_address = open_orders_acc.key.to_aligned_bytes();
2091
2092 let mut bids = market.load_bids_mut(bids_acc).or(check_unreachable!())?;
2093 let mut asks = market.load_asks_mut(asks_acc).or(check_unreachable!())?;
2094
2095 let event_q = market.load_event_queue_mut(event_q_acc)?;
2096
2097 let order_book_state = OrderBookState {
2098 bids: bids.deref_mut(),
2099 asks: asks.deref_mut(),
2100 market_state: market.deref_mut(),
2101 };
2102
2103 let args = CancelOrderByClientIdV2Args {
2104 client_order_id,
2105 open_orders_address,
2106 open_orders: open_orders.deref_mut(),
2107 open_orders_signer,
2108 order_book_state,
2109 event_q,
2110 };
2111 f(args)
2112 }
2113 }
2114
2115 pub struct SettleFundsArgs<'a, 'b: 'a> {
2116 pub market: Market<'a>,
2117 pub open_orders: &'a mut OpenOrders,
2118 pub coin_vault: CoinVault<'a, 'b>,
2119 pub pc_vault: PcVault<'a, 'b>,
2120 pub coin_wallet: CoinWallet<'a, 'b>,
2121 pub pc_wallet: PcWallet<'a, 'b>,
2122 pub vault_signer: VaultSigner<'a, 'b>,
2123 pub spl_token_program: SplTokenProgram<'a, 'b>,
2124 pub referrer: Option<PcWallet<'a, 'b>>,
2125 }
2126 impl<'a, 'b: 'a> SettleFundsArgs<'a, 'b> {
2127 pub fn with_parsed_args<T>(
2128 program_id: &'a Pubkey,
2129 accounts: &'a [AccountInfo<'b>],
2130 f: impl FnOnce(SettleFundsArgs) -> DexResult<T>,
2131 ) -> DexResult<T> {
2132 check_assert!(accounts.len() == 9 || accounts.len() == 10)?;
2133 #[rustfmt::skip]
2134 let (&[
2135 ref market_acc,
2136 ref open_orders_acc,
2137 ref owner_acc,
2138 ref coin_vault_acc,
2139 ref pc_vault_acc,
2140 ref coin_wallet_acc,
2141 ref pc_wallet_acc,
2142 ref vault_signer_acc,
2143 ref spl_token_program_acc,
2144 ], remaining_accounts) = array_refs![accounts, 9; ..;];
2145 let spl_token_program = SplTokenProgram::new(spl_token_program_acc)?;
2146 let market = Market::load(market_acc, program_id, true)?;
2147 let owner = SignerAccount::new(owner_acc).or(check_unreachable!())?;
2148
2149 let coin_vault =
2150 CoinVault::from_account(coin_vault_acc, &market).or(check_unreachable!())?;
2151 let pc_vault = PcVault::from_account(pc_vault_acc, &market).or(check_unreachable!())?;
2152 let coin_wallet =
2153 CoinWallet::from_account(coin_wallet_acc, &market).or(check_unreachable!())?;
2154 let pc_wallet =
2155 PcWallet::from_account(pc_wallet_acc, &market).or(check_unreachable!())?;
2156
2157 let referrer = match remaining_accounts {
2158 &[] => None,
2159 &[ref referrer_acc] => {
2160 Some(PcWallet::from_account(referrer_acc, &market).or(check_unreachable!())?)
2161 }
2162 _ => check_unreachable!()?,
2163 };
2164
2165 let vault_signer = VaultSigner::new(vault_signer_acc, &market, program_id)?;
2166
2167 let mut open_orders = market.load_orders_mut(
2168 open_orders_acc,
2169 Some(owner.inner()),
2170 program_id,
2171 None,
2172 None,
2173 )?;
2174
2175 let args = SettleFundsArgs {
2176 market,
2177 open_orders: open_orders.deref_mut(),
2178 coin_vault,
2179 pc_vault,
2180 coin_wallet,
2181 pc_wallet,
2182 vault_signer,
2183 spl_token_program,
2184 referrer,
2185 };
2186 f(args)
2187 }
2188 }
2189
2190 pub struct DisableMarketArgs<'a, 'b: 'a> {
2191 pub market: &'a mut MarketState,
2192 pub authorization: SigningDisableAuthority<'a, 'b>,
2193 }
2194 impl<'a, 'b: 'a> DisableMarketArgs<'a, 'b> {
2195 pub fn with_parsed_args<T>(
2196 program_id: &'a Pubkey,
2197 accounts: &'a [AccountInfo<'b>],
2198 f: impl FnOnce(DisableMarketArgs) -> DexResult<T>,
2199 ) -> DexResult<T> {
2200 check_assert_eq!(accounts.len(), 2)?;
2201 let &[ref market_acc, ref signer_acc] = array_ref![accounts, 0, 2];
2202 let mut market = Market::load(market_acc, program_id, false)?;
2203 let authorization = SigningDisableAuthority::new(signer_acc)?;
2204
2205 let args = DisableMarketArgs {
2206 market: market.deref_mut(),
2207 authorization,
2208 };
2209 f(args)
2210 }
2211 }
2212
2213 pub struct SweepFeesArgs<'a, 'b: 'a> {
2214 pub market: Market<'a>,
2215 pub pc_vault: PcVault<'a, 'b>,
2216 pub fee_receiver: PcWallet<'a, 'b>,
2217 pub vault_signer: VaultSigner<'a, 'b>,
2218 pub spl_token_program: SplTokenProgram<'a, 'b>,
2219 pub authorization: SigningFeeSweeper<'a, 'b>,
2220 }
2221 impl<'a, 'b: 'a> SweepFeesArgs<'a, 'b> {
2222 pub fn with_parsed_args<T>(
2223 program_id: &'a Pubkey,
2224 accounts: &'a [AccountInfo<'b>],
2225 f: impl FnOnce(SweepFeesArgs) -> DexResult<T>,
2226 ) -> DexResult<T> {
2227 check_assert_eq!(accounts.len(), 6)?;
2228 #[rustfmt::skip]
2229 let &[
2230 ref market_acc,
2231 ref pc_vault_acc,
2232 ref sweep_authority_acc,
2233 ref pc_wallet_acc,
2234 ref vault_signer_acc,
2235 ref spl_token_program
2236 ] = array_ref![accounts, 0, 6];
2237
2238 let market = Market::load(market_acc, program_id, false)?;
2239 let pc_vault = PcVault::from_account(pc_vault_acc, &market)?;
2240 let fee_receiver = PcWallet::from_account(pc_wallet_acc, &market)?;
2241 let vault_signer = VaultSigner::new(vault_signer_acc, &market, program_id)?;
2242 let spl_token_program = SplTokenProgram::new(spl_token_program)?;
2243 let authorization = SigningFeeSweeper::new(sweep_authority_acc)?;
2244
2245 let args = SweepFeesArgs {
2246 market,
2247 pc_vault,
2248 fee_receiver,
2249 vault_signer,
2250 spl_token_program,
2251 authorization,
2252 };
2253 f(args)
2254 }
2255 }
2256
2257 pub struct CloseOpenOrdersArgs<'a, 'b: 'a> {
2258 pub open_orders: &'a mut OpenOrders,
2259 pub open_orders_acc: &'a AccountInfo<'b>,
2260 pub dest_acc: &'a AccountInfo<'b>,
2261 }
2262
2263 impl<'a, 'b: 'a> CloseOpenOrdersArgs<'a, 'b> {
2264 pub fn with_parsed_args<T>(
2265 program_id: &'a Pubkey,
2266 accounts: &'a [AccountInfo<'b>],
2267 f: impl FnOnce(CloseOpenOrdersArgs) -> DexResult<T>,
2268 ) -> DexResult<T> {
2269 check_assert_eq!(accounts.len(), 4)?;
2271 #[rustfmt::skip]
2272 let &[
2273 ref open_orders_acc,
2274 ref owner_acc,
2275 ref dest_acc,
2276 ref market_acc,
2277 ] = array_ref![accounts, 0, 4];
2278
2279 let owner = SignerAccount::new(owner_acc)?;
2281 let market = Market::load(market_acc, program_id, true)?;
2282 let mut open_orders = market.load_orders_mut(
2283 open_orders_acc,
2284 Some(owner.inner()),
2285 program_id,
2286 None,
2287 None,
2288 )?;
2289
2290 if open_orders.free_slot_bits != std::u128::MAX {
2292 return Err(DexErrorCode::TooManyOpenOrders.into());
2293 }
2294 if open_orders.native_coin_total != 0 {
2295 solana_program::msg!(
2296 "Base currency total must be zero to close the open orders account"
2297 );
2298 return Err(DexErrorCode::TooManyOpenOrders.into());
2299 }
2300 if open_orders.native_pc_total != 0 {
2301 solana_program::msg!(
2302 "Quote currency total must be zero to close the open orders account"
2303 );
2304 return Err(DexErrorCode::TooManyOpenOrders.into());
2305 }
2306
2307 f(CloseOpenOrdersArgs {
2309 open_orders: open_orders.deref_mut(),
2310 open_orders_acc,
2311 dest_acc,
2312 })
2313 }
2314 }
2315
2316 pub struct InitOpenOrdersArgs;
2317
2318 impl InitOpenOrdersArgs {
2319 pub fn with_parsed_args<T>(
2320 program_id: &Pubkey,
2321 accounts: &[AccountInfo],
2322 f: impl FnOnce(InitOpenOrdersArgs) -> DexResult<T>,
2323 ) -> DexResult<T> {
2324 check_assert!(accounts.len() == 4 || accounts.len() == 5)?;
2326 #[rustfmt::skip]
2327 let &[
2328 ref open_orders_acc,
2329 ref owner_acc,
2330 ref market_acc,
2331 ref rent_acc,
2332 ] = array_ref![accounts, 0, 4];
2333
2334 let oo_authority = (&accounts[4..])
2335 .first()
2336 .map(|acc| SignerAccount::new(acc))
2337 .transpose()?;
2338
2339 #[cfg(any(test, feature = "fuzz"))]
2341 let rent = Rent::from_account_info(rent_acc)?;
2342 #[cfg(not(any(test, feature = "fuzz")))]
2343 let rent = Rent::get()?;
2344
2345 let owner = SignerAccount::new(owner_acc)?;
2347 let market = Market::load(market_acc, program_id, false)?;
2348
2349 let _open_orders = market.load_orders_mut(
2351 open_orders_acc,
2352 Some(owner.inner()),
2353 program_id,
2354 Some(rent),
2355 oo_authority,
2356 )?;
2357
2358 f(InitOpenOrdersArgs)
2360 }
2361 }
2362
2363 pub struct PruneArgs<'a> {
2364 pub order_book_state: OrderBookState<'a>,
2365 pub open_orders: &'a mut OpenOrders,
2366 pub open_orders_address: &'a Pubkey,
2367 pub event_q: EventQueue<'a>,
2368 pub limit: u16,
2369 }
2370
2371 impl<'a> PruneArgs<'a> {
2372 pub fn with_parsed_args<T>(
2373 program_id: &Pubkey,
2374 accounts: &[AccountInfo],
2375 limit: u16,
2376 f: impl FnOnce(PruneArgs) -> DexResult<T>,
2377 ) -> DexResult<T> {
2378 check_assert!(accounts.len() == 7)?;
2380 #[rustfmt::skip]
2381 let &[
2382 ref market_acc,
2383 ref bids_acc,
2384 ref asks_acc,
2385 ref prune_auth_acc,
2386 ref open_orders_acc,
2387 ref open_orders_owner_acc,
2388 ref event_q_acc,
2389 ] = array_ref![accounts, 0, 7];
2390
2391 let _prune_authority = SignerAccount::new(prune_auth_acc)?;
2392 let mut market = Market::load(market_acc, program_id, false)?;
2393 check_assert!(market.prune_authority() == Some(prune_auth_acc.key))?;
2394 let open_orders_address = open_orders_acc.key;
2395 let mut open_orders = market.load_orders_mut(
2396 open_orders_acc,
2397 Some(open_orders_owner_acc),
2398 program_id,
2399 None,
2400 None,
2401 )?;
2402 let mut bids = market.load_bids_mut(bids_acc).or(check_unreachable!())?;
2403 let mut asks = market.load_asks_mut(asks_acc).or(check_unreachable!())?;
2404 let event_q = market.load_event_queue_mut(event_q_acc)?;
2405 let order_book_state = OrderBookState {
2406 bids: bids.deref_mut(),
2407 asks: asks.deref_mut(),
2408 market_state: market.deref_mut(),
2409 };
2410
2411 let args = PruneArgs {
2412 order_book_state,
2413 open_orders_address,
2414 open_orders: open_orders.deref_mut(),
2415 event_q,
2416 limit,
2417 };
2418 f(args)
2419 }
2420 }
2421}
2422
2423#[inline]
2424fn remove_slop<T: Pod>(bytes: &[u8]) -> &[T] {
2425 let slop = bytes.len() % size_of::<T>();
2426 let new_len = bytes.len() - slop;
2427 cast_slice(&bytes[..new_len])
2428}
2429
2430#[inline]
2431fn remove_slop_mut<T: Pod>(bytes: &mut [u8]) -> &mut [T] {
2432 let slop = bytes.len() % size_of::<T>();
2433 let new_len = bytes.len() - slop;
2434 cast_slice_mut(&mut bytes[..new_len])
2435}
2436
2437#[cfg_attr(not(feature = "program"), allow(unused))]
2438impl State {
2439 #[cfg(feature = "program")]
2440 pub fn process(program_id: &Pubkey, accounts: &[AccountInfo], input: &[u8]) -> DexResult {
2441 let instruction = MarketInstruction::unpack(input).ok_or(ProgramError::InvalidArgument)?;
2442 match instruction {
2443 MarketInstruction::InitializeMarket(ref inner) => Self::process_initialize_market(
2444 account_parser::InitializeMarketArgs::new(program_id, inner, accounts)?,
2445 )?,
2446 MarketInstruction::NewOrder(_inner) => {
2447 unimplemented!()
2448 }
2449 MarketInstruction::NewOrderV2(_inner) => {
2450 unimplemented!()
2451 }
2452 MarketInstruction::NewOrderV3(ref inner) => {
2453 account_parser::NewOrderV3Args::with_parsed_args(
2454 program_id,
2455 inner,
2456 accounts,
2457 Self::process_new_order_v3,
2458 )?
2459 }
2460 MarketInstruction::MatchOrders(_limit) => {}
2461 MarketInstruction::ConsumeEvents(limit) => {
2462 account_parser::ConsumeEventsArgs::with_parsed_args(
2463 program_id,
2464 accounts,
2465 limit,
2466 Self::process_consume_events,
2467 )?
2468 }
2469 MarketInstruction::ConsumeEventsPermissioned(limit) => {
2470 account_parser::ConsumeEventsArgs::with_parsed_args_permissioned(
2471 program_id,
2472 accounts,
2473 limit,
2474 Self::process_consume_events,
2475 )?
2476 }
2477 MarketInstruction::CancelOrder(_inner) => {
2478 unimplemented!()
2479 }
2480 MarketInstruction::CancelOrderV2(ref inner) => {
2481 account_parser::CancelOrderV2Args::with_parsed_args(
2482 program_id,
2483 accounts,
2484 inner,
2485 Self::process_cancel_order_v2,
2486 )?
2487 }
2488 MarketInstruction::SettleFunds => account_parser::SettleFundsArgs::with_parsed_args(
2489 program_id,
2490 accounts,
2491 Self::process_settle_funds,
2492 )?,
2493 MarketInstruction::CancelOrderByClientId(_client_id) => {
2494 unimplemented!()
2495 }
2496 MarketInstruction::CancelOrderByClientIdV2(client_id) => {
2497 account_parser::CancelOrderByClientIdV2Args::with_parsed_args(
2498 program_id,
2499 accounts,
2500 client_id,
2501 Self::process_cancel_order_by_client_id_v2,
2502 )?
2503 }
2504 MarketInstruction::DisableMarket => {
2505 account_parser::DisableMarketArgs::with_parsed_args(
2506 program_id,
2507 accounts,
2508 Self::process_disable_market,
2509 )?
2510 }
2511 MarketInstruction::SweepFees => account_parser::SweepFeesArgs::with_parsed_args(
2512 program_id,
2513 accounts,
2514 Self::process_sweep_fees,
2515 )?,
2516 MarketInstruction::SendTake(ref inner) => {
2517 account_parser::SendTakeArgs::with_parsed_args(
2518 program_id,
2519 inner,
2520 accounts,
2521 Self::process_send_take,
2522 )?
2523 }
2524 MarketInstruction::CloseOpenOrders => {
2525 account_parser::CloseOpenOrdersArgs::with_parsed_args(
2526 program_id,
2527 accounts,
2528 Self::process_close_open_orders,
2529 )?
2530 }
2531 MarketInstruction::InitOpenOrders => {
2532 account_parser::InitOpenOrdersArgs::with_parsed_args(
2533 program_id,
2534 accounts,
2535 Self::process_init_open_orders,
2536 )?
2537 }
2538 MarketInstruction::Prune(limit) => account_parser::PruneArgs::with_parsed_args(
2539 program_id,
2540 accounts,
2541 limit,
2542 Self::process_prune,
2543 )?,
2544 };
2545 Ok(())
2546 }
2547
2548 #[cfg(feature = "program")]
2549 fn process_send_take(_args: account_parser::SendTakeArgs) -> DexResult {
2550 unimplemented!()
2551 }
2552
2553 fn process_prune(args: account_parser::PruneArgs) -> DexResult {
2554 let account_parser::PruneArgs {
2555 mut order_book_state,
2556 open_orders,
2557 open_orders_address,
2558 mut event_q,
2559 limit,
2560 } = args;
2561 let open_orders_addr_bytes = open_orders_address.to_aligned_bytes();
2562 let (bids_removed, asks_removed) =
2563 order_book_state.remove_all(open_orders_addr_bytes, limit)?;
2564
2565 solana_program::msg!(
2566 "Pruned {:?} bids and {:?} asks",
2567 bids_removed.len(),
2568 asks_removed.len()
2569 );
2570
2571 for bid in bids_removed {
2572 let order_id = open_orders.orders[bid.owner_slot() as usize];
2573 order_book_state.cancel_leaf_node(
2574 bid,
2575 Side::Bid,
2576 open_orders,
2577 open_orders_addr_bytes,
2578 order_id,
2579 &mut event_q,
2580 )?;
2581 }
2582
2583 for ask in asks_removed {
2584 let order_id = open_orders.orders[ask.owner_slot() as usize];
2585 order_book_state.cancel_leaf_node(
2586 ask,
2587 Side::Ask,
2588 open_orders,
2589 open_orders_addr_bytes,
2590 order_id,
2591 &mut event_q,
2592 )?;
2593 }
2594
2595 Ok(())
2596 }
2597
2598 fn process_init_open_orders(_args: account_parser::InitOpenOrdersArgs) -> DexResult {
2599 Ok(())
2600 }
2601
2602 fn process_close_open_orders(args: account_parser::CloseOpenOrdersArgs) -> DexResult {
2603 let account_parser::CloseOpenOrdersArgs {
2604 open_orders,
2605 open_orders_acc,
2606 dest_acc,
2607 } = args;
2608
2609 let dest_starting_lamports = dest_acc.lamports();
2611 **dest_acc.lamports.borrow_mut() = dest_starting_lamports
2612 .checked_add(open_orders_acc.lamports())
2613 .unwrap();
2614 **open_orders_acc.lamports.borrow_mut() = 0;
2615
2616 open_orders.account_flags = AccountFlag::Closed as u64;
2619
2620 Ok(())
2621 }
2622
2623 #[cfg(feature = "program")]
2624 fn process_settle_funds(args: account_parser::SettleFundsArgs) -> DexResult {
2625 let account_parser::SettleFundsArgs {
2626 mut market,
2627 mut open_orders,
2628 coin_vault,
2629 pc_vault,
2630 coin_wallet,
2631 pc_wallet,
2632 vault_signer,
2633 spl_token_program,
2634 referrer,
2635 } = args;
2636
2637 let native_coin_amount = open_orders.native_coin_free;
2638 let native_pc_amount = open_orders.native_pc_free;
2639
2640 market.coin_deposits_total -= native_coin_amount;
2641 market.pc_deposits_total -= native_pc_amount;
2642
2643 open_orders.native_coin_free = 0;
2644 open_orders.native_pc_free = 0;
2645
2646 open_orders.native_coin_total = open_orders
2647 .native_coin_total
2648 .checked_sub(native_coin_amount)
2649 .unwrap();
2650 open_orders.native_pc_total = open_orders
2651 .native_pc_total
2652 .checked_sub(native_pc_amount)
2653 .unwrap();
2654
2655 let token_infos: [(
2656 u64,
2657 account_parser::TokenAccount,
2658 account_parser::TokenAccount,
2659 ); 2] = [
2660 (
2661 native_coin_amount,
2662 coin_wallet.token_account(),
2663 coin_vault.token_account(),
2664 ),
2665 (
2666 native_pc_amount,
2667 pc_wallet.token_account(),
2668 pc_vault.token_account(),
2669 ),
2670 ];
2671
2672 let nonce = market.vault_signer_nonce;
2673 let market_pubkey = market.pubkey();
2674 let vault_signer_seeds = gen_vault_signer_seeds(&nonce, &market_pubkey);
2675
2676 for &(token_amount, wallet_account, vault) in token_infos.iter() {
2677 send_from_vault(
2678 token_amount,
2679 wallet_account,
2680 vault,
2681 spl_token_program,
2682 vault_signer,
2683 &vault_signer_seeds,
2684 )?;
2685 }
2686
2687 match referrer {
2688 Some(referrer_pc_wallet) if open_orders.referrer_rebates_accrued > 0 => {
2689 send_from_vault(
2690 open_orders.referrer_rebates_accrued,
2691 referrer_pc_wallet.token_account(),
2692 pc_vault.token_account(),
2693 spl_token_program,
2694 vault_signer,
2695 &vault_signer_seeds,
2696 )?;
2697 }
2698 _ => {
2699 market.pc_fees_accrued += open_orders.referrer_rebates_accrued;
2700 }
2701 };
2702 market.referrer_rebates_accrued -= open_orders.referrer_rebates_accrued;
2703 open_orders.referrer_rebates_accrued = 0;
2704
2705 Ok(())
2706 }
2707
2708 fn process_cancel_order_by_client_id_v2(
2709 args: account_parser::CancelOrderByClientIdV2Args,
2710 ) -> DexResult {
2711 let account_parser::CancelOrderByClientIdV2Args {
2712 client_order_id,
2713 open_orders_address,
2714 open_orders,
2715 open_orders_signer: _,
2716
2717 mut order_book_state,
2718 mut event_q,
2719 } = args;
2720
2721 let (_, order_id, side) = open_orders
2722 .orders_with_client_ids()
2723 .find(|entry| client_order_id == entry.0)
2724 .ok_or(DexErrorCode::ClientIdNotFound)?;
2725 order_book_state.cancel_order_v2(
2726 side,
2727 open_orders_address,
2728 open_orders,
2729 order_id,
2730 &mut event_q,
2731 )
2732 }
2733
2734 fn process_cancel_order_v2(args: account_parser::CancelOrderV2Args) -> DexResult {
2735 let account_parser::CancelOrderV2Args {
2736 instruction: &CancelOrderInstructionV2 { side, order_id },
2737
2738 open_orders_address,
2739 open_orders,
2740 open_orders_signer: _,
2741
2742 mut order_book_state,
2743 mut event_q,
2744 } = args;
2745
2746 order_book_state.cancel_order_v2(
2747 side,
2748 open_orders_address,
2749 open_orders,
2750 order_id,
2751 &mut event_q,
2752 )
2753 }
2754
2755 fn process_consume_events(args: account_parser::ConsumeEventsArgs) -> DexResult {
2756 let account_parser::ConsumeEventsArgs {
2757 limit,
2758 program_id,
2759 open_orders_accounts,
2760 market,
2761 mut event_q,
2762 } = args;
2763
2764 for _i in 0u16..limit {
2765 let event = match event_q.peek_front() {
2766 None => break,
2767 Some(e) => e,
2768 };
2769
2770 let view = event.as_view()?;
2771 let owner: [u64; 4] = event.owner;
2772 let owner_index: Result<usize, usize> = open_orders_accounts
2773 .binary_search_by_key(&owner, |account_info| account_info.key.to_aligned_bytes());
2774 let mut open_orders: RefMut<OpenOrders> = match owner_index {
2775 Err(_) => break,
2776 Ok(i) => market.load_orders_mut(
2777 &open_orders_accounts[i],
2778 None,
2779 program_id,
2780 None,
2781 None,
2782 )?,
2783 };
2784
2785 check_assert!(event.owner_slot < 128)?;
2786 check_assert_eq!(&open_orders.slot_side(event.owner_slot), &Some(view.side()))?;
2787 check_assert_eq!(
2788 open_orders.orders[event.owner_slot as usize],
2789 event.order_id
2790 )?;
2791
2792 match event.as_view()? {
2793 EventView::Fill {
2794 side,
2795 maker,
2796 native_qty_paid,
2797 native_qty_received,
2798 native_fee_or_rebate,
2799 fee_tier: _,
2800 order_id: _,
2801 owner: _,
2802 owner_slot,
2803 client_order_id,
2804 } => {
2805 match side {
2806 Side::Bid if maker => {
2807 open_orders.native_pc_total -= native_qty_paid;
2808 open_orders.native_coin_total += native_qty_received;
2809 open_orders.native_coin_free += native_qty_received;
2810 open_orders.native_pc_free += native_fee_or_rebate;
2811 }
2812 Side::Ask if maker => {
2813 open_orders.native_coin_total -= native_qty_paid;
2814 open_orders.native_pc_total += native_qty_received;
2815 open_orders.native_pc_free += native_qty_received;
2816 }
2817 _ => (),
2818 };
2819 if !maker {
2820 let referrer_rebate = fees::referrer_rebate(native_fee_or_rebate);
2821 open_orders.referrer_rebates_accrued += referrer_rebate;
2822 }
2823 if let Some(client_id) = client_order_id {
2824 debug_assert_eq!(
2825 client_id.get(),
2826 identity(open_orders.client_order_ids[owner_slot as usize])
2827 );
2828 }
2829 }
2830 EventView::Out {
2831 side,
2832 release_funds,
2833 native_qty_unlocked,
2834 native_qty_still_locked,
2835 order_id: _,
2836 owner: _,
2837 owner_slot,
2838 client_order_id,
2839 } => {
2840 let fully_out = native_qty_still_locked == 0;
2841
2842 match side {
2843 Side::Bid => {
2844 if release_funds {
2845 open_orders.native_pc_free += native_qty_unlocked;
2846 }
2847 check_assert!(
2848 open_orders.native_pc_free <= open_orders.native_pc_total
2849 )?;
2850 }
2851 Side::Ask => {
2852 if release_funds {
2853 open_orders.native_coin_free += native_qty_unlocked;
2854 }
2855 check_assert!(
2856 open_orders.native_coin_free <= open_orders.native_coin_total
2857 )?;
2858 }
2859 };
2860 if let Some(client_id) = client_order_id {
2861 debug_assert_eq!(
2862 client_id.get(),
2863 identity(open_orders.client_order_ids[owner_slot as usize])
2864 );
2865 }
2866 if fully_out {
2867 open_orders.remove_order(owner_slot)?;
2868 }
2869 }
2870 };
2871
2872 event_q
2873 .pop_front()
2874 .map_err(|()| DexErrorCode::ConsumeEventsQueueFailure)?;
2875 }
2876 Ok(())
2877 }
2878
2879 #[cfg(feature = "program")]
2880 fn process_new_order_v3(args: account_parser::NewOrderV3Args) -> DexResult {
2881 let account_parser::NewOrderV3Args {
2882 instruction,
2883 mut order_book_state,
2884 mut open_orders,
2885 open_orders_address,
2886 mut req_q,
2887 mut event_q,
2888 payer,
2889 owner,
2890 coin_vault,
2891 pc_vault,
2892 spl_token_program,
2893 fee_tier,
2894 } = args;
2895
2896 let open_orders_mut = open_orders.deref_mut();
2897
2898 check_assert_eq!(req_q.header.count(), 0)?;
2899
2900 let deposit_amount;
2901 let deposit_vault;
2902
2903 let native_pc_qty_locked;
2904 match instruction.side {
2905 Side::Bid => {
2906 let lock_qty_native = instruction.max_native_pc_qty_including_fees;
2907 native_pc_qty_locked = Some(lock_qty_native);
2908 let free_qty_to_lock = lock_qty_native.get().min(open_orders_mut.native_pc_free);
2909 deposit_amount = lock_qty_native.get() - free_qty_to_lock;
2910 deposit_vault = pc_vault.token_account();
2911 if payer.balance()? < deposit_amount {
2912 return Err(DexErrorCode::InsufficientFunds.into());
2913 }
2914 open_orders_mut.lock_free_pc(free_qty_to_lock);
2915 open_orders_mut.credit_locked_pc(deposit_amount);
2916 order_book_state.market_state.pc_deposits_total = order_book_state
2917 .market_state
2918 .pc_deposits_total
2919 .checked_add(deposit_amount)
2920 .unwrap();
2921 }
2922 Side::Ask => {
2923 native_pc_qty_locked = None;
2924 let lock_qty_native = instruction
2925 .max_coin_qty
2926 .get()
2927 .checked_mul(order_book_state.market_state.coin_lot_size)
2928 .ok_or(DexErrorCode::InsufficientFunds)?;
2929 let free_qty_to_lock = lock_qty_native.min(open_orders_mut.native_coin_free);
2930 deposit_amount = lock_qty_native - free_qty_to_lock;
2931 deposit_vault = coin_vault.token_account();
2932 if payer.balance()? < deposit_amount {
2933 return Err(DexErrorCode::InsufficientFunds.into());
2934 }
2935 open_orders_mut.lock_free_coin(free_qty_to_lock);
2936 open_orders_mut.credit_locked_coin(deposit_amount);
2937 order_book_state.market_state.coin_deposits_total = order_book_state
2938 .market_state
2939 .coin_deposits_total
2940 .checked_add(deposit_amount)
2941 .unwrap();
2942 }
2943 };
2944
2945 let order_id = req_q.gen_order_id(instruction.limit_price.get(), instruction.side);
2946 let owner_slot = open_orders_mut.add_order(order_id, instruction.side)?;
2947 open_orders_mut.client_order_ids[owner_slot as usize] = instruction.client_order_id;
2948
2949 let mut proceeds = RequestProceeds::zero();
2950
2951 let request = RequestView::NewOrder {
2952 side: instruction.side,
2953 order_type: instruction.order_type,
2954 order_id,
2955 fee_tier,
2956 self_trade_behavior: instruction.self_trade_behavior,
2957 owner: open_orders_address,
2958 owner_slot,
2959 max_coin_qty: instruction.max_coin_qty,
2960 native_pc_qty_locked,
2961 client_order_id: NonZeroU64::new(instruction.client_order_id),
2962 };
2963 let mut limit = instruction.limit;
2964 let unfilled_portion = order_book_state.process_orderbook_request(
2965 &request,
2966 &mut event_q,
2967 &mut proceeds,
2968 &mut limit,
2969 )?;
2970
2971 check_assert!(unfilled_portion.is_none())?;
2972
2973 {
2974 let coin_lot_size = order_book_state.market_state.coin_lot_size;
2975
2976 let RequestProceeds {
2977 coin_unlocked,
2978 coin_credit,
2979
2980 native_pc_unlocked,
2981 native_pc_credit,
2982
2983 coin_debit,
2984 native_pc_debit,
2985 } = proceeds;
2986
2987 let native_coin_unlocked = coin_unlocked.checked_mul(coin_lot_size).unwrap();
2988 let native_coin_credit = coin_credit.checked_mul(coin_lot_size).unwrap();
2989 let native_coin_debit = coin_debit.checked_mul(coin_lot_size).unwrap();
2990
2991 open_orders_mut.credit_locked_coin(native_coin_credit);
2992 open_orders_mut.unlock_coin(native_coin_credit);
2993 open_orders_mut.unlock_coin(native_coin_unlocked);
2994
2995 open_orders_mut.credit_locked_pc(native_pc_credit);
2996 open_orders_mut.unlock_pc(native_pc_credit);
2997 open_orders_mut.unlock_pc(native_pc_unlocked);
2998
2999 open_orders_mut.native_coin_total = open_orders_mut
3000 .native_coin_total
3001 .checked_sub(native_coin_debit)
3002 .unwrap();
3003 open_orders_mut.native_pc_total = open_orders_mut
3004 .native_pc_total
3005 .checked_sub(native_pc_debit)
3006 .unwrap();
3007 check_assert!(open_orders_mut.native_coin_free <= open_orders_mut.native_coin_total)?;
3008 check_assert!(open_orders_mut.native_pc_free <= open_orders_mut.native_pc_total)?;
3009 }
3010
3011 drop(open_orders);
3018
3019 if deposit_amount != 0 {
3020 let balance_before = deposit_vault.balance()?;
3021 let deposit_instruction = spl_token::instruction::transfer(
3022 &spl_token::ID,
3023 payer.inner().key,
3024 deposit_vault.inner().key,
3025 owner.inner().key,
3026 &[],
3027 deposit_amount,
3028 )
3029 .unwrap();
3030 invoke_spl_token(
3031 &deposit_instruction,
3032 &[
3033 payer.inner().clone(),
3034 deposit_vault.inner().clone(),
3035 owner.inner().clone(),
3036 spl_token_program.inner().clone(),
3037 ],
3038 &[],
3039 )
3040 .map_err(|err| match err {
3041 ProgramError::Custom(i) => match TokenError::from_u32(i) {
3042 Some(TokenError::InsufficientFunds) => DexErrorCode::InsufficientFunds,
3043 _ => DexErrorCode::TransferFailed,
3044 },
3045 _ => DexErrorCode::TransferFailed,
3046 })?;
3047 let balance_after = deposit_vault.balance()?;
3048 let balance_change = balance_after.checked_sub(balance_before);
3049 check_assert_eq!(Some(deposit_amount), balance_change)?;
3050 }
3051
3052 Ok(())
3053 }
3054
3055 fn process_disable_market(args: account_parser::DisableMarketArgs) -> DexResult {
3056 let account_parser::DisableMarketArgs {
3057 market,
3058 authorization: _,
3059 } = args;
3060 market.account_flags = market.account_flags | (AccountFlag::Disabled as u64);
3061 Ok(())
3062 }
3063
3064 #[cfg(feature = "program")]
3065 fn process_sweep_fees(args: account_parser::SweepFeesArgs) -> DexResult {
3066 let account_parser::SweepFeesArgs {
3067 mut market,
3068 pc_vault,
3069 fee_receiver,
3070 vault_signer,
3071 spl_token_program,
3072 authorization: _,
3073 } = args;
3074 let token_amount = market.pc_fees_accrued;
3075 market.pc_fees_accrued = 0;
3076
3077 let nonce = market.vault_signer_nonce;
3078 let market_pubkey = market.pubkey();
3079 let vault_signer_seeds = gen_vault_signer_seeds(&nonce, &market_pubkey);
3080 send_from_vault(
3081 token_amount,
3082 fee_receiver.token_account(),
3083 pc_vault.token_account(),
3084 spl_token_program,
3085 vault_signer,
3086 &vault_signer_seeds,
3087 )
3088 }
3089
3090 fn process_initialize_market(args: account_parser::InitializeMarketArgs) -> DexResult {
3091 let &InitializeMarketInstruction {
3092 coin_lot_size,
3093 pc_lot_size,
3094 fee_rate_bps,
3095 vault_signer_nonce,
3096 pc_dust_threshold,
3097 } = args.instruction;
3098
3099 let market = args.get_market();
3100 let req_q = args.get_req_q();
3101 let event_q = args.get_event_q();
3102 let bids = args.get_bids();
3103 let asks = args.get_asks();
3104 let coin_vault = args.coin_vault_and_mint.get_account().inner();
3105 let coin_mint = args.coin_vault_and_mint.get_mint().inner();
3106 let pc_vault = args.pc_vault_and_mint.get_account().inner();
3107 let pc_mint = args.pc_vault_and_mint.get_mint().inner();
3108 let market_authority = args.market_authority;
3109 let prune_authority = args.prune_authority;
3110 let consume_events_authority = args.consume_events_authority;
3111
3112 let mut rq_data = req_q.try_borrow_mut_data()?;
3114 const RQ_HEADER_WORDS: usize = size_of::<RequestQueueHeader>() / size_of::<u64>();
3115 let rq_view = init_account_padding(&mut rq_data)?;
3116 let (rq_hdr_array, rq_buf_words) = mut_array_refs![rq_view, RQ_HEADER_WORDS; .. ;];
3117 let rq_buf: &[Request] = remove_slop(cast_slice(rq_buf_words));
3118 if rq_buf.is_empty() {
3119 Err(DexErrorCode::RequestQueueEmpty)?
3120 }
3121 let rq_hdr: &mut RequestQueueHeader =
3122 try_cast_mut(rq_hdr_array).or(check_unreachable!())?;
3123 *rq_hdr = RequestQueueHeader {
3124 account_flags: (AccountFlag::Initialized | AccountFlag::RequestQueue).bits(),
3125 head: 0,
3126 count: 0,
3127 next_seq_num: 0,
3128 };
3129 let mut eq_data = event_q.try_borrow_mut_data().unwrap();
3131 const EQ_HEADER_WORDS: usize = size_of::<EventQueueHeader>() / size_of::<u64>();
3132 let eq_view = init_account_padding(&mut eq_data)?;
3133 check_assert!(eq_view.len() > EQ_HEADER_WORDS)?;
3134 let (eq_hdr_array, eq_buf_words) = mut_array_refs![eq_view, EQ_HEADER_WORDS; .. ;];
3135 let eq_buf: &[Event] = remove_slop(cast_slice(eq_buf_words));
3136 if eq_buf.len() < 128 {
3137 Err(DexErrorCode::EventQueueTooSmall)?
3138 }
3139 let eq_hdr: &mut EventQueueHeader = try_cast_mut(eq_hdr_array).or(check_unreachable!())?;
3140 *eq_hdr = EventQueueHeader {
3141 account_flags: (AccountFlag::Initialized | AccountFlag::EventQueue).bits(),
3142 head: 0,
3143 count: 0,
3144 seq_num: 0,
3145 };
3146 for (flag, account) in &[(AccountFlag::Bids, bids), (AccountFlag::Asks, asks)] {
3148 let mut ob_data = account.try_borrow_mut_data().unwrap();
3149 let ob_view = init_account_padding(&mut ob_data)?;
3150 const OB_HEADER_WORDS: usize = size_of::<OrderBookStateHeader>() / size_of::<u64>();
3151 check_assert!(ob_view.len() > OB_HEADER_WORDS)?;
3152 let (hdr_array, slab_words) = mut_array_refs![ob_view, OB_HEADER_WORDS; .. ;];
3153 let ob_hdr: &mut OrderBookStateHeader =
3154 try_cast_mut(hdr_array).or(check_unreachable!())?;
3155 *ob_hdr = OrderBookStateHeader {
3156 account_flags: (AccountFlag::Initialized | *flag).bits(),
3157 };
3158 let slab = Slab::new(cast_slice_mut(slab_words));
3159 slab.assert_minimum_capacity(100)?;
3160 }
3161 let mut market_data = market.try_borrow_mut_data()?;
3163 let market_view = init_account_padding(&mut market_data)?;
3164 let mut account_flags = AccountFlag::Initialized | AccountFlag::Market;
3165 if market_authority.is_some() {
3166 account_flags |= AccountFlag::Permissioned;
3167 if consume_events_authority.is_some() {
3168 account_flags |= AccountFlag::CrankAuthorityRequired;
3169 }
3170 }
3171 let market_state = MarketState {
3172 coin_lot_size,
3173 pc_lot_size,
3174 own_address: market.key.to_aligned_bytes(),
3175 account_flags: account_flags.bits(),
3176
3177 coin_mint: coin_mint.key.to_aligned_bytes(),
3178 coin_vault: coin_vault.key.to_aligned_bytes(),
3179 coin_deposits_total: 0,
3180 coin_fees_accrued: 0,
3181
3182 req_q: req_q.key.to_aligned_bytes(),
3183 event_q: event_q.key.to_aligned_bytes(),
3184 bids: bids.key.to_aligned_bytes(),
3185 asks: asks.key.to_aligned_bytes(),
3186
3187 pc_mint: pc_mint.key.to_aligned_bytes(),
3188 pc_vault: pc_vault.key.to_aligned_bytes(),
3189 pc_deposits_total: 0,
3190 pc_fees_accrued: 0,
3191 vault_signer_nonce,
3192
3193 pc_dust_threshold,
3194 fee_rate_bps: fee_rate_bps as u64,
3195 referrer_rebates_accrued: 0,
3196 };
3197 match market_authority {
3198 None => {
3199 let market_hdr: &mut MarketState =
3200 try_from_bytes_mut(cast_slice_mut(market_view)).or(check_unreachable!())?;
3201 *market_hdr = market_state;
3202 }
3203 Some(oo_auth) => {
3204 let market_hdr: &mut MarketStateV2 =
3205 try_from_bytes_mut(cast_slice_mut(market_view)).or(check_unreachable!())?;
3206 market_hdr.inner = market_state;
3207 market_hdr.open_orders_authority = *oo_auth.key;
3208 market_hdr.prune_authority =
3209 prune_authority.map(|p| *p.key).unwrap_or(Pubkey::default());
3210
3211 if let Some(consume_events_authority) = consume_events_authority {
3212 market_hdr.consume_events_authority = *consume_events_authority.key;
3213 }
3214 }
3215 }
3216 Ok(())
3217 }
3218}