1use anchor_lang::prelude::*;
2use anchor_spl::{
3 associated_token::AssociatedToken,
4 token::{Mint, Token, TokenAccount},
5 token_2022::Token2022,
6 token_interface,
7};
8use gmsol_utils::InitSpace;
9
10use crate::{
11 constants,
12 events::EventEmitter,
13 ops::{
14 execution_fee::PayExecutionFeeOperation,
15 glv::{CreateGlvDepositOperation, CreateGlvDepositParams, ExecuteGlvDepositOperation},
16 market::{MarketTransferInOperation, MarketTransferOutOperation},
17 },
18 states::{
19 common::{
20 action::{Action, ActionExt, ActionSigner},
21 swap::SwapActionParamsExt,
22 },
23 feature::{ActionDisabledFlag, DomainDisabledFlag},
24 glv::{GlvMarketFlag, SplitAccountsForGlv},
25 Chainlink, Glv, GlvDeposit, Market, NonceBytes, Oracle, RoleKey, Seed, Store,
26 StoreWalletSigner, TokenMapHeader, TokenMapLoader,
27 },
28 utils::{
29 internal,
30 token::{
31 is_associated_token_account, is_associated_token_account_or_owner,
32 is_associated_token_account_with_program_id,
33 },
34 },
35 CoreError,
36};
37
38#[derive(Accounts)]
40#[instruction(nonce: [u8; 32])]
41pub struct CreateGlvDeposit<'info> {
42 #[account(mut)]
44 pub owner: Signer<'info>,
45 pub receiver: UncheckedAccount<'info>,
48 pub store: AccountLoader<'info, Store>,
50 #[account(
52 mut,
53 has_one = store,
54 constraint = market.load()?.meta().market_token_mint == market_token.key() @ CoreError::MarketTokenMintMismatched,
55 )]
56 pub market: AccountLoader<'info, Market>,
57 #[account(
59 has_one = store,
60 constraint = glv.load()?.glv_token == glv_token.key() @ CoreError::TokenMintMismatched,
61 constraint = glv.load()?.contains(&market_token.key()) @ CoreError::InvalidArgument,
62 )]
63 pub glv: AccountLoader<'info, Glv>,
64 #[account(
66 init,
67 payer = owner,
68 space = 8 + GlvDeposit::INIT_SPACE,
69 seeds = [GlvDeposit::SEED, store.key().as_ref(), owner.key().as_ref(), &nonce],
70 bump,
71 )]
72 pub glv_deposit: AccountLoader<'info, GlvDeposit>,
73 pub glv_token: Box<InterfaceAccount<'info, token_interface::Mint>>,
75 pub market_token: Box<Account<'info, Mint>>,
77 pub initial_long_token: Option<Box<Account<'info, Mint>>>,
79 pub initial_short_token: Option<Box<Account<'info, Mint>>>,
81 #[account(mut, token::mint = market_token)]
83 pub market_token_source: Option<Box<Account<'info, TokenAccount>>>,
84 #[account(mut, token::mint = initial_long_token)]
86 pub initial_long_token_source: Option<Box<Account<'info, TokenAccount>>>,
87 #[account(mut, token::mint = initial_short_token)]
89 pub initial_short_token_source: Option<Box<Account<'info, TokenAccount>>>,
90 #[account(
92 mut,
93 associated_token::mint = glv_token,
94 associated_token::authority = glv_deposit,
95 associated_token::token_program = glv_token_program,
96 )]
97 pub glv_token_escrow: Box<InterfaceAccount<'info, token_interface::TokenAccount>>,
98 #[account(
100 mut,
101 associated_token::mint = market_token,
102 associated_token::authority = glv_deposit,
103 )]
104 pub market_token_escrow: Box<Account<'info, TokenAccount>>,
105 #[account(
107 mut,
108 associated_token::mint = initial_long_token,
109 associated_token::authority = glv_deposit,
110 )]
111 pub initial_long_token_escrow: Option<Box<Account<'info, TokenAccount>>>,
112 #[account(
114 mut,
115 associated_token::mint = initial_short_token,
116 associated_token::authority = glv_deposit,
117 )]
118 pub initial_short_token_escrow: Option<Box<Account<'info, TokenAccount>>>,
119 pub system_program: Program<'info, System>,
121 pub token_program: Program<'info, Token>,
123 pub glv_token_program: Program<'info, Token2022>,
125 pub associated_token_program: Program<'info, AssociatedToken>,
127}
128
129impl<'info> internal::Create<'info, GlvDeposit> for CreateGlvDeposit<'info> {
130 type CreateParams = CreateGlvDepositParams;
131
132 fn action(&self) -> AccountInfo<'info> {
133 self.glv_deposit.to_account_info()
134 }
135
136 fn payer(&self) -> AccountInfo<'info> {
137 self.owner.to_account_info()
138 }
139
140 fn system_program(&self) -> AccountInfo<'info> {
141 self.system_program.to_account_info()
142 }
143
144 fn validate(&self, _params: &Self::CreateParams) -> Result<()> {
145 self.store
146 .load()?
147 .validate_not_restarted()?
148 .validate_feature_enabled(DomainDisabledFlag::GlvDeposit, ActionDisabledFlag::Create)?;
149 let market_token = self.market_token.key();
150 let is_deposit_allowed = self
151 .glv
152 .load()?
153 .market_config(&market_token)
154 .ok_or_else(|| error!(CoreError::Internal))?
155 .get_flag(GlvMarketFlag::IsDepositAllowed);
156 require!(is_deposit_allowed, CoreError::GlvDepositIsNotAllowed);
157 Ok(())
158 }
159
160 fn create_impl(
161 &mut self,
162 params: &Self::CreateParams,
163 nonce: &NonceBytes,
164 bumps: &Self::Bumps,
165 remaining_accounts: &'info [AccountInfo<'info>],
166 ) -> Result<()> {
167 self.transfer_tokens(params)?;
168 CreateGlvDepositOperation::builder()
169 .glv_deposit(self.glv_deposit.clone())
170 .market(self.market.clone())
171 .store(self.store.clone())
172 .owner(&self.owner)
173 .receiver(&self.receiver)
174 .nonce(nonce)
175 .bump(bumps.glv_deposit)
176 .initial_long_token(self.initial_long_token_escrow.as_deref())
177 .initial_short_token(self.initial_short_token_escrow.as_deref())
178 .market_token(&self.market_token_escrow)
179 .glv_token(&self.glv_token_escrow)
180 .params(params)
181 .swap_paths(remaining_accounts)
182 .build()
183 .unchecked_execute()?;
184 Ok(())
185 }
186}
187
188impl CreateGlvDeposit<'_> {
189 fn transfer_tokens(&mut self, params: &CreateGlvDepositParams) -> Result<()> {
190 use anchor_spl::token::{transfer_checked, TransferChecked};
191
192 let amount = params.initial_long_token_amount;
193 if amount != 0 {
194 let Some(source) = self.initial_long_token_source.as_ref() else {
195 return err!(CoreError::TokenAccountNotProvided);
196 };
197 let Some(target) = self.initial_long_token_escrow.as_ref() else {
198 return err!(CoreError::TokenAccountNotProvided);
199 };
200 let Some(mint) = self.initial_long_token.as_ref() else {
201 return err!(CoreError::MintAccountNotProvided);
202 };
203 transfer_checked(
204 CpiContext::new(
205 self.token_program.to_account_info(),
206 TransferChecked {
207 from: source.to_account_info(),
208 mint: mint.to_account_info(),
209 to: target.to_account_info(),
210 authority: self.owner.to_account_info(),
211 },
212 ),
213 amount,
214 mint.decimals,
215 )?;
216 }
217
218 let amount = params.initial_short_token_amount;
219 if amount != 0 {
220 let Some(source) = self.initial_short_token_source.as_ref() else {
221 return err!(CoreError::TokenAccountNotProvided);
222 };
223 let Some(target) = self.initial_short_token_escrow.as_ref() else {
224 return err!(CoreError::TokenAccountNotProvided);
225 };
226 let Some(mint) = self.initial_short_token.as_ref() else {
227 return err!(CoreError::MintAccountNotProvided);
228 };
229 transfer_checked(
230 CpiContext::new(
231 self.token_program.to_account_info(),
232 TransferChecked {
233 from: source.to_account_info(),
234 mint: mint.to_account_info(),
235 to: target.to_account_info(),
236 authority: self.owner.to_account_info(),
237 },
238 ),
239 amount,
240 mint.decimals,
241 )?;
242 }
243
244 let amount = params.market_token_amount;
245 if amount != 0 {
246 let Some(source) = self.market_token_source.as_ref() else {
247 return err!(CoreError::TokenAccountNotProvided);
248 };
249 let target = &self.market_token_escrow;
250 let mint = &self.market_token;
251 transfer_checked(
252 CpiContext::new(
253 self.token_program.to_account_info(),
254 TransferChecked {
255 from: source.to_account_info(),
256 mint: mint.to_account_info(),
257 to: target.to_account_info(),
258 authority: self.owner.to_account_info(),
259 },
260 ),
261 amount,
262 mint.decimals,
263 )?;
264 }
265
266 for escrow in self
268 .initial_long_token_escrow
269 .as_mut()
270 .into_iter()
271 .chain(self.initial_short_token_escrow.as_mut())
272 .chain(Some(&mut self.market_token_escrow))
273 {
274 escrow.reload()?;
275 }
276
277 Ok(())
278 }
279}
280
281#[event_cpi]
283#[derive(Accounts)]
284pub struct CloseGlvDeposit<'info> {
285 pub executor: Signer<'info>,
287 pub store: AccountLoader<'info, Store>,
289 #[account(mut, seeds = [Store::WALLET_SEED, store.key().as_ref()], bump)]
291 pub store_wallet: SystemAccount<'info>,
292 #[account(mut)]
295 pub owner: UncheckedAccount<'info>,
296 #[account(mut)]
299 pub receiver: UncheckedAccount<'info>,
300 #[account(
302 mut,
303 constraint = glv_deposit.load()?.header.store == store.key() @ CoreError::StoreMismatched,
304 constraint = glv_deposit.load()?.header.owner == owner.key() @ CoreError::OwnerMismatched,
305 constraint = glv_deposit.load()?.header.receiver() == receiver.key() @ CoreError::ReceiverMismatched,
306 constraint = glv_deposit.load()?.header.rent_receiver() == owner.key @ CoreError::RentReceiverMismatched,
308 constraint = glv_deposit.load()?.tokens.market_token_account() == market_token_escrow.key() @ CoreError::MarketTokenAccountMismatched,
309 constraint = glv_deposit.load()?.tokens.glv_token_account() == glv_token_escrow.key() @ CoreError::MarketTokenAccountMismatched,
310 constraint = glv_deposit.load()?.tokens.initial_long_token.account() == initial_long_token_escrow.as_ref().map(|a| a.key()) @ CoreError::TokenAccountMismatched,
311 constraint = glv_deposit.load()?.tokens.initial_short_token.account() == initial_short_token_escrow.as_ref().map(|a| a.key()) @ CoreError::TokenAccountMismatched,
312 seeds = [GlvDeposit::SEED, store.key().as_ref(), owner.key().as_ref(), &glv_deposit.load()?.header.nonce],
313 bump = glv_deposit.load()?.header.bump,
314 )]
315 pub glv_deposit: AccountLoader<'info, GlvDeposit>,
316 #[account(
318 constraint = glv_deposit.load()?.tokens.market_token() == market_token.key() @ CoreError::MarketTokenMintMismatched
319 )]
320 pub market_token: Box<Account<'info, Mint>>,
321 #[account(
323 constraint = glv_deposit.load()?.tokens.initial_long_token.token().map(|token| initial_long_token.key() == token).unwrap_or(true) @ CoreError::TokenMintMismatched
324 )]
325 pub initial_long_token: Option<Box<Account<'info, Mint>>>,
326 #[account(
328 constraint = glv_deposit.load()?.tokens.initial_short_token.token().map(|token| initial_short_token.key() == token).unwrap_or(true) @ CoreError::TokenMintMismatched
329 )]
330 pub initial_short_token: Option<Box<Account<'info, Mint>>>,
331 #[account(
333 constraint = glv_deposit.load()?.tokens.glv_token() == glv_token.key() @ CoreError::TokenMintMismatched
334 )]
335 pub glv_token: Box<InterfaceAccount<'info, token_interface::Mint>>,
336 #[account(
338 mut,
339 associated_token::mint = market_token,
340 associated_token::authority = glv_deposit,
341 )]
342 pub market_token_escrow: Box<Account<'info, TokenAccount>>,
343 #[account(
345 mut,
346 associated_token::mint = initial_long_token,
347 associated_token::authority = glv_deposit,
348 )]
349 pub initial_long_token_escrow: Option<Box<Account<'info, TokenAccount>>>,
350 #[account(
352 mut,
353 associated_token::mint = initial_short_token,
354 associated_token::authority = glv_deposit,
355 )]
356 pub initial_short_token_escrow: Option<Box<Account<'info, TokenAccount>>>,
357 #[account(
359 mut,
360 associated_token::mint = glv_token,
361 associated_token::authority = glv_deposit,
362 associated_token::token_program = glv_token_program,
363 )]
364 pub glv_token_escrow: Box<InterfaceAccount<'info, token_interface::TokenAccount>>,
365 #[account(
368 mut,
369 constraint = is_associated_token_account(market_token_ata.key, owner.key, &market_token.key()) @ CoreError::NotAnATA,
370 )]
371 pub market_token_ata: UncheckedAccount<'info>,
372 #[account(
375 mut,
376 constraint = is_associated_token_account_or_owner(initial_long_token_ata.key, owner.key, &initial_long_token.as_ref().expect("must provided").key()) @ CoreError::NotAnATA,
377 )]
378 pub initial_long_token_ata: Option<UncheckedAccount<'info>>,
379 #[account(
382 mut,
383 constraint = is_associated_token_account_or_owner(initial_short_token_ata.key, owner.key, &initial_short_token.as_ref().expect("must provided").key()) @ CoreError::NotAnATA,
384 )]
385 pub initial_short_token_ata: Option<UncheckedAccount<'info>>,
386 #[account(
389 mut,
390 constraint = is_associated_token_account_with_program_id(glv_token_ata.key, receiver.key, &glv_token.key(), &glv_token_program.key()) @ CoreError::NotAnATA,
391 )]
392 pub glv_token_ata: UncheckedAccount<'info>,
393 pub system_program: Program<'info, System>,
395 pub token_program: Program<'info, Token>,
397 pub glv_token_program: Program<'info, Token2022>,
399 pub associated_token_program: Program<'info, AssociatedToken>,
401}
402
403impl<'info> internal::Close<'info, GlvDeposit> for CloseGlvDeposit<'info> {
404 fn expected_keeper_role(&self) -> &str {
405 RoleKey::ORDER_KEEPER
406 }
407
408 fn rent_receiver(&self) -> AccountInfo<'info> {
409 debug_assert!(
410 self.glv_deposit.load().unwrap().header.rent_receiver() == self.owner.key,
411 "The rent receiver must have been checked to be the owner"
412 );
413 self.owner.to_account_info()
414 }
415
416 fn store_wallet_bump(&self, bumps: &Self::Bumps) -> u8 {
417 bumps.store_wallet
418 }
419
420 fn validate(&self) -> Result<()> {
421 let glv_deposit = self.glv_deposit.load()?;
422 if glv_deposit.header.action_state()?.is_pending() {
423 self.store
424 .load()?
425 .validate_not_restarted()?
426 .validate_feature_enabled(
427 DomainDisabledFlag::GlvDeposit,
428 ActionDisabledFlag::Cancel,
429 )?;
430 }
431 Ok(())
432 }
433
434 fn process(
435 &self,
436 init_if_needed: bool,
437 store_wallet_signer: &StoreWalletSigner,
438 _event_emitter: &EventEmitter<'_, 'info>,
439 ) -> Result<internal::Success> {
440 use crate::utils::token::TransferAllFromEscrowToATA;
441
442 let signer = self.glv_deposit.load()?.signer();
444 let seeds = signer.as_seeds();
445
446 let builder = TransferAllFromEscrowToATA::builder()
447 .store_wallet(self.store_wallet.to_account_info())
448 .store_wallet_signer(store_wallet_signer)
449 .system_program(self.system_program.to_account_info())
450 .associated_token_program(self.associated_token_program.to_account_info())
451 .payer(self.executor.to_account_info())
452 .escrow_authority(self.glv_deposit.to_account_info())
453 .escrow_authority_seeds(&seeds)
454 .init_if_needed(init_if_needed)
455 .rent_receiver(self.rent_receiver())
456 .should_unwrap_native(
457 self.glv_deposit
458 .load()?
459 .header()
460 .should_unwrap_native_token(),
461 );
462
463 if !builder
465 .clone()
466 .token_program(self.token_program.to_account_info())
467 .mint(self.market_token.to_account_info())
468 .decimals(self.market_token.decimals)
469 .ata(self.market_token_ata.to_account_info())
470 .escrow(self.market_token_escrow.to_account_info())
471 .owner(self.owner.to_account_info())
472 .build()
473 .unchecked_execute()?
474 {
475 return Ok(false);
476 }
477
478 if !builder
480 .clone()
481 .token_program(self.glv_token_program.to_account_info())
482 .mint(self.glv_token.to_account_info())
483 .decimals(self.glv_token.decimals)
484 .ata(self.glv_token_ata.to_account_info())
485 .escrow(self.glv_token_escrow.to_account_info())
486 .owner(self.receiver.to_account_info())
487 .build()
488 .unchecked_execute()?
489 {
490 return Ok(false);
491 }
492
493 let (initial_long_token_escrow, initial_short_token_escrow) =
495 if self.initial_long_token_escrow.as_ref().map(|a| a.key())
496 == self.initial_short_token_escrow.as_ref().map(|a| a.key())
497 {
498 (self.initial_long_token_escrow.as_ref(), None)
499 } else {
500 (
501 self.initial_long_token_escrow.as_ref(),
502 self.initial_short_token_escrow.as_ref(),
503 )
504 };
505
506 if let Some(escrow) = initial_long_token_escrow.as_ref() {
508 let Some(ata) = self.initial_long_token_ata.as_ref() else {
509 return err!(CoreError::TokenAccountNotProvided);
510 };
511 let Some(mint) = self.initial_long_token.as_ref() else {
512 return err!(CoreError::MintAccountNotProvided);
513 };
514 if !builder
515 .clone()
516 .token_program(self.token_program.to_account_info())
517 .mint(mint.to_account_info())
518 .decimals(mint.decimals)
519 .ata(ata.to_account_info())
520 .escrow(escrow.to_account_info())
521 .owner(self.owner.to_account_info())
522 .build()
523 .unchecked_execute()?
524 {
525 return Ok(false);
526 }
527 }
528
529 if let Some(escrow) = initial_short_token_escrow.as_ref() {
531 let Some(ata) = self.initial_short_token_ata.as_ref() else {
532 return err!(CoreError::TokenAccountNotProvided);
533 };
534 let Some(mint) = self.initial_short_token.as_ref() else {
535 return err!(CoreError::MintAccountNotProvided);
536 };
537 if !builder
538 .clone()
539 .token_program(self.token_program.to_account_info())
540 .mint(mint.to_account_info())
541 .decimals(mint.decimals)
542 .ata(ata.to_account_info())
543 .escrow(escrow.to_account_info())
544 .owner(self.owner.to_account_info())
545 .build()
546 .unchecked_execute()?
547 {
548 return Ok(false);
549 }
550 }
551
552 Ok(true)
553 }
554
555 fn event_authority(&self, bumps: &Self::Bumps) -> (AccountInfo<'info>, u8) {
556 (
557 self.event_authority.to_account_info(),
558 bumps.event_authority,
559 )
560 }
561
562 fn action(&self) -> &AccountLoader<'info, GlvDeposit> {
563 &self.glv_deposit
564 }
565}
566
567impl<'info> internal::Authentication<'info> for CloseGlvDeposit<'info> {
568 fn authority(&self) -> &Signer<'info> {
569 &self.executor
570 }
571
572 fn store(&self) -> &AccountLoader<'info, Store> {
573 &self.store
574 }
575}
576
577#[event_cpi]
589#[derive(Accounts)]
590pub struct ExecuteGlvDeposit<'info> {
591 pub authority: Signer<'info>,
593 #[account(has_one = token_map)]
595 pub store: AccountLoader<'info, Store>,
596 #[account(has_one = store)]
598 pub token_map: AccountLoader<'info, TokenMapHeader>,
599 #[account(mut, has_one = store)]
601 pub oracle: AccountLoader<'info, Oracle>,
602 #[account(
604 mut,
605 has_one = store,
606 constraint = glv.load()?.contains(&market_token.key()) @ CoreError::InvalidArgument,
607 )]
608 pub glv: AccountLoader<'info, Glv>,
609 #[account(mut, has_one = store)]
611 pub market: AccountLoader<'info, Market>,
612 #[account(
614 mut,
615 constraint = glv_deposit.load()?.header.store == store.key() @ CoreError::StoreMismatched,
616 constraint = glv_deposit.load()?.header.market == market.key() @ CoreError::MarketMismatched,
617 constraint = glv_deposit.load()?.tokens.glv_token() == glv_token.key() @ CoreError::TokenMintMismatched,
618 constraint = glv_deposit.load()?.tokens.market_token() == market_token.key() @ CoreError::MarketTokenMintMismatched,
619 constraint = glv_deposit.load()?.tokens.market_token_account() == market_token_escrow.key() @ CoreError::MarketTokenAccountMismatched,
620 constraint = glv_deposit.load()?.tokens.glv_token_account() == glv_token_escrow.key() @ CoreError::MarketTokenAccountMismatched,
621 constraint = glv_deposit.load()?.tokens.initial_long_token.account() == initial_long_token_escrow.as_ref().map(|a| a.key()) @ CoreError::TokenAccountMismatched,
622 constraint = glv_deposit.load()?.tokens.initial_short_token.account() == initial_short_token_escrow.as_ref().map(|a| a.key()) @ CoreError::TokenAccountMismatched,
623 seeds = [GlvDeposit::SEED, store.key().as_ref(), glv_deposit.load()?.header.owner.as_ref(), &glv_deposit.load()?.header.nonce],
624 bump = glv_deposit.load()?.header.bump,
625 )]
626 pub glv_deposit: AccountLoader<'info, GlvDeposit>,
627 #[account(mut, constraint = glv.load()?.glv_token == glv_token.key() @ CoreError::TokenMintMismatched)]
629 pub glv_token: Box<InterfaceAccount<'info, token_interface::Mint>>,
630 #[account(mut, constraint = market.load()?.meta().market_token_mint == market_token.key() @ CoreError::MarketTokenMintMismatched)]
632 pub market_token: Box<Account<'info, Mint>>,
633 #[account(
635 constraint = glv_deposit.load()?.tokens.initial_long_token.token().map(|token| initial_long_token.key() == token).unwrap_or(true) @ CoreError::TokenMintMismatched
636 )]
637 pub initial_long_token: Option<Box<Account<'info, Mint>>>,
638 #[account(
640 constraint = glv_deposit.load()?.tokens.initial_short_token.token().map(|token| initial_short_token.key() == token).unwrap_or(true) @ CoreError::TokenMintMismatched
641 )]
642 pub initial_short_token: Option<Box<Account<'info, Mint>>>,
643 #[account(
645 mut,
646 associated_token::mint = glv_token,
647 associated_token::authority = glv_deposit,
648 associated_token::token_program = glv_token_program,
649 )]
650 pub glv_token_escrow: Box<InterfaceAccount<'info, token_interface::TokenAccount>>,
651 #[account(
653 mut,
654 associated_token::mint = market_token,
655 associated_token::authority = glv_deposit,
656 )]
657 pub market_token_escrow: Box<Account<'info, TokenAccount>>,
658 #[account(
660 mut,
661 associated_token::mint = initial_long_token,
662 associated_token::authority = glv_deposit,
663 )]
664 pub initial_long_token_escrow: Option<Box<Account<'info, TokenAccount>>>,
665 #[account(
667 mut,
668 associated_token::mint = initial_short_token,
669 associated_token::authority = glv_deposit,
670 )]
671 pub initial_short_token_escrow: Option<Box<Account<'info, TokenAccount>>>,
672 #[account(
674 mut,
675 token::mint = initial_long_token,
676 token::authority = store,
677 seeds = [
678 constants::MARKET_VAULT_SEED,
679 store.key().as_ref(),
680 initial_long_token_vault.mint.as_ref(),
681 ],
682 bump,
683 )]
684 pub initial_long_token_vault: Option<Box<Account<'info, TokenAccount>>>,
685 #[account(
687 mut,
688 token::mint = initial_short_token,
689 token::authority = store,
690 seeds = [
691 constants::MARKET_VAULT_SEED,
692 store.key().as_ref(),
693 initial_short_token_vault.mint.as_ref(),
694 ],
695 bump,
696 )]
697 pub initial_short_token_vault: Option<Box<Account<'info, TokenAccount>>>,
698 #[account(
700 mut,
701 associated_token::mint = market_token,
702 associated_token::authority = glv,
703 )]
704 pub market_token_vault: Box<Account<'info, TokenAccount>>,
705 pub token_program: Program<'info, Token>,
707 pub glv_token_program: Program<'info, Token2022>,
709 pub system_program: Program<'info, System>,
711 pub chainlink_program: Option<Program<'info, Chainlink>>,
713}
714
715pub(crate) fn unchecked_execute_glv_deposit<'info>(
717 ctx: Context<'_, '_, 'info, 'info, ExecuteGlvDeposit<'info>>,
718 execution_lamports: u64,
719 throw_on_execution_error: bool,
720) -> Result<()> {
721 let accounts = ctx.accounts;
722 let remaining_accounts = ctx.remaining_accounts;
723
724 accounts
726 .store
727 .load()?
728 .validate_feature_enabled(DomainDisabledFlag::GlvDeposit, ActionDisabledFlag::Execute)?;
729
730 let SplitAccountsForGlv {
731 markets,
732 market_tokens,
733 remaining_accounts,
734 tokens,
735 } = {
736 let glv_deposit = accounts.glv_deposit.load()?;
737 let token_map = accounts.token_map.load_token_map()?;
738 accounts.glv.load()?.validate_and_split_remaining_accounts(
739 &accounts.store.key(),
740 remaining_accounts,
741 Some(&*glv_deposit),
742 &token_map,
743 )?
744 };
745
746 let event_authority = accounts.event_authority.clone();
747 let event_emitter = EventEmitter::new(&event_authority, ctx.bumps.event_authority);
748
749 let signer = accounts.glv_deposit.load()?.signer();
750 accounts.transfer_tokens_in(&signer, remaining_accounts, &event_emitter)?;
751
752 let executed = accounts.perform_execution(
753 markets,
754 market_tokens,
755 &tokens,
756 remaining_accounts,
757 throw_on_execution_error,
758 &event_emitter,
759 )?;
760
761 if executed {
762 accounts.glv_deposit.load_mut()?.header.completed()?;
763 } else {
764 accounts.glv_deposit.load_mut()?.header.cancelled()?;
765 accounts.transfer_tokens_out(remaining_accounts, &event_emitter)?;
766 }
767
768 accounts.pay_execution_fee(execution_lamports)?;
770 Ok(())
771}
772
773impl<'info> internal::Authentication<'info> for ExecuteGlvDeposit<'info> {
774 fn authority(&self) -> &Signer<'info> {
775 &self.authority
776 }
777
778 fn store(&self) -> &AccountLoader<'info, Store> {
779 &self.store
780 }
781}
782
783impl<'info> ExecuteGlvDeposit<'info> {
784 #[inline(never)]
785 fn pay_execution_fee(&self, execution_fee: u64) -> Result<()> {
786 let execution_lamports = self.glv_deposit.load()?.execution_lamports(execution_fee);
787 PayExecutionFeeOperation::builder()
788 .payer(self.glv_deposit.to_account_info())
789 .receiver(self.authority.to_account_info())
790 .execution_lamports(execution_lamports)
791 .build()
792 .execute()?;
793 Ok(())
794 }
795
796 #[inline(never)]
797 fn transfer_tokens_in(
798 &self,
799 signer: &ActionSigner,
800 remaining_accounts: &'info [AccountInfo<'info>],
801 event_emitter: &EventEmitter<'_, 'info>,
802 ) -> Result<()> {
803 self.transfer_initial_tokens_in(signer, remaining_accounts, event_emitter)?;
805 Ok(())
806 }
807
808 #[inline(never)]
809 fn transfer_tokens_out(
810 &self,
811 remaining_accounts: &'info [AccountInfo<'info>],
812 event_emitter: &EventEmitter<'_, 'info>,
813 ) -> Result<()> {
814 self.transfer_initial_tokens_out(remaining_accounts, event_emitter)?;
816 Ok(())
817 }
818
819 fn transfer_initial_tokens_in(
820 &self,
821 sigenr: &ActionSigner,
822 remaining_accounts: &'info [AccountInfo<'info>],
823 event_emitter: &EventEmitter<'_, 'info>,
824 ) -> Result<()> {
825 let seeds = sigenr.as_seeds();
826 let builder = MarketTransferInOperation::builder()
827 .store(&self.store)
828 .from_authority(self.glv_deposit.to_account_info())
829 .token_program(self.token_program.to_account_info())
830 .signer_seeds(&seeds)
831 .event_emitter(*event_emitter);
832 let store = &self.store.key();
833
834 for is_primary in [true, false] {
835 let (amount, escrow, vault) = if is_primary {
836 (
837 self.glv_deposit
838 .load()?
839 .params
840 .deposit
841 .initial_long_token_amount,
842 self.initial_long_token_escrow.as_ref(),
843 self.initial_long_token_vault.as_ref(),
844 )
845 } else {
846 (
847 self.glv_deposit
848 .load()?
849 .params
850 .deposit
851 .initial_short_token_amount,
852 self.initial_short_token_escrow.as_ref(),
853 self.initial_short_token_vault.as_ref(),
854 )
855 };
856
857 if amount == 0 {
858 continue;
859 }
860
861 let escrow = escrow.ok_or_else(|| error!(CoreError::TokenAccountNotProvided))?;
862 let market = self
863 .glv_deposit
864 .load()?
865 .swap
866 .find_and_unpack_first_market(store, is_primary, remaining_accounts)?
867 .unwrap_or(self.market.clone());
868 let vault = vault.ok_or_else(|| error!(CoreError::TokenAccountNotProvided))?;
869 builder
870 .clone()
871 .market(&market)
872 .from(escrow.to_account_info())
873 .vault(vault)
874 .amount(amount)
875 .build()
876 .execute()?;
877 }
878
879 Ok(())
880 }
881
882 fn transfer_initial_tokens_out(
883 &self,
884 remaining_accounts: &'info [AccountInfo<'info>],
885 event_emitter: &EventEmitter<'_, 'info>,
886 ) -> Result<()> {
887 let builder = MarketTransferOutOperation::builder()
888 .store(&self.store)
889 .token_program(self.token_program.to_account_info())
890 .event_emitter(*event_emitter);
891
892 let store = &self.store.key();
893
894 for is_primary in [true, false] {
895 let (amount, token, escrow, vault) = if is_primary {
896 (
897 self.glv_deposit
898 .load()?
899 .params
900 .deposit
901 .initial_long_token_amount,
902 self.initial_long_token.as_ref(),
903 self.initial_long_token_escrow.as_ref(),
904 self.initial_long_token_vault.as_ref(),
905 )
906 } else {
907 (
908 self.glv_deposit
909 .load()?
910 .params
911 .deposit
912 .initial_short_token_amount,
913 self.initial_short_token.as_ref(),
914 self.initial_short_token_escrow.as_ref(),
915 self.initial_short_token_vault.as_ref(),
916 )
917 };
918
919 let Some(escrow) = escrow else {
920 continue;
921 };
922
923 let market = self
924 .glv_deposit
925 .load()?
926 .swap
927 .find_and_unpack_first_market(store, is_primary, remaining_accounts)?
928 .unwrap_or(self.market.clone());
929 let token = token.ok_or_else(|| error!(CoreError::TokenMintNotProvided))?;
930 let vault = vault.ok_or_else(|| error!(CoreError::TokenAccountNotProvided))?;
931 builder
932 .clone()
933 .market(&market)
934 .to(escrow.to_account_info())
935 .vault(vault.to_account_info())
936 .amount(amount)
937 .decimals(token.decimals)
938 .token_mint(token.to_account_info())
939 .build()
940 .execute()?;
941 }
942
943 Ok(())
944 }
945
946 fn perform_execution(
947 &mut self,
948 markets: &'info [AccountInfo<'info>],
949 market_tokens: &'info [AccountInfo<'info>],
950 tokens: &[Pubkey],
951 remaining_accounts: &'info [AccountInfo<'info>],
952 throw_on_execution_error: bool,
953 event_emitter: &EventEmitter<'_, 'info>,
954 ) -> Result<bool> {
955 let builder = ExecuteGlvDepositOperation::builder()
956 .glv_deposit(self.glv_deposit.clone())
957 .token_program(self.token_program.to_account_info())
958 .glv_token_program(self.glv_token_program.to_account_info())
959 .throw_on_execution_error(throw_on_execution_error)
960 .store(self.store.clone())
961 .glv(self.glv.clone())
962 .glv_token_mint(&mut self.glv_token)
963 .glv_token_receiver(self.glv_token_escrow.to_account_info())
964 .market(self.market.clone())
965 .market_token_source(&self.market_token_escrow)
966 .market_token_mint(&mut self.market_token)
967 .market_token_vault(self.market_token_vault.to_account_info())
968 .markets(markets)
969 .market_tokens(market_tokens)
970 .event_emitter(*event_emitter);
971
972 self.oracle.load_mut()?.with_prices(
973 &self.store,
974 &self.token_map,
975 tokens,
976 remaining_accounts,
977 self.chainlink_program.as_ref(),
978 |oracle, remaining_accounts| {
979 builder
980 .oracle(oracle)
981 .remaining_accounts(remaining_accounts)
982 .build()
983 .unchecked_execute()
984 },
985 )
986 }
987}