phoenix-rise 0.1.2

SDK for interacting with Phoenix
Documentation
use solana_pubkey::Pubkey;

use super::discriminants::ACCOUNT_DISCRIMINANTS;
use super::internal::{
    CONDITIONAL_ORDER_BITS_LEN, Reader, SequenceNumber, ShortEntries, TraderPosition,
    TraderPositionEntry, TraderState, none_if_zero, occupied_conditional_order_indices,
    read_sequence_number, read_trader_position, read_trader_state, verify_discriminant,
};
use super::{AccountDeserialize, AccountDeserializeError};

const ACCOUNT: &str = "Trader";
const POSITION_ENTRY_BYTES: usize = 40;

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Trader {
    pub sequence_number: SequenceNumber,
    pub key: Pubkey,
    pub authority: Pubkey,
    pub state: TraderState,
    pub withdraw_queue_node: Option<u32>,
    pub max_positions: u64,
    pub position_authority: Pubkey,
    pub num_markets_with_splines: u16,
    pub trader_pda_index: u8,
    pub trader_subaccount_index: u8,
    pub funding_key: Pubkey,
    pub last_deposit_slot: u64,
    pub conditional_order_bits: Vec<u8>,
    pub occupied_conditional_order_indices: Vec<u8>,
    pub positions: ShortEntries<u64, TraderPosition>,
}

impl AccountDeserialize for Trader {
    fn try_from_account_bytes(data: &[u8]) -> Result<Self, AccountDeserializeError> {
        verify_discriminant(ACCOUNT, data, ACCOUNT_DISCRIMINANTS.trader)?;
        let mut reader = Reader::with_offset(ACCOUNT, data, 8);
        let sequence_number = read_sequence_number(&mut reader)?;
        let key = reader.read_pubkey()?;
        let authority = reader.read_pubkey()?;
        let state = read_trader_state(&mut reader)?;
        reader.skip(4)?;
        let withdraw_queue_node = none_if_zero(reader.read_u32()?);
        let max_positions = reader.read_u64()?;
        let position_authority = reader.read_pubkey()?;
        let num_markets_with_splines = reader.read_u16()?;
        let trader_pda_index = reader.read_u8()?;
        let trader_subaccount_index = reader.read_u8()?;
        let funding_key = reader.read_pubkey()?;
        reader.skip(4)?;
        let last_deposit_slot = reader.read_u64()?;
        let conditional_order_bits = reader.read_bytes(CONDITIONAL_ORDER_BITS_LEN)?.to_vec();
        let occupied_conditional_order_indices =
            occupied_conditional_order_indices(&conditional_order_bits);
        let positions = read_positions(&mut reader)?;
        Ok(Self {
            sequence_number,
            key,
            authority,
            state,
            withdraw_queue_node,
            max_positions,
            position_authority,
            num_markets_with_splines,
            trader_pda_index,
            trader_subaccount_index,
            funding_key,
            last_deposit_slot,
            conditional_order_bits,
            occupied_conditional_order_indices,
            positions,
        })
    }
}

impl Trader {
    pub fn try_from_account_bytes(data: &[u8]) -> Result<Self, AccountDeserializeError> {
        <Self as AccountDeserialize>::try_from_account_bytes(data)
    }

    pub fn position_entries(&self) -> impl Iterator<Item = TraderPositionEntry> + '_ {
        self.positions
            .entries
            .iter()
            .map(|(asset_id, position)| TraderPositionEntry {
                asset_id: *asset_id,
                position: *position,
            })
    }
}

fn read_positions(
    reader: &mut Reader<'_>,
) -> Result<ShortEntries<u64, TraderPosition>, AccountDeserializeError> {
    let len = reader.read_u64()?;
    let capacity = reader.read_u64()?;
    let bytes_needed = (len as usize)
        .checked_mul(POSITION_ENTRY_BYTES)
        .ok_or_else(|| {
            AccountDeserializeError::invalid_data(ACCOUNT, "position map length overflow")
        })?;
    if bytes_needed > reader.remaining() {
        return Err(AccountDeserializeError::too_short(
            ACCOUNT,
            reader.offset() + bytes_needed,
            reader.offset() + reader.remaining(),
        ));
    }
    let mut entries = Vec::with_capacity(len as usize);
    for _ in 0..len {
        let key = reader.read_u64()?;
        let value = read_trader_position(reader)?;
        entries.push((key, value));
    }
    Ok(ShortEntries {
        len,
        capacity,
        entries,
    })
}