gmsol_model/action/
distribute_position_impact.rs1use num_traits::Zero;
2
3use crate::{
4 market::{
5 BaseMarket, PositionImpactMarketExt, PositionImpactMarketMut, PositionImpactMarketMutExt,
6 },
7 num::Unsigned,
8};
9
10use super::MarketAction;
11
12#[must_use = "actions do nothing unless you `execute` them"]
14pub struct DistributePositionImpact<M: BaseMarket<DECIMALS>, const DECIMALS: u8> {
15 market: M,
16}
17
18#[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 pub fn duration_in_seconds(&self) -> u64 {
38 self.duration_in_seconds
39 }
40
41 pub fn distribution_amount(&self) -> &T {
43 &self.distribution_amount
44 }
45
46 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}