manifest/program/processor/
global_create.rs

1use std::{cell::Ref, mem::size_of};
2
3use crate::{
4    logs::{emit_stack, GlobalCreateLog},
5    program::invoke,
6    state::GlobalFixed,
7    utils::create_account,
8    validation::{get_global_address, get_global_vault_address, loaders::GlobalCreateContext},
9};
10use hypertree::{get_mut_helper, trace};
11use solana_program::{
12    account_info::AccountInfo, entrypoint::ProgramResult, program_pack::Pack, pubkey::Pubkey,
13    rent::Rent, sysvar::Sysvar,
14};
15use spl_token_2022::{
16    extension::{BaseStateWithExtensions, ExtensionType, PodStateWithExtensions},
17    pod::PodMint,
18    state::Account,
19};
20
21pub(crate) fn process_global_create(
22    _program_id: &Pubkey,
23    accounts: &[AccountInfo],
24    _data: &[u8],
25) -> ProgramResult {
26    {
27        trace!("process_global_create accs={accounts:?}");
28        let global_create_context: GlobalCreateContext = GlobalCreateContext::load(accounts)?;
29
30        let GlobalCreateContext {
31            payer,
32            global,
33            system_program,
34            global_mint,
35            global_vault,
36            token_program,
37        } = global_create_context;
38
39        // Make the global account.
40        {
41            let (_global_key, global_bump) = get_global_address(global_mint.info.key);
42            let global_seeds: Vec<Vec<u8>> = vec![
43                b"global".to_vec(),
44                global_mint.info.key.as_ref().to_vec(),
45                vec![global_bump],
46            ];
47            create_account(
48                payer.as_ref(),
49                global.as_ref(),
50                system_program.as_ref(),
51                &crate::id(),
52                &Rent::get()?,
53                size_of::<GlobalFixed>() as u64,
54                global_seeds,
55            )?;
56
57            // Setup the empty market
58            let empty_global_fixed: GlobalFixed = GlobalFixed::new_empty(&global_mint.as_ref().key);
59            assert_eq!(global.info.data_len(), size_of::<GlobalFixed>());
60
61            let global_bytes: &mut [u8] = &mut global.info.try_borrow_mut_data()?[..];
62            *get_mut_helper::<GlobalFixed>(global_bytes, 0_u32) = empty_global_fixed;
63
64            // Global does not require a permanent free block for swapping.
65        }
66
67        // Make the global vault.
68        {
69            // We dont have to deserialize the mint, just check the owner.
70            let is_mint_22: bool = *global_mint.info.owner == spl_token_2022::id();
71            let token_program_for_mint: Pubkey = if is_mint_22 {
72                spl_token_2022::id()
73            } else {
74                spl_token::id()
75            };
76
77            let (_global_vault_key, global_vault_bump) =
78                get_global_vault_address(global_mint.info.key);
79            let global_vault_seeds: Vec<Vec<u8>> = vec![
80                b"global-vault".to_vec(),
81                global_mint.info.key.as_ref().to_vec(),
82                vec![global_vault_bump],
83            ];
84            let rent: Rent = Rent::get()?;
85
86            if is_mint_22 {
87                let mint_data: Ref<'_, &mut [u8]> = global_mint.info.data.borrow();
88                let mint_with_extension: PodStateWithExtensions<'_, PodMint> =
89                    PodStateWithExtensions::<PodMint>::unpack(&mint_data).unwrap();
90                let mint_extensions: Vec<ExtensionType> =
91                    mint_with_extension.get_extension_types()?;
92                let required_extensions: Vec<ExtensionType> =
93                    ExtensionType::get_required_init_account_extensions(&mint_extensions);
94                let space: usize =
95                    ExtensionType::try_calculate_account_len::<Account>(&required_extensions)?;
96                create_account(
97                    payer.as_ref(),
98                    global_vault.info,
99                    system_program.as_ref(),
100                    &token_program_for_mint,
101                    &rent,
102                    space as u64,
103                    global_vault_seeds,
104                )?;
105                invoke(
106                    &spl_token_2022::instruction::initialize_account3(
107                        &spl_token_2022::id(),
108                        global_vault.as_ref().key,
109                        global_mint.info.key,
110                        global_vault.as_ref().key,
111                    )?,
112                    &[
113                        payer.as_ref().clone(),
114                        global_vault.as_ref().clone(),
115                        global_mint.as_ref().clone(),
116                        token_program.as_ref().clone(),
117                    ],
118                )?;
119            } else {
120                let space: usize = spl_token::state::Account::LEN;
121                create_account(
122                    payer.as_ref(),
123                    global_vault.info,
124                    system_program.as_ref(),
125                    &token_program_for_mint,
126                    &rent,
127                    space as u64,
128                    global_vault_seeds,
129                )?;
130                invoke(
131                    &spl_token::instruction::initialize_account3(
132                        &spl_token::id(),
133                        global_vault.as_ref().key,
134                        global_mint.info.key,
135                        global_vault.as_ref().key,
136                    )?,
137                    &[
138                        payer.as_ref().clone(),
139                        global_vault.as_ref().clone(),
140                        global_mint.as_ref().clone(),
141                        token_program.as_ref().clone(),
142                    ],
143                )?;
144            }
145        }
146
147        emit_stack(GlobalCreateLog {
148            global: *global.info.key,
149            creator: *payer.key,
150        })?;
151    }
152
153    Ok(())
154}