manifest/program/processor/
deposit.rs1use std::cell::RefMut;
2
3use crate::{
4 logs::{emit_stack, DepositLog},
5 state::MarketRefMut,
6 validation::{
7 loaders::DepositContext, MintAccountInfo, Signer, TokenAccountInfo, TokenProgram,
8 },
9};
10use borsh::{BorshDeserialize, BorshSerialize};
11use hypertree::DataIndex;
12use solana_program::{account_info::AccountInfo, entrypoint::ProgramResult, pubkey::Pubkey};
13
14use super::{get_trader_index_with_hint, shared::get_mut_dynamic_account};
15
16#[cfg(feature = "certora")]
17use early_panic::early_panic;
18#[cfg(feature = "certora")]
19use solana_cvt::token::{spl_token_2022_transfer, spl_token_transfer};
20
21#[derive(BorshDeserialize, BorshSerialize)]
22pub struct DepositParams {
23 pub amount_atoms: u64,
24 pub trader_index_hint: Option<DataIndex>,
25}
26
27impl DepositParams {
28 pub fn new(amount_atoms: u64, trader_index_hint: Option<DataIndex>) -> Self {
29 DepositParams {
30 amount_atoms,
31 trader_index_hint,
32 }
33 }
34}
35
36pub(crate) fn process_deposit(
37 program_id: &Pubkey,
38 accounts: &[AccountInfo],
39 data: &[u8],
40) -> ProgramResult {
41 let params: DepositParams = DepositParams::try_from_slice(data)?;
42 process_deposit_core(program_id, accounts, params)
43}
44
45#[cfg_attr(all(feature = "certora", not(feature = "certora-test")), early_panic)]
46pub(crate) fn process_deposit_core(
47 _program_id: &Pubkey,
48 accounts: &[AccountInfo],
49 params: DepositParams,
50) -> ProgramResult {
51 let deposit_context: DepositContext = DepositContext::load(accounts)?;
52 let DepositParams {
53 amount_atoms,
54 trader_index_hint,
55 } = params;
56 let mut deposited_amount_atoms: u64 = amount_atoms;
58
59 let DepositContext {
60 market,
61 payer,
62 trader_token,
63 vault,
64 token_program,
65 mint,
66 } = deposit_context;
67
68 let market_data: &mut RefMut<&mut [u8]> = &mut market.try_borrow_mut_data()?;
69 let mut dynamic_account: MarketRefMut = get_mut_dynamic_account(market_data);
70
71 let is_base: bool =
73 &trader_token.try_borrow_data()?[0..32] == dynamic_account.get_base_mint().as_ref();
74
75 if *vault.owner == spl_token_2022::id() {
76 let before_vault_balance_atoms: u64 = vault.get_balance_atoms();
77 spl_token_2022_transfer_from_trader_to_vault(
78 &token_program,
79 &trader_token,
80 Some(mint),
81 if is_base {
82 dynamic_account.fixed.get_base_mint()
83 } else {
84 dynamic_account.get_quote_mint()
85 },
86 &vault,
87 &payer,
88 amount_atoms,
89 if is_base {
90 dynamic_account.fixed.get_base_mint_decimals()
91 } else {
92 dynamic_account.fixed.get_quote_mint_decimals()
93 },
94 )?;
95
96 let after_vault_balance_atoms: u64 = vault.get_balance_atoms();
97 deposited_amount_atoms = after_vault_balance_atoms
98 .checked_sub(before_vault_balance_atoms)
99 .unwrap();
100 } else {
101 spl_token_transfer_from_trader_to_vault(
102 &token_program,
103 &trader_token,
104 &vault,
105 &payer,
106 amount_atoms,
107 )?;
108 }
109
110 let trader_index: DataIndex =
111 get_trader_index_with_hint(trader_index_hint, &dynamic_account, &payer)?;
112 dynamic_account.deposit(trader_index, deposited_amount_atoms, is_base)?;
113
114 emit_stack(DepositLog {
115 market: *market.key,
116 trader: *payer.key,
117 mint: if is_base {
118 *dynamic_account.get_base_mint()
119 } else {
120 *dynamic_account.get_quote_mint()
121 },
122 amount_atoms: deposited_amount_atoms,
123 })?;
124
125 Ok(())
126}
127
128#[cfg(not(feature = "certora"))]
130fn spl_token_transfer_from_trader_to_vault<'a, 'info>(
131 token_program: &TokenProgram<'a, 'info>,
132 trader_account: &TokenAccountInfo<'a, 'info>,
133 vault: &TokenAccountInfo<'a, 'info>,
134 payer: &Signer<'a, 'info>,
135 amount: u64,
136) -> ProgramResult {
137 crate::program::invoke(
138 &spl_token::instruction::transfer(
139 token_program.key,
140 trader_account.key,
141 vault.key,
142 payer.key,
143 &[],
144 amount,
145 )?,
146 &[
147 token_program.as_ref().clone(),
148 trader_account.as_ref().clone(),
149 vault.as_ref().clone(),
150 payer.as_ref().clone(),
151 ],
152 )
153}
154#[cfg(feature = "certora")]
155fn spl_token_transfer_from_trader_to_vault<'a, 'info>(
157 _token_program: &TokenProgram<'a, 'info>,
158 trader_account: &TokenAccountInfo<'a, 'info>,
159 vault: &TokenAccountInfo<'a, 'info>,
160 payer: &Signer<'a, 'info>,
161 amount: u64,
162) -> ProgramResult {
163 spl_token_transfer(trader_account.info, vault.info, payer.info, amount)
164}
165
166#[cfg(not(feature = "certora"))]
168fn spl_token_2022_transfer_from_trader_to_vault<'a, 'info>(
169 token_program: &TokenProgram<'a, 'info>,
170 trader_account: &TokenAccountInfo<'a, 'info>,
171 mint: Option<MintAccountInfo<'a, 'info>>,
172 mint_pubkey: &Pubkey,
173 vault: &TokenAccountInfo<'a, 'info>,
174 payer: &Signer<'a, 'info>,
175 amount: u64,
176 decimals: u8,
177) -> ProgramResult {
178 crate::program::invoke(
179 &spl_token_2022::instruction::transfer_checked(
180 token_program.key,
181 trader_account.key,
182 mint_pubkey,
183 vault.key,
184 payer.key,
185 &[],
186 amount,
187 decimals,
188 )?,
189 &[
190 token_program.as_ref().clone(),
191 trader_account.as_ref().clone(),
192 vault.as_ref().clone(),
193 mint.unwrap().as_ref().clone(),
194 payer.as_ref().clone(),
195 ],
196 )
197}
198
199#[cfg(feature = "certora")]
200fn spl_token_2022_transfer_from_trader_to_vault<'a, 'info>(
202 _token_program: &TokenProgram<'a, 'info>,
203 trader_account: &TokenAccountInfo<'a, 'info>,
204 _mint: Option<MintAccountInfo<'a, 'info>>,
205 _mint_pubkey: &Pubkey,
206 vault: &TokenAccountInfo<'a, 'info>,
207 payer: &Signer<'a, 'info>,
208 amount: u64,
209 _decimals: u8,
210) -> ProgramResult {
211 spl_token_2022_transfer(trader_account.info, vault.info, payer.info, amount)
212}