Skip to main content

o2_api_types/domain/
book.rs

1use crate::{
2    OrderId,
3    domain::{
4        event::{
5            CancellationReason,
6            Identity,
7        },
8        trade::TradeId,
9    },
10    fuel_types::{
11        AssetId,
12        Bytes32,
13        ContractId,
14        TxId,
15    },
16    parse::{
17        HexDisplayFromStr,
18        serialize_hex,
19    },
20    primitives::{
21        OrderType,
22        Side,
23    },
24};
25use serde_with::{
26    DisplayFromStr,
27    serde_as,
28};
29use sha2::{
30    Digest,
31    Sha256,
32};
33use std::collections::BTreeMap;
34
35pub type Price = u64;
36pub type Quantity = u64;
37pub type MarketId = Bytes32;
38
39#[derive(Clone, Copy, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
40pub enum BaseQuantity {
41    Quantity(Quantity),
42    Infinite,
43}
44
45#[derive(Clone, Copy, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
46pub enum UnderlyingAsset {
47    Base {
48        remaining_quantity: Quantity,
49    },
50    Quote {
51        desired_base_quantity: BaseQuantity,
52        remaining_quote_token: Quantity,
53    },
54}
55
56#[derive(
57    Copy, Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize, Hash,
58)]
59pub struct MarketIdAssets {
60    pub base_asset: AssetId,
61    pub quote_asset: AssetId,
62}
63
64impl MarketIdAssets {
65    pub fn market_id(&self) -> MarketId {
66        let bytes: Vec<u8> = self
67            .quote_asset
68            .into_iter()
69            .chain(self.base_asset.to_vec())
70            .collect();
71        let digest = Sha256::digest(bytes.as_slice());
72        MarketId::new(digest.into())
73    }
74}
75
76#[serde_as]
77#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
78pub struct AssetConfig {
79    pub symbol: String,
80    #[serde(serialize_with = "serialize_hex")]
81    pub asset: AssetId,
82    pub decimals: u8,
83    pub min_precision: u8,
84    pub max_precision: u8,
85}
86
87#[serde_as]
88#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize)]
89pub struct OrderBookConfig {
90    #[serde_as(as = "Option<HexDisplayFromStr>")]
91    pub contract_id: Option<ContractId>,
92    #[serde_as(as = "Option<HexDisplayFromStr>")]
93    pub blob_id: Option<ContractId>,
94    #[serde_as(as = "HexDisplayFromStr")]
95    pub market_id: MarketId,
96    #[serde_as(as = "DisplayFromStr")]
97    pub taker_fee: u64,
98    #[serde_as(as = "DisplayFromStr")]
99    pub maker_fee: u64,
100    #[serde_as(as = "DisplayFromStr")]
101    pub min_order: u64,
102    #[serde_as(as = "DisplayFromStr")]
103    pub dust: u64,
104    pub price_window: u8,
105    pub base: AssetConfig,
106    pub quote: AssetConfig,
107}
108
109#[derive(
110    Default, Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize,
111)]
112pub struct Fill {
113    pub order_id: OrderId,
114    pub quantity: Quantity,
115    pub price: Price,
116    pub timestamp: u128,
117    pub fee: u64,
118}
119
120#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
121pub enum HistoryStep {
122    Confirmed { tx_id: TxId },
123}
124
125impl HistoryStep {
126    pub fn kind(&self) -> String {
127        match self {
128            HistoryStep::Confirmed { .. } => "confirmed".to_string(),
129        }
130    }
131}
132
133#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
134pub enum OrderHistory {
135    Created {
136        tx: HistoryStep,
137    },
138    Trade {
139        tx: HistoryStep,
140        trade_id: TradeId,
141    },
142    Canceled {
143        tx: HistoryStep,
144        reason: CancellationReason,
145    },
146}
147
148impl OrderHistory {
149    pub fn kind(&self) -> String {
150        match self {
151            OrderHistory::Created { .. } => "created".to_string(),
152            OrderHistory::Trade { .. } => "trade".to_string(),
153            OrderHistory::Canceled { .. } => "canceled".to_string(),
154        }
155    }
156
157    pub fn status_kind(&self) -> String {
158        match self {
159            OrderHistory::Created { tx } => tx.kind(),
160            OrderHistory::Trade { tx, .. } => tx.kind(),
161            OrderHistory::Canceled { tx, .. } => tx.kind(),
162        }
163    }
164
165    pub fn tx_id(&self) -> TxId {
166        match self {
167            OrderHistory::Created { tx } => match tx {
168                HistoryStep::Confirmed { tx_id } => *tx_id,
169            },
170            OrderHistory::Trade { tx, .. } => match tx {
171                HistoryStep::Confirmed { tx_id } => *tx_id,
172            },
173            OrderHistory::Canceled { tx, .. } => match tx {
174                HistoryStep::Confirmed { tx_id } => *tx_id,
175            },
176        }
177    }
178}
179
180#[derive(
181    Copy,
182    Clone,
183    Debug,
184    strum_macros::EnumCount,
185    strum_macros::IntoStaticStr,
186    strum_macros::FromRepr,
187    PartialEq,
188    Eq,
189    enum_iterator::Sequence,
190    Hash,
191)]
192#[repr(u8)]
193pub enum OrderStatus {
194    Active,
195    Canceled,
196    Filled,
197    PartiallyFilled,
198}
199
200impl TryFrom<u8> for OrderStatus {
201    type Error = anyhow::Error;
202
203    fn try_from(value: u8) -> Result<Self, Self::Error> {
204        OrderStatus::from_repr(value).ok_or_else(|| {
205            anyhow::anyhow!("Invalid value for OrderStatus enum: {}", value)
206        })
207    }
208}
209
210#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
211pub struct Order {
212    pub order_id: OrderId,
213    pub account: Identity,
214    pub side: Side,
215    pub order_type: OrderType,
216    pub price: Price,
217    pub desired_quantity: UnderlyingAsset,
218    pub fill: Vec<Fill>,
219    pub timestamp: u128,
220    pub order_tx_history: Vec<OrderHistory>,
221    pub base_decimals: u64,
222}
223
224#[serde_as]
225#[derive(Default, serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
226pub struct OrderBookBalance {
227    #[serde_as(as = "DisplayFromStr")]
228    locked: u128,
229    #[serde_as(as = "DisplayFromStr")]
230    unlocked: u128,
231    #[serde_as(as = "DisplayFromStr")]
232    fee: u128,
233}
234
235impl OrderBookBalance {
236    pub fn locked(&self) -> u128 {
237        self.locked
238    }
239
240    pub fn unlocked(&self) -> u128 {
241        self.unlocked
242    }
243
244    pub fn fee(&self) -> u128 {
245        self.fee
246    }
247}
248
249pub type OrderBooksBalances = BTreeMap<ContractId, OrderBookBalance>;