manifest/program/processor/
global_evict.rs1use std::cell::RefMut;
2
3use borsh::{BorshDeserialize, BorshSerialize};
4use solana_program::{account_info::AccountInfo, entrypoint::ProgramResult, pubkey::Pubkey};
5
6use crate::{
7 global_vault_seeds_with_bump,
8 logs::{emit_stack, GlobalDepositLog, GlobalEvictLog, GlobalWithdrawLog},
9 program::get_mut_dynamic_account,
10 quantities::{GlobalAtoms, WrapperU64},
11 require,
12 state::GlobalRefMut,
13 validation::{get_global_vault_address, loaders::GlobalEvictContext},
14};
15use solana_program::program::invoke_signed;
16
17use super::invoke;
18
19#[derive(BorshDeserialize, BorshSerialize)]
20pub struct GlobalEvictParams {
21 amount_atoms: u64,
23}
24
25impl GlobalEvictParams {
26 pub fn new(amount_atoms: u64) -> Self {
27 GlobalEvictParams { amount_atoms }
28 }
29}
30
31pub(crate) fn process_global_evict(
32 _program_id: &Pubkey,
33 accounts: &[AccountInfo],
34 data: &[u8],
35) -> ProgramResult {
36 let global_evict_context: GlobalEvictContext = GlobalEvictContext::load(accounts)?;
37 let GlobalEvictParams { amount_atoms } = GlobalEvictParams::try_from_slice(data)?;
38
39 let GlobalEvictContext {
40 payer,
41 global,
42 mint,
43 global_vault,
44 trader_token,
45 evictee_token,
46 token_program,
47 } = global_evict_context;
48
49 let global_data: &mut RefMut<&mut [u8]> = &mut global.try_borrow_mut_data()?;
53 let mut global_dynamic_account: GlobalRefMut = get_mut_dynamic_account(global_data);
54 let evictee_balance: GlobalAtoms =
55 global_dynamic_account.get_balance_atoms(&evictee_token.get_owner());
56
57 {
58 require!(
60 evictee_balance < GlobalAtoms::new(amount_atoms),
61 crate::program::ManifestError::InvalidEvict,
62 "Evictee balance {} is more than evictor wants to deposit",
63 evictee_balance.as_u64(),
64 )?;
65 global_dynamic_account.verify_min_balance(&evictee_token.get_owner())?;
66 }
67
68 {
70 let evictee_balance: GlobalAtoms =
71 global_dynamic_account.get_balance_atoms(&evictee_token.get_owner());
72 global_dynamic_account.withdraw_global(&evictee_token.get_owner(), evictee_balance)?;
73
74 let (_, bump) = get_global_vault_address(mint.info.key);
75
76 if *global_vault.owner == spl_token_2022::id() {
78 invoke_signed(
79 &spl_token_2022::instruction::transfer_checked(
80 token_program.key,
81 global_vault.key,
82 mint.info.key,
83 evictee_token.key,
84 global_vault.key,
85 &[],
86 evictee_balance.into(),
87 mint.mint.decimals,
88 )?,
89 &[
90 token_program.as_ref().clone(),
91 evictee_token.as_ref().clone(),
92 mint.as_ref().clone(),
93 global_vault.as_ref().clone(),
94 ],
95 global_vault_seeds_with_bump!(mint.info.key, bump),
96 )?;
97 } else {
98 invoke_signed(
99 &spl_token::instruction::transfer(
100 token_program.key,
101 global_vault.key,
102 evictee_token.key,
103 global_vault.key,
104 &[],
105 evictee_balance.into(),
106 )?,
107 &[
108 token_program.as_ref().clone(),
109 global_vault.as_ref().clone(),
110 evictee_token.as_ref().clone(),
111 ],
112 global_vault_seeds_with_bump!(mint.info.key, bump),
113 )?;
114 }
115
116 emit_stack(GlobalWithdrawLog {
117 global: *global.key,
118 trader: *payer.key,
119 global_atoms: GlobalAtoms::new(amount_atoms),
120 })?;
121 }
122
123 {
125 global_dynamic_account
126 .evict_and_take_seat(&evictee_token.get_owner(), &trader_token.get_owner())?;
127
128 emit_stack(GlobalEvictLog {
129 evictee: evictee_token.get_owner(),
130 evictor: trader_token.get_owner(),
131 evictor_atoms: GlobalAtoms::new(amount_atoms),
132 evictee_atoms: evictee_balance,
133 })?;
134 }
135
136 {
138 global_dynamic_account.deposit_global(payer.key, GlobalAtoms::new(amount_atoms))?;
139
140 if *global_vault.owner == spl_token_2022::id() {
142 invoke(
143 &spl_token_2022::instruction::transfer_checked(
144 token_program.key,
145 trader_token.key,
146 mint.info.key,
147 global_vault.key,
148 payer.key,
149 &[],
150 amount_atoms,
151 mint.mint.decimals,
152 )?,
153 &[
154 token_program.as_ref().clone(),
155 trader_token.as_ref().clone(),
156 mint.as_ref().clone(),
157 global_vault.as_ref().clone(),
158 payer.as_ref().clone(),
159 ],
160 )?;
161 } else {
162 invoke(
163 &spl_token::instruction::transfer(
164 token_program.key,
165 trader_token.key,
166 global_vault.key,
167 payer.key,
168 &[],
169 amount_atoms,
170 )?,
171 &[
172 token_program.as_ref().clone(),
173 trader_token.as_ref().clone(),
174 global_vault.as_ref().clone(),
175 payer.as_ref().clone(),
176 ],
177 )?;
178 }
179
180 emit_stack(GlobalDepositLog {
181 global: *global.key,
182 trader: *payer.key,
183 global_atoms: GlobalAtoms::new(amount_atoms),
184 })?;
185 }
186
187 Ok(())
188}