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>;