1pub mod deposit;
3
4pub mod withdrawal;
6
7pub mod shift;
9
10pub mod order;
12
13pub mod glv_deposit;
15
16pub mod glv_withdrawal;
18
19pub mod glv_shift;
21
22pub mod market_state;
24
25use std::{
26 collections::{BTreeSet, HashSet},
27 future::Future,
28 ops::Deref,
29};
30
31use deposit::{CloseDepositBuilder, CreateDepositBuilder, ExecuteDepositBuilder};
32use glv_deposit::{CloseGlvDepositBuilder, CreateGlvDepositBuilder, ExecuteGlvDepositBuilder};
33use glv_shift::{CloseGlvShiftBuilder, CreateGlvShiftBuilder, ExecuteGlvShiftBuilder};
34use glv_withdrawal::{
35 CloseGlvWithdrawalBuilder, CreateGlvWithdrawalBuilder, ExecuteGlvWithdrawalBuilder,
36};
37use gmsol_programs::gmsol_store::{
38 client::{accounts, args},
39 types::UpdateOrderParams,
40};
41use gmsol_solana_utils::{transaction_builder::TransactionBuilder, IntoAtomicGroup};
42use gmsol_utils::{
43 order::{OrderKind, PositionCutKind},
44 pubkey::optional_address,
45 swap::SwapActionParams,
46};
47use market_state::{UpdateClosedStateBuilder, UpdateFeesStateBuilder};
48use order::{
49 CloseOrderBuilder, CreateOrderBuilder, ExecuteOrderBuilder, OrderParams, PositionCutBuilder,
50 UpdateAdlBuilder,
51};
52use shift::{CloseShiftBuilder, CreateShiftBuilder, ExecuteShiftBuilder};
53use solana_sdk::{pubkey::Pubkey, signer::Signer};
54use withdrawal::{CloseWithdrawalBuilder, CreateWithdrawalBuilder, ExecuteWithdrawalBuilder};
55
56use crate::{
57 builders::{
58 callback::{Callback, CallbackParams},
59 market_state::{UpdateClosedState, UpdateFeesState},
60 order::update::SetShouldKeepPositionAccount,
61 position::CloseEmptyPosition,
62 },
63 client::Client,
64};
65
66pub trait ExchangeOps<C> {
68 fn create_deposit(&self, store: &Pubkey, market_token: &Pubkey) -> CreateDepositBuilder<C>;
70
71 fn create_first_deposit(
73 &self,
74 store: &Pubkey,
75 market_token: &Pubkey,
76 ) -> CreateDepositBuilder<C>;
77
78 fn close_deposit(&self, store: &Pubkey, deposit: &Pubkey) -> CloseDepositBuilder<C>;
80
81 fn execute_deposit(
83 &self,
84 store: &Pubkey,
85 oracle: &Pubkey,
86 deposit: &Pubkey,
87 cancel_on_execution_error: bool,
88 ) -> ExecuteDepositBuilder<C>;
89
90 fn create_withdrawal(
92 &self,
93 store: &Pubkey,
94 market_token: &Pubkey,
95 amount: u64,
96 ) -> CreateWithdrawalBuilder<C>;
97
98 fn close_withdrawal(&self, store: &Pubkey, withdrawal: &Pubkey) -> CloseWithdrawalBuilder<C>;
100
101 fn execute_withdrawal(
103 &self,
104 store: &Pubkey,
105 oracle: &Pubkey,
106 withdrawal: &Pubkey,
107 cancel_on_execution_error: bool,
108 ) -> ExecuteWithdrawalBuilder<C>;
109
110 fn create_shift(
112 &self,
113 store: &Pubkey,
114 from_market_token: &Pubkey,
115 to_market_token: &Pubkey,
116 amount: u64,
117 ) -> CreateShiftBuilder<C>;
118
119 fn close_shift(&self, shift: &Pubkey) -> CloseShiftBuilder<C>;
121
122 fn execute_shift(
124 &self,
125 oracle: &Pubkey,
126 shift: &Pubkey,
127 cancel_on_execution_error: bool,
128 ) -> ExecuteShiftBuilder<C>;
129
130 fn create_order(
132 &self,
133 store: &Pubkey,
134 market_token: &Pubkey,
135 is_output_token_long: bool,
136 params: OrderParams,
137 ) -> CreateOrderBuilder<C>;
138
139 fn market_increase(
141 &self,
142 store: &Pubkey,
143 market_token: &Pubkey,
144 is_collateral_token_long: bool,
145 initial_collateral_amount: u64,
146 is_long: bool,
147 increment_size_in_usd: u128,
148 ) -> CreateOrderBuilder<C> {
149 let params = OrderParams {
150 kind: OrderKind::MarketIncrease,
151 decrease_position_swap_type: None,
152 min_output_amount: 0,
153 size_delta_usd: increment_size_in_usd,
154 initial_collateral_delta_amount: initial_collateral_amount,
155 acceptable_price: None,
156 trigger_price: None,
157 is_long,
158 valid_from_ts: None,
159 };
160 self.create_order(store, market_token, is_collateral_token_long, params)
161 }
162
163 fn market_decrease(
165 &self,
166 store: &Pubkey,
167 market_token: &Pubkey,
168 is_collateral_token_long: bool,
169 collateral_withdrawal_amount: u64,
170 is_long: bool,
171 decrement_size_in_usd: u128,
172 ) -> CreateOrderBuilder<C> {
173 let params = OrderParams {
174 kind: OrderKind::MarketDecrease,
175 decrease_position_swap_type: None,
176 min_output_amount: 0,
177 size_delta_usd: decrement_size_in_usd,
178 initial_collateral_delta_amount: collateral_withdrawal_amount,
179 acceptable_price: None,
180 trigger_price: None,
181 is_long,
182 valid_from_ts: None,
183 };
184 self.create_order(store, market_token, is_collateral_token_long, params)
185 }
186
187 fn market_swap<'a, S>(
189 &self,
190 store: &Pubkey,
191 market_token: &Pubkey,
192 is_output_token_long: bool,
193 initial_swap_in_token: &Pubkey,
194 initial_swap_in_token_amount: u64,
195 swap_path: impl IntoIterator<Item = &'a Pubkey>,
196 ) -> CreateOrderBuilder<C>
197 where
198 C: Deref<Target = S> + Clone,
199 S: Signer,
200 {
201 let params = OrderParams {
202 kind: OrderKind::MarketSwap,
203 decrease_position_swap_type: None,
204 min_output_amount: 0,
205 size_delta_usd: 0,
206 initial_collateral_delta_amount: initial_swap_in_token_amount,
207 acceptable_price: None,
208 trigger_price: None,
209 is_long: true,
210 valid_from_ts: None,
211 };
212 let mut builder = self.create_order(store, market_token, is_output_token_long, params);
213 builder
214 .initial_collateral_token(initial_swap_in_token, None)
215 .swap_path(swap_path.into_iter().copied().collect());
216 builder
217 }
218
219 #[allow(clippy::too_many_arguments)]
221 fn limit_increase(
222 &self,
223 store: &Pubkey,
224 market_token: &Pubkey,
225 is_long: bool,
226 increment_size_in_usd: u128,
227 price: u128,
228 is_collateral_token_long: bool,
229 initial_collateral_amount: u64,
230 ) -> CreateOrderBuilder<C> {
231 let params = OrderParams {
232 kind: OrderKind::LimitIncrease,
233 decrease_position_swap_type: None,
234 min_output_amount: 0,
235 size_delta_usd: increment_size_in_usd,
236 initial_collateral_delta_amount: initial_collateral_amount,
237 acceptable_price: None,
238 trigger_price: Some(price),
239 is_long,
240 valid_from_ts: None,
241 };
242 self.create_order(store, market_token, is_collateral_token_long, params)
243 }
244
245 #[allow(clippy::too_many_arguments)]
247 fn limit_decrease(
248 &self,
249 store: &Pubkey,
250 market_token: &Pubkey,
251 is_long: bool,
252 decrement_size_in_usd: u128,
253 price: u128,
254 is_collateral_token_long: bool,
255 collateral_withdrawal_amount: u64,
256 ) -> CreateOrderBuilder<C> {
257 let params = OrderParams {
258 kind: OrderKind::LimitDecrease,
259 decrease_position_swap_type: None,
260 min_output_amount: 0,
261 size_delta_usd: decrement_size_in_usd,
262 initial_collateral_delta_amount: collateral_withdrawal_amount,
263 acceptable_price: None,
264 trigger_price: Some(price),
265 is_long,
266 valid_from_ts: None,
267 };
268 self.create_order(store, market_token, is_collateral_token_long, params)
269 }
270
271 #[allow(clippy::too_many_arguments)]
273 fn stop_loss(
274 &self,
275 store: &Pubkey,
276 market_token: &Pubkey,
277 is_long: bool,
278 decrement_size_in_usd: u128,
279 price: u128,
280 is_collateral_token_long: bool,
281 collateral_withdrawal_amount: u64,
282 ) -> CreateOrderBuilder<C> {
283 let params = OrderParams {
284 kind: OrderKind::StopLossDecrease,
285 decrease_position_swap_type: None,
286 min_output_amount: 0,
287 size_delta_usd: decrement_size_in_usd,
288 initial_collateral_delta_amount: collateral_withdrawal_amount,
289 acceptable_price: None,
290 trigger_price: Some(price),
291 is_long,
292 valid_from_ts: None,
293 };
294 self.create_order(store, market_token, is_collateral_token_long, params)
295 }
296
297 #[allow(clippy::too_many_arguments)]
299 fn limit_swap<'a, S>(
300 &self,
301 store: &Pubkey,
302 market_token: &Pubkey,
303 is_output_token_long: bool,
304 min_output_amount: u64,
305 initial_swap_in_token: &Pubkey,
306 initial_swap_in_token_amount: u64,
307 swap_path: impl IntoIterator<Item = &'a Pubkey>,
308 ) -> CreateOrderBuilder<C>
309 where
310 C: Deref<Target = S> + Clone,
311 S: Signer,
312 {
313 let params = OrderParams {
314 kind: OrderKind::LimitSwap,
315 decrease_position_swap_type: None,
316 min_output_amount: u128::from(min_output_amount),
317 size_delta_usd: 0,
318 initial_collateral_delta_amount: initial_swap_in_token_amount,
319 acceptable_price: None,
320 trigger_price: None,
321 is_long: true,
322 valid_from_ts: None,
323 };
324 let mut builder = self.create_order(store, market_token, is_output_token_long, params);
325 builder
326 .initial_collateral_token(initial_swap_in_token, None)
327 .swap_path(swap_path.into_iter().copied().collect());
328 builder
329 }
330
331 fn update_order(
333 &self,
334 store: &Pubkey,
335 market_token: &Pubkey,
336 order: &Pubkey,
337 params: UpdateOrderParams,
338 hint: Option<Option<Callback>>,
339 ) -> impl Future<Output = crate::Result<TransactionBuilder<C>>>;
340
341 fn execute_order(
343 &self,
344 store: &Pubkey,
345 oracle: &Pubkey,
346 order: &Pubkey,
347 cancel_on_execution_error: bool,
348 ) -> crate::Result<ExecuteOrderBuilder<C>>;
349
350 fn close_order(&self, order: &Pubkey) -> crate::Result<CloseOrderBuilder<C>>;
352
353 fn cancel_order_if_no_position(
355 &self,
356 store: &Pubkey,
357 order: &Pubkey,
358 position_hint: Option<&Pubkey>,
359 ) -> impl Future<Output = crate::Result<TransactionBuilder<C>>>;
360
361 fn close_empty_position(
363 &self,
364 store: &Pubkey,
365 position: &Pubkey,
366 ) -> crate::Result<TransactionBuilder<C>>;
367
368 fn liquidate(&self, oracle: &Pubkey, position: &Pubkey)
370 -> crate::Result<PositionCutBuilder<C>>;
371
372 fn auto_deleverage(
374 &self,
375 oracle: &Pubkey,
376 position: &Pubkey,
377 size_delta_usd: u128,
378 ) -> crate::Result<PositionCutBuilder<C>>;
379
380 fn update_adl(
382 &self,
383 store: &Pubkey,
384 oracle: &Pubkey,
385 market_token: &Pubkey,
386 for_long: bool,
387 for_short: bool,
388 ) -> crate::Result<UpdateAdlBuilder<C>>;
389
390 fn create_glv_deposit(
392 &self,
393 store: &Pubkey,
394 glv_token: &Pubkey,
395 market_token: &Pubkey,
396 ) -> CreateGlvDepositBuilder<C>;
397
398 fn close_glv_deposit(&self, glv_deposit: &Pubkey) -> CloseGlvDepositBuilder<C>;
400
401 fn execute_glv_deposit(
403 &self,
404 oracle: &Pubkey,
405 glv_deposit: &Pubkey,
406 cancel_on_execution_error: bool,
407 ) -> ExecuteGlvDepositBuilder<C>;
408
409 fn create_glv_withdrawal(
410 &self,
411 store: &Pubkey,
412 glv_token: &Pubkey,
413 market_token: &Pubkey,
414 amount: u64,
415 ) -> CreateGlvWithdrawalBuilder<C>;
416
417 fn close_glv_withdrawal(&self, glv_withdrawal: &Pubkey) -> CloseGlvWithdrawalBuilder<C>;
419
420 fn execute_glv_withdrawal(
422 &self,
423 oracle: &Pubkey,
424 glv_withdrawal: &Pubkey,
425 cancel_on_execution_error: bool,
426 ) -> ExecuteGlvWithdrawalBuilder<C>;
427
428 fn create_glv_shift(
429 &self,
430 store: &Pubkey,
431 glv_token: &Pubkey,
432 from_market_token: &Pubkey,
433 to_market_token: &Pubkey,
434 amount: u64,
435 ) -> CreateGlvShiftBuilder<C>;
436
437 fn close_glv_shift(&self, glv_shift: &Pubkey) -> CloseGlvShiftBuilder<C>;
438
439 fn execute_glv_shift(
440 &self,
441 oracle: &Pubkey,
442 glv_shift: &Pubkey,
443 cancel_on_execution_error: bool,
444 ) -> ExecuteGlvShiftBuilder<C>;
445
446 fn update_closed_state(
447 &self,
448 store: &Pubkey,
449 oracle: &Pubkey,
450 market_token: &Pubkey,
451 ) -> UpdateClosedStateBuilder<C>;
452
453 fn update_fees_state(
454 &self,
455 store: &Pubkey,
456 oracle: &Pubkey,
457 market_token: &Pubkey,
458 ) -> UpdateFeesStateBuilder<C>;
459
460 fn set_should_keep_position_account(
461 &self,
462 store: &Pubkey,
463 order: &Pubkey,
464 keep: bool,
465 ) -> crate::Result<TransactionBuilder<C>>;
466}
467
468impl<C: Deref<Target = impl Signer> + Clone> ExchangeOps<C> for Client<C> {
469 fn create_deposit(&self, store: &Pubkey, market_token: &Pubkey) -> CreateDepositBuilder<C> {
470 CreateDepositBuilder::new(self, *store, *market_token)
471 }
472
473 fn create_first_deposit(
474 &self,
475 store: &Pubkey,
476 market_token: &Pubkey,
477 ) -> CreateDepositBuilder<C> {
478 let mut builder = self.create_deposit(store, market_token);
479 builder.receiver(Some(self.find_first_deposit_owner_address()));
480 builder
481 }
482
483 fn close_deposit(&self, store: &Pubkey, deposit: &Pubkey) -> CloseDepositBuilder<C> {
484 CloseDepositBuilder::new(self, store, deposit)
485 }
486
487 fn execute_deposit(
488 &self,
489 store: &Pubkey,
490 oracle: &Pubkey,
491 deposit: &Pubkey,
492 cancel_on_execution_error: bool,
493 ) -> ExecuteDepositBuilder<C> {
494 ExecuteDepositBuilder::new(self, store, oracle, deposit, cancel_on_execution_error)
495 }
496
497 fn create_withdrawal(
498 &self,
499 store: &Pubkey,
500 market_token: &Pubkey,
501 amount: u64,
502 ) -> CreateWithdrawalBuilder<C> {
503 CreateWithdrawalBuilder::new(self, *store, *market_token, amount)
504 }
505
506 fn close_withdrawal(&self, store: &Pubkey, withdrawal: &Pubkey) -> CloseWithdrawalBuilder<C> {
507 CloseWithdrawalBuilder::new(self, store, withdrawal)
508 }
509
510 fn execute_withdrawal(
511 &self,
512 store: &Pubkey,
513 oracle: &Pubkey,
514 withdrawal: &Pubkey,
515 cancel_on_execution_error: bool,
516 ) -> ExecuteWithdrawalBuilder<C> {
517 ExecuteWithdrawalBuilder::new(self, store, oracle, withdrawal, cancel_on_execution_error)
518 }
519
520 fn create_shift(
521 &self,
522 store: &Pubkey,
523 from_market_token: &Pubkey,
524 to_market_token: &Pubkey,
525 amount: u64,
526 ) -> CreateShiftBuilder<C> {
527 CreateShiftBuilder::new(self, store, from_market_token, to_market_token, amount)
528 }
529
530 fn close_shift(&self, shift: &Pubkey) -> CloseShiftBuilder<C> {
531 CloseShiftBuilder::new(self, shift)
532 }
533
534 fn execute_shift(
535 &self,
536 oracle: &Pubkey,
537 shift: &Pubkey,
538 cancel_on_execution_error: bool,
539 ) -> ExecuteShiftBuilder<C> {
540 ExecuteShiftBuilder::new(self, oracle, shift, cancel_on_execution_error)
541 }
542
543 fn create_order(
544 &self,
545 store: &Pubkey,
546 market_token: &Pubkey,
547 is_output_token_long: bool,
548 params: OrderParams,
549 ) -> CreateOrderBuilder<C> {
550 CreateOrderBuilder::new(self, store, market_token, params, is_output_token_long)
551 }
552
553 async fn update_order(
554 &self,
555 store: &Pubkey,
556 market_token: &Pubkey,
557 order: &Pubkey,
558 params: UpdateOrderParams,
559 hint: Option<Option<Callback>>,
560 ) -> crate::Result<TransactionBuilder<C>> {
561 let callback = match hint {
562 Some(callback) => callback,
563 None => {
564 let order = self.order(order).await?;
565 Callback::from_header(&order.header)?
566 }
567 };
568 let CallbackParams {
569 callback_authority,
570 callback_program,
571 callback_shared_data_account,
572 callback_partitioned_data_account,
573 ..
574 } = self.get_callback_params(callback.as_ref());
575 Ok(self
576 .store_transaction()
577 .anchor_accounts(accounts::UpdateOrderV2 {
578 owner: self.payer(),
579 store: *store,
580 market: self.find_market_address(store, market_token),
581 order: *order,
582 event_authority: self.store_event_authority(),
583 program: *self.store_program_id(),
584 callback_authority,
585 callback_program,
586 callback_shared_data_account,
587 callback_partitioned_data_account,
588 })
589 .anchor_args(args::UpdateOrderV2 { params }))
590 }
591
592 fn execute_order(
593 &self,
594 store: &Pubkey,
595 oracle: &Pubkey,
596 order: &Pubkey,
597 cancel_on_execution_error: bool,
598 ) -> crate::Result<ExecuteOrderBuilder<C>> {
599 ExecuteOrderBuilder::try_new(self, store, oracle, order, cancel_on_execution_error)
600 }
601
602 fn close_order(&self, order: &Pubkey) -> crate::Result<CloseOrderBuilder<C>> {
603 Ok(CloseOrderBuilder::new(self, order))
604 }
605
606 async fn cancel_order_if_no_position(
607 &self,
608 store: &Pubkey,
609 order: &Pubkey,
610 position_hint: Option<&Pubkey>,
611 ) -> crate::Result<TransactionBuilder<C>> {
612 let position = match position_hint {
613 Some(position) => *position,
614 None => {
615 let order = self.order(order).await?;
616
617 let position = order
618 .params
619 .position()
620 .ok_or_else(|| crate::Error::custom("this order does not have position"))?;
621
622 *position
623 }
624 };
625
626 Ok(self
627 .store_transaction()
628 .anchor_args(args::CancelOrderIfNoPosition {})
629 .anchor_accounts(accounts::CancelOrderIfNoPosition {
630 authority: self.payer(),
631 store: *store,
632 order: *order,
633 position,
634 }))
635 }
636
637 fn close_empty_position(
638 &self,
639 store: &Pubkey,
640 position: &Pubkey,
641 ) -> crate::Result<TransactionBuilder<C>> {
642 let ag = CloseEmptyPosition::builder()
643 .payer(self.payer())
644 .program(self.store_program_for_builders(store))
645 .position(*position)
646 .build()
647 .into_atomic_group(&())?;
648 let txn = self.store_transaction().pre_atomic_group(ag, true);
649 Ok(txn)
650 }
651
652 fn liquidate(
653 &self,
654 oracle: &Pubkey,
655 position: &Pubkey,
656 ) -> crate::Result<PositionCutBuilder<C>> {
657 PositionCutBuilder::try_new(self, PositionCutKind::Liquidate, oracle, position)
658 }
659
660 fn auto_deleverage(
661 &self,
662 oracle: &Pubkey,
663 position: &Pubkey,
664 size_delta_usd: u128,
665 ) -> crate::Result<PositionCutBuilder<C>> {
666 PositionCutBuilder::try_new(
667 self,
668 PositionCutKind::AutoDeleverage(size_delta_usd),
669 oracle,
670 position,
671 )
672 }
673
674 fn update_adl(
675 &self,
676 store: &Pubkey,
677 oracle: &Pubkey,
678 market_token: &Pubkey,
679 for_long: bool,
680 for_short: bool,
681 ) -> crate::Result<UpdateAdlBuilder<C>> {
682 UpdateAdlBuilder::try_new(self, store, oracle, market_token, for_long, for_short)
683 }
684
685 fn create_glv_deposit(
686 &self,
687 store: &Pubkey,
688 glv_token: &Pubkey,
689 market_token: &Pubkey,
690 ) -> CreateGlvDepositBuilder<C> {
691 CreateGlvDepositBuilder::new(self, *store, *glv_token, *market_token)
692 }
693
694 fn close_glv_deposit(&self, glv_deposit: &Pubkey) -> CloseGlvDepositBuilder<C> {
695 CloseGlvDepositBuilder::new(self, *glv_deposit)
696 }
697
698 fn execute_glv_deposit(
699 &self,
700 oracle: &Pubkey,
701 glv_deposit: &Pubkey,
702 cancel_on_execution_error: bool,
703 ) -> ExecuteGlvDepositBuilder<C> {
704 ExecuteGlvDepositBuilder::new(self, *oracle, *glv_deposit, cancel_on_execution_error)
705 }
706
707 fn create_glv_withdrawal(
708 &self,
709 store: &Pubkey,
710 glv_token: &Pubkey,
711 market_token: &Pubkey,
712 amount: u64,
713 ) -> CreateGlvWithdrawalBuilder<C> {
714 CreateGlvWithdrawalBuilder::new(self, *store, *glv_token, *market_token, amount)
715 }
716
717 fn close_glv_withdrawal(&self, glv_withdrawal: &Pubkey) -> CloseGlvWithdrawalBuilder<C> {
718 CloseGlvWithdrawalBuilder::new(self, *glv_withdrawal)
719 }
720
721 fn execute_glv_withdrawal(
722 &self,
723 oracle: &Pubkey,
724 glv_withdrawal: &Pubkey,
725 cancel_on_execution_error: bool,
726 ) -> ExecuteGlvWithdrawalBuilder<C> {
727 ExecuteGlvWithdrawalBuilder::new(self, *oracle, *glv_withdrawal, cancel_on_execution_error)
728 }
729
730 fn create_glv_shift(
731 &self,
732 store: &Pubkey,
733 glv_token: &Pubkey,
734 from_market_token: &Pubkey,
735 to_market_token: &Pubkey,
736 amount: u64,
737 ) -> CreateGlvShiftBuilder<C> {
738 CreateGlvShiftBuilder::new(
739 self,
740 store,
741 glv_token,
742 from_market_token,
743 to_market_token,
744 amount,
745 )
746 }
747
748 fn close_glv_shift(&self, glv_shift: &Pubkey) -> CloseGlvShiftBuilder<C> {
749 CloseGlvShiftBuilder::new(self, glv_shift)
750 }
751
752 fn execute_glv_shift(
753 &self,
754 oracle: &Pubkey,
755 glv_shift: &Pubkey,
756 cancel_on_execution_error: bool,
757 ) -> ExecuteGlvShiftBuilder<C> {
758 let mut builder = ExecuteGlvShiftBuilder::new(self, oracle, glv_shift);
759 builder.cancel_on_execution_error(cancel_on_execution_error);
760 builder
761 }
762
763 fn update_closed_state(
764 &self,
765 store: &Pubkey,
766 oracle: &Pubkey,
767 market_token: &Pubkey,
768 ) -> UpdateClosedStateBuilder<C> {
769 UpdateClosedStateBuilder::new(
770 self,
771 UpdateClosedState::builder()
772 .payer(self.payer())
773 .market_token(*market_token)
774 .store_program(self.store_program_for_builders(store))
775 .oracle(*oracle)
776 .build(),
777 )
778 }
779
780 fn update_fees_state(
781 &self,
782 store: &Pubkey,
783 oracle: &Pubkey,
784 market_token: &Pubkey,
785 ) -> UpdateFeesStateBuilder<C> {
786 UpdateFeesStateBuilder::new(
787 self,
788 UpdateFeesState::builder()
789 .payer(self.payer())
790 .market_token(*market_token)
791 .store_program(self.store_program_for_builders(store))
792 .oracle(*oracle)
793 .build(),
794 )
795 }
796
797 fn set_should_keep_position_account(
798 &self,
799 store: &Pubkey,
800 order: &Pubkey,
801 keep: bool,
802 ) -> crate::Result<TransactionBuilder<C>> {
803 let set = SetShouldKeepPositionAccount::builder()
804 .keep(keep)
805 .order(*order)
806 .payer(self.payer())
807 .program(self.store_program_for_builders(store))
808 .build()
809 .into_atomic_group(&())?;
810 Ok(self.store_transaction().pre_atomic_group(set, false))
811 }
812}
813
814#[derive(Default)]
815struct VirtualInventoryCollector {
816 market_tokens: HashSet<Pubkey>,
817}
818
819impl VirtualInventoryCollector {
820 fn insert_market_token(&mut self, market_token: &Pubkey) -> &mut Self {
821 self.market_tokens.insert(*market_token);
822 self
823 }
824
825 fn from_swap(swap: &SwapActionParams) -> Self {
826 let mut this = Self::default();
827
828 this.insert_market_token(&swap.current_market_token);
829
830 for market_token in swap.unique_market_tokens_excluding_current(&swap.current_market_token)
831 {
832 this.insert_market_token(market_token);
833 }
834
835 this
836 }
837
838 async fn collect<C: Deref<Target = impl Signer> + Clone>(
839 &self,
840 client: &crate::Client<C>,
841 store: &Pubkey,
842 ) -> crate::Result<BTreeSet<Pubkey>> {
843 let mut addresses = BTreeSet::new();
844 for market_token in self.market_tokens.iter() {
845 let market = client.market_by_token(store, market_token).await?;
846 if let Some(address) = optional_address(&market.virtual_inventory_for_swaps) {
847 addresses.insert(*address);
848 }
849 if let Some(address) = optional_address(&market.virtual_inventory_for_positions) {
850 addresses.insert(*address);
851 }
852 }
853 Ok(addresses)
854 }
855}