gmsol_store/instructions/exchange/
execute_deposit.rs

1use anchor_lang::prelude::*;
2use anchor_spl::token::{Mint, Token, TokenAccount};
3
4use crate::{
5    constants,
6    events::EventEmitter,
7    ops::{
8        deposit::ExecuteDepositOperation,
9        execution_fee::PayExecutionFeeOperation,
10        market::{MarketTransferInOperation, MarketTransferOutOperation},
11    },
12    states::{
13        common::{
14            action::{ActionExt, ActionSigner},
15            swap::SwapActionParamsExt,
16        },
17        feature::{ActionDisabledFlag, DomainDisabledFlag},
18        Chainlink, Deposit, Market, Oracle, Seed, Store, TokenMapHeader, TokenMapLoader,
19    },
20    utils::internal,
21    CoreError,
22};
23
24/// The accounts definition for [`execute_deposit`](crate::gmsol_store::execute_deposit) instruction.
25///
26/// Remaining accounts expected by this instruction:
27///
28///   - 0..M. `[]` M feed accounts, where M represents the total number of tokens in the
29///     swap params.
30///   - M..M+N. `[writable]` N market accounts, where N represents the total number of unique
31///     markets excluding the current market in the swap params.
32#[event_cpi]
33#[derive(Accounts)]
34pub struct ExecuteDeposit<'info> {
35    /// Authority.
36    pub authority: Signer<'info>,
37    /// Store.
38    #[account(has_one = token_map)]
39    pub store: AccountLoader<'info, Store>,
40    /// Token Map.
41    #[account(has_one = store)]
42    pub token_map: AccountLoader<'info, TokenMapHeader>,
43    /// Oracle buffer to use.
44    #[account(mut, has_one = store)]
45    pub oracle: AccountLoader<'info, Oracle>,
46    /// Market.
47    #[account(mut, has_one = store)]
48    pub market: AccountLoader<'info, Market>,
49    /// The deposit to execute.
50    #[account(
51        mut,
52        constraint = deposit.load()?.header.market == market.key() @ CoreError::MarketMismatched,
53        constraint = deposit.load()?.header.store == store.key() @ CoreError::StoreMismatched,
54        constraint = deposit.load()?.tokens.market_token.account().expect("must exist") == market_token_escrow.key() @ CoreError::MarketTokenAccountMismatched,
55        constraint = deposit.load()?.tokens.initial_long_token.account() == initial_long_token_escrow.as_ref().map(|a| a.key()) @ CoreError::TokenAccountMismatched,
56        constraint = deposit.load()?.tokens.initial_short_token.account() == initial_short_token_escrow.as_ref().map(|a| a.key()) @ CoreError::TokenAccountMismatched,
57        seeds = [Deposit::SEED, store.key().as_ref(), deposit.load()?.header.owner.as_ref(), &deposit.load()?.header.nonce],
58        bump = deposit.load()?.header.bump,
59    )]
60    pub deposit: AccountLoader<'info, Deposit>,
61    /// Market token mint.
62    #[account(mut, constraint = market.load()?.meta().market_token_mint == market_token.key() @ CoreError::MarketTokenMintMismatched)]
63    pub market_token: Box<Account<'info, Mint>>,
64    /// Initial long token.
65    #[account(
66        constraint = deposit.load()?.tokens.initial_long_token.token().map(|token| initial_long_token.key() == token).unwrap_or(true) @ CoreError::TokenMintMismatched
67    )]
68    pub initial_long_token: Option<Box<Account<'info, Mint>>>,
69    /// Initial short token.
70    #[account(
71        constraint = deposit.load()?.tokens.initial_short_token.token().map(|token| initial_short_token.key() == token).unwrap_or(true) @ CoreError::TokenMintMismatched
72    )]
73    pub initial_short_token: Option<Box<Account<'info, Mint>>>,
74    /// The escrow account for receving market tokens.
75    #[account(
76        mut,
77        associated_token::mint = market_token,
78        associated_token::authority = deposit,
79    )]
80    pub market_token_escrow: Box<Account<'info, TokenAccount>>,
81    /// The escrow account for receiving initial long token for deposit.
82    #[account(
83        mut,
84        associated_token::mint = initial_long_token,
85        associated_token::authority = deposit,
86    )]
87    pub initial_long_token_escrow: Option<Box<Account<'info, TokenAccount>>>,
88    /// The escrow account for receiving initial short token for deposit.
89    #[account(
90        mut,
91        associated_token::mint = initial_short_token,
92        associated_token::authority = deposit,
93    )]
94    pub initial_short_token_escrow: Option<Box<Account<'info, TokenAccount>>>,
95    /// Initial long token vault.
96    #[account(
97        mut,
98        token::mint = initial_long_token,
99        token::authority = store,
100        seeds = [
101            constants::MARKET_VAULT_SEED,
102            store.key().as_ref(),
103            initial_long_token_vault.mint.as_ref(),
104        ],
105        bump,
106    )]
107    pub initial_long_token_vault: Option<Box<Account<'info, TokenAccount>>>,
108    /// Initial short token vault.
109    #[account(
110        mut,
111        token::mint = initial_short_token,
112        token::authority = store,
113        seeds = [
114            constants::MARKET_VAULT_SEED,
115            store.key().as_ref(),
116            initial_short_token_vault.mint.as_ref(),
117        ],
118        bump,
119    )]
120    pub initial_short_token_vault: Option<Box<Account<'info, TokenAccount>>>,
121    /// The token program.
122    pub token_program: Program<'info, Token>,
123    /// The system program.
124    pub system_program: Program<'info, System>,
125    /// Chainlink Program.
126    pub chainlink_program: Option<Program<'info, Chainlink>>,
127}
128
129/// CHECK: only ORDER_KEEPER can invoke this instruction.
130#[inline(never)]
131pub(crate) fn unchecked_execute_deposit<'info>(
132    ctx: Context<'_, '_, 'info, 'info, ExecuteDeposit<'info>>,
133    execution_fee: u64,
134    throw_on_execution_error: bool,
135) -> Result<()> {
136    let accounts = ctx.accounts;
137    let remaining_accounts = ctx.remaining_accounts;
138
139    // Validate feature enabled.
140    accounts
141        .store
142        .load()?
143        .validate_feature_enabled(DomainDisabledFlag::Deposit, ActionDisabledFlag::Execute)?;
144
145    let signer = accounts.deposit.load()?.signer();
146
147    let event_authority = accounts.event_authority.clone();
148    let event_emitter = EventEmitter::new(&event_authority, ctx.bumps.event_authority);
149
150    accounts.transfer_tokens_in(&signer, remaining_accounts, &event_emitter)?;
151
152    let executed =
153        accounts.perform_execution(remaining_accounts, throw_on_execution_error, &event_emitter)?;
154
155    if executed {
156        accounts.deposit.load_mut()?.header.completed()?;
157    } else {
158        accounts.deposit.load_mut()?.header.cancelled()?;
159        accounts.transfer_tokens_out(remaining_accounts, &event_emitter)?;
160    }
161
162    // It must be placed at the end to be executed correctly.
163    accounts.pay_execution_fee(execution_fee)?;
164
165    Ok(())
166}
167
168impl<'info> internal::Authentication<'info> for ExecuteDeposit<'info> {
169    fn authority(&self) -> &Signer<'info> {
170        &self.authority
171    }
172
173    fn store(&self) -> &AccountLoader<'info, Store> {
174        &self.store
175    }
176}
177
178impl<'info> ExecuteDeposit<'info> {
179    #[inline(never)]
180    fn pay_execution_fee(&self, execution_fee: u64) -> Result<()> {
181        let execution_lamports = self.deposit.load()?.execution_lamports(execution_fee);
182        PayExecutionFeeOperation::builder()
183            .payer(self.deposit.to_account_info())
184            .receiver(self.authority.to_account_info())
185            .execution_lamports(execution_lamports)
186            .build()
187            .execute()?;
188        Ok(())
189    }
190
191    #[inline(never)]
192    fn transfer_tokens_in(
193        &self,
194        signer: &ActionSigner,
195        remaining_accounts: &'info [AccountInfo<'info>],
196        event_emitter: &EventEmitter<'_, 'info>,
197    ) -> Result<()> {
198        let seeds = signer.as_seeds();
199
200        let builder = MarketTransferInOperation::builder()
201            .store(&self.store)
202            .from_authority(self.deposit.to_account_info())
203            .token_program(self.token_program.to_account_info())
204            .signer_seeds(&seeds)
205            .event_emitter(*event_emitter);
206
207        let store = &self.store.key();
208
209        if let Some(escrow) = self.initial_long_token_escrow.as_ref() {
210            let market = self
211                .deposit
212                .load()?
213                .swap
214                .find_and_unpack_first_market(store, true, remaining_accounts)?
215                .unwrap_or(self.market.clone());
216            let vault = self
217                .initial_long_token_vault
218                .as_ref()
219                .ok_or_else(|| error!(CoreError::TokenAccountNotProvided))?;
220            builder
221                .clone()
222                .market(&market)
223                .from(escrow.to_account_info())
224                .vault(vault)
225                .amount(self.deposit.load()?.params.initial_long_token_amount)
226                .build()
227                .execute()?;
228        }
229
230        if let Some(escrow) = self.initial_short_token_escrow.as_ref() {
231            let market = self
232                .deposit
233                .load()?
234                .swap
235                .find_and_unpack_first_market(store, false, remaining_accounts)?
236                .unwrap_or(self.market.clone());
237            let vault = self
238                .initial_short_token_vault
239                .as_ref()
240                .ok_or_else(|| error!(CoreError::TokenAccountNotProvided))?;
241            builder
242                .clone()
243                .market(&market)
244                .from(escrow.to_account_info())
245                .vault(vault)
246                .amount(self.deposit.load()?.params.initial_short_token_amount)
247                .build()
248                .execute()?;
249        }
250
251        Ok(())
252    }
253
254    #[inline(never)]
255    fn transfer_tokens_out(
256        &self,
257        remaining_accounts: &'info [AccountInfo<'info>],
258        event_emitter: &EventEmitter<'_, 'info>,
259    ) -> Result<()> {
260        let builder = MarketTransferOutOperation::builder()
261            .store(&self.store)
262            .token_program(self.token_program.to_account_info())
263            .event_emitter(*event_emitter);
264
265        let store = &self.store.key();
266
267        if let Some(escrow) = self.initial_long_token_escrow.as_ref() {
268            let market = self
269                .deposit
270                .load()?
271                .swap
272                .find_and_unpack_first_market(store, true, remaining_accounts)?
273                .unwrap_or(self.market.clone());
274            let vault = self
275                .initial_long_token_vault
276                .as_ref()
277                .ok_or_else(|| error!(CoreError::TokenAccountNotProvided))?;
278            let token = self
279                .initial_long_token
280                .as_ref()
281                .ok_or_else(|| error!(CoreError::TokenMintNotProvided))?;
282            builder
283                .clone()
284                .market(&market)
285                .to(escrow.to_account_info())
286                .vault(vault.to_account_info())
287                .amount(self.deposit.load()?.params.initial_long_token_amount)
288                .decimals(token.decimals)
289                .token_mint(token.to_account_info())
290                .build()
291                .execute()?;
292        }
293
294        if let Some(escrow) = self.initial_short_token_escrow.as_ref() {
295            let market = self
296                .deposit
297                .load()?
298                .swap
299                .find_and_unpack_first_market(store, false, remaining_accounts)?
300                .unwrap_or(self.market.clone());
301            let vault = self
302                .initial_short_token_vault
303                .as_ref()
304                .ok_or_else(|| error!(CoreError::TokenAccountNotProvided))?;
305            let token = self
306                .initial_short_token
307                .as_ref()
308                .ok_or_else(|| error!(CoreError::TokenMintNotProvided))?;
309            builder
310                .market(&market)
311                .to(escrow.to_account_info())
312                .vault(vault.to_account_info())
313                .amount(self.deposit.load()?.params.initial_short_token_amount)
314                .decimals(token.decimals)
315                .token_mint(token.to_account_info())
316                .build()
317                .execute()?;
318        }
319
320        Ok(())
321    }
322
323    #[inline(never)]
324    fn perform_execution(
325        &mut self,
326        remaining_accounts: &'info [AccountInfo<'info>],
327        throw_on_execution_error: bool,
328        event_emitter: &EventEmitter<'_, 'info>,
329    ) -> Result<bool> {
330        // Note: We only need the tokens here, the feeds are not necessary.
331        let feeds = self
332            .deposit
333            .load()?
334            .swap()
335            .to_feeds(&self.token_map.load_token_map()?)
336            .map_err(CoreError::from)?;
337        let ops = ExecuteDepositOperation::builder()
338            .store(&self.store)
339            .market(&self.market)
340            .deposit(&self.deposit)
341            .market_token_mint(&mut self.market_token)
342            .market_token_receiver(self.market_token_escrow.to_account_info())
343            .token_program(self.token_program.to_account_info())
344            .throw_on_execution_error(throw_on_execution_error)
345            .event_emitter(*event_emitter);
346
347        let executed = self.oracle.load_mut()?.with_prices(
348            &self.store,
349            &self.token_map,
350            &feeds.tokens,
351            remaining_accounts,
352            self.chainlink_program.as_ref(),
353            |oracle, remaining_accounts| {
354                ops.oracle(oracle)
355                    .remaining_accounts(remaining_accounts)
356                    .build()
357                    .execute()
358            },
359        )?;
360
361        Ok(executed)
362    }
363}