use serde::{Deserialize, Serialize};
use crate::types::{MarketId, VaultId};
use crate::wallet::Address;
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum Subscription {
L2Book {
market_id: MarketId,
},
Trades {
market_id: MarketId,
},
Bbo {
market_id: MarketId,
},
UserFills {
address: Address,
},
UserState {
address: Address,
},
VaultNav {
vault_id: VaultId,
},
Rfq {
market_id: MarketId,
},
FbaBatch {
market_id: MarketId,
},
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(tag = "channel", content = "data", rename_all = "snake_case")]
pub enum WsMessage {
SubscriptionResponse {
method: String,
subscription: Subscription,
},
Error {
message: String,
},
L2Book(serde_json::Value),
Trades(serde_json::Value),
Bbo(serde_json::Value),
UserFills(serde_json::Value),
UserState(serde_json::Value),
VaultNav(serde_json::Value),
Rfq(serde_json::Value),
FbaBatch(serde_json::Value),
Pong(serde_json::Value),
#[serde(other)]
Unknown,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn subscription_l2_book_serializes_snake_case() {
let s = Subscription::L2Book {
market_id: MarketId(1),
};
let j = serde_json::to_value(&s).unwrap();
assert_eq!(j["type"], "l2_book");
assert_eq!(j["market_id"], 1);
}
#[test]
fn subscription_user_fills_uses_address() {
let s = Subscription::UserFills {
address: Address::ZERO,
};
let j = serde_json::to_value(&s).unwrap();
assert_eq!(j["type"], "user_fills");
assert!(j["address"].is_string());
}
#[test]
fn ws_message_decodes_subscription_response() {
let raw = serde_json::json!({
"channel": "subscription_response",
"data": {
"method": "subscribe",
"subscription": { "type": "l2_book", "market_id": 1 }
}
});
let m: WsMessage = serde_json::from_value(raw).unwrap();
match m {
WsMessage::SubscriptionResponse {
method,
subscription,
} => {
assert_eq!(method, "subscribe");
assert!(matches!(subscription, Subscription::L2Book { .. }));
}
other => panic!("expected SubscriptionResponse, got {other:?}"),
}
}
#[test]
fn ws_message_decodes_error() {
let raw = serde_json::json!({ "channel": "error", "data": { "message": "bad channel" } });
let m: WsMessage = serde_json::from_value(raw).unwrap();
match m {
WsMessage::Error { message } => assert_eq!(message, "bad channel"),
other => panic!("expected Error, got {other:?}"),
}
}
}