1use std::{
2 fmt::Display,
3 ops::{Div, Rem},
4};
5
6use solana_program::{
7 account_info::AccountInfo,
8 entrypoint::ProgramResult,
9 program::{invoke, invoke_signed},
10 pubkey::Pubkey,
11};
12
13use crate::quantities::{BaseAtoms, QuoteAtoms, WrapperU64};
14
15use super::{checkers::TokenAccountInfo, TokenParams};
16
17#[allow(clippy::too_many_arguments)]
18pub(crate) fn try_withdraw<'a, 'info>(
19 market_key: &Pubkey,
20 base_params: &TokenParams,
21 quote_params: &TokenParams,
22 token_program: &AccountInfo<'info>,
23 quote_account: &AccountInfo<'info>,
24 quote_vault: TokenAccountInfo<'a, 'info>,
25 base_account: &AccountInfo<'info>,
26 base_vault: TokenAccountInfo<'a, 'info>,
27 quote_atoms_to_withdraw: QuoteAtoms,
28 base_atoms_to_withdraw: BaseAtoms,
29) -> ProgramResult {
30 for (withdraw_vault, withdraw_account, withdraw_amount, params) in [
31 (
32 quote_vault,
33 quote_account,
34 quote_atoms_to_withdraw.as_u64(),
35 quote_params,
36 ),
37 (
38 base_vault,
39 base_account,
40 base_atoms_to_withdraw.as_u64(),
41 base_params,
42 ),
43 ] {
44 maybe_invoke_withdraw(
45 market_key,
46 ¶ms.mint_key,
47 params.vault_bump as u8,
48 withdraw_amount,
49 token_program,
50 withdraw_account,
51 &withdraw_vault,
52 )?;
53 }
54 Ok(())
55}
56
57pub(crate) fn maybe_invoke_withdraw<'a, 'info>(
58 market_key: &Pubkey,
59 mint_key: &Pubkey,
60 bump: u8,
61 withdraw_amount: u64,
62 token_program: &AccountInfo<'info>,
63 withdraw_account: &AccountInfo<'info>,
64 withdraw_vault: &'a TokenAccountInfo<'a, 'info>,
65) -> ProgramResult {
66 if withdraw_amount != 0 {
67 invoke_signed(
68 &spl_token::instruction::transfer(
69 token_program.key,
70 withdraw_vault.key,
71 withdraw_account.key,
72 withdraw_vault.key,
73 &[],
74 withdraw_amount,
75 )?,
76 &[
77 token_program.clone(),
78 withdraw_vault.as_ref().clone(),
79 withdraw_account.clone(),
80 ],
81 &[&[b"vault", market_key.as_ref(), mint_key.as_ref(), &[bump]]],
82 )?;
83 }
84 Ok(())
85}
86
87pub(crate) fn maybe_invoke_deposit<'a, 'info>(
88 deposit_amount: u64,
89 token_program: &AccountInfo<'info>,
90 deposit_account: &'a TokenAccountInfo<'a, 'info>,
91 deposit_vault: &'a TokenAccountInfo<'a, 'info>,
92 trader: &AccountInfo<'info>,
93) -> ProgramResult {
94 if deposit_amount > 0 {
95 invoke(
96 &spl_token::instruction::transfer(
97 token_program.key,
98 deposit_account.key,
99 deposit_vault.key,
100 trader.key,
101 &[],
102 deposit_amount,
103 )?,
104 &[
105 token_program.as_ref().clone(),
106 deposit_account.as_ref().clone(),
107 deposit_vault.as_ref().clone(),
108 trader.as_ref().clone(),
109 ],
110 )?;
111 }
112 Ok(())
113}
114
115#[allow(clippy::too_many_arguments)]
116pub(crate) fn try_deposit<'a, 'info>(
117 token_program: &AccountInfo<'info>,
118 quote_account: TokenAccountInfo<'a, 'info>,
119 quote_vault: TokenAccountInfo<'a, 'info>,
120 base_account: TokenAccountInfo<'a, 'info>,
121 base_vault: TokenAccountInfo<'a, 'info>,
122 quote_amount: QuoteAtoms,
123 base_amount: BaseAtoms,
124 trader: &AccountInfo<'info>,
125) -> ProgramResult {
126 for (deposit_vault, deposit_account, deposit_amount) in [
127 (quote_vault, quote_account, quote_amount.as_u64()),
128 (base_vault, base_account, base_amount.as_u64()),
129 ] {
130 maybe_invoke_deposit(
131 deposit_amount,
132 token_program,
133 &deposit_account,
134 &deposit_vault,
135 trader,
136 )?;
137 }
138 Ok(())
139}
140
141pub fn get_decimal_string<N: Display + Div + Rem + Copy + TryFrom<u64>>(
142 amount: N,
143 decimals: u32,
144) -> String
145where
146 <N as Rem>::Output: std::fmt::Display,
147 <N as Div>::Output: std::fmt::Display,
148 <N as TryFrom<u64>>::Error: std::fmt::Debug,
149{
150 let scale = N::try_from(10_u64.pow(decimals)).unwrap();
151 let lhs = amount / scale;
152 let rhs = format!("{:0width$}", (amount % scale), width = decimals as usize).replace('-', ""); format!("{}.{}", lhs, rhs.trim_end_matches('0'))
154}