gmsol_store/instructions/exchange/
execute_deposit.rs1use 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#[event_cpi]
33#[derive(Accounts)]
34pub struct ExecuteDeposit<'info> {
35 pub authority: Signer<'info>,
37 #[account(has_one = token_map)]
39 pub store: AccountLoader<'info, Store>,
40 #[account(has_one = store)]
42 pub token_map: AccountLoader<'info, TokenMapHeader>,
43 #[account(mut, has_one = store)]
45 pub oracle: AccountLoader<'info, Oracle>,
46 #[account(mut, has_one = store)]
48 pub market: AccountLoader<'info, Market>,
49 #[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 #[account(mut, constraint = market.load()?.meta().market_token_mint == market_token.key() @ CoreError::MarketTokenMintMismatched)]
63 pub market_token: Box<Account<'info, Mint>>,
64 #[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 #[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 #[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 #[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 #[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 #[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 #[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 pub token_program: Program<'info, Token>,
123 pub system_program: Program<'info, System>,
125 pub chainlink_program: Option<Program<'info, Chainlink>>,
127}
128
129#[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 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 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 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}