serum_dex/
state.rs

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
65// Versioned frontend for market accounts.
66pub 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 for the market flag to be set to AccountFlag::Disabled
97        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    // Unused bytes for future upgrades.
210    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    // 0
295    pub account_flags: u64, // Initialized, Market
296
297    // 1
298    pub own_address: [u64; 4],
299
300    // 5
301    pub vault_signer_nonce: u64,
302    // 6
303    pub coin_mint: [u64; 4],
304    // 10
305    pub pc_mint: [u64; 4],
306
307    // 14
308    pub coin_vault: [u64; 4],
309    // 18
310    pub coin_deposits_total: u64,
311    // 19
312    pub coin_fees_accrued: u64,
313
314    // 20
315    pub pc_vault: [u64; 4],
316    // 24
317    pub pc_deposits_total: u64,
318    // 25
319    pub pc_fees_accrued: u64,
320
321    // 26
322    pub pc_dust_threshold: u64,
323
324    // 27
325    pub req_q: [u64; 4],
326    // 31
327    pub event_q: [u64; 4],
328
329    // 35
330    pub bids: [u64; 4],
331    // 39
332    pub asks: [u64; 4],
333
334    // 43
335    pub coin_lot_size: u64,
336    // 44
337    pub pc_lot_size: u64,
338
339    // 45
340    pub fee_rate_bps: u64,
341    // 46
342    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, // Initialized, OpenOrders
580    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    // Using Option<NonZeroU64> in a pod type requires nightly
593    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, // Initialized, RequestQueue
866    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, // Initialized, EventQueue
1094    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, // Initialized, (Bids or Asks)
1344}
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                // Dynamic sysvars don't work in unit tests.
1635                #[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                // check that the vaults are owned by the market's withdrawal authority key
1671                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                // check that the vault has no delegate
1676                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            // Dynamic sysvars don't work in unit tests.
1861            #[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, // To use an open orders authority, explicitly use the
1892                      // InitOpenOrders instruction.
1893            )?;
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            // Parse accounts.
2270            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            // Validate the accounts given are valid.
2280            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            // Only accounts with no funds associated with them can be closed.
2291            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            // Invoke processor.
2308            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            // Parse accounts.
2325            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            // Dynamic sysvars don't work in unit tests.
2340            #[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            // Validate the accounts given are valid.
2346            let owner = SignerAccount::new(owner_acc)?;
2347            let market = Market::load(market_acc, program_id, false)?;
2348
2349            // Perform open orders initialization.
2350            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            // Invoke processor.
2359            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            // Parse accounts.
2379            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        // Transfer all lamports to the destination.
2610        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        // Mark the account as closed to prevent it from being used before
2617        // garbage collection.
2618        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 the open orders account in the event that it is the owner
3012        // of itself, which may happen if the account is a PDA.
3013        //
3014        // `invoke_spl_token` will try to borrow the account info refcell,
3015        // which would cause an error (as there would be two borrows while
3016        // one of them is mutable).
3017        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        // initialize request queue
3113        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        // initialize event queue
3130        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        // initialize orderbook storage
3147        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        // initialize market
3162        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}