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 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 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}