gmsol_sdk/simulation/
deposit.rs1use gmsol_model::{
2 action::{deposit::DepositReport, swap::SwapReport},
3 LiquidityMarketMutExt, MarketAction,
4};
5use gmsol_programs::gmsol_store::types::CreateDepositParams;
6use solana_sdk::pubkey::Pubkey;
7use typed_builder::TypedBuilder;
8
9use super::{SimulationOptions, Simulator};
10
11#[derive(Debug)]
13pub struct DepositSimulationOutput {
14 pub(crate) long_swaps: Vec<SwapReport<u128, i128>>,
15 pub(crate) short_swaps: Vec<SwapReport<u128, i128>>,
16 pub(crate) report: Box<DepositReport<u128, i128>>,
17}
18
19impl DepositSimulationOutput {
20 pub fn long_swaps(&self) -> &[SwapReport<u128, i128>] {
22 &self.long_swaps
23 }
24
25 pub fn short_swaps(&self) -> &[SwapReport<u128, i128>] {
27 &self.short_swaps
28 }
29
30 pub fn report(&self) -> &DepositReport<u128, i128> {
32 &self.report
33 }
34}
35
36#[derive(Debug, TypedBuilder)]
38pub struct DepositSimulation<'a> {
39 simulator: &'a mut Simulator,
40 params: &'a CreateDepositParams,
41 market_token: &'a Pubkey,
42 #[builder(default)]
43 long_pay_token: Option<&'a Pubkey>,
44 #[builder(default)]
45 long_swap_path: &'a [Pubkey],
46 #[builder(default)]
47 short_pay_token: Option<&'a Pubkey>,
48 #[builder(default)]
49 short_swap_path: &'a [Pubkey],
50}
51
52impl DepositSimulation<'_> {
53 pub fn execute_with_options(
55 self,
56 options: SimulationOptions,
57 ) -> crate::Result<DepositSimulationOutput> {
58 let Self {
59 simulator,
60 params,
61 market_token,
62 long_pay_token,
63 long_swap_path,
64 short_pay_token,
65 short_swap_path,
66 } = self;
67
68 if params.initial_long_token_amount == 0 && params.initial_short_token_amount == 0 {
69 return Err(crate::Error::custom("[sim] empty deposit"));
70 }
71
72 let (prices, meta) = simulator.get_prices_and_meta_for_market(market_token)?;
73
74 let long_token = meta.long_token_mint;
76 let short_token = meta.short_token_mint;
77 let long_pay_token = long_pay_token.copied().unwrap_or(long_token);
78 let short_pay_token = short_pay_token.copied().unwrap_or(short_token);
79
80 let long_swap_output = simulator.swap_along_path_with_options(
81 long_swap_path,
82 &long_pay_token,
83 params.initial_long_token_amount.into(),
84 options.clone(),
85 )?;
86 if long_swap_output.output_token != long_token {
87 return Err(crate::Error::custom("[sim] invalid long swap path"));
88 }
89
90 let short_swap_output = simulator.swap_along_path_with_options(
91 short_swap_path,
92 &short_pay_token,
93 params.initial_short_token_amount.into(),
94 options.clone(),
95 )?;
96 if short_swap_output.output_token != short_token {
97 return Err(crate::Error::custom("[sim] invalid short swap path"));
98 }
99
100 let report = if options.disable_vis {
102 let market = simulator
103 .get_market_mut(market_token)
104 .expect("market storage must exist");
105 market.with_vis_disabled(|market| {
106 market
107 .deposit(long_swap_output.amount, short_swap_output.amount, prices)?
108 .execute()
109 })?
110 } else {
111 let (market, vi_map) = simulator.get_market_and_vis_mut(market_token)?;
112 market.with_vi_models(vi_map, |market| {
113 market
114 .deposit(long_swap_output.amount, short_swap_output.amount, prices)?
115 .execute()
116 })?
117 };
118
119 let minted = report.minted();
120 let min_market_token_amount = u128::from(params.min_market_token_amount);
121 if *minted < min_market_token_amount {
122 return Err(crate::Error::custom(format!(
123 "[sim] insufficient output amount: {minted} < {min_market_token_amount}",
124 )));
125 }
126
127 Ok(DepositSimulationOutput {
128 long_swaps: long_swap_output.reports,
129 short_swaps: short_swap_output.reports,
130 report: Box::new(report),
131 })
132 }
133}