1use crate::{
2 action::update_funding_state::UpdateFundingState,
3 num::Unsigned,
4 params::{
5 fee::{FundingFeeParams, LiquidationFeeParams},
6 FeeParams, PositionParams,
7 },
8 price::{Price, Prices},
9 BalanceExt, BorrowingFeeMarket, PoolExt, PositionImpactMarket, PositionImpactMarketMut,
10 SwapMarket, SwapMarketMut,
11};
12
13use super::BaseMarketExt;
14
15pub trait PerpMarket<const DECIMALS: u8>:
17 SwapMarket<DECIMALS> + PositionImpactMarket<DECIMALS> + BorrowingFeeMarket<DECIMALS>
18{
19 fn funding_factor_per_second(&self) -> &Self::Signed;
21
22 fn funding_amount_per_size_pool(&self, is_long: bool) -> crate::Result<&Self::Pool>;
24
25 fn claimable_funding_amount_per_size_pool(&self, is_long: bool) -> crate::Result<&Self::Pool>;
27
28 fn funding_amount_per_size_adjustment(&self) -> Self::Num;
30
31 fn funding_fee_params(&self) -> crate::Result<FundingFeeParams<Self::Num>>;
33
34 fn position_params(&self) -> crate::Result<PositionParams<Self::Num>>;
36
37 fn order_fee_params(&self) -> crate::Result<FeeParams<Self::Num>>;
39
40 fn min_collateral_factor_for_open_interest_multiplier(
42 &self,
43 is_long: bool,
44 ) -> crate::Result<Self::Num>;
45
46 fn liquidation_fee_params(&self) -> crate::Result<LiquidationFeeParams<Self::Num>>;
48}
49
50pub trait PerpMarketMut<const DECIMALS: u8>:
52 SwapMarketMut<DECIMALS> + PositionImpactMarketMut<DECIMALS> + PerpMarket<DECIMALS>
53{
54 fn just_passed_in_seconds_for_funding(&mut self) -> crate::Result<u64>;
56
57 fn funding_factor_per_second_mut(&mut self) -> &mut Self::Signed;
59
60 fn open_interest_pool_mut(&mut self, is_long: bool) -> crate::Result<&mut Self::Pool>;
65
66 fn open_interest_in_tokens_pool_mut(&mut self, is_long: bool)
71 -> crate::Result<&mut Self::Pool>;
72
73 fn funding_amount_per_size_pool_mut(&mut self, is_long: bool)
77 -> crate::Result<&mut Self::Pool>;
78
79 fn claimable_funding_amount_per_size_pool_mut(
83 &mut self,
84 is_long: bool,
85 ) -> crate::Result<&mut Self::Pool>;
86
87 fn collateral_sum_pool_mut(&mut self, is_long: bool) -> crate::Result<&mut Self::Pool>;
92
93 fn total_borrowing_pool_mut(&mut self) -> crate::Result<&mut Self::Pool>;
97
98 fn on_insufficient_funding_fee_payment(
100 &mut self,
101 _paid_in_collateral_amount: &Self::Num,
102 _cost_amount: &Self::Num,
103 ) -> crate::Result<()> {
104 Ok(())
105 }
106}
107
108impl<M: PerpMarket<DECIMALS>, const DECIMALS: u8> PerpMarket<DECIMALS> for &mut M {
109 fn funding_factor_per_second(&self) -> &Self::Signed {
110 (**self).funding_factor_per_second()
111 }
112
113 fn funding_amount_per_size_pool(&self, is_long: bool) -> crate::Result<&Self::Pool> {
114 (**self).funding_amount_per_size_pool(is_long)
115 }
116
117 fn claimable_funding_amount_per_size_pool(&self, is_long: bool) -> crate::Result<&Self::Pool> {
118 (**self).claimable_funding_amount_per_size_pool(is_long)
119 }
120
121 fn funding_amount_per_size_adjustment(&self) -> Self::Num {
122 (**self).funding_amount_per_size_adjustment()
123 }
124
125 fn funding_fee_params(&self) -> crate::Result<FundingFeeParams<Self::Num>> {
126 (**self).funding_fee_params()
127 }
128
129 fn position_params(&self) -> crate::Result<PositionParams<Self::Num>> {
130 (**self).position_params()
131 }
132
133 fn order_fee_params(&self) -> crate::Result<FeeParams<Self::Num>> {
134 (**self).order_fee_params()
135 }
136
137 fn min_collateral_factor_for_open_interest_multiplier(
138 &self,
139 is_long: bool,
140 ) -> crate::Result<Self::Num> {
141 (**self).min_collateral_factor_for_open_interest_multiplier(is_long)
142 }
143
144 fn liquidation_fee_params(&self) -> crate::Result<LiquidationFeeParams<Self::Num>> {
145 (**self).liquidation_fee_params()
146 }
147}
148
149impl<M: PerpMarketMut<DECIMALS>, const DECIMALS: u8> PerpMarketMut<DECIMALS> for &mut M {
150 fn funding_factor_per_second_mut(&mut self) -> &mut Self::Signed {
151 (**self).funding_factor_per_second_mut()
152 }
153
154 fn open_interest_pool_mut(&mut self, is_long: bool) -> crate::Result<&mut Self::Pool> {
155 (**self).open_interest_pool_mut(is_long)
156 }
157
158 fn open_interest_in_tokens_pool_mut(
159 &mut self,
160 is_long: bool,
161 ) -> crate::Result<&mut Self::Pool> {
162 (**self).open_interest_in_tokens_pool_mut(is_long)
163 }
164
165 fn funding_amount_per_size_pool_mut(
166 &mut self,
167 is_long: bool,
168 ) -> crate::Result<&mut Self::Pool> {
169 (**self).funding_amount_per_size_pool_mut(is_long)
170 }
171
172 fn claimable_funding_amount_per_size_pool_mut(
173 &mut self,
174 is_long: bool,
175 ) -> crate::Result<&mut Self::Pool> {
176 (**self).claimable_funding_amount_per_size_pool_mut(is_long)
177 }
178
179 fn collateral_sum_pool_mut(&mut self, is_long: bool) -> crate::Result<&mut Self::Pool> {
180 (**self).collateral_sum_pool_mut(is_long)
181 }
182
183 fn total_borrowing_pool_mut(&mut self) -> crate::Result<&mut Self::Pool> {
184 (**self).total_borrowing_pool_mut()
185 }
186
187 fn just_passed_in_seconds_for_funding(&mut self) -> crate::Result<u64> {
188 (**self).just_passed_in_seconds_for_funding()
189 }
190
191 fn on_insufficient_funding_fee_payment(
192 &mut self,
193 paid_in_collateral_amount: &Self::Num,
194 cost_amount: &Self::Num,
195 ) -> crate::Result<()> {
196 (**self).on_insufficient_funding_fee_payment(paid_in_collateral_amount, cost_amount)
197 }
198}
199
200pub trait PerpMarketExt<const DECIMALS: u8>: PerpMarket<DECIMALS> {
202 #[inline]
204 fn funding_fee_amount_per_size(
205 &self,
206 is_long: bool,
207 is_long_collateral: bool,
208 ) -> crate::Result<Self::Num> {
209 self.funding_amount_per_size_pool(is_long)?
210 .amount(is_long_collateral)
211 }
212
213 #[inline]
215 fn claimable_funding_fee_amount_per_size(
216 &self,
217 is_long: bool,
218 is_long_collateral: bool,
219 ) -> crate::Result<Self::Num> {
220 self.claimable_funding_amount_per_size_pool(is_long)?
221 .amount(is_long_collateral)
222 }
223
224 fn validate_open_interest_reserve(
226 &self,
227 prices: &Prices<Self::Num>,
228 is_long: bool,
229 ) -> crate::Result<()> {
230 let pool_value = self.pool_value_without_pnl_for_one_side(prices, is_long, false)?;
231
232 let max_reserved_value =
233 crate::utils::apply_factor(&pool_value, &self.open_interest_reserve_factor()?)
234 .ok_or(crate::Error::Computation("calculating max reserved value"))?;
235
236 let reserved_value = self.reserved_value(&prices.index_token_price, is_long)?;
237
238 if reserved_value > max_reserved_value {
239 Err(crate::Error::InsufficientReserveForOpenInterest(
240 reserved_value.to_string(),
241 max_reserved_value.to_string(),
242 ))
243 } else {
244 Ok(())
245 }
246 }
247
248 fn min_collateral_factor_for_open_interest(
250 &self,
251 delta: &Self::Signed,
252 is_long: bool,
253 ) -> crate::Result<Self::Num> {
254 let next_open_interest = self
255 .open_interest()?
256 .amount(is_long)?
257 .checked_add_with_signed(delta)
258 .ok_or(crate::Error::Computation(
259 "calculating next OI for min collateral factor",
260 ))?;
261 let factor = self.min_collateral_factor_for_open_interest_multiplier(is_long)?;
262 crate::utils::apply_factor(&next_open_interest, &factor).ok_or(crate::Error::Computation(
263 "calculating min collateral factor for OI",
264 ))
265 }
266
267 fn cap_positive_position_price_impact(
270 &self,
271 index_token_price: &Price<Self::Num>,
272 size_delta_usd: &Self::Signed,
273 impact: &mut Self::Signed,
274 ) -> crate::Result<()> {
275 use crate::{market::PositionImpactMarketExt, num::UnsignedAbs, utils};
276 use num_traits::{CheckedMul, Signed};
277
278 if impact.is_positive() {
279 let impact_pool_amount = self.position_impact_pool_amount()?;
280 let max_impact = impact_pool_amount
282 .checked_mul(index_token_price.pick_price(false))
283 .ok_or(crate::Error::Computation(
284 "overflow calculating max positive position impact based on pool amount",
285 ))?
286 .to_signed()?;
287 if *impact > max_impact {
288 *impact = max_impact;
289 }
290
291 let params = self.position_params()?;
293 let max_impact_factor = params.max_positive_position_impact_factor();
294 let max_impact = utils::apply_factor(&size_delta_usd.unsigned_abs(), max_impact_factor)
295 .ok_or(crate::Error::Computation(
296 "calculating max positive position impact based on max factor",
297 ))?
298 .to_signed()?;
299 if *impact > max_impact {
300 *impact = max_impact;
301 }
302 }
303 Ok(())
304 }
305
306 fn cap_negative_position_price_impact(
313 &self,
314 size_delta_usd: &Self::Signed,
315 for_liquidations: bool,
316 impact: &mut Self::Signed,
317 ) -> crate::Result<Self::Num> {
318 use crate::{num::UnsignedAbs, utils};
319 use num_traits::{CheckedSub, Signed, Zero};
320
321 let mut impact_diff = Zero::zero();
322 if impact.is_negative() {
323 let params = self.position_params()?;
324 let max_impact_factor = if for_liquidations {
325 params.max_position_impact_factor_for_liquidations()
326 } else {
327 params.max_negative_position_impact_factor()
328 };
329 let min_impact = utils::apply_factor(&size_delta_usd.unsigned_abs(), max_impact_factor)
333 .ok_or(crate::Error::Computation(
334 "calculating max negative position impact based on max factor",
335 ))?
336 .to_opposite_signed()?;
337 if *impact < min_impact {
338 impact_diff = min_impact
339 .checked_sub(impact)
340 .ok_or(crate::Error::Computation(
341 "overflow calculating impact diff",
342 ))?
343 .unsigned_abs();
344 *impact = min_impact;
345 }
346 }
347 Ok(impact_diff)
348 }
349}
350
351impl<M: PerpMarket<DECIMALS>, const DECIMALS: u8> PerpMarketExt<DECIMALS> for M {}
352
353pub trait PerpMarketMutExt<const DECIMALS: u8>: PerpMarketMut<DECIMALS> {
355 fn update_funding(
357 &mut self,
358 prices: &Prices<Self::Num>,
359 ) -> crate::Result<UpdateFundingState<&mut Self, DECIMALS>>
360 where
361 Self: Sized,
362 {
363 UpdateFundingState::try_new(self, prices)
364 }
365
366 fn apply_delta_to_funding_amount_per_size(
368 &mut self,
369 is_long: bool,
370 is_long_collateral: bool,
371 delta: &Self::Signed,
372 ) -> crate::Result<()> {
373 self.funding_amount_per_size_pool_mut(is_long)?
374 .apply_delta_amount(is_long_collateral, delta)
375 }
376
377 fn apply_delta_to_claimable_funding_amount_per_size(
379 &mut self,
380 is_long: bool,
381 is_long_collateral: bool,
382 delta: &Self::Signed,
383 ) -> crate::Result<()> {
384 self.claimable_funding_amount_per_size_pool_mut(is_long)?
385 .apply_delta_amount(is_long_collateral, delta)
386 }
387}
388
389impl<M: PerpMarketMut<DECIMALS>, const DECIMALS: u8> PerpMarketMutExt<DECIMALS> for M {}