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    /// Whether prices that would truncate quote coins are allowed. When `false`
106    /// (the default), order/trigger creation rejects truncating prices and
107    /// activations floor `exec_quantity` to the largest non-truncating amount.
108    #[serde(default)]
109    pub allow_fractional_price: bool,
110    pub base: AssetConfig,
111    pub quote: AssetConfig,
112}
113
114#[derive(
115    Default, Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize,
116)]
117pub struct Fill {
118    pub order_id: OrderId,
119    pub quantity: Quantity,
120    pub price: Price,
121    pub timestamp: u128,
122    pub fee: u64,
123}
124
125#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
126pub enum HistoryStep {
127    Confirmed { tx_id: TxId },
128}
129
130impl HistoryStep {
131    pub fn kind(&self) -> String {
132        match self {
133            HistoryStep::Confirmed { .. } => "confirmed".to_string(),
134        }
135    }
136}
137
138#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
139pub enum OrderHistory {
140    Created {
141        tx: HistoryStep,
142    },
143    Trade {
144        tx: HistoryStep,
145        trade_id: TradeId,
146    },
147    Canceled {
148        tx: HistoryStep,
149        reason: CancellationReason,
150    },
151}
152
153impl OrderHistory {
154    pub fn kind(&self) -> String {
155        match self {
156            OrderHistory::Created { .. } => "created".to_string(),
157            OrderHistory::Trade { .. } => "trade".to_string(),
158            OrderHistory::Canceled { .. } => "canceled".to_string(),
159        }
160    }
161
162    pub fn status_kind(&self) -> String {
163        match self {
164            OrderHistory::Created { tx } => tx.kind(),
165            OrderHistory::Trade { tx, .. } => tx.kind(),
166            OrderHistory::Canceled { tx, .. } => tx.kind(),
167        }
168    }
169
170    pub fn tx_id(&self) -> TxId {
171        match self {
172            OrderHistory::Created { tx } => match tx {
173                HistoryStep::Confirmed { tx_id } => *tx_id,
174            },
175            OrderHistory::Trade { tx, .. } => match tx {
176                HistoryStep::Confirmed { tx_id } => *tx_id,
177            },
178            OrderHistory::Canceled { tx, .. } => match tx {
179                HistoryStep::Confirmed { tx_id } => *tx_id,
180            },
181        }
182    }
183}
184
185#[derive(
186    Copy,
187    Clone,
188    Debug,
189    strum_macros::EnumCount,
190    strum_macros::IntoStaticStr,
191    strum_macros::FromRepr,
192    PartialEq,
193    Eq,
194    enum_iterator::Sequence,
195    Hash,
196)]
197#[repr(u8)]
198pub enum OrderStatus {
199    Active,
200    Canceled,
201    Filled,
202    PartiallyFilled,
203}
204
205impl TryFrom<u8> for OrderStatus {
206    type Error = anyhow::Error;
207
208    fn try_from(value: u8) -> Result<Self, Self::Error> {
209        OrderStatus::from_repr(value).ok_or_else(|| {
210            anyhow::anyhow!("Invalid value for OrderStatus enum: {}", value)
211        })
212    }
213}
214
215#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
216pub struct Order {
217    pub order_id: OrderId,
218    pub account: Identity,
219    pub side: Side,
220    pub order_type: OrderType,
221    pub price: Price,
222    pub desired_quantity: UnderlyingAsset,
223    pub fill: Vec<Fill>,
224    pub timestamp: u128,
225    pub order_tx_history: Vec<OrderHistory>,
226    pub base_decimals: u64,
227}
228
229#[serde_as]
230#[derive(Default, serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
231pub struct OrderBookBalance {
232    #[serde_as(as = "DisplayFromStr")]
233    locked: u128,
234    #[serde_as(as = "DisplayFromStr")]
235    unlocked: u128,
236    #[serde_as(as = "DisplayFromStr")]
237    fee: u128,
238}
239
240impl OrderBookBalance {
241    pub fn locked(&self) -> u128 {
242        self.locked
243    }
244
245    pub fn unlocked(&self) -> u128 {
246        self.unlocked
247    }
248
249    pub fn fee(&self) -> u128 {
250        self.fee
251    }
252}
253
254pub type OrderBooksBalances = BTreeMap<ContractId, OrderBookBalance>;