Skip to main content

df_hyperliquid_core/live/account/
events.rs

1//! `userEvents`, on the channel `user`: one kind of event a frame, a fill, a funding payment, a
2//! liquidation, the venue's cancels or a TWAP's progress. A kind this build does not read is kept
3//! as written.
4
5use std::fmt;
6
7use crate::account::TwapSliceFill;
8use crate::account::history::Fill;
9use crate::live::{Funding, TwapEvent};
10use crate::utils::{Address, Dec};
11use serde::{Deserialize, Deserializer, de};
12use serde_json::value::RawValue;
13
14/// `userEvents`, on the channel `user`: one kind of event a frame.
15#[derive(Debug, Clone, PartialEq, Eq)]
16pub enum UserEvent {
17    Fills(Vec<Fill>),
18    Funding(Funding),
19    Liquidation(Liquidation),
20    /// Orders the venue canceled, not the account.
21    NonUserCancel(Vec<Cancel>),
22    TwapHistory(Vec<TwapEvent>),
23    TwapSliceFills(Vec<TwapSliceFill>),
24    /// A kind this build does not read: its key, and its value as written.
25    Other {
26        key: String,
27        data: String,
28    },
29}
30
31impl<'de> Deserialize<'de> for UserEvent {
32    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
33        struct Event;
34
35        impl<'de> de::Visitor<'de> for Event {
36            type Value = UserEvent;
37
38            fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
39                f.write_str("an object with one event in it")
40            }
41
42            fn visit_map<A: de::MapAccess<'de>>(self, mut map: A) -> Result<UserEvent, A::Error> {
43                let key: String = map.next_key()?.ok_or_else(|| de::Error::custom("an event with nothing in it"))?;
44                let event = match key.as_str() {
45                    "fills" => UserEvent::Fills(map.next_value()?),
46                    "funding" => UserEvent::Funding(map.next_value()?),
47                    "liquidation" => UserEvent::Liquidation(map.next_value()?),
48                    "nonUserCancel" => UserEvent::NonUserCancel(map.next_value()?),
49                    "twapHistory" => UserEvent::TwapHistory(map.next_value()?),
50                    "twapSliceFills" => UserEvent::TwapSliceFills(map.next_value()?),
51                    _ => {
52                        let data: Box<RawValue> = map.next_value()?;
53                        UserEvent::Other { key, data: data.get().to_owned() }
54                    }
55                };
56                if map.next_key::<de::IgnoredAny>()?.is_some() {
57                    return Err(de::Error::custom("more than one event in a frame"));
58                }
59                Ok(event)
60            }
61        }
62
63        deserializer.deserialize_map(Event)
64    }
65}
66
67/// A liquidation the account took part in. The venue writes these keys in snake case.
68#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
69pub struct Liquidation {
70    pub lid: u64,
71    pub liquidator: Address,
72    pub liquidated_user: Address,
73    pub liquidated_ntl_pos: Dec,
74    pub liquidated_account_value: Dec,
75}
76
77/// An order the venue canceled.
78#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
79pub struct Cancel {
80    pub coin: String,
81    pub oid: u64,
82}
83
84#[cfg(test)]
85#[path = "tests/events.rs"]
86mod tests;