manifest/program/processor/
create_market.rs1use std::{cell::Ref, mem::size_of};
2
3use crate::{
4 logs::{emit_stack, CreateMarketLog},
5 program::{expand_market_if_needed, invoke},
6 require,
7 state::MarketFixed,
8 utils::create_account,
9 validation::{get_vault_address, loaders::CreateMarketContext},
10};
11use hypertree::{get_mut_helper, trace};
12use solana_program::{
13 account_info::AccountInfo, entrypoint::ProgramResult, program_pack::Pack, pubkey::Pubkey,
14 rent::Rent, sysvar::Sysvar,
15};
16use spl_token_2022::{
17 extension::{
18 mint_close_authority::MintCloseAuthority, permanent_delegate::PermanentDelegate,
19 BaseStateWithExtensions, ExtensionType, PodStateWithExtensions, StateWithExtensions,
20 },
21 pod::PodMint,
22 state::{Account, Mint},
23};
24
25pub(crate) fn process_create_market(
26 _program_id: &Pubkey,
27 accounts: &[AccountInfo],
28 _data: &[u8],
29) -> ProgramResult {
30 trace!("process_create_market accs={accounts:?}");
31 let create_market_context: CreateMarketContext = CreateMarketContext::load(accounts)?;
32
33 let CreateMarketContext {
34 market,
35 payer,
36 base_mint,
37 quote_mint,
38 base_vault,
39 quote_vault,
40 system_program,
41 token_program,
42 token_program_22,
43 } = create_market_context;
44
45 require!(
46 base_mint.info.key != quote_mint.info.key,
47 crate::program::ManifestError::InvalidMarketParameters,
48 "Base and quote must be different",
49 )?;
50
51 for mint in [base_mint.as_ref(), quote_mint.as_ref()] {
52 if *mint.owner == spl_token_2022::id() {
53 let mint_data: Ref<'_, &mut [u8]> = mint.data.borrow();
54 let pool_mint: StateWithExtensions<'_, Mint> =
55 StateWithExtensions::<Mint>::unpack(&mint_data)?;
56 if let Ok(extension) = pool_mint.get_extension::<MintCloseAuthority>() {
58 let close_authority: Option<Pubkey> = extension.close_authority.into();
59 if close_authority.is_some() {
60 solana_program::msg!(
61 "Warning, you are creating a market with a close authority."
62 );
63 }
64 }
65 if let Ok(extension) = pool_mint.get_extension::<PermanentDelegate>() {
69 let permanent_delegate: Option<Pubkey> = extension.delegate.into();
70 if permanent_delegate.is_some() {
71 solana_program::msg!(
72 "Warning, you are creating a market with a permanent delegate. There is no loss of funds protection for funds on this market"
73 );
74 }
75 }
76 }
77 }
78
79 {
80 let rent: Rent = Rent::get()?;
82 for (token_account, mint) in [
83 (base_vault.as_ref(), base_mint.as_ref()),
84 (quote_vault.as_ref(), quote_mint.as_ref()),
85 ] {
86 let is_mint_22: bool = *mint.owner == spl_token_2022::id();
88 let token_program_for_mint: Pubkey = if is_mint_22 {
89 spl_token_2022::id()
90 } else {
91 spl_token::id()
92 };
93
94 let (_vault_key, bump) = get_vault_address(market.key, mint.key);
95 let seeds: Vec<Vec<u8>> = vec![
96 b"vault".to_vec(),
97 market.key.as_ref().to_vec(),
98 mint.key.as_ref().to_vec(),
99 vec![bump],
100 ];
101
102 if is_mint_22 {
103 let mint_data: Ref<'_, &mut [u8]> = mint.data.borrow();
104 let mint_with_extension: PodStateWithExtensions<'_, PodMint> =
105 PodStateWithExtensions::<PodMint>::unpack(&mint_data).unwrap();
106 let mint_extensions: Vec<ExtensionType> =
107 mint_with_extension.get_extension_types()?;
108 let required_extensions: Vec<ExtensionType> =
109 ExtensionType::get_required_init_account_extensions(&mint_extensions);
110 let space: usize =
111 ExtensionType::try_calculate_account_len::<Account>(&required_extensions)?;
112 create_account(
113 payer.as_ref(),
114 token_account,
115 system_program.as_ref(),
116 &token_program_for_mint,
117 &rent,
118 space as u64,
119 seeds,
120 )?;
121 invoke(
122 &spl_token_2022::instruction::initialize_account3(
123 &token_program_for_mint,
124 token_account.key,
125 mint.key,
126 token_account.key,
127 )?,
128 &[
129 payer.as_ref().clone(),
130 token_account.clone(),
131 mint.clone(),
132 token_program_22.as_ref().clone(),
133 ],
134 )?;
135 } else {
136 let space: usize = spl_token::state::Account::LEN;
137 create_account(
138 payer.as_ref(),
139 token_account,
140 system_program.as_ref(),
141 &token_program_for_mint,
142 &rent,
143 space as u64,
144 seeds,
145 )?;
146 invoke(
147 &spl_token::instruction::initialize_account3(
148 &token_program_for_mint,
149 token_account.key,
150 mint.key,
151 token_account.key,
152 )?,
153 &[
154 payer.as_ref().clone(),
155 token_account.clone(),
156 mint.clone(),
157 token_program.as_ref().clone(),
158 ],
159 )?;
160 }
161 }
162
163 let empty_market_fixed: MarketFixed =
173 MarketFixed::new_empty(&base_mint, "e_mint, market.key);
174 assert_eq!(market.data_len(), size_of::<MarketFixed>());
175
176 let market_bytes: &mut [u8] = &mut market.try_borrow_mut_data()?[..];
177 *get_mut_helper::<MarketFixed>(market_bytes, 0_u32) = empty_market_fixed;
178
179 emit_stack(CreateMarketLog {
180 market: *market.key,
181 creator: *payer.key,
182 base_mint: *base_mint.info.key,
183 quote_mint: *quote_mint.info.key,
184 })?;
185 }
186
187 expand_market_if_needed(&payer, &market)?;
189
190 Ok(())
191}