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