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    /// Optional stop loss price
31    pub stop_loss_price: Option<IFixed>,
32    /// Optional take profit price
33    pub take_profit_price: Option<IFixed>,
34    /// `true` if position is short, `false` if position is long
35    pub position_is_ask: bool,
36    pub size: u64,
37    /// Can be set at random value if `is_limit_order` is false
38    pub price: u64,
39    /// Can be set at random value if `is_limit_order` is false
40    pub order_type: OrderType,
41}
42
43impl StopOrderTicketDetails for SLTPDetails {}
44
45/// The details to be hashed for the `encrypted_details` argument of `create_stop_order_ticket`.
46#[derive(Debug, serde::Serialize)]
47pub struct StandaloneDetails {
48    pub clearing_house_id: ID,
49    /// The `Clock` value after (>=) which the order isn't valid anymore
50    pub expire_timestamp: Option<u64>,
51    /// `true` if limit order, `false` if market order
52    pub is_limit_order: bool,
53    pub stop_index_price: IFixed,
54    /// `true` if the order can be placed when oracle index price is >= than
55    /// chosen `stop_index_price`
56    pub ge_stop_index_price: bool,
57    pub side: Side,
58    pub size: u64,
59    /// Can be set at random value if `is_limit_order` is false
60    pub price: u64,
61    /// Can be set at random value if `is_limit_order` is false
62    pub order_type: OrderType,
63    pub reduce_only: bool,
64}
65
66impl StopOrderTicketDetails for StandaloneDetails {}
67
68#[derive(Clone, Copy, Debug, clap::ValueEnum, Serialize, Deserialize)]
69#[serde(into = "u64")]
70pub enum StopOrderType {
71    /// Stop-Loss / Take-Profit type, aimed to reduce position
72    SLTP,
73    /// Standard stop order, without restrictions
74    Standalone,
75}
76
77impl From<StopOrderType> for u64 {
78    fn from(value: StopOrderType) -> Self {
79        match value {
80            StopOrderType::SLTP => 0,
81            StopOrderType::Standalone => 1,
82        }
83    }
84}
85
86#[derive(thiserror::Error, Debug)]
87#[error("Invalid stop order type value")]
88pub struct InvalidStopOrderTypeValue;
89
90impl TryFrom<u64> for StopOrderType {
91    type Error = InvalidStopOrderTypeValue;
92
93    fn try_from(value: u64) -> Result<Self, Self::Error> {
94        match value {
95            0 => Ok(Self::SLTP),
96            1 => Ok(Self::Standalone),
97            _ => Err(InvalidStopOrderTypeValue),
98        }
99    }
100}