phoenix_seat_manager/
lib.rs

1use ellipsis_macros::declare_id;
2use instruction::SeatManagerInstruction;
3use processor::{
4    process_change_market_status, process_claim_market_authority, process_claim_seat,
5    process_claim_seat_manager_authority, process_confirm_renounce_seat_manager_authority,
6    process_designated_market_maker, process_evict_seat, process_name_successor,
7};
8use solana_program::instruction::Instruction;
9use solana_program::msg;
10use solana_program::pubkey::Pubkey;
11
12use solana_program::{
13    account_info::AccountInfo, entrypoint::ProgramResult, program_error::ProgramError,
14};
15
16use crate::processor::{
17    process_change_market_fee_recipient, process_name_market_authority_successor,
18};
19pub mod instruction;
20pub mod instruction_builders;
21pub mod loaders;
22pub mod processor;
23pub mod seat_manager;
24pub mod shank_structs;
25
26#[cfg(not(feature = "no-entrypoint"))]
27use solana_security_txt::security_txt;
28
29#[cfg(not(feature = "no-entrypoint"))]
30security_txt! {
31    // Required fields
32    name: "Phoenix Seat Manager V1",
33    project_url: "https://ellipsislabs.xyz/",
34    contacts: "email:maintainers@ellipsislabs.xyz",
35    policy: "https://github.com/Ellipsis-Labs/phoenix-v1/blob/master/SECURITY.md",
36    // Optional Fields
37    preferred_languages: "en",
38    source_code: "https://github.com/Ellipsis-Labs/phoenix-seat-manager-v1",
39    auditors: "contact@osec.io"
40}
41
42const MAX_DMMS: u64 = 128;
43
44declare_id!("PSMxQbAoDWDbvd9ezQJgARyq6R9L5kJAasaLDVcZwf1");
45
46pub fn get_seat_manager_seeds(
47    market: &Pubkey,
48    seat_manager: &Pubkey,
49    program_id: &Pubkey,
50) -> Result<Vec<Vec<u8>>, ProgramError> {
51    let mut seeds = vec![market.to_bytes().to_vec()];
52    let (seat_manager_key, bump) = Pubkey::find_program_address(
53        seeds
54            .iter()
55            .map(|seed| seed.as_slice())
56            .collect::<Vec<&[u8]>>()
57            .as_slice(),
58        program_id,
59    );
60    seeds.push(vec![bump]);
61
62    if seat_manager_key == *seat_manager {
63        Ok(seeds)
64    } else {
65        let caller = std::panic::Location::caller();
66        msg!(
67            "Invalid seat manager key, expected: {} found {}.\n{}",
68            seat_manager_key,
69            seat_manager,
70            caller
71        );
72        return Err(ProgramError::InvalidInstructionData.into());
73    }
74}
75
76pub fn get_seat_manager_address(market: &Pubkey) -> (Pubkey, u8) {
77    Pubkey::find_program_address(&[&market.to_bytes()], &crate::id())
78}
79
80pub fn get_seat_deposit_collector_seeds(
81    market: &Pubkey,
82    seat_deposit_collector: &Pubkey,
83    program_id: &Pubkey,
84) -> Result<Vec<Vec<u8>>, ProgramError> {
85    let mut seeds = vec![market.to_bytes().to_vec(), b"deposit".to_vec()];
86    let (seat_deposit_collector_key, bump) = Pubkey::find_program_address(
87        seeds
88            .iter()
89            .map(|seed| seed.as_slice())
90            .collect::<Vec<&[u8]>>()
91            .as_slice(),
92        program_id,
93    );
94    seeds.push(vec![bump]);
95
96    if seat_deposit_collector_key == *seat_deposit_collector {
97        Ok(seeds)
98    } else {
99        let caller = std::panic::Location::caller();
100        msg!(
101            "Invalid seat deposit collector key, expected: {} found {}.\n{}",
102            seat_deposit_collector_key,
103            seat_deposit_collector,
104            caller
105        );
106        return Err(ProgramError::InvalidInstructionData.into());
107    }
108}
109
110pub fn get_seat_deposit_collector_address(market: &Pubkey) -> (Pubkey, u8) {
111    Pubkey::find_program_address(&[&market.to_bytes(), b"deposit"], &crate::id())
112}
113
114pub fn get_accounts_for_instruction<'a, 'info>(
115    instruction: &Instruction,
116    accounts: &'a [AccountInfo<'info>],
117) -> Result<Vec<AccountInfo<'info>>, ProgramError> {
118    let mut accounts_from_instruction = vec![];
119    // This is inefficient, but it also makes life a lot easier
120    for account_key in instruction
121        .accounts
122        .iter()
123        .map(|ai| ai.pubkey)
124        .chain([instruction.program_id])
125    {
126        if let Some(account) = accounts.iter().find(|&ai| *ai.key == account_key) {
127            accounts_from_instruction.push(account.clone());
128        } else {
129            msg!("Failed to find key {} for instruction", account_key);
130            return Err(ProgramError::InvalidArgument);
131        }
132    }
133    Ok(accounts_from_instruction)
134}
135
136#[cfg(not(feature = "no-entrypoint"))]
137solana_program::entrypoint!(process_instruction);
138
139pub fn process_instruction(
140    program_id: &Pubkey,
141    accounts: &[AccountInfo],
142    instruction_data: &[u8],
143) -> ProgramResult {
144    let (tag, data) = instruction_data
145        .split_first()
146        .ok_or(ProgramError::InvalidInstructionData)?;
147
148    let instruction =
149        SeatManagerInstruction::try_from(*tag).or(Err(ProgramError::InvalidInstructionData))?;
150
151    match instruction {
152        SeatManagerInstruction::ClaimMarketAuthority => {
153            msg!("SeatManagerInstruction::ClaimMarketAuthority");
154            process_claim_market_authority(program_id, accounts)
155        }
156        SeatManagerInstruction::ClaimSeatAuthorized => {
157            msg!("SeatManagerInstruction::ClaimSeatAuthorized");
158            process_claim_seat(program_id, accounts, true)
159        }
160        SeatManagerInstruction::ClaimSeat => {
161            msg!("SeatManagerInstruction::ClaimSeat");
162            process_claim_seat(program_id, accounts, false)
163        }
164        SeatManagerInstruction::EvictSeat => {
165            msg!("SeatManagerInstruction::EvictSeat");
166            process_evict_seat(program_id, accounts)
167        }
168        SeatManagerInstruction::AddDesignatedMarketMaker => {
169            msg!("SeatManagerInstruction::AddDesignatedMarketMaker");
170            process_designated_market_maker(program_id, accounts, false)
171        }
172        SeatManagerInstruction::RemoveDesignatedMarketMaker => {
173            msg!("SeatManagerInstruction::RemoveDesignatedMarketMaker");
174            process_designated_market_maker(program_id, accounts, true)
175        }
176        SeatManagerInstruction::NameSuccessor => {
177            msg!("SeatManagerInstruction::NameSuccessor");
178            process_name_successor(program_id, accounts)
179        }
180        SeatManagerInstruction::ClaimSeatManagerAuthority => {
181            msg!("SeatManagerInstruction::ClaimSeatManagerAuthority");
182            process_claim_seat_manager_authority(program_id, accounts)
183        }
184        SeatManagerInstruction::ChangeMarketStatus => {
185            msg!("SeatManagerInstruction::ChangeMarketStatus");
186            process_change_market_status(program_id, accounts, data)
187        }
188        SeatManagerInstruction::NameMarketAuthoritySuccessor => {
189            msg!("SeatManagerInstruction::NameMarketAuthoritySuccessor");
190            process_name_market_authority_successor(program_id, accounts, data)
191        }
192        SeatManagerInstruction::ChangeMarketFeeRecipient => {
193            msg!("SeatManagerInstruction::ChangeMarketFeeRecipient");
194            process_change_market_fee_recipient(program_id, accounts)
195        }
196        SeatManagerInstruction::ConfirmRenounceSeatManagerAuthority => {
197            msg!("SeatManagerInstruction::ConfirmRenounceSeatManagerAuthority");
198            process_confirm_renounce_seat_manager_authority(program_id, accounts)
199        }
200    }
201}