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 serde::{Deserialize, Serialize};
8use serde_json::Value as JsonValue;
9
10///
11/// IcrcTokenReport
12///
13/// Serializable report for generic ICRC ledger token metadata.
14///
15
16#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
17pub struct IcrcTokenReport {
18    pub schema_version: u32,
19    pub ledger_canister_id: String,
20    pub fetched_at: String,
21    pub source_endpoint: String,
22    pub fetched_by: String,
23    pub token_name: String,
24    pub token_symbol: String,
25    pub decimals: u8,
26    pub transfer_fee: String,
27    pub total_supply: String,
28    pub minting_account_owner: Option<String>,
29    pub minting_account_subaccount_hex: Option<String>,
30    pub supported_standards: Vec<IcrcTokenStandardRow>,
31    pub metadata: Vec<IcrcTokenMetadataRow>,
32}
33
34///
35/// IcrcIndexReport
36///
37/// Serializable report for one generic ICRC-106 index discovery lookup.
38///
39
40#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
41pub struct IcrcIndexReport {
42    pub schema_version: u32,
43    pub ledger_canister_id: String,
44    pub fetched_at: String,
45    pub source_endpoint: String,
46    pub fetched_by: String,
47    pub index_canister_id: Option<String>,
48    pub index_error: Option<String>,
49}
50
51///
52/// IcrcTransactionsReport
53///
54/// Serializable report for a generic ICRC ledger transaction/block history page.
55///
56
57#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
58pub struct IcrcTransactionsReport {
59    pub schema_version: u32,
60    pub ledger_canister_id: String,
61    pub fetched_at: String,
62    pub source_endpoint: String,
63    pub fetched_by: String,
64    pub requested_start: String,
65    pub requested_limit: u32,
66    pub follow_archives: bool,
67    pub log_length: Option<String>,
68    pub blocks: Vec<IcrcTransactionBlockRow>,
69    pub archived_blocks: Vec<IcrcArchivedBlocksRow>,
70    pub followed_archive_blocks: Vec<IcrcFollowedArchiveBlockRow>,
71    pub archive_follow_errors: Vec<IcrcArchiveFollowErrorRow>,
72}
73
74///
75/// IcrcBlockTypesReport
76///
77/// Serializable report for generic ICRC-3 supported block type discovery.
78///
79
80#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
81pub struct IcrcBlockTypesReport {
82    pub schema_version: u32,
83    pub ledger_canister_id: String,
84    pub fetched_at: String,
85    pub source_endpoint: String,
86    pub fetched_by: String,
87    pub block_types: Vec<IcrcBlockTypeRow>,
88}
89
90///
91/// IcrcArchivesReport
92///
93/// Serializable report for generic ICRC-3 archive range discovery.
94///
95
96#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
97pub struct IcrcArchivesReport {
98    pub schema_version: u32,
99    pub ledger_canister_id: String,
100    pub from_canister_id: Option<String>,
101    pub fetched_at: String,
102    pub source_endpoint: String,
103    pub fetched_by: String,
104    pub archives: Vec<IcrcArchiveRow>,
105}
106
107///
108/// IcrcTipCertificateReport
109///
110/// Serializable report for a generic ICRC-3 ledger tip certificate.
111///
112
113#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
114pub struct IcrcTipCertificateReport {
115    pub schema_version: u32,
116    pub ledger_canister_id: String,
117    pub fetched_at: String,
118    pub source_endpoint: String,
119    pub fetched_by: String,
120    pub certificate_present: bool,
121    pub certificate_hex: Option<String>,
122    pub certificate_bytes: Option<usize>,
123    pub hash_tree_hex: Option<String>,
124    pub hash_tree_bytes: Option<usize>,
125}
126
127///
128/// IcrcCapabilitiesReport
129///
130/// Serializable report for generic ICRC ledger endpoint capabilities.
131///
132
133#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
134pub struct IcrcCapabilitiesReport {
135    pub schema_version: u32,
136    pub ledger_canister_id: String,
137    pub fetched_at: String,
138    pub source_endpoint: String,
139    pub fetched_by: String,
140    pub supported_standards: Vec<IcrcTokenStandardRow>,
141    pub capabilities: Vec<IcrcCapabilityRow>,
142}
143
144///
145/// IcrcCapabilityRow
146///
147/// Serializable row for one probed generic ICRC ledger capability.
148///
149
150#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
151pub struct IcrcCapabilityRow {
152    pub capability: String,
153    pub method: String,
154    pub status: IcrcCapabilityStatus,
155    pub details: Option<String>,
156    pub error: Option<String>,
157}
158
159///
160/// IcrcCapabilityStatus
161///
162/// Result of probing one optional ICRC ledger capability.
163///
164
165#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize)]
166#[serde(rename_all = "snake_case")]
167pub enum IcrcCapabilityStatus {
168    /// The target answered the capability query successfully.
169    Available,
170    /// The target does not export the probed query method.
171    Unsupported,
172    /// The target exports the method but the query failed.
173    Error,
174}
175
176impl IcrcCapabilityStatus {
177    /// Return the stable JSON and text label.
178    #[must_use]
179    pub const fn as_str(self) -> &'static str {
180        match self {
181            Self::Available => "available",
182            Self::Unsupported => "unsupported",
183            Self::Error => "error",
184        }
185    }
186}
187
188///
189/// IcrcTokenStandardRow
190///
191/// Serializable row for one ICRC standard supported by a ledger.
192///
193
194#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
195pub struct IcrcTokenStandardRow {
196    pub name: String,
197    pub url: String,
198}
199
200///
201/// IcrcTokenMetadataRow
202///
203/// Serializable row for one raw ICRC ledger metadata entry.
204///
205
206#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
207pub struct IcrcTokenMetadataRow {
208    pub key: String,
209    pub value_type: IcrcMetadataValueKind,
210    pub value: JsonValue,
211}
212
213///
214/// IcrcMetadataValueKind
215///
216/// Native ICRC-1 metadata value variant represented by a report row.
217///
218
219#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
220#[serde(rename_all = "snake_case")]
221pub enum IcrcMetadataValueKind {
222    /// An arbitrary-precision unsigned integer.
223    Nat,
224    /// An arbitrary-precision signed integer.
225    Int,
226    /// A Unicode text value.
227    Text,
228    /// An opaque byte sequence.
229    Blob,
230}
231
232impl IcrcMetadataValueKind {
233    /// Return the stable JSON and text label.
234    #[must_use]
235    pub const fn as_str(self) -> &'static str {
236        match self {
237            Self::Nat => "nat",
238            Self::Int => "int",
239            Self::Text => "text",
240            Self::Blob => "blob",
241        }
242    }
243}
244
245///
246/// IcrcTransactionBlockRow
247///
248/// Serializable row for one ICRC-3 block returned by a ledger canister.
249///
250
251#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
252pub struct IcrcTransactionBlockRow {
253    pub index: String,
254    pub block_type: Option<String>,
255    pub transaction_kind: Option<String>,
256    pub timestamp_unix_nanos: Option<String>,
257    pub amount_base_units: Option<String>,
258    pub raw_block: JsonValue,
259}
260
261///
262/// IcrcArchivedBlocksRow
263///
264/// Serializable row for one ICRC-3 archive callback returned by a ledger canister.
265///
266
267#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
268pub struct IcrcArchivedBlocksRow {
269    pub callback_canister_id: String,
270    pub callback_method: String,
271    pub ranges: Vec<IcrcArchivedRangeRow>,
272}
273
274///
275/// IcrcArchivedRangeRow
276///
277/// Serializable row for one ICRC-3 archived block range.
278///
279
280#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
281pub struct IcrcArchivedRangeRow {
282    pub start: String,
283    pub length: String,
284}
285
286///
287/// IcrcFollowedArchiveBlockRow
288///
289/// Serializable row for one ICRC-3 block fetched from an archive callback.
290///
291
292#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
293pub struct IcrcFollowedArchiveBlockRow {
294    pub archive_canister_id: String,
295    pub callback_method: String,
296    pub index: String,
297    pub block_type: Option<String>,
298    pub transaction_kind: Option<String>,
299    pub timestamp_unix_nanos: Option<String>,
300    pub amount_base_units: Option<String>,
301    pub raw_block: JsonValue,
302}
303
304#[cfg(test)]
305mod tests {
306    use super::*;
307
308    #[test]
309    fn capability_status_labels_are_stable() {
310        for (status, label) in [
311            (IcrcCapabilityStatus::Available, "available"),
312            (IcrcCapabilityStatus::Unsupported, "unsupported"),
313            (IcrcCapabilityStatus::Error, "error"),
314        ] {
315            assert_eq!(
316                serde_json::to_string(&status).unwrap(),
317                format!("\"{label}\"")
318            );
319            assert_eq!(status.as_str(), label);
320        }
321    }
322
323    #[test]
324    fn metadata_value_kind_labels_round_trip() {
325        for (kind, label) in [
326            (IcrcMetadataValueKind::Nat, "nat"),
327            (IcrcMetadataValueKind::Int, "int"),
328            (IcrcMetadataValueKind::Text, "text"),
329            (IcrcMetadataValueKind::Blob, "blob"),
330        ] {
331            assert_eq!(
332                serde_json::to_string(&kind).unwrap(),
333                format!("\"{label}\"")
334            );
335            assert_eq!(
336                serde_json::from_str::<IcrcMetadataValueKind>(&format!("\"{label}\"")).unwrap(),
337                kind
338            );
339            assert_eq!(kind.as_str(), label);
340        }
341    }
342}
343
344///
345/// IcrcArchiveFollowErrorRow
346///
347/// Serializable row for one archive callback that could not be followed.
348///
349
350#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
351pub struct IcrcArchiveFollowErrorRow {
352    pub callback_canister_id: String,
353    pub callback_method: String,
354    pub ranges: Vec<IcrcArchivedRangeRow>,
355    pub error: String,
356}
357
358///
359/// IcrcBlockTypeRow
360///
361/// Serializable row for one supported ICRC-3 block type.
362///
363
364#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
365pub struct IcrcBlockTypeRow {
366    pub block_type: String,
367    pub url: String,
368}
369
370///
371/// IcrcArchiveRow
372///
373/// Serializable row for one ICRC-3 archive range.
374///
375
376#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
377pub struct IcrcArchiveRow {
378    pub canister_id: String,
379    pub start: String,
380    pub end: String,
381}