Skip to main content

ic_query/icrc/model/contracts/reports/
ledger.rs

1//! Module: icrc::model::contracts::reports::ledger
2//!
3//! Responsibility: serialized ICRC ledger metadata, capability, and history contracts.
4//! Does not own: account-index history, requests, live transport, archive following, or rendering.
5//! Boundary: preserves raw ledger, block, archive, certificate, and capability fields.
6
7use crate::icrc::{IcrcTokenData, IcrcTokenStandardRow};
8use serde::Serialize;
9use serde_json::Value as JsonValue;
10
11///
12/// IcrcTokenReport
13///
14/// Serializable report for generic ICRC ledger token metadata.
15///
16
17#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
18pub struct IcrcTokenReport {
19    pub schema_version: u32,
20    pub ledger_canister_id: String,
21    pub fetched_at: String,
22    pub source_endpoint: String,
23    pub fetched_by: String,
24    /// Raw ledger metadata shared with token source capabilities.
25    #[serde(flatten)]
26    pub token: IcrcTokenData,
27}
28
29///
30/// IcrcIndexReport
31///
32/// Serializable report for one generic ICRC-106 index discovery lookup.
33///
34
35#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
36pub struct IcrcIndexReport {
37    pub schema_version: u32,
38    pub ledger_canister_id: String,
39    pub fetched_at: String,
40    pub source_endpoint: String,
41    pub fetched_by: String,
42    pub index_canister_id: Option<String>,
43    pub index_error: Option<String>,
44}
45
46///
47/// IcrcTransactionsData
48///
49/// Source-layer ICRC-3 block history result from a ledger canister.
50///
51
52#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
53pub struct IcrcTransactionsData {
54    /// Total number of blocks as a decimal natural, or unknown for custom sources.
55    /// Returned blocks and archive ranges must stay below this length when known.
56    pub log_length: Option<String>,
57    /// Blocks returned directly by the ledger.
58    pub blocks: Vec<IcrcTransactionBlockRow>,
59    /// Archive referrals returned for the requested page.
60    pub archived_blocks: Vec<IcrcArchivedBlocksRow>,
61    /// Blocks retained from successful archive callbacks.
62    pub followed_archive_blocks: Vec<IcrcFollowedArchiveBlockRow>,
63    /// Bounded failures retained while following archive callbacks.
64    pub archive_follow_errors: Vec<IcrcArchiveFollowErrorRow>,
65}
66
67///
68/// IcrcTransactionsReport
69///
70/// Serializable report for a generic ICRC ledger transaction/block history page.
71///
72
73#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
74pub struct IcrcTransactionsReport {
75    pub schema_version: u32,
76    pub ledger_canister_id: String,
77    pub fetched_at: String,
78    pub source_endpoint: String,
79    pub fetched_by: String,
80    pub requested_start: String,
81    pub requested_limit: u32,
82    pub follow_archives: bool,
83    /// Canonical history payload.
84    #[serde(flatten)]
85    pub transactions: IcrcTransactionsData,
86}
87
88///
89/// IcrcBlockTypesReport
90///
91/// Serializable report for generic ICRC-3 supported block type discovery.
92///
93
94#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
95pub struct IcrcBlockTypesReport {
96    pub schema_version: u32,
97    pub ledger_canister_id: String,
98    pub fetched_at: String,
99    pub source_endpoint: String,
100    pub fetched_by: String,
101    pub block_types: Vec<IcrcBlockTypeRow>,
102}
103
104///
105/// IcrcArchivesReport
106///
107/// Serializable report for generic ICRC-3 archive range discovery.
108///
109
110#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
111pub struct IcrcArchivesReport {
112    pub schema_version: u32,
113    pub ledger_canister_id: String,
114    pub from_canister_id: Option<String>,
115    pub fetched_at: String,
116    pub source_endpoint: String,
117    pub fetched_by: String,
118    pub archives: Vec<IcrcArchiveRow>,
119}
120
121///
122/// IcrcTipCertificateReport
123///
124/// Serializable report for a generic ICRC-3 ledger tip certificate.
125///
126
127#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
128pub struct IcrcTipCertificateReport {
129    pub schema_version: u32,
130    pub ledger_canister_id: String,
131    pub fetched_at: String,
132    pub source_endpoint: String,
133    pub fetched_by: String,
134    pub certificate_present: bool,
135    pub certificate_hex: Option<String>,
136    pub certificate_bytes: Option<usize>,
137    pub hash_tree_hex: Option<String>,
138    pub hash_tree_bytes: Option<usize>,
139}
140
141///
142/// IcrcCapabilitiesReport
143///
144/// Serializable report for generic ICRC ledger endpoint capabilities.
145///
146
147#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
148pub struct IcrcCapabilitiesReport {
149    pub schema_version: u32,
150    pub ledger_canister_id: String,
151    pub fetched_at: String,
152    pub source_endpoint: String,
153    pub fetched_by: String,
154    pub supported_standards: Vec<IcrcTokenStandardRow>,
155    pub capabilities: Vec<IcrcCapabilityRow>,
156}
157
158///
159/// IcrcCapabilityRow
160///
161/// Serializable row for one probed generic ICRC ledger capability.
162///
163
164#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
165pub struct IcrcCapabilityRow {
166    pub capability: String,
167    pub method: String,
168    pub status: IcrcCapabilityStatus,
169    pub details: Option<String>,
170    pub error: Option<String>,
171}
172
173///
174/// IcrcCapabilityStatus
175///
176/// Result of probing one optional ICRC ledger capability.
177///
178
179#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize)]
180#[serde(rename_all = "snake_case")]
181pub enum IcrcCapabilityStatus {
182    /// The target answered the capability query successfully.
183    Available,
184    /// The target does not export the probed query method.
185    Unsupported,
186    /// The target exports the method but the query failed.
187    Error,
188}
189
190impl IcrcCapabilityStatus {
191    /// Return the stable JSON and text label.
192    #[must_use]
193    pub const fn as_str(self) -> &'static str {
194        match self {
195            Self::Available => "available",
196            Self::Unsupported => "unsupported",
197            Self::Error => "error",
198        }
199    }
200}
201
202///
203/// IcrcTransactionBlockRow
204///
205/// Serializable row for one ICRC-3 block returned by a ledger canister.
206///
207
208#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
209pub struct IcrcTransactionBlockRow {
210    pub index: String,
211    pub block_type: Option<String>,
212    pub transaction_kind: Option<String>,
213    pub timestamp_unix_nanos: Option<String>,
214    pub amount_base_units: Option<String>,
215    pub raw_block: JsonValue,
216}
217
218///
219/// IcrcArchivedBlocksRow
220///
221/// Serializable row for one ICRC-3 archive callback returned by a ledger canister.
222///
223
224#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
225pub struct IcrcArchivedBlocksRow {
226    pub callback_canister_id: String,
227    pub callback_method: String,
228    pub ranges: Vec<IcrcArchivedRangeRow>,
229}
230
231///
232/// IcrcArchivedRangeRow
233///
234/// Serializable row for one ICRC-3 archived block range.
235///
236
237#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
238pub struct IcrcArchivedRangeRow {
239    pub start: String,
240    pub length: String,
241}
242
243///
244/// IcrcFollowedArchiveBlockRow
245///
246/// Serializable row for one ICRC-3 block fetched from an archive callback.
247///
248
249#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
250pub struct IcrcFollowedArchiveBlockRow {
251    pub archive_canister_id: String,
252    pub callback_method: String,
253    /// Canonical block summary and raw evidence.
254    #[serde(flatten)]
255    pub block: IcrcTransactionBlockRow,
256}
257
258#[cfg(test)]
259mod tests {
260    use super::*;
261
262    #[test]
263    fn capability_status_labels_are_stable() {
264        for (status, label) in [
265            (IcrcCapabilityStatus::Available, "available"),
266            (IcrcCapabilityStatus::Unsupported, "unsupported"),
267            (IcrcCapabilityStatus::Error, "error"),
268        ] {
269            assert_eq!(
270                serde_json::to_string(&status).unwrap(),
271                format!("\"{label}\"")
272            );
273            assert_eq!(status.as_str(), label);
274        }
275    }
276}
277
278///
279/// IcrcArchiveFollowErrorRow
280///
281/// Serializable row for one archive callback that could not be followed.
282///
283
284#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
285pub struct IcrcArchiveFollowErrorRow {
286    pub callback_canister_id: String,
287    pub callback_method: String,
288    pub ranges: Vec<IcrcArchivedRangeRow>,
289    pub error: String,
290}
291
292///
293/// IcrcBlockTypeRow
294///
295/// Serializable row for one supported ICRC-3 block type.
296///
297
298#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
299pub struct IcrcBlockTypeRow {
300    pub block_type: String,
301    pub url: String,
302}
303
304///
305/// IcrcArchiveRow
306///
307/// Serializable row for one ICRC-3 archive range.
308///
309
310#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
311pub struct IcrcArchiveRow {
312    pub canister_id: String,
313    pub start: String,
314    pub end: String,
315}