gmsol_model/action/decrease_position/
report.rs

1use std::fmt;
2
3#[cfg(feature = "anchor-lang")]
4use anchor_lang::Space;
5
6use crate::{num::Unsigned, params::fee::PositionFees, position::InsolventCloseStep};
7
8use super::{ClaimableCollateral, DecreasePositionParams, ProcessCollateralResult};
9
10/// Report of the execution of position decreasing.
11#[must_use = "
12    `output_amount`, `secondary_output_amount`, `should_remove`, `withdrawable_collateral_amount`,
13    `claimable_funding_amounts`, `claimable_collateral_for_holding` and `claimable_collateral_for_user`
14    must be used
15"]
16#[derive(Clone)]
17#[cfg_attr(
18    feature = "anchor-lang",
19    derive(anchor_lang::AnchorDeserialize, anchor_lang::AnchorSerialize)
20)]
21pub struct DecreasePositionReport<Unsigned, Signed> {
22    price_impact_value: Signed,
23    price_impact_diff: Unsigned,
24    execution_price: Unsigned,
25    size_delta_in_tokens: Unsigned,
26    withdrawable_collateral_amount: Unsigned,
27    initial_size_delta_usd: Unsigned,
28    size_delta_usd: Unsigned,
29    fees: PositionFees<Unsigned>,
30    pnl: Pnl<Signed>,
31    insolvent_close_step: Option<InsolventCloseStep>,
32    // Output
33    should_remove: bool,
34    is_output_token_long: bool,
35    is_secondary_output_token_long: bool,
36    output_amounts: OutputAmounts<Unsigned>,
37    claimable_funding_long_token_amount: Unsigned,
38    claimable_funding_short_token_amount: Unsigned,
39    for_holding: ClaimableCollateral<Unsigned>,
40    for_user: ClaimableCollateral<Unsigned>,
41}
42
43#[cfg(feature = "gmsol-utils")]
44impl<Unsigned, Signed> gmsol_utils::InitSpace for DecreasePositionReport<Unsigned, Signed>
45where
46    Unsigned: gmsol_utils::InitSpace,
47    Signed: gmsol_utils::InitSpace,
48{
49    const INIT_SPACE: usize = Signed::INIT_SPACE
50        + 6 * Unsigned::INIT_SPACE
51        + PositionFees::<Unsigned>::INIT_SPACE
52        + Pnl::<Signed>::INIT_SPACE
53        + 1
54        + InsolventCloseStep::INIT_SPACE
55        + 3 * bool::INIT_SPACE
56        + OutputAmounts::<Unsigned>::INIT_SPACE
57        + 2 * Unsigned::INIT_SPACE
58        + 2 * ClaimableCollateral::<Unsigned>::INIT_SPACE;
59}
60
61impl<T: Unsigned + fmt::Debug> fmt::Debug for DecreasePositionReport<T, T::Signed>
62where
63    T::Signed: fmt::Debug,
64{
65    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
66        f.debug_struct("DecreasePositionReport")
67            .field("price_impact_value", &self.price_impact_value)
68            .field("price_impact_diff", &self.price_impact_diff)
69            .field("execution_price", &self.execution_price)
70            .field("size_delta_in_tokens", &self.size_delta_in_tokens)
71            .field(
72                "withdrawable_collateral_amount",
73                &self.withdrawable_collateral_amount,
74            )
75            .field("initial_size_delta_usd", &self.initial_size_delta_usd)
76            .field("size_delta_usd", &self.size_delta_usd)
77            .field("fees", &self.fees)
78            .field("pnl", &self.pnl)
79            .field("insolvent_close_step", &self.insolvent_close_step)
80            .field("should_remove", &self.should_remove)
81            .field("is_output_token_long", &self.is_output_token_long)
82            .field(
83                "is_secondary_output_token_long",
84                &self.is_secondary_output_token_long,
85            )
86            .field("output_amounts", &self.output_amounts)
87            .field(
88                "claimable_funding_long_token_amount",
89                &self.claimable_funding_long_token_amount,
90            )
91            .field(
92                "claimable_funding_short_token_amount",
93                &self.claimable_funding_short_token_amount,
94            )
95            .field("for_holding", &self.for_holding)
96            .field("for_user", &self.for_user)
97            .finish()
98    }
99}
100
101impl<T: Unsigned + Clone> DecreasePositionReport<T, T::Signed> {
102    pub(super) fn new(
103        params: &DecreasePositionParams<T>,
104        execution: ProcessCollateralResult<T>,
105        withdrawable_collateral_amount: T,
106        size_delta_usd: T,
107        should_remove: bool,
108    ) -> Self {
109        let claimable_funding_long_token_amount = execution
110            .fees
111            .funding_fees()
112            .claimable_long_token_amount()
113            .clone();
114        let claimable_funding_short_token_amount = execution
115            .fees
116            .funding_fees()
117            .claimable_short_token_amount()
118            .clone();
119        Self {
120            price_impact_value: execution.price_impact_value,
121            price_impact_diff: execution.price_impact_diff,
122            execution_price: execution.execution_price,
123            size_delta_in_tokens: execution.size_delta_in_tokens,
124            withdrawable_collateral_amount,
125            initial_size_delta_usd: params.initial_size_delta_usd.clone(),
126            size_delta_usd,
127            fees: execution.fees,
128            pnl: execution.pnl,
129            insolvent_close_step: execution.collateral.insolvent_close_step,
130            // Output
131            should_remove,
132            is_output_token_long: execution.is_output_token_long,
133            is_secondary_output_token_long: execution.is_secondary_output_token_long,
134            output_amounts: OutputAmounts {
135                output_amount: execution.collateral.output_amount,
136                secondary_output_amount: execution.collateral.secondary_output_amount,
137            },
138            claimable_funding_long_token_amount,
139            claimable_funding_short_token_amount,
140            for_holding: execution.collateral.for_holding,
141            for_user: execution.collateral.for_user,
142        }
143    }
144
145    /// Get size delta in tokens.
146    pub fn size_delta_in_tokens(&self) -> &T {
147        &self.size_delta_in_tokens
148    }
149
150    /// Get initial size delta in usd.
151    pub fn initial_size_delta_usd(&self) -> &T {
152        &self.initial_size_delta_usd
153    }
154
155    /// Get size delta in usd.
156    pub fn size_delta_usd(&self) -> &T {
157        &self.size_delta_usd
158    }
159
160    /// Get execution price.
161    pub fn execution_price(&self) -> &T {
162        &self.execution_price
163    }
164
165    /// Get price impact value.
166    pub fn price_impact_value(&self) -> &T::Signed {
167        &self.price_impact_value
168    }
169
170    /// Get price impact diff.
171    pub fn price_impact_diff(&self) -> &T {
172        &self.price_impact_diff
173    }
174
175    /// Get execution fees.
176    pub fn fees(&self) -> &PositionFees<T> {
177        &self.fees
178    }
179
180    /// Returns whether the output token (collateral token) is the long token.
181    pub fn is_output_token_long(&self) -> bool {
182        self.is_output_token_long
183    }
184
185    /// Returns whether the secondary output token (pnl token) is the long token.
186    pub fn is_secondary_output_token_long(&self) -> bool {
187        self.is_secondary_output_token_long
188    }
189
190    /// Get the output amount.
191    #[must_use = "the returned amount of output tokens should be transferred out from the market vault"]
192    pub fn output_amount(&self) -> &T {
193        &self.output_amounts.output_amount
194    }
195
196    /// Get secondary output amount.
197    #[must_use = "the returned amount of secondary output tokens should be transferred out from the market vault"]
198    pub fn secondary_output_amount(&self) -> &T {
199        &self.output_amounts.secondary_output_amount
200    }
201
202    /// Get output amounts.
203    pub fn output_amounts(&self) -> &OutputAmounts<T> {
204        &self.output_amounts
205    }
206
207    pub(super) fn output_amounts_mut(&mut self) -> (&mut T, &mut T) {
208        (
209            &mut self.output_amounts.output_amount,
210            &mut self.output_amounts.secondary_output_amount,
211        )
212    }
213
214    /// Returns whether the position should be removed.
215    #[must_use = "The position should be removed if `true` is returned"]
216    pub fn should_remove(&self) -> bool {
217        self.should_remove
218    }
219
220    /// Get withdrawable collateral amount.
221    #[must_use = "the returned amount of collateral tokens should be transferred out from the market vault"]
222    pub fn withdrawable_collateral_amount(&self) -> &T {
223        &self.withdrawable_collateral_amount
224    }
225
226    /// Get claimable funding amounts.
227    #[must_use = "the returned amounts of tokens should be transferred out from the market vault"]
228    pub fn claimable_funding_amounts(&self) -> (&T, &T) {
229        (
230            &self.claimable_funding_long_token_amount,
231            &self.claimable_funding_short_token_amount,
232        )
233    }
234
235    /// Get claimable collateral for holding.
236    #[must_use = "the returned amount of tokens should be transferred out from the market vault"]
237    pub fn claimable_collateral_for_holding(&self) -> &ClaimableCollateral<T> {
238        &self.for_holding
239    }
240
241    /// Get Get claimable collateral for user.
242    #[must_use = "the returned amount of tokens should be transferred out from the market vault"]
243    pub fn claimable_collateral_for_user(&self) -> &ClaimableCollateral<T> {
244        &self.for_user
245    }
246
247    /// Get processed pnl.
248    pub fn pnl(&self) -> &Pnl<T::Signed> {
249        &self.pnl
250    }
251
252    /// Get insolvent close step.
253    pub fn insolvent_close_step(&self) -> Option<InsolventCloseStep> {
254        self.insolvent_close_step
255    }
256}
257
258/// Processed PnL.
259#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
260#[cfg_attr(
261    feature = "anchor-lang",
262    derive(anchor_lang::AnchorDeserialize, anchor_lang::AnchorSerialize)
263)]
264#[derive(Debug, Clone, Copy, Default)]
265pub struct Pnl<T> {
266    /// Final PnL value.
267    pnl: T,
268    /// Uncapped PnL value.
269    uncapped_pnl: T,
270}
271
272#[cfg(feature = "gmsol-utils")]
273impl<T: gmsol_utils::InitSpace> gmsol_utils::InitSpace for Pnl<T> {
274    const INIT_SPACE: usize = 2 * T::INIT_SPACE;
275}
276
277impl<T> Pnl<T> {
278    /// Create a new [`Pnl`].
279    pub fn new(pnl: T, uncapped_pnl: T) -> Self {
280        Self { pnl, uncapped_pnl }
281    }
282
283    /// Get final pnl value.
284    pub fn pnl(&self) -> &T {
285        &self.pnl
286    }
287
288    /// Get uncapped pnl value.
289    pub fn uncapped_pnl(&self) -> &T {
290        &self.uncapped_pnl
291    }
292}
293
294/// Output amounts.
295#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
296#[cfg_attr(
297    feature = "anchor-lang",
298    derive(anchor_lang::AnchorDeserialize, anchor_lang::AnchorSerialize)
299)]
300#[derive(Debug, Clone, Copy, Default)]
301pub struct OutputAmounts<T> {
302    pub(super) output_amount: T,
303    pub(super) secondary_output_amount: T,
304}
305
306#[cfg(feature = "gmsol-utils")]
307impl<T: gmsol_utils::InitSpace> gmsol_utils::InitSpace for OutputAmounts<T> {
308    const INIT_SPACE: usize = 2 * T::INIT_SPACE;
309}
310
311impl<T> OutputAmounts<T> {
312    /// Get output amount.
313    pub fn output_amount(&self) -> &T {
314        &self.output_amount
315    }
316
317    /// Get secondary output amount.
318    pub fn secondary_output_amount(&self) -> &T {
319        &self.secondary_output_amount
320    }
321}