use crate::L2Book;
pub const MAX_POOLS: usize = 32;
pub const POOL_BOOKS_WASM_OFFSET: u32 = 0x14000;
#[derive(Clone, Copy)]
#[repr(C)]
pub struct PoolMeta {
pub address: [u8; 32],
pub pair_index: u16,
pub fee_bps: u16,
pub venue_id: u8,
pub protocol_id: u8,
pub gas_cost_1e5: u16,
pub gas_units_1k: u16,
pub gas_price_gwei: u16,
pub native_price_deci_usd: u16,
pub _pad: [u8; 2],
}
impl Default for PoolMeta {
fn default() -> Self {
Self {
address: [0; 32],
pair_index: 0,
fee_bps: 0,
venue_id: 0,
protocol_id: 0,
gas_cost_1e5: 0,
gas_units_1k: 0,
gas_price_gwei: 0,
native_price_deci_usd: 0,
_pad: [0; 2],
}
}
}
impl PoolMeta {
#[inline(always)]
pub fn gas_cost_usd(&self) -> f64 {
self.gas_cost_1e5 as f64 / 100_000.0
}
#[inline(always)]
pub fn gas_units(&self) -> u64 {
self.gas_units_1k as u64 * 1000
}
#[inline(always)]
pub fn native_price_usd(&self) -> f64 {
self.native_price_deci_usd as f64 / 10.0
}
#[inline]
pub fn compute_gas_cost_usd(&self) -> f64 {
self.gas_units() as f64 * self.gas_price_gwei as f64 * self.native_price_usd() / 1e9
}
#[inline]
pub fn total_cost_bps(&self, notional_1e9: u64) -> f64 {
let fee = self.fee_bps as f64;
let gas_bps = if notional_1e9 > 0 {
(self.gas_cost_usd() * 10_000.0 * 1_000_000_000.0) / notional_1e9 as f64
} else {
0.0
};
fee + gas_bps
}
}
#[derive(Clone)]
#[repr(C)]
pub struct PoolBooks {
pub pool_ct: u8,
pub _pad: [u8; 7],
pub metas: [PoolMeta; MAX_POOLS],
pub books: [L2Book; MAX_POOLS],
}
impl Default for PoolBooks {
fn default() -> Self {
Self {
pool_ct: 0,
_pad: [0; 7],
metas: [PoolMeta::default(); MAX_POOLS],
books: [L2Book::default(); MAX_POOLS],
}
}
}
impl PoolBooks {
#[inline]
pub fn book_for_pool(&self, addr: &[u8; 32], pair_index: u16) -> Option<&L2Book> {
let ct = self.pool_ct as usize;
for i in 0..ct {
if self.metas[i].address == *addr && self.metas[i].pair_index == pair_index {
return Some(&self.books[i]);
}
}
None
}
#[inline(always)]
pub fn book_at_slot(&self, slot: usize) -> &L2Book {
if slot < self.pool_ct as usize {
&self.books[slot]
} else {
&self.books[0]
}
}
#[inline(always)]
pub fn meta_at_slot(&self, slot: usize) -> &PoolMeta {
if slot < self.pool_ct as usize {
&self.metas[slot]
} else {
&self.metas[0]
}
}
}
pub const POOL_STATE_TABLE_WASM_OFFSET: u32 = 0x23000;
pub const MAX_POOL_STATES: usize = 32;
pub mod pool_type {
pub const V2: u8 = 0;
pub const V3_CLMM: u8 = 1;
pub const STABLESWAP: u8 = 2;
}
#[derive(Clone, Copy, Debug)]
#[repr(C)]
pub struct PoolAmm {
pub reserve0_lo: u64,
pub reserve0_hi: u64,
pub reserve1_lo: u64,
pub reserve1_hi: u64,
pub sqrt_price_x64: u128, pub liquidity: u128,
pub tick: i32,
pub tick_spacing: i32,
pub fee_ppm: u32,
pub pool_type: u8,
pub _pad0: [u8; 3],
pub last_block: u64,
pub last_update_ns: u64,
}
impl Default for PoolAmm {
fn default() -> Self {
unsafe { core::mem::zeroed() }
}
}
impl PoolAmm {
#[inline(always)]
pub fn reserve0(&self) -> u128 {
(self.reserve0_hi as u128) << 64 | self.reserve0_lo as u128
}
#[inline(always)]
pub fn reserve1(&self) -> u128 {
(self.reserve1_hi as u128) << 64 | self.reserve1_lo as u128
}
#[inline(always)]
pub fn is_v2(&self) -> bool {
self.pool_type == pool_type::V2
}
#[inline(always)]
pub fn is_v3(&self) -> bool {
self.pool_type == pool_type::V3_CLMM
}
#[inline(always)]
pub fn is_valid(&self) -> bool {
self.last_block > 0
}
#[inline(always)]
pub fn fee_bps(&self) -> u32 {
self.fee_ppm / 100
}
}
#[derive(Clone, Copy)]
#[repr(C)]
pub struct PoolStateTable {
pub count: u8,
pub _pad: [u8; 15],
pub states: [PoolAmm; MAX_POOL_STATES],
}
impl Default for PoolStateTable {
fn default() -> Self {
Self {
count: 0,
_pad: [0; 15],
states: [PoolAmm::default(); MAX_POOL_STATES],
}
}
}
impl PoolStateTable {
#[inline(always)]
pub fn state_at(&self, slot: usize) -> &PoolAmm {
if slot < self.count as usize {
&self.states[slot]
} else {
&self.states[0]
}
}
}
const _: () = assert!(
POOL_BOOKS_WASM_OFFSET as usize >= crate::VENUE_BOOKS_WASM_OFFSET as usize,
"POOL_BOOKS_WASM_OFFSET must not overlap VenueBooks"
);
const _: () = assert!(
core::mem::size_of::<PoolAmm>() == 96,
"PoolAmm must be exactly 96 bytes"
);
const _: () = assert!(
core::mem::size_of::<PoolStateTable>() == 3088,
"PoolStateTable must be exactly 3088 bytes (16 + 32*96)"
);
const _: () = assert!(
POOL_STATE_TABLE_WASM_OFFSET as usize + core::mem::size_of::<PoolStateTable>() < 0x1000000,
"PoolStateTable exceeds WASM 16MB memory limit"
);