use num_traits::Zero;
use crate::{
market::{
BaseMarket, PositionImpactMarketExt, PositionImpactMarketMut, PositionImpactMarketMutExt,
},
num::Unsigned,
};
use super::MarketAction;
#[must_use = "actions do nothing unless you `execute` them"]
pub struct DistributePositionImpact<M: BaseMarket<DECIMALS>, const DECIMALS: u8> {
market: M,
}
#[derive(Debug)]
#[cfg_attr(
feature = "anchor-lang",
derive(anchor_lang::AnchorDeserialize, anchor_lang::AnchorSerialize)
)]
pub struct DistributePositionImpactReport<T> {
duration_in_seconds: u64,
distribution_amount: T,
next_position_impact_pool_amount: T,
}
#[cfg(feature = "gmsol-utils")]
impl<T: gmsol_utils::InitSpace> gmsol_utils::InitSpace for DistributePositionImpactReport<T> {
const INIT_SPACE: usize = u64::INIT_SPACE + 2 * T::INIT_SPACE;
}
impl<T> DistributePositionImpactReport<T> {
pub fn duration_in_seconds(&self) -> u64 {
self.duration_in_seconds
}
pub fn distribution_amount(&self) -> &T {
&self.distribution_amount
}
pub fn next_position_impact_pool_amount(&self) -> &T {
&self.next_position_impact_pool_amount
}
}
impl<M: PositionImpactMarketMut<DECIMALS>, const DECIMALS: u8> MarketAction
for DistributePositionImpact<M, DECIMALS>
{
type Report = DistributePositionImpactReport<M::Num>;
fn execute(mut self) -> crate::Result<Self::Report> {
let duration_in_seconds = self
.market
.just_passed_in_seconds_for_position_impact_distribution()?;
let (distribution_amount, next_position_impact_pool_amount) = self
.market
.pending_position_impact_pool_distribution_amount(duration_in_seconds)?;
if !distribution_amount.is_zero() {
self.market
.apply_delta_to_position_impact_pool(&distribution_amount.to_opposite_signed()?)?;
}
Ok(DistributePositionImpactReport {
duration_in_seconds,
distribution_amount,
next_position_impact_pool_amount,
})
}
}
impl<M: BaseMarket<DECIMALS>, const DECIMALS: u8> From<M>
for DistributePositionImpact<M, DECIMALS>
{
fn from(market: M) -> Self {
Self { market }
}
}
#[cfg(test)]
mod tests {
use std::{thread::sleep, time::Duration};
use crate::{
market::LiquidityMarketMutExt,
price::Prices,
test::{TestMarket, TestPosition},
MarketAction, PositionMutExt,
};
use super::*;
#[test]
fn test_distribute_position_impact() -> crate::Result<()> {
let mut market = TestMarket::<u64, 9>::default();
market.distribute_position_impact()?.execute()?;
let prices = Prices::new_for_test(120, 120, 1);
market
.deposit(1_000_000_000_000, 100_000_000_000_000, prices)?
.execute()?;
println!("{market:#?}");
let mut position = TestPosition::long(true);
for _ in 0..100 {
market.distribute_position_impact()?.execute()?;
_ = position
.ops(&mut market)
.increase(
Prices::new_for_test(123, 123, 1),
1_000_000_000_000,
50_000_000_000_000,
None,
)?
.execute()?;
market.distribute_position_impact()?.execute()?;
_ = position
.ops(&mut market)
.decrease(
Prices::new_for_test(123, 123, 1),
50_000_000_000_000,
None,
0,
Default::default(),
)?
.execute()?;
}
println!("{market:#?}");
sleep(Duration::from_secs(1));
let report = market.distribute_position_impact()?.execute()?;
println!("{report:#?}");
println!("{market:#?}");
Ok(())
}
}