af_iperps/
stop_order_helpers.rs

1//! Helpers for stop orders.
2
3use af_utilities::IFixed;
4use fastcrypto::hash::{Blake2b256, HashFunction};
5use serde::{Deserialize, Serialize};
6use sui_framework_sdk::object::ID;
7
8use crate::order_helpers::{OrderType, Side};
9
10pub trait StopOrderTicketDetails {
11    /// Pure transaction input to use when calling `create_stop_order_ticket`.
12    fn encrypted_details(&self, salt: Vec<u8>) -> bcs::Result<Vec<u8>>
13    where
14        Self: serde::Serialize,
15    {
16        let mut bytes = bcs::to_bytes(self)?;
17        bytes.extend(salt);
18        Ok(Blake2b256::digest(bytes).to_vec())
19    }
20}
21
22/// The details to be hashed for the `encrypted_details` argument of `create_stop_order_ticket`.
23#[derive(Debug, serde::Serialize)]
24pub struct SLTPDetails {
25    pub clearing_house_id: ID,
26    /// The `Clock` value after (>=) which the order isn't valid anymore
27    pub expire_timestamp: Option<u64>,
28    /// `true` if limit order, `false` if market order
29    pub is_limit_order: bool,
30    pub stop_index_price: IFixed,
31    /// `true` if stop loss order, `false` if take profit order
32    pub is_stop_loss: bool,
33    /// - position_is_ask: `true` if position is short, `false` if position is long
34    pub position_is_ask: bool,
35    pub size: u64,
36    /// Can be set at random value if `is_limit_order` is false
37    pub price: u64,
38    /// Can be set at random value if `is_limit_order` is false
39    pub order_type: OrderType,
40}
41
42impl StopOrderTicketDetails for SLTPDetails {}
43
44/// The details to be hashed for the `encrypted_details` argument of `create_stop_order_ticket`.
45#[derive(Debug, serde::Serialize)]
46pub struct StandaloneDetails {
47    pub clearing_house_id: ID,
48    /// The `Clock` value after (>=) which the order isn't valid anymore
49    pub expire_timestamp: Option<u64>,
50    /// `true` if limit order, `false` if market order
51    pub is_limit_order: bool,
52    pub stop_index_price: IFixed,
53    /// `true` means the order can be placed when oracle index price is >= than chosen
54    /// `stop_index_price`
55    pub ge_stop_index_price: bool,
56    pub side: Side,
57    pub size: u64,
58    /// Can be set at random value if `is_limit_order` is false
59    pub price: u64,
60    /// Can be set at random value if `is_limit_order` is false
61    pub order_type: OrderType,
62    pub reduce_only: bool,
63}
64
65impl StopOrderTicketDetails for StandaloneDetails {}
66
67#[derive(Clone, Copy, Debug, clap::ValueEnum, Serialize, Deserialize)]
68#[serde(into = "u64")]
69pub enum StopOrderType {
70    /// Stop-Loss / Take-Profit type, aimed to reduce position
71    SLTP,
72    /// Standard stop order, without restrictions
73    Standalone,
74}
75
76impl From<StopOrderType> for u64 {
77    fn from(value: StopOrderType) -> Self {
78        match value {
79            StopOrderType::SLTP => 0,
80            StopOrderType::Standalone => 1,
81        }
82    }
83}
84
85#[derive(thiserror::Error, Debug)]
86#[error("Invalid stop order type value")]
87pub struct InvalidStopOrderTypeValue;
88
89impl TryFrom<u64> for StopOrderType {
90    type Error = InvalidStopOrderTypeValue;
91
92    fn try_from(value: u64) -> Result<Self, Self::Error> {
93        match value {
94            0 => Ok(Self::SLTP),
95            1 => Ok(Self::Standalone),
96            _ => Err(InvalidStopOrderTypeValue),
97        }
98    }
99}