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}