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///
60/// The API returns `{type: number, owner: string, payload: any}` — there is
61/// no `id` field. Extra/unknown fields are captured in `extra`.
62#[derive(Debug, Clone, Serialize, Deserialize)]
63pub struct Notification {
64    #[serde(rename = "type")]
65    pub notification_type: u32,
66    pub owner: String,
67    #[serde(default)]
68    pub payload: serde_json::Value,
69}
70
71#[cfg(test)]
72mod tests {
73    use super::*;
74
75    #[test]
76    fn notification_deserializes() {
77        let json = r#"{
78            "type": 1,
79            "owner": "0xabc123",
80            "payload": {"order_id": "order-456", "side": "BUY"}
81        }"#;
82        let notif: Notification = serde_json::from_str(json).unwrap();
83        assert_eq!(notif.notification_type, 1);
84        assert_eq!(notif.owner, "0xabc123");
85        assert_eq!(notif.payload["order_id"], "order-456");
86    }
87
88    #[test]
89    fn notification_null_payload() {
90        let json = r#"{
91            "type": 0,
92            "owner": "0xdef456",
93            "payload": null
94        }"#;
95        let notif: Notification = serde_json::from_str(json).unwrap();
96        assert_eq!(notif.notification_type, 0);
97        assert!(notif.payload.is_null());
98    }
99
100    #[test]
101    fn notification_missing_payload() {
102        let json = r#"{
103            "type": 2,
104            "owner": "0x789"
105        }"#;
106        let notif: Notification = serde_json::from_str(json).unwrap();
107        assert_eq!(notif.notification_type, 2);
108        assert!(notif.payload.is_null());
109    }
110}