use alloy::primitives::Address;
use hyperliquid_sdk_rs::{providers::WsProvider, types::ws::Message, Network};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
rustls::crypto::aws_lc_rs::default_provider()
.install_default()
.expect("Failed to install crypto provider");
let user: Address = "0x1234567890123456789012345678901234567890".parse()?;
let mut ws = WsProvider::connect(Network::Mainnet).await?;
println!("Connected to Hyperliquid WebSocket");
println!("\n=== Phase 1 Subscriptions ===");
let (_btc_book_id, mut btc_book_rx) = ws.subscribe_l2_book("BTC").await?;
println!("Subscribed to BTC L2 book");
let (_mids_id, mut mids_rx) = ws.subscribe_all_mids().await?;
println!("Subscribed to all mids");
let (_trades_id, mut trades_rx) = ws.subscribe_trades("ETH").await?;
println!("Subscribed to ETH trades");
let (_bbo_id, mut bbo_rx) = ws.subscribe_bbo("SOL").await?;
println!("Subscribed to SOL BBO");
let (_open_orders_id, mut open_orders_rx) = ws.subscribe_open_orders(user).await?;
println!("Subscribed to open orders for user");
let (_clearinghouse_id, mut clearinghouse_rx) =
ws.subscribe_clearinghouse_state(user).await?;
println!("Subscribed to clearinghouse state for user");
println!("\n=== Phase 2 Subscriptions ===");
let (_twap_states_id, mut twap_states_rx) = ws.subscribe_twap_states(user).await?;
println!("Subscribed to TWAP states for user");
let (_web_data3_id, mut web_data3_rx) = ws.subscribe_web_data3(user).await?;
println!("Subscribed to webData3 for user");
let (_active_ctx_id, mut active_ctx_rx) =
ws.subscribe_active_asset_ctx("BTC").await?;
println!("Subscribed to active asset context for BTC");
let (_active_data_id, mut active_data_rx) =
ws.subscribe_active_asset_data(user, "ETH").await?;
println!("Subscribed to active asset data for ETH");
let (_twap_fills_id, mut twap_fills_rx) =
ws.subscribe_user_twap_slice_fills(user).await?;
println!("Subscribed to TWAP slice fills for user");
let (_twap_history_id, mut twap_history_rx) =
ws.subscribe_user_twap_history(user).await?;
println!("Subscribed to TWAP history for user");
ws.start_reading().await?;
let mut message_count = 0;
let timeout = tokio::time::sleep(std::time::Duration::from_secs(10));
tokio::pin!(timeout);
println!("\n=== Receiving messages ===");
loop {
tokio::select! {
Some(msg) = btc_book_rx.recv() => {
if let Message::L2Book(book) = msg {
println!("\n[L2Book] BTC book update:");
println!(" Coin: {}", book.data.coin);
println!(" Time: {}", book.data.time);
if let Some(bids) = book.data.levels.first() {
if let Some(best_bid) = bids.first() {
println!(" Best bid: {} @ {}", best_bid.sz, best_bid.px);
}
}
if let Some(asks) = book.data.levels.get(1) {
if let Some(best_ask) = asks.first() {
println!(" Best ask: {} @ {}", best_ask.sz, best_ask.px);
}
}
message_count += 1;
}
}
Some(msg) = mids_rx.recv() => {
if let Message::AllMids(mids) = msg {
println!("\n[AllMids] Mid prices update:");
for (coin, price) in mids.data.mids.iter().take(5) {
println!(" {}: {}", coin, price);
}
println!(" ... and {} more", mids.data.mids.len().saturating_sub(5));
message_count += 1;
}
}
Some(msg) = trades_rx.recv() => {
if let Message::Trades(trades) = msg {
println!("\n[Trades] Trade update:");
for trade in trades.data.iter().take(3) {
println!(" {} {} @ {} ({})",
trade.side, trade.sz, trade.px, trade.time);
}
message_count += 1;
}
}
Some(msg) = bbo_rx.recv() => {
if let Message::Bbo(bbo) = msg {
println!("\n[BBO] Best bid/offer for {}:", bbo.data.coin);
println!(" Bid: {} @ {}", bbo.data.bbo.bid.sz, bbo.data.bbo.bid.px);
println!(" Ask: {} @ {}", bbo.data.bbo.ask.sz, bbo.data.bbo.ask.px);
message_count += 1;
}
}
Some(msg) = open_orders_rx.recv() => {
if let Message::OpenOrders(orders) = msg {
println!("\n[OpenOrders] Open orders update:");
println!(" {} orders", orders.data.orders.len());
for order in orders.data.orders.iter().take(3) {
println!(" {:?}", order);
}
message_count += 1;
}
}
Some(msg) = clearinghouse_rx.recv() => {
if let Message::ClearinghouseState(state) = msg {
println!("\n[ClearinghouseState] State update:");
println!(" {:?}", state.data);
message_count += 1;
}
}
Some(msg) = twap_states_rx.recv() => {
if let Message::TwapStates(states) = msg {
println!("\n[TwapStates] TWAP states update:");
println!(" {} active TWAP orders", states.data.twap_states.len());
for state in states.data.twap_states.iter().take(3) {
println!(" {:?}", state);
}
message_count += 1;
}
}
Some(msg) = web_data3_rx.recv() => {
if let Message::WebData3(data) = msg {
println!("\n[WebData3] Aggregate user data update:");
println!(" {:?}", data.data);
message_count += 1;
}
}
Some(msg) = active_ctx_rx.recv() => {
if let Message::ActiveAssetCtx(ctx) = msg {
println!("\n[ActiveAssetCtx] Asset context update:");
println!(" {:?}", ctx.data);
message_count += 1;
}
}
Some(msg) = active_data_rx.recv() => {
if let Message::ActiveAssetData(data) = msg {
println!("\n[ActiveAssetData] Asset data update:");
println!(" {:?}", data.data);
message_count += 1;
}
}
Some(msg) = twap_fills_rx.recv() => {
if let Message::UserTwapSliceFills(fills) = msg {
println!("\n[UserTwapSliceFills] TWAP fills update:");
println!(" {} fills", fills.data.twap_slice_fills.len());
for fill in fills.data.twap_slice_fills.iter().take(3) {
println!(" {:?}", fill);
}
message_count += 1;
}
}
Some(msg) = twap_history_rx.recv() => {
if let Message::UserTwapHistory(history) = msg {
println!("\n[UserTwapHistory] TWAP history update:");
println!(" {} entries", history.data.twap_history.len());
for entry in history.data.twap_history.iter().take(3) {
println!(" {:?}", entry);
}
message_count += 1;
}
}
_ = &mut timeout => {
println!("\n\nDemo timeout reached after 10 seconds");
break;
}
else => {
println!("\nAll channels closed, exiting");
break;
}
}
if message_count >= 20 {
println!("\n\nReceived {} messages, exiting demo", message_count);
break;
}
}
println!("\n=== WebSocket demo completed ===");
println!("\nPhase 1 subscriptions demonstrated:");
println!(" - L2 order book (subscribe_l2_book)");
println!(" - All mid prices (subscribe_all_mids)");
println!(" - Trades (subscribe_trades)");
println!(" - Best bid/offer (subscribe_bbo)");
println!(" - Open orders (subscribe_open_orders)");
println!(" - Clearinghouse state (subscribe_clearinghouse_state)");
println!("\nPhase 2 subscriptions demonstrated:");
println!(" - TWAP states (subscribe_twap_states)");
println!(" - WebData3 (subscribe_web_data3)");
println!(" - Active asset context (subscribe_active_asset_ctx)");
println!(" - Active asset data (subscribe_active_asset_data)");
println!(" - TWAP slice fills (subscribe_user_twap_slice_fills)");
println!(" - TWAP history (subscribe_user_twap_history)");
Ok(())
}