diff --git a/src/instruction_builders.rs b/src/instruction_builders.rs index 89a79a2..2227ee7 100644 --- a/src/instruction_builders.rs +++ b/src/instruction_builders.rs @@ -11,7 +11,7 @@ use solana_program::{ use spl_associated_token_account::get_associated_token_address; use crate::{ - get_seat_deposit_collector_address, get_seat_manager_address, + get_authorized_delegate_pda, get_seat_deposit_collector_address, get_seat_manager_address, instruction::SeatManagerInstruction, }; @@ -319,3 +319,99 @@ pub fn create_confirm_renounce_seat_manager_authority_instruction( data: SeatManagerInstruction::ConfirmRenounceSeatManagerAuthority.to_vec(), } } + +pub fn create_add_approved_evictor_instruction( + authority: &Pubkey, + authorized_delegate: &Pubkey, +) -> Instruction { + let (authorized_delegate_pda, _) = get_authorized_delegate_pda(authority, authorized_delegate); + Instruction { + program_id: crate::id(), + accounts: vec![ + AccountMeta::new(*authority, true), + AccountMeta::new_readonly(*authorized_delegate, false), + AccountMeta::new(authorized_delegate_pda, false), + ], + data: SeatManagerInstruction::AddApprovedEvictor.to_vec(), + } +} + +pub fn create_remove_approved_evictor_instruction( + authority: &Pubkey, + authorized_delegate: &Pubkey, +) -> Instruction { + let (authorized_delegate_pda, _) = get_authorized_delegate_pda(authority, authorized_delegate); + Instruction { + program_id: crate::id(), + accounts: vec![ + AccountMeta::new(*authority, true), + AccountMeta::new_readonly(*authorized_delegate, false), + AccountMeta::new(authorized_delegate_pda, false), + ], + data: SeatManagerInstruction::RemoveApprovedEvictor.to_vec(), + } +} + +pub fn create_evict_seat_with_authorized_delegate_instruction( + market: &Pubkey, + base_mint: &Pubkey, + quote_mint: &Pubkey, + authorized_delegate: &Pubkey, + traders: Vec, + seat_manager_authority: &Pubkey, +) -> Instruction { + let (base_vault, _) = get_vault_address(market, base_mint); + let (quote_vault, _) = get_vault_address(market, quote_mint); + let (seat_manager, _) = get_seat_manager_address(market); + let (seat_deposit_collector, _) = get_seat_deposit_collector_address(market); + + let (authorized_delegate_pda, _) = + get_authorized_delegate_pda(seat_manager_authority, authorized_delegate); + + let mut accounts = vec![ + AccountMeta::new_readonly(phoenix::id(), false), + AccountMeta::new_readonly(phoenix_log_authority::id(), false), + AccountMeta::new(*market, false), + AccountMeta::new_readonly(seat_manager, false), + AccountMeta::new(seat_deposit_collector, false), + AccountMeta::new_readonly(*base_mint, false), + AccountMeta::new_readonly(*quote_mint, false), + AccountMeta::new(base_vault, false), + AccountMeta::new(quote_vault, false), + AccountMeta::new_readonly(spl_associated_token_account::id(), false), + AccountMeta::new_readonly(spl_token::id(), false), + AccountMeta::new_readonly(system_program::id(), false), + AccountMeta::new_readonly(*authorized_delegate, true), + AccountMeta::new_readonly(authorized_delegate_pda, false), + ]; + + for trader_accounts in traders.iter() { + let base_account = get_associated_token_address(&trader_accounts.trader_pubkey, base_mint); + let quote_account = + get_associated_token_address(&trader_accounts.trader_pubkey, quote_mint); + let (seat, _) = get_seat_address(market, &trader_accounts.trader_pubkey); + accounts.push(AccountMeta::new(trader_accounts.trader_pubkey, false)); + accounts.push(AccountMeta::new(seat, false)); + accounts.push(AccountMeta::new(base_account, false)); + accounts.push(AccountMeta::new(quote_account, false)); + + for backup_account in [ + trader_accounts.base_token_account_backup, + trader_accounts.quote_token_account_backup, + ] + .iter() + { + if backup_account.is_some() { + accounts.push(AccountMeta::new(backup_account.unwrap(), false)); + } else { + accounts.push(AccountMeta::new_readonly(Pubkey::default(), false)); + } + } + } + + Instruction { + program_id: crate::id(), + accounts, + data: SeatManagerInstruction::EvictSeatWithAuthorizedDelegate.to_vec(), + } +} diff --git a/src/lib.rs b/src/lib.rs index b34ecd6..4ef2b2f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -78,6 +78,19 @@ pub fn get_seat_manager_address(market: &Pubkey) -> (Pubkey, u8) { Pubkey::find_program_address(&[&market.to_bytes()], &crate::id()) } +pub fn get_authorized_delegate_pda( + seat_manager_authority: &Pubkey, + authorized_delegate: &Pubkey, +) -> (Pubkey, u8) { + Pubkey::find_program_address( + &[ + &seat_manager_authority.to_bytes(), + &authorized_delegate.to_bytes(), + ], + &crate::id(), + ) +} + pub fn get_seat_deposit_collector_seeds( market: &Pubkey, seat_deposit_collector: &Pubkey, diff --git a/src/processor/authorized_evictor.rs b/src/processor/authorized_evictor.rs index 6f9f6e5..fd69258 100644 --- a/src/processor/authorized_evictor.rs +++ b/src/processor/authorized_evictor.rs @@ -1,5 +1,5 @@ use phoenix::program::{ - checkers::{Program, Signer, PDA}, + checkers::{Program, Signer}, system_utils::create_account, }; use solana_program::{ @@ -37,7 +37,7 @@ pub fn process_authorized_evictor( authorized_delegate_pda_seeds.clone(), )?; } else { - // TODO + close_account(authorized_delegate_pda, seat_manager_authority.as_ref())?; } Ok(()) @@ -76,3 +76,22 @@ pub fn get_authorized_delegate_seeds_and_validate( return Err(ProgramError::InvalidInstructionData.into()); } } + +pub fn close_account<'info>( + info: &AccountInfo<'info>, + sol_destination: &AccountInfo<'info>, +) -> Result<(), ProgramError> { + let dest_starting_lamports = sol_destination.lamports(); + + **sol_destination.lamports.borrow_mut() = + dest_starting_lamports.checked_add(info.lamports()).unwrap(); + + **info.lamports.borrow_mut() = 0; + + info.assign(&system_program::ID); + info.realloc(0, false).map_err(Into::into) +} + +pub fn does_pda_exist(program_id: &Pubkey, pda_ai: &AccountInfo) -> bool { + pda_ai.owner == program_id && pda_ai.lamports() != 0 +} diff --git a/src/processor/evict_seat.rs b/src/processor/evict_seat.rs index b6ff7ca..c73616f 100644 --- a/src/processor/evict_seat.rs +++ b/src/processor/evict_seat.rs @@ -23,7 +23,7 @@ use solana_program::{ }; use spl_associated_token_account::instruction::create_associated_token_account; -use super::get_authorized_delegate_seeds_and_validate; +use super::{does_pda_exist, get_authorized_delegate_seeds_and_validate}; struct TraderAccountsContext<'a, 'info> { trader: &'a AccountInfo<'info>, @@ -118,7 +118,7 @@ pub fn process_evict_seat( )?; // If the PDA exists, then the signer is an authorized delegate - is_authorized_delegate = authorized_delegate_pda.lamports() > 0; + is_authorized_delegate = does_pda_exist(program_id, authorized_delegate_pda); } // Get market parameters to perform checks