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