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}