use serde::{Deserialize as SerdeDeserialize, Deserializer, Serialize};
use std::borrow::Cow;
#[must_use]
pub fn sns_proposal_action_label(id: u64) -> Cow<'static, str> {
match id {
0 => Cow::Borrowed("unspecified"),
1 => Cow::Borrowed("motion"),
2 => Cow::Borrowed("manage_nervous_system_parameters"),
3 => Cow::Borrowed("upgrade_sns_controlled_canister"),
4 => Cow::Borrowed("add_generic_nervous_system_function"),
5 => Cow::Borrowed("remove_generic_nervous_system_function"),
6 => Cow::Borrowed("execute_generic_nervous_system_function"),
7 => Cow::Borrowed("upgrade_sns_to_next_version"),
8 => Cow::Borrowed("manage_sns_metadata"),
9 => Cow::Borrowed("transfer_sns_treasury_funds"),
10 => Cow::Borrowed("register_dapp_canisters"),
11 => Cow::Borrowed("deregister_dapp_canisters"),
12 => Cow::Borrowed("mint_sns_tokens"),
13 => Cow::Borrowed("manage_ledger_parameters"),
14 => Cow::Borrowed("manage_dapp_canister_settings"),
15 => Cow::Borrowed("advance_sns_target_version"),
16 => Cow::Borrowed("set_topics_for_custom_proposals"),
17 => Cow::Borrowed("register_extension"),
18 => Cow::Borrowed("execute_extension_operation"),
19 => Cow::Borrowed("upgrade_extension"),
id if id >= 1_000 => Cow::Owned(format!("generic:{id}")),
id => Cow::Owned(format!("unknown:{id}")),
}
}
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd, SerdeDeserialize, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum SnsProposalDecisionState {
Open,
Decided,
Executed,
Failed,
}
impl SnsProposalDecisionState {
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
Self::Open => "open",
Self::Decided => "decided",
Self::Executed => "executed",
Self::Failed => "failed",
}
}
}
#[derive(Clone, Debug, Eq, PartialEq, SerdeDeserialize, Serialize)]
#[serde(deny_unknown_fields)]
pub struct SnsProposalRow {
pub proposal_id: u64,
pub action_id: u64,
pub title: String,
pub summary: String,
pub url: Option<String>,
#[serde(deserialize_with = "deserialize_required_option")]
pub status: Option<i32>,
#[serde(deserialize_with = "deserialize_required_option")]
pub topic: Option<String>,
pub reject_cost_e8s: u64,
pub proposal_creation_timestamp_seconds: u64,
pub decided_timestamp_seconds: Option<u64>,
pub executed_timestamp_seconds: Option<u64>,
pub failed_timestamp_seconds: Option<u64>,
pub failure_reason: Option<SnsProposalFailureReason>,
pub reward_event_round: u64,
pub reward_event_end_timestamp_seconds: Option<u64>,
pub is_eligible_for_rewards: bool,
pub latest_tally: Option<SnsProposalTally>,
pub ballots: Vec<SnsProposalBallotRow>,
pub payload_text_rendering: Option<String>,
pub proposer_neuron_id: Option<String>,
}
impl SnsProposalRow {
#[must_use]
pub const fn decision_state(&self) -> SnsProposalDecisionState {
if matches!(self.failed_timestamp_seconds, Some(1..)) {
SnsProposalDecisionState::Failed
} else if matches!(self.executed_timestamp_seconds, Some(1..)) {
SnsProposalDecisionState::Executed
} else if matches!(self.decided_timestamp_seconds, Some(1..)) {
SnsProposalDecisionState::Decided
} else {
SnsProposalDecisionState::Open
}
}
#[must_use]
pub const fn ballot_count(&self) -> usize {
self.ballots.len()
}
}
fn deserialize_required_option<'de, D, T>(deserializer: D) -> Result<Option<T>, D::Error>
where
D: Deserializer<'de>,
T: SerdeDeserialize<'de>,
{
Option::<T>::deserialize(deserializer)
}
#[derive(Clone, Debug, Eq, PartialEq, SerdeDeserialize, Serialize)]
#[serde(deny_unknown_fields)]
pub struct SnsProposalBallotRow {
pub neuron_id: String,
pub vote: i32,
pub cast_timestamp_seconds: u64,
pub voting_power: u64,
}
#[derive(Clone, Debug, Eq, PartialEq, SerdeDeserialize, Serialize)]
pub struct SnsProposalFailureReason {
pub error_type: i32,
pub error_message: String,
}
#[derive(Clone, Debug, Eq, PartialEq, SerdeDeserialize, Serialize)]
pub struct SnsProposalTally {
pub timestamp_seconds: u64,
pub yes: u64,
pub no: u64,
pub total: u64,
}
#[cfg(test)]
mod tests;