gmsol_model/params/
fee.rs

1use num_traits::{CheckedAdd, CheckedSub, Zero};
2use typed_builder::TypedBuilder;
3
4use crate::{fixed::FixedPointOps, num::Unsigned, price::Price, utils};
5
6/// Fee Parameters.
7#[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    /// Set discount factor.
18    pub fn with_discount_factor(self, factor: T) -> Self {
19        Self {
20            discount_factor: Some(factor),
21            ..self
22        }
23    }
24
25    /// Get receiver factor.
26    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    /// Get basic fee.
50    #[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    /// Get receiver fee.
62    #[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    /// Apply fees to `amount`.
71    /// - `DECIMALS` is the decimals of the parameters.
72    ///
73    /// Returns `None` if the computation fails, otherwise `amount` after fees and the fees are returned.
74    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    /// Get order fees.
92    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    /// Get position fees with only order fees considered.
127    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/// Borrowing Fee Parameters.
149#[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    /// Get borrowing exponent factor.
162    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    /// Get borrowing factor.
171    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    /// Get whether to skip borrowing fee for smaller side.
180    pub fn skip_borrowing_fee_for_smaller_side(&self) -> bool {
181        self.skip_borrowing_fee_for_smaller_side
182    }
183
184    /// Get borrowing fee receiver factor.
185    pub fn receiver_factor(&self) -> &T {
186        &self.receiver_factor
187    }
188}
189
190/// Borrowing Fee Kink Model Parameters.
191#[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    /// Get optimal usage factor.
207    pub fn optimal_usage_factor(&self, is_long: bool) -> &T {
208        &self.params_for_one_side(is_long).optimal_usage_factor
209    }
210
211    /// Get base borrowing factor.
212    pub fn base_borrowing_factor(&self, is_long: bool) -> &T {
213        &self.params_for_one_side(is_long).base_borrowing_factor
214    }
215
216    /// Get above optimal usage borrowing factor.
217    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    /// Calculate borrowing factor per second.
224    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/// Borrowing Fee Kink Model Parameters for one side.
296#[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/// Funding Fee Parameters.
304#[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    /// Get funding exponent factor.
318    pub fn exponent(&self) -> &T {
319        &self.exponent
320    }
321
322    /// Get funding increase factor per second.
323    pub fn increase_factor_per_second(&self) -> &T {
324        &self.increase_factor_per_second
325    }
326
327    /// Get funding decrease factor per second.
328    pub fn decrease_factor_per_second(&self) -> &T {
329        &self.decrease_factor_per_second
330    }
331
332    /// Get max funding factor per second.
333    pub fn max_factor_per_second(&self) -> &T {
334        &self.max_factor_per_second
335    }
336
337    /// Get min funding factor per second.
338    pub fn min_factor_per_second(&self) -> &T {
339        &self.min_factor_per_second
340    }
341
342    /// Fallback funding factor.
343    pub fn factor(&self) -> &T {
344        &self.funding_factor
345    }
346
347    /// Threshold for stable funding.
348    pub fn threshold_for_stable_funding(&self) -> &T {
349        &self.threshold_for_stable_funding
350    }
351
352    /// Threshold for decrease funding.
353    pub fn threshold_for_decrease_funding(&self) -> &T {
354        &self.threshold_for_decrease_funding
355    }
356
357    /// Get change type for next funding rate.
358    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/// Funding Rate Change Type.
390#[derive(Default, Debug)]
391pub enum FundingRateChangeType {
392    /// No Change.
393    #[default]
394    NoChange,
395    /// Increase.
396    Increase,
397    /// Decrease.
398    Decrease,
399}
400
401/// Liquidation Fee Parameters.
402#[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/// Fees.
443#[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    /// Create a new [`Fees`].
470    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    /// Get fee amount for receiver
478    pub fn fee_amount_for_receiver(&self) -> &T {
479        &self.fee_amount_for_receiver
480    }
481
482    /// Get fee amount for pool.
483    pub fn fee_amount_for_pool(&self) -> &T {
484        &self.fee_amount_for_pool
485    }
486}
487
488/// Order Fees.
489#[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    /// Get fee amounts.
507    pub fn fee_amounts(&self) -> &Fees<T> {
508        &self.base
509    }
510
511    /// Get order fee value.
512    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/// Borrowing Fee.
527#[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    /// Get total borrowing fee amount.
545    pub fn fee_amount(&self) -> &T {
546        &self.fee_amount
547    }
548
549    /// Get borrowing fee amount for receiver.
550    pub fn fee_amount_for_receiver(&self) -> &T {
551        &self.fee_amount_for_receiver
552    }
553
554    /// Get borrowing fee amount for pool.
555    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/// Funding Fees.
577#[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    /// Get funding fee amount.
596    pub fn amount(&self) -> &T {
597        &self.amount
598    }
599
600    /// Get claimable long token funding fee amount.
601    pub fn claimable_long_token_amount(&self) -> &T {
602        &self.claimable_long_token_amount
603    }
604
605    /// Get claimable short token funding fee amount.
606    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/// Liquidation Fees.
622#[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    /// Get total liquidation fee amount.
651    pub fn fee_amount(&self) -> &T {
652        &self.fee_amount
653    }
654
655    /// Get liquidation fee amount for receiver.
656    pub fn fee_amount_for_receiver(&self) -> &T {
657        &self.fee_amount_for_receiver
658    }
659
660    /// Get liquidation fee amount for pool.
661    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    /// Get total liquidation fee value.
673    pub fn fee_value(&self) -> &T {
674        &self.fee_value
675    }
676}
677
678/// Position Fees.
679#[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    /// Get fee for receiver.
705    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    /// Get fee for pool.
724    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    /// Get paid order fee value.
747    pub fn paid_order_fee_value(&self) -> &T {
748        &self.paid_order_fee_value
749    }
750
751    /// Get order fees.
752    pub fn order_fees(&self) -> &OrderFees<T> {
753        &self.order
754    }
755
756    /// Get borrowing fees.
757    pub fn borrowing_fees(&self) -> &BorrowingFees<T> {
758        &self.borrowing
759    }
760
761    /// Get funding fees.
762    pub fn funding_fees(&self) -> &FundingFees<T> {
763        &self.funding
764    }
765
766    /// Get liquidation fees.
767    pub fn liquidation_fees(&self) -> Option<&LiquidationFees<T>> {
768        self.liquidation.as_ref()
769    }
770
771    /// Get total cost amount in collateral tokens.
772    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    /// Get total cost excluding funding fee.
782    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    /// Set paid order fee value.
804    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    /// Clear fees excluding funding fee.
809    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    /// Set borrowing fees.
819    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    /// Set funding fees.
842    pub fn set_funding_fees(mut self, fees: FundingFees<T>) -> Self {
843        self.funding = fees;
844        self
845    }
846
847    /// Set liquidation fees.
848    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}