@b3dotfun/sdk 0.0.58-alpha.3 → 0.0.58-test.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/dist/cjs/anyspend/react/components/common/CryptoPaymentMethod.js +0 -4
  2. package/dist/cjs/anyspend/utils/index.d.ts +0 -1
  3. package/dist/cjs/anyspend/utils/index.js +0 -1
  4. package/dist/cjs/global-account/react/components/B3DynamicModal.js +0 -17
  5. package/dist/cjs/global-account/react/hooks/useWagmiConfig.d.ts +1 -441
  6. package/dist/cjs/global-account/react/hooks/useWagmiConfig.js +0 -2
  7. package/dist/cjs/shared/react/components/CurrencySelector.js +3 -8
  8. package/dist/cjs/shared/react/components/FormattedCurrency.d.ts +3 -3
  9. package/dist/cjs/shared/react/components/FormattedCurrency.js +26 -31
  10. package/dist/cjs/shared/react/hooks/useCurrencyConversion.d.ts +5 -8
  11. package/dist/cjs/shared/react/hooks/useCurrencyConversion.js +94 -153
  12. package/dist/cjs/shared/react/stores/currencyStore.d.ts +8 -83
  13. package/dist/cjs/shared/react/stores/currencyStore.js +5 -147
  14. package/dist/esm/anyspend/react/components/common/CryptoPaymentMethod.js +1 -5
  15. package/dist/esm/anyspend/utils/index.d.ts +0 -1
  16. package/dist/esm/anyspend/utils/index.js +0 -1
  17. package/dist/esm/global-account/react/components/B3DynamicModal.js +0 -17
  18. package/dist/esm/global-account/react/hooks/useWagmiConfig.d.ts +1 -441
  19. package/dist/esm/global-account/react/hooks/useWagmiConfig.js +0 -2
  20. package/dist/esm/shared/react/components/CurrencySelector.js +5 -10
  21. package/dist/esm/shared/react/components/FormattedCurrency.d.ts +3 -3
  22. package/dist/esm/shared/react/components/FormattedCurrency.js +26 -31
  23. package/dist/esm/shared/react/hooks/useCurrencyConversion.d.ts +5 -8
  24. package/dist/esm/shared/react/hooks/useCurrencyConversion.js +95 -154
  25. package/dist/esm/shared/react/stores/currencyStore.d.ts +8 -83
  26. package/dist/esm/shared/react/stores/currencyStore.js +5 -143
  27. package/dist/types/anyspend/utils/index.d.ts +0 -1
  28. package/dist/types/global-account/react/hooks/useWagmiConfig.d.ts +1 -441
  29. package/dist/types/shared/react/components/FormattedCurrency.d.ts +3 -3
  30. package/dist/types/shared/react/hooks/useCurrencyConversion.d.ts +5 -8
  31. package/dist/types/shared/react/stores/currencyStore.d.ts +8 -83
  32. package/package.json +8 -4
  33. package/src/anyspend/react/components/common/CryptoPaymentMethod.tsx +2 -6
  34. package/src/anyspend/utils/index.ts +0 -1
  35. package/src/global-account/react/components/B3DynamicModal.tsx +0 -20
  36. package/src/global-account/react/hooks/useWagmiConfig.tsx +0 -2
  37. package/src/shared/react/components/CurrencySelector.tsx +5 -36
  38. package/src/shared/react/components/FormattedCurrency.tsx +30 -36
  39. package/src/shared/react/hooks/__tests__/useCurrencyConversion.test.ts +14 -14
  40. package/src/shared/react/hooks/useCurrencyConversion.ts +96 -163
  41. package/src/shared/react/stores/currencyStore.ts +10 -216
  42. package/dist/cjs/anyspend/utils/accountStore.d.ts +0 -7
  43. package/dist/cjs/anyspend/utils/accountStore.js +0 -8
  44. package/dist/esm/anyspend/utils/accountStore.d.ts +0 -7
  45. package/dist/esm/anyspend/utils/accountStore.js +0 -5
  46. package/dist/types/anyspend/utils/accountStore.d.ts +0 -7
  47. package/src/anyspend/utils/accountStore.ts +0 -12
@@ -1,6 +1,6 @@
1
1
  import { useQuery } from "@tanstack/react-query";
2
2
  import { formatDisplayNumber } from "@b3dotfun/sdk/shared/utils/number";
