gmsol_store/states/market/
pool.rs1use anchor_lang::prelude::*;
2use borsh::{BorshDeserialize, BorshSerialize};
3use gmsol_model::PoolKind;
4
5#[zero_copy]
7#[cfg_attr(feature = "debug", derive(Debug))]
8#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
9pub struct PoolStorage {
10 pub(super) rev: u64,
11 padding: [u8; 8],
12 pool: Pool,
13}
14
15impl PoolStorage {
16 pub(crate) fn set_is_pure(&mut self, is_pure: bool) {
18 self.pool.set_is_pure(is_pure);
19 }
20
21 pub fn pool(&self) -> &Pool {
23 &self.pool
24 }
25
26 pub(super) fn pool_mut(&mut self) -> &mut Pool {
28 &mut self.pool
29 }
30}
31
32#[zero_copy]
34#[cfg_attr(feature = "debug", derive(derive_more::Debug))]
35#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
36#[derive(BorshSerialize, BorshDeserialize, InitSpace)]
37pub struct Pool {
38 is_pure: u8,
42 #[cfg_attr(feature = "serde", serde(skip))]
43 #[cfg_attr(feature = "debug", debug(skip))]
44 padding: [u8; 15],
45 pub(super) long_token_amount: u128,
47 pub(super) short_token_amount: u128,
49}
50
51const PURE_VALUE: u8 = 1;
52
53impl Pool {
54 fn set_is_pure(&mut self, is_pure: bool) {
56 self.is_pure = if is_pure { PURE_VALUE } else { 0 };
57 }
58
59 fn is_pure(&self) -> bool {
61 !matches!(self.is_pure, 0)
62 }
63}
64
65impl gmsol_model::Balance for Pool {
66 type Num = u128;
67
68 type Signed = i128;
69
70 fn long_amount(&self) -> gmsol_model::Result<Self::Num> {
72 if self.is_pure() {
73 debug_assert_eq!(
74 self.short_token_amount, 0,
75 "short token amount must be zero"
76 );
77 Ok(self.long_token_amount.div_ceil(2))
82 } else {
83 Ok(self.long_token_amount)
84 }
85 }
86
87 fn short_amount(&self) -> gmsol_model::Result<Self::Num> {
89 if self.is_pure() {
90 debug_assert_eq!(
91 self.short_token_amount, 0,
92 "short token amount must be zero"
93 );
94 Ok(self.long_token_amount / 2)
95 } else {
96 Ok(self.short_token_amount)
97 }
98 }
99}
100
101impl gmsol_model::Pool for Pool {
102 fn apply_delta_to_long_amount(&mut self, delta: &Self::Signed) -> gmsol_model::Result<()> {
103 self.long_token_amount = self.long_token_amount.checked_add_signed(*delta).ok_or(
104 gmsol_model::Error::Computation("apply delta to long amount"),
105 )?;
106 Ok(())
107 }
108
109 fn apply_delta_to_short_amount(&mut self, delta: &Self::Signed) -> gmsol_model::Result<()> {
110 let amount = if self.is_pure() {
111 &mut self.long_token_amount
112 } else {
113 &mut self.short_token_amount
114 };
115 *amount = amount
116 .checked_add_signed(*delta)
117 .ok_or(gmsol_model::Error::Computation(
118 "apply delta to short amount",
119 ))?;
120 Ok(())
121 }
122
123 fn checked_apply_delta(
124 &self,
125 delta: gmsol_model::Delta<&Self::Signed>,
126 ) -> gmsol_model::Result<Self> {
127 let mut ans = *self;
128 if let Some(amount) = delta.long() {
129 ans.apply_delta_to_long_amount(amount)?;
130 }
131 if let Some(amount) = delta.short() {
132 ans.apply_delta_to_short_amount(amount)?;
133 }
134 Ok(ans)
135 }
136}
137
138#[zero_copy]
140#[cfg_attr(feature = "debug", derive(derive_more::Debug))]
141#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
142pub struct Pools {
143 primary: PoolStorage,
145 swap_impact: PoolStorage,
147 claimable_fee: PoolStorage,
149 open_interest_for_long: PoolStorage,
151 open_interest_for_short: PoolStorage,
153 open_interest_in_tokens_for_long: PoolStorage,
155 open_interest_in_tokens_for_short: PoolStorage,
157 position_impact: PoolStorage,
159 borrowing_factor: PoolStorage,
161 funding_amount_per_size_for_long: PoolStorage,
163 funding_amount_per_size_for_short: PoolStorage,
165 claimable_funding_amount_per_size_for_long: PoolStorage,
167 claimable_funding_amount_per_size_for_short: PoolStorage,
169 collateral_sum_for_long: PoolStorage,
171 collateral_sum_for_short: PoolStorage,
173 total_borrowing: PoolStorage,
175 #[cfg_attr(feature = "debug", debug(skip))]
176 reserved: [PoolStorage; 16],
177}
178
179impl Pools {
180 pub(super) fn init(&mut self, is_pure: bool) {
181 self.primary.set_is_pure(is_pure);
182 self.swap_impact.set_is_pure(is_pure);
183 self.claimable_fee.set_is_pure(is_pure);
184 self.open_interest_for_long.set_is_pure(is_pure);
185 self.open_interest_for_short.set_is_pure(is_pure);
186 self.open_interest_in_tokens_for_long.set_is_pure(is_pure);
187 self.open_interest_in_tokens_for_short.set_is_pure(is_pure);
188 self.position_impact.set_is_pure(false);
190 self.borrowing_factor.set_is_pure(false);
192 self.funding_amount_per_size_for_long.set_is_pure(is_pure);
193 self.funding_amount_per_size_for_short.set_is_pure(is_pure);
194 self.claimable_funding_amount_per_size_for_long
195 .set_is_pure(is_pure);
196 self.claimable_funding_amount_per_size_for_short
197 .set_is_pure(is_pure);
198 self.collateral_sum_for_long.set_is_pure(is_pure);
199 self.collateral_sum_for_short.set_is_pure(is_pure);
200 self.total_borrowing.set_is_pure(false);
202 }
203
204 pub(super) fn get(&self, kind: PoolKind) -> Option<&PoolStorage> {
205 let pool = match kind {
206 PoolKind::Primary => &self.primary,
207 PoolKind::SwapImpact => &self.swap_impact,
208 PoolKind::ClaimableFee => &self.claimable_fee,
209 PoolKind::OpenInterestForLong => &self.open_interest_for_long,
210 PoolKind::OpenInterestForShort => &self.open_interest_for_short,
211 PoolKind::OpenInterestInTokensForLong => &self.open_interest_in_tokens_for_long,
212 PoolKind::OpenInterestInTokensForShort => &self.open_interest_in_tokens_for_short,
213 PoolKind::PositionImpact => &self.position_impact,
214 PoolKind::BorrowingFactor => &self.borrowing_factor,
215 PoolKind::FundingAmountPerSizeForLong => &self.funding_amount_per_size_for_long,
216 PoolKind::FundingAmountPerSizeForShort => &self.funding_amount_per_size_for_short,
217 PoolKind::ClaimableFundingAmountPerSizeForLong => {
218 &self.claimable_funding_amount_per_size_for_long
219 }
220 PoolKind::ClaimableFundingAmountPerSizeForShort => {
221 &self.claimable_funding_amount_per_size_for_short
222 }
223 PoolKind::CollateralSumForLong => &self.collateral_sum_for_long,
224 PoolKind::CollateralSumForShort => &self.collateral_sum_for_short,
225 PoolKind::TotalBorrowing => &self.total_borrowing,
226 _ => return None,
227 };
228 Some(pool)
229 }
230
231 pub(super) fn get_mut(&mut self, kind: PoolKind) -> Option<&mut PoolStorage> {
232 let pool = match kind {
233 PoolKind::Primary => &mut self.primary,
234 PoolKind::SwapImpact => &mut self.swap_impact,
235 PoolKind::ClaimableFee => &mut self.claimable_fee,
236 PoolKind::OpenInterestForLong => &mut self.open_interest_for_long,
237 PoolKind::OpenInterestForShort => &mut self.open_interest_for_short,
238 PoolKind::OpenInterestInTokensForLong => &mut self.open_interest_in_tokens_for_long,
239 PoolKind::OpenInterestInTokensForShort => &mut self.open_interest_in_tokens_for_short,
240 PoolKind::PositionImpact => &mut self.position_impact,
241 PoolKind::BorrowingFactor => &mut self.borrowing_factor,
242 PoolKind::FundingAmountPerSizeForLong => &mut self.funding_amount_per_size_for_long,
243 PoolKind::FundingAmountPerSizeForShort => &mut self.funding_amount_per_size_for_short,
244 PoolKind::ClaimableFundingAmountPerSizeForLong => {
245 &mut self.claimable_funding_amount_per_size_for_long
246 }
247 PoolKind::ClaimableFundingAmountPerSizeForShort => {
248 &mut self.claimable_funding_amount_per_size_for_short
249 }
250 PoolKind::CollateralSumForLong => &mut self.collateral_sum_for_long,
251 PoolKind::CollateralSumForShort => &mut self.collateral_sum_for_short,
252 PoolKind::TotalBorrowing => &mut self.total_borrowing,
253 _ => return None,
254 };
255 Some(pool)
256 }
257}
258
259#[cfg(test)]
260mod tests {
261 use super::*;
262 use crate::events::EventPool;
263
264 #[test]
265 fn test_event_pool() {
266 let pool = Pool {
267 is_pure: PURE_VALUE,
268 padding: Default::default(),
269 long_token_amount: u128::MAX,
270 short_token_amount: u128::MAX,
271 };
272
273 let event_pool = EventPool {
274 is_pure: pool.is_pure,
275 padding: pool.padding,
276 long_token_amount: pool.long_token_amount,
277 short_token_amount: pool.short_token_amount,
278 };
279
280 let mut data = Vec::with_capacity(Pool::INIT_SPACE);
281 pool.serialize(&mut data)
282 .expect("failed to serialize `Pool`");
283
284 let mut event_data = Vec::with_capacity(Pool::INIT_SPACE);
285 event_pool
286 .serialize(&mut event_data)
287 .expect("failed to serialize `EventPool`");
288
289 assert_eq!(data, event_data);
290 }
291}