Skip to main content

nautilus_model/
currencies.rs

1// -------------------------------------------------------------------------------------------------
2//  Copyright (C) 2015-2026 Nautech Systems Pty Ltd. All rights reserved.
3//  https://nautechsystems.io
4//
5//  Licensed under the GNU Lesser General Public License Version 3.0 (the "License");
6//  You may not use this file except in compliance with the License.
7//  You may obtain a copy of the License at https://www.gnu.org/licenses/lgpl-3.0.en.html
8//
9//  Unless required by applicable law or agreed to in writing, software
10//  distributed under the License is distributed on an "AS IS" BASIS,
11//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12//  See the License for the specific language governing permissions and
13//  limitations under the License.
14// -------------------------------------------------------------------------------------------------
15
16//! Common `Currency` constants.
17//!
18//! Precision and metadata references:
19//! - ISO 4217 Maintenance Agency dataset (<https://github.com/datasets/currency-codes>):
20//!   authoritative alphabetic codes, numeric codes, and minor units for fiat and commodity-backed entries.
21//! - Cardano ledger documentation (<https://docs.cardano.org/native-tokens/understanding-assets>):
22//!   1 ADA = 1,000,000 lovelace, underpinning the six-decimal crypto precision we retain.
23//! - XRPL documentation on drops (<https://xrpl.org/xrp-ledger-tokens.html#drops-and-xrp>):
24//!   1 XRP = 1,000,000 drops, confirming the six-decimal allowance for XRP.
25//! - Tezos protocol reference (<https://tezos.gitlab.io/active/numismatics.html>):
26//!   1 tez = 1,000,000 mutez, informing the six-decimal precision for XTZ.
27//! - Stablecoin contract metadata on Etherscan for USDC, USDP, and BRZ
28//!   (e.g. <https://etherscan.io/token/0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48#readContract>,
29//!   <https://etherscan.io/token/0x8e870d67f660d95d5be530380d0ec0bd388289e1#readContract>,
30//!   <https://etherscan.io/token/0x01d33fd36ec67c6ada32cf36b31e88ee190b1839#readContract>):
31//!   each exposes 6–18 on-chain decimals; we clamp to an 8-decimal internal default.
32
33use std::{
34    collections::HashMap,
35    sync::{LazyLock, Mutex, OnceLock},
36};
37
38use ustr::Ustr;
39
40use crate::{enums::CurrencyType, types::Currency};
41
42///////////////////////////////////////////////////////////////////////////////
43// Fiat currencies
44///////////////////////////////////////////////////////////////////////////////
45static AUD_LOCK: OnceLock<Currency> = OnceLock::new();
46static BRL_LOCK: OnceLock<Currency> = OnceLock::new();
47static CAD_LOCK: OnceLock<Currency> = OnceLock::new();
48static CHF_LOCK: OnceLock<Currency> = OnceLock::new();
49static CNY_LOCK: OnceLock<Currency> = OnceLock::new();
50static CNH_LOCK: OnceLock<Currency> = OnceLock::new();
51static CZK_LOCK: OnceLock<Currency> = OnceLock::new();
52static DKK_LOCK: OnceLock<Currency> = OnceLock::new();
53static EUR_LOCK: OnceLock<Currency> = OnceLock::new();
54static GBP_LOCK: OnceLock<Currency> = OnceLock::new();
55static HKD_LOCK: OnceLock<Currency> = OnceLock::new();
56static HUF_LOCK: OnceLock<Currency> = OnceLock::new();
57static ILS_LOCK: OnceLock<Currency> = OnceLock::new();
58static INR_LOCK: OnceLock<Currency> = OnceLock::new();
59static JPY_LOCK: OnceLock<Currency> = OnceLock::new();
60static KRW_LOCK: OnceLock<Currency> = OnceLock::new();
61static MXN_LOCK: OnceLock<Currency> = OnceLock::new();
62static NOK_LOCK: OnceLock<Currency> = OnceLock::new();
63static NZD_LOCK: OnceLock<Currency> = OnceLock::new();
64static PLN_LOCK: OnceLock<Currency> = OnceLock::new();
65static RUB_LOCK: OnceLock<Currency> = OnceLock::new();
66static SAR_LOCK: OnceLock<Currency> = OnceLock::new();
67static SEK_LOCK: OnceLock<Currency> = OnceLock::new();
68static SGD_LOCK: OnceLock<Currency> = OnceLock::new();
69static THB_LOCK: OnceLock<Currency> = OnceLock::new();
70static TRY_LOCK: OnceLock<Currency> = OnceLock::new();
71static TWD_LOCK: OnceLock<Currency> = OnceLock::new();
72static USD_LOCK: OnceLock<Currency> = OnceLock::new();
73static ZAR_LOCK: OnceLock<Currency> = OnceLock::new();
74
75///////////////////////////////////////////////////////////////////////////////
76// Commodity backed currencies
77///////////////////////////////////////////////////////////////////////////////
78static XAG_LOCK: OnceLock<Currency> = OnceLock::new();
79static XAU_LOCK: OnceLock<Currency> = OnceLock::new();
80static XPT_LOCK: OnceLock<Currency> = OnceLock::new();
81
82///////////////////////////////////////////////////////////////////////////////
83// Crypto currencies
84///////////////////////////////////////////////////////////////////////////////
85static ONEINCH_LOCK: OnceLock<Currency> = OnceLock::new();
86static AAVE_LOCK: OnceLock<Currency> = OnceLock::new();
87static ACA_LOCK: OnceLock<Currency> = OnceLock::new();
88static ADA_LOCK: OnceLock<Currency> = OnceLock::new();
89static APT_LOCK: OnceLock<Currency> = OnceLock::new();
90static ARB_LOCK: OnceLock<Currency> = OnceLock::new();
91static AVAX_LOCK: OnceLock<Currency> = OnceLock::new();
92static BCH_LOCK: OnceLock<Currency> = OnceLock::new();
93static BIO_LOCK: OnceLock<Currency> = OnceLock::new();
94static BTC_LOCK: OnceLock<Currency> = OnceLock::new();
95static BTTC_LOCK: OnceLock<Currency> = OnceLock::new();
96static BNB_LOCK: OnceLock<Currency> = OnceLock::new();
97static BRZ_LOCK: OnceLock<Currency> = OnceLock::new();
98static BSV_LOCK: OnceLock<Currency> = OnceLock::new();
99static BUSD_LOCK: OnceLock<Currency> = OnceLock::new();
100static CAKE_LOCK: OnceLock<Currency> = OnceLock::new();
101static CRV_LOCK: OnceLock<Currency> = OnceLock::new();
102static DASH_LOCK: OnceLock<Currency> = OnceLock::new();
103static DOGE_LOCK: OnceLock<Currency> = OnceLock::new();
104static DOT_LOCK: OnceLock<Currency> = OnceLock::new();
105static ENA_LOCK: OnceLock<Currency> = OnceLock::new();
106static EOS_LOCK: OnceLock<Currency> = OnceLock::new();
107static ETH_LOCK: OnceLock<Currency> = OnceLock::new();
108static ETHW_LOCK: OnceLock<Currency> = OnceLock::new();
109static FDUSD_LOCK: OnceLock<Currency> = OnceLock::new();
110static GWEI_LOCK: OnceLock<Currency> = OnceLock::new();
111static HYPE_LOCK: OnceLock<Currency> = OnceLock::new();
112static JOE_LOCK: OnceLock<Currency> = OnceLock::new();
113static LINK_LOCK: OnceLock<Currency> = OnceLock::new();
114static LTC_LOCK: OnceLock<Currency> = OnceLock::new();
115static LUNA_LOCK: OnceLock<Currency> = OnceLock::new();
116static MAMUSD_LOCK: OnceLock<Currency> = OnceLock::new();
117static NBT_LOCK: OnceLock<Currency> = OnceLock::new();
118static POL_LOCK: OnceLock<Currency> = OnceLock::new();
119static PROVE_LOCK: OnceLock<Currency> = OnceLock::new();
120static RLUSD_LOCK: OnceLock<Currency> = OnceLock::new();
121static SOL_LOCK: OnceLock<Currency> = OnceLock::new();
122static SUI_LOCK: OnceLock<Currency> = OnceLock::new();
123static TON_LOCK: OnceLock<Currency> = OnceLock::new();
124static TRX_LOCK: OnceLock<Currency> = OnceLock::new();
125static TRYB_LOCK: OnceLock<Currency> = OnceLock::new();
126static TUSD_LOCK: OnceLock<Currency> = OnceLock::new();
127static SHIB_LOCK: OnceLock<Currency> = OnceLock::new();
128static UNI_LOCK: OnceLock<Currency> = OnceLock::new();
129static VTC_LOCK: OnceLock<Currency> = OnceLock::new();
130static WBTC_LOCK: OnceLock<Currency> = OnceLock::new();
131static WSB_LOCK: OnceLock<Currency> = OnceLock::new();
132static XBT_LOCK: OnceLock<Currency> = OnceLock::new();
133static XEC_LOCK: OnceLock<Currency> = OnceLock::new();
134static XLM_LOCK: OnceLock<Currency> = OnceLock::new();
135static XMR_LOCK: OnceLock<Currency> = OnceLock::new();
136static XRP_LOCK: OnceLock<Currency> = OnceLock::new();
137static XTZ_LOCK: OnceLock<Currency> = OnceLock::new();
138static USDC_LOCK: OnceLock<Currency> = OnceLock::new();
139static USDC_POS_LOCK: OnceLock<Currency> = OnceLock::new();
140static USDP_LOCK: OnceLock<Currency> = OnceLock::new();
141static PUSD_LOCK: OnceLock<Currency> = OnceLock::new();
142static USDT_LOCK: OnceLock<Currency> = OnceLock::new();
143static ZEC_LOCK: OnceLock<Currency> = OnceLock::new();
144
145impl Currency {
146    ///////////////////////////////////////////////////////////////////////////
147    // Fiat currencies
148    ///////////////////////////////////////////////////////////////////////////
149    #[allow(non_snake_case)]
150    #[must_use]
151    pub fn AUD() -> Self {
152        *AUD_LOCK.get_or_init(|| Self {
153            code: Ustr::from("AUD"),
154            precision: 2,
155            iso4217: 36,
156            name: Ustr::from("Australian dollar"),
157            currency_type: CurrencyType::Fiat,
158        })
159    }
160    #[allow(non_snake_case)]
161    #[must_use]
162    pub fn BRL() -> Self {
163        *BRL_LOCK.get_or_init(|| Self {
164            code: Ustr::from("BRL"),
165            precision: 2,
166            iso4217: 986,
167            name: Ustr::from("Brazilian real"),
168            currency_type: CurrencyType::Fiat,
169        })
170    }
171
172    #[allow(non_snake_case)]
173    #[must_use]
174    pub fn CAD() -> Self {
175        *CAD_LOCK.get_or_init(|| Self {
176            code: Ustr::from("CAD"),
177            precision: 2,
178            iso4217: 124,
179            name: Ustr::from("Canadian dollar"),
180            currency_type: CurrencyType::Fiat,
181        })
182    }
183
184    #[allow(non_snake_case)]
185    #[must_use]
186    pub fn CHF() -> Self {
187        *CHF_LOCK.get_or_init(|| Self {
188            code: Ustr::from("CHF"),
189            precision: 2,
190            iso4217: 756,
191            name: Ustr::from("Swiss franc"),
192            currency_type: CurrencyType::Fiat,
193        })
194    }
195
196    #[allow(non_snake_case)]
197    #[must_use]
198    pub fn CNY() -> Self {
199        *CNY_LOCK.get_or_init(|| Self {
200            code: Ustr::from("CNY"),
201            precision: 2,
202            iso4217: 156,
203            name: Ustr::from("Chinese yuan"),
204            currency_type: CurrencyType::Fiat,
205        })
206    }
207
208    #[allow(non_snake_case)]
209    #[must_use]
210    pub fn CNH() -> Self {
211        *CNH_LOCK.get_or_init(|| Self {
212            code: Ustr::from("CNH"),
213            precision: 2,
214            iso4217: 0,
215            name: Ustr::from("Chinese yuan (offshore)"),
216            currency_type: CurrencyType::Fiat,
217        })
218    }
219
220    #[allow(non_snake_case)]
221    #[must_use]
222    pub fn CZK() -> Self {
223        *CZK_LOCK.get_or_init(|| Self {
224            code: Ustr::from("CZK"),
225            precision: 2,
226            iso4217: 203,
227            name: Ustr::from("Czech koruna"),
228            currency_type: CurrencyType::Fiat,
229        })
230    }
231
232    #[allow(non_snake_case)]
233    #[must_use]
234    pub fn DKK() -> Self {
235        *DKK_LOCK.get_or_init(|| Self {
236            code: Ustr::from("DKK"),
237            precision: 2,
238            iso4217: 208,
239            name: Ustr::from("Danish krone"),
240            currency_type: CurrencyType::Fiat,
241        })
242    }
243
244    #[allow(non_snake_case)]
245    #[must_use]
246    pub fn EUR() -> Self {
247        *EUR_LOCK.get_or_init(|| Self {
248            code: Ustr::from("EUR"),
249            precision: 2,
250            iso4217: 978,
251            name: Ustr::from("Euro"),
252            currency_type: CurrencyType::Fiat,
253        })
254    }
255
256    #[allow(non_snake_case)]
257    #[must_use]
258    pub fn GBP() -> Self {
259        *GBP_LOCK.get_or_init(|| Self {
260            code: Ustr::from("GBP"),
261            precision: 2,
262            iso4217: 826,
263            name: Ustr::from("British Pound"),
264            currency_type: CurrencyType::Fiat,
265        })
266    }
267
268    #[allow(non_snake_case)]
269    #[must_use]
270    pub fn HKD() -> Self {
271        *HKD_LOCK.get_or_init(|| Self {
272            code: Ustr::from("HKD"),
273            precision: 2,
274            iso4217: 344,
275            name: Ustr::from("Hong Kong dollar"),
276            currency_type: CurrencyType::Fiat,
277        })
278    }
279
280    #[allow(non_snake_case)]
281    #[must_use]
282    pub fn HUF() -> Self {
283        *HUF_LOCK.get_or_init(|| Self {
284            code: Ustr::from("HUF"),
285            precision: 2,
286            iso4217: 348,
287            name: Ustr::from("Hungarian forint"),
288            currency_type: CurrencyType::Fiat,
289        })
290    }
291
292    #[allow(non_snake_case)]
293    #[must_use]
294    pub fn ILS() -> Self {
295        *ILS_LOCK.get_or_init(|| Self {
296            code: Ustr::from("ILS"),
297            precision: 2,
298            iso4217: 376,
299            name: Ustr::from("Israeli new shekel"),
300            currency_type: CurrencyType::Fiat,
301        })
302    }
303
304    #[allow(non_snake_case)]
305    #[must_use]
306    pub fn INR() -> Self {
307        *INR_LOCK.get_or_init(|| Self {
308            code: Ustr::from("INR"),
309            precision: 2,
310            iso4217: 356,
311            name: Ustr::from("Indian rupee"),
312            currency_type: CurrencyType::Fiat,
313        })
314    }
315
316    #[allow(non_snake_case)]
317    #[must_use]
318    pub fn JPY() -> Self {
319        *JPY_LOCK.get_or_init(|| Self {
320            code: Ustr::from("JPY"),
321            precision: 0,
322            iso4217: 392,
323            name: Ustr::from("Japanese yen"),
324            currency_type: CurrencyType::Fiat,
325        })
326    }
327    #[allow(non_snake_case)]
328    #[must_use]
329    pub fn KRW() -> Self {
330        *KRW_LOCK.get_or_init(|| Self {
331            code: Ustr::from("KRW"),
332            precision: 0,
333            iso4217: 410,
334            name: Ustr::from("South Korean won"),
335            currency_type: CurrencyType::Fiat,
336        })
337    }
338
339    #[allow(non_snake_case)]
340    #[must_use]
341    pub fn MXN() -> Self {
342        *MXN_LOCK.get_or_init(|| Self {
343            code: Ustr::from("MXN"),
344            precision: 2,
345            iso4217: 484,
346            name: Ustr::from("Mexican peso"),
347            currency_type: CurrencyType::Fiat,
348        })
349    }
350
351    #[allow(non_snake_case)]
352    #[must_use]
353    pub fn NOK() -> Self {
354        *NOK_LOCK.get_or_init(|| Self {
355            code: Ustr::from("NOK"),
356            precision: 2,
357            iso4217: 578,
358            name: Ustr::from("Norwegian krone"),
359            currency_type: CurrencyType::Fiat,
360        })
361    }
362
363    #[allow(non_snake_case)]
364    #[must_use]
365    pub fn NZD() -> Self {
366        *NZD_LOCK.get_or_init(|| Self {
367            code: Ustr::from("NZD"),
368            precision: 2,
369            iso4217: 554,
370            name: Ustr::from("New Zealand dollar"),
371            currency_type: CurrencyType::Fiat,
372        })
373    }
374
375    #[allow(non_snake_case)]
376    #[must_use]
377    pub fn PLN() -> Self {
378        *PLN_LOCK.get_or_init(|| Self {
379            code: Ustr::from("PLN"),
380            precision: 2,
381            iso4217: 985,
382            name: Ustr::from("Polish złoty"),
383            currency_type: CurrencyType::Fiat,
384        })
385    }
386
387    #[allow(non_snake_case)]
388    #[must_use]
389    pub fn RUB() -> Self {
390        *RUB_LOCK.get_or_init(|| Self {
391            code: Ustr::from("RUB"),
392            precision: 2,
393            iso4217: 643,
394            name: Ustr::from("Russian ruble"),
395            currency_type: CurrencyType::Fiat,
396        })
397    }
398
399    #[allow(non_snake_case)]
400    #[must_use]
401    pub fn SAR() -> Self {
402        *SAR_LOCK.get_or_init(|| Self {
403            code: Ustr::from("SAR"),
404            precision: 2,
405            iso4217: 682,
406            name: Ustr::from("Saudi riyal"),
407            currency_type: CurrencyType::Fiat,
408        })
409    }
410
411    #[allow(non_snake_case)]
412    #[must_use]
413    pub fn SEK() -> Self {
414        *SEK_LOCK.get_or_init(|| Self {
415            code: Ustr::from("SEK"),
416            precision: 2,
417            iso4217: 752,
418            name: Ustr::from("Swedish krona"),
419            currency_type: CurrencyType::Fiat,
420        })
421    }
422
423    #[allow(non_snake_case)]
424    #[must_use]
425    pub fn SGD() -> Self {
426        *SGD_LOCK.get_or_init(|| Self {
427            code: Ustr::from("SGD"),
428            precision: 2,
429            iso4217: 702,
430            name: Ustr::from("Singapore dollar"),
431            currency_type: CurrencyType::Fiat,
432        })
433    }
434
435    #[allow(non_snake_case)]
436    #[must_use]
437    pub fn THB() -> Self {
438        *THB_LOCK.get_or_init(|| Self {
439            code: Ustr::from("THB"),
440            precision: 2,
441            iso4217: 764,
442            name: Ustr::from("Thai baht"),
443            currency_type: CurrencyType::Fiat,
444        })
445    }
446
447    #[allow(non_snake_case)]
448    #[must_use]
449    pub fn TRY() -> Self {
450        *TRY_LOCK.get_or_init(|| Self {
451            code: Ustr::from("TRY"),
452            precision: 2,
453            iso4217: 949,
454            name: Ustr::from("Turkish lira"),
455            currency_type: CurrencyType::Fiat,
456        })
457    }
458
459    #[allow(non_snake_case)]
460    #[must_use]
461    pub fn TWD() -> Self {
462        *TWD_LOCK.get_or_init(|| Self {
463            code: Ustr::from("TWD"),
464            precision: 2,
465            iso4217: 901,
466            name: Ustr::from("New Taiwan dollar"),
467            currency_type: CurrencyType::Fiat,
468        })
469    }
470
471    #[allow(non_snake_case)]
472    #[must_use]
473    pub fn USD() -> Self {
474        *USD_LOCK.get_or_init(|| Self {
475            code: Ustr::from("USD"),
476            precision: 2,
477            iso4217: 840,
478            name: Ustr::from("United States dollar"),
479            currency_type: CurrencyType::Fiat,
480        })
481    }
482    #[allow(non_snake_case)]
483    #[must_use]
484    pub fn ZAR() -> Self {
485        *ZAR_LOCK.get_or_init(|| Self {
486            code: Ustr::from("ZAR"),
487            precision: 2,
488            iso4217: 710,
489            name: Ustr::from("South African rand"),
490            currency_type: CurrencyType::Fiat,
491        })
492    }
493
494    #[allow(non_snake_case)]
495    #[must_use]
496    pub fn XAG() -> Self {
497        *XAG_LOCK.get_or_init(|| Self {
498            code: Ustr::from("XAG"),
499            precision: 2,
500            iso4217: 961,
501            name: Ustr::from("Silver (one troy ounce)"),
502            currency_type: CurrencyType::CommodityBacked,
503        })
504    }
505
506    #[allow(non_snake_case)]
507    #[must_use]
508    pub fn XAU() -> Self {
509        *XAU_LOCK.get_or_init(|| Self {
510            code: Ustr::from("XAU"),
511            precision: 2,
512            iso4217: 959,
513            name: Ustr::from("Gold (one troy ounce)"),
514            currency_type: CurrencyType::CommodityBacked,
515        })
516    }
517
518    #[allow(non_snake_case)]
519    #[must_use]
520    pub fn XPT() -> Self {
521        *XPT_LOCK.get_or_init(|| Self {
522            code: Ustr::from("XPT"),
523            precision: 2,
524            iso4217: 962,
525            name: Ustr::from("Platinum (one troy ounce)"),
526            currency_type: CurrencyType::CommodityBacked,
527        })
528    }
529
530    ///////////////////////////////////////////////////////////////////////////
531    // Crypto currencies
532    ///////////////////////////////////////////////////////////////////////////
533    #[allow(non_snake_case)]
534    #[must_use]
535    pub fn ONEINCH() -> Self {
536        *ONEINCH_LOCK.get_or_init(|| Self {
537            code: Ustr::from("1INCH"),
538            precision: 8,
539            iso4217: 0,
540            name: Ustr::from("1inch Network"),
541            currency_type: CurrencyType::Crypto,
542        })
543    }
544
545    #[allow(non_snake_case)]
546    #[must_use]
547    pub fn AAVE() -> Self {
548        *AAVE_LOCK.get_or_init(|| Self {
549            code: Ustr::from("AAVE"),
550            precision: 8,
551            iso4217: 0,
552            name: Ustr::from("Aave"),
553            currency_type: CurrencyType::Crypto,
554        })
555    }
556
557    #[allow(non_snake_case)]
558    #[must_use]
559    pub fn ACA() -> Self {
560        *ACA_LOCK.get_or_init(|| Self {
561            code: Ustr::from("ACA"),
562            precision: 8,
563            iso4217: 0,
564            name: Ustr::from("Acala Token"),
565            currency_type: CurrencyType::Crypto,
566        })
567    }
568
569    #[allow(non_snake_case)]
570    #[must_use]
571    pub fn ADA() -> Self {
572        *ADA_LOCK.get_or_init(|| Self {
573            code: Ustr::from("ADA"),
574            precision: 6,
575            iso4217: 0,
576            name: Ustr::from("Cardano"),
577            currency_type: CurrencyType::Crypto,
578        })
579    }
580
581    #[allow(non_snake_case)]
582    #[must_use]
583    pub fn APT() -> Self {
584        *APT_LOCK.get_or_init(|| Self {
585            code: Ustr::from("APT"),
586            precision: 8,
587            iso4217: 0,
588            name: Ustr::from("Aptos"),
589            currency_type: CurrencyType::Crypto,
590        })
591    }
592
593    #[allow(non_snake_case)]
594    #[must_use]
595    pub fn ARB() -> Self {
596        *ARB_LOCK.get_or_init(|| Self {
597            code: Ustr::from("ARB"),
598            precision: 8,
599            iso4217: 0,
600            name: Ustr::from("Arbitrum"),
601            currency_type: CurrencyType::Crypto,
602        })
603    }
604
605    #[allow(non_snake_case)]
606    #[must_use]
607    pub fn AVAX() -> Self {
608        *AVAX_LOCK.get_or_init(|| Self {
609            code: Ustr::from("AVAX"),
610            precision: 8,
611            iso4217: 0,
612            name: Ustr::from("Avalanche"),
613            currency_type: CurrencyType::Crypto,
614        })
615    }
616
617    #[allow(non_snake_case)]
618    #[must_use]
619    pub fn BCH() -> Self {
620        *BCH_LOCK.get_or_init(|| Self {
621            code: Ustr::from("BCH"),
622            precision: 8,
623            iso4217: 0,
624            name: Ustr::from("Bitcoin Cash"),
625            currency_type: CurrencyType::Crypto,
626        })
627    }
628
629    #[allow(non_snake_case)]
630    #[must_use]
631    pub fn BIO() -> Self {
632        *BIO_LOCK.get_or_init(|| Self {
633            code: Ustr::from("BIO"),
634            precision: 8,
635            iso4217: 0,
636            name: Ustr::from("BioPassport"),
637            currency_type: CurrencyType::Crypto,
638        })
639    }
640
641    #[allow(non_snake_case)]
642    #[must_use]
643    pub fn BTC() -> Self {
644        *BTC_LOCK.get_or_init(|| Self {
645            code: Ustr::from("BTC"),
646            precision: 8,
647            iso4217: 0,
648            name: Ustr::from("Bitcoin"),
649            currency_type: CurrencyType::Crypto,
650        })
651    }
652
653    #[allow(non_snake_case)]
654    #[must_use]
655    pub fn BTTC() -> Self {
656        *BTTC_LOCK.get_or_init(|| Self {
657            code: Ustr::from("BTTC"),
658            precision: 8,
659            iso4217: 0,
660            name: Ustr::from("BitTorrent"),
661            currency_type: CurrencyType::Crypto,
662        })
663    }
664
665    #[allow(non_snake_case)]
666    #[must_use]
667    pub fn BNB() -> Self {
668        *BNB_LOCK.get_or_init(|| Self {
669            code: Ustr::from("BNB"),
670            precision: 8,
671            iso4217: 0,
672            name: Ustr::from("Binance Coin"),
673            currency_type: CurrencyType::Crypto,
674        })
675    }
676
677    #[allow(non_snake_case)]
678    #[must_use]
679    pub fn BRZ() -> Self {
680        *BRZ_LOCK.get_or_init(|| Self {
681            code: Ustr::from("BRZ"),
682            precision: 8,
683            iso4217: 0,
684            name: Ustr::from("Brazilian Digital Token"),
685            currency_type: CurrencyType::Crypto,
686        })
687    }
688
689    #[allow(non_snake_case)]
690    #[must_use]
691    pub fn BSV() -> Self {
692        *BSV_LOCK.get_or_init(|| Self {
693            code: Ustr::from("BSV"),
694            precision: 8,
695            iso4217: 0,
696            name: Ustr::from("Bitcoin SV"),
697            currency_type: CurrencyType::Crypto,
698        })
699    }
700
701    #[allow(non_snake_case)]
702    #[must_use]
703    pub fn BUSD() -> Self {
704        *BUSD_LOCK.get_or_init(|| Self {
705            code: Ustr::from("BUSD"),
706            precision: 8,
707            iso4217: 0,
708            name: Ustr::from("Binance USD"),
709            currency_type: CurrencyType::Crypto,
710        })
711    }
712
713    #[allow(non_snake_case)]
714    #[must_use]
715    pub fn CAKE() -> Self {
716        *CAKE_LOCK.get_or_init(|| Self {
717            code: Ustr::from("CAKE"),
718            precision: 8,
719            iso4217: 0,
720            name: Ustr::from("PancakeSwap"),
721            currency_type: CurrencyType::Crypto,
722        })
723    }
724
725    #[allow(non_snake_case)]
726    #[must_use]
727    pub fn CRV() -> Self {
728        *CRV_LOCK.get_or_init(|| Self {
729            code: Ustr::from("CRV"),
730            precision: 8,
731            iso4217: 0,
732            name: Ustr::from("Curve DAO Token"),
733            currency_type: CurrencyType::Crypto,
734        })
735    }
736
737    #[allow(non_snake_case)]
738    #[must_use]
739    pub fn DASH() -> Self {
740        *DASH_LOCK.get_or_init(|| Self {
741            code: Ustr::from("DASH"),
742            precision: 8,
743            iso4217: 0,
744            name: Ustr::from("Dash"),
745            currency_type: CurrencyType::Crypto,
746        })
747    }
748
749    #[allow(non_snake_case)]
750    #[must_use]
751    pub fn DOT() -> Self {
752        *DOT_LOCK.get_or_init(|| Self {
753            code: Ustr::from("DOT"),
754            precision: 8,
755            iso4217: 0,
756            name: Ustr::from("Polkadot"),
757            currency_type: CurrencyType::Crypto,
758        })
759    }
760
761    #[allow(non_snake_case)]
762    #[must_use]
763    pub fn DOGE() -> Self {
764        *DOGE_LOCK.get_or_init(|| Self {
765            code: Ustr::from("DOGE"),
766            precision: 8,
767            iso4217: 0,
768            name: Ustr::from("Dogecoin"),
769            currency_type: CurrencyType::Crypto,
770        })
771    }
772
773    #[allow(non_snake_case)]
774    #[must_use]
775    pub fn ENA() -> Self {
776        *ENA_LOCK.get_or_init(|| Self {
777            code: Ustr::from("ENA"),
778            precision: 8,
779            iso4217: 0,
780            name: Ustr::from("Ethena"),
781            currency_type: CurrencyType::Crypto,
782        })
783    }
784
785    #[allow(non_snake_case)]
786    #[must_use]
787    pub fn EOS() -> Self {
788        *EOS_LOCK.get_or_init(|| Self {
789            code: Ustr::from("EOS"),
790            precision: 8,
791            iso4217: 0,
792            name: Ustr::from("EOS"),
793            currency_type: CurrencyType::Crypto,
794        })
795    }
796
797    #[allow(non_snake_case)]
798    #[must_use]
799    pub fn ETH() -> Self {
800        *ETH_LOCK.get_or_init(|| Self {
801            code: Ustr::from("ETH"),
802            precision: 8,
803            iso4217: 0,
804            name: Ustr::from("Ethereum"),
805            currency_type: CurrencyType::Crypto,
806        })
807    }
808
809    #[allow(non_snake_case)]
810    #[must_use]
811    pub fn ETHW() -> Self {
812        *ETHW_LOCK.get_or_init(|| Self {
813            code: Ustr::from("ETHW"),
814            precision: 8,
815            iso4217: 0,
816            name: Ustr::from("EthereumPoW"),
817            currency_type: CurrencyType::Crypto,
818        })
819    }
820
821    #[allow(non_snake_case)]
822    #[must_use]
823    pub fn FDUSD() -> Self {
824        *FDUSD_LOCK.get_or_init(|| Self {
825            code: Ustr::from("FDUSD"),
826            precision: 8,
827            iso4217: 0,
828            name: Ustr::from("First Digital USD"),
829            currency_type: CurrencyType::Crypto,
830        })
831    }
832
833    #[allow(non_snake_case)]
834    #[must_use]
835    pub fn GWEI() -> Self {
836        *GWEI_LOCK.get_or_init(|| Self {
837            code: Ustr::from("GWEI"),
838            precision: 8,
839            iso4217: 0,
840            name: Ustr::from("Gwei"),
841            currency_type: CurrencyType::Crypto,
842        })
843    }
844
845    #[allow(non_snake_case)]
846    #[must_use]
847    pub fn HYPE() -> Self {
848        *HYPE_LOCK.get_or_init(|| Self {
849            code: Ustr::from("HYPE"),
850            precision: 8,
851            iso4217: 0,
852            name: Ustr::from("Hyperliquid"),
853            currency_type: CurrencyType::Crypto,
854        })
855    }
856
857    #[allow(non_snake_case)]
858    #[must_use]
859    pub fn JOE() -> Self {
860        *JOE_LOCK.get_or_init(|| Self {
861            code: Ustr::from("JOE"),
862            precision: 8,
863            iso4217: 0,
864            name: Ustr::from("JOE"),
865            currency_type: CurrencyType::Crypto,
866        })
867    }
868
869    #[allow(non_snake_case)]
870    #[must_use]
871    pub fn LINK() -> Self {
872        *LINK_LOCK.get_or_init(|| Self {
873            code: Ustr::from("LINK"),
874            precision: 8,
875            iso4217: 0,
876            name: Ustr::from("Chainlink"),
877            currency_type: CurrencyType::Crypto,
878        })
879    }
880
881    #[allow(non_snake_case)]
882    #[must_use]
883    pub fn LTC() -> Self {
884        *LTC_LOCK.get_or_init(|| Self {
885            code: Ustr::from("LTC"),
886            precision: 8,
887            iso4217: 0,
888            name: Ustr::from("Litecoin"),
889            currency_type: CurrencyType::Crypto,
890        })
891    }
892
893    #[allow(non_snake_case)]
894    #[must_use]
895    pub fn LUNA() -> Self {
896        *LUNA_LOCK.get_or_init(|| Self {
897            code: Ustr::from("LUNA"),
898            precision: 8,
899            iso4217: 0,
900            name: Ustr::from("Terra"),
901            currency_type: CurrencyType::Crypto,
902        })
903    }
904
905    #[allow(non_snake_case)]
906    #[must_use]
907    pub fn MAMUSD() -> Self {
908        *MAMUSD_LOCK.get_or_init(|| Self {
909            code: Ustr::from("MAMUSD"),
910            precision: 8,
911            iso4217: 0,
912            name: Ustr::from("MAMUSD"),
913            currency_type: CurrencyType::Crypto,
914        })
915    }
916
917    #[allow(non_snake_case)]
918    #[must_use]
919    pub fn NBT() -> Self {
920        *NBT_LOCK.get_or_init(|| Self {
921            code: Ustr::from("NBT"),
922            precision: 8,
923            iso4217: 0,
924            name: Ustr::from("NanoByte Token"),
925            currency_type: CurrencyType::Crypto,
926        })
927    }
928
929    #[allow(non_snake_case)]
930    #[must_use]
931    pub fn POL() -> Self {
932        *POL_LOCK.get_or_init(|| Self {
933            code: Ustr::from("POL"),
934            precision: 8,
935            iso4217: 0,
936            name: Ustr::from("Polygon"),
937            currency_type: CurrencyType::Crypto,
938        })
939    }
940
941    #[allow(non_snake_case)]
942    #[must_use]
943    pub fn PROVE() -> Self {
944        *PROVE_LOCK.get_or_init(|| Self {
945            code: Ustr::from("PROVE"),
946            precision: 8,
947            iso4217: 0,
948            name: Ustr::from("Prove AI"),
949            currency_type: CurrencyType::Crypto,
950        })
951    }
952
953    #[allow(non_snake_case)]
954    #[must_use]
955    pub fn RLUSD() -> Self {
956        *RLUSD_LOCK.get_or_init(|| Self {
957            code: Ustr::from("RLUSD"),
958            precision: 8,
959            iso4217: 0,
960            name: Ustr::from("Ripple USD"),
961            currency_type: CurrencyType::Crypto,
962        })
963    }
964
965    #[allow(non_snake_case)]
966    #[must_use]
967    pub fn SOL() -> Self {
968        *SOL_LOCK.get_or_init(|| Self {
969            code: Ustr::from("SOL"),
970            precision: 8,
971            iso4217: 0,
972            name: Ustr::from("Solana"),
973            currency_type: CurrencyType::Crypto,
974        })
975    }
976
977    #[allow(non_snake_case)]
978    #[must_use]
979    pub fn SHIB() -> Self {
980        *SHIB_LOCK.get_or_init(|| Self {
981            code: Ustr::from("SHIB"),
982            precision: 8,
983            iso4217: 0,
984            name: Ustr::from("Shiba Inu"),
985            currency_type: CurrencyType::Crypto,
986        })
987    }
988
989    #[allow(non_snake_case)]
990    #[must_use]
991    pub fn SUI() -> Self {
992        *SUI_LOCK.get_or_init(|| Self {
993            code: Ustr::from("SUI"),
994            precision: 8,
995            iso4217: 0,
996            name: Ustr::from("Sui"),
997            currency_type: CurrencyType::Crypto,
998        })
999    }
1000
1001    #[allow(non_snake_case)]
1002    #[must_use]
1003    pub fn TON() -> Self {
1004        *TON_LOCK.get_or_init(|| Self {
1005            code: Ustr::from("TON"),
1006            precision: 8,
1007            iso4217: 0,
1008            name: Ustr::from("Toncoin"),
1009            currency_type: CurrencyType::Crypto,
1010        })
1011    }
1012
1013    #[allow(non_snake_case)]
1014    #[must_use]
1015    pub fn TRX() -> Self {
1016        *TRX_LOCK.get_or_init(|| Self {
1017            code: Ustr::from("TRX"),
1018            precision: 8,
1019            iso4217: 0,
1020            name: Ustr::from("TRON"),
1021            currency_type: CurrencyType::Crypto,
1022        })
1023    }
1024
1025    #[allow(non_snake_case)]
1026    #[must_use]
1027    pub fn TRYB() -> Self {
1028        *TRYB_LOCK.get_or_init(|| Self {
1029            code: Ustr::from("TRYB"),
1030            precision: 8,
1031            iso4217: 0,
1032            name: Ustr::from("BiLira"),
1033            currency_type: CurrencyType::Crypto,
1034        })
1035    }
1036
1037    #[allow(non_snake_case)]
1038    #[must_use]
1039    pub fn TUSD() -> Self {
1040        *TUSD_LOCK.get_or_init(|| Self {
1041            code: Ustr::from("TUSD"),
1042            precision: 8,
1043            iso4217: 0,
1044            name: Ustr::from("TrueUSD"),
1045            currency_type: CurrencyType::Crypto,
1046        })
1047    }
1048
1049    #[allow(non_snake_case)]
1050    #[must_use]
1051    pub fn UNI() -> Self {
1052        *UNI_LOCK.get_or_init(|| Self {
1053            code: Ustr::from("UNI"),
1054            precision: 8,
1055            iso4217: 0,
1056            name: Ustr::from("Uniswap"),
1057            currency_type: CurrencyType::Crypto,
1058        })
1059    }
1060
1061    #[allow(non_snake_case)]
1062    #[must_use]
1063    pub fn VTC() -> Self {
1064        *VTC_LOCK.get_or_init(|| Self {
1065            code: Ustr::from("VTC"),
1066            precision: 8,
1067            iso4217: 0,
1068            name: Ustr::from("Vertcoin"),
1069            currency_type: CurrencyType::Crypto,
1070        })
1071    }
1072
1073    #[allow(non_snake_case)]
1074    #[must_use]
1075    pub fn WBTC() -> Self {
1076        *WBTC_LOCK.get_or_init(|| Self {
1077            code: Ustr::from("WBTC"),
1078            precision: 8,
1079            iso4217: 0,
1080            name: Ustr::from("Wrapped Bitcoin"),
1081            currency_type: CurrencyType::Crypto,
1082        })
1083    }
1084
1085    #[allow(non_snake_case)]
1086    #[must_use]
1087    pub fn WSB() -> Self {
1088        *WSB_LOCK.get_or_init(|| Self {
1089            code: Ustr::from("WSB"),
1090            precision: 8,
1091            iso4217: 0,
1092            name: Ustr::from("WallStreetBets DApp"),
1093            currency_type: CurrencyType::Crypto,
1094        })
1095    }
1096
1097    #[allow(non_snake_case)]
1098    #[must_use]
1099    pub fn XBT() -> Self {
1100        *XBT_LOCK.get_or_init(|| Self {
1101            code: Ustr::from("XBT"),
1102            precision: 8,
1103            iso4217: 0,
1104            name: Ustr::from("Bitcoin"),
1105            currency_type: CurrencyType::Crypto,
1106        })
1107    }
1108
1109    #[allow(non_snake_case)]
1110    #[must_use]
1111    pub fn XEC() -> Self {
1112        *XEC_LOCK.get_or_init(|| Self {
1113            code: Ustr::from("XEC"),
1114            precision: 8,
1115            iso4217: 0,
1116            name: Ustr::from("eCash"),
1117            currency_type: CurrencyType::Crypto,
1118        })
1119    }
1120
1121    #[allow(non_snake_case)]
1122    #[must_use]
1123    pub fn XLM() -> Self {
1124        *XLM_LOCK.get_or_init(|| Self {
1125            code: Ustr::from("XLM"),
1126            precision: 8,
1127            iso4217: 0,
1128            name: Ustr::from("Stellar Lumen"),
1129            currency_type: CurrencyType::Crypto,
1130        })
1131    }
1132
1133    #[allow(non_snake_case)]
1134    #[must_use]
1135    pub fn XMR() -> Self {
1136        *XMR_LOCK.get_or_init(|| Self {
1137            code: Ustr::from("XMR"),
1138            precision: 8,
1139            iso4217: 0,
1140            name: Ustr::from("Monero"),
1141            currency_type: CurrencyType::Crypto,
1142        })
1143    }
1144
1145    #[allow(non_snake_case)]
1146    #[must_use]
1147    pub fn USDT() -> Self {
1148        *USDT_LOCK.get_or_init(|| Self {
1149            code: Ustr::from("USDT"),
1150            precision: 8,
1151            iso4217: 0,
1152            name: Ustr::from("Tether"),
1153            currency_type: CurrencyType::Crypto,
1154        })
1155    }
1156
1157    #[allow(non_snake_case)]
1158    #[must_use]
1159    pub fn XRP() -> Self {
1160        *XRP_LOCK.get_or_init(|| Self {
1161            code: Ustr::from("XRP"),
1162            precision: 6,
1163            iso4217: 0,
1164            name: Ustr::from("XRP"),
1165            currency_type: CurrencyType::Crypto,
1166        })
1167    }
1168
1169    #[allow(non_snake_case)]
1170    #[must_use]
1171    pub fn XTZ() -> Self {
1172        *XTZ_LOCK.get_or_init(|| Self {
1173            code: Ustr::from("XTZ"),
1174            precision: 6,
1175            iso4217: 0,
1176            name: Ustr::from("Tezos"),
1177            currency_type: CurrencyType::Crypto,
1178        })
1179    }
1180
1181    #[must_use]
1182    #[allow(non_snake_case)]
1183    pub fn USDC() -> Self {
1184        *USDC_LOCK.get_or_init(|| Self {
1185            code: Ustr::from("USDC"),
1186            precision: 8,
1187            iso4217: 0,
1188            name: Ustr::from("USD Coin"),
1189            currency_type: CurrencyType::Crypto,
1190        })
1191    }
1192
1193    #[must_use]
1194    #[allow(non_snake_case)]
1195    pub fn USDC_POS() -> Self {
1196        *USDC_POS_LOCK.get_or_init(|| Self {
1197            code: Ustr::from("USDC.e"),
1198            precision: 6,
1199            iso4217: 0,
1200            name: Ustr::from("USD Coin (PoS)"),
1201            currency_type: CurrencyType::Crypto,
1202        })
1203    }
1204
1205    #[allow(non_snake_case)]
1206    #[must_use]
1207    pub fn USDP() -> Self {
1208        *USDP_LOCK.get_or_init(|| Self {
1209            code: Ustr::from("USDP"),
1210            precision: 8,
1211            iso4217: 0,
1212            name: Ustr::from("Pax Dollar"),
1213            currency_type: CurrencyType::Crypto,
1214        })
1215    }
1216
1217    #[allow(non_snake_case)]
1218    #[must_use]
1219    pub fn pUSD() -> Self {
1220        *PUSD_LOCK.get_or_init(|| Self {
1221            code: Ustr::from("pUSD"),
1222            precision: 6,
1223            iso4217: 0,
1224            name: Ustr::from("Polymarket USD"),
1225            currency_type: CurrencyType::Crypto,
1226        })
1227    }
1228
1229    #[allow(non_snake_case)]
1230    #[must_use]
1231    pub fn ZEC() -> Self {
1232        *ZEC_LOCK.get_or_init(|| Self {
1233            code: Ustr::from("ZEC"),
1234            precision: 8,
1235            iso4217: 0,
1236            name: Ustr::from("Zcash"),
1237            currency_type: CurrencyType::Crypto,
1238        })
1239    }
1240}
1241
1242/// A map of built-in `Currency` constants.
1243pub static CURRENCY_MAP: LazyLock<Mutex<HashMap<String, Currency>>> = LazyLock::new(|| {
1244    let mut map = HashMap::new();
1245    ///////////////////////////////////////////////////////////////////////////
1246    // Fiat currencies
1247    ///////////////////////////////////////////////////////////////////////////
1248    map.insert(Currency::AUD().code.to_string(), Currency::AUD());
1249    map.insert(Currency::BRL().code.to_string(), Currency::BRL());
1250    map.insert(Currency::CAD().code.to_string(), Currency::CAD());
1251    map.insert(Currency::CHF().code.to_string(), Currency::CHF());
1252    map.insert(Currency::CNY().code.to_string(), Currency::CNY());
1253    map.insert(Currency::CNH().code.to_string(), Currency::CNH());
1254    map.insert(Currency::CZK().code.to_string(), Currency::CZK());
1255    map.insert(Currency::DKK().code.to_string(), Currency::DKK());
1256    map.insert(Currency::EUR().code.to_string(), Currency::EUR());
1257    map.insert(Currency::GBP().code.to_string(), Currency::GBP());
1258    map.insert(Currency::HKD().code.to_string(), Currency::HKD());
1259    map.insert(Currency::HUF().code.to_string(), Currency::HUF());
1260    map.insert(Currency::ILS().code.to_string(), Currency::ILS());
1261    map.insert(Currency::INR().code.to_string(), Currency::INR());
1262    map.insert(Currency::JPY().code.to_string(), Currency::JPY());
1263    map.insert(Currency::KRW().code.to_string(), Currency::KRW());
1264    map.insert(Currency::MXN().code.to_string(), Currency::MXN());
1265    map.insert(Currency::NOK().code.to_string(), Currency::NOK());
1266    map.insert(Currency::NZD().code.to_string(), Currency::NZD());
1267    map.insert(Currency::PLN().code.to_string(), Currency::PLN());
1268    map.insert(Currency::RUB().code.to_string(), Currency::RUB());
1269    map.insert(Currency::SAR().code.to_string(), Currency::SAR());
1270    map.insert(Currency::SEK().code.to_string(), Currency::SEK());
1271    map.insert(Currency::SGD().code.to_string(), Currency::SGD());
1272    map.insert(Currency::THB().code.to_string(), Currency::THB());
1273    map.insert(Currency::TRY().code.to_string(), Currency::TRY());
1274    map.insert(Currency::USD().code.to_string(), Currency::USD());
1275    map.insert(Currency::XAG().code.to_string(), Currency::XAG());
1276    map.insert(Currency::XAU().code.to_string(), Currency::XAU());
1277    map.insert(Currency::XPT().code.to_string(), Currency::XPT());
1278    map.insert(Currency::ZAR().code.to_string(), Currency::ZAR());
1279    ///////////////////////////////////////////////////////////////////////////
1280    // Crypto currencies
1281    ///////////////////////////////////////////////////////////////////////////
1282    map.insert(Currency::AAVE().code.to_string(), Currency::AAVE());
1283    map.insert(Currency::ACA().code.to_string(), Currency::ACA());
1284    map.insert(Currency::ADA().code.to_string(), Currency::ADA());
1285    map.insert(Currency::APT().code.to_string(), Currency::APT());
1286    map.insert(Currency::ARB().code.to_string(), Currency::ARB());
1287    map.insert(Currency::AVAX().code.to_string(), Currency::AVAX());
1288    map.insert(Currency::BCH().code.to_string(), Currency::BCH());
1289    map.insert(Currency::BIO().code.to_string(), Currency::BIO());
1290    map.insert(Currency::BTC().code.to_string(), Currency::BTC());
1291    map.insert(Currency::BTTC().code.to_string(), Currency::BTTC());
1292    map.insert(Currency::BNB().code.to_string(), Currency::BNB());
1293    map.insert(Currency::BRZ().code.to_string(), Currency::BRZ());
1294    map.insert(Currency::BSV().code.to_string(), Currency::BSV());
1295    map.insert(Currency::BUSD().code.to_string(), Currency::BUSD());
1296    map.insert(Currency::CRV().code.to_string(), Currency::CRV());
1297    map.insert(Currency::DASH().code.to_string(), Currency::DASH());
1298    map.insert(Currency::DOGE().code.to_string(), Currency::DOGE());
1299    map.insert(Currency::DOT().code.to_string(), Currency::DOT());
1300    map.insert(Currency::ENA().code.to_string(), Currency::ENA());
1301    map.insert(Currency::EOS().code.to_string(), Currency::EOS());
1302    map.insert(Currency::ETH().code.to_string(), Currency::ETH());
1303    map.insert(Currency::ETHW().code.to_string(), Currency::ETHW());
1304    map.insert(Currency::FDUSD().code.to_string(), Currency::FDUSD());
1305    map.insert(Currency::GWEI().code.to_string(), Currency::GWEI());
1306    map.insert(Currency::HYPE().code.to_string(), Currency::HYPE());
1307    map.insert(Currency::JOE().code.to_string(), Currency::JOE());
1308    map.insert(Currency::LINK().code.to_string(), Currency::LINK());
1309    map.insert(Currency::LTC().code.to_string(), Currency::LTC());
1310    map.insert(Currency::LUNA().code.to_string(), Currency::LUNA());
1311    map.insert(Currency::MAMUSD().code.to_string(), Currency::MAMUSD());
1312    map.insert(Currency::NBT().code.to_string(), Currency::NBT());
1313    map.insert(Currency::POL().code.to_string(), Currency::POL());
1314    map.insert(Currency::PROVE().code.to_string(), Currency::PROVE());
1315    map.insert(Currency::RLUSD().code.to_string(), Currency::RLUSD());
1316    map.insert(Currency::SOL().code.to_string(), Currency::SOL());
1317    map.insert(Currency::SUI().code.to_string(), Currency::SUI());
1318    map.insert(Currency::TON().code.to_string(), Currency::TON());
1319    map.insert(Currency::TRX().code.to_string(), Currency::TRX());
1320    map.insert(Currency::TRYB().code.to_string(), Currency::TRYB());
1321    map.insert(Currency::TUSD().code.to_string(), Currency::TUSD());
1322    map.insert(Currency::UNI().code.to_string(), Currency::UNI());
1323    map.insert(Currency::VTC().code.to_string(), Currency::VTC());
1324    map.insert(Currency::WBTC().code.to_string(), Currency::WBTC());
1325    map.insert(Currency::WSB().code.to_string(), Currency::WSB());
1326    map.insert(Currency::XBT().code.to_string(), Currency::XBT());
1327    map.insert(Currency::XEC().code.to_string(), Currency::XEC());
1328    map.insert(Currency::XLM().code.to_string(), Currency::XLM());
1329    map.insert(Currency::XMR().code.to_string(), Currency::XMR());
1330    map.insert(Currency::XRP().code.to_string(), Currency::XRP());
1331    map.insert(Currency::XTZ().code.to_string(), Currency::XTZ());
1332    map.insert(Currency::USDC().code.to_string(), Currency::USDC());
1333    map.insert(Currency::USDC_POS().code.to_string(), Currency::USDC_POS());
1334    map.insert(Currency::USDP().code.to_string(), Currency::USDP());
1335    map.insert(Currency::pUSD().code.to_string(), Currency::pUSD());
1336    map.insert(Currency::USDT().code.to_string(), Currency::USDT());
1337    map.insert(Currency::ZEC().code.to_string(), Currency::ZEC());
1338    Mutex::new(map)
1339});
1340
1341#[cfg(test)]
1342mod tests {
1343    use rstest::rstest;
1344
1345    use super::*;
1346    use crate::enums::CurrencyType;
1347
1348    #[rstest]
1349    fn test_pusd_currency_invariants() {
1350        // pUSD is Polymarket's CLOB V2 collateral token; the adapter assumes
1351        // 6-decimal precision matching the underlying USDC backing, the code
1352        // string `"pUSD"`, and discoverability via the global registry.
1353        let pusd = Currency::pUSD();
1354        assert_eq!(pusd.code.as_str(), "pUSD");
1355        assert_eq!(pusd.precision, 6);
1356        assert_eq!(pusd.iso4217, 0);
1357        assert_eq!(pusd.currency_type, CurrencyType::Crypto);
1358
1359        // Registered in the global map and round-trips by code.
1360        let from_map = Currency::try_from_str("pUSD").expect("pUSD must be registered");
1361        assert_eq!(from_map, pusd);
1362
1363        // The locked accessor is idempotent.
1364        assert_eq!(Currency::pUSD(), Currency::pUSD());
1365    }
1366}