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    /// SPL token mint for this market's collateral.
12    pub mint: Pubkey,
13    /// Pyth price feed account for this market's oracle.
14    pub oracle: Pubkey,
15    /// Matcher authority — the only signer allowed to submit trades.
16    pub matcher: Pubkey,
17    /// Bump seed for the Market PDA.
18    pub bump: u8,
19    /// Bump seed for the vault token account PDA.
20    pub vault_bump: u8,
21    /// Padding for 8-byte alignment.
22    pub _padding: [u8; 6],
23}
24
25impl MarketHeader {
26    pub const SIZE: usize = 32 + 32 + 32 + 32 + 1 + 1 + 6; // 136 bytes
27}
28
29/// Total account size: discriminator + header + engine
30pub const MARKET_ACCOUNT_SIZE: usize = 8 + MarketHeader::SIZE + std::mem::size_of::<RiskEngine>();
31
32/// Market PDA signer seeds: [b"market", authority_key, &[bump]]
33pub fn market_signer_seeds<'a>(
34    authority: &'a Pubkey,
35    bump: &'a [u8; 1],
36) -> [&'a [u8]; 3] {
37    [b"market", authority.as_ref(), bump.as_ref()]
38}
39
40/// Helper to get a mutable reference to the RiskEngine from raw account data.
41///
42/// SAFETY: The caller must ensure the account data is at least
43/// `8 + MarketHeader::SIZE + size_of::<RiskEngine>()` bytes and properly
44/// initialized. The RiskEngine is #[repr(C)] with all-valid bit patterns.
45pub fn engine_from_account_data(data: &mut [u8]) -> &mut RiskEngine {
46    let offset = 8 + MarketHeader::SIZE;
47    let engine_bytes = &mut data[offset..offset + std::mem::size_of::<RiskEngine>()];
48    unsafe { &mut *(engine_bytes.as_mut_ptr() as *mut RiskEngine) }
49}
50
51pub fn engine_from_account_data_ref(data: &[u8]) -> &RiskEngine {
52    let offset = 8 + MarketHeader::SIZE;
53    let engine_bytes = &data[offset..offset + std::mem::size_of::<RiskEngine>()];
54    unsafe { &*(engine_bytes.as_ptr() as *const RiskEngine) }
55}
56
57pub fn header_from_account_data(data: &[u8]) -> std::result::Result<MarketHeader, anchor_lang::error::Error> {
58    let header_bytes = &data[8..8 + MarketHeader::SIZE];
59    MarketHeader::try_from_slice(header_bytes)
60        .map_err(|_| anchor_lang::error!(crate::error::PercolatorError::CorruptState))
61}
62
63pub fn write_header(data: &mut [u8], header: &MarketHeader) {
64    let mut cursor = &mut data[8..8 + MarketHeader::SIZE];
65    header.serialize(&mut cursor).unwrap();
66}