ic_query/icrc/model/contracts/reports/account_history.rs
1//! Module: icrc::model::contracts::reports::account_history
2//!
3//! Responsibility: serialized ICRC account-history page, cache, and row contracts.
4//! Does not own: ledger-wide history, requests, live transport, cache mechanics, or rendering.
5//! Boundary: owns the stable JSON and persisted snapshot shapes for indexed account history.
6
7use crate::cache::{CacheCollectionCompleteness, CacheValidationStatus};
8use serde::{Deserialize as SerdeDeserialize, Serialize};
9use serde_json::Value as JsonValue;
10
11///
12/// IcrcAccountTransactionPageData
13///
14/// Source-layer account-history page returned by an ICRC index canister.
15///
16
17#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
18pub struct IcrcAccountTransactionPageData {
19 /// Index canister that answered the query.
20 pub index_canister_id: String,
21 /// Account balance reported by the index.
22 pub balance: String,
23 /// Oldest transaction id known for the account.
24 pub oldest_transaction_id: Option<String>,
25 /// Cursor for requesting the next older page.
26 pub next_start: Option<String>,
27 /// Ledger token symbol.
28 pub token_symbol: String,
29 /// Ledger token decimals.
30 pub decimals: u8,
31 /// Account transactions in index response order.
32 pub transactions: Vec<IcrcAccountTransactionRow>,
33}
34
35///
36/// IcrcAccountTransactionPageReport
37///
38/// Serializable report for a backward page of ICRC index account transactions.
39///
40
41#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
42pub struct IcrcAccountTransactionPageReport {
43 /// Shared record, flattened in serialized output.
44 #[serde(flatten)]
45 pub provenance: super::IcrcReportProvenance,
46 /// Queried account owner principal.
47 pub account_owner: String,
48 /// Queried subaccount as normalized hex.
49 pub subaccount_hex: Option<String>,
50 /// Exclusive block-index cursor supplied by the caller.
51 pub requested_start: Option<String>,
52 /// Maximum number of transactions requested.
53 pub requested_limit: u32,
54 /// Validated index response and ledger display metadata.
55 #[serde(flatten)]
56 pub page: IcrcAccountTransactionPageData,
57}
58
59///
60/// IcrcAccountTransactionContext
61///
62/// Collected account identity and acquisition metadata shared by complete-history views.
63///
64
65#[derive(Clone, Debug, Eq, PartialEq, SerdeDeserialize, Serialize)]
66pub struct IcrcAccountTransactionContext {
67 /// Ledger canister whose history was collected.
68 pub ledger_canister_id: String,
69 /// Verified index canister used for every page.
70 pub index_canister_id: String,
71 /// Queried account owner principal.
72 pub account_owner: String,
73 /// Queried subaccount as normalized hex.
74 pub subaccount_hex: Option<String>,
75 /// Explicit IC API endpoint used for collection.
76 pub source_endpoint: String,
77 /// Complete collection start timestamp.
78 pub collection_started_at: String,
79 /// Complete collection finish timestamp.
80 pub collection_completed_at: String,
81 /// Collector identity.
82 pub fetched_by: String,
83}
84
85///
86/// IcrcAccountTransactionSnapshot
87///
88/// Complete persisted account-history snapshot collected by exhausting the index API.
89///
90
91#[derive(Clone, Debug, Eq, PartialEq, SerdeDeserialize, Serialize)]
92#[serde(deny_unknown_fields)]
93pub struct IcrcAccountTransactionSnapshot {
94 /// Shared identity and collection metadata, flattened in JSON.
95 #[serde(flatten)]
96 pub context: IcrcAccountTransactionContext,
97 /// Cache schema version.
98 pub schema_version: u32,
99 /// Account balance reported by the first index page.
100 pub balance: String,
101 /// Ledger token symbol used for text rendering.
102 pub token_symbol: String,
103 /// Ledger token decimals used for text rendering.
104 pub decimals: u8,
105 /// Highest collected transaction id.
106 pub newest_transaction_id: Option<String>,
107 /// Lowest collected transaction id.
108 pub oldest_transaction_id: Option<String>,
109 /// Complete-collection evidence.
110 pub completeness: CacheCollectionCompleteness,
111 /// Canonical newest-first account transactions.
112 pub transactions: Vec<IcrcAccountTransactionRow>,
113}
114
115///
116/// IcrcAccountTransactionRefreshReport
117///
118/// Serializable forced-refresh outcome for one complete account-history cache.
119///
120
121#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
122pub struct IcrcAccountTransactionRefreshReport {
123 /// Shared identity and collection metadata, flattened in JSON.
124 #[serde(flatten)]
125 pub context: IcrcAccountTransactionContext,
126 /// Report schema version.
127 pub schema_version: u32,
128 /// Number of unique transactions published.
129 pub transaction_count: usize,
130 /// Highest published transaction id.
131 pub newest_transaction_id: Option<String>,
132 /// Lowest published transaction id.
133 pub oldest_transaction_id: Option<String>,
134 /// Maximum transactions requested per source page.
135 pub page_size: u32,
136 /// Number of source pages collected.
137 pub page_count: u32,
138 /// Whether the source guarantees one point-in-time snapshot.
139 pub point_in_time_guaranteed: bool,
140 /// Whether a prior complete cache existed.
141 pub replaced_existing_cache: bool,
142 /// Non-fatal error encountered finalizing the refresh-attempt sidecar.
143 pub attempt_finalization_error: Option<String>,
144 /// Published complete-cache path.
145 pub cache_path: String,
146 /// Refresh-attempt sidecar path.
147 pub refresh_attempt_path: String,
148 /// Refresh lock path.
149 pub refresh_lock_path: String,
150}
151
152///
153/// IcrcAccountTransactionListReport
154///
155/// Serializable cache-only view over a complete account-history snapshot.
156///
157
158#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
159pub struct IcrcAccountTransactionListReport {
160 /// Shared identity and collection metadata, flattened in JSON.
161 #[serde(flatten)]
162 pub context: IcrcAccountTransactionContext,
163 /// Report schema version.
164 pub schema_version: u32,
165 /// Maximum cached rows requested by this view.
166 pub requested_limit: u32,
167 /// Stable requested ordering name.
168 pub sort: String,
169 /// Total rows in the complete cache.
170 pub total_transaction_count: usize,
171 /// Rows returned by this view.
172 pub returned_transaction_count: usize,
173 /// Highest transaction id in the complete cache.
174 pub newest_transaction_id: Option<String>,
175 /// Lowest transaction id in the complete cache.
176 pub oldest_transaction_id: Option<String>,
177 /// Account balance captured from the first index page.
178 pub balance: String,
179 /// Ledger token symbol used for text rendering.
180 pub token_symbol: String,
181 /// Ledger token decimals used for text rendering.
182 pub decimals: u8,
183 /// Whether source exhaustion was proven.
184 pub complete: bool,
185 /// Whether the source guaranteed one point-in-time snapshot.
186 pub point_in_time_guaranteed: bool,
187 /// Maximum transactions requested per source page.
188 pub page_size: u32,
189 /// Number of source pages collected.
190 pub page_count: u32,
191 /// Complete-cache path read by this view.
192 pub cache_path: String,
193 /// Selected cached rows in requested order.
194 pub transactions: Vec<IcrcAccountTransactionRow>,
195}
196
197///
198/// IcrcAccountTransactionCacheStatusReport
199///
200/// Serializable local cache and latest-refresh status.
201///
202
203#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
204pub struct IcrcAccountTransactionCacheStatusReport {
205 /// Report schema version.
206 pub schema_version: u32,
207 /// Ledger canister in the requested cache identity.
208 pub ledger_canister_id: String,
209 /// Account owner in the requested cache identity.
210 pub account_owner: String,
211 /// Subaccount in the requested cache identity.
212 pub subaccount_hex: Option<String>,
213 /// IC API endpoint in the requested cache identity.
214 pub source_endpoint: String,
215 /// Whether a cache file exists at the expected path.
216 pub found: bool,
217 /// Validation summary when a cache file exists.
218 pub cache: Option<IcrcAccountTransactionCacheSummary>,
219 /// Expected complete-cache path.
220 pub expected_cache_path: String,
221 /// Refresh-attempt sidecar path.
222 pub refresh_attempt_path: String,
223 /// Refresh lock path.
224 pub refresh_lock_path: String,
225 /// Latest refresh-attempt state when present.
226 pub latest_attempt: Option<IcrcAccountTransactionRefreshAttemptStatus>,
227}
228
229///
230/// IcrcAccountTransactionCacheSummary
231///
232/// Existing-file admission outcome; invalid files carry no invented collection metadata.
233///
234
235#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
236#[serde(tag = "cache_status", rename_all = "snake_case")]
237pub enum IcrcAccountTransactionCacheSummary {
238 /// One admitted complete snapshot.
239 Valid {
240 /// Verified collection facts, flattened in JSON.
241 #[serde(flatten)]
242 data: IcrcAccountTransactionValidCacheSummary,
243 },
244 /// Existing file that failed admission.
245 Invalid {
246 /// Existing file path.
247 cache_path: String,
248 /// Original validation failure.
249 cache_error: String,
250 },
251}
252
253impl IcrcAccountTransactionCacheSummary {
254 /// Return the typed admission status.
255 #[must_use]
256 pub const fn cache_status(&self) -> CacheValidationStatus {
257 match self {
258 Self::Valid { .. } => CacheValidationStatus::Valid,
259 Self::Invalid { .. } => CacheValidationStatus::Invalid,
260 }
261 }
262}
263
264///
265/// IcrcAccountTransactionValidCacheSummary
266///
267/// Facts read only from an admitted complete account-history snapshot.
268///
269
270#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
271pub struct IcrcAccountTransactionValidCacheSummary {
272 /// Verified index canister.
273 pub index_canister_id: String,
274 /// Number of cached transaction rows.
275 pub transaction_count: usize,
276 /// Highest cached transaction id.
277 pub newest_transaction_id: Option<String>,
278 /// Lowest cached transaction id.
279 pub oldest_transaction_id: Option<String>,
280 /// Maximum transactions requested per source page.
281 pub page_size: u32,
282 /// Number of source pages collected.
283 pub page_count: u32,
284 /// Whether the source guaranteed one point-in-time snapshot.
285 pub point_in_time_guaranteed: bool,
286 /// Complete collection start timestamp.
287 pub collection_started_at: String,
288 /// Complete collection finish timestamp.
289 pub collection_completed_at: String,
290 /// Complete-cache path.
291 pub cache_path: String,
292}
293
294///
295/// IcrcAccountTransactionRefreshAttemptStatus
296///
297/// Serializable status of the latest complete-history refresh attempt.
298///
299
300#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
301pub struct IcrcAccountTransactionRefreshAttemptStatus {
302 /// Explicit or resolved index canister recorded by the attempt.
303 pub index_canister_id: Option<String>,
304 /// Validated shared lifecycle evidence.
305 #[serde(flatten)]
306 pub lifecycle: crate::cache::SnapshotRefreshAttemptStatus,
307}
308
309///
310/// IcrcAccountRow
311///
312/// Serializable ICRC account identity used in account-transaction rows.
313///
314
315#[derive(Clone, Debug, Eq, PartialEq, SerdeDeserialize, Serialize)]
316pub struct IcrcAccountRow {
317 /// ICRC account owner principal when the index uses structured accounts.
318 pub owner: Option<String>,
319 /// Optional 32-byte subaccount as lowercase hex.
320 pub subaccount_hex: Option<String>,
321 /// Legacy ICP account identifier when the index returns identifier text.
322 pub account_identifier: Option<String>,
323}
324
325///
326/// IcrcAccountTransactionRow
327///
328/// Serializable projected and lossless JSON representation of one index transaction.
329///
330
331#[derive(Clone, Debug, Eq, PartialEq, SerdeDeserialize, Serialize)]
332pub struct IcrcAccountTransactionRow {
333 /// Ledger block index of the transaction.
334 pub id: String,
335 /// Index-reported transaction kind.
336 pub kind: String,
337 /// Ledger transaction timestamp as Unix nanoseconds when present.
338 pub timestamp_unix_nanos: Option<String>,
339 /// Operation amount in ledger base units when the operation carries one.
340 pub amount_base_units: Option<String>,
341 /// Operation fee in ledger base units when the operation carries one.
342 pub fee_base_units: Option<String>,
343 /// Source account when present.
344 pub from: Option<IcrcAccountRow>,
345 /// Destination account when present.
346 pub to: Option<IcrcAccountRow>,
347 /// Spender account when present.
348 pub spender: Option<IcrcAccountRow>,
349 /// Operation memo as lowercase hex when present.
350 pub memo_hex: Option<String>,
351 /// Caller-supplied creation time as Unix nanoseconds when present.
352 pub created_at_time_unix_nanos: Option<String>,
353 /// Approval expiry as Unix nanoseconds when present.
354 pub expires_at_unix_nanos: Option<String>,
355 /// Expected prior allowance in base units when present.
356 pub expected_allowance_base_units: Option<String>,
357 /// Lossless JSON projection of every typed transaction field returned by the index.
358 pub raw_transaction: JsonValue,
359}