manifest/program/processor/
global_create.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
use std::{cell::Ref, mem::size_of};

use crate::{
    logs::{emit_stack, GlobalCreateLog},
    program::invoke,
    state::GlobalFixed,
    utils::create_account,
    validation::{get_global_address, get_global_vault_address, loaders::GlobalCreateContext},
};
use hypertree::{get_mut_helper, trace};
use solana_program::{
    account_info::AccountInfo, entrypoint::ProgramResult, program_pack::Pack, pubkey::Pubkey,
    rent::Rent, sysvar::Sysvar,
};
use spl_token_2022::{
    extension::{BaseStateWithExtensions, ExtensionType, PodStateWithExtensions},
    pod::PodMint,
    state::Account,
};

pub(crate) fn process_global_create(
    _program_id: &Pubkey,
    accounts: &[AccountInfo],
    _data: &[u8],
) -> ProgramResult {
    {
        trace!("process_global_create accs={accounts:?}");
        let global_create_context: GlobalCreateContext = GlobalCreateContext::load(accounts)?;

        let GlobalCreateContext {
            payer,
            global,
            system_program,
            global_mint,
            global_vault,
            token_program,
        } = global_create_context;

        // Make the global account.
        {
            let (_global_key, global_bump) = get_global_address(global_mint.info.key);
            let global_seeds: Vec<Vec<u8>> = vec![
                b"global".to_vec(),
                global_mint.info.key.as_ref().to_vec(),
                vec![global_bump],
            ];
            create_account(
                payer.as_ref(),
                global.as_ref(),
                system_program.as_ref(),
                &crate::id(),
                &Rent::get()?,
                size_of::<GlobalFixed>() as u64,
                global_seeds,
            )?;

            // Setup the empty market
            let empty_global_fixed: GlobalFixed = GlobalFixed::new_empty(&global_mint.as_ref().key);
            assert_eq!(global.info.data_len(), size_of::<GlobalFixed>());

            let global_bytes: &mut [u8] = &mut global.info.try_borrow_mut_data()?[..];
            *get_mut_helper::<GlobalFixed>(global_bytes, 0_u32) = empty_global_fixed;

            // Global does not require a permanent free block for swapping.
        }

        // Make the global vault.
        {
            // We dont have to deserialize the mint, just check the owner.
            let is_mint_22: bool = *global_mint.info.owner == spl_token_2022::id();
            let token_program_for_mint: Pubkey = if is_mint_22 {
                spl_token_2022::id()
            } else {
                spl_token::id()
            };

            let (_global_vault_key, global_vault_bump) =
                get_global_vault_address(global_mint.info.key);
            let global_vault_seeds: Vec<Vec<u8>> = vec![
                b"global-vault".to_vec(),
                global_mint.info.key.as_ref().to_vec(),
                vec![global_vault_bump],
            ];
            let rent: Rent = Rent::get()?;

            if is_mint_22 {
                let mint_data: Ref<'_, &mut [u8]> = global_mint.info.data.borrow();
                let mint_with_extension: PodStateWithExtensions<'_, PodMint> =
                    PodStateWithExtensions::<PodMint>::unpack(&mint_data).unwrap();
                let mint_extensions: Vec<ExtensionType> =
                    mint_with_extension.get_extension_types()?;
                let required_extensions: Vec<ExtensionType> =
                    ExtensionType::get_required_init_account_extensions(&mint_extensions);
                let space: usize =
                    ExtensionType::try_calculate_account_len::<Account>(&required_extensions)?;
                create_account(
                    payer.as_ref(),
                    global_vault.info,
                    system_program.as_ref(),
                    &token_program_for_mint,
                    &rent,
                    space as u64,
                    global_vault_seeds,
                )?;
                invoke(
                    &spl_token_2022::instruction::initialize_account3(
                        &spl_token_2022::id(),
                        global_vault.as_ref().key,
                        global_mint.info.key,
                        global_vault.as_ref().key,
                    )?,
                    &[
                        payer.as_ref().clone(),
                        global_vault.as_ref().clone(),
                        global_mint.as_ref().clone(),
                        token_program.as_ref().clone(),
                    ],
                )?;
            } else {
                let space: usize = spl_token::state::Account::LEN;
                create_account(
                    payer.as_ref(),
                    global_vault.info,
                    system_program.as_ref(),
                    &token_program_for_mint,
                    &rent,
                    space as u64,
                    global_vault_seeds,
                )?;
                invoke(
                    &spl_token::instruction::initialize_account3(
                        &spl_token::id(),
                        global_vault.as_ref().key,
                        global_mint.info.key,
                        global_vault.as_ref().key,
                    )?,
                    &[
                        payer.as_ref().clone(),
                        global_vault.as_ref().clone(),
                        global_mint.as_ref().clone(),
                        token_program.as_ref().clone(),
                    ],
                )?;
            }
        }

        emit_stack(GlobalCreateLog {
            global: *global.info.key,
            creator: *payer.key,
        })?;
    }

    Ok(())
}