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