phoenix/program/processor/
fees.rs1use std::mem::size_of;
2
3use crate::{
4 program::{
5 assert_with_msg, load_with_dispatch_mut,
6 token_utils::{get_decimal_string, maybe_invoke_withdraw},
7 ChangeFeeRecipientContext, CollectFeesContext, MarketHeader, PhoenixMarketContext,
8 },
9 quantities::{QuoteLots, WrapperU64},
10 state::markets::MarketEvent,
11};
12use solana_program::{
13 account_info::AccountInfo, entrypoint::ProgramResult, program_error::ProgramError,
14 pubkey::Pubkey,
15};
16
17pub(crate) fn process_collect_fees<'a, 'info>(
18 _program_id: &Pubkey,
19 market_context: &PhoenixMarketContext<'a, 'info>,
20 accounts: &'a [AccountInfo<'info>],
21 _data: &[u8],
22 record_event_fn: &mut dyn FnMut(MarketEvent<Pubkey>),
23) -> ProgramResult {
24 let CollectFeesContext {
25 fee_recipient_token_account,
26 quote_vault,
27 token_program,
28 } = CollectFeesContext::load(market_context, accounts)?;
29
30 let PhoenixMarketContext {
31 market_info,
32 signer: _,
33 } = market_context;
34
35 let num_quote_lots_out = {
36 let market_bytes = &mut market_info.try_borrow_mut_data()?[size_of::<MarketHeader>()..];
37 let market = load_with_dispatch_mut(&market_info.size_params, market_bytes)?.inner;
38 market.collect_fees(record_event_fn)
39 };
40
41 let header = market_info.get_header()?;
42 let quote_atoms_collected = num_quote_lots_out * header.get_quote_lot_size();
43 phoenix_log!(
44 "Collected {} in fees",
45 get_decimal_string(quote_atoms_collected.as_u64(), header.quote_params.decimals)
46 );
47
48 maybe_invoke_withdraw(
49 market_info.key,
50 &header.quote_params.mint_key,
51 header.quote_params.vault_bump as u8,
52 quote_atoms_collected.as_u64(),
53 token_program.as_ref(),
54 fee_recipient_token_account.as_ref(),
55 "e_vault,
56 )?;
57 Ok(())
58}
59
60pub(crate) fn process_change_fee_recipient<'a, 'info>(
61 _program_id: &Pubkey,
62 market_context: &PhoenixMarketContext<'a, 'info>,
63 accounts: &'a [AccountInfo<'info>],
64 _data: &[u8],
65) -> ProgramResult {
66 let ChangeFeeRecipientContext {
67 new_fee_recipient,
68 previous_fee_recipient,
69 } = ChangeFeeRecipientContext::load(market_context, accounts)?;
70 let PhoenixMarketContext { market_info, .. } = market_context;
71
72 let uncollected_fees = {
73 let market_bytes = &mut market_info.try_borrow_mut_data()?[size_of::<MarketHeader>()..];
74 load_with_dispatch_mut(&market_info.size_params, market_bytes)?
75 .inner
76 .get_uncollected_fee_amount()
77 };
78
79 let mut header = market_info.get_header_mut()?;
80 if uncollected_fees > QuoteLots::ZERO {
81 assert_with_msg(
82 previous_fee_recipient.is_some(),
83 ProgramError::MissingRequiredSignature,
84 "Previous fee recipient must sign if there are uncollected fees",
85 )?;
86 }
87 header.fee_recipient = *new_fee_recipient.key;
88 Ok(())
89}