phoenix/program/processor/
manage_seat.rs

1use crate::program::{
2    dispatch_market::load_with_dispatch_mut, error::assert_with_msg, loaders::get_seat_address,
3    status::SeatApprovalStatus, system_utils::create_account, AuthorizedSeatRequestContext,
4    MarketHeader, ModifySeatContext, PhoenixMarketContext, RequestSeatContext, Seat,
5};
6use borsh::BorshDeserialize;
7use sokoban::node_allocator::ZeroCopy;
8use solana_program::{
9    account_info::AccountInfo, entrypoint::ProgramResult, program_error::ProgramError,
10    pubkey::Pubkey, rent::Rent, sysvar::Sysvar,
11};
12use std::mem::size_of;
13
14/// This instruction is used to request a seat on the market by the market authority for a trader
15pub(crate) fn process_request_seat_authorized<'a, 'info>(
16    _program_id: &Pubkey,
17    market_context: &PhoenixMarketContext<'a, 'info>,
18    accounts: &'a [AccountInfo<'info>],
19    _data: &[u8],
20) -> ProgramResult {
21    let AuthorizedSeatRequestContext {
22        payer,
23        trader,
24        seat,
25        system_program,
26    } = AuthorizedSeatRequestContext::load(market_context, accounts)?;
27    _create_seat(
28        payer.as_ref(),
29        trader.key,
30        seat.as_ref(),
31        market_context.market_info.key,
32        system_program.as_ref(),
33    )
34}
35
36/// This instruction is used to request a seat on the market for a trader (by the trader)
37pub(crate) fn process_request_seat<'a, 'info>(
38    _program_id: &Pubkey,
39    market_context: &PhoenixMarketContext<'a, 'info>,
40    accounts: &'a [AccountInfo<'info>],
41    _data: &[u8],
42) -> ProgramResult {
43    let RequestSeatContext {
44        seat,
45        system_program,
46        ..
47    } = RequestSeatContext::load(market_context, accounts)?;
48    let PhoenixMarketContext {
49        market_info,
50        signer: trader,
51    } = market_context;
52    _create_seat(
53        trader.as_ref(),
54        trader.key,
55        seat.as_ref(),
56        market_info.key,
57        system_program.as_ref(),
58    )
59}
60
61fn _create_seat<'a, 'info>(
62    payer: &'a AccountInfo<'info>,
63    trader: &'a Pubkey,
64    seat: &'a AccountInfo<'info>,
65    market_key: &Pubkey,
66    system_program: &'a AccountInfo<'info>,
67) -> ProgramResult {
68    let (seat_address, bump) = get_seat_address(market_key, trader);
69    assert_with_msg(
70        &seat_address == seat.key,
71        ProgramError::InvalidAccountData,
72        "Invalid seat address",
73    )?;
74    let space = size_of::<Seat>();
75    let seeds = vec![
76        b"seat".to_vec(),
77        market_key.as_ref().to_vec(),
78        trader.as_ref().to_vec(),
79        vec![bump],
80    ];
81    create_account(
82        payer,
83        seat,
84        system_program,
85        &crate::id(),
86        &Rent::get()?,
87        space as u64,
88        seeds,
89    )?;
90    let mut seat_bytes = seat.try_borrow_mut_data()?;
91    *Seat::load_mut_bytes(&mut seat_bytes).ok_or(ProgramError::InvalidAccountData)? =
92        Seat::new_init(*market_key, *trader)?;
93    Ok(())
94}
95
96/// This instruction is used to modify a seat on the market
97/// The seat can be modified only by the market authority
98pub(crate) fn process_change_seat_status<'a, 'info>(
99    _program_id: &Pubkey,
100    market_context: &PhoenixMarketContext<'a, 'info>,
101    accounts: &'a [AccountInfo<'info>],
102    data: &[u8],
103) -> ProgramResult {
104    let ModifySeatContext { seat: seat_info } = ModifySeatContext::load(market_context, accounts)?;
105    let PhoenixMarketContext {
106        market_info,
107        signer: _,
108    } = market_context;
109    let new_status = SeatApprovalStatus::try_from_slice(data)?;
110    let mut seat = seat_info.load_mut()?;
111    let current_status = SeatApprovalStatus::from(seat.approval_status);
112    if current_status == new_status {
113        phoenix_log!("Seat status is unchanged");
114        return Ok(());
115    }
116    match (current_status, new_status) {
117        (SeatApprovalStatus::NotApproved, SeatApprovalStatus::Approved) => {
118            seat.approval_status = SeatApprovalStatus::Approved as u64;
119            // Initialize a seat for the approved trader
120            let market_bytes = &mut market_info.try_borrow_mut_data()?[size_of::<MarketHeader>()..];
121            let market = load_with_dispatch_mut(&market_info.size_params, market_bytes)?.inner;
122            assert_with_msg(
123                market.get_or_register_trader(&seat.trader).is_some(),
124                ProgramError::InvalidArgument,
125                "Failed to register trader",
126            )?;
127        }
128        (SeatApprovalStatus::Approved, SeatApprovalStatus::NotApproved) => {
129            seat.approval_status = SeatApprovalStatus::NotApproved as u64;
130        }
131        (SeatApprovalStatus::Approved, SeatApprovalStatus::Retired) => {
132            seat.approval_status = SeatApprovalStatus::Retired as u64;
133        }
134        (SeatApprovalStatus::NotApproved, SeatApprovalStatus::Retired) => {
135            seat.approval_status = SeatApprovalStatus::Retired as u64;
136        }
137        _ => {
138            phoenix_log!(
139                "Invalid seat status transition from {} to {}",
140                current_status,
141                new_status
142            );
143            return Err(ProgramError::InvalidInstructionData);
144        }
145    }
146    Ok(())
147}