1use std::time::SystemTime;
2
3use serde::{Deserialize, Serialize};
4use serde_with::{TimestampMilliSeconds, TimestampSeconds, serde_as};
5use strum::IntoStaticStr;
6use uuid::Uuid;
7
8use super::errors::ServerError;
9use super::ids::{
10 Balance, Decimals, MarketId, Nonce, OrderId, PositionType, Price, Quantity, QuoteCount,
11 RfqVersion, Strike, UserId,
12};
13
14#[derive(Debug, Clone, Serialize, Deserialize, IntoStaticStr)]
15#[serde(tag = "type", content = "data")]
16#[strum(serialize_all = "snake_case")]
17pub enum ServerMessage {
18 RfqCreated(RfqCreatedMessage),
19 RfqClosed(RfqClosedMessage),
20
21 QuoteAcknowledged(QuoteAcknowledgedMessage),
22 QuoteBestStatus(QuoteBestStatusMessage),
23 QuoteOutbid(QuoteOutbidMessage),
24 QuoteFilled(QuoteFilledMessage),
25 QuoteSelected(QuoteSelectedMessage),
26 QuoteCancelled(QuoteCancelledMessage),
27 QuoteRefreshRequested(QuoteRefreshRequestedMessage),
28 RfqAvailableAgain(RfqAvailableAgainMessage),
29
30 QuoteReceived(QuoteReceivedMessage),
31
32 ActiveRfqs(ActiveRfqsMessage),
33 MyQuotes(MyQuotesMessage),
34
35 OrderAccepted(OrderAcceptedMessage),
36 SponsoredTxToSign(SponsoredTxToSignMessage),
37 OrderSubmitted(OrderSubmittedMessage),
38 OrderConfirmed(OrderConfirmedMessage),
39 OrderFailed(OrderFailedMessage),
40
41 Pong(PongMessage),
42 Error(ServerError),
43}
44
45#[derive(Debug, Clone, Serialize, Deserialize)]
46pub struct RfqOrderOption {
47 pub strike: Strike,
48}
49
50#[serde_as]
51#[derive(Debug, Clone, Serialize, Deserialize)]
52pub struct ActiveRfqInfo {
53 pub rfq_id: Uuid,
54 pub market: MarketId,
55 pub position_type: PositionType,
56 pub strike: Strike,
57 pub quantity: Quantity,
58 #[serde_as(as = "TimestampSeconds<i64>")]
59 pub expires_at: SystemTime,
60 pub quotes_count: QuoteCount,
61 pub best_price: Option<Price>,
62 #[serde(default, skip_serializing_if = "Vec::is_empty")]
63 pub order_options: Vec<RfqOrderOption>,
64}
65
66#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
67#[serde(rename_all = "lowercase")]
68pub enum QuoteStatus {
69 Pending,
70 Best,
71 Outbid,
72 Filled,
73 Expired,
74}
75
76#[serde_as]
77#[derive(Debug, Clone, Serialize, Deserialize)]
78pub struct MakerQuoteInfo {
79 pub rfq_id: Uuid,
80 pub order_id: OrderId,
81 pub market: MarketId,
82 pub strike: Strike,
83 pub price: Price,
84 pub quantity: Quantity,
85 #[serde_as(as = "TimestampSeconds<i64>")]
86 pub valid_until: SystemTime,
87 pub status: QuoteStatus,
88 #[serde_as(as = "TimestampSeconds<i64>")]
89 pub created_at: SystemTime,
90}
91
92#[derive(Debug, Clone, Serialize, Deserialize)]
93pub struct MyQuotesMessage {
94 pub quotes: Vec<MakerQuoteInfo>,
95}
96
97#[serde_as]
98#[derive(Debug, Clone, Serialize, Deserialize)]
99pub struct RfqCreatedMessage {
100 pub rfq_id: Uuid,
101 #[serde(default)]
102 pub rfq_version: RfqVersion,
103 #[serde(default, skip_serializing_if = "Option::is_none")]
104 pub client_request_id: Option<Uuid>,
105 #[serde_as(as = "TimestampSeconds<i64>")]
106 pub expires_at: SystemTime,
107 #[serde_as(as = "TimestampSeconds<i64>")]
108 pub created_at: SystemTime,
109 #[serde(default, skip_serializing_if = "Vec::is_empty")]
110 pub order_options: Vec<RfqOrderOption>,
111}
112
113#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, IntoStaticStr)]
114#[serde(rename_all = "snake_case")]
115#[strum(serialize_all = "snake_case")]
116pub enum RfqCloseReason {
117 Expired,
118 TakerCancelled,
119 Filled,
120 MarketExpired,
121 LadderTimeout,
122}
123
124#[serde_as]
125#[derive(Debug, Clone, Serialize, Deserialize)]
126pub struct RfqClosedMessage {
127 pub rfq_id: Uuid,
128 #[serde(default)]
129 pub rfq_version: RfqVersion,
130 pub reason: RfqCloseReason,
131 #[serde(default, skip_serializing_if = "Option::is_none")]
132 pub your_quote: Option<RfqClosedYourQuote>,
133 #[serde(default, skip_serializing_if = "Option::is_none")]
134 pub winner: Option<RfqClosedWinner>,
135 #[serde_as(as = "TimestampSeconds<i64>")]
136 pub closed_at: SystemTime,
137}
138
139#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, IntoStaticStr)]
140#[serde(rename_all = "snake_case")]
141#[strum(serialize_all = "snake_case")]
142pub enum QuoteFinalStatus {
143 Expired,
144 Outbid,
145 Cancelled,
146 Filled,
147}
148
149#[derive(Debug, Clone, Serialize, Deserialize)]
150pub struct RfqClosedYourQuote {
151 pub order_id: OrderId,
152 pub status: QuoteFinalStatus,
153 pub price: Price,
154}
155
156#[derive(Debug, Clone, Serialize, Deserialize)]
157pub struct RfqClosedWinner {
158 pub maker: UserId,
159 pub price: Price,
160 #[serde(default, skip_serializing_if = "Option::is_none")]
161 pub tx_signature: Option<String>,
162}
163
164#[derive(Debug, Clone, Serialize, Deserialize)]
165pub struct QuoteAcknowledgedMessage {
166 pub rfq_id: Uuid,
167 pub order_id: OrderId,
168 #[serde(default, skip_serializing_if = "Option::is_none")]
169 pub replaced_order_id: Option<OrderId>,
170}
171
172#[derive(Debug, Clone, Serialize, Deserialize)]
173pub struct QuoteBestStatusMessage {
174 pub rfq_id: Uuid,
175 pub order_id: OrderId,
176 pub is_best: bool,
177 #[serde(default, skip_serializing_if = "Option::is_none")]
178 pub current_best_price: Option<Price>,
179}
180
181#[derive(Debug, Clone, Serialize, Deserialize)]
182pub struct QuoteOutbidMessage {
183 pub rfq_id: Uuid,
184 pub order_id: OrderId,
185 pub your_price: Price,
186 #[serde(default, skip_serializing_if = "Option::is_none")]
187 pub current_best_price: Option<Price>,
188}
189
190#[serde_as]
191#[derive(Debug, Clone, Serialize, Deserialize)]
192pub struct QuoteFilledMessage {
193 pub rfq_id: Uuid,
194 pub order_id: OrderId,
195 pub taker: UserId,
196 pub price: Price,
197 pub quantity: Quantity,
198 pub strike: Strike,
199 pub position_pda: String,
200 pub tx_signature: String,
201 #[serde_as(as = "TimestampSeconds<i64>")]
202 pub filled_at: SystemTime,
203}
204
205#[serde_as]
206#[derive(Debug, Clone, Serialize, Deserialize)]
207pub struct QuoteReceivedMessage {
208 pub rfq_id: Uuid,
209 pub strike: Strike,
210 pub maker: UserId,
211 pub price: Price,
212 #[serde_as(as = "TimestampSeconds<i64>")]
213 pub valid_until: SystemTime,
214 pub nonce: Nonce,
215 pub order_id: OrderId,
216}
217
218#[serde_as]
219#[derive(Debug, Clone, Serialize, Deserialize)]
220pub struct QuoteRefreshRequestedMessage {
221 pub rfq_id: Uuid,
222 pub strike: Strike,
223 #[serde_as(as = "TimestampSeconds<i64>")]
224 pub min_valid_until: SystemTime,
225 pub reason: String,
226}
227
228#[serde_as]
229#[derive(Debug, Clone, Serialize, Deserialize)]
230pub struct QuoteSelectedMessage {
231 pub rfq_id: Uuid,
232 pub order_id: OrderId,
233 pub taker: UserId,
234 pub price: Price,
235 pub quantity: Quantity,
236 pub strike: Strike,
237 #[serde_as(as = "TimestampSeconds<i64>")]
238 pub signature_deadline: SystemTime,
239}
240
241#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, IntoStaticStr)]
242#[serde(rename_all = "snake_case")]
243#[strum(serialize_all = "snake_case")]
244pub enum QuoteCancelReason {
245 Requested,
246 RiskCheck,
247 RfqAccepted,
248}
249
250#[serde_as]
251#[derive(Debug, Clone, Serialize, Deserialize)]
252pub struct QuoteCancelledMessage {
253 pub rfq_id: Uuid,
254 #[serde(default)]
255 pub order_ids: Vec<OrderId>,
256 pub reason: QuoteCancelReason,
257 #[serde_as(as = "TimestampSeconds<i64>")]
258 pub cancelled_at: SystemTime,
259}
260
261#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, IntoStaticStr)]
262#[serde(rename_all = "snake_case")]
263#[strum(serialize_all = "snake_case")]
264pub enum RfqAvailableAgainReason {
265 SignatureTimeout,
266 TxFailed,
267 TxBuildFailed,
268}
269
270impl std::fmt::Display for RfqAvailableAgainReason {
271 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
272 f.write_str(self.into())
273 }
274}
275
276#[serde_as]
277#[derive(Debug, Clone, Serialize, Deserialize)]
278pub struct RfqAvailableAgainMessage {
279 pub rfq_id: Uuid,
280 #[serde(default)]
281 pub rfq_version: RfqVersion,
282 pub reason: RfqAvailableAgainReason,
283 #[serde_as(as = "TimestampSeconds<i64>")]
284 pub available_again_at: SystemTime,
285}
286
287#[derive(Debug, Clone, Serialize, Deserialize)]
288pub struct ActiveRfqsMessage {
289 pub rfqs: Vec<ActiveRfqInfo>,
290}
291
292#[derive(Debug, Clone, Serialize, Deserialize)]
293pub struct OrderAcceptedMessage {
294 pub order_id: OrderId,
295}
296
297#[serde_as]
298#[derive(Debug, Clone, Serialize, Deserialize)]
299pub struct SponsoredTxToSignMessage {
300 pub order_id: OrderId,
301 pub tx_base64: String,
302 #[serde_as(as = "TimestampSeconds<i64>")]
303 pub signature_deadline: SystemTime,
304}
305
306#[derive(Debug, Clone, Serialize, Deserialize)]
307pub struct OrderSubmittedMessage {
308 pub order_id: OrderId,
309 pub tx_signature: String,
310}
311
312#[derive(Debug, Clone, Serialize, Deserialize)]
313pub struct OrderConfirmedMessage {
314 pub order_id: OrderId,
315 pub position_pda: String,
316 #[serde(default, skip_serializing_if = "Option::is_none")]
317 pub tx_signature: Option<String>,
318}
319
320#[derive(Debug, Clone, Serialize, Deserialize)]
321pub struct OrderFailedMessage {
322 pub order_id: OrderId,
323 pub reason: String,
324}
325
326#[serde_as]
327#[derive(Debug, Clone, Serialize, Deserialize)]
328pub struct PongMessage {
329 #[serde_as(as = "TimestampMilliSeconds<i64>")]
330 pub server_time_unix_ms: SystemTime,
331}
332
333#[derive(Debug, Clone, Serialize, Deserialize)]
339pub struct TokenCapInfo {
340 pub underlying_mint: String,
341 pub symbol: String,
342 pub current_oi: Quantity,
343 pub max_oi: Quantity,
344 pub utilization: f64,
345}
346
347#[derive(Debug, Clone, Serialize, Deserialize)]
349pub struct MarketCapInfo {
350 pub market_id: MarketId,
351 pub current_oi: Quantity,
352 pub max_oi: Quantity,
353 pub utilization: f64,
354}
355
356#[derive(Debug, Clone, Serialize, Deserialize)]
358pub struct MakerPositionCapInfo {
359 pub current: u32,
360 pub limit: u32,
361}
362
363#[derive(Debug, Clone, Serialize, Deserialize)]
365pub struct MakerNotionalCapInfo {
366 pub underlying_mint: String,
367 pub symbol: String,
368 pub current: Quantity,
369 pub limit: Quantity,
370}
371
372#[derive(Debug, Clone, Serialize, Deserialize)]
374pub struct MakerBalanceCapInfo {
375 pub mint: String,
376 pub symbol: String,
377 pub decimals: Decimals,
378 pub deposited: Balance,
379 pub committed: Balance,
380 pub available: Balance,
381}
382
383#[derive(Debug, Clone, Serialize, Deserialize)]
385pub struct QuoteCapInfo {
386 pub quote_mint: String,
387 pub symbol: String,
388 pub current_notional: Balance,
390 pub max_notional: Balance,
392 pub utilization: f64,
393}