Skip to main content

chio_link/
monitor.rs

1use serde::{Deserialize, Serialize};
2
3pub const CHIO_LINK_RUNTIME_REPORT_SCHEMA: &str = "chio.link.runtime-report.v1";
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
6#[serde(rename_all = "snake_case")]
7pub enum AlertSeverity {
8    Info,
9    Warning,
10    Critical,
11}
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
14#[serde(rename_all = "snake_case")]
15pub enum ChainHealthStatus {
16    Healthy,
17    Disabled,
18    Down,
19    Recovering,
20    Unavailable,
21    Unmonitored,
22}
23
24#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
25#[serde(rename_all = "snake_case")]
26pub enum PairHealthStatus {
27    Healthy,
28    FallbackActive,
29    DegradedGrace,
30    Paused,
31    Tripped,
32    Unavailable,
33}
34
35#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
36#[serde(rename_all = "camelCase")]
37pub struct OracleAlert {
38    pub code: String,
39    pub severity: AlertSeverity,
40    pub message: String,
41    #[serde(default, skip_serializing_if = "Option::is_none")]
42    pub pair: Option<String>,
43    #[serde(default, skip_serializing_if = "Option::is_none")]
44    pub chain_id: Option<u64>,
45    pub observed_at: u64,
46}
47
48#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
49#[serde(rename_all = "camelCase")]
50pub struct ChainHealthReport {
51    pub chain_id: u64,
52    pub label: String,
53    pub caip2: String,
54    pub enabled: bool,
55    pub status: ChainHealthStatus,
56    #[serde(default, skip_serializing_if = "Option::is_none")]
57    pub sequencer_uptime_feed: Option<String>,
58    #[serde(default, skip_serializing_if = "Option::is_none")]
59    pub checked_at: Option<u64>,
60    #[serde(default, skip_serializing_if = "Option::is_none")]
61    pub status_started_at: Option<u64>,
62    #[serde(default, skip_serializing_if = "Option::is_none")]
63    pub note: Option<String>,
64}
65
66#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
67#[serde(rename_all = "camelCase")]
68pub struct PairHealthReport {
69    pub pair: String,
70    pub chain_id: u64,
71    pub status: PairHealthStatus,
72    #[serde(default, skip_serializing_if = "Option::is_none")]
73    pub active_backend: Option<String>,
74    #[serde(default, skip_serializing_if = "Option::is_none")]
75    pub active_source: Option<String>,
76    #[serde(default, skip_serializing_if = "Option::is_none")]
77    pub feed_reference: Option<String>,
78    #[serde(default, skip_serializing_if = "Option::is_none")]
79    pub updated_at: Option<u64>,
80    #[serde(default, skip_serializing_if = "Option::is_none")]
81    pub cache_age_seconds: Option<u64>,
82    #[serde(default, skip_serializing_if = "Option::is_none")]
83    pub conversion_margin_bps: Option<u32>,
84    #[serde(default, skip_serializing_if = "Option::is_none")]
85    pub confidence_bps: Option<u32>,
86    #[serde(default, skip_serializing_if = "Option::is_none")]
87    pub note: Option<String>,
88    #[serde(default, skip_serializing_if = "Option::is_none")]
89    pub last_error: Option<String>,
90}
91
92#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
93#[serde(rename_all = "camelCase")]
94pub struct OracleRuntimeReport {
95    pub schema: String,
96    pub generated_at: u64,
97    pub global_pause: bool,
98    #[serde(default, skip_serializing_if = "Option::is_none")]
99    pub pause_reason: Option<String>,
100    pub chains: Vec<ChainHealthReport>,
101    pub pairs: Vec<PairHealthReport>,
102    pub alerts: Vec<OracleAlert>,
103}
104
105impl OracleRuntimeReport {
106    #[must_use]
107    pub fn new(generated_at: u64) -> Self {
108        Self {
109            schema: CHIO_LINK_RUNTIME_REPORT_SCHEMA.to_string(),
110            generated_at,
111            global_pause: false,
112            pause_reason: None,
113            chains: Vec::new(),
114            pairs: Vec::new(),
115            alerts: Vec::new(),
116        }
117    }
118}