1use num_traits::{CheckedAdd, CheckedSub, Zero};
2use typed_builder::TypedBuilder;
3
4use crate::{fixed::FixedPointOps, num::Unsigned, pool::delta::BalanceChange, price::Price, utils};
5
6#[derive(Debug, Clone, Copy, TypedBuilder)]
8pub struct FeeParams<T> {
9 positive_impact_fee_factor: T,
10 negative_impact_fee_factor: T,
11 fee_receiver_factor: T,
12 #[builder(default = None, setter(strip_option))]
13 discount_factor: Option<T>,
14}
15
16impl<T> FeeParams<T> {
17 pub fn with_discount_factor(self, factor: T) -> Self {
19 Self {
20 discount_factor: Some(factor),
21 ..self
22 }
23 }
24
25 pub fn receiver_factor(&self) -> &T {
27 &self.fee_receiver_factor
28 }
29
30 #[inline]
31 fn factor(&self, balance_change: BalanceChange) -> &T {
32 match balance_change {
33 BalanceChange::Improved => &self.positive_impact_fee_factor,
34 BalanceChange::Unchanged | BalanceChange::Worsened => &self.negative_impact_fee_factor,
35 }
36 }
37
38 fn discount_factor(&self) -> T
39 where
40 T: Zero + Clone,
41 {
42 self.discount_factor
43 .as_ref()
44 .cloned()
45 .unwrap_or(Zero::zero())
46 }
47
48 #[inline]
50 pub fn fee<const DECIMALS: u8>(&self, balance_change: BalanceChange, amount: &T) -> Option<T>
51 where
52 T: FixedPointOps<DECIMALS>,
53 {
54 let factor = self.factor(balance_change);
55 let fee = utils::apply_factor(amount, factor)?;
56 let discount = utils::apply_factor(&fee, &self.discount_factor())?;
57 fee.checked_sub(&discount)
58 }
59
60 #[inline]
62 pub fn receiver_fee<const DECIMALS: u8>(&self, fee_amount: &T) -> Option<T>
63 where
64 T: FixedPointOps<DECIMALS>,
65 {
66 utils::apply_factor(fee_amount, &self.fee_receiver_factor)
67 }
68
69 pub fn apply_fees<const DECIMALS: u8>(
74 &self,
75 balance_change: BalanceChange,
76 amount: &T,
77 ) -> Option<(T, Fees<T>)>
78 where
79 T: FixedPointOps<DECIMALS>,
80 {
81 let fee_amount = self.fee(balance_change, amount)?;
82 let fee_receiver_amount = self.receiver_fee(&fee_amount)?;
83 let fees = Fees {
84 fee_amount_for_pool: fee_amount.checked_sub(&fee_receiver_amount)?,
85 fee_amount_for_receiver: fee_receiver_amount,
86 };
87 Some((amount.checked_sub(&fee_amount)?, fees))
88 }
89
90 fn order_fees<const DECIMALS: u8>(
92 &self,
93 collateral_token_price: &Price<T>,
94 size_delta_usd: &T,
95 balance_change: BalanceChange,
96 ) -> crate::Result<OrderFees<T>>
97 where
98 T: FixedPointOps<DECIMALS>,
99 {
100 if collateral_token_price.has_zero() {
101 return Err(crate::Error::InvalidPrices);
102 }
103
104 let fee_value = self
105 .fee(balance_change, size_delta_usd)
106 .ok_or(crate::Error::Computation("calculating order fee value"))?;
107 let fee_amount = fee_value
108 .checked_div(collateral_token_price.pick_price(false))
109 .ok_or(crate::Error::Computation("calculating order fee amount"))?;
110
111 let receiver_fee_amount = self
112 .receiver_fee(&fee_amount)
113 .ok_or(crate::Error::Computation("calculating order receiver fee"))?;
114 Ok(OrderFees {
115 base: Fees::new(
116 fee_amount
117 .checked_sub(&receiver_fee_amount)
118 .ok_or(crate::Error::Computation("calculating order fee for pool"))?,
119 receiver_fee_amount,
120 ),
121 fee_value,
122 })
123 }
124
125 pub fn base_position_fees<const DECIMALS: u8>(
127 &self,
128 collateral_token_price: &Price<T>,
129 size_delta_usd: &T,
130 balance_change: BalanceChange,
131 ) -> crate::Result<PositionFees<T>>
132 where
133 T: FixedPointOps<DECIMALS>,
134 {
135 let order_fees = self.order_fees(collateral_token_price, size_delta_usd, balance_change)?;
136 Ok(PositionFees {
137 paid_order_and_borrowing_fee_value: order_fees.fee_value.clone(),
138 order: order_fees,
139 borrowing: Default::default(),
140 funding: Default::default(),
141 liquidation: Default::default(),
142 })
143 }
144}
145
146#[derive(Debug, Clone, Copy, TypedBuilder)]
148pub struct BorrowingFeeParams<T> {
149 receiver_factor: T,
150 exponent_for_long: T,
151 exponent_for_short: T,
152 factor_for_long: T,
153 factor_for_short: T,
154 #[builder(default = true)]
155 skip_borrowing_fee_for_smaller_side: bool,
156}
157
158impl<T> BorrowingFeeParams<T> {
159 pub fn exponent(&self, is_long: bool) -> &T {
161 if is_long {
162 &self.exponent_for_long
163 } else {
164 &self.exponent_for_short
165 }
166 }
167
168 pub fn factor(&self, is_long: bool) -> &T {
170 if is_long {
171 &self.factor_for_long
172 } else {
173 &self.factor_for_short
174 }
175 }
176
177 pub fn skip_borrowing_fee_for_smaller_side(&self) -> bool {
179 self.skip_borrowing_fee_for_smaller_side
180 }
181
182 pub fn receiver_factor(&self) -> &T {
184 &self.receiver_factor
185 }
186}
187
188#[derive(Debug, Clone, Copy, TypedBuilder)]
190pub struct BorrowingFeeKinkModelParams<T> {
191 long: BorrowingFeeKinkModelParamsForOneSide<T>,
192 short: BorrowingFeeKinkModelParamsForOneSide<T>,
193}
194
195impl<T> BorrowingFeeKinkModelParams<T> {
196 fn params_for_one_side(&self, is_long: bool) -> &BorrowingFeeKinkModelParamsForOneSide<T> {
197 if is_long {
198 &self.long
199 } else {
200 &self.short
201 }
202 }
203
204 pub fn optimal_usage_factor(&self, is_long: bool) -> &T {
206 &self.params_for_one_side(is_long).optimal_usage_factor
207 }
208
209 pub fn base_borrowing_factor(&self, is_long: bool) -> &T {
211 &self.params_for_one_side(is_long).base_borrowing_factor
212 }
213
214 pub fn above_optimal_usage_borrowing_factor(&self, is_long: bool) -> &T {
216 &self
217 .params_for_one_side(is_long)
218 .above_optimal_usage_borrowing_factor
219 }
220
221 pub fn borrowing_factor_per_second<const DECIMALS: u8, M>(
223 &self,
224 market: &M,
225 is_long: bool,
226 reserved_value: &T,
227 pool_value: &T,
228 ) -> crate::Result<Option<T>>
229 where
230 M: crate::BaseMarket<DECIMALS, Num = T> + ?Sized,
231 T: FixedPointOps<DECIMALS>,
232 {
233 use crate::market::utils::MarketUtils;
234
235 let optimal_usage_factor = self.optimal_usage_factor(is_long);
236
237 if optimal_usage_factor.is_zero() {
238 return Ok(None);
239 }
240
241 let usage_factor = market.usage_factor(is_long, reserved_value, pool_value)?;
242
243 let base_borrowing_factor = self.base_borrowing_factor(is_long);
244
245 let borrowing_factor_per_second = utils::apply_factor(&usage_factor, base_borrowing_factor)
246 .ok_or(crate::Error::Computation(
247 "borrowing fee kink model: calculating borrowing factor per second",
248 ))?;
249
250 if usage_factor > *optimal_usage_factor && T::UNIT > *optimal_usage_factor {
251 let diff =
252 usage_factor
253 .checked_sub(optimal_usage_factor)
254 .ok_or(crate::Error::Computation(
255 "borrowing fee kink model: calculating diff",
256 ))?;
257
258 let above_optimal_usage_borrowing_factor =
259 self.above_optimal_usage_borrowing_factor(is_long);
260
261 let additional_borrowing_factor_per_second =
262 if above_optimal_usage_borrowing_factor > base_borrowing_factor {
263 above_optimal_usage_borrowing_factor
264 .checked_sub(base_borrowing_factor)
265 .ok_or(crate::Error::Computation(
266 "borrowing fee kink model: calculating additional factor",
267 ))?
268 } else {
269 T::zero()
270 };
271
272 let divisor =
273 T::UNIT
274 .checked_sub(optimal_usage_factor)
275 .ok_or(crate::Error::Computation(
276 "borrowing fee kink model: calculating divisor",
277 ))?;
278
279 let borrowing_factor_per_second = additional_borrowing_factor_per_second
280 .checked_mul_div(&diff, &divisor)
281 .and_then(|a| borrowing_factor_per_second.checked_add(&a))
282 .ok_or(crate::Error::Computation(
283 "borrowing fee kink model: increasing borrowing factor per second",
284 ))?;
285
286 Ok(Some(borrowing_factor_per_second))
287 } else {
288 Ok(Some(borrowing_factor_per_second))
289 }
290 }
291}
292
293#[derive(Debug, Clone, Copy, TypedBuilder)]
295pub struct BorrowingFeeKinkModelParamsForOneSide<T> {
296 optimal_usage_factor: T,
297 base_borrowing_factor: T,
298 above_optimal_usage_borrowing_factor: T,
299}
300
301#[derive(Debug, Clone, Copy, TypedBuilder)]
303pub struct FundingFeeParams<T> {
304 exponent: T,
305 funding_factor: T,
306 increase_factor_per_second: T,
307 decrease_factor_per_second: T,
308 max_factor_per_second: T,
309 min_factor_per_second: T,
310 threshold_for_stable_funding: T,
311 threshold_for_decrease_funding: T,
312}
313
314impl<T> FundingFeeParams<T> {
315 pub fn exponent(&self) -> &T {
317 &self.exponent
318 }
319
320 pub fn increase_factor_per_second(&self) -> &T {
322 &self.increase_factor_per_second
323 }
324
325 pub fn decrease_factor_per_second(&self) -> &T {
327 &self.decrease_factor_per_second
328 }
329
330 pub fn max_factor_per_second(&self) -> &T {
332 &self.max_factor_per_second
333 }
334
335 pub fn min_factor_per_second(&self) -> &T {
337 &self.min_factor_per_second
338 }
339
340 pub fn factor(&self) -> &T {
342 &self.funding_factor
343 }
344
345 pub fn threshold_for_stable_funding(&self) -> &T {
347 &self.threshold_for_stable_funding
348 }
349
350 pub fn threshold_for_decrease_funding(&self) -> &T {
352 &self.threshold_for_decrease_funding
353 }
354
355 pub fn change(
357 &self,
358 funding_factor_per_second: &T::Signed,
359 long_open_interest: &T,
360 short_open_interest: &T,
361 diff_factor: &T,
362 ) -> FundingRateChangeType
363 where
364 T: Ord + Unsigned,
365 {
366 use num_traits::Signed;
367
368 let is_skew_the_same_direction_as_funding = (funding_factor_per_second.is_positive()
369 && *long_open_interest > *short_open_interest)
370 || (funding_factor_per_second.is_negative()
371 && *long_open_interest < *short_open_interest);
372
373 if is_skew_the_same_direction_as_funding {
374 if *diff_factor > self.threshold_for_stable_funding {
375 FundingRateChangeType::Increase
376 } else if *diff_factor < self.threshold_for_decrease_funding {
377 FundingRateChangeType::Decrease
378 } else {
379 FundingRateChangeType::NoChange
380 }
381 } else {
382 FundingRateChangeType::Increase
383 }
384 }
385}
386
387#[derive(Default, Debug)]
389pub enum FundingRateChangeType {
390 #[default]
392 NoChange,
393 Increase,
395 Decrease,
397}
398
399#[derive(Debug, Clone, Copy, TypedBuilder)]
401pub struct LiquidationFeeParams<T> {
402 factor: T,
403 receiver_factor: T,
404}
405
406impl<T> LiquidationFeeParams<T> {
407 pub(crate) fn fee<const DECIMALS: u8>(
408 &self,
409 size_delta_usd: &T,
410 collateral_token_price: &Price<T>,
411 ) -> crate::Result<LiquidationFees<T>>
412 where
413 T: FixedPointOps<DECIMALS>,
414 {
415 if self.factor.is_zero() {
416 return Ok(Default::default());
417 }
418
419 let fee_value = utils::apply_factor(size_delta_usd, &self.factor).ok_or(
420 crate::Error::Computation("liquidation fee: calculating fee value"),
421 )?;
422 let fee_amount = fee_value
423 .checked_round_up_div(collateral_token_price.pick_price(false))
424 .ok_or(crate::Error::Computation(
425 "liquidation fee: calculating fee amount",
426 ))?;
427 let fee_amount_for_receiver = utils::apply_factor(&fee_amount, &self.receiver_factor)
428 .ok_or(crate::Error::Computation(
429 "liquidation fee: calculating fee amount for receiver",
430 ))?;
431
432 Ok(LiquidationFees {
433 fee_value,
434 fee_amount,
435 fee_amount_for_receiver,
436 })
437 }
438}
439
440#[derive(Debug, Clone, Copy)]
442#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
443#[cfg_attr(
444 feature = "anchor-lang",
445 derive(anchor_lang::AnchorDeserialize, anchor_lang::AnchorSerialize)
446)]
447pub struct Fees<T> {
448 fee_amount_for_receiver: T,
449 fee_amount_for_pool: T,
450}
451
452#[cfg(feature = "gmsol-utils")]
453impl<T: gmsol_utils::InitSpace> gmsol_utils::InitSpace for Fees<T> {
454 const INIT_SPACE: usize = 2 * T::INIT_SPACE;
455}
456
457impl<T: Zero> Default for Fees<T> {
458 fn default() -> Self {
459 Self {
460 fee_amount_for_receiver: Zero::zero(),
461 fee_amount_for_pool: Zero::zero(),
462 }
463 }
464}
465
466impl<T> Fees<T> {
467 pub fn new(pool: T, receiver: T) -> Self {
469 Self {
470 fee_amount_for_pool: pool,
471 fee_amount_for_receiver: receiver,
472 }
473 }
474
475 pub fn fee_amount_for_receiver(&self) -> &T {
477 &self.fee_amount_for_receiver
478 }
479
480 pub fn fee_amount_for_pool(&self) -> &T {
482 &self.fee_amount_for_pool
483 }
484}
485
486#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
488#[cfg_attr(
489 feature = "anchor-lang",
490 derive(anchor_lang::AnchorDeserialize, anchor_lang::AnchorSerialize)
491)]
492#[derive(Debug, Clone, Copy)]
493pub struct OrderFees<T> {
494 base: Fees<T>,
495 fee_value: T,
496}
497
498#[cfg(feature = "gmsol-utils")]
499impl<T: gmsol_utils::InitSpace> gmsol_utils::InitSpace for OrderFees<T> {
500 const INIT_SPACE: usize = Fees::<T>::INIT_SPACE + T::INIT_SPACE;
501}
502
503impl<T> OrderFees<T> {
504 pub fn fee_amounts(&self) -> &Fees<T> {
506 &self.base
507 }
508
509 pub fn fee_value(&self) -> &T {
511 &self.fee_value
512 }
513}
514
515impl<T: Zero> Default for OrderFees<T> {
516 fn default() -> Self {
517 Self {
518 base: Default::default(),
519 fee_value: Zero::zero(),
520 }
521 }
522}
523
524#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
526#[cfg_attr(
527 feature = "anchor-lang",
528 derive(anchor_lang::AnchorDeserialize, anchor_lang::AnchorSerialize)
529)]
530#[derive(Debug, Clone, Copy)]
531pub struct BorrowingFees<T> {
532 fee_amount: T,
533 fee_amount_for_receiver: T,
534}
535
536#[cfg(feature = "gmsol-utils")]
537impl<T: gmsol_utils::InitSpace> gmsol_utils::InitSpace for BorrowingFees<T> {
538 const INIT_SPACE: usize = 2 * T::INIT_SPACE;
539}
540
541impl<T> BorrowingFees<T> {
542 pub fn fee_amount(&self) -> &T {
544 &self.fee_amount
545 }
546
547 pub fn fee_amount_for_receiver(&self) -> &T {
549 &self.fee_amount_for_receiver
550 }
551
552 pub fn fee_amount_for_pool(&self) -> crate::Result<T>
554 where
555 T: CheckedSub,
556 {
557 self.fee_amount
558 .checked_sub(&self.fee_amount_for_receiver)
559 .ok_or(crate::Error::Computation(
560 "borrowing fee: calculating fee for pool",
561 ))
562 }
563}
564
565impl<T: Zero> Default for BorrowingFees<T> {
566 fn default() -> Self {
567 Self {
568 fee_amount: Zero::zero(),
569 fee_amount_for_receiver: Zero::zero(),
570 }
571 }
572}
573
574#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
576#[cfg_attr(
577 feature = "anchor-lang",
578 derive(anchor_lang::AnchorDeserialize, anchor_lang::AnchorSerialize)
579)]
580#[derive(Debug, Clone, Copy, TypedBuilder)]
581pub struct FundingFees<T> {
582 amount: T,
583 claimable_long_token_amount: T,
584 claimable_short_token_amount: T,
585}
586
587#[cfg(feature = "gmsol-utils")]
588impl<T: gmsol_utils::InitSpace> gmsol_utils::InitSpace for FundingFees<T> {
589 const INIT_SPACE: usize = 3 * T::INIT_SPACE;
590}
591
592impl<T> FundingFees<T> {
593 pub fn amount(&self) -> &T {
595 &self.amount
596 }
597
598 pub fn claimable_long_token_amount(&self) -> &T {
600 &self.claimable_long_token_amount
601 }
602
603 pub fn claimable_short_token_amount(&self) -> &T {
605 &self.claimable_short_token_amount
606 }
607}
608
609impl<T: Zero> Default for FundingFees<T> {
610 fn default() -> Self {
611 Self {
612 amount: Zero::zero(),
613 claimable_long_token_amount: Zero::zero(),
614 claimable_short_token_amount: Zero::zero(),
615 }
616 }
617}
618
619#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
621#[cfg_attr(
622 feature = "anchor-lang",
623 derive(anchor_lang::AnchorDeserialize, anchor_lang::AnchorSerialize)
624)]
625#[derive(Debug, Clone, Copy)]
626pub struct LiquidationFees<T> {
627 fee_value: T,
628 fee_amount: T,
629 fee_amount_for_receiver: T,
630}
631
632#[cfg(feature = "gmsol-utils")]
633impl<T: gmsol_utils::InitSpace> gmsol_utils::InitSpace for LiquidationFees<T> {
634 const INIT_SPACE: usize = 3 * T::INIT_SPACE;
635}
636
637impl<T: Zero> Default for LiquidationFees<T> {
638 fn default() -> Self {
639 Self {
640 fee_value: Zero::zero(),
641 fee_amount: Zero::zero(),
642 fee_amount_for_receiver: Zero::zero(),
643 }
644 }
645}
646
647impl<T> LiquidationFees<T> {
648 pub fn fee_amount(&self) -> &T {
650 &self.fee_amount
651 }
652
653 pub fn fee_amount_for_receiver(&self) -> &T {
655 &self.fee_amount_for_receiver
656 }
657
658 pub fn fee_amount_for_pool(&self) -> crate::Result<T>
660 where
661 T: CheckedSub,
662 {
663 self.fee_amount
664 .checked_sub(&self.fee_amount_for_receiver)
665 .ok_or(crate::Error::Computation(
666 "liquidation fee: calculating fee for pool",
667 ))
668 }
669
670 pub fn fee_value(&self) -> &T {
672 &self.fee_value
673 }
674}
675
676#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
678#[cfg_attr(
679 feature = "anchor-lang",
680 derive(anchor_lang::AnchorDeserialize, anchor_lang::AnchorSerialize)
681)]
682#[derive(Debug, Clone, Copy)]
683pub struct PositionFees<T> {
684 paid_order_and_borrowing_fee_value: T,
685 order: OrderFees<T>,
686 borrowing: BorrowingFees<T>,
687 funding: FundingFees<T>,
688 liquidation: Option<LiquidationFees<T>>,
689}
690
691#[cfg(feature = "gmsol-utils")]
692impl<T: gmsol_utils::InitSpace> gmsol_utils::InitSpace for PositionFees<T> {
693 const INIT_SPACE: usize = T::INIT_SPACE
694 + OrderFees::<T>::INIT_SPACE
695 + BorrowingFees::<T>::INIT_SPACE
696 + FundingFees::<T>::INIT_SPACE
697 + 1
698 + LiquidationFees::<T>::INIT_SPACE;
699}
700
701impl<T> PositionFees<T> {
702 pub fn for_receiver(&self) -> crate::Result<T>
704 where
705 T: CheckedAdd,
706 {
707 self.order
708 .fee_amounts()
709 .fee_amount_for_receiver()
710 .checked_add(self.borrowing.fee_amount_for_receiver())
711 .and_then(|total| {
712 if let Some(fees) = self.liquidation_fees() {
713 total.checked_add(fees.fee_amount_for_receiver())
714 } else {
715 Some(total)
716 }
717 })
718 .ok_or(crate::Error::Computation("calculating fee for receiver"))
719 }
720
721 pub fn for_pool<const DECIMALS: u8>(&self) -> crate::Result<T>
723 where
724 T: FixedPointOps<DECIMALS>,
725 {
726 let amount = self
727 .order
728 .fee_amounts()
729 .fee_amount_for_pool()
730 .checked_add(&self.borrowing.fee_amount_for_pool()?)
731 .ok_or(crate::Error::Computation("adding borrowing fee for pool"))
732 .and_then(|total| {
733 if let Some(fees) = self.liquidation_fees() {
734 total
735 .checked_add(&fees.fee_amount_for_pool()?)
736 .ok_or(crate::Error::Computation("adding liquidation fee for pool"))
737 } else {
738 Ok(total)
739 }
740 })?;
741 Ok(amount)
742 }
743
744 pub fn paid_order_and_borrowing_fee_value(&self) -> &T {
746 &self.paid_order_and_borrowing_fee_value
747 }
748
749 pub fn order_fees(&self) -> &OrderFees<T> {
751 &self.order
752 }
753
754 pub fn borrowing_fees(&self) -> &BorrowingFees<T> {
756 &self.borrowing
757 }
758
759 pub fn funding_fees(&self) -> &FundingFees<T> {
761 &self.funding
762 }
763
764 pub fn liquidation_fees(&self) -> Option<&LiquidationFees<T>> {
766 self.liquidation.as_ref()
767 }
768
769 pub fn total_cost_amount(&self) -> crate::Result<T>
771 where
772 T: CheckedAdd,
773 {
774 self.total_cost_excluding_funding()?
775 .checked_add(&self.funding.amount)
776 .ok_or(crate::Error::Overflow)
777 }
778
779 pub fn total_cost_excluding_funding(&self) -> crate::Result<T>
781 where
782 T: CheckedAdd,
783 {
784 self.order
785 .fee_amounts()
786 .fee_amount_for_pool()
787 .checked_add(self.order.fee_amounts().fee_amount_for_receiver())
788 .and_then(|acc| acc.checked_add(self.borrowing.fee_amount()))
789 .and_then(|acc| {
790 if let Some(fees) = self.liquidation_fees() {
791 acc.checked_add(fees.fee_amount())
792 } else {
793 Some(acc)
794 }
795 })
796 .ok_or(crate::Error::Computation(
797 "overflow while calculating total cost excluding funding",
798 ))
799 }
800
801 pub(crate) fn set_paid_order_and_borrowing_fee_value(
803 &mut self,
804 paid_order_and_borrowing_fee_value: T,
805 ) {
806 self.paid_order_and_borrowing_fee_value = paid_order_and_borrowing_fee_value;
807 }
808
809 pub fn clear_fees_excluding_funding(&mut self)
811 where
812 T: Zero,
813 {
814 self.order = Default::default();
815 self.borrowing = BorrowingFees::default();
816 self.liquidation = None;
817 }
818
819 pub fn set_borrowing_fees<const DECIMALS: u8>(
821 mut self,
822 receiver_factor: &T,
823 price: &Price<T>,
824 value: T,
825 ) -> crate::Result<Self>
826 where
827 T: FixedPointOps<DECIMALS>,
828 {
829 let price = price.pick_price(false);
830 debug_assert!(!price.is_zero(), "must be non-zero");
831 let amount = value
832 .checked_div(price)
833 .ok_or(crate::Error::Computation("calculating borrowing amount"))?;
834 let paid_fee_value = self
835 .paid_order_and_borrowing_fee_value
836 .checked_add(&value)
837 .ok_or(crate::Error::Computation("adding borrowing fee value"))?;
838 self.borrowing.fee_amount_for_receiver =
839 crate::utils::apply_factor(&amount, receiver_factor).ok_or(
840 crate::Error::Computation("calculating borrowing fee amount for receiver"),
841 )?;
842 self.borrowing.fee_amount = amount;
843 self.paid_order_and_borrowing_fee_value = paid_fee_value;
844 Ok(self)
845 }
846
847 pub fn set_funding_fees(mut self, fees: FundingFees<T>) -> Self {
849 self.funding = fees;
850 self
851 }
852
853 pub fn set_liquidation_fees(mut self, fees: Option<LiquidationFees<T>>) -> Self {
855 self.liquidation = fees;
856 self
857 }
858}
859
860impl<T: Zero> Default for PositionFees<T> {
861 fn default() -> Self {
862 Self {
863 paid_order_and_borrowing_fee_value: Zero::zero(),
864 order: Default::default(),
865 borrowing: Default::default(),
866 funding: Default::default(),
867 liquidation: None,
868 }
869 }
870}