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::Serialize;
8use serde_json::Value as JsonValue;
9
10///
11/// IcrcTokenRequest
12///
13/// Request accepted by the generic ICRC token metadata report builder.
14///
15
16#[derive(Clone, Debug, Eq, PartialEq)]
17pub struct IcrcTokenRequest {
18    pub source_endpoint: String,
19    pub now_unix_secs: u64,
20    pub ledger_canister_id: String,
21}
22
23impl IcrcTokenRequest {
24    #[must_use]
25    pub fn new(
26        source_endpoint: impl Into<String>,
27        now_unix_secs: u64,
28        ledger_canister_id: impl Into<String>,
29    ) -> Self {
30        Self {
31            source_endpoint: source_endpoint.into(),
32            now_unix_secs,
33            ledger_canister_id: ledger_canister_id.into(),
34        }
35    }
36}
37
38///
39/// IcrcBalanceRequest
40///
41/// Request accepted by the generic ICRC account balance report builder.
42///
43
44#[derive(Clone, Debug, Eq, PartialEq)]
45pub struct IcrcBalanceRequest {
46    pub source_endpoint: String,
47    pub now_unix_secs: u64,
48    pub ledger_canister_id: String,
49    pub account_owner: String,
50    pub subaccount_hex: Option<String>,
51}
52
53impl IcrcBalanceRequest {
54    #[must_use]
55    pub fn new(
56        source_endpoint: impl Into<String>,
57        now_unix_secs: u64,
58        ledger_canister_id: impl Into<String>,
59        account_owner: impl Into<String>,
60    ) -> Self {
61        Self {
62            source_endpoint: source_endpoint.into(),
63            now_unix_secs,
64            ledger_canister_id: ledger_canister_id.into(),
65            account_owner: account_owner.into(),
66            subaccount_hex: None,
67        }
68    }
69
70    #[must_use]
71    pub fn with_subaccount_hex(mut self, subaccount_hex: impl Into<String>) -> Self {
72        self.subaccount_hex = Some(subaccount_hex.into());
73        self
74    }
75}
76
77///
78/// IcrcAllowanceRequest
79///
80/// Request accepted by the generic ICRC allowance report builder.
81///
82
83#[derive(Clone, Debug, Eq, PartialEq)]
84pub struct IcrcAllowanceRequest {
85    pub source_endpoint: String,
86    pub now_unix_secs: u64,
87    pub ledger_canister_id: String,
88    pub account_owner: String,
89    pub account_subaccount_hex: Option<String>,
90    pub spender_owner: String,
91    pub spender_subaccount_hex: Option<String>,
92}
93
94impl IcrcAllowanceRequest {
95    #[must_use]
96    pub fn new(
97        source_endpoint: impl Into<String>,
98        now_unix_secs: u64,
99        ledger_canister_id: impl Into<String>,
100        account_owner: impl Into<String>,
101        spender_owner: impl Into<String>,
102    ) -> Self {
103        Self {
104            source_endpoint: source_endpoint.into(),
105            now_unix_secs,
106            ledger_canister_id: ledger_canister_id.into(),
107            account_owner: account_owner.into(),
108            account_subaccount_hex: None,
109            spender_owner: spender_owner.into(),
110            spender_subaccount_hex: None,
111        }
112    }
113
114    #[must_use]
115    pub fn with_account_subaccount_hex(
116        mut self,
117        account_subaccount_hex: impl Into<String>,
118    ) -> Self {
119        self.account_subaccount_hex = Some(account_subaccount_hex.into());
120        self
121    }
122
123    #[must_use]
124    pub fn with_spender_subaccount_hex(
125        mut self,
126        spender_subaccount_hex: impl Into<String>,
127    ) -> Self {
128        self.spender_subaccount_hex = Some(spender_subaccount_hex.into());
129        self
130    }
131}
132
133///
134/// IcrcAccountTransactionsRequest
135///
136/// Request accepted by the generic ICRC index account-transaction report builder.
137///
138
139#[derive(Clone, Debug, Eq, PartialEq)]
140pub struct IcrcAccountTransactionsRequest {
141    /// IC API endpoint used for ledger and index queries.
142    pub source_endpoint: String,
143    /// Collection time as Unix seconds.
144    pub now_unix_secs: u64,
145    /// Ledger canister whose account history is requested.
146    pub ledger_canister_id: String,
147    /// Optional explicit index canister; otherwise ICRC-106 discovery is used.
148    pub index_canister_id: Option<String>,
149    /// Account owner principal.
150    pub account_owner: String,
151    /// Optional normalized 32-byte subaccount hex.
152    pub subaccount_hex: Option<String>,
153    /// Optional exclusive block-index cursor for backward pagination.
154    pub start: Option<u64>,
155    /// Maximum number of account transactions to request.
156    pub limit: u32,
157}
158
159impl IcrcAccountTransactionsRequest {
160    /// Constructs an account-history request that discovers the index through the ledger.
161    #[must_use]
162    pub fn new(
163        source_endpoint: impl Into<String>,
164        now_unix_secs: u64,
165        ledger_canister_id: impl Into<String>,
166        account_owner: impl Into<String>,
167        limit: u32,
168    ) -> Self {
169        Self {
170            source_endpoint: source_endpoint.into(),
171            now_unix_secs,
172            ledger_canister_id: ledger_canister_id.into(),
173            index_canister_id: None,
174            account_owner: account_owner.into(),
175            subaccount_hex: None,
176            start: None,
177            limit,
178        }
179    }
180
181    /// Uses an explicit index canister instead of ICRC-106 discovery.
182    #[must_use]
183    pub fn with_index_canister_id(mut self, index_canister_id: impl Into<String>) -> Self {
184        self.index_canister_id = Some(index_canister_id.into());
185        self
186    }
187
188    /// Selects a 32-byte ICRC subaccount encoded as hex.
189    #[must_use]
190    pub fn with_subaccount_hex(mut self, subaccount_hex: impl Into<String>) -> Self {
191        self.subaccount_hex = Some(subaccount_hex.into());
192        self
193    }
194
195    /// Starts after the given transaction block index when paginating backward.
196    #[must_use]
197    pub const fn with_start(mut self, start: u64) -> Self {
198        self.start = Some(start);
199        self
200    }
201}
202
203///
204/// IcrcIndexRequest
205///
206/// Request accepted by the generic ICRC index discovery report builder.
207///
208
209#[derive(Clone, Debug, Eq, PartialEq)]
210pub struct IcrcIndexRequest {
211    pub source_endpoint: String,
212    pub now_unix_secs: u64,
213    pub ledger_canister_id: String,
214}
215
216impl IcrcIndexRequest {
217    #[must_use]
218    pub fn new(
219        source_endpoint: impl Into<String>,
220        now_unix_secs: u64,
221        ledger_canister_id: impl Into<String>,
222    ) -> Self {
223        Self {
224            source_endpoint: source_endpoint.into(),
225            now_unix_secs,
226            ledger_canister_id: ledger_canister_id.into(),
227        }
228    }
229}
230
231///
232/// IcrcTransactionsRequest
233///
234/// Request accepted by the generic ICRC transaction history report builder.
235///
236
237#[derive(Clone, Debug, Eq, PartialEq)]
238pub struct IcrcTransactionsRequest {
239    pub source_endpoint: String,
240    pub now_unix_secs: u64,
241    pub ledger_canister_id: String,
242    pub start: u64,
243    pub limit: u32,
244    pub follow_archives: bool,
245}
246
247impl IcrcTransactionsRequest {
248    #[must_use]
249    pub fn new(
250        source_endpoint: impl Into<String>,
251        now_unix_secs: u64,
252        ledger_canister_id: impl Into<String>,
253        start: u64,
254        limit: u32,
255    ) -> Self {
256        Self {
257            source_endpoint: source_endpoint.into(),
258            now_unix_secs,
259            ledger_canister_id: ledger_canister_id.into(),
260            start,
261            limit,
262            follow_archives: false,
263        }
264    }
265
266    #[must_use]
267    pub const fn with_follow_archives(mut self, follow_archives: bool) -> Self {
268        self.follow_archives = follow_archives;
269        self
270    }
271}
272
273///
274/// IcrcBlockTypesRequest
275///
276/// Request accepted by the generic ICRC supported block types report builder.
277///
278
279#[derive(Clone, Debug, Eq, PartialEq)]
280pub struct IcrcBlockTypesRequest {
281    pub source_endpoint: String,
282    pub now_unix_secs: u64,
283    pub ledger_canister_id: String,
284}
285
286impl IcrcBlockTypesRequest {
287    #[must_use]
288    pub fn new(
289        source_endpoint: impl Into<String>,
290        now_unix_secs: u64,
291        ledger_canister_id: impl Into<String>,
292    ) -> Self {
293        Self {
294            source_endpoint: source_endpoint.into(),
295            now_unix_secs,
296            ledger_canister_id: ledger_canister_id.into(),
297        }
298    }
299}
300
301///
302/// IcrcArchivesRequest
303///
304/// Request accepted by the generic ICRC archives report builder.
305///
306
307#[derive(Clone, Debug, Eq, PartialEq)]
308pub struct IcrcArchivesRequest {
309    pub source_endpoint: String,
310    pub now_unix_secs: u64,
311    pub ledger_canister_id: String,
312    pub from_canister_id: Option<String>,
313}
314
315impl IcrcArchivesRequest {
316    #[must_use]
317    pub fn new(
318        source_endpoint: impl Into<String>,
319        now_unix_secs: u64,
320        ledger_canister_id: impl Into<String>,
321    ) -> Self {
322        Self {
323            source_endpoint: source_endpoint.into(),
324            now_unix_secs,
325            ledger_canister_id: ledger_canister_id.into(),
326            from_canister_id: None,
327        }
328    }
329
330    #[must_use]
331    pub fn with_from_canister_id(mut self, from_canister_id: impl Into<String>) -> Self {
332        self.from_canister_id = Some(from_canister_id.into());
333        self
334    }
335}
336
337///
338/// IcrcTipCertificateRequest
339///
340/// Request accepted by the generic ICRC-3 tip certificate report builder.
341///
342
343#[derive(Clone, Debug, Eq, PartialEq)]
344pub struct IcrcTipCertificateRequest {
345    pub source_endpoint: String,
346    pub now_unix_secs: u64,
347    pub ledger_canister_id: String,
348}
349
350impl IcrcTipCertificateRequest {
351    #[must_use]
352    pub fn new(
353        source_endpoint: impl Into<String>,
354        now_unix_secs: u64,
355        ledger_canister_id: impl Into<String>,
356    ) -> Self {
357        Self {
358            source_endpoint: source_endpoint.into(),
359            now_unix_secs,
360            ledger_canister_id: ledger_canister_id.into(),
361        }
362    }
363}
364
365///
366/// IcrcCapabilitiesRequest
367///
368/// Request accepted by the generic ICRC ledger capabilities report builder.
369///
370
371#[derive(Clone, Debug, Eq, PartialEq)]
372pub struct IcrcCapabilitiesRequest {
373    pub source_endpoint: String,
374    pub now_unix_secs: u64,
375    pub ledger_canister_id: String,
376}
377
378impl IcrcCapabilitiesRequest {
379    #[must_use]
380    pub fn new(
381        source_endpoint: impl Into<String>,
382        now_unix_secs: u64,
383        ledger_canister_id: impl Into<String>,
384    ) -> Self {
385        Self {
386            source_endpoint: source_endpoint.into(),
387            now_unix_secs,
388            ledger_canister_id: ledger_canister_id.into(),
389        }
390    }
391}
392
393///
394/// IcrcTokenReport
395///
396/// Serializable report for generic ICRC ledger token metadata.
397///
398
399#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
400pub struct IcrcTokenReport {
401    pub schema_version: u32,
402    pub ledger_canister_id: String,
403    pub fetched_at: String,
404    pub source_endpoint: String,
405    pub fetched_by: String,
406    pub token_name: String,
407    pub token_symbol: String,
408    pub decimals: u8,
409    pub transfer_fee: String,
410    pub total_supply: String,
411    pub minting_account_owner: Option<String>,
412    pub minting_account_subaccount_hex: Option<String>,
413    pub supported_standards: Vec<IcrcTokenStandardRow>,
414    pub metadata: Vec<IcrcTokenMetadataRow>,
415}
416
417///
418/// IcrcBalanceReport
419///
420/// Serializable report for one generic ICRC account balance lookup.
421///
422
423#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
424pub struct IcrcBalanceReport {
425    pub schema_version: u32,
426    pub ledger_canister_id: String,
427    pub account_owner: String,
428    pub subaccount_hex: Option<String>,
429    pub fetched_at: String,
430    pub source_endpoint: String,
431    pub fetched_by: String,
432    pub token_symbol: String,
433    pub decimals: u8,
434    pub balance: String,
435}
436
437///
438/// IcrcAllowanceReport
439///
440/// Serializable report for one generic ICRC allowance lookup.
441///
442
443#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
444pub struct IcrcAllowanceReport {
445    pub schema_version: u32,
446    pub ledger_canister_id: String,
447    pub account_owner: String,
448    pub account_subaccount_hex: Option<String>,
449    pub spender_owner: String,
450    pub spender_subaccount_hex: Option<String>,
451    pub fetched_at: String,
452    pub source_endpoint: String,
453    pub fetched_by: String,
454    pub token_symbol: String,
455    pub decimals: u8,
456    pub allowance: String,
457    pub expires_at_unix_nanos: Option<String>,
458}
459
460///
461/// IcrcAccountTransactionsReport
462///
463/// Serializable report for a backward page of ICRC index account transactions.
464///
465
466#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
467pub struct IcrcAccountTransactionsReport {
468    /// Report schema version.
469    pub schema_version: u32,
470    /// Ledger canister whose transactions were indexed.
471    pub ledger_canister_id: String,
472    /// Index canister that answered the account-history query.
473    pub index_canister_id: String,
474    /// Queried account owner principal.
475    pub account_owner: String,
476    /// Queried subaccount as normalized hex.
477    pub subaccount_hex: Option<String>,
478    /// Exclusive block-index cursor supplied by the caller.
479    pub requested_start: Option<String>,
480    /// Maximum number of transactions requested.
481    pub requested_limit: u32,
482    /// Cursor to pass as `start` to request the next older page.
483    pub next_start: Option<String>,
484    /// Oldest transaction id known for this account.
485    pub oldest_transaction_id: Option<String>,
486    /// Account balance reported by the index at its synchronized tip.
487    pub balance: String,
488    /// Ledger token symbol used for text rendering.
489    pub token_symbol: String,
490    /// Ledger token decimals used for text rendering.
491    pub decimals: u8,
492    /// Collection timestamp in UTC text form.
493    pub fetched_at: String,
494    /// IC API endpoint used for ledger and index calls.
495    pub source_endpoint: String,
496    /// Collector identity.
497    pub fetched_by: String,
498    /// Transactions returned by the index in its native page order.
499    pub transactions: Vec<IcrcAccountTransactionRow>,
500}
501
502///
503/// IcrcIndexReport
504///
505/// Serializable report for one generic ICRC-106 index discovery lookup.
506///
507
508#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
509pub struct IcrcIndexReport {
510    pub schema_version: u32,
511    pub ledger_canister_id: String,
512    pub fetched_at: String,
513    pub source_endpoint: String,
514    pub fetched_by: String,
515    pub index_canister_id: Option<String>,
516    pub index_error: Option<String>,
517}
518
519///
520/// IcrcTransactionsReport
521///
522/// Serializable report for a generic ICRC ledger transaction/block history page.
523///
524
525#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
526pub struct IcrcTransactionsReport {
527    pub schema_version: u32,
528    pub ledger_canister_id: String,
529    pub fetched_at: String,
530    pub source_endpoint: String,
531    pub fetched_by: String,
532    pub requested_start: String,
533    pub requested_limit: u32,
534    pub follow_archives: bool,
535    pub log_length: Option<String>,
536    pub blocks: Vec<IcrcTransactionBlockRow>,
537    pub archived_blocks: Vec<IcrcArchivedBlocksRow>,
538    pub followed_archive_blocks: Vec<IcrcFollowedArchiveBlockRow>,
539    pub archive_follow_errors: Vec<IcrcArchiveFollowErrorRow>,
540}
541
542///
543/// IcrcBlockTypesReport
544///
545/// Serializable report for generic ICRC-3 supported block type discovery.
546///
547
548#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
549pub struct IcrcBlockTypesReport {
550    pub schema_version: u32,
551    pub ledger_canister_id: String,
552    pub fetched_at: String,
553    pub source_endpoint: String,
554    pub fetched_by: String,
555    pub block_types: Vec<IcrcBlockTypeRow>,
556}
557
558///
559/// IcrcArchivesReport
560///
561/// Serializable report for generic ICRC-3 archive range discovery.
562///
563
564#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
565pub struct IcrcArchivesReport {
566    pub schema_version: u32,
567    pub ledger_canister_id: String,
568    pub from_canister_id: Option<String>,
569    pub fetched_at: String,
570    pub source_endpoint: String,
571    pub fetched_by: String,
572    pub archives: Vec<IcrcArchiveRow>,
573}
574
575///
576/// IcrcTipCertificateReport
577///
578/// Serializable report for a generic ICRC-3 ledger tip certificate.
579///
580
581#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
582pub struct IcrcTipCertificateReport {
583    pub schema_version: u32,
584    pub ledger_canister_id: String,
585    pub fetched_at: String,
586    pub source_endpoint: String,
587    pub fetched_by: String,
588    pub certificate_present: bool,
589    pub certificate_hex: Option<String>,
590    pub certificate_bytes: Option<usize>,
591    pub hash_tree_hex: Option<String>,
592    pub hash_tree_bytes: Option<usize>,
593}
594
595///
596/// IcrcCapabilitiesReport
597///
598/// Serializable report for generic ICRC ledger endpoint capabilities.
599///
600
601#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
602pub struct IcrcCapabilitiesReport {
603    pub schema_version: u32,
604    pub ledger_canister_id: String,
605    pub fetched_at: String,
606    pub source_endpoint: String,
607    pub fetched_by: String,
608    pub supported_standards: Vec<IcrcTokenStandardRow>,
609    pub capabilities: Vec<IcrcCapabilityRow>,
610}
611
612///
613/// IcrcCapabilityRow
614///
615/// Serializable row for one probed generic ICRC ledger capability.
616///
617
618#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
619pub struct IcrcCapabilityRow {
620    pub capability: String,
621    pub method: String,
622    pub status: String,
623    pub details: Option<String>,
624    pub error: Option<String>,
625}
626
627///
628/// IcrcTokenStandardRow
629///
630/// Serializable row for one ICRC standard supported by a ledger.
631///
632
633#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
634pub struct IcrcTokenStandardRow {
635    pub name: String,
636    pub url: String,
637}
638
639///
640/// IcrcTokenMetadataRow
641///
642/// Serializable row for one raw ICRC ledger metadata entry.
643///
644
645#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
646pub struct IcrcTokenMetadataRow {
647    pub key: String,
648    pub value_type: String,
649    pub value: JsonValue,
650}
651
652///
653/// IcrcAccountRow
654///
655/// Serializable ICRC account identity used in account-transaction rows.
656///
657
658#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
659pub struct IcrcAccountRow {
660    /// ICRC account owner principal when the index uses structured accounts.
661    pub owner: Option<String>,
662    /// Optional 32-byte subaccount as lowercase hex.
663    pub subaccount_hex: Option<String>,
664    /// Legacy ICP account identifier when the index returns identifier text.
665    pub account_identifier: Option<String>,
666}
667
668///
669/// IcrcAccountTransactionRow
670///
671/// Serializable projected and lossless JSON representation of one index transaction.
672///
673
674#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
675pub struct IcrcAccountTransactionRow {
676    /// Ledger block index of the transaction.
677    pub id: String,
678    /// Index-reported transaction kind.
679    pub kind: String,
680    /// Ledger transaction timestamp as Unix nanoseconds when present.
681    pub timestamp_unix_nanos: Option<String>,
682    /// Operation amount in ledger base units when the operation carries one.
683    pub amount_base_units: Option<String>,
684    /// Operation fee in ledger base units when the operation carries one.
685    pub fee_base_units: Option<String>,
686    /// Source account when present.
687    pub from: Option<IcrcAccountRow>,
688    /// Destination account when present.
689    pub to: Option<IcrcAccountRow>,
690    /// Spender account when present.
691    pub spender: Option<IcrcAccountRow>,
692    /// Operation memo as lowercase hex when present.
693    pub memo_hex: Option<String>,
694    /// Caller-supplied creation time as Unix nanoseconds when present.
695    pub created_at_time_unix_nanos: Option<String>,
696    /// Approval expiry as Unix nanoseconds when present.
697    pub expires_at_unix_nanos: Option<String>,
698    /// Expected prior allowance in base units when present.
699    pub expected_allowance_base_units: Option<String>,
700    /// Lossless JSON projection of every typed transaction field returned by the index.
701    pub raw_transaction: JsonValue,
702}
703
704///
705/// IcrcTransactionBlockRow
706///
707/// Serializable row for one ICRC-3 block returned by a ledger canister.
708///
709
710#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
711pub struct IcrcTransactionBlockRow {
712    pub index: String,
713    pub block_type: Option<String>,
714    pub transaction_kind: Option<String>,
715    pub timestamp_unix_nanos: Option<String>,
716    pub amount_base_units: Option<String>,
717    pub raw_block: JsonValue,
718}
719
720///
721/// IcrcArchivedBlocksRow
722///
723/// Serializable row for one ICRC-3 archive callback returned by a ledger canister.
724///
725
726#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
727pub struct IcrcArchivedBlocksRow {
728    pub callback_canister_id: String,
729    pub callback_method: String,
730    pub ranges: Vec<IcrcArchivedRangeRow>,
731}
732
733///
734/// IcrcArchivedRangeRow
735///
736/// Serializable row for one ICRC-3 archived block range.
737///
738
739#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
740pub struct IcrcArchivedRangeRow {
741    pub start: String,
742    pub length: String,
743}
744
745///
746/// IcrcFollowedArchiveBlockRow
747///
748/// Serializable row for one ICRC-3 block fetched from an archive callback.
749///
750
751#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
752pub struct IcrcFollowedArchiveBlockRow {
753    pub archive_canister_id: String,
754    pub callback_method: String,
755    pub index: String,
756    pub block_type: Option<String>,
757    pub transaction_kind: Option<String>,
758    pub timestamp_unix_nanos: Option<String>,
759    pub amount_base_units: Option<String>,
760    pub raw_block: JsonValue,
761}
762
763///
764/// IcrcArchiveFollowErrorRow
765///
766/// Serializable row for one archive callback that could not be followed.
767///
768
769#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
770pub struct IcrcArchiveFollowErrorRow {
771    pub callback_canister_id: String,
772    pub callback_method: String,
773    pub ranges: Vec<IcrcArchivedRangeRow>,
774    pub error: String,
775}
776
777///
778/// IcrcBlockTypeRow
779///
780/// Serializable row for one supported ICRC-3 block type.
781///
782
783#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
784pub struct IcrcBlockTypeRow {
785    pub block_type: String,
786    pub url: String,
787}
788
789///
790/// IcrcArchiveRow
791///
792/// Serializable row for one ICRC-3 archive range.
793///
794
795#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
796pub struct IcrcArchiveRow {
797    pub canister_id: String,
798    pub start: String,
799    pub end: String,
800}