use std::fmt;
#[cfg(feature = "anchor-lang")]
use anchor_lang::Space;
use crate::{num::Unsigned, params::fee::PositionFees, position::InsolventCloseStep};
use super::{ClaimableCollateral, DecreasePositionParams, ProcessCollateralResult};
#[must_use = "
`output_amount`, `secondary_output_amount`, `should_remove`, `withdrawable_collateral_amount`,
`claimable_funding_amounts`, `claimable_collateral_for_holding` and `claimable_collateral_for_user`
must be used
"]
#[derive(Clone)]
#[cfg_attr(
feature = "anchor-lang",
derive(anchor_lang::AnchorDeserialize, anchor_lang::AnchorSerialize)
)]
pub struct DecreasePositionReport<Unsigned, Signed> {
price_impact_value: Signed,
price_impact_diff: Unsigned,
execution_price: Unsigned,
size_delta_in_tokens: Unsigned,
withdrawable_collateral_amount: Unsigned,
initial_size_delta_usd: Unsigned,
size_delta_usd: Unsigned,
fees: PositionFees<Unsigned>,
pnl: Pnl<Signed>,
insolvent_close_step: Option<InsolventCloseStep>,
should_remove: bool,
is_output_token_long: bool,
is_secondary_output_token_long: bool,
output_amounts: OutputAmounts<Unsigned>,
claimable_funding_long_token_amount: Unsigned,
claimable_funding_short_token_amount: Unsigned,
for_holding: ClaimableCollateral<Unsigned>,
for_user: ClaimableCollateral<Unsigned>,
}
#[cfg(feature = "gmsol-utils")]
impl<Unsigned, Signed> gmsol_utils::InitSpace for DecreasePositionReport<Unsigned, Signed>
where
Unsigned: gmsol_utils::InitSpace,
Signed: gmsol_utils::InitSpace,
{
const INIT_SPACE: usize = Signed::INIT_SPACE
+ 6 * Unsigned::INIT_SPACE
+ PositionFees::<Unsigned>::INIT_SPACE
+ Pnl::<Signed>::INIT_SPACE
+ 1
+ InsolventCloseStep::INIT_SPACE
+ 3 * bool::INIT_SPACE
+ OutputAmounts::<Unsigned>::INIT_SPACE
+ 2 * Unsigned::INIT_SPACE
+ 2 * ClaimableCollateral::<Unsigned>::INIT_SPACE;
}
impl<T: Unsigned + fmt::Debug> fmt::Debug for DecreasePositionReport<T, T::Signed>
where
T::Signed: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("DecreasePositionReport")
.field("price_impact_value", &self.price_impact_value)
.field("price_impact_diff", &self.price_impact_diff)
.field("execution_price", &self.execution_price)
.field("size_delta_in_tokens", &self.size_delta_in_tokens)
.field(
"withdrawable_collateral_amount",
&self.withdrawable_collateral_amount,
)
.field("initial_size_delta_usd", &self.initial_size_delta_usd)
.field("size_delta_usd", &self.size_delta_usd)
.field("fees", &self.fees)
.field("pnl", &self.pnl)
.field("insolvent_close_step", &self.insolvent_close_step)
.field("should_remove", &self.should_remove)
.field("is_output_token_long", &self.is_output_token_long)
.field(
"is_secondary_output_token_long",
&self.is_secondary_output_token_long,
)
.field("output_amounts", &self.output_amounts)
.field(
"claimable_funding_long_token_amount",
&self.claimable_funding_long_token_amount,
)
.field(
"claimable_funding_short_token_amount",
&self.claimable_funding_short_token_amount,
)
.field("for_holding", &self.for_holding)
.field("for_user", &self.for_user)
.finish()
}
}
impl<T: Unsigned + Clone> DecreasePositionReport<T, T::Signed> {
pub(super) fn new(
params: &DecreasePositionParams<T>,
execution: ProcessCollateralResult<T>,
withdrawable_collateral_amount: T,
size_delta_usd: T,
should_remove: bool,
) -> Self {
let claimable_funding_long_token_amount = execution
.fees
.funding_fees()
.claimable_long_token_amount()
.clone();
let claimable_funding_short_token_amount = execution
.fees
.funding_fees()
.claimable_short_token_amount()
.clone();
Self {
price_impact_value: execution.price_impact_value,
price_impact_diff: execution.price_impact_diff,
execution_price: execution.execution_price,
size_delta_in_tokens: execution.size_delta_in_tokens,
withdrawable_collateral_amount,
initial_size_delta_usd: params.initial_size_delta_usd.clone(),
size_delta_usd,
fees: execution.fees,
pnl: execution.pnl,
insolvent_close_step: execution.collateral.insolvent_close_step,
should_remove,
is_output_token_long: execution.is_output_token_long,
is_secondary_output_token_long: execution.is_secondary_output_token_long,
output_amounts: OutputAmounts {
output_amount: execution.collateral.output_amount,
secondary_output_amount: execution.collateral.secondary_output_amount,
},
claimable_funding_long_token_amount,
claimable_funding_short_token_amount,
for_holding: execution.collateral.for_holding,
for_user: execution.collateral.for_user,
}
}
pub fn size_delta_in_tokens(&self) -> &T {
&self.size_delta_in_tokens
}
pub fn initial_size_delta_usd(&self) -> &T {
&self.initial_size_delta_usd
}
pub fn size_delta_usd(&self) -> &T {
&self.size_delta_usd
}
pub fn execution_price(&self) -> &T {
&self.execution_price
}
pub fn price_impact_value(&self) -> &T::Signed {
&self.price_impact_value
}
pub fn price_impact_diff(&self) -> &T {
&self.price_impact_diff
}
pub fn fees(&self) -> &PositionFees<T> {
&self.fees
}
pub fn is_output_token_long(&self) -> bool {
self.is_output_token_long
}
pub fn is_secondary_output_token_long(&self) -> bool {
self.is_secondary_output_token_long
}
#[must_use = "the returned amount of output tokens should be transferred out from the market vault"]
pub fn output_amount(&self) -> &T {
&self.output_amounts.output_amount
}
#[must_use = "the returned amount of secondary output tokens should be transferred out from the market vault"]
pub fn secondary_output_amount(&self) -> &T {
&self.output_amounts.secondary_output_amount
}
pub fn output_amounts(&self) -> &OutputAmounts<T> {
&self.output_amounts
}
pub(super) fn output_amounts_mut(&mut self) -> (&mut T, &mut T) {
(
&mut self.output_amounts.output_amount,
&mut self.output_amounts.secondary_output_amount,
)
}
#[must_use = "The position should be removed if `true` is returned"]
pub fn should_remove(&self) -> bool {
self.should_remove
}
#[must_use = "the returned amount of collateral tokens should be transferred out from the market vault"]
pub fn withdrawable_collateral_amount(&self) -> &T {
&self.withdrawable_collateral_amount
}
#[must_use = "the returned amounts of tokens should be transferred out from the market vault"]
pub fn claimable_funding_amounts(&self) -> (&T, &T) {
(
&self.claimable_funding_long_token_amount,
&self.claimable_funding_short_token_amount,
)
}
#[must_use = "the returned amount of tokens should be transferred out from the market vault"]
pub fn claimable_collateral_for_holding(&self) -> &ClaimableCollateral<T> {
&self.for_holding
}
#[must_use = "the returned amount of tokens should be transferred out from the market vault"]
pub fn claimable_collateral_for_user(&self) -> &ClaimableCollateral<T> {
&self.for_user
}
pub fn pnl(&self) -> &Pnl<T::Signed> {
&self.pnl
}
pub fn insolvent_close_step(&self) -> Option<InsolventCloseStep> {
self.insolvent_close_step
}
}
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(
feature = "anchor-lang",
derive(anchor_lang::AnchorDeserialize, anchor_lang::AnchorSerialize)
)]
#[derive(Debug, Clone, Copy, Default)]
pub struct Pnl<T> {
pnl: T,
uncapped_pnl: T,
}
#[cfg(feature = "gmsol-utils")]
impl<T: gmsol_utils::InitSpace> gmsol_utils::InitSpace for Pnl<T> {
const INIT_SPACE: usize = 2 * T::INIT_SPACE;
}
impl<T> Pnl<T> {
pub fn new(pnl: T, uncapped_pnl: T) -> Self {
Self { pnl, uncapped_pnl }
}
pub fn pnl(&self) -> &T {
&self.pnl
}
pub fn uncapped_pnl(&self) -> &T {
&self.uncapped_pnl
}
}
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(
feature = "anchor-lang",
derive(anchor_lang::AnchorDeserialize, anchor_lang::AnchorSerialize)
)]
#[derive(Debug, Clone, Copy, Default)]
pub struct OutputAmounts<T> {
pub(super) output_amount: T,
pub(super) secondary_output_amount: T,
}
#[cfg(feature = "gmsol-utils")]
impl<T: gmsol_utils::InitSpace> gmsol_utils::InitSpace for OutputAmounts<T> {
const INIT_SPACE: usize = 2 * T::INIT_SPACE;
}
impl<T> OutputAmounts<T> {
pub fn output_amount(&self) -> &T {
&self.output_amount
}
pub fn secondary_output_amount(&self) -> &T {
&self.secondary_output_amount
}
}