gmsol_model/action/
distribute_position_impact.rs

1use num_traits::Zero;
2
3use crate::{
4    market::{
5        BaseMarket, PositionImpactMarketExt, PositionImpactMarketMut, PositionImpactMarketMutExt,
6    },
7    num::Unsigned,
8};
9
10use super::MarketAction;
11
12/// Distribute Position Impact.
13#[must_use = "actions do nothing unless you `execute` them"]
14pub struct DistributePositionImpact<M: BaseMarket<DECIMALS>, const DECIMALS: u8> {
15    market: M,
16}
17
18/// Distribute Position Impact Report.
19#[derive(Debug)]
20#[cfg_attr(
21    feature = "anchor-lang",
22    derive(anchor_lang::AnchorDeserialize, anchor_lang::AnchorSerialize)
23)]
24pub struct DistributePositionImpactReport<T> {
25    duration_in_seconds: u64,
26    distribution_amount: T,
27    next_position_impact_pool_amount: T,
28}
29
30#[cfg(feature = "gmsol-utils")]
31impl<T: gmsol_utils::InitSpace> gmsol_utils::InitSpace for DistributePositionImpactReport<T> {
32    const INIT_SPACE: usize = u64::INIT_SPACE + 2 * T::INIT_SPACE;
33}
34
35impl<T> DistributePositionImpactReport<T> {
36    /// Get considered duration in seconds.
37    pub fn duration_in_seconds(&self) -> u64 {
38        self.duration_in_seconds
39    }
40
41    /// Get distribution amount.
42    pub fn distribution_amount(&self) -> &T {
43        &self.distribution_amount
44    }
45
46    /// Get Next position impact pool amount.
47    pub fn next_position_impact_pool_amount(&self) -> &T {
48        &self.next_position_impact_pool_amount
49    }
50}
51
52impl<M: PositionImpactMarketMut<DECIMALS>, const DECIMALS: u8> MarketAction
53    for DistributePositionImpact<M, DECIMALS>
54{
55    type Report = DistributePositionImpactReport<M::Num>;
56
57    fn execute(mut self) -> crate::Result<Self::Report> {
58        let duration_in_seconds = self
59            .market
60            .just_passed_in_seconds_for_position_impact_distribution()?;
61
62        let (distribution_amount, next_position_impact_pool_amount) = self
63            .market
64            .pending_position_impact_pool_distribution_amount(duration_in_seconds)?;
65
66        if !distribution_amount.is_zero() {
67            self.market
68                .apply_delta_to_position_impact_pool(&distribution_amount.to_opposite_signed()?)?;
69        }
70
71        Ok(DistributePositionImpactReport {
72            duration_in_seconds,
73            distribution_amount,
74            next_position_impact_pool_amount,
75        })
76    }
77}
78
79impl<M: BaseMarket<DECIMALS>, const DECIMALS: u8> From<M>
80    for DistributePositionImpact<M, DECIMALS>
81{
82    fn from(market: M) -> Self {
83        Self { market }
84    }
85}
86
87#[cfg(test)]
88mod tests {
89    use std::{thread::sleep, time::Duration};
90
91    use crate::{
92        market::LiquidityMarketMutExt,
93        price::Prices,
94        test::{TestMarket, TestPosition},
95        MarketAction, PositionMutExt,
96    };
97
98    use super::*;
99
100    #[test]
101    fn test_distribute_position_impact() -> crate::Result<()> {
102        let mut market = TestMarket::<u64, 9>::default();
103        market.distribute_position_impact()?.execute()?;
104        let prices = Prices::new_for_test(120, 120, 1);
105        market
106            .deposit(1_000_000_000_000, 100_000_000_000_000, prices)?
107            .execute()?;
108        println!("{market:#?}");
109        let mut position = TestPosition::long(true);
110        for _ in 0..100 {
111            market.distribute_position_impact()?.execute()?;
112            _ = position
113                .ops(&mut market)
114                .increase(
115                    Prices::new_for_test(123, 123, 1),
116                    1_000_000_000_000,
117                    50_000_000_000_000,
118                    None,
119                )?
120                .execute()?;
121            market.distribute_position_impact()?.execute()?;
122            _ = position
123                .ops(&mut market)
124                .decrease(
125                    Prices::new_for_test(123, 123, 1),
126                    50_000_000_000_000,
127                    None,
128                    0,
129                    Default::default(),
130                )?
131                .execute()?;
132        }
133        println!("{market:#?}");
134        sleep(Duration::from_secs(1));
135        let report = market.distribute_position_impact()?.execute()?;
136        println!("{report:#?}");
137        println!("{market:#?}");
138        Ok(())
139    }
140}