Skip to main content

ic_query/icrc/model/
contracts.rs

1//! Module: icrc::model::contracts
2//!
3//! Responsibility: public ICRC request, report, and serializable row contracts.
4//! Does not own: errors, source-layer data, subaccount validation, live transport, or rendering.
5//! Boundary: preserves the public request API and raw JSON report fields.
6
7use serde::{Deserialize as SerdeDeserialize, Serialize};
8use serde_json::Value as JsonValue;
9use std::path::PathBuf;
10
11///
12/// IcrcLedgerRequest
13///
14/// Shared ledger identity and provenance for metadata and capability report builders.
15///
16
17#[derive(Clone, Debug, Eq, PartialEq)]
18pub struct IcrcLedgerRequest {
19    pub source_endpoint: String,
20    pub now_unix_secs: u64,
21    pub ledger_canister_id: String,
22}
23
24impl IcrcLedgerRequest {
25    #[must_use]
26    pub fn new(
27        source_endpoint: impl Into<String>,
28        now_unix_secs: u64,
29        ledger_canister_id: impl Into<String>,
30    ) -> Self {
31        Self {
32            source_endpoint: source_endpoint.into(),
33            now_unix_secs,
34            ledger_canister_id: ledger_canister_id.into(),
35        }
36    }
37}
38
39///
40/// IcrcBalanceRequest
41///
42/// Request accepted by the generic ICRC account balance report builder.
43///
44
45#[derive(Clone, Debug, Eq, PartialEq)]
46pub struct IcrcBalanceRequest {
47    pub source_endpoint: String,
48    pub now_unix_secs: u64,
49    pub ledger_canister_id: String,
50    pub account_owner: String,
51    pub subaccount_hex: Option<String>,
52}
53
54impl IcrcBalanceRequest {
55    #[must_use]
56    pub fn new(
57        source_endpoint: impl Into<String>,
58        now_unix_secs: u64,
59        ledger_canister_id: impl Into<String>,
60        account_owner: impl Into<String>,
61    ) -> Self {
62        Self {
63            source_endpoint: source_endpoint.into(),
64            now_unix_secs,
65            ledger_canister_id: ledger_canister_id.into(),
66            account_owner: account_owner.into(),
67            subaccount_hex: None,
68        }
69    }
70
71    #[must_use]
72    pub fn with_subaccount_hex(mut self, subaccount_hex: impl Into<String>) -> Self {
73        self.subaccount_hex = Some(subaccount_hex.into());
74        self
75    }
76}
77
78///
79/// IcrcAllowanceRequest
80///
81/// Request accepted by the generic ICRC allowance report builder.
82///
83
84#[derive(Clone, Debug, Eq, PartialEq)]
85pub struct IcrcAllowanceRequest {
86    pub source_endpoint: String,
87    pub now_unix_secs: u64,
88    pub ledger_canister_id: String,
89    pub account_owner: String,
90    pub account_subaccount_hex: Option<String>,
91    pub spender_owner: String,
92    pub spender_subaccount_hex: Option<String>,
93}
94
95impl IcrcAllowanceRequest {
96    #[must_use]
97    pub fn new(
98        source_endpoint: impl Into<String>,
99        now_unix_secs: u64,
100        ledger_canister_id: impl Into<String>,
101        account_owner: impl Into<String>,
102        spender_owner: impl Into<String>,
103    ) -> Self {
104        Self {
105            source_endpoint: source_endpoint.into(),
106            now_unix_secs,
107            ledger_canister_id: ledger_canister_id.into(),
108            account_owner: account_owner.into(),
109            account_subaccount_hex: None,
110            spender_owner: spender_owner.into(),
111            spender_subaccount_hex: None,
112        }
113    }
114
115    #[must_use]
116    pub fn with_account_subaccount_hex(
117        mut self,
118        account_subaccount_hex: impl Into<String>,
119    ) -> Self {
120        self.account_subaccount_hex = Some(account_subaccount_hex.into());
121        self
122    }
123
124    #[must_use]
125    pub fn with_spender_subaccount_hex(
126        mut self,
127        spender_subaccount_hex: impl Into<String>,
128    ) -> Self {
129        self.spender_subaccount_hex = Some(spender_subaccount_hex.into());
130        self
131    }
132}
133
134///
135/// IcrcAccountTransactionPageRequest
136///
137/// Request accepted by the live ICRC index account-transaction page builder.
138///
139
140#[derive(Clone, Debug, Eq, PartialEq)]
141pub struct IcrcAccountTransactionPageRequest {
142    /// IC API endpoint used for ledger and index queries.
143    pub source_endpoint: String,
144    /// Collection time as Unix seconds.
145    pub now_unix_secs: u64,
146    /// Ledger canister whose account history is requested.
147    pub ledger_canister_id: String,
148    /// Optional explicit index canister; otherwise ICRC-106 discovery is used.
149    pub index_canister_id: Option<String>,
150    /// Account owner principal.
151    pub account_owner: String,
152    /// Optional normalized 32-byte subaccount hex.
153    pub subaccount_hex: Option<String>,
154    /// Optional exclusive block-index cursor for backward pagination.
155    pub start: Option<String>,
156    /// Maximum number of account transactions to request.
157    pub limit: u32,
158}
159
160impl IcrcAccountTransactionPageRequest {
161    /// Constructs an account-history request that discovers the index through the ledger.
162    #[must_use]
163    pub fn new(
164        source_endpoint: impl Into<String>,
165        now_unix_secs: u64,
166        ledger_canister_id: impl Into<String>,
167        account_owner: impl Into<String>,
168        limit: u32,
169    ) -> Self {
170        Self {
171            source_endpoint: source_endpoint.into(),
172            now_unix_secs,
173            ledger_canister_id: ledger_canister_id.into(),
174            index_canister_id: None,
175            account_owner: account_owner.into(),
176            subaccount_hex: None,
177            start: None,
178            limit,
179        }
180    }
181
182    /// Uses an explicit index canister instead of ICRC-106 discovery.
183    #[must_use]
184    pub fn with_index_canister_id(mut self, index_canister_id: impl Into<String>) -> Self {
185        self.index_canister_id = Some(index_canister_id.into());
186        self
187    }
188
189    /// Selects a 32-byte ICRC subaccount encoded as hex.
190    #[must_use]
191    pub fn with_subaccount_hex(mut self, subaccount_hex: impl Into<String>) -> Self {
192        self.subaccount_hex = Some(subaccount_hex.into());
193        self
194    }
195
196    /// Starts after the given transaction block index when paginating backward.
197    #[must_use]
198    pub fn with_start(mut self, start: impl Into<String>) -> Self {
199        self.start = Some(start.into());
200        self
201    }
202}
203
204///
205/// IcrcAccountTransactionCacheRequest
206///
207/// Stable account-history cache identity independent of page and view options.
208///
209
210#[derive(Clone, Debug, Eq, PartialEq)]
211pub struct IcrcAccountTransactionCacheRequest {
212    /// Root directory containing the shared cache.
213    pub cache_root: PathBuf,
214    /// IC API endpoint whose indexed history is cached.
215    pub source_endpoint: String,
216    /// Ledger canister whose account history is cached.
217    pub ledger_canister_id: String,
218    /// Account owner principal.
219    pub account_owner: String,
220    /// Optional normalized 32-byte subaccount hex.
221    pub subaccount_hex: Option<String>,
222}
223
224impl IcrcAccountTransactionCacheRequest {
225    /// Constructs a cache identity for the default subaccount.
226    #[must_use]
227    pub fn new(
228        cache_root: impl Into<PathBuf>,
229        source_endpoint: impl Into<String>,
230        ledger_canister_id: impl Into<String>,
231        account_owner: impl Into<String>,
232    ) -> Self {
233        Self {
234            cache_root: cache_root.into(),
235            source_endpoint: source_endpoint.into(),
236            ledger_canister_id: ledger_canister_id.into(),
237            account_owner: account_owner.into(),
238            subaccount_hex: None,
239        }
240    }
241
242    /// Selects a 32-byte ICRC subaccount encoded as hex.
243    #[must_use]
244    pub fn with_subaccount_hex(mut self, subaccount_hex: impl Into<String>) -> Self {
245        self.subaccount_hex = Some(subaccount_hex.into());
246        self
247    }
248}
249
250///
251/// IcrcAccountTransactionRefreshRequest
252///
253/// Request for a forced complete account-history refresh.
254///
255
256#[derive(Clone, Debug, Eq, PartialEq)]
257pub struct IcrcAccountTransactionRefreshRequest {
258    /// Stable cache identity.
259    pub cache: IcrcAccountTransactionCacheRequest,
260    /// Collection start time as Unix seconds.
261    pub now_unix_secs: u64,
262    /// Optional explicit index canister; otherwise ICRC-106 discovery is used.
263    pub index_canister_id: Option<String>,
264    /// Maximum transactions requested per index page.
265    pub page_size: u32,
266    /// Optional diagnostic bound that fails rather than publishing a partial cache.
267    pub max_pages: Option<u32>,
268    /// Age after which an abandoned refresh lock is reported as stale.
269    pub lock_stale_after_seconds: u64,
270}
271
272impl IcrcAccountTransactionRefreshRequest {
273    /// Constructs a complete refresh request.
274    #[must_use]
275    pub const fn new(
276        cache: IcrcAccountTransactionCacheRequest,
277        now_unix_secs: u64,
278        page_size: u32,
279        lock_stale_after_seconds: u64,
280    ) -> Self {
281        Self {
282            cache,
283            now_unix_secs,
284            index_canister_id: None,
285            page_size,
286            max_pages: None,
287            lock_stale_after_seconds,
288        }
289    }
290
291    /// Uses an explicit index canister instead of ICRC-106 discovery.
292    #[must_use]
293    pub fn with_index_canister_id(mut self, index_canister_id: impl Into<String>) -> Self {
294        self.index_canister_id = Some(index_canister_id.into());
295        self
296    }
297
298    /// Bounds pages for diagnostics; reaching the bound never publishes a cache.
299    #[must_use]
300    pub const fn with_max_pages(mut self, max_pages: Option<u32>) -> Self {
301        self.max_pages = max_pages;
302        self
303    }
304}
305
306///
307/// IcrcAccountTransactionSort
308///
309/// Supported cached account-history ordering.
310///
311
312#[derive(Clone, Copy, Debug, Eq, PartialEq)]
313pub enum IcrcAccountTransactionSort {
314    /// Highest transaction id first.
315    Newest,
316    /// Lowest transaction id first.
317    Oldest,
318}
319
320impl IcrcAccountTransactionSort {
321    /// Stable JSON/text name for this ordering.
322    #[must_use]
323    pub const fn as_str(self) -> &'static str {
324        match self {
325            Self::Newest => "newest",
326            Self::Oldest => "oldest",
327        }
328    }
329}
330
331///
332/// IcrcAccountTransactionListRequest
333///
334/// Cache-only account-history list view.
335///
336
337#[derive(Clone, Debug, Eq, PartialEq)]
338pub struct IcrcAccountTransactionListRequest {
339    /// Stable cache identity.
340    pub cache: IcrcAccountTransactionCacheRequest,
341    /// Maximum cached rows returned by this view.
342    pub limit: u32,
343    /// Requested cached-row ordering.
344    pub sort: IcrcAccountTransactionSort,
345}
346
347impl IcrcAccountTransactionListRequest {
348    /// Constructs a newest-first cached list view.
349    #[must_use]
350    pub const fn new(cache: IcrcAccountTransactionCacheRequest, limit: u32) -> Self {
351        Self {
352            cache,
353            limit,
354            sort: IcrcAccountTransactionSort::Newest,
355        }
356    }
357
358    /// Selects cached-row ordering.
359    #[must_use]
360    pub const fn with_sort(mut self, sort: IcrcAccountTransactionSort) -> Self {
361        self.sort = sort;
362        self
363    }
364}
365
366///
367/// IcrcTransactionsRequest
368///
369/// Request accepted by the generic ICRC transaction history report builder.
370///
371
372#[derive(Clone, Debug, Eq, PartialEq)]
373pub struct IcrcTransactionsRequest {
374    pub source_endpoint: String,
375    pub now_unix_secs: u64,
376    pub ledger_canister_id: String,
377    pub start: u64,
378    pub limit: u32,
379    pub follow_archives: bool,
380}
381
382impl IcrcTransactionsRequest {
383    #[must_use]
384    pub fn new(
385        source_endpoint: impl Into<String>,
386        now_unix_secs: u64,
387        ledger_canister_id: impl Into<String>,
388        start: u64,
389        limit: u32,
390    ) -> Self {
391        Self {
392            source_endpoint: source_endpoint.into(),
393            now_unix_secs,
394            ledger_canister_id: ledger_canister_id.into(),
395            start,
396            limit,
397            follow_archives: false,
398        }
399    }
400
401    #[must_use]
402    pub const fn with_follow_archives(mut self, follow_archives: bool) -> Self {
403        self.follow_archives = follow_archives;
404        self
405    }
406}
407
408///
409/// IcrcArchivesRequest
410///
411/// Request accepted by the generic ICRC archives report builder.
412///
413
414#[derive(Clone, Debug, Eq, PartialEq)]
415pub struct IcrcArchivesRequest {
416    pub source_endpoint: String,
417    pub now_unix_secs: u64,
418    pub ledger_canister_id: String,
419    pub from_canister_id: Option<String>,
420}
421
422impl IcrcArchivesRequest {
423    #[must_use]
424    pub fn new(
425        source_endpoint: impl Into<String>,
426        now_unix_secs: u64,
427        ledger_canister_id: impl Into<String>,
428    ) -> Self {
429        Self {
430            source_endpoint: source_endpoint.into(),
431            now_unix_secs,
432            ledger_canister_id: ledger_canister_id.into(),
433            from_canister_id: None,
434        }
435    }
436
437    #[must_use]
438    pub fn with_from_canister_id(mut self, from_canister_id: impl Into<String>) -> Self {
439        self.from_canister_id = Some(from_canister_id.into());
440        self
441    }
442}
443
444///
445/// IcrcTokenReport
446///
447/// Serializable report for generic ICRC ledger token metadata.
448///
449
450#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
451pub struct IcrcTokenReport {
452    pub schema_version: u32,
453    pub ledger_canister_id: String,
454    pub fetched_at: String,
455    pub source_endpoint: String,
456    pub fetched_by: String,
457    pub token_name: String,
458    pub token_symbol: String,
459    pub decimals: u8,
460    pub transfer_fee: String,
461    pub total_supply: String,
462    pub minting_account_owner: Option<String>,
463    pub minting_account_subaccount_hex: Option<String>,
464    pub supported_standards: Vec<IcrcTokenStandardRow>,
465    pub metadata: Vec<IcrcTokenMetadataRow>,
466}
467
468///
469/// IcrcBalanceReport
470///
471/// Serializable report for one generic ICRC account balance lookup.
472///
473
474#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
475pub struct IcrcBalanceReport {
476    pub schema_version: u32,
477    pub ledger_canister_id: String,
478    pub account_owner: String,
479    pub subaccount_hex: Option<String>,
480    pub fetched_at: String,
481    pub source_endpoint: String,
482    pub fetched_by: String,
483    pub token_symbol: String,
484    pub decimals: u8,
485    pub balance: String,
486}
487
488///
489/// IcrcAllowanceReport
490///
491/// Serializable report for one generic ICRC allowance lookup.
492///
493
494#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
495pub struct IcrcAllowanceReport {
496    pub schema_version: u32,
497    pub ledger_canister_id: String,
498    pub account_owner: String,
499    pub account_subaccount_hex: Option<String>,
500    pub spender_owner: String,
501    pub spender_subaccount_hex: Option<String>,
502    pub fetched_at: String,
503    pub source_endpoint: String,
504    pub fetched_by: String,
505    pub token_symbol: String,
506    pub decimals: u8,
507    pub allowance: String,
508    pub expires_at_unix_nanos: Option<String>,
509}
510
511///
512/// IcrcAccountTransactionPageReport
513///
514/// Serializable report for a backward page of ICRC index account transactions.
515///
516
517#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
518pub struct IcrcAccountTransactionPageReport {
519    /// Report schema version.
520    pub schema_version: u32,
521    /// Ledger canister whose transactions were indexed.
522    pub ledger_canister_id: String,
523    /// Index canister that answered the account-history query.
524    pub index_canister_id: String,
525    /// Queried account owner principal.
526    pub account_owner: String,
527    /// Queried subaccount as normalized hex.
528    pub subaccount_hex: Option<String>,
529    /// Exclusive block-index cursor supplied by the caller.
530    pub requested_start: Option<String>,
531    /// Maximum number of transactions requested.
532    pub requested_limit: u32,
533    /// Cursor to pass as `start` to request the next older page.
534    pub next_start: Option<String>,
535    /// Oldest transaction id known for this account.
536    pub oldest_transaction_id: Option<String>,
537    /// Account balance reported by the index at its synchronized tip.
538    pub balance: String,
539    /// Ledger token symbol used for text rendering.
540    pub token_symbol: String,
541    /// Ledger token decimals used for text rendering.
542    pub decimals: u8,
543    /// Collection timestamp in UTC text form.
544    pub fetched_at: String,
545    /// IC API endpoint used for ledger and index calls.
546    pub source_endpoint: String,
547    /// Collector identity.
548    pub fetched_by: String,
549    /// Transactions returned by the index in its native page order.
550    pub transactions: Vec<IcrcAccountTransactionRow>,
551}
552
553///
554/// IcrcAccountTransactionCompleteness
555///
556/// Evidence that a persisted account-history snapshot exhausted the index API.
557///
558
559#[derive(Clone, Debug, Eq, PartialEq, SerdeDeserialize, Serialize)]
560pub struct IcrcAccountTransactionCompleteness {
561    /// Stable completeness classification; complete snapshots use `api_exhausted`.
562    pub status: String,
563    /// Maximum transactions requested per source page.
564    pub page_size: u32,
565    /// Number of source pages collected.
566    pub page_count: u32,
567    /// Number of unique persisted transaction rows.
568    pub row_count: usize,
569    /// Whether the source guarantees every page belongs to one point in time.
570    pub point_in_time_guaranteed: bool,
571}
572
573///
574/// IcrcAccountTransactionSnapshot
575///
576/// Complete persisted account-history snapshot collected by exhausting the index API.
577///
578
579#[derive(Clone, Debug, Eq, PartialEq, SerdeDeserialize, Serialize)]
580pub struct IcrcAccountTransactionSnapshot {
581    /// Cache schema version.
582    pub schema_version: u32,
583    /// IC API endpoint used for ledger and index calls.
584    pub source_endpoint: String,
585    /// Collection start timestamp.
586    pub collection_started_at: String,
587    /// Collection completion timestamp.
588    pub collection_completed_at: String,
589    /// Collector identity.
590    pub fetched_by: String,
591    /// Ledger canister whose transactions were indexed.
592    pub ledger_canister_id: String,
593    /// Verified index canister used for every page.
594    pub index_canister_id: String,
595    /// Queried account owner principal.
596    pub account_owner: String,
597    /// Queried subaccount as normalized hex.
598    pub subaccount_hex: Option<String>,
599    /// Account balance reported by the first index page.
600    pub balance: String,
601    /// Ledger token symbol used for text rendering.
602    pub token_symbol: String,
603    /// Ledger token decimals used for text rendering.
604    pub decimals: u8,
605    /// Highest collected transaction id.
606    pub newest_transaction_id: Option<String>,
607    /// Lowest collected transaction id.
608    pub oldest_transaction_id: Option<String>,
609    /// Complete-collection evidence.
610    pub completeness: IcrcAccountTransactionCompleteness,
611    /// Canonical newest-first account transactions.
612    pub transactions: Vec<IcrcAccountTransactionRow>,
613}
614
615///
616/// IcrcAccountTransactionRefreshReport
617///
618/// Serializable forced-refresh outcome for one complete account-history cache.
619///
620
621#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
622pub struct IcrcAccountTransactionRefreshReport {
623    /// Report schema version.
624    pub schema_version: u32,
625    /// Ledger canister whose account history was collected.
626    pub ledger_canister_id: String,
627    /// Verified index canister used for every page.
628    pub index_canister_id: String,
629    /// Queried account owner principal.
630    pub account_owner: String,
631    /// Queried subaccount as normalized hex.
632    pub subaccount_hex: Option<String>,
633    /// Number of unique transactions published.
634    pub transaction_count: usize,
635    /// Highest published transaction id.
636    pub newest_transaction_id: Option<String>,
637    /// Lowest published transaction id.
638    pub oldest_transaction_id: Option<String>,
639    /// Maximum transactions requested per source page.
640    pub page_size: u32,
641    /// Number of source pages collected.
642    pub page_count: u32,
643    /// Whether the source guarantees one point-in-time snapshot.
644    pub point_in_time_guaranteed: bool,
645    /// Whether a prior complete cache existed.
646    pub replaced_existing_cache: bool,
647    /// Non-fatal error encountered finalizing the refresh-attempt sidecar.
648    pub attempt_finalization_error: Option<String>,
649    /// Collection start timestamp.
650    pub collection_started_at: String,
651    /// Collection completion timestamp.
652    pub collection_completed_at: String,
653    /// IC API endpoint used for ledger and index calls.
654    pub source_endpoint: String,
655    /// Collector identity.
656    pub fetched_by: String,
657    /// Published complete-cache path.
658    pub cache_path: String,
659    /// Refresh-attempt sidecar path.
660    pub refresh_attempt_path: String,
661    /// Refresh lock path.
662    pub refresh_lock_path: String,
663}
664
665///
666/// IcrcAccountTransactionListReport
667///
668/// Serializable cache-only view over a complete account-history snapshot.
669///
670
671#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
672pub struct IcrcAccountTransactionListReport {
673    /// Report schema version.
674    pub schema_version: u32,
675    /// Ledger canister whose cached history is shown.
676    pub ledger_canister_id: String,
677    /// Verified index canister used to collect the cache.
678    pub index_canister_id: String,
679    /// Cached account owner principal.
680    pub account_owner: String,
681    /// Cached subaccount as normalized hex.
682    pub subaccount_hex: Option<String>,
683    /// Maximum cached rows requested by this view.
684    pub requested_limit: u32,
685    /// Stable requested ordering name.
686    pub sort: String,
687    /// Total rows in the complete cache.
688    pub total_transaction_count: usize,
689    /// Rows returned by this view.
690    pub returned_transaction_count: usize,
691    /// Highest transaction id in the complete cache.
692    pub newest_transaction_id: Option<String>,
693    /// Lowest transaction id in the complete cache.
694    pub oldest_transaction_id: Option<String>,
695    /// Account balance captured from the first index page.
696    pub balance: String,
697    /// Ledger token symbol used for text rendering.
698    pub token_symbol: String,
699    /// Ledger token decimals used for text rendering.
700    pub decimals: u8,
701    /// Complete collection start timestamp.
702    pub collection_started_at: String,
703    /// Complete collection finish timestamp.
704    pub collection_completed_at: String,
705    /// IC API endpoint represented by the cache.
706    pub source_endpoint: String,
707    /// Collector identity.
708    pub fetched_by: String,
709    /// Whether source exhaustion was proven.
710    pub complete: bool,
711    /// Whether the source guaranteed one point-in-time snapshot.
712    pub point_in_time_guaranteed: bool,
713    /// Maximum transactions requested per source page.
714    pub page_size: u32,
715    /// Number of source pages collected.
716    pub page_count: u32,
717    /// Complete-cache path read by this view.
718    pub cache_path: String,
719    /// Selected cached rows in requested order.
720    pub transactions: Vec<IcrcAccountTransactionRow>,
721}
722
723///
724/// IcrcAccountTransactionCacheStatusReport
725///
726/// Serializable local cache and latest-refresh status.
727///
728
729#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
730pub struct IcrcAccountTransactionCacheStatusReport {
731    /// Report schema version.
732    pub schema_version: u32,
733    /// Ledger canister in the requested cache identity.
734    pub ledger_canister_id: String,
735    /// Account owner in the requested cache identity.
736    pub account_owner: String,
737    /// Subaccount in the requested cache identity.
738    pub subaccount_hex: Option<String>,
739    /// IC API endpoint in the requested cache identity.
740    pub source_endpoint: String,
741    /// Whether a cache file exists at the expected path.
742    pub found: bool,
743    /// Validation summary when a cache file exists.
744    pub cache: Option<IcrcAccountTransactionCacheSummary>,
745    /// Expected complete-cache path.
746    pub expected_cache_path: String,
747    /// Refresh-attempt sidecar path.
748    pub refresh_attempt_path: String,
749    /// Refresh lock path.
750    pub refresh_lock_path: String,
751    /// Latest refresh-attempt state when present.
752    pub latest_attempt: Option<IcrcAccountTransactionRefreshAttemptStatus>,
753}
754
755///
756/// IcrcAccountTransactionCacheSummary
757///
758/// Serializable validation summary for one complete account-history cache.
759///
760
761#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
762pub struct IcrcAccountTransactionCacheSummary {
763    /// Stable cache validation status.
764    pub cache_status: String,
765    /// Validation error when the existing cache is invalid.
766    pub cache_error: Option<String>,
767    /// Verified index canister when the cache is valid.
768    pub index_canister_id: Option<String>,
769    /// Number of cached transaction rows.
770    pub transaction_count: usize,
771    /// Highest cached transaction id.
772    pub newest_transaction_id: Option<String>,
773    /// Lowest cached transaction id.
774    pub oldest_transaction_id: Option<String>,
775    /// Maximum transactions requested per source page.
776    pub page_size: u32,
777    /// Number of source pages collected.
778    pub page_count: u32,
779    /// Whether source exhaustion was proven.
780    pub complete: bool,
781    /// Whether the source guaranteed one point-in-time snapshot.
782    pub point_in_time_guaranteed: bool,
783    /// Complete collection start timestamp.
784    pub collection_started_at: String,
785    /// Complete collection finish timestamp.
786    pub collection_completed_at: String,
787    /// Complete-cache path.
788    pub cache_path: String,
789}
790
791///
792/// IcrcAccountTransactionRefreshAttemptStatus
793///
794/// Serializable status of the latest complete-history refresh attempt.
795///
796
797#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
798pub struct IcrcAccountTransactionRefreshAttemptStatus {
799    /// Stable attempt lifecycle status.
800    pub status: String,
801    /// Attempt start timestamp.
802    pub started_at: String,
803    /// Last attempt update timestamp.
804    pub updated_at: String,
805    /// Explicit or resolved index canister recorded by the attempt.
806    pub index_canister_id: Option<String>,
807    /// Maximum transactions requested per source page.
808    pub page_size: u32,
809    /// Successfully collected pages.
810    pub pages_fetched: u32,
811    /// Rows retained before the latest update.
812    pub rows_fetched: usize,
813    /// Last exclusive cursor when present.
814    pub last_cursor: Option<String>,
815    /// Final failure text when the attempt failed.
816    pub last_error: Option<String>,
817}
818
819///
820/// IcrcIndexReport
821///
822/// Serializable report for one generic ICRC-106 index discovery lookup.
823///
824
825#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
826pub struct IcrcIndexReport {
827    pub schema_version: u32,
828    pub ledger_canister_id: String,
829    pub fetched_at: String,
830    pub source_endpoint: String,
831    pub fetched_by: String,
832    pub index_canister_id: Option<String>,
833    pub index_error: Option<String>,
834}
835
836///
837/// IcrcTransactionsReport
838///
839/// Serializable report for a generic ICRC ledger transaction/block history page.
840///
841
842#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
843pub struct IcrcTransactionsReport {
844    pub schema_version: u32,
845    pub ledger_canister_id: String,
846    pub fetched_at: String,
847    pub source_endpoint: String,
848    pub fetched_by: String,
849    pub requested_start: String,
850    pub requested_limit: u32,
851    pub follow_archives: bool,
852    pub log_length: Option<String>,
853    pub blocks: Vec<IcrcTransactionBlockRow>,
854    pub archived_blocks: Vec<IcrcArchivedBlocksRow>,
855    pub followed_archive_blocks: Vec<IcrcFollowedArchiveBlockRow>,
856    pub archive_follow_errors: Vec<IcrcArchiveFollowErrorRow>,
857}
858
859///
860/// IcrcBlockTypesReport
861///
862/// Serializable report for generic ICRC-3 supported block type discovery.
863///
864
865#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
866pub struct IcrcBlockTypesReport {
867    pub schema_version: u32,
868    pub ledger_canister_id: String,
869    pub fetched_at: String,
870    pub source_endpoint: String,
871    pub fetched_by: String,
872    pub block_types: Vec<IcrcBlockTypeRow>,
873}
874
875///
876/// IcrcArchivesReport
877///
878/// Serializable report for generic ICRC-3 archive range discovery.
879///
880
881#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
882pub struct IcrcArchivesReport {
883    pub schema_version: u32,
884    pub ledger_canister_id: String,
885    pub from_canister_id: Option<String>,
886    pub fetched_at: String,
887    pub source_endpoint: String,
888    pub fetched_by: String,
889    pub archives: Vec<IcrcArchiveRow>,
890}
891
892///
893/// IcrcTipCertificateReport
894///
895/// Serializable report for a generic ICRC-3 ledger tip certificate.
896///
897
898#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
899pub struct IcrcTipCertificateReport {
900    pub schema_version: u32,
901    pub ledger_canister_id: String,
902    pub fetched_at: String,
903    pub source_endpoint: String,
904    pub fetched_by: String,
905    pub certificate_present: bool,
906    pub certificate_hex: Option<String>,
907    pub certificate_bytes: Option<usize>,
908    pub hash_tree_hex: Option<String>,
909    pub hash_tree_bytes: Option<usize>,
910}
911
912///
913/// IcrcCapabilitiesReport
914///
915/// Serializable report for generic ICRC ledger endpoint capabilities.
916///
917
918#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
919pub struct IcrcCapabilitiesReport {
920    pub schema_version: u32,
921    pub ledger_canister_id: String,
922    pub fetched_at: String,
923    pub source_endpoint: String,
924    pub fetched_by: String,
925    pub supported_standards: Vec<IcrcTokenStandardRow>,
926    pub capabilities: Vec<IcrcCapabilityRow>,
927}
928
929///
930/// IcrcCapabilityRow
931///
932/// Serializable row for one probed generic ICRC ledger capability.
933///
934
935#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
936pub struct IcrcCapabilityRow {
937    pub capability: String,
938    pub method: String,
939    pub status: String,
940    pub details: Option<String>,
941    pub error: Option<String>,
942}
943
944///
945/// IcrcTokenStandardRow
946///
947/// Serializable row for one ICRC standard supported by a ledger.
948///
949
950#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
951pub struct IcrcTokenStandardRow {
952    pub name: String,
953    pub url: String,
954}
955
956///
957/// IcrcTokenMetadataRow
958///
959/// Serializable row for one raw ICRC ledger metadata entry.
960///
961
962#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
963pub struct IcrcTokenMetadataRow {
964    pub key: String,
965    pub value_type: String,
966    pub value: JsonValue,
967}
968
969///
970/// IcrcAccountRow
971///
972/// Serializable ICRC account identity used in account-transaction rows.
973///
974
975#[derive(Clone, Debug, Eq, PartialEq, SerdeDeserialize, Serialize)]
976pub struct IcrcAccountRow {
977    /// ICRC account owner principal when the index uses structured accounts.
978    pub owner: Option<String>,
979    /// Optional 32-byte subaccount as lowercase hex.
980    pub subaccount_hex: Option<String>,
981    /// Legacy ICP account identifier when the index returns identifier text.
982    pub account_identifier: Option<String>,
983}
984
985///
986/// IcrcAccountTransactionRow
987///
988/// Serializable projected and lossless JSON representation of one index transaction.
989///
990
991#[derive(Clone, Debug, Eq, PartialEq, SerdeDeserialize, Serialize)]
992pub struct IcrcAccountTransactionRow {
993    /// Ledger block index of the transaction.
994    pub id: String,
995    /// Index-reported transaction kind.
996    pub kind: String,
997    /// Ledger transaction timestamp as Unix nanoseconds when present.
998    pub timestamp_unix_nanos: Option<String>,
999    /// Operation amount in ledger base units when the operation carries one.
1000    pub amount_base_units: Option<String>,
1001    /// Operation fee in ledger base units when the operation carries one.
1002    pub fee_base_units: Option<String>,
1003    /// Source account when present.
1004    pub from: Option<IcrcAccountRow>,
1005    /// Destination account when present.
1006    pub to: Option<IcrcAccountRow>,
1007    /// Spender account when present.
1008    pub spender: Option<IcrcAccountRow>,
1009    /// Operation memo as lowercase hex when present.
1010    pub memo_hex: Option<String>,
1011    /// Caller-supplied creation time as Unix nanoseconds when present.
1012    pub created_at_time_unix_nanos: Option<String>,
1013    /// Approval expiry as Unix nanoseconds when present.
1014    pub expires_at_unix_nanos: Option<String>,
1015    /// Expected prior allowance in base units when present.
1016    pub expected_allowance_base_units: Option<String>,
1017    /// Lossless JSON projection of every typed transaction field returned by the index.
1018    pub raw_transaction: JsonValue,
1019}
1020
1021///
1022/// IcrcTransactionBlockRow
1023///
1024/// Serializable row for one ICRC-3 block returned by a ledger canister.
1025///
1026
1027#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
1028pub struct IcrcTransactionBlockRow {
1029    pub index: String,
1030    pub block_type: Option<String>,
1031    pub transaction_kind: Option<String>,
1032    pub timestamp_unix_nanos: Option<String>,
1033    pub amount_base_units: Option<String>,
1034    pub raw_block: JsonValue,
1035}
1036
1037///
1038/// IcrcArchivedBlocksRow
1039///
1040/// Serializable row for one ICRC-3 archive callback returned by a ledger canister.
1041///
1042
1043#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
1044pub struct IcrcArchivedBlocksRow {
1045    pub callback_canister_id: String,
1046    pub callback_method: String,
1047    pub ranges: Vec<IcrcArchivedRangeRow>,
1048}
1049
1050///
1051/// IcrcArchivedRangeRow
1052///
1053/// Serializable row for one ICRC-3 archived block range.
1054///
1055
1056#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
1057pub struct IcrcArchivedRangeRow {
1058    pub start: String,
1059    pub length: String,
1060}
1061
1062///
1063/// IcrcFollowedArchiveBlockRow
1064///
1065/// Serializable row for one ICRC-3 block fetched from an archive callback.
1066///
1067
1068#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
1069pub struct IcrcFollowedArchiveBlockRow {
1070    pub archive_canister_id: String,
1071    pub callback_method: String,
1072    pub index: String,
1073    pub block_type: Option<String>,
1074    pub transaction_kind: Option<String>,
1075    pub timestamp_unix_nanos: Option<String>,
1076    pub amount_base_units: Option<String>,
1077    pub raw_block: JsonValue,
1078}
1079
1080///
1081/// IcrcArchiveFollowErrorRow
1082///
1083/// Serializable row for one archive callback that could not be followed.
1084///
1085
1086#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
1087pub struct IcrcArchiveFollowErrorRow {
1088    pub callback_canister_id: String,
1089    pub callback_method: String,
1090    pub ranges: Vec<IcrcArchivedRangeRow>,
1091    pub error: String,
1092}
1093
1094///
1095/// IcrcBlockTypeRow
1096///
1097/// Serializable row for one supported ICRC-3 block type.
1098///
1099
1100#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
1101pub struct IcrcBlockTypeRow {
1102    pub block_type: String,
1103    pub url: String,
1104}
1105
1106///
1107/// IcrcArchiveRow
1108///
1109/// Serializable row for one ICRC-3 archive range.
1110///
1111
1112#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
1113pub struct IcrcArchiveRow {
1114    pub canister_id: String,
1115    pub start: String,
1116    pub end: String,
1117}