1use std::{
2 collections::{BTreeSet, HashMap},
3 ops::Deref,
4};
5
6use anchor_client::{
7 anchor_lang::{prelude::AccountMeta, system_program},
8 solana_sdk::{address_lookup_table::AddressLookupTableAccount, pubkey::Pubkey, signer::Signer},
9};
10use anchor_spl::associated_token::get_associated_token_address_with_program_id;
11use gmsol_solana_utils::{
12 bundle_builder::{BundleBuilder, BundleOptions},
13 compute_budget::ComputeBudget,
14 transaction_builder::TransactionBuilder,
15};
16use gmsol_store::{
17 accounts, instruction,
18 ops::glv::CreateGlvWithdrawalParams,
19 states::{
20 common::{action::Action, swap::SwapActionParams, TokensWithFeed},
21 glv::GlvWithdrawal,
22 Glv, HasMarketMeta, NonceBytes, PriceProviderKind, TokenMapAccess,
23 },
24};
25
26use crate::{
27 exchange::{generate_nonce, get_ata_or_owner_with_program_id},
28 store::{token::TokenAccountOps, utils::FeedsParser},
29 utils::{
30 builder::{
31 FeedAddressMap, FeedIds, MakeBundleBuilder, PullOraclePriceConsumer, SetExecutionFee,
32 },
33 fix_optional_account_metas, ZeroCopy,
34 },
35};
36
37use super::{split_to_accounts, GlvOps};
38
39pub const EXECUTE_GLV_WITHDRAWAL_COMPUTE_BUDGET: u32 = 800_000;
40
41pub struct CreateGlvWithdrawalBuilder<'a, C> {
43 client: &'a crate::Client<C>,
44 store: Pubkey,
45 glv_token: Pubkey,
46 market_token: Pubkey,
47 final_long_token: Option<Pubkey>,
48 final_short_token: Option<Pubkey>,
49 long_token_swap_path: Vec<Pubkey>,
50 short_token_swap_path: Vec<Pubkey>,
51 glv_token_amount: u64,
52 min_final_long_token_amount: u64,
53 min_final_short_token_amount: u64,
54 max_execution_lamports: u64,
55 nonce: Option<NonceBytes>,
56 glv_token_source: Option<Pubkey>,
57 hint: Option<CreateGlvWithdrawalHint>,
58 should_unwrap_native_token: bool,
59 receiver: Pubkey,
60}
61
62#[derive(Clone)]
64pub struct CreateGlvWithdrawalHint {
65 long_token_mint: Pubkey,
66 short_token_mint: Pubkey,
67}
68
69impl CreateGlvWithdrawalHint {
70 pub fn new(meta: &impl HasMarketMeta) -> Self {
72 let meta = meta.market_meta();
73 Self {
74 long_token_mint: meta.long_token_mint,
75 short_token_mint: meta.short_token_mint,
76 }
77 }
78}
79
80impl<'a, C: Deref<Target = impl Signer> + Clone> CreateGlvWithdrawalBuilder<'a, C> {
81 pub(super) fn new(
82 client: &'a crate::Client<C>,
83 store: Pubkey,
84 glv_token: Pubkey,
85 market_token: Pubkey,
86 amount: u64,
87 ) -> Self {
88 Self {
89 client,
90 store,
91 glv_token,
92 market_token,
93 final_long_token: None,
94 final_short_token: None,
95 long_token_swap_path: vec![],
96 short_token_swap_path: vec![],
97 glv_token_amount: amount,
98 min_final_long_token_amount: 0,
99 min_final_short_token_amount: 0,
100 max_execution_lamports: GlvWithdrawal::MIN_EXECUTION_LAMPORTS,
101 nonce: None,
102 glv_token_source: None,
103 hint: None,
104 should_unwrap_native_token: true,
105 receiver: client.payer(),
106 }
107 }
108
109 pub fn nonce(&mut self, nonce: NonceBytes) -> &mut Self {
111 self.nonce = Some(nonce);
112 self
113 }
114
115 pub fn max_execution_fee(&mut self, lamports: u64) -> &mut Self {
117 self.max_execution_lamports = lamports;
118 self
119 }
120
121 pub fn final_long_token(
123 &mut self,
124 token: Option<&Pubkey>,
125 min_amount: u64,
126 swap_path: Vec<Pubkey>,
127 ) -> &mut Self {
128 self.final_long_token = token.copied();
129 self.min_final_long_token_amount = min_amount;
130 self.long_token_swap_path = swap_path;
131 self
132 }
133
134 pub fn final_short_token(
136 &mut self,
137 token: Option<&Pubkey>,
138 min_amount: u64,
139 swap_path: Vec<Pubkey>,
140 ) -> &mut Self {
141 self.final_short_token = token.copied();
142 self.min_final_short_token_amount = min_amount;
143 self.short_token_swap_path = swap_path;
144 self
145 }
146
147 pub fn glv_token_source(&mut self, address: &Pubkey) -> &mut Self {
149 self.glv_token_source = Some(*address);
150 self
151 }
152
153 pub fn hint(&mut self, hint: CreateGlvWithdrawalHint) -> &mut Self {
155 self.hint = Some(hint);
156 self
157 }
158
159 pub fn should_unwrap_native_token(&mut self, should_unwrap: bool) -> &mut Self {
162 self.should_unwrap_native_token = should_unwrap;
163 self
164 }
165
166 pub fn receiver(&mut self, receiver: Option<Pubkey>) -> &mut Self {
169 self.receiver = receiver.unwrap_or(self.client.payer());
170 self
171 }
172
173 fn market_address(&self) -> Pubkey {
174 self.client
175 .find_market_address(&self.store, &self.market_token)
176 }
177
178 pub async fn prepare_hint(&mut self) -> crate::Result<CreateGlvWithdrawalHint> {
180 match &self.hint {
181 Some(hint) => Ok(hint.clone()),
182 None => {
183 let market = self.market_address();
184 let market = self.client.market(&market).await?;
185 let hint = CreateGlvWithdrawalHint::new(&*market);
186 self.hint = Some(hint.clone());
187 Ok(hint)
188 }
189 }
190 }
191
192 pub async fn build_with_address(
194 &mut self,
195 ) -> crate::Result<(TransactionBuilder<'a, C>, Pubkey)> {
196 let hint = self.prepare_hint().await?;
197
198 let nonce = self.nonce.unwrap_or_else(generate_nonce);
199 let owner = self.client.payer();
200 let receiver = self.receiver;
201 let glv_withdrawal = self
202 .client
203 .find_glv_withdrawal_address(&self.store, &owner, &nonce);
204 let market = self.market_address();
205 let glv = self.client.find_glv_address(&self.glv_token);
206 let token_program_id = anchor_spl::token::ID;
207 let glv_token_program_id = anchor_spl::token_2022::ID;
208
209 let final_long_token = self.final_long_token.unwrap_or(hint.long_token_mint);
210 let final_short_token = self.final_short_token.unwrap_or(hint.short_token_mint);
211
212 let glv_token_source = self.glv_token_source.unwrap_or_else(|| {
213 get_associated_token_address_with_program_id(
214 &owner,
215 &self.glv_token,
216 &glv_token_program_id,
217 )
218 });
219
220 let glv_token_escrow = get_associated_token_address_with_program_id(
221 &glv_withdrawal,
222 &self.glv_token,
223 &glv_token_program_id,
224 );
225 let market_token_escrow = get_associated_token_address_with_program_id(
226 &glv_withdrawal,
227 &self.market_token,
228 &token_program_id,
229 );
230 let final_long_token_escrow = get_associated_token_address_with_program_id(
231 &glv_withdrawal,
232 &final_long_token,
233 &token_program_id,
234 );
235 let final_short_token_escrow = get_associated_token_address_with_program_id(
236 &glv_withdrawal,
237 &final_short_token,
238 &token_program_id,
239 );
240
241 let mut prepare = self.client.prepare_associated_token_account(
243 &final_long_token,
244 &token_program_id,
245 Some(&receiver),
246 );
247
248 prepare = prepare.merge(self.client.prepare_associated_token_account(
250 &final_short_token,
251 &token_program_id,
252 Some(&receiver),
253 ));
254
255 prepare = prepare.merge(self.client.prepare_associated_token_account(
257 &self.glv_token,
258 &glv_token_program_id,
259 Some(&glv_withdrawal),
260 ));
261
262 prepare = prepare.merge(self.client.prepare_associated_token_account(
264 &self.market_token,
265 &token_program_id,
266 Some(&glv_withdrawal),
267 ));
268
269 prepare = prepare.merge(self.client.prepare_associated_token_account(
271 &final_long_token,
272 &token_program_id,
273 Some(&glv_withdrawal),
274 ));
275 prepare = prepare.merge(self.client.prepare_associated_token_account(
277 &final_short_token,
278 &token_program_id,
279 Some(&glv_withdrawal),
280 ));
281
282 let create = self
283 .client
284 .store_transaction()
285 .anchor_accounts(accounts::CreateGlvWithdrawal {
286 owner,
287 receiver,
288 store: self.store,
289 market,
290 glv,
291 glv_withdrawal,
292 glv_token: self.glv_token,
293 market_token: self.market_token,
294 final_long_token,
295 final_short_token,
296 glv_token_source,
297 glv_token_escrow,
298 market_token_escrow,
299 final_long_token_escrow,
300 final_short_token_escrow,
301 system_program: system_program::ID,
302 token_program: token_program_id,
303 glv_token_program: glv_token_program_id,
304 associated_token_program: anchor_spl::associated_token::ID,
305 })
306 .anchor_args(instruction::CreateGlvWithdrawal {
307 nonce,
308 params: CreateGlvWithdrawalParams {
309 execution_lamports: self.max_execution_lamports,
310 long_token_swap_length: self
311 .long_token_swap_path
312 .len()
313 .try_into()
314 .map_err(|_| crate::Error::invalid_argument("swap path too long"))?,
315 short_token_swap_length: self
316 .short_token_swap_path
317 .len()
318 .try_into()
319 .map_err(|_| crate::Error::invalid_argument("swap path too long"))?,
320 glv_token_amount: self.glv_token_amount,
321 min_final_long_token_amount: self.min_final_long_token_amount,
322 min_final_short_token_amount: self.min_final_short_token_amount,
323 should_unwrap_native_token: self.should_unwrap_native_token,
324 },
325 })
326 .accounts(
327 self.long_token_swap_path
328 .iter()
329 .chain(self.short_token_swap_path.iter())
330 .map(|token| AccountMeta {
331 pubkey: self.client.find_market_address(&self.store, token),
332 is_signer: false,
333 is_writable: false,
334 })
335 .collect::<Vec<_>>(),
336 );
337
338 Ok((prepare.merge(create), glv_withdrawal))
339 }
340}
341
342pub struct CloseGlvWithdrawalBuilder<'a, C> {
344 client: &'a crate::Client<C>,
345 glv_withdrawal: Pubkey,
346 reason: String,
347 hint: Option<CloseGlvWithdrawalHint>,
348}
349
350#[derive(Clone)]
352pub struct CloseGlvWithdrawalHint {
353 store: Pubkey,
354 owner: Pubkey,
355 receiver: Pubkey,
356 glv_token: Pubkey,
357 market_token: Pubkey,
358 final_long_token: Pubkey,
359 final_short_token: Pubkey,
360 market_token_escrow: Pubkey,
361 final_long_token_escrow: Pubkey,
362 final_short_token_escrow: Pubkey,
363 glv_token_escrow: Pubkey,
364 should_unwrap_native_token: bool,
365}
366
367impl CloseGlvWithdrawalHint {
368 pub fn new(glv_withdrawal: &GlvWithdrawal) -> Self {
370 Self {
371 store: *glv_withdrawal.header().store(),
372 owner: *glv_withdrawal.header().owner(),
373 receiver: glv_withdrawal.header().receiver(),
374 glv_token: glv_withdrawal.tokens().glv_token(),
375 market_token: glv_withdrawal.tokens().market_token(),
376 final_long_token: glv_withdrawal.tokens().final_long_token(),
377 final_short_token: glv_withdrawal.tokens().final_short_token(),
378 market_token_escrow: glv_withdrawal.tokens().market_token_account(),
379 final_long_token_escrow: glv_withdrawal.tokens().final_long_token_account(),
380 final_short_token_escrow: glv_withdrawal.tokens().final_short_token_account(),
381 glv_token_escrow: glv_withdrawal.tokens().glv_token_account(),
382 should_unwrap_native_token: glv_withdrawal.header().should_unwrap_native_token(),
383 }
384 }
385}
386
387impl<'a, C: Deref<Target = impl Signer> + Clone> CloseGlvWithdrawalBuilder<'a, C> {
388 pub(super) fn new(client: &'a crate::Client<C>, glv_withdrawal: Pubkey) -> Self {
389 Self {
390 client,
391 glv_withdrawal,
392 reason: "cancelled".to_string(),
393 hint: None,
394 }
395 }
396
397 pub fn hint(&mut self, hint: CloseGlvWithdrawalHint) -> &mut Self {
399 self.hint = Some(hint);
400 self
401 }
402
403 pub fn reason(&mut self, reason: impl ToString) -> &mut Self {
405 self.reason = reason.to_string();
406 self
407 }
408
409 async fn prepare_hint(&mut self) -> crate::Result<CloseGlvWithdrawalHint> {
410 match &self.hint {
411 Some(hint) => Ok(hint.clone()),
412 None => {
413 let glv_deposit = self
414 .client
415 .account::<ZeroCopy<GlvWithdrawal>>(&self.glv_withdrawal)
416 .await?
417 .ok_or(crate::Error::NotFound)?
418 .0;
419 let hint = CloseGlvWithdrawalHint::new(&glv_deposit);
420 self.hint = Some(hint.clone());
421 Ok(hint)
422 }
423 }
424 }
425
426 pub async fn build(&mut self) -> crate::Result<TransactionBuilder<'a, C>> {
428 let hint = self.prepare_hint().await?;
429
430 let token_program_id = anchor_spl::token::ID;
431 let glv_token_program_id = anchor_spl::token_2022::ID;
432
433 let payer = self.client.payer();
434
435 let market_token_ata = get_associated_token_address_with_program_id(
436 &hint.owner,
437 &hint.market_token,
438 &token_program_id,
439 );
440 let glv_token_ata = get_associated_token_address_with_program_id(
441 &hint.owner,
442 &hint.glv_token,
443 &glv_token_program_id,
444 );
445 let final_long_token_ata = get_ata_or_owner_with_program_id(
446 &hint.receiver,
447 &hint.final_long_token,
448 hint.should_unwrap_native_token,
449 &token_program_id,
450 );
451 let final_short_token_ata = get_ata_or_owner_with_program_id(
452 &hint.receiver,
453 &hint.final_short_token,
454 hint.should_unwrap_native_token,
455 &token_program_id,
456 );
457
458 let rpc = self
459 .client
460 .store_transaction()
461 .anchor_accounts(accounts::CloseGlvWithdrawal {
462 executor: payer,
463 store: hint.store,
464 store_wallet: self.client.find_store_wallet_address(&hint.store),
465 owner: hint.owner,
466 receiver: hint.receiver,
467 glv_withdrawal: self.glv_withdrawal,
468 market_token: hint.market_token,
469 final_long_token: hint.final_long_token,
470 final_short_token: hint.final_short_token,
471 glv_token: hint.glv_token,
472 market_token_escrow: hint.market_token_escrow,
473 final_long_token_escrow: hint.final_long_token_escrow,
474 final_short_token_escrow: hint.final_short_token_escrow,
475 market_token_ata,
476 final_long_token_ata,
477 final_short_token_ata,
478 glv_token_escrow: hint.glv_token_escrow,
479 glv_token_ata,
480 system_program: system_program::ID,
481 token_program: token_program_id,
482 glv_token_program: glv_token_program_id,
483 associated_token_program: anchor_spl::associated_token::ID,
484 event_authority: self.client.store_event_authority(),
485 program: *self.client.store_program_id(),
486 })
487 .anchor_args(instruction::CloseGlvWithdrawal {
488 reason: self.reason.clone(),
489 });
490 Ok(rpc)
491 }
492}
493
494pub struct ExecuteGlvWithdrawalBuilder<'a, C> {
496 client: &'a crate::Client<C>,
497 oracle: Pubkey,
498 glv_withdrawal: Pubkey,
499 execution_lamports: u64,
500 cancel_on_execution_error: bool,
501 hint: Option<ExecuteGlvWithdrawalHint>,
502 token_map: Option<Pubkey>,
503 feeds_parser: FeedsParser,
504 close: bool,
505 alts: HashMap<Pubkey, Vec<Pubkey>>,
506}
507
508#[derive(Clone)]
510pub struct ExecuteGlvWithdrawalHint {
511 close: CloseGlvWithdrawalHint,
512 token_map: Pubkey,
513 glv_market_tokens: BTreeSet<Pubkey>,
514 swap: SwapActionParams,
515 pub feeds: TokensWithFeed,
517}
518
519impl Deref for ExecuteGlvWithdrawalHint {
520 type Target = CloseGlvWithdrawalHint;
521
522 fn deref(&self) -> &Self::Target {
523 &self.close
524 }
525}
526
527impl ExecuteGlvWithdrawalHint {
528 pub fn new(
530 glv: &Glv,
531 glv_withdrawal: &GlvWithdrawal,
532 token_map_address: &Pubkey,
533 token_map: &impl TokenMapAccess,
534 index_tokens: impl IntoIterator<Item = Pubkey>,
535 ) -> crate::Result<Self> {
536 let glv_market_tokens = glv.market_tokens().collect();
537 let mut collector = glv.tokens_collector(Some(glv_withdrawal));
538 for token in index_tokens {
539 collector.insert_token(&token);
540 }
541 let close = CloseGlvWithdrawalHint::new(glv_withdrawal);
542 Ok(Self {
543 close,
544 token_map: *token_map_address,
545 glv_market_tokens,
546 swap: *glv_withdrawal.swap(),
547 feeds: collector.to_feeds(token_map)?,
548 })
549 }
550}
551
552impl<'a, C: Deref<Target = impl Signer> + Clone> ExecuteGlvWithdrawalBuilder<'a, C> {
553 pub(super) fn new(
554 client: &'a crate::Client<C>,
555 oracle: Pubkey,
556 glv_withdrawal: Pubkey,
557 cancel_on_execution_error: bool,
558 ) -> Self {
559 Self {
560 client,
561 oracle,
562 glv_withdrawal,
563 execution_lamports: 0,
564 cancel_on_execution_error,
565 hint: None,
566 token_map: None,
567 feeds_parser: Default::default(),
568 close: true,
569 alts: Default::default(),
570 }
571 }
572
573 pub fn hint(&mut self, hint: ExecuteGlvWithdrawalHint) -> &mut Self {
575 self.hint = Some(hint);
576 self
577 }
578
579 pub fn token_map(&mut self, address: &Pubkey) -> &mut Self {
581 self.token_map = Some(*address);
582 self
583 }
584
585 pub fn close(&mut self, close: bool) -> &mut Self {
587 self.close = close;
588 self
589 }
590
591 #[cfg(feature = "pyth-pull-oracle")]
593 pub fn parse_with_pyth_price_updates(
594 &mut self,
595 price_updates: crate::pyth::pull_oracle::Prices,
596 ) -> &mut Self {
597 self.feeds_parser.with_pyth_price_updates(price_updates);
598 self
599 }
600
601 pub fn add_alt(&mut self, account: AddressLookupTableAccount) -> &mut Self {
603 self.alts.insert(account.key, account.addresses);
604 self
605 }
606
607 pub async fn prepare_hint(&mut self) -> crate::Result<ExecuteGlvWithdrawalHint> {
609 match &self.hint {
610 Some(hint) => Ok(hint.clone()),
611 None => {
612 let glv_deposit = self
613 .client
614 .account::<ZeroCopy<GlvWithdrawal>>(&self.glv_withdrawal)
615 .await?
616 .ok_or(crate::Error::NotFound)?
617 .0;
618
619 let glv_address = self
620 .client
621 .find_glv_address(&glv_deposit.tokens().glv_token());
622 let glv = self
623 .client
624 .account::<ZeroCopy<Glv>>(&glv_address)
625 .await?
626 .ok_or(crate::Error::NotFound)?
627 .0;
628
629 let mut index_tokens = Vec::with_capacity(glv.num_markets());
630 for token in glv.market_tokens() {
631 let market = self.client.find_market_address(glv.store(), &token);
632 let market = self.client.market(&market).await?;
633 index_tokens.push(market.meta().index_token_mint);
634 }
635
636 let store = glv_deposit.header().store();
637 let token_map_address = self
638 .client
639 .authorized_token_map_address(store)
640 .await?
641 .ok_or(crate::Error::NotFound)?;
642 let token_map = self.client.token_map(&token_map_address).await?;
643 let hint = ExecuteGlvWithdrawalHint::new(
644 &glv,
645 &glv_deposit,
646 &token_map_address,
647 &token_map,
648 index_tokens,
649 )?;
650 self.hint = Some(hint.clone());
651 Ok(hint)
652 }
653 }
654 }
655}
656
657#[cfg(feature = "pyth-pull-oracle")]
658mod pyth {
659 use crate::pyth::{
660 pull_oracle::{ExecuteWithPythPrices, Prices},
661 PythPullOracleContext,
662 };
663
664 use super::*;
665
666 impl<'a, C: Deref<Target = impl Signer> + Clone> ExecuteWithPythPrices<'a, C>
667 for ExecuteGlvWithdrawalBuilder<'a, C>
668 {
669 fn set_execution_fee(&mut self, lamports: u64) {
670 SetExecutionFee::set_execution_fee(self, lamports);
671 }
672
673 async fn context(&mut self) -> crate::Result<PythPullOracleContext> {
674 let hint = self.prepare_hint().await?;
675 let ctx = PythPullOracleContext::try_from_feeds(&hint.feeds)?;
676 Ok(ctx)
677 }
678
679 async fn build_rpc_with_price_updates(
680 &mut self,
681 price_updates: Prices,
682 ) -> crate::Result<Vec<TransactionBuilder<'a, C, ()>>> {
683 let txn = self
684 .parse_with_pyth_price_updates(price_updates)
685 .build()
686 .await?;
687 Ok(txn.into_builders())
688 }
689 }
690}
691
692impl<'a, C: Deref<Target = impl Signer> + Clone> MakeBundleBuilder<'a, C>
693 for ExecuteGlvWithdrawalBuilder<'a, C>
694{
695 async fn build_with_options(
696 &mut self,
697 options: BundleOptions,
698 ) -> gmsol_solana_utils::Result<BundleBuilder<'a, C>> {
699 let hint = self
700 .prepare_hint()
701 .await
702 .map_err(gmsol_solana_utils::Error::custom)?;
703
704 let token_program_id = anchor_spl::token::ID;
705 let glv_token_program_id = anchor_spl::token_2022::ID;
706
707 let authority = self.client.payer();
708 let glv = self.client.find_glv_address(&hint.glv_token);
709 let market = self
710 .client
711 .find_market_address(&hint.close.store, &hint.market_token);
712
713 let feeds = self
714 .feeds_parser
715 .parse(&hint.feeds)
716 .collect::<Result<Vec<_>, _>>()
717 .map_err(gmsol_solana_utils::Error::custom)?;
718 let markets = hint
719 .swap
720 .unique_market_tokens_excluding_current(&hint.market_token)
721 .map(|mint| AccountMeta {
722 pubkey: self.client.find_market_address(&hint.store, mint),
723 is_signer: false,
724 is_writable: true,
725 });
726
727 let glv_accounts = split_to_accounts(
728 hint.glv_market_tokens.iter().copied(),
729 &glv,
730 &hint.store,
731 self.client.store_program_id(),
732 &token_program_id,
733 false,
734 )
735 .0;
736
737 let final_long_token_vault = self
738 .client
739 .find_market_vault_address(&hint.store, &hint.final_long_token);
740 let final_short_token_vault = self
741 .client
742 .find_market_vault_address(&hint.store, &hint.final_short_token);
743
744 let market_token_vault = get_associated_token_address_with_program_id(
745 &glv,
746 &hint.market_token,
747 &token_program_id,
748 );
749
750 let market_token_withdrawal_vault = self
751 .client
752 .find_market_vault_address(&hint.store, &hint.market_token);
753
754 let execute = self
755 .client
756 .store_transaction()
757 .accounts(fix_optional_account_metas(
758 accounts::ExecuteGlvWithdrawal {
759 authority,
760 store: hint.store,
761 token_map: hint.token_map,
762 oracle: self.oracle,
763 glv,
764 market,
765 glv_withdrawal: self.glv_withdrawal,
766 glv_token: hint.glv_token,
767 market_token: hint.market_token,
768 final_long_token: hint.final_long_token,
769 final_short_token: hint.final_short_token,
770 glv_token_escrow: hint.glv_token_escrow,
771 market_token_escrow: hint.market_token_escrow,
772 final_long_token_escrow: hint.final_long_token_escrow,
773 final_short_token_escrow: hint.final_short_token_escrow,
774 market_token_withdrawal_vault,
775 final_long_token_vault,
776 final_short_token_vault,
777 market_token_vault,
778 token_program: token_program_id,
779 glv_token_program: glv_token_program_id,
780 system_program: system_program::ID,
781 chainlink_program: None,
782 event_authority: self.client.store_event_authority(),
783 program: *self.client.store_program_id(),
784 },
785 &crate::program_ids::DEFAULT_GMSOL_STORE_ID,
786 self.client.store_program_id(),
787 ))
788 .anchor_args(instruction::ExecuteGlvWithdrawal {
789 execution_lamports: self.execution_lamports,
790 throw_on_execution_error: !self.cancel_on_execution_error,
791 })
792 .accounts(glv_accounts)
793 .accounts(feeds.into_iter().chain(markets).collect::<Vec<_>>())
794 .compute_budget(
795 ComputeBudget::default().with_limit(EXECUTE_GLV_WITHDRAWAL_COMPUTE_BUDGET),
796 )
797 .lookup_tables(self.alts.clone());
798
799 let rpc = if self.close {
800 let close = self
801 .client
802 .close_glv_withdrawal(&self.glv_withdrawal)
803 .reason("executed")
804 .hint(hint.close)
805 .build()
806 .await
807 .map_err(gmsol_solana_utils::Error::custom)?;
808 execute.merge(close)
809 } else {
810 execute
811 };
812
813 let mut tx = self.client.bundle_with_options(options);
814
815 tx.try_push(rpc)?;
816
817 Ok(tx)
818 }
819}
820
821impl<C: Deref<Target = impl Signer> + Clone> PullOraclePriceConsumer
822 for ExecuteGlvWithdrawalBuilder<'_, C>
823{
824 async fn feed_ids(&mut self) -> crate::Result<FeedIds> {
825 let hint = self.prepare_hint().await?;
826 Ok(FeedIds::new(hint.store, hint.feeds))
827 }
828
829 fn process_feeds(
830 &mut self,
831 provider: PriceProviderKind,
832 map: FeedAddressMap,
833 ) -> crate::Result<()> {
834 self.feeds_parser
835 .insert_pull_oracle_feed_parser(provider, map);
836 Ok(())
837 }
838}
839
840impl<C> SetExecutionFee for ExecuteGlvWithdrawalBuilder<'_, C> {
841 fn set_execution_fee(&mut self, lamports: u64) -> &mut Self {
842 self.execution_lamports = lamports;
843 self
844 }
845}