Skip to main content

ic_query/sns/report/model/reports/
swap.rs

1//! Module: sns::report::model::reports::swap
2//!
3//! Responsibility: SNS decentralization-swap report DTOs.
4//! Does not own: swap canister calls, source validation, lookup, or rendering.
5//! Boundary: preserves native swap lifecycle, sale parameters, derived state, and query gaps.
6
7use super::invocation::SnsCanisterMethod;
8use serde::Serialize;
9
10///
11/// MainnetSnsSwap
12///
13/// Source-layer result from the three bounded native swap queries for one SNS.
14///
15
16#[derive(Clone, Debug, PartialEq, Serialize)]
17pub struct MainnetSnsSwap {
18    /// Swap canister identity queried by the source.
19    pub swap_canister_id: String,
20    /// Native lifecycle query method.
21    pub lifecycle_method: SnsCanisterMethod,
22    /// Native sale-parameters query method.
23    pub sale_parameters_method: SnsCanisterMethod,
24    /// Native derived-state query method.
25    pub derived_state_method: SnsCanisterMethod,
26    /// Whether the source can prove one point-in-time snapshot across all queries.
27    pub point_in_time_guaranteed: bool,
28    /// Lifecycle response, absent only when represented by a matching gap.
29    pub lifecycle: Option<SnsSwapLifecycle>,
30    /// Sale parameters, or `None` for either a matching gap or a successful empty response.
31    pub sale_parameters: Option<SnsSwapSaleParameters>,
32    /// Derived-state response, absent only when represented by a matching gap.
33    pub derived_state: Option<SnsSwapDerivedState>,
34    /// Component query failures retained by the source.
35    pub gaps: Vec<SnsSwapQueryGap>,
36}
37
38///
39/// SnsSwapComponent
40///
41/// Native swap query component represented by a report value or typed gap.
42///
43
44#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd, Serialize)]
45#[serde(rename_all = "snake_case")]
46pub enum SnsSwapComponent {
47    /// Swap lifecycle state and lifecycle timestamps.
48    Lifecycle,
49    /// Decentralization-sale parameters.
50    SaleParameters,
51    /// Participation totals and derived token rate.
52    DerivedState,
53}
54
55impl SnsSwapComponent {
56    /// Return the stable lowercase component label used in text reports.
57    #[must_use]
58    pub const fn as_str(self) -> &'static str {
59        match self {
60            Self::Lifecycle => "lifecycle",
61            Self::SaleParameters => "sale_parameters",
62            Self::DerivedState => "derived_state",
63        }
64    }
65}
66
67///
68/// SnsSwapQueryGap
69///
70/// One swap query that failed while the other bounded components were retained.
71///
72
73#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
74pub struct SnsSwapQueryGap {
75    /// Typed swap component whose query failed.
76    pub component: SnsSwapComponent,
77    /// Native query method that failed.
78    pub method: SnsCanisterMethod,
79    /// Transport, encoding, or decoding failure retained for diagnostics.
80    pub reason: String,
81}
82
83///
84/// SnsSwapLifecycle
85///
86/// Raw lifecycle code and timestamps returned by the SNS swap canister.
87///
88
89#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
90pub struct SnsSwapLifecycle {
91    /// Optional native lifecycle numeric discriminant.
92    pub lifecycle: Option<i32>,
93    /// Timestamp at which the decentralization sale opened, when returned.
94    pub decentralization_sale_open_timestamp_seconds: Option<u64>,
95    /// Timestamp at which the decentralization swap terminated, when returned.
96    pub decentralization_swap_termination_timestamp_seconds: Option<u64>,
97}
98
99///
100/// SnsSwapNeuronBasketConstructionParameters
101///
102/// Native neuron-basket construction parameters returned by the swap canister.
103///
104
105#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
106pub struct SnsSwapNeuronBasketConstructionParameters {
107    /// Number of neurons created in each participant basket.
108    pub count: u64,
109    /// Dissolve-delay interval between neurons in a basket, in seconds.
110    pub dissolve_delay_interval_seconds: u64,
111}
112
113///
114/// SnsSwapSaleParameters
115///
116/// Native decentralization-sale parameters returned by the swap canister.
117///
118
119#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
120pub struct SnsSwapSaleParameters {
121    /// Minimum legacy total ICP target in e8s.
122    pub min_icp_e8s: u64,
123    /// Maximum legacy total ICP target in e8s.
124    pub max_icp_e8s: u64,
125    /// Minimum direct participation target in ICP e8s, when returned.
126    pub min_direct_participation_icp_e8s: Option<u64>,
127    /// Maximum direct participation target in ICP e8s, when returned.
128    pub max_direct_participation_icp_e8s: Option<u64>,
129    /// SNS tokens offered by the sale in e8s.
130    pub sns_token_e8s: u64,
131    /// Minimum number of direct participants.
132    pub min_participants: u32,
133    /// Minimum ICP contribution per participant in e8s.
134    pub min_participant_icp_e8s: u64,
135    /// Maximum ICP contribution per participant in e8s.
136    pub max_participant_icp_e8s: u64,
137    /// Scheduled swap deadline in Unix seconds.
138    pub swap_due_timestamp_seconds: u64,
139    /// Optional delay before the sale opens, in seconds.
140    pub sale_delay_seconds: Option<u64>,
141    /// Neuron-basket construction parameters, when configured.
142    pub neuron_basket_construction_parameters: Option<SnsSwapNeuronBasketConstructionParameters>,
143}
144
145///
146/// SnsSwapDerivedState
147///
148/// Native aggregate participation values returned by the swap canister.
149///
150
151#[derive(Clone, Debug, PartialEq, Serialize)]
152pub struct SnsSwapDerivedState {
153    /// Derived SNS-token amount per ICP, when returned.
154    pub sns_tokens_per_icp: Option<f64>,
155    /// Total buyer ICP in e8s, when returned.
156    pub buyer_total_icp_e8s: Option<u64>,
157    /// Direct-participation ICP in e8s, when returned.
158    pub direct_participation_icp_e8s: Option<u64>,
159    /// Neurons' Fund participation ICP in e8s, when returned.
160    pub neurons_fund_participation_icp_e8s: Option<u64>,
161    /// Number of direct participants, when returned.
162    pub direct_participant_count: Option<u64>,
163    /// Number of Community Fund participants, when returned by older swap state.
164    pub cf_participant_count: Option<u64>,
165    /// Number of Community Fund neurons, when returned by older swap state.
166    pub cf_neuron_count: Option<u64>,
167}
168
169///
170/// SnsSwapReport
171///
172/// Bounded live report for one resolved SNS decentralization swap.
173///
174
175#[derive(Clone, Debug, PartialEq, Serialize)]
176pub struct SnsSwapReport {
177    /// Report schema version.
178    pub schema_version: u32,
179    /// Shared record, flattened in JSON.
180    #[serde(flatten)]
181    pub context: crate::sns::SnsInstanceContext,
182    /// Fixed number of bounded swap component queries attempted.
183    pub component_query_count: usize,
184    /// Number of component queries that returned successfully.
185    pub successful_component_query_count: usize,
186    /// Number of typed component query gaps.
187    pub component_gap_count: usize,
188
189    /// Validated source payload shared with native collection.
190    #[serde(flatten)]
191    pub swap: MainnetSnsSwap,
192}
193
194pub(in crate::sns::report) const fn sns_swap_lifecycle_name(
195    lifecycle: Option<i32>,
196) -> Option<&'static str> {
197    match lifecycle {
198        None => None,
199        Some(0) => Some("unspecified"),
200        Some(1) => Some("pending"),
201        Some(2) => Some("open"),
202        Some(3) => Some("committed"),
203        Some(4) => Some("aborted"),
204        Some(5) => Some("adopted"),
205        Some(_) => Some("unknown"),
206    }
207}
208
209#[cfg(test)]
210mod tests {
211    use super::sns_swap_lifecycle_name;
212
213    #[test]
214    fn lifecycle_names_preserve_native_codes_and_unknown_values() {
215        for (code, expected) in [
216            (None, None),
217            (Some(0), Some("unspecified")),
218            (Some(1), Some("pending")),
219            (Some(2), Some("open")),
220            (Some(3), Some("committed")),
221            (Some(4), Some("aborted")),
222            (Some(5), Some("adopted")),
223            (Some(99), Some("unknown")),
224        ] {
225            assert_eq!(sns_swap_lifecycle_name(code), expected);
226        }
227    }
228}