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