Skip to main content

polyoxide_clob/api/
notifications.rs

1use polyoxide_core::HttpClient;
2use serde::{Deserialize, Serialize};
3
4use crate::{
5    account::{Credentials, Signer, Wallet},
6    error::ClobError,
7    request::{AuthMode, Request},
8};
9
10/// Notifications namespace for notification operations
11#[derive(Clone)]
12pub struct Notifications {
13    pub(crate) http_client: HttpClient,
14    pub(crate) wallet: Wallet,
15    pub(crate) credentials: Credentials,
16    pub(crate) signer: Signer,
17    pub(crate) chain_id: u64,
18}
19
20impl Notifications {
21    fn l2_auth(&self) -> AuthMode {
22        AuthMode::L2 {
23            address: self.wallet.address(),
24            credentials: self.credentials.clone(),
25            signer: self.signer.clone(),
26        }
27    }
28
29    /// List notifications for the current user
30    pub fn list(&self) -> Request<Vec<Notification>> {
31        Request::get(
32            self.http_client.clone(),
33            "/notifications",
34            self.l2_auth(),
35            self.chain_id,
36        )
37    }
38
39    /// Drop (dismiss) notifications by ID
40    pub async fn drop(&self, ids: impl Into<Vec<String>>) -> Result<serde_json::Value, ClobError> {
41        #[derive(Serialize)]
42        struct Body {
43            ids: Vec<String>,
44        }
45
46        Request::<serde_json::Value>::delete(
47            self.http_client.clone(),
48            "/notifications",
49            self.l2_auth(),
50            self.chain_id,
51        )
52        .body(&Body { ids: ids.into() })?
53        .send()
54        .await
55    }
56}
57
58/// A notification from the CLOB API.
59#[derive(Debug, Clone, Serialize, Deserialize)]
60pub struct Notification {
61    pub id: String,
62    #[serde(rename = "type")]
63    pub notification_type: u32,
64    pub owner: String,
65    #[serde(default)]
66    pub payload: serde_json::Value,
67    #[serde(default)]
68    pub timestamp: Option<String>,
69}
70
71#[cfg(test)]
72mod tests {
73    use super::*;
74
75    #[test]
76    fn notification_deserializes() {
77        let json = r#"{
78            "id": "notif-1",
79            "type": 1,
80            "owner": "0xabc123",
81            "payload": {"order_id": "order-456", "side": "BUY"},
82            "timestamp": "2024-01-01T00:00:00Z"
83        }"#;
84        let notif: Notification = serde_json::from_str(json).unwrap();
85        assert_eq!(notif.id, "notif-1");
86        assert_eq!(notif.notification_type, 1);
87        assert_eq!(notif.owner, "0xabc123");
88        assert_eq!(notif.payload["order_id"], "order-456");
89        assert_eq!(notif.timestamp.as_deref(), Some("2024-01-01T00:00:00Z"));
90    }
91
92    #[test]
93    fn notification_null_payload() {
94        let json = r#"{
95            "id": "notif-2",
96            "type": 0,
97            "owner": "0xdef456",
98            "payload": null
99        }"#;
100        let notif: Notification = serde_json::from_str(json).unwrap();
101        assert_eq!(notif.id, "notif-2");
102        assert_eq!(notif.notification_type, 0);
103        assert!(notif.payload.is_null());
104        assert!(notif.timestamp.is_none());
105    }
106
107    #[test]
108    fn notification_missing_payload() {
109        let json = r#"{
110            "id": "notif-3",
111            "type": 2,
112            "owner": "0x789"
113        }"#;
114        let notif: Notification = serde_json::from_str(json).unwrap();
115        assert_eq!(notif.id, "notif-3");
116        assert_eq!(notif.notification_type, 2);
117        assert!(notif.payload.is_null());
118    }
119}