1use num_traits::CheckedSub;
2
3use crate::num::Unsigned;
4
5use self::delta::PoolDelta;
6
7pub mod balance;
9
10pub mod delta;
12
13pub use self::{
14 balance::{Balance, BalanceExt},
15 delta::Delta,
16};
17
18pub trait Pool: Balance + Sized {
20 fn apply_delta_to_long_amount(&mut self, delta: &Self::Signed) -> crate::Result<()> {
22 *self = self.checked_apply_delta(Delta::new_with_long(delta))?;
23 Ok(())
24 }
25
26 fn apply_delta_to_short_amount(&mut self, delta: &Self::Signed) -> crate::Result<()> {
28 *self = self.checked_apply_delta(Delta::new_with_short(delta))?;
29 Ok(())
30 }
31
32 fn checked_apply_delta(&self, delta: Delta<&Self::Signed>) -> crate::Result<Self>;
34
35 fn checked_cancel_amounts(&self) -> crate::Result<Self>
40 where
41 Self::Signed: CheckedSub,
42 {
43 let long_amount = self.long_amount()?;
44 let short_amount = self.short_amount()?;
45 let is_long_side_left = long_amount >= short_amount;
46 let leftover_amount = long_amount.clone().diff(short_amount.clone());
47 let (long_delta, short_delta) = if is_long_side_left {
48 (long_amount.diff(leftover_amount), short_amount)
49 } else {
50 (long_amount, short_amount.diff(leftover_amount))
51 };
52 self.checked_apply_delta(Delta::new_both_sides(
53 true,
54 &long_delta.to_opposite_signed()?,
55 &short_delta.to_opposite_signed()?,
56 ))
57 }
58}
59
60pub trait PoolExt: Pool {
62 #[inline]
64 fn apply_delta_amount(&mut self, is_long: bool, delta: &Self::Signed) -> crate::Result<()> {
65 if is_long {
66 self.apply_delta_to_long_amount(delta)
67 } else {
68 self.apply_delta_to_short_amount(delta)
69 }
70 }
71}
72
73impl<P: Pool> PoolExt for P {}
74
75#[derive(
77 Debug,
78 Clone,
79 Copy,
80 Default,
81 num_enum::TryFromPrimitive,
82 num_enum::IntoPrimitive,
83 PartialEq,
84 Eq,
85 PartialOrd,
86 Ord,
87 Hash,
88)]
89#[cfg_attr(
90 feature = "strum",
91 derive(strum::EnumIter, strum::EnumString, strum::Display)
92)]
93#[cfg_attr(feature = "strum", strum(serialize_all = "snake_case"))]
94#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
95#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))]
96#[cfg_attr(
97 feature = "anchor-lang",
98 derive(
99 anchor_lang::AnchorDeserialize,
100 anchor_lang::AnchorSerialize,
101 anchor_lang::InitSpace
102 )
103)]
104#[repr(u8)]
105#[non_exhaustive]
106pub enum PoolKind {
107 #[default]
109 Primary,
110 SwapImpact,
112 ClaimableFee,
114 OpenInterestForLong,
116 OpenInterestForShort,
118 OpenInterestInTokensForLong,
120 OpenInterestInTokensForShort,
122 PositionImpact,
124 BorrowingFactor,
126 FundingAmountPerSizeForLong,
128 FundingAmountPerSizeForShort,
130 ClaimableFundingAmountPerSizeForLong,
132 ClaimableFundingAmountPerSizeForShort,
134 CollateralSumForLong,
136 CollateralSumForShort,
138 TotalBorrowing,
140}
141
142#[cfg(test)]
143mod tests {
144 use crate::{test::TestPool, Balance};
145
146 use super::{Delta, Pool};
147
148 #[test]
149 fn cancel_amounts() -> crate::Result<()> {
150 let pool = TestPool::<u64>::default();
151
152 let pool_1 = pool.checked_apply_delta(Delta::new_both_sides(true, &1_000, &3_000))?;
153 let expected_1 = pool.checked_apply_delta(Delta::new_both_sides(true, &0, &2_000))?;
154 assert_eq!(pool_1.checked_cancel_amounts()?, expected_1);
155
156 let pool_2 = pool.checked_apply_delta(Delta::new_both_sides(true, &3_005, &3_000))?;
157 let expected_2 = pool.checked_apply_delta(Delta::new_both_sides(true, &5, &0))?;
158 assert_eq!(pool_2.checked_cancel_amounts()?, expected_2);
159
160 let pool_3 = pool.checked_apply_delta(Delta::new_both_sides(true, &3_000, &3_000))?;
161 let expected_3 = pool.checked_apply_delta(Delta::new_both_sides(true, &0, &0))?;
162 assert_eq!(pool_3.checked_cancel_amounts()?, expected_3);
163
164 let pool_4 = pool
165 .checked_apply_delta(Delta::new_both_sides(true, &i64::MAX, &i64::MAX))?
166 .checked_apply_delta(Delta::new_both_sides(true, &i64::MAX, &i64::MAX))?
167 .checked_apply_delta(Delta::new_both_sides(true, &1, &1))?;
168 assert_eq!(pool_4.long_amount()?, u64::MAX);
169 assert_eq!(pool_4.short_amount()?, u64::MAX);
170 assert!(pool_4.checked_cancel_amounts().is_err());
172
173 let pool_5 = pool.checked_apply_delta(Delta::new_both_sides(true, &i64::MAX, &i64::MAX))?;
174 let expected_5 = pool.checked_apply_delta(Delta::new_both_sides(true, &0, &0))?;
175 assert_eq!(pool_5.checked_cancel_amounts()?, expected_5);
176 let pool_5 = pool
177 .checked_apply_delta(Delta::new_both_sides(true, &i64::MAX, &i64::MAX))?
178 .checked_apply_delta(Delta::new_both_sides(true, &i64::MAX, &0))?
179 .checked_apply_delta(Delta::new_both_sides(true, &1, &0))?;
180 let expected_5 = pool
181 .checked_apply_delta(Delta::new_both_sides(true, &i64::MAX, &0))?
182 .checked_apply_delta(Delta::new_both_sides(true, &1, &0))?;
183 assert_eq!(pool_5.long_amount()?, u64::MAX);
184 assert_eq!(pool_5.short_amount()?, i64::MAX.unsigned_abs());
185 assert_eq!(pool_5.checked_cancel_amounts()?, expected_5);
186
187 Ok(())
188 }
189}