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]
89#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
90#[serde(deny_unknown_fields)]
91pub struct SidecarConfig {
92 #[serde_as(as = "Option<HexDisplayFromStr>")]
94 pub contract_id: Option<ContractId>,
95 #[serde_as(as = "Option<HexDisplayFromStr>")]
97 pub blob_id: Option<ContractId>,
98 #[serde_as(as = "DisplayFromStr")]
100 pub maker_fee: u64,
101 #[serde_as(as = "DisplayFromStr")]
102 pub taker_fee: u64,
103}
104
105#[serde_as]
106#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize)]
107pub struct OrderBookConfig {
108 #[serde_as(as = "Option<HexDisplayFromStr>")]
109 pub contract_id: Option<ContractId>,
110 #[serde_as(as = "Option<HexDisplayFromStr>")]
111 pub blob_id: Option<ContractId>,
112 #[serde_as(as = "HexDisplayFromStr")]
113 pub market_id: MarketId,
114 #[serde_as(as = "DisplayFromStr")]
115 pub taker_fee: u64,
116 #[serde_as(as = "DisplayFromStr")]
117 pub maker_fee: u64,
118 #[serde_as(as = "DisplayFromStr")]
119 pub min_order: u64,
120 #[serde_as(as = "DisplayFromStr")]
121 pub dust: u64,
122 pub price_window: u8,
123 #[serde(default)]
127 pub allow_fractional_price: bool,
128 pub base: AssetConfig,
129 pub quote: AssetConfig,
130 #[serde(default, skip_serializing_if = "Vec::is_empty")]
132 pub house_identities: Vec<String>,
133 #[serde(default, skip_serializing_if = "Option::is_none")]
135 pub sidecar: Option<SidecarConfig>,
136}
137
138#[derive(
139 Default, Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize,
140)]
141pub struct Fill {
142 pub order_id: OrderId,
143 pub quantity: Quantity,
144 pub price: Price,
145 pub timestamp: u128,
146 pub fee: u64,
147}
148
149#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
150pub enum HistoryStep {
151 Confirmed { tx_id: TxId },
152}
153
154impl HistoryStep {
155 pub fn kind(&self) -> String {
156 match self {
157 HistoryStep::Confirmed { .. } => "confirmed".to_string(),
158 }
159 }
160}
161
162#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
163pub enum OrderHistory {
164 Created {
165 tx: HistoryStep,
166 },
167 Trade {
168 tx: HistoryStep,
169 trade_id: TradeId,
170 },
171 Canceled {
172 tx: HistoryStep,
173 reason: CancellationReason,
174 },
175}
176
177impl OrderHistory {
178 pub fn kind(&self) -> String {
179 match self {
180 OrderHistory::Created { .. } => "created".to_string(),
181 OrderHistory::Trade { .. } => "trade".to_string(),
182 OrderHistory::Canceled { .. } => "canceled".to_string(),
183 }
184 }
185
186 pub fn status_kind(&self) -> String {
187 match self {
188 OrderHistory::Created { tx } => tx.kind(),
189 OrderHistory::Trade { tx, .. } => tx.kind(),
190 OrderHistory::Canceled { tx, .. } => tx.kind(),
191 }
192 }
193
194 pub fn tx_id(&self) -> TxId {
195 match self {
196 OrderHistory::Created { tx } => match tx {
197 HistoryStep::Confirmed { tx_id } => *tx_id,
198 },
199 OrderHistory::Trade { tx, .. } => match tx {
200 HistoryStep::Confirmed { tx_id } => *tx_id,
201 },
202 OrderHistory::Canceled { tx, .. } => match tx {
203 HistoryStep::Confirmed { tx_id } => *tx_id,
204 },
205 }
206 }
207}
208
209#[derive(
210 Copy,
211 Clone,
212 Debug,
213 strum_macros::EnumCount,
214 strum_macros::IntoStaticStr,
215 strum_macros::FromRepr,
216 PartialEq,
217 Eq,
218 enum_iterator::Sequence,
219 Hash,
220)]
221#[repr(u8)]
222pub enum OrderStatus {
223 Active,
224 Canceled,
225 Filled,
226 PartiallyFilled,
227}
228
229impl TryFrom<u8> for OrderStatus {
230 type Error = anyhow::Error;
231
232 fn try_from(value: u8) -> Result<Self, Self::Error> {
233 OrderStatus::from_repr(value).ok_or_else(|| {
234 anyhow::anyhow!("Invalid value for OrderStatus enum: {}", value)
235 })
236 }
237}
238
239#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
240pub struct Order {
241 pub order_id: OrderId,
242 pub account: Identity,
243 pub side: Side,
244 pub order_type: OrderType,
245 pub price: Price,
246 pub desired_quantity: UnderlyingAsset,
247 pub fill: Vec<Fill>,
248 pub timestamp: u128,
249 pub order_tx_history: Vec<OrderHistory>,
250 pub base_decimals: u64,
251}
252
253#[serde_as]
254#[derive(Default, serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
255pub struct OrderBookBalance {
256 #[serde_as(as = "DisplayFromStr")]
257 locked: u128,
258 #[serde_as(as = "DisplayFromStr")]
259 unlocked: u128,
260 #[serde_as(as = "DisplayFromStr")]
261 fee: u128,
262}
263
264impl OrderBookBalance {
265 pub fn locked(&self) -> u128 {
266 self.locked
267 }
268
269 pub fn unlocked(&self) -> u128 {
270 self.unlocked
271 }
272
273 pub fn fee(&self) -> u128 {
274 self.fee
275 }
276}
277
278pub type OrderBooksBalances = BTreeMap<ContractId, OrderBookBalance>;