pub const ONLINE_FEATURES_WASM_OFFSET: u32 = 0x1A000;
#[derive(Clone, Copy, Debug)]
#[repr(C)]
pub struct OnlineFeatures {
pub version: u16,
pub flags: u16,
pub _pad0: [u8; 4],
pub microprice_1e9: u64,
pub ofi_1level_1e8: i64,
pub ofi_5level_1e8: i64,
pub mlofi_10_1e8: i64,
pub ofi_ewma_1e6: i64,
pub trade_sign_imbalance_1e6: i64,
pub trade_arrival_rate_1e3: u32,
pub vpin_1e4: u16,
pub _pad1: u16,
pub spread_regime: u8,
pub _pad2a: u8,
pub spread_zscore_1e3: i16,
pub cancel_rate_1e4: u16,
pub depth_imbalance_1e4: i16,
pub rv_1m_bps: u32,
pub rv_5m_bps: u32,
pub rv_1h_bps: u32,
pub _pad3: u32,
pub pred_dir_up_1e4: u16,
pub pred_dir_flat_1e4: u16,
pub pred_dir_down_1e4: u16,
pub pred_stress_normal_1e4: u16,
pub pred_stress_widening_1e4: u16,
pub pred_stress_crisis_1e4: u16,
pub pred_toxic_1e4: u16,
pub prediction_age_ms: u16,
pub fill_prob_bid_1e4: u16,
pub fill_prob_ask_1e4: u16,
pub queue_decay_rate_1e4: u16,
pub _fill_pad: u16,
pub feature_ts_ns: u64,
pub _reserved: [u8; 136],
}
impl Default for OnlineFeatures {
fn default() -> Self {
let mut f = unsafe { core::mem::zeroed::<Self>() };
f.version = 1;
f
}
}
impl OnlineFeatures {
#[inline(always)]
pub fn vpin_valid(&self) -> bool {
self.flags & 1 != 0
}
#[inline(always)]
pub fn microprice_f64(&self) -> f64 {
self.microprice_1e9 as f64 / 1_000_000_000.0
}
#[inline(always)]
pub fn ofi_1level_f64(&self) -> f64 {
self.ofi_1level_1e8 as f64 / 100_000_000.0
}
#[inline(always)]
pub fn trade_sign_imbalance_f64(&self) -> f64 {
self.trade_sign_imbalance_1e6 as f64 / 1_000_000.0
}
}
const _: () = assert!(
core::mem::size_of::<OnlineFeatures>() == 256,
"OnlineFeatures must be exactly 256 bytes"
);
const _: () = assert!(
0x1A000 >= 0x14000 + core::mem::size_of::<crate::PoolBooks>(),
"ONLINE_FEATURES_WASM_OFFSET overlaps with PoolBooks"
);
const _: () = assert!(
ONLINE_FEATURES_WASM_OFFSET as usize + core::mem::size_of::<OnlineFeatures>() < 0x1000000,
"OnlineFeatures exceeds WASM 16MB memory limit"
);
pub const CHAIN_FEE_TABLE_WASM_OFFSET: u32 = 0x1B000;
pub const MAX_CHAINS: usize = 8;
#[derive(Clone, Copy, Debug)]
#[repr(C)]
pub struct ChainFee {
pub chain_id: u8,
pub _pad: [u8; 7],
pub base_fee_native: u64,
pub priority_fee_native: u64,
pub estimated_gas_units: u64,
pub native_price_1e9: u64,
pub last_update_ns: u64,
}
impl Default for ChainFee {
fn default() -> Self {
Self {
chain_id: 255,
_pad: [0; 7],
base_fee_native: 0,
priority_fee_native: 0,
estimated_gas_units: 0,
native_price_1e9: 0,
last_update_ns: 0,
}
}
}
impl ChainFee {
pub fn total_gas_cost_native(&self) -> u64 {
if self.chain_id == chain_id::SOLANA {
let priority_lamports = (self.priority_fee_native as u128)
.saturating_mul(self.estimated_gas_units as u128)
/ 1_000_000;
(self.base_fee_native as u128).saturating_add(priority_lamports) as u64
} else {
(self.base_fee_native + self.priority_fee_native)
.saturating_mul(self.estimated_gas_units)
}
}
pub fn gas_cost_usd_1e9(&self) -> u64 {
let cost = self.total_gas_cost_native();
((cost as u128 * self.native_price_1e9 as u128) / 1_000_000_000) as u64
}
}
#[derive(Clone, Copy)]
#[repr(C)]
pub struct ChainFeeTable {
pub chain_ct: u8,
pub _pad: [u8; 7],
pub chains: [ChainFee; MAX_CHAINS],
}
impl Default for ChainFeeTable {
fn default() -> Self {
Self {
chain_ct: 0,
_pad: [0; 7],
chains: [ChainFee::default(); MAX_CHAINS],
}
}
}
impl ChainFeeTable {
pub fn fee_for_chain(&self, chain_id: u8) -> Option<&ChainFee> {
for i in 0..self.chain_ct as usize {
if i < MAX_CHAINS && self.chains[i].chain_id == chain_id {
return Some(&self.chains[i]);
}
}
None
}
}
pub mod chain_id {
pub const ETHEREUM: u8 = 0;
pub const ARBITRUM: u8 = 1;
pub const BASE: u8 = 2;
pub const OPTIMISM: u8 = 3;
pub const POLYGON: u8 = 4;
pub const SOLANA: u8 = 5;
}
pub fn venue_chain_id(venue_id: u8) -> u8 {
match venue_id {
10 => chain_id::ETHEREUM, 11 => chain_id::ARBITRUM, 12 => chain_id::BASE, 13 => chain_id::OPTIMISM, 14 => chain_id::POLYGON, 15 => chain_id::SOLANA, _ => 255, }
}
const _: () = assert!(
core::mem::size_of::<ChainFee>() == 48,
"ChainFee must be exactly 48 bytes"
);
const _: () = assert!(
core::mem::size_of::<ChainFeeTable>() == 392,
"ChainFeeTable must be exactly 392 bytes (8 + 48*8)"
);
const _: () = assert!(
CHAIN_FEE_TABLE_WASM_OFFSET as usize
>= ONLINE_FEATURES_WASM_OFFSET as usize + core::mem::size_of::<OnlineFeatures>(),
"ChainFeeTable overlaps OnlineFeatures"
);