ic_query/icrc/model/token_metadata/mod.rs
1//! Canonical token metadata payload and rows shared by ledger sources and SNS/ICRC reports.
2
3use serde::{Deserialize, Serialize};
4use serde_json::Value as JsonValue;
5
6///
7/// IcrcTokenData
8///
9/// Source-layer token metadata returned by an ICRC ledger.
10///
11
12#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
13pub struct IcrcTokenData {
14 /// Native ledger token name.
15 pub token_name: String,
16 /// Native ledger token symbol.
17 pub token_symbol: String,
18 /// Number of decimal places in a base-unit amount.
19 pub decimals: u8,
20 /// Transfer fee as exact base-10 base-unit text.
21 pub transfer_fee: String,
22 /// Total supply as exact base-10 base-unit text.
23 pub total_supply: String,
24 /// Optional minting-account owner in principal text.
25 pub minting_account_owner: Option<String>,
26 /// Optional raw minting subaccount in lowercase hexadecimal.
27 pub minting_account_subaccount_hex: Option<String>,
28 /// Standards advertised by the ledger.
29 pub supported_standards: Vec<IcrcTokenStandardRow>,
30 /// Raw ledger metadata preserving native value kinds.
31 pub metadata: Vec<IcrcTokenMetadataRow>,
32}
33
34///
35/// IcrcTokenStandardRow
36///
37/// Serializable row for one ICRC standard supported by a ledger.
38///
39
40#[cfg_attr(
41 any(feature = "icrc-host", feature = "sns-host"),
42 derive(ic_platform::candid::contract::CandidType)
43)]
44#[cfg_attr(
45 any(feature = "icrc-host", feature = "sns-host"),
46 candid_path("ic_platform::candid::contract")
47)]
48#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
49pub struct IcrcTokenStandardRow {
50 /// Standard name advertised by the ledger.
51 pub name: String,
52 /// Specification URL advertised by the ledger.
53 pub url: String,
54}
55
56///
57/// IcrcTokenMetadataRow
58///
59/// Serializable row for one raw ICRC ledger metadata entry.
60///
61
62#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
63pub struct IcrcTokenMetadataRow {
64 /// Native metadata key.
65 pub key: String,
66 /// Native Candid metadata variant.
67 pub value_type: IcrcMetadataValueKind,
68 /// Lossless decimal, text, or lowercase hexadecimal JSON string.
69 pub value: JsonValue,
70}
71
72///
73/// IcrcMetadataValueKind
74///
75/// Native ICRC-1 metadata value variant represented by a report row.
76///
77
78#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
79#[serde(rename_all = "snake_case")]
80pub enum IcrcMetadataValueKind {
81 /// An arbitrary-precision unsigned integer.
82 Nat,
83 /// An arbitrary-precision signed integer.
84 Int,
85 /// A Unicode text value.
86 Text,
87 /// An opaque byte sequence.
88 Blob,
89}
90
91impl IcrcMetadataValueKind {
92 /// Return the stable JSON and text label.
93 #[must_use]
94 pub const fn as_str(self) -> &'static str {
95 match self {
96 Self::Nat => "nat",
97 Self::Int => "int",
98 Self::Text => "text",
99 Self::Blob => "blob",
100 }
101 }
102}
103
104#[cfg(test)]
105mod tests;
106
107///
108/// IcrcIndexData
109///
110/// ICRC-106 discovery outcome shared by sources and serialized reports.
111///
112
113#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
114#[serde(rename_all = "snake_case")]
115pub enum IcrcIndexData {
116 /// Index principal returned by the ledger.
117 Found(String),
118 /// Index discovery is unavailable; source families own transport-error policy.
119 Unavailable(String),
120}
121
122impl IcrcIndexData {
123 /// Borrow the discovered index principal when discovery succeeded.
124 #[must_use]
125 pub fn canister_id(&self) -> Option<&str> {
126 match self {
127 Self::Found(principal) => Some(principal),
128 Self::Unavailable(_) => None,
129 }
130 }
131
132 /// Borrow the source's explanation when discovery is unavailable.
133 #[must_use]
134 pub fn unavailable_reason(&self) -> Option<&str> {
135 match self {
136 Self::Found(_) => None,
137 Self::Unavailable(reason) => Some(reason),
138 }
139 }
140}