Skip to main content

percli_chain/
read.rs

1use anyhow::{bail, Result};
2use percli_core::RiskEngine;
3
4/// Discriminator expected at bytes 0..8 of the market account.
5const MARKET_DISCRIMINATOR: &[u8; 8] = b"percmrkt";
6
7/// MarketHeader size (authority: 32 + mint: 32 + oracle: 32 + matcher: 32 + bump: 1 + vault_bump: 1 + padding: 6 = 136).
8const HEADER_SIZE: usize = 136;
9
10/// Offset where RiskEngine data begins in the account.
11const ENGINE_OFFSET: usize = 8 + HEADER_SIZE;
12
13/// Minimum account data size for a valid market.
14pub fn min_account_size() -> usize {
15    ENGINE_OFFSET + std::mem::size_of::<RiskEngine>()
16}
17
18/// Read the authority pubkey from raw market account data.
19pub fn read_authority(data: &[u8]) -> Result<[u8; 32]> {
20    if data.len() < ENGINE_OFFSET {
21        bail!("Account data too small for market header");
22    }
23    // Validate discriminator
24    if &data[..8] != MARKET_DISCRIMINATOR {
25        bail!(
26            "Invalid market discriminator: expected {:?}, got {:?}",
27            MARKET_DISCRIMINATOR,
28            &data[..8]
29        );
30    }
31    let mut authority = [0u8; 32];
32    authority.copy_from_slice(&data[8..40]);
33    Ok(authority)
34}
35
36/// Get a reference to the RiskEngine from raw market account data.
37///
38/// # Safety
39/// The data must be at least `min_account_size()` bytes and the engine
40/// region must be properly aligned. RiskEngine is `#[repr(C)]` with
41/// all-valid bit patterns.
42pub fn engine_from_data(data: &[u8]) -> Result<&RiskEngine> {
43    if data.len() < min_account_size() {
44        bail!(
45            "Account data too small: {} < {}",
46            data.len(),
47            min_account_size()
48        );
49    }
50    if &data[..8] != MARKET_DISCRIMINATOR {
51        bail!("Invalid market discriminator");
52    }
53    let engine_bytes = &data[ENGINE_OFFSET..ENGINE_OFFSET + std::mem::size_of::<RiskEngine>()];
54    // SAFETY: RiskEngine is #[repr(C)] with all-valid bit patterns (all fields are
55    // integers or arrays of integers). The slice is correctly sized.
56    Ok(unsafe { &*(engine_bytes.as_ptr() as *const RiskEngine) })
57}