3
- import { useCurrencyStore, getCurrencySymbol, getCurrencyMetadata } from "../stores/currencyStore";
3
+ import { CURRENCY_SYMBOLS, useCurrencyStore } from "../stores/currencyStore";
4
4
 
5
5
  const COINBASE_API_URL = "https://api.coinbase.com/v2/exchange-rates";
6
6
  const REFETCH_INTERVAL_MS = 30000;
@@ -47,11 +47,9 @@ async function fetchAllExchangeRates(baseCurrency: string): Promise<Record<strin
47
47
  export function useCurrencyConversion() {
48
48
  const selectedCurrency = useCurrencyStore(state => state.selectedCurrency);
49
49
  const baseCurrency = useCurrencyStore(state => state.baseCurrency);
50
- const getCustomExchangeRate = useCurrencyStore(state => state.getExchangeRate);
51
- const customCurrencies = useCurrencyStore(state => state.customCurrencies);
52
50
 
53
- // Fetch all exchange rates for the base currency from Coinbase API
54
- const { data: apiExchangeRates } = useQuery({
51
+ // Fetch all exchange rates for the base currency
52
+ const { data: exchangeRates } = useQuery({
55
53
  queryKey: ["exchangeRates", baseCurrency],
56
54
  queryFn: () => fetchAllExchangeRates(baseCurrency),
57
55
  refetchInterval: REFETCH_INTERVAL_MS,
@@ -60,163 +58,93 @@ export function useCurrencyConversion() {
60
58
  retryDelay: attemptIndex => Math.min(1000 * 2 ** attemptIndex, REFETCH_INTERVAL_MS),
61
59
  });
62
60
 
63
- /**
64
- * Get exchange rate between two currencies, checking custom rates first, then API rates.
65
- * Supports chaining through base currency for custom currencies.
66
- *
67
- * Examples:
68
- * - WIN → USD: Checks WIN→USD custom rate, then chains WIN→B3→USD
69
- * - BTC → EUR: Checks BTC→EUR custom rate, then chains BTC→B3→EUR
70
- */
71
- const getExchangeRate = (from: string, to: string): number | undefined => {
72
- // If same currency, rate is 1
73
- if (from === to) return 1;
74
-
75
- // 1. Check direct custom exchange rate first
76
- const directCustomRate = getCustomExchangeRate(from, to);
77
- if (directCustomRate !== undefined) {
78
- return directCustomRate;
79
- }
80
-
81
- // 2. Check direct API rate (from base currency)
82
- if (from === baseCurrency && apiExchangeRates) {
83
- return apiExchangeRates[to];
84
- }
85
-
86
- // 3. Try to chain through base currency using custom rates
87
- // e.g., WIN → B3 → USD (where WIN→B3 is custom, B3→USD is API)
88
- const customFromToBase = getCustomExchangeRate(from, baseCurrency);
89
- if (customFromToBase !== undefined) {
90
- // We have a custom rate from 'from' to base
91
- // Now get rate from base to 'to'
92
- const baseToTo = apiExchangeRates?.[to] ?? getCustomExchangeRate(baseCurrency, to);
93
- if (baseToTo !== undefined) {
94
- return customFromToBase * baseToTo;
95
- }
96
- }
97
-
98
- // 4. Try reverse: chain from base currency through custom rate
99
- // e.g., USD → B3 → WIN (where B3→WIN is custom)
100
- const customBaseToTo = getCustomExchangeRate(baseCurrency, to);
101
- if (customBaseToTo !== undefined && apiExchangeRates) {
102
- // We have a custom rate from base to 'to'
103
- // Now get rate from 'from' to base
104
- const fromToBase = apiExchangeRates[from];
105
- if (fromToBase !== undefined && fromToBase !== 0) {
106
- return fromToBase * customBaseToTo;
107
- }
108
- }
109
-
110
- // 5. Fall back to pure API conversion through base
111
- // e.g., EUR to GBP = (EUR to B3) * (B3 to GBP)
112
- if (apiExchangeRates) {
113
- const fromToBase = apiExchangeRates[from];
114
- const baseToTo = apiExchangeRates[to];
115
- if (fromToBase && baseToTo && fromToBase !== 0) {
116
- return baseToTo / fromToBase;
117
- }
118
- }
119
-
120
- return undefined;
121
- };
122
-
123
- // Extract specific rates
124
- const exchangeRate = getExchangeRate(baseCurrency, selectedCurrency);
61
+ // Extract specific rates from the full rates object
62
+ const exchangeRate = exchangeRates?.[selectedCurrency];
63
+ const usdRate = exchangeRates?.["USD"];
125
64
 
126
65
  /**
127
- * Formats a numeric value as a currency string with automatic conversion.
66
+ * Formats a numeric value as a currency string with proper conversion and formatting.
128
67
  *
129
- * New behavior:
130
- * - Takes the SOURCE currency (what the value is in) as a required parameter
131
- * - Automatically converts from source → display currency (selected in picker)
132
- * - Supports multi-hop conversions (e.g., WIN → B3 → USD)
133
- * - Applies currency-specific formatting rules to the TARGET currency
68
+ * Behavior:
69
+ * - When exchange rate is unavailable, displays value in base currency
70
+ * - Applies currency-specific formatting rules:
71
+ * - JPY/KRW: No decimal places
72
+ * - ETH/SOL: 6 significant digits with subscript notation for small values
73
+ * - Fiat (USD/EUR/GBP/CAD/AUD): 2 decimal places minimum for values < 1000
74
+ * - Handles symbol positioning (prefix for fiat, suffix for crypto)
134
75
  *
135
- * @param value - The numeric value to format
136
- * @param sourceCurrency - The currency the value is currently in (e.g., "WIN", "B3", "USD")
76
+ * @param value - The numeric value to format (in base currency)
137
77
  * @param options - Optional formatting overrides
138
- * @param options.decimals - Override number of decimal places for display
78
+ * @param options.decimals - Override number of decimal places
79
+ * @param options.currency - Override currency (bypasses conversion)
139
80
  * @returns Formatted currency string with appropriate symbol and decimal places
140
81
  *
141
82
  * @example
142
83
  * ```tsx
143
- * // Value is 3031 WIN, user has USD selected
144
- * formatCurrencyValue(3031, "WIN") // Returns "$30.31" (converts WIN→B3→USD)
145
- *
146
- * // Value is 100 B3, user has B3 selected (no conversion)
147
- * formatCurrencyValue(100, "B3") // Returns "100 B3"
148
- *
149
- * // Value is 50 USD, user has EUR selected
150
- * formatCurrencyValue(50, "USD") // Returns "€45.50" (converts USD→EUR)
84
+ * formatCurrencyValue(100) // Returns "$100.00" if USD is selected
85
+ * formatCurrencyValue(0.0001) // Returns "0.0₄1 ETH" if ETH is selected
86
+ * formatCurrencyValue(1500) // Returns "¥1,500" if JPY is selected
87
+ * formatCurrencyValue(100, { decimals: 4, currency: "ETH" }) // Returns "100.0000 ETH"
151
88
  * ```
152
89
  */
153
- const formatCurrencyValue = (value: number, sourceCurrency: string, options?: { decimals?: number }): string => {
90
+ const formatCurrencyValue = (value: number, options?: { decimals?: number; currency?: string }): string => {
91
+ const overrideCurrency = options?.currency;
154
92
  const overrideDecimals = options?.decimals;
155
93
 
156
- // If source and display currency are the same, no conversion needed
157
- if (sourceCurrency === selectedCurrency) {
158
- const customMetadata = getCurrencyMetadata(sourceCurrency);
159
- const decimalsToUse = overrideDecimals !== undefined ? overrideDecimals : customMetadata?.decimals;
94
+ // Custom currency provided - bypass conversion and use simple formatting
95
+ if (overrideCurrency) {
96
+ const decimalsToUse = overrideDecimals !== undefined ? overrideDecimals : overrideCurrency === "B3" ? 0 : 2;
160
97
 
161
98
  const formatted = formatDisplayNumber(value, {
162
99
  fractionDigits: decimalsToUse,
163
- significantDigits: decimalsToUse === undefined ? 6 : undefined,
164
- showSubscripts: customMetadata?.showSubscripts ?? false,
100
+ showSubscripts: false,
165
101
  });
166
-
167
- const symbol = getCurrencySymbol(sourceCurrency);
168
- const usePrefix = customMetadata?.prefixSymbol ?? ["USD", "EUR", "GBP", "CAD", "AUD"].includes(sourceCurrency);
169
-
170
- return usePrefix ? `${symbol}${formatted}` : `${formatted} ${symbol}`;
102
+ return `${formatted} ${overrideCurrency}`;
171
103
  }
172
104
 
173
- // Get exchange rate from source to display currency
174
- const conversionRate = getExchangeRate(sourceCurrency, selectedCurrency);
105
+ // Custom decimals for base currency without conversion
106
+ if (overrideDecimals !== undefined && selectedCurrency === baseCurrency) {
107
+ const formatted = formatDisplayNumber(value, {
108
+ fractionDigits: overrideDecimals,
109
+ showSubscripts: false,
110
+ });
111
+ return `${formatted} ${baseCurrency}`;
112
+ }
175
113
 
176
- // If no conversion rate available, display in source currency
177
- if (conversionRate === undefined) {
178
- const customMetadata = getCurrencyMetadata(sourceCurrency);
114
+ // If showing base currency, no conversion needed
115
+ if (selectedCurrency === baseCurrency || !exchangeRate) {
179
116
  const formatted = formatDisplayNumber(value, {
180
- significantDigits: 6,
181
- showSubscripts: customMetadata?.showSubscripts ?? false,
117
+ significantDigits: baseCurrency === "B3" ? 6 : 8,
118
+ showSubscripts: true,
182
119
  });
183
- const symbol = getCurrencySymbol(sourceCurrency);
184
- return `${formatted} ${symbol}`;
120
+ return `${formatted} ${baseCurrency}`;
185
121
  }
186
122
 
187
- // Convert value
188
- const convertedValue = value * conversionRate;
123
+ // Convert value using current exchange rate
124
+ const convertedValue = value * exchangeRate;
125
+ const symbol = CURRENCY_SYMBOLS[selectedCurrency];
189
126
 
190
- // Get symbol and metadata for display currency
191
- const symbol = getCurrencySymbol(selectedCurrency);
192
- const customMetadata = getCurrencyMetadata(selectedCurrency);
193
- const usePrefix = customMetadata?.prefixSymbol ?? ["USD", "EUR", "GBP", "CAD", "AUD"].includes(selectedCurrency);
127
+ // Currencies that display symbol before the number (e.g., $100.00)
128
+ const prefixCurrencies = ["USD", "EUR", "GBP", "CAD", "AUD"];
194
129
 
195
130
  let formatted: string;
196
131
 
197
- // Apply formatting based on display currency
198
- if (overrideDecimals !== undefined) {
199
- formatted = formatDisplayNumber(convertedValue, {
200
- fractionDigits: overrideDecimals,
201
- showSubscripts: false,
202
- });
203
- } else if (customMetadata) {
204
- formatted = formatDisplayNumber(convertedValue, {
205
- fractionDigits: customMetadata.decimals,
206
- significantDigits: customMetadata.decimals === undefined ? 6 : undefined,
207
- showSubscripts: customMetadata.showSubscripts ?? false,
208
- });
209
- } else if (selectedCurrency === "JPY" || selectedCurrency === "KRW") {
132
+ if (selectedCurrency === "JPY" || selectedCurrency === "KRW") {
133
+ // Japanese Yen and Korean Won don't use decimal places
210
134
  formatted = formatDisplayNumber(convertedValue, {
211
135
  fractionDigits: 0,
212
136
  showSubscripts: false,
213
137
  });
214
138
  } else if (selectedCurrency === "ETH" || selectedCurrency === "SOL") {
139
+ // Crypto currencies use more precision and subscript notation
140
+ // for very small amounts (e.g., 0.0₃45 ETH)
215
141
  formatted = formatDisplayNumber(convertedValue, {
216
142
  significantDigits: 6,
217
143
  showSubscripts: true,
218
144
  });
219
145
  } else {
146
+ // Standard fiat currencies (USD, EUR, GBP, CAD, AUD)
147
+ // Use 2 decimal places minimum for amounts under 1000
220
148
  formatted = formatDisplayNumber(convertedValue, {
221
149
  significantDigits: 6,
222
150
  fractionDigits: convertedValue < 1000 ? 2 : undefined,
@@ -224,62 +152,71 @@ export function useCurrencyConversion() {
224
152
  });
225
153
  }
226
154
 
227
- return usePrefix ? `${symbol}${formatted}` : `${formatted} ${symbol}`;
155
+ // Apply currency symbol with correct positioning
156
+ if (prefixCurrencies.includes(selectedCurrency)) {
157
+ return `${symbol}${formatted}`;
158
+ } else {
159
+ // Suffix currencies: JPY, KRW, ETH, SOL, B3
160
+ return `${formatted} ${symbol}`;
161
+ }
228
162
  };
229
163
 
230
164
  /**
231
165
  * Formats a tooltip value showing the alternate currency representation.
232
166
  *
233
- * New behavior:
234
- * - Takes the SOURCE currency (what the value is in)
235
- * - When displaying in non-USD: Shows USD equivalent in tooltip
236
- * - When displaying in USD: Shows source currency in tooltip
167
+ * Behavior:
168
+ * - When displaying base currency: Shows USD equivalent
169
+ * - When displaying other currency: Shows base currency equivalent
170
+ * - For custom currencies: Shows appropriate conversion or original value
237
171
  *
238
172
  * @param value - The numeric value to format
239
- * @param sourceCurrency - The currency the value is currently in
173
+ * @param customCurrency - Optional custom currency override
240
174
  * @returns Formatted tooltip string
241
175
  *
242
176
  * @example
243
177
  * ```tsx
244
- * // Value is 3031 WIN, displaying as EUR
245
- * formatTooltipValue(3031, "WIN") // Returns "$30.31 USD"
246
- *
247
- * // Value is 100 B3, displaying as USD
248
- * formatTooltipValue(100, "B3") // Returns "100 B3"
178
+ * formatTooltipValue(100) // Returns "$150.00 USD" if displaying B3 with rate 1.5
179
+ * formatTooltipValue(100, "ETH") // Returns "100.0000 ETH" if custom currency
249
180
  * ```
250
181
  */
251
- const formatTooltipValue = (value: number, sourceCurrency: string): string => {
182
+ const formatTooltipValue = (value: number, customCurrency?: string): string => {
183
+ const displayCurrency = customCurrency || selectedCurrency;
252
184
  const absoluteValue = Math.abs(value);
253
185
 
254
- // If displaying in USD, show source currency in tooltip
255
- if (selectedCurrency === "USD") {
256
- const formatted = formatDisplayNumber(absoluteValue, {
257
- significantDigits: 6,
258
- showSubscripts: getCurrencyMetadata(sourceCurrency)?.showSubscripts ?? false,
259
- });
260
- const symbol = getCurrencySymbol(sourceCurrency);
261
- return `${formatted} ${symbol}`;
186
+ // Custom currency provided
187
+ if (customCurrency) {
188
+ if (customCurrency === baseCurrency) {
189
+ // Show USD equivalent for base currency using USD rate
190
+ const usdValue = usdRate ? absoluteValue * usdRate : absoluteValue;
191
+ const formatted = formatDisplayNumber(usdValue, {
192
+ significantDigits: 6,
193
+ fractionDigits: usdValue < 1000 ? 2 : undefined,
194
+ showSubscripts: true,
195
+ });
196
+ return `$${formatted} USD`;
197
+ } else {
198
+ // Show as-is for other custom currencies
199
+ return `${formatDisplayNumber(absoluteValue, { significantDigits: 6 })} ${customCurrency}`;
200
+ }
262
201
  }
263
202
 
264
- // Otherwise, show USD equivalent in tooltip
265
- const usdRate = getExchangeRate(sourceCurrency, "USD");
266
- if (usdRate === undefined) {
267
- // Fallback to source currency if no USD rate
268
- const formatted = formatDisplayNumber(absoluteValue, {
203
+ // Showing base currency - display USD equivalent
204
+ if (displayCurrency === baseCurrency) {
205
+ const usdValue = usdRate ? absoluteValue * usdRate : absoluteValue;
206
+ const formatted = formatDisplayNumber(usdValue, {
269
207
  significantDigits: 6,
270
- showSubscripts: getCurrencyMetadata(sourceCurrency)?.showSubscripts ?? false,
208
+ fractionDigits: usdValue < 1000 ? 2 : undefined,
209
+ showSubscripts: true,
271
210
  });
272
- const symbol = getCurrencySymbol(sourceCurrency);
273
- return `${formatted} ${symbol}`;
211
+ return `$${formatted} USD`;
274
212
  }
275
213
 
276
- const usdValue = absoluteValue * usdRate;
277
- const formatted = formatDisplayNumber(usdValue, {
278
- significantDigits: 6,
279
- fractionDigits: usdValue < 1000 ? 2 : undefined,
214
+ // Showing other currency - display base currency equivalent
215
+ const formatted = formatDisplayNumber(absoluteValue, {
216
+ significantDigits: baseCurrency === "B3" ? 6 : 8,
280
217
  showSubscripts: true,
281
218
  });
282
- return `$${formatted} USD`;
219
+ return `${formatted} ${baseCurrency}`;
283
220
  };
284
221
 
285
222
  return {
@@ -294,12 +231,8 @@ export function useCurrencyConversion() {
294
231
  /** Format a tooltip value showing alternate currency representation */
295
232
  formatTooltipValue,
296
233
  /** Symbol for the currently selected currency (e.g., "$", "€", "ETH") */
297
- selectedCurrencySymbol: getCurrencySymbol(selectedCurrency),
234
+ selectedCurrencySymbol: CURRENCY_SYMBOLS[selectedCurrency],
298
235
  /** Symbol for the base currency */
299
- baseCurrencySymbol: getCurrencySymbol(baseCurrency),
300
- /** Get exchange rate between any two currencies */
301
- getExchangeRate,
302
- /** All registered custom currencies */
303
- customCurrencies,
236
+ baseCurrencySymbol: CURRENCY_SYMBOLS[baseCurrency],
304
237
  };
305
238
  }
@@ -2,41 +2,11 @@ import { create } from "zustand";
2
2
  import { persist } from "zustand/middleware";
3
3
 
4
4
  /**
5
- * Built-in supported currencies for display and conversion.
5
+ * Supported currencies for display and conversion.
6
6
  * Includes fiat currencies (USD, EUR, GBP, JPY, CAD, AUD, KRW) and crypto (ETH, SOL, B3).
7
7
  */
8
8
  export type SupportedCurrency = "ETH" | "USD" | "EUR" | "GBP" | "JPY" | "CAD" | "AUD" | "B3" | "SOL" | "KRW";
9
9
 
10
- /**
11
- * Metadata for a custom currency including display formatting rules.
12
- */
13
- export interface CurrencyMetadata {
14
- /** The currency code/symbol (e.g., "BTC", "DOGE") */
15
- code: string;
16
- /** Display symbol for the currency (e.g., "₿", "Ð") */
17
- symbol: string;
18
- /** Human-readable name (e.g., "Bitcoin", "Dogecoin") */
19
- name: string;
20
- /** Whether to show symbol before the value (true for $100, false for 100 ETH) */
21
- prefixSymbol?: boolean;
22
- /** Number of decimal places to show (undefined uses smart formatting) */
23
- decimals?: number;
24
- /** Whether to use subscript notation for small values */
25
- showSubscripts?: boolean;
26
- }
27
-
28
- /**
29
- * Exchange rate between two currencies.
30
- */
31
- export interface ExchangeRate {
32
- /** Currency code being converted from */
33
- from: string;
34
- /** Currency code being converted to */
35
- to: string;
36
- /** Exchange rate multiplier (amount_in_to = amount_in_from * rate) */
37
- rate: number;
38
- }
39
-
40
10
  /**
41
11
  * Currency symbols used for display formatting.
42
12
  * Prefix currencies (USD, EUR, GBP, CAD, AUD) show symbol before the amount.
@@ -75,214 +45,38 @@ export const CURRENCY_NAMES: Record<SupportedCurrency, string> = {
75
45
  * Currency store state interface.
76
46
  * @property selectedCurrency - The currency currently selected for display
77
47
  * @property baseCurrency - The base currency for conversion (typically B3)
78
- * @property customCurrencies - Map of custom currency codes to their metadata
79
- * @property customExchangeRates - Map of "FROM-TO" pairs to exchange rates
80
48
  * @property setSelectedCurrency - Update the selected display currency
81
49
  * @property setBaseCurrency - Update the base currency for conversions
82
- * @property addCurrency - Register a new custom currency with metadata
83
- * @property removeCurrency - Remove a custom currency
84
- * @property setExchangeRate - Set a custom exchange rate between two currencies
85
- * @property getExchangeRate - Get exchange rate between two currencies
86
- * @property getAllCurrencies - Get all available currencies (built-in + custom)
87
50
  */
88
51
  interface CurrencyState {
89
- selectedCurrency: string;
90
- baseCurrency: string;
91
- customCurrencies: Record<string, CurrencyMetadata>;
92
- customExchangeRates: Record<string, number>;
93
- setSelectedCurrency: (currency: string) => void;
94
- setBaseCurrency: (currency: string) => void;
95
- addCurrency: (metadata: CurrencyMetadata) => void;
96
- removeCurrency: (code: string) => void;
97
- setExchangeRate: (from: string, to: string, rate: number) => void;
98
- getExchangeRate: (from: string, to: string) => number | undefined;
99
- getAllCurrencies: () => string[];
52
+ selectedCurrency: SupportedCurrency;
53
+ baseCurrency: SupportedCurrency;
54
+ setSelectedCurrency: (currency: SupportedCurrency) => void;
55
+ setBaseCurrency: (currency: SupportedCurrency) => void;
100
56
  }
101
57
 
102
58
  /**
103
59
  * Zustand store for managing currency selection and conversion.
104
60
  * Persists user's selected currency preference in localStorage.
105
- * Supports dynamic currency registration and custom exchange rates.
106
61
  *
107
62
  * @example
108
63
  * ```tsx
109
- * const { selectedCurrency, setSelectedCurrency, addCurrency, setExchangeRate } = useCurrencyStore();
110
- *
111
- * // Add a new currency
112
- * addCurrency({
113
- * code: "BTC",
114
- * symbol: "₿",
115
- * name: "Bitcoin",
116
- * showSubscripts: true,
117
- * });
118
- *
119
- * // Set exchange rate: 1 BTC = 50000 USD
120
- * setExchangeRate("BTC", "USD", 50000);
121
- *
122
- * // Change display currency
123
- * setSelectedCurrency('BTC');
64
+ * const { selectedCurrency, setSelectedCurrency } = useCurrencyStore();
65
+ * // Change display currency to USD
66
+ * setSelectedCurrency('USD');
124
67
  * ```
125
68
  */
126
69
  export const useCurrencyStore = create<CurrencyState>()(
127
70
  persist(
128
- (set, get) => ({
71
+ set => ({
129
72
  selectedCurrency: "B3",
130
73
  baseCurrency: "B3",
131
- customCurrencies: {},
132
- customExchangeRates: {},
133
-
134
74
  setSelectedCurrency: currency => set({ selectedCurrency: currency }),
135
-
136
75
  setBaseCurrency: currency => set({ baseCurrency: currency }),
137
-
138
- addCurrency: metadata => {
139
- set(state => ({
140
- customCurrencies: {
141
- ...state.customCurrencies,
142
- [metadata.code]: metadata,
143
- },
144
- }));
145
- },
146
-
147
- removeCurrency: code => {
148
- set(state => {
149
- // Remove the currency
150
- const { [code]: _removed, ...remaining } = state.customCurrencies;
151
-
152
- // Remove all exchange rates involving this currency
153
- const filteredRates: Record<string, number> = {};
154
- for (const [key, rate] of Object.entries(state.customExchangeRates)) {
155
- // Key format is "FROM-TO", skip if either matches the removed code
156
- const [from, to] = key.split("-");
157
- if (from !== code && to !== code) {
158
- filteredRates[key] = rate;
159
- }
160
- }
161
-
162
- return {
163
- customCurrencies: remaining,
164
- customExchangeRates: filteredRates,
165
- };
166
- });
167
- },
168
-
169
- setExchangeRate: (from, to, rate) => {
170
- set(state => {
171
- const key = `${from}-${to}`;
172
- const inverseKey = `${to}-${from}`;
173
-
174
- // Only set inverse rate if rate is not 0 (to avoid Infinity)
175
- const newRates: Record<string, number> = {
176
- ...state.customExchangeRates,
177
- [key]: rate,
178
- };
179
-
180
- if (rate !== 0) {
181
- newRates[inverseKey] = 1 / rate;
182
- }
183
-
184
- return {
185
- customExchangeRates: newRates,
186
- };
187
- });
188
- },
189
-
190
- getExchangeRate: (from, to) => {
191
- const key = `${from}-${to}`;
192
- return get().customExchangeRates[key];
193
- },
194
-
195
- getAllCurrencies: () => {
196
- const builtIn = Object.keys(CURRENCY_SYMBOLS);
197
- const custom = Object.keys(get().customCurrencies);
198
- return [...builtIn, ...custom];
199
- },
200
76
  }),
201
77
  {
202
78
  name: "currency-storage",
203
- version: 3,
79
+ version: 2,
204
80
  },
205
81
  ),
206
82
  );
207
-
208
- /**
209
- * Get the symbol for any currency (built-in or custom).
210
- */
211
- export function getCurrencySymbol(currency: string): string {
212
- // Check built-in currencies first
213
- if (currency in CURRENCY_SYMBOLS) {
214
- return CURRENCY_SYMBOLS[currency as SupportedCurrency];
215
- }
216
-
217
- // Check custom currencies
218
- const customCurrencies = useCurrencyStore.getState().customCurrencies;
219
- const customCurrency = customCurrencies[currency];
220
- if (customCurrency) {
221
- return customCurrency.symbol;
222
- }
223
-
224
- // Fallback to currency code
225
- return currency;
226
- }
227
-
228
- /**
229
- * Get the name for any currency (built-in or custom).
230
- */
231
- export function getCurrencyName(currency: string): string {
232
- // Check built-in currencies first
233
- if (currency in CURRENCY_NAMES) {
234
- return CURRENCY_NAMES[currency as SupportedCurrency];
235
- }
236
-
237
- // Check custom currencies
238
- const customCurrencies = useCurrencyStore.getState().customCurrencies;
239
- const customCurrency = customCurrencies[currency];
240
- if (customCurrency) {
241
- return customCurrency.name;
242
- }
243
-
244
- // Fallback to currency code
245
- return currency;
246
- }
247
-
248
- /**
249
- * Get metadata for a custom currency.
250
- */
251
- export function getCurrencyMetadata(currency: string): CurrencyMetadata | undefined {
252
- const customCurrencies = useCurrencyStore.getState().customCurrencies;
253
- return customCurrencies[currency];
254
- }
255
-
256
- /**
257
- * Get the number of decimal places for a currency (for converting from smallest unit).
258
- * Used when parsing amounts from wei/smallest unit format.
259
- *
260
- * @param currency - Currency code
261
- * @returns Number of decimal places (e.g., 18 for ETH/wei, 2 for USD cents, 0 for JPY)
262
- */
263
- export function getCurrencyDecimalPlaces(currency: string): number {
264
- // Check custom currencies first
265
- const customCurrencies = useCurrencyStore.getState().customCurrencies;
266
- const customMetadata = customCurrencies[currency];
267
- if (customMetadata?.decimals !== undefined) {
268
- return customMetadata.decimals;
269
- }
270
-
271
- // Built-in currencies with 18 decimals (wei-like)
272
- if (currency === "WIN" || currency === "ETH" || currency === "SOL" || currency === "B3") {
273
- return 18;
274
- }
275
-
276
- // Fiat currencies with cent-like decimals
277
- if (currency === "USD" || currency === "EUR" || currency === "GBP" || currency === "CAD" || currency === "AUD") {
278
- return 2;
279
- }
280
-
281
- // Currencies without fractional units
282
- if (currency === "JPY" || currency === "KRW") {
283
- return 0;
284
- }
285
-
286
- // Default to 18 decimals (wei-like)
287
- return 18;
288
- }
@@ -1,7 +0,0 @@
1
- import type { Wallet } from "thirdweb/wallets";
2
- interface GlobalWalletState {
3
- globalAccountWallet?: Wallet;
4
- setGlobalAccountWallet: (account?: Wallet) => void;
5
- }
6
- export declare const useGlobalWalletState: import("zustand").UseBoundStore<import("zustand").StoreApi<GlobalWalletState>>;
7
- export {};
@@ -1,8 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.useGlobalWalletState = void 0;
4
- const zustand_1 = require("zustand");
5
- exports.useGlobalWalletState = (0, zustand_1.create)(set => ({
6
- globalAccountWallet: undefined,
7
- setGlobalAccountWallet: account => set({ globalAccountWallet: account }),
8
- }));
@@ -1,7 +0,0 @@
1
- import type { Wallet } from "thirdweb/wallets";
2
- interface GlobalWalletState {
3
- globalAccountWallet?: Wallet;
4
- setGlobalAccountWallet: (account?: Wallet) => void;
5
- }
6
- export declare const useGlobalWalletState: import("zustand").UseBoundStore<import("zustand").StoreApi<GlobalWalletState>>;
7
- export {};
@@ -1,5 +0,0 @@
1
- import { create } from "zustand";
2
- export const useGlobalWalletState = create(set => ({
3
- globalAccountWallet: undefined,
4
- setGlobalAccountWallet: account => set({ globalAccountWallet: account }),
5
- }));
@@ -1,7 +0,0 @@
1
- import type { Wallet } from "thirdweb/wallets";
2
- interface GlobalWalletState {
3
- globalAccountWallet?: Wallet;
4
- setGlobalAccountWallet: (account?: Wallet) => void;
5
- }
6
- export declare const useGlobalWalletState: import("zustand").UseBoundStore<import("zustand").StoreApi<GlobalWalletState>>;
7
- export {};