Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,6 @@ pub enum Error {
SignatureFailure(String),
#[error("Vault address not found")]
VaultAddressNotFound,
#[error("Subscription error: {0:?}")]
SubscriptionError(String),
}
4 changes: 2 additions & 2 deletions src/exchange/exchange_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ use crate::{
VaultTransfer, Withdraw3,
};

#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct ExchangeClient {
pub http_client: HttpClient,
pub wallet: PrivateKeySigner,
Expand Down Expand Up @@ -139,7 +139,7 @@ impl ExchangeClient {
})
}

async fn post(
pub async fn post(
&self,
action: serde_json::Value,
signature: Signature,
Expand Down
2 changes: 1 addition & 1 deletion src/info/info_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ pub enum InfoRequest {
},
}

#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct InfoClient {
pub http_client: HttpClient,
pub(crate) ws_manager: Option<WsManager>,
Expand Down
3 changes: 2 additions & 1 deletion src/info/sub_structs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,12 +108,13 @@ pub struct Vip {
pub ntl_cutoff: String,
}

#[derive(Deserialize, Debug)]
#[derive(Deserialize, Debug, Clone)]
#[serde(rename_all = "camelCase")]
pub struct UserTokenBalance {
pub coin: String,
pub hold: String,
pub total: String,
pub token: u32,
pub entry_ntl: String,
}

Expand Down
24 changes: 12 additions & 12 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
#![deny(unreachable_pub)]
mod consts;
mod eip712;
mod errors;
mod exchange;
mod helpers;
mod info;
mod market_maker;
mod meta;
mod prelude;
mod req;
mod signature;
mod ws;
pub mod consts;
pub mod eip712;
pub mod errors;
pub mod exchange;
pub mod helpers;
pub mod info;
pub mod market_maker;
pub mod meta;
pub mod prelude;
pub mod req;
pub mod signature;
pub mod ws;
pub use consts::{EPSILON, LOCAL_API_URL, MAINNET_API_URL, TESTNET_API_URL};
pub use eip712::Eip712;
pub use errors::Error;
Expand Down
26 changes: 21 additions & 5 deletions src/meta.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
use std::collections::HashMap;

use alloy::primitives::B128;
use serde::Deserialize;
use serde::{Deserialize, Serialize};

#[derive(Deserialize, Debug, Clone)]
pub struct Meta {
pub universe: Vec<AssetMeta>,
}

#[derive(Deserialize, Debug, Clone)]
#[derive(Deserialize, Debug, Clone, Serialize)]
pub struct SpotMeta {
pub universe: Vec<SpotAssetMeta>,
pub tokens: Vec<TokenInfo>,
Expand Down Expand Up @@ -52,14 +52,29 @@ pub enum SpotMetaAndAssetCtxs {
Context(Vec<SpotAssetContext>),
}

impl SpotMetaAndAssetCtxs {
pub fn get_spot_meta(&self) -> &SpotMeta {
match self {
SpotMetaAndAssetCtxs::SpotMeta(meta) => meta,
_ => panic!("Not a spot meta"),
}
}
pub fn get_context(&self) -> &Vec<SpotAssetContext> {
match self {
SpotMetaAndAssetCtxs::Context(ctxs) => ctxs,
_ => panic!("Not a context"),
}
}
}

#[derive(Deserialize, Debug, Clone)]
#[serde(untagged)]
pub enum MetaAndAssetCtxs {
Meta(Meta),
Context(Vec<AssetContext>),
}

#[derive(Deserialize, Debug, Clone)]
#[derive(Deserialize, Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct SpotAssetContext {
pub day_ntl_vlm: String,
Expand Down Expand Up @@ -94,7 +109,7 @@ pub struct AssetMeta {
pub only_isolated: Option<bool>,
}

#[derive(Deserialize, Debug, Clone)]
#[derive(Deserialize, Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct SpotAssetMeta {
pub tokens: [usize; 2],
Expand All @@ -103,7 +118,7 @@ pub struct SpotAssetMeta {
pub is_canonical: bool,
}

#[derive(Debug, Deserialize, Clone)]
#[derive(Debug, Deserialize, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct TokenInfo {
pub name: String,
Expand All @@ -112,4 +127,5 @@ pub struct TokenInfo {
pub index: usize,
pub token_id: B128,
pub is_canonical: bool,
pub full_name: Option<String>,
}
2 changes: 1 addition & 1 deletion src/req.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ struct ErrorData {
msg: String,
}

#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct HttpClient {
pub client: Client,
pub base_url: String,
Expand Down
6 changes: 6 additions & 0 deletions src/ws/message_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@ use serde::Deserialize;

use crate::ws::sub_structs::*;

#[derive(Deserialize, Clone, Debug)]
pub struct SubscriptionError {
pub data: String,
}

#[derive(Deserialize, Clone, Debug)]
pub struct Trades {
pub data: Vec<Trade>,
Expand Down Expand Up @@ -58,6 +63,7 @@ pub struct WebData2 {
}

#[derive(Deserialize, Clone, Debug)]
#[serde(rename_all = "camelCase")]
pub struct ActiveAssetCtx {
pub data: ActiveAssetCtxData,
}
Expand Down
29 changes: 20 additions & 9 deletions src/ws/ws_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,16 @@ use crate::{
WebData2,
};

use super::SubscriptionError;

#[derive(Debug)]
struct SubscriptionData {
sending_channel: UnboundedSender<Message>,
subscription_id: u32,
id: String,
}
#[derive(Debug)]

#[derive(Debug, Clone)]
pub(crate) struct WsManager {
stop_flag: Arc<AtomicBool>,
writer: Arc<Mutex<SplitSink<WebSocketStream<MaybeTlsStream<TcpStream>>, protocol::Message>>>,
Expand Down Expand Up @@ -92,6 +95,7 @@ pub enum Message {
ActiveAssetData(ActiveAssetData),
ActiveSpotAssetCtx(ActiveSpotAssetCtx),
Bbo(Bbo),
Error(SubscriptionError),
Pong,
}

Expand Down Expand Up @@ -296,6 +300,15 @@ impl WsManager {
Message::SubscriptionResponse | Message::Pong => Ok(String::default()),
Message::NoData => Ok("".to_string()),
Message::HyperliquidError(err) => Ok(format!("hyperliquid error: {err:?}")),
Message::Error(err) => {
let error_str = err.data.to_string();
let identifier = error_str
.split("Invalid subscription ")
.nth(1)
.unwrap_or("Invalid subscription")
.to_string();
Ok(identifier)
}
}
}

Expand All @@ -309,8 +322,10 @@ impl WsManager {
if !data.starts_with('{') {
return Ok(());
}

let message = serde_json::from_str::<Message>(&data)
.map_err(|e| Error::JsonParse(e.to_string()))?;

let identifier = WsManager::get_identifier(&message)?;
if identifier.is_empty() {
return Ok(());
Expand Down Expand Up @@ -411,15 +426,11 @@ impl WsManager {
) -> Result<u32> {
let mut subscriptions = self.subscriptions.lock().await;

let identifier_entry = if let Subscription::UserEvents { user: _ } =
serde_json::from_str::<Subscription>(&identifier)
.map_err(|e| Error::JsonParse(e.to_string()))?
{
let subscription = serde_json::from_str::<Subscription>(&identifier)
.map_err(|e| Error::JsonParse(e.to_string()))?;
let identifier_entry = if let Subscription::UserEvents { user: _ } = subscription {
"userEvents".to_string()
} else if let Subscription::OrderUpdates { user: _ } =
serde_json::from_str::<Subscription>(&identifier)
.map_err(|e| Error::JsonParse(e.to_string()))?
{
} else if let Subscription::OrderUpdates { user: _ } = subscription {
"orderUpdates".to_string()
} else {
identifier.clone()
Expand Down