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 _cost_amount: &Self::Num,
102 _paid_in_collateral_amount: &Self::Num,
103 _paid_in_secondary_output_amount: &Self::Num,
104 _is_collateral_token_long: bool,
105 ) -> crate::Result<()> {
106 Ok(())
107 }
108}
109
110impl<M: PerpMarket<DECIMALS>, const DECIMALS: u8> PerpMarket<DECIMALS> for &mut M {
111 fn funding_factor_per_second(&self) -> &Self::Signed {
112 (**self).funding_factor_per_second()
113 }
114
115 fn funding_amount_per_size_pool(&self, is_long: bool) -> crate::Result<&Self::Pool> {
116 (**self).funding_amount_per_size_pool(is_long)
117 }
118
119 fn claimable_funding_amount_per_size_pool(&self, is_long: bool) -> crate::Result<&Self::Pool> {
120 (**self).claimable_funding_amount_per_size_pool(is_long)
121 }
122
123 fn funding_amount_per_size_adjustment(&self) -> Self::Num {
124 (**self).funding_amount_per_size_adjustment()
125 }
126
127 fn funding_fee_params(&self) -> crate::Result<FundingFeeParams<Self::Num>> {
128 (**self).funding_fee_params()
129 }
130
131 fn position_params(&self) -> crate::Result<PositionParams<Self::Num>> {
132 (**self).position_params()
133 }
134
135 fn order_fee_params(&self) -> crate::Result<FeeParams<Self::Num>> {
136 (**self).order_fee_params()
137 }
138
139 fn min_collateral_factor_for_open_interest_multiplier(
140 &self,
141 is_long: bool,
142 ) -> crate::Result<Self::Num> {
143 (**self).min_collateral_factor_for_open_interest_multiplier(is_long)
144 }
145
146 fn liquidation_fee_params(&self) -> crate::Result<LiquidationFeeParams<Self::Num>> {
147 (**self).liquidation_fee_params()
148 }
149}
150
151impl<M: PerpMarketMut<DECIMALS>, const DECIMALS: u8> PerpMarketMut<DECIMALS> for &mut M {
152 fn funding_factor_per_second_mut(&mut self) -> &mut Self::Signed {
153 (**self).funding_factor_per_second_mut()
154 }
155
156 fn open_interest_pool_mut(&mut self, is_long: bool) -> crate::Result<&mut Self::Pool> {
157 (**self).open_interest_pool_mut(is_long)
158 }
159
160 fn open_interest_in_tokens_pool_mut(
161 &mut self,
162 is_long: bool,
163 ) -> crate::Result<&mut Self::Pool> {
164 (**self).open_interest_in_tokens_pool_mut(is_long)
165 }
166
167 fn funding_amount_per_size_pool_mut(
168 &mut self,
169 is_long: bool,
170 ) -> crate::Result<&mut Self::Pool> {
171 (**self).funding_amount_per_size_pool_mut(is_long)
172 }
173
174 fn claimable_funding_amount_per_size_pool_mut(
175 &mut self,
176 is_long: bool,
177 ) -> crate::Result<&mut Self::Pool> {
178 (**self).claimable_funding_amount_per_size_pool_mut(is_long)
179 }
180
181 fn collateral_sum_pool_mut(&mut self, is_long: bool) -> crate::Result<&mut Self::Pool> {
182 (**self).collateral_sum_pool_mut(is_long)
183 }
184
185 fn total_borrowing_pool_mut(&mut self) -> crate::Result<&mut Self::Pool> {
186 (**self).total_borrowing_pool_mut()
187 }
188
189 fn just_passed_in_seconds_for_funding(&mut self) -> crate::Result<u64> {
190 (**self).just_passed_in_seconds_for_funding()
191 }
192
193 fn on_insufficient_funding_fee_payment(
194 &mut self,
195 cost_amount: &Self::Num,
196 paid_in_collateral_amount: &Self::Num,
197 paid_in_secondary_output_amount: &Self::Num,
198 is_collateral_token_long: bool,
199 ) -> crate::Result<()> {
200 (**self).on_insufficient_funding_fee_payment(
201 cost_amount,
202 paid_in_collateral_amount,
203 paid_in_secondary_output_amount,
204 is_collateral_token_long,
205 )
206 }
207}
208
209pub trait PerpMarketExt<const DECIMALS: u8>: PerpMarket<DECIMALS> {
211 #[inline]
213 fn funding_fee_amount_per_size(
214 &self,
215 is_long: bool,
216 is_long_collateral: bool,
217 ) -> crate::Result<Self::Num> {
218 self.funding_amount_per_size_pool(is_long)?
219 .amount(is_long_collateral)
220 }
221
222 #[inline]
224 fn claimable_funding_fee_amount_per_size(
225 &self,
226 is_long: bool,
227 is_long_collateral: bool,
228 ) -> crate::Result<Self::Num> {
229 self.claimable_funding_amount_per_size_pool(is_long)?
230 .amount(is_long_collateral)
231 }
232
233 fn validate_open_interest_reserve(
235 &self,
236 prices: &Prices<Self::Num>,
237 is_long: bool,
238 ) -> crate::Result<()> {
239 let pool_value = self.pool_value_without_pnl_for_one_side(prices, is_long, false)?;
240
241 let max_reserved_value =
242 crate::utils::apply_factor(&pool_value, &self.open_interest_reserve_factor()?)
243 .ok_or(crate::Error::Computation("calculating max reserved value"))?;
244
245 let reserved_value = self.reserved_value(&prices.index_token_price, is_long)?;
246
247 if reserved_value > max_reserved_value {
248 Err(crate::Error::InsufficientReserveForOpenInterest(
249 reserved_value.to_string(),
250 max_reserved_value.to_string(),
251 ))
252 } else {
253 Ok(())
254 }
255 }
256
257 fn min_collateral_factor_for_open_interest(
259 &self,
260 delta: &Self::Signed,
261 is_long: bool,
262 ) -> crate::Result<Self::Num> {
263 let next_open_interest = self
264 .open_interest()?
265 .amount(is_long)?
266 .checked_add_with_signed(delta)
267 .ok_or(crate::Error::Computation(
268 "calculating next OI for min collateral factor",
269 ))?;
270 let factor = self.min_collateral_factor_for_open_interest_multiplier(is_long)?;
271 crate::utils::apply_factor(&next_open_interest, &factor).ok_or(crate::Error::Computation(
272 "calculating min collateral factor for OI",
273 ))
274 }
275
276 fn cap_positive_position_price_impact(
279 &self,
280 index_token_price: &Price<Self::Num>,
281 size_delta_usd: &Self::Signed,
282 impact: &mut Self::Signed,
283 ) -> crate::Result<()> {
284 use crate::{market::PositionImpactMarketExt, num::UnsignedAbs, utils};
285 use num_traits::{CheckedMul, Signed};
286
287 if impact.is_positive() {
288 let impact_pool_amount = self.position_impact_pool_amount()?;
289 let max_impact = impact_pool_amount
291 .checked_mul(index_token_price.pick_price(false))
292 .ok_or(crate::Error::Computation(
293 "overflow calculating max positive position impact based on pool amount",
294 ))?
295 .to_signed()?;
296 if *impact > max_impact {
297 *impact = max_impact;
298 }
299
300 let params = self.position_params()?;
302 let max_impact_factor = params.max_positive_position_impact_factor();
303 let max_impact = utils::apply_factor(&size_delta_usd.unsigned_abs(), max_impact_factor)
304 .ok_or(crate::Error::Computation(
305 "calculating max positive position impact based on max factor",
306 ))?
307 .to_signed()?;
308 if *impact > max_impact {
309 *impact = max_impact;
310 }
311 }
312 Ok(())
313 }
314
315 fn cap_negative_position_price_impact(
322 &self,
323 size_delta_usd: &Self::Signed,
324 for_liquidations: bool,
325 impact: &mut Self::Signed,
326 ) -> crate::Result<Self::Num> {
327 use crate::{num::UnsignedAbs, utils};
328 use num_traits::{CheckedSub, Signed, Zero};
329
330 let mut impact_diff = Zero::zero();
331 if impact.is_negative() {
332 let params = self.position_params()?;
333 let max_impact_factor = if for_liquidations {
334 params.max_position_impact_factor_for_liquidations()
335 } else {
336 params.max_negative_position_impact_factor()
337 };
338 let min_impact = utils::apply_factor(&size_delta_usd.unsigned_abs(), max_impact_factor)
342 .ok_or(crate::Error::Computation(
343 "calculating max negative position impact based on max factor",
344 ))?
345 .to_opposite_signed()?;
346 if *impact < min_impact {
347 impact_diff = min_impact
348 .checked_sub(impact)
349 .ok_or(crate::Error::Computation(
350 "overflow calculating impact diff",
351 ))?
352 .unsigned_abs();
353 *impact = min_impact;
354 }
355 }
356 Ok(impact_diff)
357 }
358}
359
360impl<M: PerpMarket<DECIMALS>, const DECIMALS: u8> PerpMarketExt<DECIMALS> for M {}
361
362pub trait PerpMarketMutExt<const DECIMALS: u8>: PerpMarketMut<DECIMALS> {
364 fn update_funding(
366 &mut self,
367 prices: &Prices<Self::Num>,
368 ) -> crate::Result<UpdateFundingState<&mut Self, DECIMALS>>
369 where
370 Self: Sized,
371 {
372 UpdateFundingState::try_new(self, prices)
373 }
374
375 fn apply_delta_to_funding_amount_per_size(
377 &mut self,
378 is_long: bool,
379 is_long_collateral: bool,
380 delta: &Self::Signed,
381 ) -> crate::Result<()> {
382 self.funding_amount_per_size_pool_mut(is_long)?
383 .apply_delta_amount(is_long_collateral, delta)
384 }
385
386 fn apply_delta_to_claimable_funding_amount_per_size(
388 &mut self,
389 is_long: bool,
390 is_long_collateral: bool,
391 delta: &Self::Signed,
392 ) -> crate::Result<()> {
393 self.claimable_funding_amount_per_size_pool_mut(is_long)?
394 .apply_delta_amount(is_long_collateral, delta)
395 }
396}
397
398impl<M: PerpMarketMut<DECIMALS>, const DECIMALS: u8> PerpMarketMutExt<DECIMALS> for M {}