Skip to main content

ic_query/icrc/model/
token_metadata.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(candid::CandidType)
43)]
44#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
45pub struct IcrcTokenStandardRow {
46    /// Standard name advertised by the ledger.
47    pub name: String,
48    /// Specification URL advertised by the ledger.
49    pub url: String,
50}
51
52///
53/// IcrcTokenMetadataRow
54///
55/// Serializable row for one raw ICRC ledger metadata entry.
56///
57
58#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
59pub struct IcrcTokenMetadataRow {
60    /// Native metadata key.
61    pub key: String,
62    /// Native Candid metadata variant.
63    pub value_type: IcrcMetadataValueKind,
64    /// Lossless decimal, text, or lowercase hexadecimal JSON string.
65    pub value: JsonValue,
66}
67
68///
69/// IcrcMetadataValueKind
70///
71/// Native ICRC-1 metadata value variant represented by a report row.
72///
73
74#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
75#[serde(rename_all = "snake_case")]
76pub enum IcrcMetadataValueKind {
77    /// An arbitrary-precision unsigned integer.
78    Nat,
79    /// An arbitrary-precision signed integer.
80    Int,
81    /// A Unicode text value.
82    Text,
83    /// An opaque byte sequence.
84    Blob,
85}
86
87impl IcrcMetadataValueKind {
88    /// Return the stable JSON and text label.
89    #[must_use]
90    pub const fn as_str(self) -> &'static str {
91        match self {
92            Self::Nat => "nat",
93            Self::Int => "int",
94            Self::Text => "text",
95            Self::Blob => "blob",
96        }
97    }
98}
99
100#[cfg(test)]
101mod tests {
102    use super::*;
103
104    #[test]
105    fn metadata_value_kind_labels_round_trip() {
106        for (kind, label) in [
107            (IcrcMetadataValueKind::Nat, "nat"),
108            (IcrcMetadataValueKind::Int, "int"),
109            (IcrcMetadataValueKind::Text, "text"),
110            (IcrcMetadataValueKind::Blob, "blob"),
111        ] {
112            assert_eq!(
113                serde_json::to_string(&kind).unwrap(),
114                format!("\"{label}\"")
115            );
116            assert_eq!(
117                serde_json::from_str::<IcrcMetadataValueKind>(&format!("\"{label}\"")).unwrap(),
118                kind
119            );
120            assert_eq!(kind.as_str(), label);
121        }
122    }
123}