nautilus_model/
currencies.rs

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