gmsol_store/instructions/exchange/
execute_order.rs

1use std::ops::Deref;
2
3use anchor_lang::prelude::*;
4use anchor_spl::token::{Mint, Token, TokenAccount};
5
6use crate::{
7    constants,
8    events::{EventEmitter, TradeData, TradeEventRef},
9    ops::{
10        execution_fee::PayExecutionFeeOperation,
11        market::{MarketTransferInOperation, MarketTransferOutOperation},
12        order::{
13            ExecuteOrderOperation, ProcessTransferOutOperation, RemovePosition,
14            ShouldSendTradeEvent,
15        },
16    },
17    states::{
18        common::{
19            action::{ActionExt, ActionSigner},
20            swap::SwapActionParamsExt,
21        },
22        feature::ActionDisabledFlag,
23        order::{Order, TransferOut},
24        position::Position,
25        user::UserHeader,
26        Chainlink, Market, Oracle, Seed, Store, TokenMapHeader, TokenMapLoader,
27    },
28    utils::{internal, pubkey::DEFAULT_PUBKEY},
29    CoreError,
30};
31
32/// The accounts definition for [`prepare_trade_event_buffer`](crate::gmsol_store::prepare_trade_event_buffer).
33#[derive(Accounts)]
34#[instruction(index: u16)]
35pub struct PrepareTradeEventBuffer<'info> {
36    /// Authority.
37    #[account(mut)]
38    pub authority: Signer<'info>,
39    /// Store.
40    pub store: AccountLoader<'info, Store>,
41    /// Trade Event Buffer.
42    #[account(
43        init_if_needed,
44        payer = authority,
45        // The "zero-copy" init space of `TradeData` is used here.
46        space = 8 + <TradeData as gmsol_utils::InitSpace>::INIT_SPACE,
47        seeds = [TradeData::SEED, store.key().as_ref(), authority.key().as_ref(), &index.to_le_bytes()],
48        bump,
49    )]
50    pub event: AccountLoader<'info, TradeData>,
51    /// System Program.
52    pub system_program: Program<'info, System>,
53}
54
55pub(crate) fn prepare_trade_event_buffer(
56    ctx: Context<PrepareTradeEventBuffer>,
57    _index: u16,
58) -> Result<()> {
59    match ctx.accounts.event.load_init() {
60        Ok(mut event) => {
61            require_keys_eq!(event.authority, DEFAULT_PUBKEY, CoreError::Internal);
62            event.store = ctx.accounts.store.key();
63            event.authority = ctx.accounts.authority.key();
64        }
65        Err(Error::AnchorError(err)) => {
66            if err.error_code_number != ErrorCode::AccountDiscriminatorAlreadySet as u32 {
67                return Err(Error::AnchorError(err));
68            }
69        }
70        Err(err) => {
71            return Err(err);
72        }
73    }
74    ctx.accounts.event.exit(&crate::ID)?;
75    require_keys_eq!(
76        ctx.accounts.event.load()?.store,
77        ctx.accounts.store.key(),
78        CoreError::PermissionDenied
79    );
80    require_keys_eq!(
81        ctx.accounts.event.load()?.authority,
82        ctx.accounts.authority.key(),
83        CoreError::PermissionDenied
84    );
85    Ok(())
86}
87
88pub(crate) fn get_pnl_token(
89    position: &Option<AccountLoader<'_, Position>>,
90    market: &Market,
91) -> Result<Pubkey> {
92    let is_long = position
93        .as_ref()
94        .ok_or_else(|| error!(CoreError::PositionIsRequired))?
95        .load()?
96        .try_is_long()?;
97    if is_long {
98        Ok(market.meta().long_token_mint)
99    } else {
100        Ok(market.meta.short_token_mint)
101    }
102}
103
104pub(crate) fn check_delegation(account: &TokenAccount, target: Pubkey) -> Result<bool> {
105    let is_matched = account
106        .delegate
107        .map(|delegate| delegate == target)
108        .ok_or_else(|| error!(CoreError::NoDelegatedAuthorityIsSet))?;
109    Ok(is_matched)
110}
111
112pub(crate) fn validated_recent_timestamp(config: &Store, timestamp: i64) -> Result<i64> {
113    let recent_time_window = config.amount.recent_time_window;
114    let expiration_time = timestamp.saturating_add_unsigned(recent_time_window);
115    let clock = Clock::get()?;
116    if timestamp <= clock.unix_timestamp && clock.unix_timestamp <= expiration_time {
117        Ok(timestamp)
118    } else {
119        err!(CoreError::InvalidArgument)
120    }
121}
122
123/// The accounts definition for [`execute_increase_or_swap_order`](crate::gmsol_store::execute_increase_or_swap_order) instruction.
124///
125/// Remaining accounts expected by this instruction:
126///   - 0..M. `[]` M feed accounts, where M represents the total number of tokens in the
127///     swap params.
128///   - M..M+N. `[writable]` N market accounts, where N represents the total number of unique
129///     markets excluding the current market in the swap params.
130#[event_cpi]
131#[derive(Accounts)]
132#[instruction(recent_timestamp: i64)]
133pub struct ExecuteIncreaseOrSwapOrder<'info> {
134    /// Authority.
135    pub authority: Signer<'info>,
136    /// Store.
137    #[account(mut, has_one = token_map)]
138    pub store: AccountLoader<'info, Store>,
139    /// Token Map.
140    #[account(has_one = store)]
141    pub token_map: AccountLoader<'info, TokenMapHeader>,
142    /// Oracle buffer to use.
143    #[account(mut, has_one = store)]
144    pub oracle: AccountLoader<'info, Oracle>,
145    /// Market.
146    #[account(mut, has_one = store)]
147    pub market: AccountLoader<'info, Market>,
148    /// The owner of the order.
149    /// CHECK: only used to receive fund.
150    #[account(mut)]
151    pub owner: UncheckedAccount<'info>,
152    /// User Account.
153    #[account(
154        mut,
155        constraint = user.load()?.is_initialized() @ CoreError::InvalidUserAccount,
156        has_one = owner,
157        has_one = store,
158        seeds = [UserHeader::SEED, store.key().as_ref(), owner.key().as_ref()],
159        bump = user.load()?.bump,
160    )]
161    pub user: AccountLoader<'info, UserHeader>,
162    /// Order to execute.
163    #[account(
164        mut,
165        constraint = order.load()?.header.store == store.key() @ CoreError::StoreMismatched,
166        constraint = order.load()?.header.market == market.key() @ CoreError::MarketMismatched,
167        constraint = order.load()?.header.owner == owner.key() @ CoreError::OwnerMismatched,
168        constraint = order.load()?.params.position().copied() == position.as_ref().map(|p| p.key()) @ CoreError::PositionMismatched,
169        constraint = order.load()?.tokens.initial_collateral.account() == initial_collateral_token_escrow.as_ref().map(|a| a.key()) @ CoreError::TokenAccountMismatched,
170        constraint = order.load()?.tokens.final_output_token.account() == final_output_token_escrow.as_ref().map(|a| a.key()) @ CoreError::TokenAccountMismatched,
171        constraint = order.load()?.tokens.long_token.account() == long_token_escrow.as_ref().map(|a| a.key())@ CoreError::TokenAccountMismatched,
172        constraint = order.load()?.tokens.short_token.account() == short_token_escrow.as_ref().map(|a| a.key())@ CoreError::TokenAccountMismatched,
173    )]
174    pub order: AccountLoader<'info, Order>,
175    #[account(
176        mut,
177        constraint = position.load()?.owner == order.load()?.header.owner,
178        constraint = position.load()?.store == store.key(),
179        seeds = [
180            Position::SEED,
181            store.key().as_ref(),
182            order.load()?.header.owner.as_ref(),
183            position.load()?.market_token.as_ref(),
184            position.load()?.collateral_token.as_ref(),
185            &[position.load()?.kind],
186        ],
187        bump = position.load()?.bump,
188    )]
189    pub position: Option<AccountLoader<'info, Position>>,
190    /// Trade event buffer.
191    #[account(mut, has_one = store, has_one = authority)]
192    pub event: Option<AccountLoader<'info, TradeData>>,
193    /// Initial collateral token.
194    pub initial_collateral_token: Option<Box<Account<'info, Mint>>>,
195    /// Final output token.
196    pub final_output_token: Option<Box<Account<'info, Mint>>>,
197    /// Long token.
198    pub long_token: Option<Box<Account<'info, Mint>>>,
199    /// Short token.
200    pub short_token: Option<Box<Account<'info, Mint>>>,
201    /// The escrow account for initial collateral tokens.
202    #[account(
203        mut,
204        associated_token::mint = initial_collateral_token,
205        associated_token::authority = order,
206    )]
207    pub initial_collateral_token_escrow: Option<Box<Account<'info, TokenAccount>>>,
208    /// The escrow account for final output tokens.
209    #[account(
210        mut,
211        associated_token::mint = final_output_token,
212        associated_token::authority = order,
213    )]
214    pub final_output_token_escrow: Option<Box<Account<'info, TokenAccount>>>,
215    /// The escrow account for long tokens.
216    #[account(
217        mut,
218        associated_token::mint = long_token,
219        associated_token::authority = order,
220    )]
221    pub long_token_escrow: Option<Box<Account<'info, TokenAccount>>>,
222    /// The escrow account for short tokens.
223    #[account(
224        mut,
225        associated_token::mint = short_token,
226        associated_token::authority = order,
227    )]
228    pub short_token_escrow: Option<Box<Account<'info, TokenAccount>>>,
229    /// Initial collatearl token vault.
230    #[account(
231        mut,
232        token::mint = initial_collateral_token,
233        token::authority = store,
234        seeds = [
235            constants::MARKET_VAULT_SEED,
236            store.key().as_ref(),
237            initial_collateral_token_vault.mint.as_ref(),
238        ],
239        bump,
240    )]
241    pub initial_collateral_token_vault: Option<Box<Account<'info, TokenAccount>>>,
242    /// Final output token vault.
243    #[account(
244        mut,
245        token::mint = final_output_token,
246        token::authority = store,
247        seeds = [
248            constants::MARKET_VAULT_SEED,
249            store.key().as_ref(),
250            final_output_token_vault.mint.as_ref(),
251        ],
252        bump,
253    )]
254    pub final_output_token_vault: Option<Box<Account<'info, TokenAccount>>>,
255    /// Long token vault.
256    #[account(
257        mut,
258        token::mint = long_token,
259        token::authority = store,
260        seeds = [
261            constants::MARKET_VAULT_SEED,
262            store.key().as_ref(),
263            long_token_vault.mint.as_ref(),
264        ],
265        bump,
266    )]
267    pub long_token_vault: Option<Box<Account<'info, TokenAccount>>>,
268    /// Short token vault.
269    #[account(
270        mut,
271        token::mint = short_token,
272        token::authority = store,
273        seeds = [
274            constants::MARKET_VAULT_SEED,
275            store.key().as_ref(),
276            short_token_vault.mint.as_ref(),
277        ],
278        bump,
279    )]
280    pub short_token_vault: Option<Box<Account<'info, TokenAccount>>>,
281    /// The token program.
282    pub token_program: Program<'info, Token>,
283    /// The system program.
284    pub system_program: Program<'info, System>,
285    /// Chainlink Program.
286    pub chainlink_program: Option<Program<'info, Chainlink>>,
287}
288
289#[inline(never)]
290pub(crate) fn unchecked_execute_increase_or_swap_order<'info>(
291    mut ctx: Context<'_, '_, 'info, 'info, ExecuteIncreaseOrSwapOrder<'info>>,
292    _recent_timestamp: i64,
293    execution_fee: u64,
294    throw_on_execution_error: bool,
295) -> Result<()> {
296    let accounts = &mut ctx.accounts;
297
298    let kind = accounts.order.load()?.params().kind()?;
299
300    // Validate the order kind.
301    require!(
302        kind.is_increase_position() || kind.is_swap(),
303        CoreError::InvalidArgument
304    );
305
306    // Validate feature enabled.
307    accounts.store.load()?.validate_feature_enabled(
308        kind.try_into()
309            .map_err(CoreError::from)
310            .map_err(|err| error!(err))?,
311        ActionDisabledFlag::Execute,
312    )?;
313
314    let remaining_accounts = ctx.remaining_accounts;
315    let signer = accounts.order.load()?.signer();
316
317    let event_authority = accounts.event_authority.clone();
318    let event_emitter = EventEmitter::new(&event_authority, ctx.bumps.event_authority);
319
320    accounts.transfer_tokens_in(&signer, remaining_accounts, &event_emitter)?;
321
322    let (is_position_removed, transfer_out, should_send_trade_event) =
323        accounts.perform_execution(remaining_accounts, throw_on_execution_error, &event_emitter)?;
324
325    if transfer_out.executed() {
326        accounts.order.load_mut()?.header.completed()?;
327        accounts.process_transfer_out(remaining_accounts, &transfer_out, &event_emitter)?;
328    } else {
329        accounts.order.load_mut()?.header.cancelled()?;
330        accounts.transfer_tokens_out(remaining_accounts, &event_emitter)?;
331    }
332
333    if should_send_trade_event {
334        let event_loader = accounts.event.clone();
335        let event = event_loader
336            .as_ref()
337            .ok_or_else(|| error!(CoreError::EventBufferNotProvided))?
338            .load()?;
339        let event = TradeEventRef::from(&*event);
340        event_emitter.emit_cpi(&event)?;
341    }
342
343    if is_position_removed {
344        msg!("[Position] the position is removed");
345    }
346
347    // It must be placed at the end to be executed correctly.
348    ctx.accounts.pay_execution_fee(execution_fee)?;
349
350    Ok(())
351}
352
353impl<'info> internal::Authentication<'info> for ExecuteIncreaseOrSwapOrder<'info> {
354    fn authority(&self) -> &Signer<'info> {
355        &self.authority
356    }
357
358    fn store(&self) -> &AccountLoader<'info, Store> {
359        &self.store
360    }
361}
362
363impl<'info> ExecuteIncreaseOrSwapOrder<'info> {
364    #[inline(never)]
365    fn transfer_tokens_in(
366        &self,
367        signer: &ActionSigner,
368        remaining_accounts: &'info [AccountInfo<'info>],
369        event_emitter: &EventEmitter<'_, 'info>,
370    ) -> Result<()> {
371        if let Some(escrow) = self.initial_collateral_token_escrow.as_ref() {
372            let store = &self.store.key();
373            let market = self
374                .order
375                .load()?
376                .swap
377                .find_and_unpack_first_market(store, true, remaining_accounts)?
378                .unwrap_or(self.market.clone());
379            let vault = self
380                .initial_collateral_token_vault
381                .as_ref()
382                .ok_or_else(|| error!(CoreError::TokenAccountNotProvided))?;
383            let amount = self.order.load()?.params.initial_collateral_delta_amount;
384            MarketTransferInOperation::builder()
385                .store(&self.store)
386                .from_authority(self.order.to_account_info())
387                .token_program(self.token_program.to_account_info())
388                .signer_seeds(&signer.as_seeds())
389                .market(&market)
390                .from(escrow.to_account_info())
391                .vault(vault)
392                .amount(amount)
393                .event_emitter(*event_emitter)
394                .build()
395                .execute()?;
396        }
397        Ok(())
398    }
399
400    #[inline(never)]
401    fn transfer_tokens_out(
402        &self,
403        remaining_accounts: &'info [AccountInfo<'info>],
404        event_emitter: &EventEmitter<'_, 'info>,
405    ) -> Result<()> {
406        if let Some(escrow) = self.initial_collateral_token_escrow.as_ref() {
407            let store = &self.store.key();
408            let market = self
409                .order
410                .load()?
411                .swap
412                .find_and_unpack_first_market(store, true, remaining_accounts)?
413                .unwrap_or(self.market.clone());
414            let vault = self
415                .initial_collateral_token_vault
416                .as_ref()
417                .ok_or_else(|| error!(CoreError::TokenAccountNotProvided))?;
418            let token = self
419                .initial_collateral_token
420                .as_ref()
421                .ok_or_else(|| error!(CoreError::TokenMintNotProvided))?;
422            let amount = self.order.load()?.params.initial_collateral_delta_amount;
423            MarketTransferOutOperation::builder()
424                .store(&self.store)
425                .token_program(self.token_program.to_account_info())
426                .market(&market)
427                .to(escrow.to_account_info())
428                .vault(vault.to_account_info())
429                .amount(amount)
430                .decimals(token.decimals)
431                .token_mint(token.to_account_info())
432                .event_emitter(*event_emitter)
433                .build()
434                .execute()?;
435        }
436        Ok(())
437    }
438
439    #[inline(never)]
440    fn perform_execution(
441        &mut self,
442        remaining_accounts: &'info [AccountInfo<'info>],
443        throw_on_execution_error: bool,
444        event_emitter: &EventEmitter<'_, 'info>,
445    ) -> Result<(RemovePosition, Box<TransferOut>, ShouldSendTradeEvent)> {
446        // Note: We only need the tokens here, the feeds are not necessary.
447        let feeds = self
448            .order
449            .load()?
450            .swap
451            .to_feeds(&self.token_map.load_token_map()?)
452            .map_err(CoreError::from)?;
453        let ops = ExecuteOrderOperation::builder()
454            .store(&self.store)
455            .market(&self.market)
456            .owner(self.owner.to_account_info())
457            .user(&self.user)
458            .order(&self.order)
459            .position(self.position.as_ref())
460            .event(self.event.as_ref())
461            .throw_on_execution_error(throw_on_execution_error)
462            .executor(self.authority.to_account_info())
463            .event_emitter(*event_emitter);
464
465        self.oracle.load_mut()?.with_prices(
466            &self.store,
467            &self.token_map,
468            &feeds.tokens,
469            remaining_accounts,
470            self.chainlink_program.as_ref(),
471            |oracle, remaining_accounts| {
472                ops.oracle(oracle)
473                    .remaining_accounts(remaining_accounts)
474                    .build()
475                    .execute()
476            },
477        )
478    }
479
480    #[inline(never)]
481    fn process_transfer_out(
482        &self,
483        remaining_accounts: &'info [AccountInfo<'info>],
484        transfer_out: &TransferOut,
485        event_emitter: &EventEmitter<'_, 'info>,
486    ) -> Result<()> {
487        let is_pnl_token_long_token = self.order.load()?.params.side()?.is_long();
488        let final_output_market = self
489            .order
490            .load()?
491            .swap
492            .find_and_unpack_last_market(&self.store.key(), true, remaining_accounts)?
493            .unwrap_or(self.market.clone());
494        ProcessTransferOutOperation::builder()
495            .token_program(self.token_program.to_account_info())
496            .store(&self.store)
497            .market(&self.market)
498            .is_pnl_token_long_token(is_pnl_token_long_token)
499            .final_output_token(self.final_output_token.as_deref())
500            .final_output_market(&final_output_market)
501            .final_output_token_account(
502                self.final_output_token_escrow
503                    .as_ref()
504                    .map(|a| a.to_account_info()),
505            )
506            .final_output_token_vault(self.final_output_token_vault.as_deref())
507            .long_token(self.long_token.as_deref())
508            .long_token_account(self.long_token_escrow.as_ref().map(|a| a.to_account_info()))
509            .long_token_vault(self.long_token_vault.as_deref())
510            .short_token(self.short_token.as_deref())
511            .short_token_account(
512                self.short_token_escrow
513                    .as_ref()
514                    .map(|a| a.to_account_info()),
515            )
516            .short_token_vault(self.short_token_vault.as_deref())
517            .claimable_long_token_account_for_user(None)
518            .claimable_short_token_account_for_user(None)
519            .claimable_pnl_token_account_for_holding(None)
520            .transfer_out(transfer_out)
521            .event_emitter(*event_emitter)
522            .build()
523            .execute()?;
524        Ok(())
525    }
526
527    #[inline(never)]
528    fn pay_execution_fee(&self, execution_fee: u64) -> Result<()> {
529        let execution_lamports = self.order.load()?.execution_lamports(execution_fee);
530        PayExecutionFeeOperation::builder()
531            .payer(self.order.to_account_info())
532            .receiver(self.authority.to_account_info())
533            .execution_lamports(execution_lamports)
534            .build()
535            .execute()?;
536        Ok(())
537    }
538}
539
540/// The accounts definition for [`execute_decrease_order`](crate::gmsol_store::execute_decrease_order)
541/// instruction.
542///
543/// Remaining accounts expected by this instruction:
544///   - 0..M. `[]` M feed accounts, where M represents the total number of tokens in the
545///     swap params.
546///   - M..M+N. `[writable]` N market accounts, where N represents the total number of unique
547///     markets excluding the current market in the swap params.
548#[event_cpi]
549#[derive(Accounts)]
550#[instruction(recent_timestamp: i64)]
551pub struct ExecuteDecreaseOrder<'info> {
552    /// Authority.
553    pub authority: Signer<'info>,
554    /// Store.
555    #[account(mut, has_one = token_map)]
556    pub store: AccountLoader<'info, Store>,
557    /// Token Map.
558    #[account(has_one = store)]
559    pub token_map: AccountLoader<'info, TokenMapHeader>,
560    /// Oracle buffer to use.
561    #[account(mut, has_one = store)]
562    pub oracle: AccountLoader<'info, Oracle>,
563    /// Market.
564    #[account(mut, has_one = store)]
565    pub market: AccountLoader<'info, Market>,
566    /// The owner of the order.
567    /// CHECK: only used to receive fund.
568    #[account(mut)]
569    pub owner: UncheckedAccount<'info>,
570    /// User Account.
571    #[account(
572        mut,
573        constraint = user.load()?.is_initialized() @ CoreError::InvalidUserAccount,
574        has_one = owner,
575        has_one = store,
576        seeds = [UserHeader::SEED, store.key().as_ref(), owner.key().as_ref()],
577        bump = user.load()?.bump,
578    )]
579    pub user: AccountLoader<'info, UserHeader>,
580    /// Order to execute.
581    #[account(
582        mut,
583        constraint = order.load()?.header.store == store.key() @ CoreError::StoreMismatched,
584        constraint = order.load()?.header.market == market.key() @ CoreError::MarketMismatched,
585        constraint = order.load()?.header.owner == owner.key() @ CoreError::OwnerMismatched,
586        constraint = order.load()?.params.position().copied() == Some(position.key()) @ CoreError::PositionMismatched,
587        constraint = order.load()?.tokens.final_output_token.account() == Some(final_output_token_escrow.key()) @ CoreError::TokenAccountMismatched,
588        constraint = order.load()?.tokens.long_token.account() == Some(long_token_escrow.key()) @ CoreError::TokenAccountMismatched,
589        constraint = order.load()?.tokens.short_token.account() == Some(short_token_escrow.key()) @ CoreError::TokenAccountMismatched,
590    )]
591    pub order: AccountLoader<'info, Order>,
592    #[account(
593        mut,
594        constraint = position.load()?.owner == order.load()?.header.owner,
595        constraint = position.load()?.store == store.key(),
596        seeds = [
597            Position::SEED,
598            store.key().as_ref(),
599            order.load()?.header.owner.as_ref(),
600            position.load()?.market_token.as_ref(),
601            position.load()?.collateral_token.as_ref(),
602            &[position.load()?.kind],
603        ],
604        bump = position.load()?.bump,
605    )]
606    pub position: AccountLoader<'info, Position>,
607    /// Trade event buffer.
608    #[account(mut, has_one = store, has_one = authority)]
609    pub event: AccountLoader<'info, TradeData>,
610    /// Final output token.
611    pub final_output_token: Box<Account<'info, Mint>>,
612    /// Long token.
613    pub long_token: Box<Account<'info, Mint>>,
614    /// Short token.
615    pub short_token: Box<Account<'info, Mint>>,
616    /// The escrow account for final output tokens.
617    #[account(
618        mut,
619        associated_token::mint = final_output_token,
620        associated_token::authority = order,
621    )]
622    pub final_output_token_escrow: Box<Account<'info, TokenAccount>>,
623    /// The escrow account for long tokens.
624    #[account(
625        mut,
626        associated_token::mint = long_token,
627        associated_token::authority = order,
628    )]
629    pub long_token_escrow: Box<Account<'info, TokenAccount>>,
630    /// The escrow account for short tokens.
631    #[account(
632        mut,
633        associated_token::mint = short_token,
634        associated_token::authority = order,
635    )]
636    pub short_token_escrow: Box<Account<'info, TokenAccount>>,
637    /// Final output token vault.
638    #[account(
639        mut,
640        token::mint = final_output_token,
641        token::authority = store,
642        seeds = [
643            constants::MARKET_VAULT_SEED,
644            store.key().as_ref(),
645            final_output_token_vault.mint.as_ref(),
646        ],
647        bump,
648    )]
649    pub final_output_token_vault: Box<Account<'info, TokenAccount>>,
650    /// Long token vault.
651    #[account(
652        mut,
653        token::mint = long_token,
654        token::authority = store,
655        seeds = [
656            constants::MARKET_VAULT_SEED,
657            store.key().as_ref(),
658            long_token_vault.mint.as_ref(),
659        ],
660        bump,
661    )]
662    pub long_token_vault: Box<Account<'info, TokenAccount>>,
663    /// Short token vault.
664    #[account(
665        mut,
666        token::mint = short_token,
667        token::authority = store,
668        seeds = [
669            constants::MARKET_VAULT_SEED,
670            store.key().as_ref(),
671            short_token_vault.mint.as_ref(),
672        ],
673        bump,
674    )]
675    pub short_token_vault: Box<Account<'info, TokenAccount>>,
676    #[account(
677        mut,
678        token::mint = market.load()?.meta().long_token_mint,
679        token::authority = store,
680        constraint = check_delegation(&claimable_long_token_account_for_user, order.load()?.header.owner)?,
681        seeds = [
682            constants::CLAIMABLE_ACCOUNT_SEED,
683            store.key().as_ref(),
684            market.load()?.meta().long_token_mint.as_ref(),
685            order.load()?.header.owner.as_ref(),
686            &store.load()?.claimable_time_key(validated_recent_timestamp(store.load()?.deref(), recent_timestamp)?)?,
687        ],
688        bump,
689    )]
690    pub claimable_long_token_account_for_user: Box<Account<'info, TokenAccount>>,
691    #[account(
692        mut,
693        token::mint = market.load()?.meta().short_token_mint,
694        token::authority = store,
695        constraint = check_delegation(&claimable_short_token_account_for_user, order.load()?.header.owner)?,
696        seeds = [
697            constants::CLAIMABLE_ACCOUNT_SEED,
698            store.key().as_ref(),
699            market.load()?.meta().short_token_mint.as_ref(),
700            order.load()?.header.owner.as_ref(),
701            &store.load()?.claimable_time_key(validated_recent_timestamp(store.load()?.deref(), recent_timestamp)?)?,
702        ],
703        bump,
704    )]
705    pub claimable_short_token_account_for_user: Box<Account<'info, TokenAccount>>,
706    #[account(
707        mut,
708        token::mint = get_pnl_token(&Some(position.clone()), market.load()?.deref())?,
709        token::authority = store,
710        constraint = check_delegation(&claimable_pnl_token_account_for_holding, store.load()?.address.holding)?,
711        seeds = [
712            constants::CLAIMABLE_ACCOUNT_SEED,
713            store.key().as_ref(),
714            get_pnl_token(&Some(position.clone()), market.load()?.deref())?.as_ref(),
715            store.load()?.address.holding.as_ref(),
716            &store.load()?.claimable_time_key(validated_recent_timestamp(store.load()?.deref(), recent_timestamp)?)?,
717        ],
718        bump,
719    )]
720    pub claimable_pnl_token_account_for_holding: Box<Account<'info, TokenAccount>>,
721    /// The token program.
722    pub token_program: Program<'info, Token>,
723    /// The system program.
724    pub system_program: Program<'info, System>,
725    /// Chainlink Program.
726    pub chainlink_program: Option<Program<'info, Chainlink>>,
727}
728
729pub(crate) fn unchecked_execute_decrease_order<'info>(
730    mut ctx: Context<'_, '_, 'info, 'info, ExecuteDecreaseOrder<'info>>,
731    _recent_timestamp: i64,
732    execution_fee: u64,
733    throw_on_execution_error: bool,
734) -> Result<()> {
735    let accounts = &mut ctx.accounts;
736    let remaining_accounts = ctx.remaining_accounts;
737
738    let kind = accounts.order.load()?.params().kind()?;
739
740    // Validate the order kind.
741    require!(kind.is_decrease_position(), CoreError::InvalidArgument);
742
743    // Validate feature enabled.
744    accounts.store.load()?.validate_feature_enabled(
745        kind.try_into()
746            .map_err(CoreError::from)
747            .map_err(|err| error!(err))?,
748        ActionDisabledFlag::Execute,
749    )?;
750
751    let event_authority = accounts.event_authority.clone();
752    let event_emitter = EventEmitter::new(&event_authority, ctx.bumps.event_authority);
753    let (is_position_removed, transfer_out, should_send_trade_event) =
754        accounts.perform_execution(remaining_accounts, throw_on_execution_error, &event_emitter)?;
755
756    if transfer_out.executed() {
757        accounts.order.load_mut()?.header.completed()?;
758        accounts.process_transfer_out(remaining_accounts, &transfer_out, &event_emitter)?;
759    } else {
760        accounts.order.load_mut()?.header.cancelled()?;
761    }
762
763    if should_send_trade_event {
764        let event_loader = accounts.event.clone();
765        let event = event_loader.load()?;
766        let event = TradeEventRef::from(&*event);
767        event_emitter.emit_cpi(&event)?;
768    }
769
770    if is_position_removed {
771        msg!("[Position] the position is removed");
772    }
773
774    // It must be placed at the end to be executed correctly.
775    ctx.accounts.pay_execution_fee(execution_fee)?;
776
777    Ok(())
778}
779
780impl<'info> internal::Authentication<'info> for ExecuteDecreaseOrder<'info> {
781    fn authority(&self) -> &Signer<'info> {
782        &self.authority
783    }
784
785    fn store(&self) -> &AccountLoader<'info, Store> {
786        &self.store
787    }
788}
789
790impl<'info> ExecuteDecreaseOrder<'info> {
791    #[inline(never)]
792    fn perform_execution(
793        &mut self,
794        remaining_accounts: &'info [AccountInfo<'info>],
795        throw_on_execution_error: bool,
796        event_emitter: &EventEmitter<'_, 'info>,
797    ) -> Result<(RemovePosition, Box<TransferOut>, ShouldSendTradeEvent)> {
798        // Note: We only need the tokens here, the feeds are not necessary.
799        let feeds = self
800            .order
801            .load()?
802            .swap
803            .to_feeds(&self.token_map.load_token_map()?)
804            .map_err(CoreError::from)?;
805        let ops = ExecuteOrderOperation::builder()
806            .store(&self.store)
807            .market(&self.market)
808            .owner(self.owner.to_account_info())
809            .user(&self.user)
810            .order(&self.order)
811            .position(Some(&self.position))
812            .event(Some(&self.event))
813            .throw_on_execution_error(throw_on_execution_error)
814            .executor(self.authority.to_account_info())
815            .event_emitter(*event_emitter);
816
817        self.oracle.load_mut()?.with_prices(
818            &self.store,
819            &self.token_map,
820            &feeds.tokens,
821            remaining_accounts,
822            self.chainlink_program.as_ref(),
823            #[inline(never)]
824            |oracle, remaining_accounts| {
825                ops.oracle(oracle)
826                    .remaining_accounts(remaining_accounts)
827                    .build()
828                    .execute()
829            },
830        )
831    }
832
833    #[inline(never)]
834    fn process_transfer_out(
835        &self,
836        remaining_accounts: &'info [AccountInfo<'info>],
837        transfer_out: &TransferOut,
838        event_emitter: &EventEmitter<'_, 'info>,
839    ) -> Result<()> {
840        let is_pnl_token_long_token = self.order.load()?.params.side()?.is_long();
841        let final_output_market = self
842            .order
843            .load()?
844            .swap
845            .find_and_unpack_last_market(&self.store.key(), true, remaining_accounts)?
846            .unwrap_or(self.market.clone());
847        ProcessTransferOutOperation::builder()
848            .token_program(self.token_program.to_account_info())
849            .store(&self.store)
850            .market(&self.market)
851            .is_pnl_token_long_token(is_pnl_token_long_token)
852            .final_output_market(&final_output_market)
853            .final_output_token(Some(&self.final_output_token))
854            .final_output_token_account(Some(self.final_output_token_escrow.to_account_info()))
855            .final_output_token_vault(Some(&*self.final_output_token_vault))
856            .long_token(Some(&self.long_token))
857            .long_token_account(Some(self.long_token_escrow.to_account_info()))
858            .long_token_vault(Some(&*self.long_token_vault))
859            .short_token(Some(&self.short_token))
860            .short_token_account(Some(self.short_token_escrow.to_account_info()))
861            .short_token_vault(Some(&*self.short_token_vault))
862            .claimable_long_token_account_for_user(Some(
863                self.claimable_long_token_account_for_user.to_account_info(),
864            ))
865            .claimable_short_token_account_for_user(Some(
866                self.claimable_short_token_account_for_user
867                    .to_account_info(),
868            ))
869            .claimable_pnl_token_account_for_holding(Some(
870                self.claimable_pnl_token_account_for_holding
871                    .to_account_info(),
872            ))
873            .transfer_out(transfer_out)
874            .event_emitter(*event_emitter)
875            .build()
876            .execute()?;
877        Ok(())
878    }
879
880    #[inline(never)]
881    fn pay_execution_fee(&self, execution_fee: u64) -> Result<()> {
882        let execution_lamports = self.order.load()?.execution_lamports(execution_fee);
883        PayExecutionFeeOperation::builder()
884            .payer(self.order.to_account_info())
885            .receiver(self.authority.to_account_info())
886            .execution_lamports(execution_lamports)
887            .build()
888            .execute()?;
889        Ok(())
890    }
891}