Skip to main content

percli_program/
state.rs

1use anchor_lang::prelude::*;
2use percli_core::RiskEngine;
3
4/// Market account header — stored at the beginning of the account data.
5/// The RiskEngine state follows immediately after, accessed via raw pointer
6/// because RiskEngine is ~1.165 MB and doesn't derive Copy.
7#[derive(AnchorSerialize, AnchorDeserialize, Clone, Copy)]
8pub struct MarketHeader {
9    /// Authority that created this market (can update params).
10    pub authority: Pubkey,
11    /// Bump seed for the Market PDA.
12    pub bump: u8,
13    /// Padding for 8-byte alignment.
14    pub _padding: [u8; 7],
15}
16
17impl MarketHeader {
18    pub const SIZE: usize = 32 + 1 + 7; // 40 bytes
19}
20
21/// Total account size: discriminator + header + engine
22pub const MARKET_ACCOUNT_SIZE: usize = 8 + MarketHeader::SIZE + std::mem::size_of::<RiskEngine>();
23
24/// Helper to get a mutable reference to the RiskEngine from raw account data.
25///
26/// SAFETY: The caller must ensure the account data is at least
27/// `8 + MarketHeader::SIZE + size_of::<RiskEngine>()` bytes and properly
28/// initialized. The RiskEngine is #[repr(C)] with all-valid bit patterns.
29pub fn engine_from_account_data(data: &mut [u8]) -> &mut RiskEngine {
30    let offset = 8 + MarketHeader::SIZE;
31    let engine_bytes = &mut data[offset..offset + std::mem::size_of::<RiskEngine>()];
32    // SAFETY: RiskEngine is #[repr(C)], all fields have valid zero representations,
33    // and we ensure the slice is correctly sized and aligned.
34    unsafe { &mut *(engine_bytes.as_mut_ptr() as *mut RiskEngine) }
35}
36
37pub fn engine_from_account_data_ref(data: &[u8]) -> &RiskEngine {
38    let offset = 8 + MarketHeader::SIZE;
39    let engine_bytes = &data[offset..offset + std::mem::size_of::<RiskEngine>()];
40    unsafe { &*(engine_bytes.as_ptr() as *const RiskEngine) }
41}
42
43pub fn header_from_account_data(data: &[u8]) -> MarketHeader {
44    let header_bytes = &data[8..8 + MarketHeader::SIZE];
45    MarketHeader::try_from_slice(header_bytes).unwrap()
46}
47
48pub fn write_header(data: &mut [u8], header: &MarketHeader) {
49    let mut cursor = &mut data[8..8 + MarketHeader::SIZE];
50    header.serialize(&mut cursor).unwrap();
51}