2022-03-22 23:53:45 -07:00
|
|
|
use crate::error::MangoError;
|
|
|
|
use anchor_lang::prelude::*;
|
2022-03-24 11:20:56 -07:00
|
|
|
use fixed::types::I80F48;
|
2022-03-22 23:53:45 -07:00
|
|
|
use mango_macro::Pod;
|
2022-03-24 11:20:56 -07:00
|
|
|
use num_enum::{IntoPrimitive, TryFromPrimitive};
|
2022-04-01 03:22:03 -07:00
|
|
|
use static_assertions::const_assert_eq;
|
|
|
|
use std::mem::size_of;
|
2022-03-24 11:20:56 -07:00
|
|
|
|
|
|
|
use super::Side;
|
2022-03-22 23:53:45 -07:00
|
|
|
|
2022-08-01 07:53:30 -07:00
|
|
|
pub const MAX_NUM_EVENTS: u32 = 488;
|
2022-03-22 23:53:45 -07:00
|
|
|
|
|
|
|
pub trait QueueHeader: bytemuck::Pod {
|
|
|
|
type Item: bytemuck::Pod + Copy;
|
|
|
|
|
|
|
|
fn head(&self) -> usize;
|
2022-06-18 08:49:07 -07:00
|
|
|
fn set_head(&mut self, value: u32);
|
2022-03-22 23:53:45 -07:00
|
|
|
fn count(&self) -> usize;
|
2022-06-18 08:49:07 -07:00
|
|
|
fn set_count(&mut self, value: u32);
|
2022-03-22 23:53:45 -07:00
|
|
|
|
|
|
|
fn incr_event_id(&mut self);
|
2022-06-18 08:49:07 -07:00
|
|
|
fn decr_event_id(&mut self, n: u64);
|
2022-03-22 23:53:45 -07:00
|
|
|
}
|
|
|
|
|
2022-03-24 06:40:08 -07:00
|
|
|
#[account(zero_copy)]
|
2022-05-18 08:16:14 -07:00
|
|
|
pub struct EventQueue {
|
|
|
|
pub header: EventQueueHeader,
|
2022-06-18 08:49:07 -07:00
|
|
|
pub buf: [AnyEvent; MAX_NUM_EVENTS as usize],
|
2022-03-22 23:53:45 -07:00
|
|
|
}
|
|
|
|
|
2022-05-18 08:16:14 -07:00
|
|
|
impl EventQueue {
|
2022-03-22 23:53:45 -07:00
|
|
|
pub fn len(&self) -> usize {
|
|
|
|
self.header.count()
|
|
|
|
}
|
|
|
|
|
2022-03-24 06:40:08 -07:00
|
|
|
pub fn is_empty(&self) -> bool {
|
|
|
|
self.len() == 0
|
|
|
|
}
|
|
|
|
|
2022-03-22 23:53:45 -07:00
|
|
|
pub fn full(&self) -> bool {
|
|
|
|
self.header.count() == self.buf.len()
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn empty(&self) -> bool {
|
|
|
|
self.header.count() == 0
|
|
|
|
}
|
|
|
|
|
2022-05-18 08:16:14 -07:00
|
|
|
pub fn push_back(&mut self, value: AnyEvent) -> std::result::Result<(), AnyEvent> {
|
2022-03-22 23:53:45 -07:00
|
|
|
if self.full() {
|
|
|
|
return Err(value);
|
|
|
|
}
|
|
|
|
let slot = (self.header.head() + self.header.count()) % self.buf.len();
|
|
|
|
self.buf[slot] = value;
|
|
|
|
|
|
|
|
let count = self.header.count();
|
2022-06-18 08:49:07 -07:00
|
|
|
self.header.set_count((count + 1) as u32); // guaranteed because of full() check
|
2022-03-22 23:53:45 -07:00
|
|
|
|
|
|
|
self.header.incr_event_id();
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2022-05-18 08:16:14 -07:00
|
|
|
pub fn peek_front(&self) -> Option<&AnyEvent> {
|
2022-03-22 23:53:45 -07:00
|
|
|
if self.empty() {
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
Some(&self.buf[self.header.head()])
|
|
|
|
}
|
|
|
|
|
2022-05-18 08:16:14 -07:00
|
|
|
pub fn peek_front_mut(&mut self) -> Option<&mut AnyEvent> {
|
2022-03-22 23:53:45 -07:00
|
|
|
if self.empty() {
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
Some(&mut self.buf[self.header.head()])
|
|
|
|
}
|
|
|
|
|
2022-05-18 08:16:14 -07:00
|
|
|
pub fn pop_front(&mut self) -> Result<AnyEvent> {
|
2022-03-24 06:40:08 -07:00
|
|
|
require!(!self.empty(), MangoError::SomeError);
|
|
|
|
|
2022-03-22 23:53:45 -07:00
|
|
|
let value = self.buf[self.header.head()];
|
|
|
|
|
|
|
|
let count = self.header.count();
|
2022-06-18 08:49:07 -07:00
|
|
|
self.header.set_count((count - 1) as u32);
|
2022-03-22 23:53:45 -07:00
|
|
|
|
|
|
|
let head = self.header.head();
|
2022-06-18 08:49:07 -07:00
|
|
|
self.header.set_head(((head + 1) % self.buf.len()) as u32);
|
2022-03-22 23:53:45 -07:00
|
|
|
|
|
|
|
Ok(value)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn revert_pushes(&mut self, desired_len: usize) -> Result<()> {
|
|
|
|
require!(desired_len <= self.header.count(), MangoError::SomeError);
|
|
|
|
let len_diff = self.header.count() - desired_len;
|
2022-06-18 08:49:07 -07:00
|
|
|
self.header.set_count(desired_len as u32);
|
|
|
|
self.header.decr_event_id(len_diff as u64);
|
2022-03-22 23:53:45 -07:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2022-05-18 08:16:14 -07:00
|
|
|
pub fn iter(&self) -> impl Iterator<Item = &AnyEvent> {
|
|
|
|
EventQueueIterator {
|
2022-03-22 23:53:45 -07:00
|
|
|
queue: self,
|
|
|
|
index: 0,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-18 08:16:14 -07:00
|
|
|
struct EventQueueIterator<'a> {
|
|
|
|
queue: &'a EventQueue,
|
2022-03-22 23:53:45 -07:00
|
|
|
index: usize,
|
|
|
|
}
|
|
|
|
|
2022-05-18 08:16:14 -07:00
|
|
|
impl<'a> Iterator for EventQueueIterator<'a> {
|
|
|
|
type Item = &'a AnyEvent;
|
2022-03-22 23:53:45 -07:00
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
|
|
if self.index == self.queue.len() {
|
|
|
|
None
|
|
|
|
} else {
|
|
|
|
let item =
|
|
|
|
&self.queue.buf[(self.queue.header.head() + self.index) % self.queue.buf.len()];
|
|
|
|
self.index += 1;
|
|
|
|
Some(item)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-18 08:16:14 -07:00
|
|
|
#[zero_copy]
|
|
|
|
#[derive(Pod)]
|
2022-03-22 23:53:45 -07:00
|
|
|
pub struct EventQueueHeader {
|
2022-06-18 08:49:07 -07:00
|
|
|
head: u32,
|
|
|
|
count: u32,
|
|
|
|
pub seq_num: u64,
|
2022-03-22 23:53:45 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
impl QueueHeader for EventQueueHeader {
|
|
|
|
type Item = AnyEvent;
|
|
|
|
|
|
|
|
fn head(&self) -> usize {
|
2022-06-18 08:49:07 -07:00
|
|
|
self.head as usize
|
2022-03-22 23:53:45 -07:00
|
|
|
}
|
2022-06-18 08:49:07 -07:00
|
|
|
fn set_head(&mut self, value: u32) {
|
2022-03-22 23:53:45 -07:00
|
|
|
self.head = value;
|
|
|
|
}
|
|
|
|
fn count(&self) -> usize {
|
2022-06-18 08:49:07 -07:00
|
|
|
self.count as usize
|
2022-03-22 23:53:45 -07:00
|
|
|
}
|
2022-06-18 08:49:07 -07:00
|
|
|
fn set_count(&mut self, value: u32) {
|
2022-03-22 23:53:45 -07:00
|
|
|
self.count = value;
|
|
|
|
}
|
|
|
|
fn incr_event_id(&mut self) {
|
|
|
|
self.seq_num += 1;
|
|
|
|
}
|
2022-06-18 08:49:07 -07:00
|
|
|
fn decr_event_id(&mut self, n: u64) {
|
2022-03-22 23:53:45 -07:00
|
|
|
self.seq_num -= n;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-01 07:53:30 -07:00
|
|
|
const_assert_eq!(std::mem::size_of::<EventQueue>(), 4 * 2 + 8 + 488 * 208);
|
2022-05-11 04:33:01 -07:00
|
|
|
const_assert_eq!(std::mem::size_of::<EventQueue>() % 8, 0);
|
2022-03-22 23:53:45 -07:00
|
|
|
|
2022-08-01 07:53:30 -07:00
|
|
|
const EVENT_SIZE: usize = 208;
|
2022-05-18 08:16:14 -07:00
|
|
|
#[zero_copy]
|
|
|
|
#[derive(Debug, Pod)]
|
2022-03-22 23:53:45 -07:00
|
|
|
pub struct AnyEvent {
|
|
|
|
pub event_type: u8,
|
2022-08-01 07:53:30 -07:00
|
|
|
pub padding: [u8; 207], // note: anchor can't parse the struct for IDL when it includes non numbers, EVENT_SIZE == 208, 207 == 208 - 1
|
2022-03-22 23:53:45 -07:00
|
|
|
}
|
2022-03-24 11:20:56 -07:00
|
|
|
|
2022-05-18 08:16:14 -07:00
|
|
|
const_assert_eq!(size_of::<AnyEvent>(), EVENT_SIZE);
|
|
|
|
|
2022-03-24 11:20:56 -07:00
|
|
|
#[derive(Copy, Clone, IntoPrimitive, TryFromPrimitive, Eq, PartialEq)]
|
|
|
|
#[repr(u8)]
|
|
|
|
pub enum EventType {
|
|
|
|
Fill,
|
|
|
|
Out,
|
|
|
|
Liquidate,
|
|
|
|
}
|
|
|
|
|
2022-09-20 03:57:01 -07:00
|
|
|
#[derive(Copy, Clone, Debug, Pod, AnchorSerialize, AnchorDeserialize)]
|
2022-03-24 11:20:56 -07:00
|
|
|
#[repr(C)]
|
|
|
|
pub struct FillEvent {
|
|
|
|
pub event_type: u8,
|
|
|
|
pub taker_side: Side, // side from the taker's POV
|
2022-03-25 12:35:19 -07:00
|
|
|
pub maker_out: bool, // true if maker order quantity == 0
|
2022-03-28 12:13:16 -07:00
|
|
|
pub maker_slot: u8,
|
2022-03-24 11:20:56 -07:00
|
|
|
pub market_fees_applied: bool,
|
2022-04-01 03:22:03 -07:00
|
|
|
pub padding: [u8; 3],
|
2022-03-24 11:20:56 -07:00
|
|
|
pub timestamp: u64,
|
2022-06-18 08:49:07 -07:00
|
|
|
pub seq_num: u64,
|
2022-03-24 11:20:56 -07:00
|
|
|
|
|
|
|
pub maker: Pubkey,
|
2022-11-08 06:27:56 -08:00
|
|
|
pub maker_order_id: u128,
|
2022-03-24 11:20:56 -07:00
|
|
|
pub maker_client_order_id: u64,
|
|
|
|
pub maker_fee: I80F48,
|
|
|
|
|
|
|
|
// Timestamp of when the maker order was placed; copied over from the LeafNode
|
|
|
|
pub maker_timestamp: u64,
|
|
|
|
|
|
|
|
pub taker: Pubkey,
|
2022-11-08 06:27:56 -08:00
|
|
|
pub taker_order_id: u128,
|
2022-03-24 11:20:56 -07:00
|
|
|
pub taker_client_order_id: u64,
|
|
|
|
pub taker_fee: I80F48,
|
|
|
|
|
|
|
|
pub price: i64,
|
|
|
|
pub quantity: i64, // number of quote lots
|
2022-08-01 07:53:30 -07:00
|
|
|
pub reserved: [u8; 16],
|
2022-03-24 11:20:56 -07:00
|
|
|
}
|
2022-09-20 03:57:01 -07:00
|
|
|
const_assert_eq!(size_of::<FillEvent>() % 8, 0);
|
2022-04-01 03:22:03 -07:00
|
|
|
const_assert_eq!(size_of::<FillEvent>(), EVENT_SIZE);
|
2022-03-24 11:20:56 -07:00
|
|
|
|
|
|
|
impl FillEvent {
|
2022-03-24 11:27:00 -07:00
|
|
|
#[allow(clippy::too_many_arguments)]
|
2022-03-24 11:20:56 -07:00
|
|
|
pub fn new(
|
|
|
|
taker_side: Side,
|
|
|
|
maker_out: bool,
|
2022-03-28 12:13:16 -07:00
|
|
|
maker_slot: u8,
|
2022-03-24 11:20:56 -07:00
|
|
|
timestamp: u64,
|
2022-06-18 08:49:07 -07:00
|
|
|
seq_num: u64,
|
2022-03-24 11:20:56 -07:00
|
|
|
maker: Pubkey,
|
2022-11-08 06:27:56 -08:00
|
|
|
maker_order_id: u128,
|
2022-03-24 11:20:56 -07:00
|
|
|
maker_client_order_id: u64,
|
|
|
|
maker_fee: I80F48,
|
|
|
|
maker_timestamp: u64,
|
|
|
|
|
|
|
|
taker: Pubkey,
|
2022-11-08 06:27:56 -08:00
|
|
|
taker_order_id: u128,
|
2022-03-24 11:20:56 -07:00
|
|
|
taker_client_order_id: u64,
|
|
|
|
taker_fee: I80F48,
|
|
|
|
price: i64,
|
|
|
|
quantity: i64,
|
|
|
|
) -> FillEvent {
|
|
|
|
Self {
|
|
|
|
event_type: EventType::Fill as u8,
|
|
|
|
taker_side,
|
|
|
|
maker_out,
|
2022-03-28 12:13:16 -07:00
|
|
|
maker_slot,
|
2022-03-24 11:20:56 -07:00
|
|
|
market_fees_applied: true, // Since mango v3.3.5, market fees are adjusted at matching time
|
2022-04-01 03:22:03 -07:00
|
|
|
padding: Default::default(),
|
2022-03-24 11:20:56 -07:00
|
|
|
timestamp,
|
|
|
|
seq_num,
|
|
|
|
maker,
|
|
|
|
maker_order_id,
|
|
|
|
maker_client_order_id,
|
|
|
|
maker_fee,
|
|
|
|
maker_timestamp,
|
|
|
|
taker,
|
|
|
|
taker_order_id,
|
|
|
|
taker_client_order_id,
|
|
|
|
taker_fee,
|
|
|
|
price,
|
|
|
|
quantity,
|
2022-08-01 07:53:30 -07:00
|
|
|
reserved: [0; 16],
|
2022-03-24 11:20:56 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn base_quote_change(&self, side: Side) -> (i64, i64) {
|
|
|
|
match side {
|
|
|
|
Side::Bid => (
|
|
|
|
self.quantity,
|
|
|
|
-self.price.checked_mul(self.quantity).unwrap(),
|
|
|
|
),
|
|
|
|
Side::Ask => (
|
|
|
|
-self.quantity,
|
|
|
|
self.price.checked_mul(self.quantity).unwrap(),
|
|
|
|
),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-20 03:57:01 -07:00
|
|
|
#[derive(Copy, Clone, Debug, Pod, AnchorSerialize, AnchorDeserialize)]
|
2022-03-24 11:20:56 -07:00
|
|
|
#[repr(C)]
|
|
|
|
pub struct OutEvent {
|
|
|
|
pub event_type: u8,
|
|
|
|
pub side: Side,
|
2022-03-28 12:13:16 -07:00
|
|
|
pub owner_slot: u8,
|
2022-03-24 11:20:56 -07:00
|
|
|
padding0: [u8; 5],
|
|
|
|
pub timestamp: u64,
|
2022-06-18 08:49:07 -07:00
|
|
|
pub seq_num: u64,
|
2022-03-24 11:20:56 -07:00
|
|
|
pub owner: Pubkey,
|
|
|
|
pub quantity: i64,
|
2022-09-20 03:57:01 -07:00
|
|
|
padding1: [u8; 144],
|
2022-03-24 11:20:56 -07:00
|
|
|
}
|
2022-09-20 03:57:01 -07:00
|
|
|
const_assert_eq!(size_of::<OutEvent>() % 8, 0);
|
2022-04-01 03:22:03 -07:00
|
|
|
const_assert_eq!(size_of::<OutEvent>(), EVENT_SIZE);
|
2022-03-24 11:20:56 -07:00
|
|
|
|
|
|
|
impl OutEvent {
|
2022-03-28 12:13:16 -07:00
|
|
|
pub fn new(
|
|
|
|
side: Side,
|
|
|
|
owner_slot: u8,
|
|
|
|
timestamp: u64,
|
2022-06-18 08:49:07 -07:00
|
|
|
seq_num: u64,
|
2022-03-28 12:13:16 -07:00
|
|
|
owner: Pubkey,
|
|
|
|
quantity: i64,
|
|
|
|
) -> Self {
|
2022-03-24 11:20:56 -07:00
|
|
|
Self {
|
|
|
|
event_type: EventType::Out.into(),
|
|
|
|
side,
|
2022-03-28 12:13:16 -07:00
|
|
|
owner_slot,
|
2022-03-24 11:20:56 -07:00
|
|
|
padding0: [0; 5],
|
|
|
|
timestamp,
|
|
|
|
seq_num,
|
|
|
|
owner,
|
|
|
|
quantity,
|
|
|
|
padding1: [0; EVENT_SIZE - 64],
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|