zo_abi/
dex.rs

1use anchor_lang::prelude::Pubkey;
2use bytemuck::{Pod, PodCastError, Zeroable};
3use std::{mem::size_of, num::NonZeroU64};
4
5#[derive(Copy, Clone, Debug)]
6#[repr(u64)]
7pub enum AccountFlag {
8    Initialized = 1u64 << 0,
9    Market = 1u64 << 1,
10    OpenOrders = 1u64 << 2,
11    RequestQueue = 1u64 << 3,
12    EventQueue = 1u64 << 4,
13    Bids = 1u64 << 5,
14    Asks = 1u64 << 6,
15    Disabled = 1u64 << 7,
16    Closed = 1u64 << 8,
17    Permissioned = 1u64 << 9,
18}
19
20#[derive(Copy, Clone, Debug)]
21#[repr(u8)]
22pub enum EventFlag {
23    Fill = 0x1,
24    Out = 0x2,
25    Bid = 0x4,
26    Maker = 0x8,
27    ReleaseFunds = 0x10,
28}
29
30#[derive(Copy, Clone, Debug)]
31#[repr(u8)]
32pub enum Side {
33    Bid = 0,
34    Ask = 1,
35}
36
37#[derive(Copy, Clone, Debug)]
38#[repr(packed)]
39pub struct ZoDexMarket {
40    _head_pad: [u8; 5],
41
42    pub account_flags: u64,
43    pub own_address: Pubkey,
44    pub pc_fees_accrued: u64,
45    pub req_q: Pubkey,
46    pub event_q: Pubkey,
47    pub bids: Pubkey,
48    pub asks: Pubkey,
49    pub coin_lot_size: u64,
50    pub pc_lot_size: u64,
51    pub fee_rate_bps: u64,
52    pub referrer_rebates_accrued: u64,
53    pub funding_index: i128,
54    pub last_updated: u64,
55    pub strike: u64,
56    pub perp_type: u64,
57    pub coin_decimals: u64,
58    pub open_interest: u64,
59
60    pub open_orders_authority: Pubkey,
61    pub prune_authority: Pubkey,
62
63    _pad: [u8; 1032],
64    _tail_pad: [u8; 7],
65}
66
67unsafe impl Zeroable for ZoDexMarket {}
68unsafe impl Pod for ZoDexMarket {}
69
70impl ZoDexMarket {
71    pub fn deserialize(buf: &[u8]) -> Result<&Self, PodCastError> {
72        const FLAGS: u64 = (AccountFlag::Initialized as u64)
73            | (AccountFlag::Market as u64)
74            | (AccountFlag::Permissioned as u64);
75
76        let r: &Self = bytemuck::try_from_bytes(buf)?;
77
78        if r._head_pad[..] != *"serum".as_bytes()
79            || r._tail_pad[..] != *"padding".as_bytes()
80            || r.account_flags != FLAGS
81        {
82            panic!("Invalid buffer for market");
83        }
84
85        Ok(r)
86    }
87
88    pub fn lots_to_price(self, n: u64) -> f64 {
89        let adj = 10f64.powi(self.coin_decimals as i32 - 6i32);
90        let n = n * self.pc_lot_size;
91        let (q, r) = (n / self.coin_lot_size, n % self.coin_lot_size);
92        (q as f64 + (r as f64 / self.coin_lot_size as f64)) * adj
93    }
94
95    pub fn lots_to_size(self, n: u64) -> f64 {
96        (n * self.coin_lot_size) as f64 / 10f64.powi(self.coin_decimals as i32)
97    }
98
99    pub fn price_to_lots(self, n: f64) -> u64 {
100        (n * (10f64.powi(6 - self.coin_decimals as i32)
101            * self.coin_lot_size as f64
102            / self.pc_lot_size as f64))
103            .round() as u64
104    }
105
106    pub fn size_to_lots(self, n: f64) -> u64 {
107        (n * 10f64.powi(self.coin_decimals as i32)).round() as u64
108            / self.coin_lot_size
109    }
110
111    pub fn parse_order(self, n: &LeafNode, side: Side) -> Order {
112        Order {
113            owner_slot: n.owner_slot,
114            fee_tier: n.fee_tier,
115            control: n.control,
116            order_id: n.key,
117            client_order_id: n.client_order_id,
118            size: self.lots_to_size(n.quantity),
119            price: self.lots_to_price((n.key >> 64) as u64),
120            side,
121        }
122    }
123}
124
125#[derive(Copy, Clone, Debug)]
126#[repr(packed)]
127pub struct EventQueueHeader {
128    _head_pad: [u8; 5],
129
130    pub account_flags: u64,
131    pub head: u64,
132    pub count: u64,
133    pub seq_num: u64,
134}
135
136unsafe impl Zeroable for EventQueueHeader {}
137unsafe impl Pod for EventQueueHeader {}
138
139impl EventQueueHeader {
140    pub fn deserialize(buf: &[u8]) -> Result<&Self, PodCastError> {
141        const FLAGS: u64 = (AccountFlag::Initialized as u64)
142            | (AccountFlag::EventQueue as u64);
143
144        let r: &Self = bytemuck::try_from_bytes(buf)?;
145
146        if r._head_pad[..] != *"serum".as_bytes() || r.account_flags != FLAGS {
147            panic!("Invalid buffer for event queue header");
148        }
149
150        Ok(r)
151    }
152}
153
154#[derive(Copy, Clone, Debug)]
155#[repr(packed)]
156pub struct Event {
157    pub event_flags: u8,
158    pub owner_slot: u8,
159    pub fee_tier: u8,
160
161    _pad: [u8; 5],
162
163    pub native_qty_released: u64,
164    pub native_qty_paid: u64,
165    pub native_fee_or_rebate: u64,
166    pub order_id: u128,
167    pub control: Pubkey,
168    pub client_order_id: u64,
169}
170
171unsafe impl Zeroable for Event {}
172unsafe impl Pod for Event {}
173
174impl Event {
175    pub fn split(
176        buf: &[u8],
177    ) -> Result<(&EventQueueHeader, &[Self]), PodCastError> {
178        let (header, body) = buf.split_at(size_of::<EventQueueHeader>());
179
180        if body[(body.len() - 7)..] != *"padding".as_bytes() {
181            panic!("Invalid buffer for event queue");
182        }
183
184        let header = EventQueueHeader::deserialize(header)?;
185
186        // Omit slop and padding at the end.
187        let body = &body[..(body.len() - body.len() % size_of::<Self>())];
188        let body: &[Self] = bytemuck::try_cast_slice(body)?;
189
190        Ok((header, body))
191    }
192
193    pub fn deserialize_queue(
194        buf: &[u8],
195    ) -> Result<
196        (&EventQueueHeader, impl Iterator<Item = &Self> + '_),
197        PodCastError,
198    > {
199        let (header, body) = Self::split(buf)?;
200
201        let (tail, head) = body.split_at(header.head as usize);
202        let head_len = head.len().min(header.count as usize);
203        let tail_len = header.count as usize - head_len;
204
205        let head = &head[..head_len];
206        let tail = &tail[..tail_len];
207
208        Ok((header, head.iter().chain(tail.iter())))
209    }
210
211    /// Iterator over sequence number and Events. Also
212    /// return the new seq_num.
213    pub fn deserialize_since(
214        buf: &[u8],
215        last_seq_num: u64,
216    ) -> Result<(impl Iterator<Item = (u64, &Self)> + '_, u64), PodCastError>
217    {
218        let (header, body) = Self::split(buf)?;
219        let len = body.len() as u64;
220
221        const MOD32: u64 = 1u64 << 32;
222
223        let mut missed = (MOD32 + header.seq_num - last_seq_num) % MOD32;
224        if missed > len {
225            missed = len - 1;
226        }
227
228        let start_seq = (MOD32 + header.seq_num - missed) % MOD32;
229        let end = (header.head + header.count) % len;
230        let start = (len + end - missed) % len;
231
232        Ok((
233            (0u64..missed).map(move |i| {
234                let seq = (start_seq + i) % MOD32;
235                let j = ((start + i) % len) as usize;
236
237                (seq, &body[j])
238            }),
239            header.seq_num % MOD32,
240        ))
241    }
242
243    pub fn is_fill(&self) -> bool {
244        self.event_flags & (EventFlag::Fill as u8) != 0
245    }
246
247    pub fn is_bid(&self) -> bool {
248        self.event_flags & (EventFlag::Bid as u8) != 0
249    }
250
251    pub fn is_maker(&self) -> bool {
252        self.event_flags & (EventFlag::Maker as u8) != 0
253    }
254}
255
256#[derive(Copy, Clone, Debug)]
257#[repr(packed)]
258struct InnerNode {
259    _prefix_len: u32,
260    _key: u128,
261    pub children: [u32; 2],
262    _pad: [u8; 40],
263}
264
265unsafe impl Zeroable for InnerNode {}
266unsafe impl Pod for InnerNode {}
267
268#[derive(Copy, Clone, Debug)]
269#[repr(packed)]
270pub struct LeafNode {
271    pub owner_slot: u8,
272    pub fee_tier: u8,
273    _pad: [u8; 2],
274    pub key: u128,
275    pub control: Pubkey,
276    pub quantity: u64,
277    pub client_order_id: u64,
278}
279
280unsafe impl Zeroable for LeafNode {}
281unsafe impl Pod for LeafNode {}
282
283impl LeafNode {
284    pub fn price(&self) -> NonZeroU64 {
285        NonZeroU64::new((self.key >> 64) as u64).unwrap()
286    }
287}
288
289enum SlabNodeRef<'a> {
290    Inner(&'a InnerNode),
291    Leaf(&'a LeafNode),
292}
293
294#[derive(Copy, Clone, Debug)]
295#[repr(packed)]
296struct SlabNode {
297    tag: u32,
298    node: [u8; 68],
299}
300
301unsafe impl Zeroable for SlabNode {}
302unsafe impl Pod for SlabNode {}
303
304impl SlabNode {
305    fn load(&self) -> Option<SlabNodeRef<'_>> {
306        match self.tag {
307            0 | 3 | 4 => None,
308            1 => Some(SlabNodeRef::Inner(bytemuck::from_bytes(&self.node))),
309            2 => Some(SlabNodeRef::Leaf(bytemuck::from_bytes(&self.node))),
310            i => panic!("Invalid tag {} for slab node", i),
311        }
312    }
313}
314
315#[derive(Copy, Clone, Debug)]
316#[repr(packed)]
317struct SlabHeader {
318    _head_pad: [u8; 5],
319    account_flags: u64,
320    _bump_index: u32,
321    _pad0: [u8; 4],
322    _free_list_len: u32,
323    _pad1: [u8; 4],
324    _free_list_head: u32,
325    root: u32,
326    leaf_count: u32,
327    _pad2: [u8; 4],
328}
329
330unsafe impl Zeroable for SlabHeader {}
331unsafe impl Pod for SlabHeader {}
332
333#[derive(Clone, Debug)]
334pub struct Slab<'a> {
335    head: &'a SlabHeader,
336    nodes: &'a [SlabNode],
337}
338
339impl<'a> Slab<'a> {
340    pub fn deserialize(buf: &'a [u8]) -> Result<Slab<'a>, PodCastError> {
341        if buf.len() < size_of::<SlabHeader>() {
342            return Err(PodCastError::SizeMismatch);
343        }
344
345        let (head, tail) = buf.split_at(size_of::<SlabHeader>());
346        let head: &SlabHeader = bytemuck::try_from_bytes(head)?;
347        let tail = &tail[..(tail.len() - tail.len() % size_of::<SlabNode>())];
348
349        if buf[..5] != *b"serum"
350            || buf[(buf.len() - 7)..] != *b"padding"
351            || head.account_flags & AccountFlag::Initialized as u64 == 0
352            || (head.account_flags & AccountFlag::Bids as u64 != 0)
353                == (head.account_flags & AccountFlag::Asks as u64 != 0)
354        {
355            panic!("Invalid buffer for slab");
356        }
357
358        Ok(Self {
359            head,
360            nodes: bytemuck::try_cast_slice(tail)?,
361        })
362    }
363
364    pub fn is_bids(&self) -> bool {
365        self.head.account_flags & AccountFlag::Bids as u64 != 0
366    }
367
368    pub fn is_asks(&self) -> bool {
369        self.head.account_flags & AccountFlag::Asks as u64 != 0
370    }
371
372    pub fn side(&self) -> Side {
373        match self.is_bids() {
374            true => Side::Bid,
375            false => Side::Ask,
376        }
377    }
378
379    pub fn get_min(&self) -> Option<&LeafNode> {
380        self.iter_front().next()
381    }
382
383    pub fn get_max(&self) -> Option<&LeafNode> {
384        self.iter_back().next()
385    }
386
387    pub fn get_best(&self) -> Option<&LeafNode> {
388        self.iter_best().next()
389    }
390
391    pub fn iter_front(&self) -> SlabIter<'_, '_> {
392        SlabIter {
393            slab: self,
394            stack: if self.head.leaf_count > 0 {
395                vec![self.head.root]
396            } else {
397                vec![]
398            },
399            ascending: true,
400        }
401    }
402
403    pub fn iter_back(&self) -> SlabIter<'_, '_> {
404        SlabIter {
405            slab: self,
406            stack: if self.head.leaf_count > 0 {
407                vec![self.head.root]
408            } else {
409                vec![]
410            },
411            ascending: false,
412        }
413    }
414
415    pub fn iter_best(&self) -> SlabIter<'_, '_> {
416        match self.is_bids() {
417            true => self.iter_back(),
418            false => self.iter_front(),
419        }
420    }
421}
422
423pub struct SlabIter<'a, 'b: 'a> {
424    slab: &'a Slab<'b>,
425    stack: Vec<u32>,
426    ascending: bool,
427}
428
429impl<'a, 'b: 'a> Iterator for SlabIter<'a, 'b> {
430    type Item = &'a LeafNode;
431    fn next(&mut self) -> Option<Self::Item> {
432        loop {
433            match self.slab.nodes[self.stack.pop()? as usize].load()? {
434                SlabNodeRef::Inner(x) => self.stack.extend(if self.ascending {
435                    [x.children[1], x.children[0]]
436                } else {
437                    x.children
438                }),
439                SlabNodeRef::Leaf(x) => return Some(x),
440            }
441        }
442    }
443}
444
445#[derive(Clone, Debug)]
446pub struct Order {
447    pub owner_slot: u8,
448    pub fee_tier: u8,
449    pub control: Pubkey,
450    pub order_id: u128,
451    pub client_order_id: u64,
452    pub size: f64,
453    pub price: f64,
454    pub side: Side,
455}