ic_query/sns/report/model/reports/proposals/
row.rs1use serde::{Deserialize as SerdeDeserialize, Deserializer, Serialize};
8
9#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd, SerdeDeserialize, Serialize)]
16#[serde(rename_all = "snake_case")]
17pub enum SnsProposalDecisionState {
18 Open,
20 Decided,
22 Executed,
24 Failed,
26}
27
28impl SnsProposalDecisionState {
29 #[must_use]
31 pub const fn as_str(self) -> &'static str {
32 match self {
33 Self::Open => "open",
34 Self::Decided => "decided",
35 Self::Executed => "executed",
36 Self::Failed => "failed",
37 }
38 }
39}
40
41#[derive(Clone, Debug, Eq, PartialEq, SerdeDeserialize, Serialize)]
48pub struct SnsProposalRow {
49 pub proposal_id: u64,
50 pub action_id: u64,
51 pub action: String,
52 pub title: String,
53 pub summary: String,
54 pub url: Option<String>,
55 pub decision_state: SnsProposalDecisionState,
56 #[serde(deserialize_with = "deserialize_required_option")]
57 pub status: Option<i32>,
58 #[serde(deserialize_with = "deserialize_required_option")]
59 pub topic: Option<String>,
60 pub reject_cost_e8s: u64,
61 pub proposal_creation_timestamp_seconds: u64,
62 pub created_at: String,
63 pub decided_timestamp_seconds: Option<u64>,
64 pub decided_at: Option<String>,
65 pub executed_timestamp_seconds: Option<u64>,
66 pub executed_at: Option<String>,
67 pub failed_timestamp_seconds: Option<u64>,
68 pub failed_at: Option<String>,
69 pub failure_reason: Option<SnsProposalFailureReason>,
70 pub reward_event_round: u64,
71 pub reward_event_end_timestamp_seconds: Option<u64>,
72 pub is_eligible_for_rewards: bool,
73 pub latest_tally: Option<SnsProposalTally>,
74 pub ballot_count: usize,
75 pub ballots: Vec<SnsProposalBallotRow>,
76 pub payload_text_rendering: Option<String>,
77 pub proposer_neuron_id: Option<String>,
78}
79
80fn deserialize_required_option<'de, D, T>(deserializer: D) -> Result<Option<T>, D::Error>
81where
82 D: Deserializer<'de>,
83 T: SerdeDeserialize<'de>,
84{
85 Option::<T>::deserialize(deserializer)
86}
87
88#[derive(Clone, Debug, Eq, PartialEq, SerdeDeserialize, Serialize)]
95pub struct SnsProposalBallotRow {
96 pub neuron_id: String,
97 pub vote: i32,
98 pub vote_text: String,
99 pub cast_timestamp_seconds: u64,
100 pub cast_at: Option<String>,
101 pub voting_power: u64,
102}
103
104#[derive(Clone, Debug, Eq, PartialEq, SerdeDeserialize, Serialize)]
111pub struct SnsProposalFailureReason {
112 pub error_type: i32,
113 pub error_message: String,
114}
115
116#[derive(Clone, Debug, Eq, PartialEq, SerdeDeserialize, Serialize)]
123pub struct SnsProposalTally {
124 pub timestamp_seconds: u64,
125 pub yes: u64,
126 pub no: u64,
127 pub total: u64,
128}
129
130#[cfg(test)]
131mod tests {
132 use super::*;
133
134 #[test]
135 fn proposal_decision_state_labels_round_trip() {
136 for (state, label) in [
137 (SnsProposalDecisionState::Open, "open"),
138 (SnsProposalDecisionState::Decided, "decided"),
139 (SnsProposalDecisionState::Executed, "executed"),
140 (SnsProposalDecisionState::Failed, "failed"),
141 ] {
142 assert_eq!(
143 serde_json::to_string(&state).unwrap(),
144 format!("\"{label}\"")
145 );
146 assert_eq!(
147 serde_json::from_str::<SnsProposalDecisionState>(&format!("\"{label}\"")).unwrap(),
148 state
149 );
150 }
151 assert!(serde_json::from_str::<SnsProposalDecisionState>("\"unknown\"").is_err());
152 }
153}