manifest/validation/
loaders.rs

1use std::{cell::Ref, slice::Iter};
2
3use hypertree::{get_helper, trace};
4use solana_program::{
5    account_info::{next_account_info, AccountInfo},
6    program_error::ProgramError,
7    pubkey::Pubkey,
8    system_program,
9};
10
11use crate::{
12    program::ManifestError,
13    require,
14    state::{GlobalFixed, MarketFixed},
15    validation::{EmptyAccount, MintAccountInfo, Program, Signer, TokenAccountInfo},
16};
17
18use super::{get_vault_address, ManifestAccountInfo, TokenProgram};
19
20#[cfg(feature = "certora")]
21use early_panic::early_panic;
22
23/// CreateMarket account infos
24pub(crate) struct CreateMarketContext<'a, 'info> {
25    pub payer: Signer<'a, 'info>,
26    pub market: ManifestAccountInfo<'a, 'info, MarketFixed>,
27    pub base_mint: MintAccountInfo<'a, 'info>,
28    pub quote_mint: MintAccountInfo<'a, 'info>,
29    pub base_vault: EmptyAccount<'a, 'info>,
30    pub quote_vault: EmptyAccount<'a, 'info>,
31    pub system_program: Program<'a, 'info>,
32    pub token_program: TokenProgram<'a, 'info>,
33    pub token_program_22: TokenProgram<'a, 'info>,
34}
35
36impl<'a, 'info> CreateMarketContext<'a, 'info> {
37    pub fn load(accounts: &'a [AccountInfo<'info>]) -> Result<Self, ProgramError> {
38        let account_iter: &mut Iter<AccountInfo<'info>> = &mut accounts.iter();
39
40        let payer: Signer = Signer::new_payer(next_account_info(account_iter)?)?;
41        let market: ManifestAccountInfo<MarketFixed> =
42            ManifestAccountInfo::<MarketFixed>::new_init(next_account_info(account_iter)?)?;
43        let system_program: Program =
44            Program::new(next_account_info(account_iter)?, &system_program::id())?;
45        let base_mint: MintAccountInfo = MintAccountInfo::new(next_account_info(account_iter)?)?;
46        let quote_mint: MintAccountInfo = MintAccountInfo::new(next_account_info(account_iter)?)?;
47        let base_vault: EmptyAccount = EmptyAccount::new(next_account_info(account_iter)?)?;
48        let quote_vault: EmptyAccount = EmptyAccount::new(next_account_info(account_iter)?)?;
49
50        let (expected_base_vault, _base_vault_bump) =
51            get_vault_address(market.key, base_mint.info.key);
52        let (expected_quote_vault, _quote_vault_bump) =
53            get_vault_address(market.key, quote_mint.info.key);
54
55        require!(
56            expected_base_vault == *base_vault.info.key,
57            ManifestError::IncorrectAccount,
58            "Incorrect base vault account",
59        )?;
60        require!(
61            expected_quote_vault == *quote_vault.info.key,
62            ManifestError::IncorrectAccount,
63            "Incorrect quote vault account",
64        )?;
65        let token_program: TokenProgram = TokenProgram::new(next_account_info(account_iter)?)?;
66        let token_program_22: TokenProgram = TokenProgram::new(next_account_info(account_iter)?)?;
67
68        Ok(Self {
69            payer,
70            market,
71            base_vault,
72            quote_vault,
73            base_mint,
74            quote_mint,
75            token_program,
76            token_program_22,
77            system_program,
78        })
79    }
80}
81
82/// ClaimSeat account infos
83pub(crate) struct ClaimSeatContext<'a, 'info> {
84    pub payer: Signer<'a, 'info>,
85    pub market: ManifestAccountInfo<'a, 'info, MarketFixed>,
86    pub _system_program: Program<'a, 'info>,
87}
88
89impl<'a, 'info> ClaimSeatContext<'a, 'info> {
90    #[cfg_attr(all(feature = "certora", not(feature = "certora-test")), early_panic)]
91    pub fn load(accounts: &'a [AccountInfo<'info>]) -> Result<Self, ProgramError> {
92        let account_iter: &mut Iter<AccountInfo<'info>> = &mut accounts.iter();
93
94        let payer: Signer = Signer::new(next_account_info(account_iter)?)?;
95        let market: ManifestAccountInfo<MarketFixed> =
96            ManifestAccountInfo::<MarketFixed>::new(next_account_info(account_iter)?)?;
97        let _system_program: Program =
98            Program::new(next_account_info(account_iter)?, &system_program::id())?;
99        Ok(Self {
100            payer,
101            market,
102            _system_program,
103        })
104    }
105}
106
107/// ExpandMarketContext account infos
108pub(crate) struct ExpandMarketContext<'a, 'info> {
109    pub payer: Signer<'a, 'info>,
110    pub market: ManifestAccountInfo<'a, 'info, MarketFixed>,
111    pub _system_program: Program<'a, 'info>,
112}
113
114impl<'a, 'info> ExpandMarketContext<'a, 'info> {
115    pub fn load(accounts: &'a [AccountInfo<'info>]) -> Result<Self, ProgramError> {
116        let account_iter: &mut Iter<AccountInfo<'info>> = &mut accounts.iter();
117
118        let payer: Signer = Signer::new_payer(next_account_info(account_iter)?)?;
119        let market: ManifestAccountInfo<MarketFixed> =
120            ManifestAccountInfo::<MarketFixed>::new(next_account_info(account_iter)?)?;
121        let _system_program: Program =
122            Program::new(next_account_info(account_iter)?, &system_program::id())?;
123        Ok(Self {
124            payer,
125            market,
126            _system_program,
127        })
128    }
129}
130
131/// Deposit into a market account infos
132pub(crate) struct DepositContext<'a, 'info> {
133    pub payer: Signer<'a, 'info>,
134    pub market: ManifestAccountInfo<'a, 'info, MarketFixed>,
135    pub trader_token: TokenAccountInfo<'a, 'info>,
136    pub vault: TokenAccountInfo<'a, 'info>,
137    pub token_program: TokenProgram<'a, 'info>,
138    pub mint: MintAccountInfo<'a, 'info>,
139}
140
141impl<'a, 'info> DepositContext<'a, 'info> {
142    #[cfg_attr(all(feature = "certora", not(feature = "certora-test")), early_panic)]
143    pub fn load(accounts: &'a [AccountInfo<'info>]) -> Result<Self, ProgramError> {
144        let account_iter: &mut Iter<AccountInfo<'info>> = &mut accounts.iter();
145
146        let payer: Signer = Signer::new(next_account_info(account_iter)?)?;
147        let market: ManifestAccountInfo<MarketFixed> =
148            ManifestAccountInfo::<MarketFixed>::new(next_account_info(account_iter)?)?;
149
150        let market_fixed: Ref<MarketFixed> = market.get_fixed()?;
151        let base_mint: &Pubkey = market_fixed.get_base_mint();
152        let quote_mint: &Pubkey = market_fixed.get_quote_mint();
153
154        let token_account_info: &AccountInfo<'info> = next_account_info(account_iter)?;
155
156        // Infer the mint key from the token account.
157        let (mint, expected_vault_address) =
158            if &token_account_info.try_borrow_data()?[0..32] == base_mint.as_ref() {
159                (base_mint, market_fixed.get_base_vault())
160            } else if &token_account_info.try_borrow_data()?[0..32] == quote_mint.as_ref() {
161                (quote_mint, market_fixed.get_quote_vault())
162            } else {
163                return Err(ManifestError::InvalidWithdrawAccounts.into());
164            };
165
166        trace!("trader token account {:?}", token_account_info.key);
167        let trader_token: TokenAccountInfo =
168            TokenAccountInfo::new_with_owner(token_account_info, mint, payer.key)?;
169
170        trace!("vault token account {:?}", expected_vault_address);
171        let vault: TokenAccountInfo = TokenAccountInfo::new_with_owner_and_key(
172            next_account_info(account_iter)?,
173            mint,
174            &expected_vault_address,
175            &expected_vault_address,
176        )?;
177
178        let token_program: TokenProgram = TokenProgram::new(next_account_info(account_iter)?)?;
179        let mint: MintAccountInfo = MintAccountInfo::new(next_account_info(account_iter)?)?;
180
181        // Drop the market ref so it can be passed through the return.
182        drop(market_fixed);
183        Ok(Self {
184            payer,
185            market,
186            trader_token,
187            vault,
188            token_program,
189            mint,
190        })
191    }
192}
193
194/// Withdraw account infos
195pub(crate) struct WithdrawContext<'a, 'info> {
196    pub payer: Signer<'a, 'info>,
197    pub market: ManifestAccountInfo<'a, 'info, MarketFixed>,
198    pub trader_token: TokenAccountInfo<'a, 'info>,
199    pub vault: TokenAccountInfo<'a, 'info>,
200    pub token_program: TokenProgram<'a, 'info>,
201    pub mint: MintAccountInfo<'a, 'info>,
202}
203
204impl<'a, 'info> WithdrawContext<'a, 'info> {
205    pub fn load(accounts: &'a [AccountInfo<'info>]) -> Result<Self, ProgramError> {
206        let account_iter: &mut Iter<AccountInfo<'info>> = &mut accounts.iter();
207
208        let payer: Signer = Signer::new(next_account_info(account_iter)?)?;
209        let market: ManifestAccountInfo<MarketFixed> =
210            ManifestAccountInfo::<MarketFixed>::new(next_account_info(account_iter)?)?;
211
212        let market_fixed: Ref<MarketFixed> = market.get_fixed()?;
213        let base_mint: &Pubkey = market_fixed.get_base_mint();
214        let quote_mint: &Pubkey = market_fixed.get_quote_mint();
215
216        let token_account_info: &AccountInfo<'info> = next_account_info(account_iter)?;
217
218        let (mint, expected_vault_address) =
219            if &token_account_info.try_borrow_data()?[0..32] == base_mint.as_ref() {
220                (base_mint, market_fixed.get_base_vault())
221            } else if &token_account_info.try_borrow_data()?[0..32] == quote_mint.as_ref() {
222                (quote_mint, market_fixed.get_quote_vault())
223            } else {
224                return Err(ManifestError::InvalidWithdrawAccounts.into());
225            };
226
227        let trader_token: TokenAccountInfo =
228            TokenAccountInfo::new_with_owner(token_account_info, mint, payer.key)?;
229        let vault: TokenAccountInfo = TokenAccountInfo::new_with_owner_and_key(
230            next_account_info(account_iter)?,
231            mint,
232            &expected_vault_address,
233            &expected_vault_address,
234        )?;
235
236        let token_program: TokenProgram = TokenProgram::new(next_account_info(account_iter)?)?;
237        let mint: MintAccountInfo = MintAccountInfo::new(next_account_info(account_iter)?)?;
238
239        // Drop the market ref so it can be passed through the return.
240        drop(market_fixed);
241        Ok(Self {
242            payer,
243            market,
244            trader_token,
245            vault,
246            token_program,
247            mint,
248        })
249    }
250}
251
252/// Swap account infos
253pub(crate) struct SwapContext<'a, 'info> {
254    pub payer: Signer<'a, 'info>,
255    pub market: ManifestAccountInfo<'a, 'info, MarketFixed>,
256    pub trader_base: TokenAccountInfo<'a, 'info>,
257    pub trader_quote: TokenAccountInfo<'a, 'info>,
258    pub base_vault: TokenAccountInfo<'a, 'info>,
259    pub quote_vault: TokenAccountInfo<'a, 'info>,
260    pub token_program_base: TokenProgram<'a, 'info>,
261    pub token_program_quote: TokenProgram<'a, 'info>,
262    pub base_mint: Option<MintAccountInfo<'a, 'info>>,
263    pub quote_mint: Option<MintAccountInfo<'a, 'info>>,
264
265    // One for each side. First is base, then is quote.
266    pub global_trade_accounts_opts: [Option<GlobalTradeAccounts<'a, 'info>>; 2],
267}
268
269impl<'a, 'info> SwapContext<'a, 'info> {
270    #[cfg_attr(all(feature = "certora", not(feature = "certora-test")), early_panic)]
271    pub fn load(accounts: &'a [AccountInfo<'info>]) -> Result<Self, ProgramError> {
272        let account_iter: &mut Iter<AccountInfo<'info>> = &mut accounts.iter();
273
274        let payer: Signer = Signer::new(next_account_info(account_iter)?)?;
275        let market: ManifestAccountInfo<MarketFixed> =
276            ManifestAccountInfo::<MarketFixed>::new(next_account_info(account_iter)?)?;
277        // Included in case we need to expand for a reverse order.
278        let _system_program: Program =
279            Program::new(next_account_info(account_iter)?, &system_program::id())?;
280
281        let market_fixed: Ref<MarketFixed> = market.get_fixed()?;
282        let base_mint_key: Pubkey = *market_fixed.get_base_mint();
283        let quote_mint_key: Pubkey = *market_fixed.get_quote_mint();
284
285        let trader_base: TokenAccountInfo = TokenAccountInfo::new_with_owner(
286            next_account_info(account_iter)?,
287            &base_mint_key,
288            payer.key,
289        )?;
290        let trader_quote: TokenAccountInfo = TokenAccountInfo::new_with_owner(
291            next_account_info(account_iter)?,
292            &quote_mint_key,
293            payer.key,
294        )?;
295        let base_vault_address: &Pubkey = market_fixed.get_base_vault();
296        let quote_vault_address: &Pubkey = market_fixed.get_quote_vault();
297
298        let base_vault: TokenAccountInfo = TokenAccountInfo::new_with_owner_and_key(
299            next_account_info(account_iter)?,
300            &base_mint_key,
301            &base_vault_address,
302            &base_vault_address,
303        )?;
304        let quote_vault: TokenAccountInfo = TokenAccountInfo::new_with_owner_and_key(
305            next_account_info(account_iter)?,
306            &quote_mint_key,
307            &quote_vault_address,
308            &quote_vault_address,
309        )?;
310        drop(market_fixed);
311
312        let token_program_base: TokenProgram = TokenProgram::new(next_account_info(account_iter)?)?;
313        let mut base_mint: Option<MintAccountInfo> = None;
314
315        let mut current_account_info_or: Result<&AccountInfo<'info>, ProgramError> =
316            next_account_info(account_iter);
317
318        // Possibly includes base mint.
319        if current_account_info_or
320            .as_ref()
321            .is_ok_and(|f| *f.owner == spl_token::id() || *f.owner == spl_token_2022::id())
322        {
323            let current_account_info: &AccountInfo<'info> = current_account_info_or?;
324            base_mint = Some(MintAccountInfo::new(current_account_info)?);
325            current_account_info_or = next_account_info(account_iter);
326        }
327
328        // Clone is not a problem since we are deserializing token program
329        // anyways, so at most this is one more.
330        let mut token_program_quote: TokenProgram = token_program_base.clone();
331        let mut quote_mint: Option<MintAccountInfo> = None;
332        let mut global_trade_accounts_opts: [Option<GlobalTradeAccounts<'a, 'info>>; 2] =
333            [None, None];
334
335        // Possibly includes quote token program.
336        if current_account_info_or
337            .as_ref()
338            .is_ok_and(|f| *f.key == spl_token::id() || *f.key == spl_token_2022::id())
339        {
340            let current_account_info: &AccountInfo<'info> = current_account_info_or?;
341            token_program_quote = TokenProgram::new(current_account_info)?;
342            current_account_info_or = next_account_info(account_iter);
343        }
344        // Possibly includes quote mint if the quote token program was token22.
345        if current_account_info_or
346            .as_ref()
347            .is_ok_and(|f| *f.owner == spl_token::id() || *f.owner == spl_token_2022::id())
348        {
349            let current_account_info: &AccountInfo<'info> = current_account_info_or?;
350            quote_mint = Some(MintAccountInfo::new(current_account_info)?);
351            current_account_info_or = next_account_info(account_iter);
352        }
353
354        if current_account_info_or.is_ok() {
355            let current_account_info: &AccountInfo<'info> = current_account_info_or?;
356
357            // It is possible that the global account does not exist. Do not
358            // throw an error. This will happen when users just blindly include
359            // global accounts that have not been initialized.
360            if !current_account_info.data_is_empty() {
361                let global: ManifestAccountInfo<'a, 'info, GlobalFixed> =
362                    ManifestAccountInfo::<GlobalFixed>::new(current_account_info)?;
363                let global_data: Ref<&mut [u8]> = global.data.borrow();
364                let global_fixed: &GlobalFixed = get_helper::<GlobalFixed>(&global_data, 0_u32);
365                let global_mint_key: &Pubkey = global_fixed.get_mint();
366                let expected_global_vault_address: &Pubkey = global_fixed.get_vault();
367
368                let global_vault: TokenAccountInfo<'a, 'info> =
369                    TokenAccountInfo::new_with_owner_and_key(
370                        next_account_info(account_iter)?,
371                        global_mint_key,
372                        &expected_global_vault_address,
373                        &expected_global_vault_address,
374                    )?;
375
376                let index: usize = if *global_mint_key == base_mint_key {
377                    0
378                } else {
379                    require!(
380                        quote_mint_key == *global_mint_key,
381                        ManifestError::MissingGlobal,
382                        "Unexpected global accounts",
383                    )?;
384                    1
385                };
386
387                drop(global_data);
388                global_trade_accounts_opts[index] = Some(GlobalTradeAccounts {
389                    mint_opt: if index == 0 {
390                        base_mint.clone()
391                    } else {
392                        quote_mint.clone()
393                    },
394                    global,
395                    global_vault_opt: Some(global_vault),
396                    market_vault_opt: if index == 0 {
397                        Some(base_vault.clone())
398                    } else {
399                        Some(quote_vault.clone())
400                    },
401                    token_program_opt: if index == 0 {
402                        Some(token_program_base.clone())
403                    } else {
404                        Some(token_program_quote.clone())
405                    },
406                    gas_payer_opt: None,
407                    gas_receiver_opt: Some(payer.clone()),
408                    market: *market.info.key,
409                    system_program: None,
410                });
411            }
412        }
413
414        Ok(Self {
415            payer,
416            market,
417            trader_base,
418            trader_quote,
419            base_vault,
420            quote_vault,
421            token_program_base,
422            token_program_quote,
423            base_mint,
424            quote_mint,
425            global_trade_accounts_opts,
426        })
427    }
428}
429
430/// Accounts needed to make a global trade. Scope is beyond just crate so
431/// clients can place orders on markets in testing.
432pub struct GlobalTradeAccounts<'a, 'info> {
433    /// Required if this is a token22 token.
434    pub mint_opt: Option<MintAccountInfo<'a, 'info>>,
435    pub global: ManifestAccountInfo<'a, 'info, GlobalFixed>,
436
437    // These are required when matching a global order, not necessarily when
438    // cancelling since tokens dont move in that case.
439    pub global_vault_opt: Option<TokenAccountInfo<'a, 'info>>,
440    pub market_vault_opt: Option<TokenAccountInfo<'a, 'info>>,
441    pub token_program_opt: Option<TokenProgram<'a, 'info>>,
442
443    pub system_program: Option<Program<'a, 'info>>,
444
445    // Trader is sending or cancelling the order. They are the one who will pay
446    // or receive gas prepayments.
447    pub gas_payer_opt: Option<Signer<'a, 'info>>,
448    pub gas_receiver_opt: Option<Signer<'a, 'info>>,
449    pub market: Pubkey,
450}
451
452/// BatchUpdate account infos
453pub(crate) struct BatchUpdateContext<'a, 'info> {
454    pub payer: Signer<'a, 'info>,
455    pub market: ManifestAccountInfo<'a, 'info, MarketFixed>,
456    pub _system_program: Program<'a, 'info>,
457
458    // One for each side. First is base, then is quote.
459    pub global_trade_accounts_opts: [Option<GlobalTradeAccounts<'a, 'info>>; 2],
460}
461
462impl<'a, 'info> BatchUpdateContext<'a, 'info> {
463    pub fn load(accounts: &'a [AccountInfo<'info>]) -> Result<Self, ProgramError> {
464        let account_iter: &mut Iter<AccountInfo<'info>> = &mut accounts.iter();
465
466        // Does not have to be writable, but this ix will fail if removing a
467        // global or requiring expanding.
468        let payer: Signer = Signer::new(next_account_info(account_iter)?)?;
469        let market: ManifestAccountInfo<MarketFixed> =
470            ManifestAccountInfo::<MarketFixed>::new(next_account_info(account_iter)?)?;
471        let system_program: Program =
472            Program::new(next_account_info(account_iter)?, &system_program::id())?;
473        // Certora version is not mutable.
474        #[cfg(feature = "certora")]
475        let global_trade_accounts_opts: [Option<GlobalTradeAccounts<'a, 'info>>; 2] = [None, None];
476        #[cfg(not(feature = "certora"))]
477        let mut global_trade_accounts_opts: [Option<GlobalTradeAccounts<'a, 'info>>; 2] =
478            [None, None];
479
480        #[cfg(not(feature = "certora"))]
481        {
482            let market_fixed: Ref<MarketFixed> = market.get_fixed()?;
483            let base_mint: Pubkey = *market_fixed.get_base_mint();
484            let quote_mint: Pubkey = *market_fixed.get_quote_mint();
485            let base_vault: Pubkey = *market_fixed.get_base_vault();
486            let quote_vault: Pubkey = *market_fixed.get_quote_vault();
487            drop(market_fixed);
488
489            for _ in 0..2 {
490                let next_account_info_or: Result<&AccountInfo<'info>, ProgramError> =
491                    next_account_info(account_iter);
492                if next_account_info_or.is_ok() {
493                    let mint: MintAccountInfo<'a, 'info> =
494                        MintAccountInfo::new(next_account_info_or?)?;
495                    let (index, expected_market_vault_address) = if base_mint == *mint.info.key {
496                        (0, &base_vault)
497                    } else {
498                        require!(
499                            quote_mint == *mint.info.key,
500                            ManifestError::MissingGlobal,
501                            "Unexpected global mint",
502                        )?;
503                        (1, &quote_vault)
504                    };
505
506                    let global_or: Result<
507                        ManifestAccountInfo<'a, 'info, GlobalFixed>,
508                        ProgramError,
509                    > = ManifestAccountInfo::<GlobalFixed>::new(next_account_info(account_iter)?);
510
511                    // If a client blindly fills in the global account and vault,
512                    // then handle that case and allow them to try to work without
513                    // the global accounts.
514                    if global_or.is_err() {
515                        let _global_vault: Result<&AccountInfo<'info>, ProgramError> =
516                            next_account_info(account_iter);
517                        let _market_vault: Result<&AccountInfo<'info>, ProgramError> =
518                            next_account_info(account_iter);
519                        let _token_program: Result<&AccountInfo<'info>, ProgramError> =
520                            next_account_info(account_iter);
521                        continue;
522                    }
523                    let global: ManifestAccountInfo<'a, 'info, GlobalFixed> = global_or.unwrap();
524                    let global_data: Ref<&mut [u8]> = global.data.borrow();
525                    let global_fixed: &GlobalFixed = get_helper::<GlobalFixed>(&global_data, 0_u32);
526                    let expected_global_vault_address: &Pubkey = global_fixed.get_vault();
527
528                    let global_vault: TokenAccountInfo<'a, 'info> =
529                        TokenAccountInfo::new_with_owner_and_key(
530                            next_account_info(account_iter)?,
531                            mint.info.key,
532                            &expected_global_vault_address,
533                            &expected_global_vault_address,
534                        )?;
535                    drop(global_data);
536
537                    let market_vault: TokenAccountInfo<'a, 'info> =
538                        TokenAccountInfo::new_with_owner_and_key(
539                            next_account_info(account_iter)?,
540                            mint.info.key,
541                            &expected_market_vault_address,
542                            &expected_market_vault_address,
543                        )?;
544                    let token_program: TokenProgram<'a, 'info> =
545                        TokenProgram::new(next_account_info(account_iter)?)?;
546
547                    global_trade_accounts_opts[index] = Some(GlobalTradeAccounts {
548                        mint_opt: Some(mint),
549                        global,
550                        global_vault_opt: Some(global_vault),
551                        market_vault_opt: Some(market_vault),
552                        token_program_opt: Some(token_program),
553                        system_program: Some(system_program.clone()),
554                        gas_payer_opt: Some(payer.clone()),
555                        gas_receiver_opt: Some(payer.clone()),
556                        market: *market.info.key,
557                    })
558                };
559            }
560        }
561
562        Ok(Self {
563            payer,
564            market,
565            _system_program: system_program,
566            global_trade_accounts_opts,
567        })
568    }
569}
570
571/// Global create
572pub(crate) struct GlobalCreateContext<'a, 'info> {
573    pub payer: Signer<'a, 'info>,
574    pub global: EmptyAccount<'a, 'info>,
575    pub system_program: Program<'a, 'info>,
576    pub global_mint: MintAccountInfo<'a, 'info>,
577    pub global_vault: EmptyAccount<'a, 'info>,
578    pub token_program: TokenProgram<'a, 'info>,
579}
580
581impl<'a, 'info> GlobalCreateContext<'a, 'info> {
582    pub fn load(accounts: &'a [AccountInfo<'info>]) -> Result<Self, ProgramError> {
583        let account_iter: &mut Iter<AccountInfo<'info>> = &mut accounts.iter();
584
585        let payer: Signer = Signer::new_payer(next_account_info(account_iter)?)?;
586        let global: EmptyAccount = EmptyAccount::new(next_account_info(account_iter)?)?;
587        let system_program: Program =
588            Program::new(next_account_info(account_iter)?, &system_program::id())?;
589        let global_mint: MintAccountInfo = MintAccountInfo::new(next_account_info(account_iter)?)?;
590        // Address of the global vault is verified in the handler because the
591        // create will only work if the signer seeds match.
592        let global_vault: EmptyAccount = EmptyAccount::new(next_account_info(account_iter)?)?;
593        let token_program: TokenProgram = TokenProgram::new(next_account_info(account_iter)?)?;
594        Ok(Self {
595            payer,
596            global,
597            system_program,
598            global_mint,
599            global_vault,
600            token_program,
601        })
602    }
603}
604
605/// Global add trader
606pub(crate) struct GlobalAddTraderContext<'a, 'info> {
607    pub payer: Signer<'a, 'info>,
608    pub global: ManifestAccountInfo<'a, 'info, GlobalFixed>,
609    pub _system_program: Program<'a, 'info>,
610}
611
612impl<'a, 'info> GlobalAddTraderContext<'a, 'info> {
613    pub fn load(accounts: &'a [AccountInfo<'info>]) -> Result<Self, ProgramError> {
614        let account_iter: &mut Iter<AccountInfo<'info>> = &mut accounts.iter();
615
616        let payer: Signer = Signer::new_payer(next_account_info(account_iter)?)?;
617        let global: ManifestAccountInfo<GlobalFixed> =
618            ManifestAccountInfo::<GlobalFixed>::new(next_account_info(account_iter)?)?;
619        let _system_program: Program =
620            Program::new(next_account_info(account_iter)?, &system_program::id())?;
621        Ok(Self {
622            payer,
623            global,
624            _system_program,
625        })
626    }
627}
628
629/// Global deposit
630pub(crate) struct GlobalDepositContext<'a, 'info> {
631    pub payer: Signer<'a, 'info>,
632    pub global: ManifestAccountInfo<'a, 'info, GlobalFixed>,
633    pub mint: MintAccountInfo<'a, 'info>,
634    pub global_vault: TokenAccountInfo<'a, 'info>,
635    pub trader_token: TokenAccountInfo<'a, 'info>,
636    pub token_program: TokenProgram<'a, 'info>,
637}
638
639impl<'a, 'info> GlobalDepositContext<'a, 'info> {
640    pub fn load(accounts: &'a [AccountInfo<'info>]) -> Result<Self, ProgramError> {
641        let account_iter: &mut Iter<AccountInfo<'info>> = &mut accounts.iter();
642
643        let payer: Signer = Signer::new(next_account_info(account_iter)?)?;
644        let global: ManifestAccountInfo<GlobalFixed> =
645            ManifestAccountInfo::<GlobalFixed>::new(next_account_info(account_iter)?)?;
646
647        let mint: MintAccountInfo = MintAccountInfo::new(next_account_info(account_iter)?)?;
648
649        let global_data: Ref<&mut [u8]> = global.data.borrow();
650        let global_fixed: &GlobalFixed = get_helper::<GlobalFixed>(&global_data, 0_u32);
651        let expected_global_vault_address: &Pubkey = global_fixed.get_vault();
652
653        let global_vault: TokenAccountInfo = TokenAccountInfo::new_with_owner_and_key(
654            next_account_info(account_iter)?,
655            mint.info.key,
656            &expected_global_vault_address,
657            &expected_global_vault_address,
658        )?;
659        drop(global_data);
660
661        let token_account_info: &AccountInfo<'info> = next_account_info(account_iter)?;
662        let trader_token: TokenAccountInfo =
663            TokenAccountInfo::new_with_owner(token_account_info, mint.info.key, payer.key)?;
664        let token_program: TokenProgram = TokenProgram::new(next_account_info(account_iter)?)?;
665        Ok(Self {
666            payer,
667            global,
668            mint,
669            global_vault,
670            trader_token,
671            token_program,
672        })
673    }
674}
675
676/// Global withdraw
677pub(crate) struct GlobalWithdrawContext<'a, 'info> {
678    pub payer: Signer<'a, 'info>,
679    pub global: ManifestAccountInfo<'a, 'info, GlobalFixed>,
680    pub mint: MintAccountInfo<'a, 'info>,
681    pub global_vault: TokenAccountInfo<'a, 'info>,
682    pub trader_token: TokenAccountInfo<'a, 'info>,
683    pub token_program: TokenProgram<'a, 'info>,
684}
685
686impl<'a, 'info> GlobalWithdrawContext<'a, 'info> {
687    pub fn load(accounts: &'a [AccountInfo<'info>]) -> Result<Self, ProgramError> {
688        let account_iter: &mut Iter<AccountInfo<'info>> = &mut accounts.iter();
689
690        let payer: Signer = Signer::new(next_account_info(account_iter)?)?;
691        let global: ManifestAccountInfo<GlobalFixed> =
692            ManifestAccountInfo::<GlobalFixed>::new(next_account_info(account_iter)?)?;
693
694        let mint: MintAccountInfo = MintAccountInfo::new(next_account_info(account_iter)?)?;
695
696        let global_data: Ref<&mut [u8]> = global.data.borrow();
697        let global_fixed: &GlobalFixed = get_helper::<GlobalFixed>(&global_data, 0_u32);
698        let expected_global_vault_address: &Pubkey = global_fixed.get_vault();
699
700        let global_vault: TokenAccountInfo = TokenAccountInfo::new_with_owner_and_key(
701            next_account_info(account_iter)?,
702            mint.info.key,
703            &expected_global_vault_address,
704            &expected_global_vault_address,
705        )?;
706        drop(global_data);
707
708        let token_account_info: &AccountInfo<'info> = next_account_info(account_iter)?;
709        let trader_token: TokenAccountInfo =
710            TokenAccountInfo::new_with_owner(token_account_info, mint.info.key, payer.key)?;
711        let token_program: TokenProgram = TokenProgram::new(next_account_info(account_iter)?)?;
712        Ok(Self {
713            payer,
714            global,
715            mint,
716            global_vault,
717            trader_token,
718            token_program,
719        })
720    }
721}
722
723/// Global evict
724pub(crate) struct GlobalEvictContext<'a, 'info> {
725    pub payer: Signer<'a, 'info>,
726    pub global: ManifestAccountInfo<'a, 'info, GlobalFixed>,
727    pub mint: MintAccountInfo<'a, 'info>,
728    pub global_vault: TokenAccountInfo<'a, 'info>,
729    pub trader_token: TokenAccountInfo<'a, 'info>,
730    pub evictee_token: TokenAccountInfo<'a, 'info>,
731    pub token_program: TokenProgram<'a, 'info>,
732}
733
734impl<'a, 'info> GlobalEvictContext<'a, 'info> {
735    pub fn load(accounts: &'a [AccountInfo<'info>]) -> Result<Self, ProgramError> {
736        let account_iter: &mut Iter<AccountInfo<'info>> = &mut accounts.iter();
737
738        let payer: Signer = Signer::new_payer(next_account_info(account_iter)?)?;
739        let global: ManifestAccountInfo<GlobalFixed> =
740            ManifestAccountInfo::<GlobalFixed>::new(next_account_info(account_iter)?)?;
741
742        let mint: MintAccountInfo = MintAccountInfo::new(next_account_info(account_iter)?)?;
743
744        let global_data: Ref<&mut [u8]> = global.data.borrow();
745        let global_fixed: &GlobalFixed = get_helper::<GlobalFixed>(&global_data, 0_u32);
746        let expected_global_vault_address: &Pubkey = global_fixed.get_vault();
747
748        let global_vault: TokenAccountInfo = TokenAccountInfo::new_with_owner_and_key(
749            next_account_info(account_iter)?,
750            mint.info.key,
751            &expected_global_vault_address,
752            &expected_global_vault_address,
753        )?;
754        drop(global_data);
755
756        let token_account_info: &AccountInfo<'info> = next_account_info(account_iter)?;
757        let trader_token: TokenAccountInfo =
758            TokenAccountInfo::new_with_owner(token_account_info, mint.info.key, payer.key)?;
759        let token_account_info: &AccountInfo<'info> = next_account_info(account_iter)?;
760        let evictee_token: TokenAccountInfo =
761            TokenAccountInfo::new(token_account_info, mint.info.key)?;
762        let token_program: TokenProgram = TokenProgram::new(next_account_info(account_iter)?)?;
763        Ok(Self {
764            payer,
765            global,
766            mint,
767            global_vault,
768            trader_token,
769            evictee_token,
770            token_program,
771        })
772    }
773}
774
775/// Global clean
776pub(crate) struct GlobalCleanContext<'a, 'info> {
777    pub payer: Signer<'a, 'info>,
778    pub market: ManifestAccountInfo<'a, 'info, MarketFixed>,
779    pub system_program: Program<'a, 'info>,
780    pub global: ManifestAccountInfo<'a, 'info, GlobalFixed>,
781}
782
783impl<'a, 'info> GlobalCleanContext<'a, 'info> {
784    pub fn load(accounts: &'a [AccountInfo<'info>]) -> Result<Self, ProgramError> {
785        let account_iter: &mut Iter<AccountInfo<'info>> = &mut accounts.iter();
786
787        let payer: Signer = Signer::new_payer(next_account_info(account_iter)?)?;
788        let market: ManifestAccountInfo<MarketFixed> =
789            ManifestAccountInfo::<MarketFixed>::new(next_account_info(account_iter)?)?;
790        let system_program: Program =
791            Program::new(next_account_info(account_iter)?, &system_program::id())?;
792        let global: ManifestAccountInfo<GlobalFixed> =
793            ManifestAccountInfo::<GlobalFixed>::new(next_account_info(account_iter)?)?;
794
795        Ok(Self {
796            payer,
797            market,
798            system_program,
799            global,
800        })
801    }
802}