2023-06-15 01:41:58 -07:00
|
|
|
use std::{
|
|
|
|
cell::RefCell,
|
|
|
|
collections::{BTreeMap, HashSet},
|
|
|
|
convert::TryFrom,
|
|
|
|
mem::size_of,
|
|
|
|
};
|
2023-02-18 06:24:56 -08:00
|
|
|
|
|
|
|
use arrayref::array_ref;
|
2023-03-14 05:39:19 -07:00
|
|
|
use async_channel::Sender;
|
2023-02-18 06:24:56 -08:00
|
|
|
use async_trait::async_trait;
|
2023-03-09 07:08:03 -08:00
|
|
|
use log::*;
|
2023-02-18 06:24:56 -08:00
|
|
|
use mango::{
|
2023-03-09 07:20:49 -08:00
|
|
|
instruction::consume_events,
|
|
|
|
queue::{AnyEvent, EventQueueHeader, EventType, FillEvent, OutEvent, Queue},
|
2023-02-18 06:24:56 -08:00
|
|
|
};
|
2023-04-05 10:06:58 -07:00
|
|
|
use mango_feeds_connector::solana_sdk::account::ReadableAccount;
|
2023-03-09 07:20:49 -08:00
|
|
|
use solana_sdk::{instruction::Instruction, pubkey::Pubkey};
|
2023-02-18 06:24:56 -08:00
|
|
|
|
|
|
|
use bytemuck::cast_ref;
|
|
|
|
|
2023-04-06 07:52:14 -07:00
|
|
|
use mango_feeds_connector::{account_write_filter::AccountWriteSink, chain_data::AccountData};
|
2023-04-05 10:06:58 -07:00
|
|
|
|
2023-04-06 07:52:14 -07:00
|
|
|
use crate::helpers::{to_sdk_instruction, to_sp_pk};
|
2023-02-18 06:24:56 -08:00
|
|
|
|
|
|
|
const MAX_BACKLOG: usize = 2;
|
2023-04-13 10:48:25 -07:00
|
|
|
const MAX_ACCS_PER_TX: usize = 24;
|
|
|
|
const MAX_EVENTS_PER_TX: usize = 50;
|
2023-02-18 06:24:56 -08:00
|
|
|
|
|
|
|
pub struct MangoV3PerpCrankSink {
|
2023-03-09 07:20:49 -08:00
|
|
|
mkt_pks_by_evq_pks: BTreeMap<Pubkey, Pubkey>,
|
|
|
|
group_pk: Pubkey,
|
|
|
|
cache_pk: Pubkey,
|
|
|
|
mango_v3_program: Pubkey,
|
2023-03-15 08:13:25 -07:00
|
|
|
instruction_sender: Sender<(Pubkey, Vec<Instruction>)>,
|
2023-02-18 06:24:56 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl MangoV3PerpCrankSink {
|
2023-03-09 07:20:49 -08:00
|
|
|
pub fn new(
|
|
|
|
pks: Vec<(Pubkey, Pubkey)>,
|
|
|
|
group_pk: Pubkey,
|
|
|
|
cache_pk: Pubkey,
|
|
|
|
mango_v3_program: Pubkey,
|
2023-03-15 08:13:25 -07:00
|
|
|
instruction_sender: Sender<(Pubkey, Vec<Instruction>)>,
|
2023-03-09 07:20:49 -08:00
|
|
|
) -> Self {
|
|
|
|
Self {
|
|
|
|
mkt_pks_by_evq_pks: pks
|
|
|
|
.iter()
|
|
|
|
.map(|(mkt_pk, evq_pk)| (evq_pk.clone(), mkt_pk.clone()))
|
|
|
|
.collect(),
|
|
|
|
group_pk,
|
|
|
|
cache_pk,
|
|
|
|
mango_v3_program,
|
|
|
|
instruction_sender,
|
|
|
|
}
|
|
|
|
}
|
2023-02-18 06:24:56 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// couldn't compile the correct struct size / math on m1, fixed sizes resolve this issue
|
|
|
|
const EVENT_SIZE: usize = 200; //size_of::<AnyEvent>();
|
|
|
|
const QUEUE_LEN: usize = 256;
|
|
|
|
type EventQueueEvents = [AnyEvent; QUEUE_LEN];
|
|
|
|
|
|
|
|
#[async_trait]
|
|
|
|
impl AccountWriteSink for MangoV3PerpCrankSink {
|
2023-04-06 07:52:14 -07:00
|
|
|
async fn process(
|
|
|
|
&self,
|
|
|
|
pk: &mango_feeds_connector::solana_sdk::pubkey::Pubkey,
|
|
|
|
account: &AccountData,
|
|
|
|
) -> Result<(), String> {
|
2023-03-09 07:20:49 -08:00
|
|
|
let account = &account.account;
|
|
|
|
|
2023-03-15 08:13:25 -07:00
|
|
|
let (ix, mkt_pk): (Result<Instruction, String>, Pubkey) = {
|
2023-03-09 07:20:49 -08:00
|
|
|
const HEADER_SIZE: usize = size_of::<EventQueueHeader>();
|
|
|
|
let header_data = array_ref![account.data(), 0, HEADER_SIZE];
|
|
|
|
let header = RefCell::<EventQueueHeader>::new(*bytemuck::from_bytes(header_data));
|
|
|
|
let seq_num = header.clone().into_inner().seq_num.clone();
|
|
|
|
// trace!("evq {} seq_num {}", mkt.name, header.seq_num);
|
|
|
|
|
|
|
|
const QUEUE_SIZE: usize = EVENT_SIZE * QUEUE_LEN;
|
|
|
|
let events_data = array_ref![account.data(), HEADER_SIZE, QUEUE_SIZE];
|
|
|
|
let events = RefCell::<EventQueueEvents>::new(*bytemuck::from_bytes(events_data));
|
|
|
|
let event_queue = Queue {
|
|
|
|
header: header.borrow_mut(),
|
|
|
|
buf: events.borrow_mut(),
|
|
|
|
};
|
|
|
|
|
|
|
|
// only crank if at least 1 fill or a sufficient events of other categories are buffered
|
|
|
|
let contains_fill_events = event_queue
|
|
|
|
.iter()
|
|
|
|
.find(|e| e.event_type == EventType::Fill as u8)
|
|
|
|
.is_some();
|
|
|
|
let len = event_queue.iter().count();
|
|
|
|
let has_backlog = len > MAX_BACKLOG;
|
|
|
|
debug!("evq {pk:?} seq_num={seq_num} len={len} contains_fill_events={contains_fill_events} has_backlog={has_backlog}");
|
|
|
|
|
|
|
|
if !contains_fill_events && !has_backlog {
|
|
|
|
return Err("throttled".into());
|
|
|
|
}
|
|
|
|
|
|
|
|
trace!("evq {pk:?} seq_num={seq_num} len={len} contains_fill_events={contains_fill_events} has_backlog={has_backlog}");
|
|
|
|
|
2023-04-13 10:48:25 -07:00
|
|
|
let mut mango_accounts = HashSet::new();
|
2023-06-15 01:41:58 -07:00
|
|
|
event_queue.iter().take(MAX_EVENTS_PER_TX).for_each(|e| {
|
|
|
|
if mango_accounts.len() < MAX_ACCS_PER_TX {
|
|
|
|
match EventType::try_from(e.event_type).expect("mango v4 event") {
|
|
|
|
EventType::Fill => {
|
|
|
|
let fill: &FillEvent = cast_ref(e);
|
|
|
|
mango_accounts.insert(fill.maker);
|
|
|
|
mango_accounts.insert(fill.taker);
|
|
|
|
}
|
|
|
|
EventType::Out => {
|
|
|
|
let out: &OutEvent = cast_ref(e);
|
|
|
|
mango_accounts.insert(out.owner);
|
2023-03-09 07:20:49 -08:00
|
|
|
}
|
2023-06-15 01:41:58 -07:00
|
|
|
EventType::Liquidate => {}
|
2023-04-13 10:48:25 -07:00
|
|
|
}
|
2023-06-15 01:41:58 -07:00
|
|
|
}
|
|
|
|
});
|
2023-03-09 07:20:49 -08:00
|
|
|
|
2023-04-05 10:06:58 -07:00
|
|
|
let pk = solana_sdk::pubkey::Pubkey::new_from_array(pk.to_bytes());
|
2023-03-09 07:20:49 -08:00
|
|
|
let mkt_pk = self
|
|
|
|
.mkt_pks_by_evq_pks
|
2023-04-05 10:06:58 -07:00
|
|
|
.get(&pk)
|
2023-03-09 07:20:49 -08:00
|
|
|
.expect(&format!("{pk:?} is a known public key"));
|
|
|
|
|
|
|
|
let ix = to_sdk_instruction(
|
|
|
|
consume_events(
|
|
|
|
&to_sp_pk(&self.mango_v3_program),
|
|
|
|
&to_sp_pk(&self.group_pk),
|
|
|
|
&to_sp_pk(&self.cache_pk),
|
|
|
|
&to_sp_pk(mkt_pk),
|
2023-04-06 07:52:14 -07:00
|
|
|
&to_sp_pk(&pk),
|
2023-06-15 01:41:58 -07:00
|
|
|
&mut mango_accounts
|
|
|
|
.iter()
|
|
|
|
.map(|pk| pk.clone())
|
|
|
|
.collect::<Vec<_>>(),
|
2023-03-09 07:20:49 -08:00
|
|
|
MAX_EVENTS_PER_TX,
|
|
|
|
)
|
|
|
|
.unwrap(),
|
|
|
|
);
|
|
|
|
|
2023-03-15 08:13:25 -07:00
|
|
|
(Ok(ix), mkt_pk.clone())
|
2023-03-09 07:20:49 -08:00
|
|
|
};
|
|
|
|
|
|
|
|
// info!(
|
|
|
|
// "evq={pk:?} count={} limit=10",
|
|
|
|
// event_queue.iter().count()
|
|
|
|
// );
|
|
|
|
|
2023-03-15 08:13:25 -07:00
|
|
|
if let Err(e) = self.instruction_sender.send((mkt_pk, vec![ix?])).await {
|
2023-03-09 07:20:49 -08:00
|
|
|
return Err(e.to_string());
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|