gmsol_sdk/glv/
calculator.rs1use gmsol_model::utils::market_token_amount_to_usd;
2use solana_sdk::pubkey::Pubkey;
3
4use crate::{
5 glv::{GlvModel, GlvStatus},
6 market::{caluclator::MarketCalculator, MarketCalculations, Value},
7};
8
9pub trait GlvCalculator: MarketCalculator {
11 fn get_glv_model(&self, glv_token: &Pubkey) -> Option<&GlvModel>;
13
14 fn get_market_token_value_in_glv(
16 &self,
17 glv_token: &Pubkey,
18 market_token: &Pubkey,
19 maximize: bool,
20 ) -> crate::Result<u128> {
21 Calculator::new(self, glv_token)?.get_market_token_value_in_glv(market_token, maximize)
22 }
23
24 fn get_glv_value(&self, glv_token: &Pubkey, maximize: bool) -> crate::Result<u128> {
26 Calculator::new(self, glv_token)?.get_glv_value(maximize)
27 }
28
29 fn get_glv_token_value(
31 &self,
32 glv_token: &Pubkey,
33 amount: u64,
34 maximize: bool,
35 ) -> crate::Result<u128> {
36 Calculator::new(self, glv_token)?.get_glv_token_value(amount, maximize)
37 }
38
39 fn get_max_sellable_glv_value_for_market_token(
41 &self,
42 glv_token: &Pubkey,
43 market_token: &Pubkey,
44 ) -> crate::Result<u128> {
45 Calculator::new(self, glv_token)?.get_max_sellable_glv_value_for_market_token(market_token)
46 }
47
48 fn get_max_sellable_glv_value(&self, glv_token: &Pubkey) -> crate::Result<u128> {
50 let calculator = Calculator::new(self, glv_token)?;
51
52 let mut value = 0u128;
53 for market_token in calculator.glv.market_tokens() {
54 value = value
55 .checked_add(calculator.get_max_sellable_glv_value_for_market_token(&market_token)?)
56 .ok_or_else(|| crate::Error::custom("max sellable value overflow"))?;
57 }
58
59 Ok(value)
60 }
61
62 fn get_glv_status(&self, glv_token: &Pubkey) -> crate::Result<GlvStatus> {
64 Calculator::new(self, glv_token)?.get_glv_status()
65 }
66}
67
68struct Calculator<'a, C: ?Sized> {
69 glv: &'a GlvModel,
70 context: &'a C,
71}
72
73impl<'a, C: GlvCalculator + ?Sized> Calculator<'a, C> {
74 fn new(context: &'a C, glv_token: &Pubkey) -> crate::Result<Self> {
75 let glv = context.get_glv_model(glv_token).ok_or_else(|| {
76 crate::Error::custom(format!("[sim] GLV for GLV token `{glv_token}` not found"))
77 })?;
78
79 Ok(Self { glv, context })
80 }
81
82 fn get_market_token_value_in_glv(
83 &self,
84 market_token: &Pubkey,
85 maximize: bool,
86 ) -> crate::Result<u128> {
87 let Self { glv, context } = self;
88 let balance = glv
89 .market_config(market_token)
90 .ok_or_else(|| {
91 crate::Error::custom(format!(
92 "[sim] the given GLV does not include the specified market token: {market_token}"
93 ))
94 })?
95 .balance;
96 let (market, prices) = context.get_market_model_with_prices(market_token)?;
97 let value_for_market =
98 gmsol_model::glv::get_glv_value_for_market(&prices, market, balance.into(), maximize)?
99 .market_token_value_in_glv;
100 Ok(value_for_market)
101 }
102
103 fn get_max_sellable_glv_value_for_market_token(
104 &self,
105 market_token: &Pubkey,
106 ) -> crate::Result<u128> {
107 let value_in_glv = self.get_market_token_value_in_glv(market_token, false)?;
108 let (market, prices) = self
109 .context
110 .get_market_model_with_prices(market_token)
111 .expect("must exist");
112 let max_sellable_value = market.max_sellable_value(&prices)?;
113 Ok(value_in_glv.min(max_sellable_value))
114 }
115
116 fn get_max_sellable_glv_value(&self) -> crate::Result<u128> {
117 let mut value = 0u128;
118 for market_token in self.glv.market_tokens() {
119 value = value
120 .checked_add(self.get_max_sellable_glv_value_for_market_token(&market_token)?)
121 .ok_or_else(|| crate::Error::custom("max sellable value overflow"))?;
122 }
123
124 Ok(value)
125 }
126
127 fn get_glv_value(&self, maximize: bool) -> crate::Result<u128> {
128 let mut value = 0u128;
129
130 for market_token in self.glv.market_tokens() {
131 let value_for_market = self.get_market_token_value_in_glv(&market_token, maximize)?;
132 value = value
133 .checked_add(value_for_market)
134 .ok_or(crate::Error::custom("[sim] GLV value overflow"))?;
135 }
136
137 Ok(value)
138 }
139
140 fn get_glv_token_value(&self, amount: u64, maximize: bool) -> crate::Result<u128> {
141 let glv_value = self.get_glv_value(maximize)?;
142 let supply = self.glv.supply();
143 let value =
144 market_token_amount_to_usd(&(u128::from(amount)), &glv_value, &u128::from(supply))
145 .ok_or_else(|| {
146 crate::Error::custom("[sim] failed to convert glv token amount into value")
147 })?;
148 Ok(value)
149 }
150
151 fn get_glv_status(&self) -> crate::Result<GlvStatus> {
152 let max_sellable_value = self.get_max_sellable_glv_value()?;
153 let max_total_value = self.get_glv_value(true)?;
154 let min_total_value = self.get_glv_value(false)?;
155 Ok(GlvStatus {
156 max_sellable_value,
157 total_value: Value {
158 min: min_total_value,
159 max: max_total_value,
160 },
161 })
162 }
163}