1use schemars::JsonSchema;
2use serde::{Deserialize, Deserializer, Serialize};
3
4use crate::prelude::*;
5
6#[derive(Serialize, Deserialize, Clone, Default, Debug, PartialEq, Eq, JsonSchema)]
8pub struct DenomMetadata {
9 pub description: String,
10 #[serde(deserialize_with = "deserialize_null_default")]
11 pub denom_units: Vec<DenomUnit>,
12 pub base: String,
13 pub display: String,
14 pub name: String,
15 pub symbol: String,
16 pub uri: String,
17 pub uri_hash: String,
18}
19
20#[derive(Serialize, Deserialize, Clone, Default, Debug, PartialEq, Eq, JsonSchema)]
22pub struct DenomUnit {
23 pub denom: String,
24 pub exponent: u32,
25 #[serde(deserialize_with = "deserialize_null_default")]
26 pub aliases: Vec<String>,
27}
28
29fn deserialize_null_default<'de, D, T>(deserializer: D) -> Result<T, D::Error>
32where
33 T: Default + Deserialize<'de>,
34 D: Deserializer<'de>,
35{
36 let opt = Option::deserialize(deserializer)?;
37 Ok(opt.unwrap_or_default())
38}
39
40#[cfg(test)]
41mod tests {
42 use super::*;
43 use crate::{DenomMetadata, DenomUnit};
44 use serde_json::{json, Error};
45
46 #[test]
47 fn deserialize_denom_metadata_with_null_fields_works() {
48 let json_with_null_denom_units = json!({
50 "description": "Test Token",
51 "denom_units": null,
52 "base": "utest",
53 "display": "TEST",
54 "name": "Test Token",
55 "symbol": "TEST",
56 "uri": "https://test.com",
57 "uri_hash": "hash"
58 });
59
60 let metadata_null_denom_units: DenomMetadata =
61 serde_json::from_value(json_with_null_denom_units).unwrap();
62 assert_eq!(
63 metadata_null_denom_units.denom_units,
64 Vec::<DenomUnit>::new()
65 );
66
67 let json_with_units = json!({
69 "description": "Test Token",
70 "denom_units": [
71 {
72 "denom": "utest",
73 "exponent": 6,
74 "aliases": ["microtest"]
75 }
76 ],
77 "base": "utest",
78 "display": "TEST",
79 "name": "Test Token",
80 "symbol": "TEST",
81 "uri": "https://test.com",
82 "uri_hash": "hash"
83 });
84
85 let metadata_with_units: DenomMetadata = serde_json::from_value(json_with_units).unwrap();
86 assert_eq!(metadata_with_units.denom_units.len(), 1);
87 assert_eq!(metadata_with_units.denom_units[0].denom, "utest");
88
89 let json_with_null_aliases = json!({
91 "description": "Test Token",
92 "denom_units": [
93 {
94 "denom": "utest",
95 "exponent": 6,
96 "aliases": null
97 }
98 ],
99 "base": "utest",
100 "display": "TEST",
101 "name": "Test Token",
102 "symbol": "TEST",
103 "uri": "https://test.com",
104 "uri_hash": "hash"
105 });
106
107 let metadata_with_null_aliases: DenomMetadata =
108 serde_json::from_value(json_with_null_aliases).unwrap();
109 assert_eq!(metadata_with_null_aliases.denom_units.len(), 1);
110 assert_eq!(
111 metadata_with_null_aliases.denom_units[0].aliases,
112 Vec::<String>::new()
113 );
114 }
115
116 #[test]
117 fn deserialize_denom_metadata_with_missing_fields_fails() {
118 let json_missing_denom_units = json!({
120 "description": "Test Token",
121 "base": "utest",
122 "display": "TEST",
123 "name": "Test Token",
124 "symbol": "TEST",
125 "uri": "https://test.com",
126 "uri_hash": "hash"
127 });
128
129 let metadata: Result<DenomMetadata, Error> =
130 serde_json::from_value(json_missing_denom_units);
131 assert!(metadata.is_err());
132
133 let json_missing_alias = json!({
134 "description": "Test Token",
135 "base": "utest",
136 "denom_units": [
137 {
138 "denom": "utest",
139 "exponent": 6,
140 }
141 ],
142 "display": "TEST",
143 "name": "Test Token",
144 "symbol": "TEST",
145 "uri": "https://test.com",
146 "uri_hash": "hash"
147 });
148
149 let metadata_missing_alias: Result<DenomMetadata, Error> =
150 serde_json::from_value(json_missing_alias);
151 assert!(metadata_missing_alias.is_err());
152 }
153
154 #[test]
155 fn query_denom_metadata_with_null_denom_units_works() {
156 let json_with_null_denom_units = json!({
158 "description": "Test Token",
159 "denom_units": null,
160 "base": "utest",
161 "display": "TEST",
162 "name": "Test Token",
163 "symbol": "TEST",
164 "uri": "https://test.com",
165 "uri_hash": "hash"
166 });
167
168 let metadata_with_null_denom_units: DenomMetadata =
169 serde_json::from_value(json_with_null_denom_units).unwrap();
170 assert_eq!(
171 metadata_with_null_denom_units.denom_units,
172 Vec::<DenomUnit>::new()
173 );
174
175 let json_with_units = json!({
177 "description": "Test Token",
178 "denom_units": [
179 {
180 "denom": "utest",
181 "exponent": 6,
182 "aliases": ["microtest"]
183 }
184 ],
185 "base": "utest",
186 "display": "TEST",
187 "name": "Test Token",
188 "symbol": "TEST",
189 "uri": "https://test.com",
190 "uri_hash": "hash"
191 });
192
193 let metadata_with_units: DenomMetadata = serde_json::from_value(json_with_units).unwrap();
194 assert_eq!(metadata_with_units.denom_units.len(), 1);
195 assert_eq!(metadata_with_units.denom_units[0].denom, "utest");
196 assert_eq!(metadata_with_units.denom_units[0].aliases.len(), 1);
197 assert_eq!(metadata_with_units.denom_units[0].aliases[0], "microtest");
198
199 let json_with_null_aliases = json!({
201 "description": "Test Token",
202 "denom_units": [
203 {
204 "denom": "utest",
205 "exponent": 6,
206 "aliases": null
207 }
208 ],
209 "base": "utest",
210 "display": "TEST",
211 "name": "Test Token",
212 "symbol": "TEST",
213 "uri": "https://test.com",
214 "uri_hash": "hash"
215 });
216
217 let metadata_with_null_aliases: DenomMetadata =
218 serde_json::from_value(json_with_null_aliases).unwrap();
219 assert_eq!(metadata_with_null_aliases.denom_units.len(), 1);
220 assert_eq!(
221 metadata_with_null_aliases.denom_units[0].aliases,
222 Vec::<String>::new()
223 );
224 }
225
226 #[test]
227 fn query_denom_metadata_with_missing_fields_fails() {
228 let json_missing_denom_units = json!({
230 "description": "Test Token",
231 "base": "utest",
232 "display": "TEST",
233 "name": "Test Token",
234 "symbol": "TEST",
235 "uri": "https://test.com",
236 "uri_hash": "hash"
237 });
238
239 let json_missing_denom_units_metadata: Result<DenomMetadata, Error> =
240 serde_json::from_value(json_missing_denom_units);
241 assert!(json_missing_denom_units_metadata.is_err());
242
243 let json_missing_aliases = json!({
245 "description": "Test Token",
246 "denom_units": [
247 {
248 "denom": "utest",
249 "exponent": 6
250 }
251 ],
252 "base": "utest",
253 "display": "TEST",
254 "name": "Test Token",
255 "symbol": "TEST",
256 "uri": "https://test.com",
257 "uri_hash": "hash"
258 });
259
260 let missing_aliases_metadata: Result<DenomMetadata, Error> =
261 serde_json::from_value(json_missing_aliases);
262 assert!(missing_aliases_metadata.is_err());
263 }
264
265 #[test]
266 fn query_denom_metadata_with_mixed_null_and_value_works() {
267 let mixed_json = json!({
269 "description": "Mixed Token",
270 "denom_units": [
271 {
272 "denom": "unit1",
273 "exponent": 0,
274 "aliases": null
275 },
276 {
277 "denom": "unit2",
278 "exponent": 6,
279 "aliases": ["microunit", "u"]
280 },
281 {
282 "denom": "unit3",
283 "exponent": 9,
284 "aliases": []
285 }
286 ],
287 "base": "unit1",
288 "display": "MIXED",
289 "name": "Mixed Token",
290 "symbol": "MIX",
291 "uri": "https://mixed.token",
292 "uri_hash": "hash123"
293 });
294
295 let metadata: DenomMetadata = serde_json::from_value(mixed_json).unwrap();
296
297 assert!(metadata.denom_units[0].aliases.is_empty());
299
300 assert_eq!(metadata.denom_units[1].aliases.len(), 2);
302 assert_eq!(metadata.denom_units[1].aliases[0], "microunit");
303 assert_eq!(metadata.denom_units[1].aliases[1], "u");
304
305 assert!(metadata.denom_units[2].aliases.is_empty());
307 }
308}