0xtrails 0.12.0 → 0.12.2

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 (205) hide show
  1. package/dist/analytics.d.ts +65 -50
  2. package/dist/analytics.d.ts.map +1 -1
  3. package/dist/{ccip-DtfgR432.js → ccip-62W6LwH2.js} +28 -28
  4. package/dist/chains.d.ts.map +1 -1
  5. package/dist/error.d.ts +2 -0
  6. package/dist/error.d.ts.map +1 -1
  7. package/dist/estimate.d.ts.map +1 -1
  8. package/dist/fees.d.ts.map +1 -1
  9. package/dist/{index-CHiCSmCD.js → index-C0QTNYIA.js} +43750 -41806
  10. package/dist/index.d.ts +5 -0
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +199 -171
  13. package/dist/localeUtils.d.ts.map +1 -1
  14. package/dist/meld/components/MeldCountriesList.d.ts +0 -2
  15. package/dist/meld/components/MeldCountriesList.d.ts.map +1 -1
  16. package/dist/meld/components/MeldFundMethods.d.ts.map +1 -1
  17. package/dist/meld/components/MeldTokensList.d.ts.map +1 -1
  18. package/dist/meld/utils/meld.d.ts +2 -52
  19. package/dist/meld/utils/meld.d.ts.map +1 -1
  20. package/dist/poolUtils.d.ts.map +1 -1
  21. package/dist/prepareSend.d.ts.map +1 -1
  22. package/dist/prices.d.ts +1 -2
  23. package/dist/prices.d.ts.map +1 -1
  24. package/dist/query/balance.fetchers.d.ts +2 -2
  25. package/dist/query/balance.fetchers.d.ts.map +1 -1
  26. package/dist/query/fiat.fetchers.d.ts +11 -0
  27. package/dist/query/fiat.fetchers.d.ts.map +1 -0
  28. package/dist/query/fiat.hooks.d.ts +18 -0
  29. package/dist/query/fiat.hooks.d.ts.map +1 -0
  30. package/dist/query/fiat.queries.d.ts +24 -0
  31. package/dist/query/fiat.queries.d.ts.map +1 -0
  32. package/dist/query/meld.fetchers.d.ts +19 -0
  33. package/dist/query/meld.fetchers.d.ts.map +1 -0
  34. package/dist/query/meld.hooks.d.ts +4 -0
  35. package/dist/query/meld.hooks.d.ts.map +1 -0
  36. package/dist/query/meld.queries.d.ts +61 -0
  37. package/dist/query/meld.queries.d.ts.map +1 -0
  38. package/dist/recover.d.ts.map +1 -1
  39. package/dist/tokens.d.ts.map +1 -1
  40. package/dist/transactionIntent/deposits/depositOrchestrator.d.ts.map +1 -1
  41. package/dist/transactionIntent/deposits/gaslessDeposit.d.ts.map +1 -1
  42. package/dist/transactionIntent/deposits/standardDeposit.d.ts +7 -1
  43. package/dist/transactionIntent/deposits/standardDeposit.d.ts.map +1 -1
  44. package/dist/transactionIntent/handlers/intentHandler.d.ts +2 -0
  45. package/dist/transactionIntent/handlers/intentHandler.d.ts.map +1 -1
  46. package/dist/transactionIntent/quote/normalizeQuote.d.ts +2 -2
  47. package/dist/transactionIntent/quote/normalizeQuote.d.ts.map +1 -1
  48. package/dist/transactionIntent/quote/quoteHelpers.d.ts +1 -1
  49. package/dist/transactionIntent/quote/quoteHelpers.d.ts.map +1 -1
  50. package/dist/transactionIntent/types.d.ts +2 -0
  51. package/dist/transactionIntent/types.d.ts.map +1 -1
  52. package/dist/transactionIntent/utils/balanceChecker.d.ts +3 -1
  53. package/dist/transactionIntent/utils/balanceChecker.d.ts.map +1 -1
  54. package/dist/transactions.d.ts +2 -9
  55. package/dist/transactions.d.ts.map +1 -1
  56. package/dist/umd/trails.min.js +206 -152
  57. package/dist/utils/fiat.d.ts +8 -0
  58. package/dist/utils/fiat.d.ts.map +1 -0
  59. package/dist/utils/format.d.ts.map +1 -1
  60. package/dist/utils/passthrough.d.ts +5 -2
  61. package/dist/utils/passthrough.d.ts.map +1 -1
  62. package/dist/utils/validation.d.ts +33 -0
  63. package/dist/utils/validation.d.ts.map +1 -1
  64. package/dist/utils.d.ts.map +1 -1
  65. package/dist/walletUtils.d.ts +1 -1
  66. package/dist/walletUtils.d.ts.map +1 -1
  67. package/dist/widget/components/ClassicSwap.d.ts.map +1 -1
  68. package/dist/widget/components/DepositTracker.d.ts.map +1 -1
  69. package/dist/widget/components/Earn.d.ts +2 -0
  70. package/dist/widget/components/Earn.d.ts.map +1 -1
  71. package/dist/widget/components/FeeOption.d.ts.map +1 -1
  72. package/dist/widget/components/Fund.d.ts.map +1 -1
  73. package/dist/widget/components/FundMethods.d.ts.map +1 -1
  74. package/dist/widget/components/HookModalContent.d.ts.map +1 -1
  75. package/dist/widget/components/MeldForm.d.ts.map +1 -1
  76. package/dist/widget/components/MeldHistory.d.ts.map +1 -1
  77. package/dist/widget/components/MeldStepsFlow.d.ts.map +1 -1
  78. package/dist/widget/components/OFTProgressBar.d.ts +2 -0
  79. package/dist/widget/components/OFTProgressBar.d.ts.map +1 -1
  80. package/dist/widget/components/OnRampProviderSelector.d.ts.map +1 -1
  81. package/dist/widget/components/OnrampHistoryRow.d.ts.map +1 -1
  82. package/dist/widget/components/Pay.d.ts.map +1 -1
  83. package/dist/widget/components/PercentageMaxButtons.d.ts.map +1 -1
  84. package/dist/widget/components/PoolDeposit.d.ts +2 -0
  85. package/dist/widget/components/PoolDeposit.d.ts.map +1 -1
  86. package/dist/widget/components/QuoteDetails.d.ts.map +1 -1
  87. package/dist/widget/components/Receipt.d.ts.map +1 -1
  88. package/dist/widget/components/SlippageToleranceSettings.d.ts.map +1 -1
  89. package/dist/widget/components/Swap.d.ts +2 -0
  90. package/dist/widget/components/Swap.d.ts.map +1 -1
  91. package/dist/widget/components/TransferPendingVertical.d.ts.map +1 -1
  92. package/dist/widget/components/Withdraw.d.ts.map +1 -1
  93. package/dist/widget/hooks/useAmountUsd.d.ts.map +1 -1
  94. package/dist/widget/hooks/useCustomTokenSearch.d.ts.map +1 -1
  95. package/dist/widget/hooks/useDisplayCurrencyPreference.d.ts.map +1 -1
  96. package/dist/widget/hooks/useFiatOnRampCurrencies.d.ts +3 -21
  97. package/dist/widget/hooks/useFiatOnRampCurrencies.d.ts.map +1 -1
  98. package/dist/widget/hooks/useMeldTransactionHistory.d.ts.map +1 -1
  99. package/dist/widget/hooks/useOnRampCountryDefaults.d.ts +0 -18
  100. package/dist/widget/hooks/useOnRampCountryDefaults.d.ts.map +1 -1
  101. package/dist/widget/hooks/useOnRampPaymentMethods.d.ts +2 -18
  102. package/dist/widget/hooks/useOnRampPaymentMethods.d.ts.map +1 -1
  103. package/dist/widget/hooks/useOnRampQuote.d.ts.map +1 -1
  104. package/dist/widget/hooks/useQuote.d.ts +5 -1
  105. package/dist/widget/hooks/useQuote.d.ts.map +1 -1
  106. package/dist/widget/hooks/useSendForm.d.ts +3 -1
  107. package/dist/widget/hooks/useSendForm.d.ts.map +1 -1
  108. package/dist/widget/hooks/useTokenList.d.ts.map +1 -1
  109. package/dist/widget/hooks/useTokenWithFreshBalance.d.ts +3 -2
  110. package/dist/widget/hooks/useTokenWithFreshBalance.d.ts.map +1 -1
  111. package/dist/widget/index.js +1 -1
  112. package/dist/widget/types/commonProps.d.ts +2 -0
  113. package/dist/widget/types/commonProps.d.ts.map +1 -1
  114. package/dist/widget/utils/transactionFailure.d.ts +20 -0
  115. package/dist/widget/utils/transactionFailure.d.ts.map +1 -0
  116. package/dist/widget/widget.d.ts +44 -3
  117. package/dist/widget/widget.d.ts.map +1 -1
  118. package/dist/widget/workers/intentExecutionWorker.d.ts.map +1 -1
  119. package/package.json +22 -22
  120. package/src/analytics.ts +115 -79
  121. package/src/chains.ts +0 -1
  122. package/src/error.ts +11 -0
  123. package/src/estimate.ts +12 -7
  124. package/src/fees.ts +0 -1
  125. package/src/index.ts +11 -0
  126. package/src/localeUtils.ts +3 -1
  127. package/src/meld/components/MeldCountriesList.tsx +30 -15
  128. package/src/meld/components/MeldFundMethods.tsx +8 -4
  129. package/src/meld/components/MeldTokensList.tsx +90 -2
  130. package/src/meld/utils/meld.ts +3 -400
  131. package/src/poolUtils.ts +5 -19
  132. package/src/prepareSend.ts +32 -5
  133. package/src/prices.ts +7 -33
  134. package/src/query/balance.fetchers.ts +128 -168
  135. package/src/query/fiat.fetchers.ts +33 -0
  136. package/src/query/fiat.hooks.ts +71 -0
  137. package/src/query/fiat.queries.ts +67 -0
  138. package/src/query/meld.fetchers.ts +97 -0
  139. package/src/query/meld.hooks.ts +18 -0
  140. package/src/query/meld.queries.ts +184 -0
  141. package/src/recover.ts +6 -1
  142. package/src/tokens.ts +31 -6
  143. package/src/transactionIntent/deposits/depositOrchestrator.ts +2 -0
  144. package/src/transactionIntent/deposits/gaslessDeposit.ts +9 -2
  145. package/src/transactionIntent/deposits/standardDeposit.ts +35 -14
  146. package/src/transactionIntent/handlers/intentHandler.ts +134 -138
  147. package/src/transactionIntent/quote/normalizeQuote.ts +31 -22
  148. package/src/transactionIntent/quote/quoteHelpers.ts +24 -7
  149. package/src/transactionIntent/types.ts +2 -0
  150. package/src/transactionIntent/utils/balanceChecker.ts +10 -4
  151. package/src/transactions.ts +22 -13
  152. package/src/umd.tsx +1 -1
  153. package/src/utils/fiat.ts +32 -0
  154. package/src/utils/format.ts +1 -3
  155. package/src/utils/passthrough.ts +19 -3
  156. package/src/utils/validation.ts +88 -0
  157. package/src/utils.ts +2 -1
  158. package/src/walletUtils.ts +2 -2
  159. package/src/widget/components/AccountIntentTransactionHistory.tsx +2 -2
  160. package/src/widget/components/ClassicSwap.tsx +10 -4
  161. package/src/widget/components/DepositTracker.tsx +2 -5
  162. package/src/widget/components/Earn.tsx +6 -0
  163. package/src/widget/components/FeeOption.tsx +15 -8
  164. package/src/widget/components/Fund.tsx +16 -11
  165. package/src/widget/components/FundMethods.tsx +255 -192
  166. package/src/widget/components/HookModalContent.tsx +4 -0
  167. package/src/widget/components/MeldForm.tsx +44 -42
  168. package/src/widget/components/MeldHistory.tsx +4 -3
  169. package/src/widget/components/MeldStepsFlow.tsx +33 -71
  170. package/src/widget/components/OFTProgressBar.tsx +32 -12
  171. package/src/widget/components/OnRampProviderSelector.tsx +2 -1
  172. package/src/widget/components/OnrampHistoryRow.tsx +2 -1
  173. package/src/widget/components/Pay.tsx +8 -2
  174. package/src/widget/components/PercentageMaxButtons.tsx +5 -3
  175. package/src/widget/components/PoolDeposit.tsx +6 -0
  176. package/src/widget/components/PoolWithdraw.tsx +1 -1
  177. package/src/widget/components/QuoteDetails.tsx +5 -4
  178. package/src/widget/components/Receipt.tsx +4 -3
  179. package/src/widget/components/SlippageToleranceSettings.tsx +3 -2
  180. package/src/widget/components/Swap.tsx +2 -0
  181. package/src/widget/components/TransferPendingVertical.tsx +21 -28
  182. package/src/widget/components/UserPreferences.tsx +1 -1
  183. package/src/widget/components/Withdraw.tsx +20 -14
  184. package/src/widget/hooks/useAmountUsd.ts +3 -15
  185. package/src/widget/hooks/useCustomTokenSearch.tsx +2 -6
  186. package/src/widget/hooks/useDisplayCurrencyPreference.tsx +1 -2
  187. package/src/widget/hooks/useFiatOnRampCurrencies.ts +11 -76
  188. package/src/widget/hooks/useMeldTransactionHistory.ts +24 -89
  189. package/src/widget/hooks/useOnRampCountryDefaults.ts +3 -49
  190. package/src/widget/hooks/useOnRampPaymentMethods.ts +21 -100
  191. package/src/widget/hooks/useOnRampQuote.ts +2 -5
  192. package/src/widget/hooks/useQuote.ts +10 -12
  193. package/src/widget/hooks/useSendForm.ts +6 -0
  194. package/src/widget/hooks/useTokenList.ts +3 -6
  195. package/src/widget/hooks/useTokenWithFreshBalance.ts +141 -11
  196. package/src/widget/types/commonProps.ts +2 -0
  197. package/src/widget/utils/transactionFailure.ts +52 -0
  198. package/src/widget/widget.tsx +137 -59
  199. package/src/widget/workers/intentExecutionWorker.ts +3 -1
  200. package/dist/widget/hooks/useExchangeRate.d.ts +0 -31
  201. package/dist/widget/hooks/useExchangeRate.d.ts.map +0 -1
  202. package/dist/widget/hooks/useFiatCurrencyList.d.ts +0 -3
  203. package/dist/widget/hooks/useFiatCurrencyList.d.ts.map +0 -1
  204. package/src/widget/hooks/useExchangeRate.ts +0 -257
  205. package/src/widget/hooks/useFiatCurrencyList.ts +0 -66
package/src/index.ts CHANGED
@@ -137,6 +137,17 @@ export {
137
137
  formatUsdAmountLocaleDisplay,
138
138
  } from "./utils/format.js"
139
139
  export { balanceQueries } from "./query/balance.queries.js"
140
+ export { fiatQueries } from "./query/fiat.queries.js"
141
+ export {
142
+ useFiatCurrencyList,
143
+ useExchangeRate,
144
+ } from "./query/fiat.hooks.js"
145
+ export { meldQueries } from "./query/meld.queries.js"
146
+ export {
147
+ useMeldPaymentMethods,
148
+ useMeldServiceProviders,
149
+ } from "./query/meld.hooks.js"
150
+ export { getCurrencyInfo } from "./utils/fiat.js"
140
151
  export {
141
152
  getTokenPrice,
142
153
  getTokenPrices,
@@ -3,6 +3,8 @@
3
3
  * Handles European format (1.234,56) vs US format (1,234.56)
4
4
  */
5
5
 
6
+ import { isValidNumber } from "./utils/validation.js"
7
+
6
8
  /**
7
9
  * Detects if a string uses European number format
8
10
  * European: uses comma as decimal separator and period/space for thousands
@@ -238,5 +240,5 @@ export function isValidLocaleNumber(value: string): boolean {
238
240
  }
239
241
 
240
242
  const parsed = parseLocaleNumber(value)
241
- return !Number.isNaN(parsed) && Number.isFinite(parsed)
243
+ return isValidNumber(parsed)
242
244
  }
@@ -1,9 +1,9 @@
1
1
  import { Search } from "lucide-react"
2
2
  import type React from "react"
3
3
  import { useMemo, useState } from "react"
4
- import { useCountryCode } from "../../query/geo.hooks.js"
5
- import type { TrailsOnramp } from "../../onrampClient.js"
6
- import { useMeldCountries, type Country } from "../utils/meld.js"
4
+ import { useCountryCode, useCountryList } from "../../query/geo.hooks.js"
5
+ import { getMeldSupportedCountries } from "../../widget/utils/countryUtils.js"
6
+ import type { Country } from "../utils/meld.js"
7
7
  import { SimpleHeader } from "./SimpleHeader.js"
8
8
 
9
9
  // Convert country code (e.g., "US") to flag emoji
@@ -22,17 +22,25 @@ export interface MeldCountriesListProps {
22
22
  onBack?: () => void
23
23
  onSelectCountry?: (country: Country) => void
24
24
  selectedCountry?: Country | null
25
- trailsClient: TrailsOnramp | null
26
25
  }
27
26
 
28
27
  export const MeldCountriesList: React.FC<MeldCountriesListProps> = ({
29
28
  onBack,
30
29
  onSelectCountry,
31
30
  selectedCountry,
32
- trailsClient,
33
31
  }) => {
34
- const { countries, isLoading, error, refetch } =
35
- useMeldCountries(trailsClient)
32
+ const {
33
+ data: apiCountries = [],
34
+ isLoading,
35
+ error,
36
+ refetch,
37
+ } = useCountryList()
38
+
39
+ const countries = useMemo(
40
+ () => getMeldSupportedCountries(apiCountries),
41
+ [apiCountries],
42
+ )
43
+
36
44
  const [searchTerm, setSearchTerm] = useState("")
37
45
 
38
46
  // Use proper geolocation hook
@@ -48,7 +56,7 @@ export const MeldCountriesList: React.FC<MeldCountriesListProps> = ({
48
56
  filtered = countries.filter(
49
57
  (country) =>
50
58
  country.name.toLowerCase().includes(lowerSearchTerm) ||
51
- country.code.toLowerCase().includes(lowerSearchTerm),
59
+ country.countryCode.toLowerCase().includes(lowerSearchTerm),
52
60
  )
53
61
  }
54
62
 
@@ -56,10 +64,16 @@ export const MeldCountriesList: React.FC<MeldCountriesListProps> = ({
56
64
  return filtered.sort((a, b) => {
57
65
  // If we have a detected user country, prioritize it
58
66
  if (userCountryCode) {
59
- if (a.code === userCountryCode && b.code !== userCountryCode) {
67
+ if (
68
+ a.countryCode === userCountryCode &&
69
+ b.countryCode !== userCountryCode
70
+ ) {
60
71
  return -1 // a (user's country) comes first
61
72
  }
62
- if (b.code === userCountryCode && a.code !== userCountryCode) {
73
+ if (
74
+ b.countryCode === userCountryCode &&
75
+ a.countryCode !== userCountryCode
76
+ ) {
63
77
  return 1 // b (user's country) comes first
64
78
  }
65
79
  }
@@ -123,7 +137,7 @@ export const MeldCountriesList: React.FC<MeldCountriesListProps> = ({
123
137
  )}
124
138
  <button
125
139
  type="button"
126
- onClick={refetch}
140
+ onClick={() => refetch()}
127
141
  className="mt-3 px-4 py-2 text-sm bg-red-100 hover:bg-red-200 dark:bg-red-800 dark:hover:bg-red-700 text-red-700 dark:text-red-200 rounded-md transition-colors"
128
142
  >
129
143
  Retry
@@ -143,12 +157,13 @@ export const MeldCountriesList: React.FC<MeldCountriesListProps> = ({
143
157
  </div>
144
158
  ) : (
145
159
  filteredCountries.map((country) => {
146
- const isSelected = selectedCountry?.code === country.code
147
- const isUserCountry = userCountryCode === country.code
160
+ const isSelected =
161
+ selectedCountry?.countryCode === country.countryCode
162
+ const isUserCountry = userCountryCode === country.countryCode
148
163
 
149
164
  return (
150
165
  <button
151
- key={country.code}
166
+ key={country.countryCode}
152
167
  type="button"
153
168
  onClick={() => handleCountrySelect(country)}
154
169
  className={`w-full flex items-center justify-between cursor-pointer font-semibold py-4 px-6 rounded-lg transition-all duration-200 ${
@@ -159,7 +174,7 @@ export const MeldCountriesList: React.FC<MeldCountriesListProps> = ({
159
174
  >
160
175
  <div className="flex items-center space-x-3 flex-1">
161
176
  <div className="w-10 h-10 rounded-lg flex items-center justify-center text-2xl">
162
- {getCountryFlag(country.code)}
177
+ {getCountryFlag(country.countryCode)}
163
178
  </div>
164
179
  <div className="flex-1 text-left">
165
180
  <div className="flex items-center gap-2">
@@ -3,7 +3,8 @@ import type React from "react"
3
3
  import { useMemo, useState } from "react"
4
4
  import { logger } from "../../logger.js"
5
5
  import type { TrailsOnramp } from "../../onrampClient.js"
6
- import { useMeldPaymentMethods } from "../utils/meld.js"
6
+ import { useQuery } from "@tanstack/react-query"
7
+ import { meldQueries } from "../../query/meld.queries.js"
7
8
  import { SimpleHeader } from "./SimpleHeader.js"
8
9
 
9
10
  export type MeldPaymentMethod =
@@ -33,9 +34,12 @@ export const MeldFundMethods: React.FC<MeldFundMethodsProps> = ({
33
34
  fiatCurrency = "USD",
34
35
  onNavigateToFund,
35
36
  }) => {
36
- const { paymentMethods, isLoading, error } = useMeldPaymentMethods(
37
- trailsClient || null,
38
- fiatCurrency,
37
+ const {
38
+ data: paymentMethods = [],
39
+ isLoading,
40
+ error,
41
+ } = useQuery(
42
+ meldQueries.paymentMethodList(trailsClient || null, fiatCurrency),
39
43
  )
40
44
  const [searchTerm, setSearchTerm] = useState("")
41
45
  const [failedImages, setFailedImages] = useState<Set<string>>(new Set())
@@ -1,9 +1,15 @@
1
1
  import { Search } from "lucide-react"
2
2
  import type React from "react"
3
3
  import { useMemo, useState } from "react"
4
+ import { useQuery } from "@tanstack/react-query"
5
+ import { zeroAddress } from "viem"
4
6
  import type { TrailsOnramp } from "../../onrampClient.js"
5
7
  import { TokenImage } from "../../widget/components/TokenImage.js"
6
- import { useMeldTokens, type MeldToken } from "../utils/meld.js"
8
+ import { getChainInfo } from "../../chains.js"
9
+ import { commonTokens } from "../../tokens.js"
10
+ import { useSupportedChains } from "../../query/chains.hooks.js"
11
+ import { meldQueries } from "../../query/meld.queries.js"
12
+ import { MELD_CHAIN_SUFFIX_TO_ID, type MeldToken } from "../utils/meld.js"
7
13
  import { SimpleHeader } from "./SimpleHeader.js"
8
14
 
9
15
  // Get chain badge color
@@ -40,7 +46,89 @@ export const MeldTokensList: React.FC<MeldTokensListProps> = ({
40
46
  trailsClient,
41
47
  countryCode,
42
48
  }) => {
43
- const { tokens, isLoading, error } = useMeldTokens(trailsClient, countryCode)
49
+ const {
50
+ data: rawCurrencies = [],
51
+ isLoading: isLoadingCurrencies,
52
+ error: currenciesError,
53
+ } = useQuery(
54
+ meldQueries.cryptoCurrencyList(trailsClient, countryCode ?? null),
55
+ )
56
+ const { data: supportedChains = [] } = useSupportedChains()
57
+ const supportedChainIds = useMemo(
58
+ () => supportedChains.map((c) => c.id),
59
+ [supportedChains],
60
+ )
61
+
62
+ // Transform raw API data into MeldToken[] with filtering
63
+ const tokens = useMemo(() => {
64
+ const allowedSymbols = new Set([
65
+ "ETH",
66
+ "MATIC",
67
+ "AVAX",
68
+ "BNB",
69
+ "USDC",
70
+ "USDT",
71
+ "DAI",
72
+ ])
73
+ const stablecoins = ["USDC", "USDT", "DAI"]
74
+
75
+ return rawCurrencies
76
+ .map((crypto) => {
77
+ const code = crypto.currencyCode || ""
78
+ const name = crypto.name || code
79
+ const parts = code.split("_")
80
+ const symbol = parts[0] || code
81
+ const chain = parts[1] || ""
82
+ const chainId = MELD_CHAIN_SUFFIX_TO_ID[chain]
83
+ let contractAddress: string | undefined
84
+
85
+ if (chainId && symbol) {
86
+ const isNativeToken =
87
+ (symbol === "ETH" && [1, 10, 8453, 42161].includes(chainId)) ||
88
+ (symbol === "MATIC" && chainId === 137) ||
89
+ (symbol === "AVAX" && chainId === 43114) ||
90
+ (symbol === "BNB" && chainId === 56)
91
+
92
+ if (isNativeToken) {
93
+ contractAddress = zeroAddress
94
+ } else {
95
+ const commonToken = commonTokens.find(
96
+ (token) => token.symbol === symbol && token.chainId === chainId,
97
+ )
98
+ contractAddress = commonToken?.contractAddress
99
+ }
100
+ }
101
+
102
+ return {
103
+ code,
104
+ name,
105
+ symbol,
106
+ chain,
107
+ chainName: chainId ? (getChainInfo(chainId)?.name ?? chain) : chain,
108
+ chainId,
109
+ contractAddress,
110
+ } satisfies MeldToken
111
+ })
112
+ .filter((token) => allowedSymbols.has(token.symbol))
113
+ .filter(
114
+ (token) =>
115
+ token.chainId != null && supportedChainIds.includes(token.chainId),
116
+ )
117
+ .filter(
118
+ (token, index, self) =>
119
+ index === self.findIndex((t) => t.code === token.code),
120
+ )
121
+ .sort((a, b) => {
122
+ const aIsStable = stablecoins.includes(a.symbol)
123
+ const bIsStable = stablecoins.includes(b.symbol)
124
+ if (aIsStable && !bIsStable) return -1
125
+ if (!aIsStable && bIsStable) return 1
126
+ return a.symbol.localeCompare(b.symbol)
127
+ })
128
+ }, [rawCurrencies, supportedChainIds])
129
+
130
+ const isLoading = isLoadingCurrencies
131
+ const error = currenciesError
44
132
  const [searchTerm, setSearchTerm] = useState("")
45
133
 
46
134
  // Filter tokens based on search term and put selected token at the top
@@ -2,17 +2,7 @@
2
2
  * Utility functions for Meld integration
3
3
  */
4
4
 
5
- import { useState, useEffect, useRef, useMemo } from "react"
6
- import { useQuery } from "@tanstack/react-query"
7
- import { DAY_MS } from "../../utils/time.js"
8
- import {
9
- getOnrampClient,
10
- useOnrampClient,
11
- type TrailsOnramp,
12
- } from "../../onrampClient.js"
13
- import { getChainInfo, getSupportedSequenceChains } from "../../chains.js"
14
- import { commonTokens } from "../../tokens.js"
15
- import { zeroAddress } from "viem"
5
+ import { getOnrampClient, type TrailsOnramp } from "../../onrampClient.js"
16
6
  import {
17
7
  mainnet,
18
8
  base,
@@ -24,15 +14,8 @@ import {
24
14
  } from "viem/chains"
25
15
  import { getConfig } from "../../config.js"
26
16
  import { PROD_TRAILS_API_URL } from "../../constants.js"
27
- import { useCountryList } from "../../query/geo.hooks.js"
28
- import { getMeldSupportedCountries } from "../../widget/utils/countryUtils.js"
29
- import type {
30
- MeldServiceProvider,
31
- GetMeldServiceProvidersRequest,
32
- } from "../../onramp-client/trails-onramp.gen.js"
33
- import { logger } from "../../index.js"
34
17
 
35
- const MELD_CHAIN_SUFFIX_TO_ID: Record<string, number> = {
18
+ export const MELD_CHAIN_SUFFIX_TO_ID: Record<string, number> = {
36
19
  ETH: mainnet.id,
37
20
  BASE: base.id,
38
21
  OP: optimism.id,
@@ -57,127 +40,10 @@ export function getMeldOnrampClient(
57
40
  }
58
41
 
59
42
  export interface Country {
60
- code: string
43
+ countryCode: string
61
44
  name: string
62
45
  }
63
46
 
64
- /**
65
- * Hook to fetch list of countries from API
66
- * Returns a list of countries that support Meld
67
- */
68
- export function useMeldCountries(_trailsClient: TrailsOnramp | null): {
69
- countries: Country[]
70
- isLoading: boolean
71
- error: Error | null
72
- refetch: () => void
73
- } {
74
- // Use the country list from the API
75
- const {
76
- data: apiCountries = [],
77
- isLoading,
78
- error,
79
- refetch,
80
- } = useCountryList()
81
-
82
- // Convert API countries to Meld format and filter for Meld-supported countries
83
- const countries = useMemo(() => {
84
- const meldSupportedCountries = getMeldSupportedCountries(apiCountries)
85
- return meldSupportedCountries.map((country) => ({
86
- code: country.countryCode,
87
- name: country.name,
88
- }))
89
- }, [apiCountries])
90
-
91
- return {
92
- countries,
93
- isLoading,
94
- error: error as Error | null,
95
- refetch,
96
- }
97
- }
98
-
99
- /**
100
- * Hook to fetch payment methods for Meld (for use in MeldFundMethods component)
101
- * Uses a default fiat currency (USD) or can accept a country code to get the default currency
102
- *
103
- * @note Results are cached for 24 hours as payment methods are stable and don't change frequently.
104
- */
105
- export function useMeldPaymentMethods(
106
- trailsClient: TrailsOnramp | null,
107
- fiatCurrency: string = "USD",
108
- ): {
109
- paymentMethods: Array<{
110
- paymentMethod: string
111
- name: string
112
- paymentType: string
113
- logos?: { dark?: string; light?: string }
114
- }>
115
- isLoading: boolean
116
- error: Error | null
117
- } {
118
- const { data, isLoading, error } = useQuery({
119
- queryKey: ["meld-payment-methods", fiatCurrency],
120
- queryFn: async () => {
121
- if (!trailsClient) {
122
- throw new Error("No trails client available")
123
- }
124
-
125
- logger.console.log(
126
- "[useMeldPaymentMethods] Fetching payment methods for:",
127
- fiatCurrency,
128
- )
129
- const response = await trailsClient.getMeldPaymentMethods({
130
- fiatCurrency,
131
- })
132
-
133
- // Parse payment methods from response
134
- const methods = Array.isArray(response.paymentMethods)
135
- ? response.paymentMethods
136
- : []
137
-
138
- const parsedMethods = methods.map(
139
- (method: {
140
- paymentMethod?: string
141
- payment_method?: string
142
- name?: string
143
- paymentType?: string
144
- payment_type?: string
145
- logos?: { dark?: string; light?: string }
146
- }) => ({
147
- paymentMethod: method.paymentMethod || method.payment_method || "",
148
- name: method.name || "",
149
- paymentType: method.paymentType || method.payment_type || "",
150
- logos: method.logos
151
- ? {
152
- dark: method.logos.dark,
153
- light: method.logos.light,
154
- }
155
- : undefined,
156
- }),
157
- )
158
-
159
- logger.console.log(
160
- "[useMeldPaymentMethods] Fetched",
161
- parsedMethods.length,
162
- "methods",
163
- )
164
- return parsedMethods
165
- },
166
- enabled: !!trailsClient,
167
- staleTime: DAY_MS, // 24 hours - payment methods don't change frequently
168
- gcTime: DAY_MS, // 24 hours cache time
169
- retry: 2,
170
- refetchOnWindowFocus: false,
171
- refetchOnReconnect: false, // Don't refetch on reconnect since data is stable for 24h
172
- })
173
-
174
- return {
175
- paymentMethods: data || [],
176
- isLoading,
177
- error: error as Error | null,
178
- }
179
- }
180
-
181
47
  export interface MeldToken {
182
48
  code: string // e.g., "USDC_ETH"
183
49
  name: string // e.g., "USD Coin"
@@ -209,266 +75,3 @@ export interface MeldQuote {
209
75
  lowKyc: boolean | null
210
76
  partnerFee: number
211
77
  }
212
-
213
- /**
214
- * Hook to fetch and filter crypto tokens from Meld
215
- * Filters to show only: Native tokens (ETH, MATIC, AVAX, BNB) + stablecoins (USDC, USDT, DAI)
216
- */
217
- export function useMeldTokens(
218
- trailsClient: TrailsOnramp | null,
219
- countryCode?: string,
220
- ): {
221
- tokens: MeldToken[]
222
- isLoading: boolean
223
- error: Error | null
224
- } {
225
- const [tokens, setTokens] = useState<MeldToken[]>([])
226
- const [isLoading, setIsLoading] = useState(false)
227
- const [error, setError] = useState<Error | null>(null)
228
- const debounceTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null)
229
- const abortControllerRef = useRef<AbortController | null>(null)
230
-
231
- useEffect(() => {
232
- if (!trailsClient) {
233
- setTokens([])
234
- return
235
- }
236
-
237
- // Clear any existing debounce timer
238
- if (debounceTimerRef.current) {
239
- clearTimeout(debounceTimerRef.current)
240
- }
241
-
242
- // Abort any in-flight requests
243
- if (abortControllerRef.current) {
244
- abortControllerRef.current.abort()
245
- }
246
-
247
- // Create new abort controller
248
- abortControllerRef.current = new AbortController()
249
-
250
- // Debounce the fetch
251
- debounceTimerRef.current = setTimeout(() => {
252
- setIsLoading(true)
253
- setError(null)
254
-
255
- const fetchTokens = async () => {
256
- try {
257
- // If no country code provided, don't fetch
258
- if (!countryCode) {
259
- logger.console.log("[useMeldTokens] No country code provided")
260
- setTokens([])
261
- setIsLoading(false)
262
- return
263
- }
264
-
265
- logger.console.log(
266
- "[useMeldTokens] Fetching tokens for country:",
267
- countryCode,
268
- )
269
- const response = await trailsClient.getMeldCryptoCurrencies({
270
- countryCode: countryCode,
271
- })
272
- logger.console.log("[useMeldTokens] API response:", response)
273
-
274
- // Check if request was aborted
275
- if (abortControllerRef.current?.signal.aborted) {
276
- return
277
- }
278
-
279
- // Parse crypto currencies from response
280
- const cryptos = Array.isArray(response.cryptoCurrencies)
281
- ? response.cryptoCurrencies
282
- : []
283
-
284
- // Allowed tokens: native tokens + major stablecoins
285
- const allowedSymbols = new Set([
286
- "ETH",
287
- "MATIC",
288
- "AVAX",
289
- "BNB",
290
- "USDC",
291
- "USDT",
292
- "DAI",
293
- ])
294
-
295
- // Get supported Sequence chain IDs
296
- const supportedChainIds = (await getSupportedSequenceChains()).map(
297
- (chain) => chain.id,
298
- )
299
-
300
- const parsedTokens: MeldToken[] = cryptos
301
- .map((crypto) => {
302
- const code = crypto.currencyCode || ""
303
- const name = crypto.name || code
304
-
305
- // Parse token code (e.g., "USDC_ETH" -> symbol: "USDC", chain: "ETH")
306
- const parts = code.split("_")
307
- const symbol = parts[0] || code
308
- const chain = parts[1] || ""
309
-
310
- const chainId = MELD_CHAIN_SUFFIX_TO_ID[chain]
311
- let contractAddress: string | undefined
312
-
313
- if (chainId && symbol) {
314
- // For native tokens, use zero address
315
- const isNativeToken =
316
- (symbol === "ETH" &&
317
- [1, 10, 8453, 42161].includes(chainId)) ||
318
- (symbol === "MATIC" && chainId === 137) ||
319
- (symbol === "AVAX" && chainId === 43114) ||
320
- (symbol === "BNB" && chainId === 56)
321
-
322
- if (isNativeToken) {
323
- contractAddress = zeroAddress
324
- } else {
325
- // Look up contract address in commonTokens
326
- const commonToken = commonTokens.find(
327
- (token) =>
328
- token.symbol === symbol && token.chainId === chainId,
329
- )
330
- contractAddress = commonToken?.contractAddress
331
- }
332
- }
333
-
334
- return {
335
- code,
336
- name,
337
- symbol,
338
- chain,
339
- chainName: chainId
340
- ? (getChainInfo(chainId)?.name ?? chain)
341
- : chain,
342
- chainId,
343
- contractAddress,
344
- }
345
- })
346
- .filter((token) => allowedSymbols.has(token.symbol)) // Only allowed tokens
347
- .filter(
348
- (token) =>
349
- token.chainId && supportedChainIds.includes(token.chainId),
350
- ) // Only Sequence-supported chains
351
- .filter(
352
- (token, index, self) =>
353
- // Remove duplicates by code
354
- index === self.findIndex((t) => t.code === token.code),
355
- )
356
- // Sort: Stablecoins first (USDC, USDT, DAI), then native tokens
357
- .sort((a, b) => {
358
- const stablecoins = ["USDC", "USDT", "DAI"]
359
- const aIsStable = stablecoins.includes(a.symbol)
360
- const bIsStable = stablecoins.includes(b.symbol)
361
-
362
- if (aIsStable && !bIsStable) return -1
363
- if (!aIsStable && bIsStable) return 1
364
-
365
- // Within same category, sort alphabetically
366
- return a.symbol.localeCompare(b.symbol)
367
- })
368
-
369
- // Check if aborted before setting state
370
- if (abortControllerRef.current?.signal.aborted) {
371
- return
372
- }
373
-
374
- logger.console.log(
375
- "[useMeldTokens] Setting tokens:",
376
- parsedTokens.length,
377
- "tokens",
378
- )
379
- logger.console.log("[useMeldTokens] Tokens:", parsedTokens)
380
- setTokens(parsedTokens)
381
- } catch (err) {
382
- // Ignore abort errors
383
- if (err instanceof Error && err.name === "AbortError") {
384
- return
385
- }
386
-
387
- // Check if aborted before setting error
388
- if (abortControllerRef.current?.signal.aborted) {
389
- return
390
- }
391
-
392
- setError(err instanceof Error ? err : new Error(String(err)))
393
- setTokens([])
394
- } finally {
395
- // Only update loading state if not aborted
396
- if (!abortControllerRef.current?.signal.aborted) {
397
- setIsLoading(false)
398
- }
399
- }
400
- }
401
-
402
- fetchTokens()
403
- }, 300)
404
-
405
- // Cleanup function
406
- return () => {
407
- if (debounceTimerRef.current) {
408
- clearTimeout(debounceTimerRef.current)
409
- }
410
- if (abortControllerRef.current) {
411
- abortControllerRef.current.abort()
412
- }
413
- }
414
- }, [trailsClient, countryCode])
415
-
416
- return { tokens, isLoading, error }
417
- }
418
-
419
- /**
420
- * Hook to fetch list of Meld service providers
421
- * Supports filtering by country, currencies, payment methods, etc.
422
- *
423
- * @note Results are cached for 24 hours as service providers are stable and don't change frequently.
424
- */
425
- export function useMeldProviders(
426
- trailsClient?: TrailsOnramp | null,
427
- options?: Partial<GetMeldServiceProvidersRequest>,
428
- ): {
429
- providers: MeldServiceProvider[]
430
- isLoading: boolean
431
- error: Error | null
432
- refetch: () => void
433
- } {
434
- const defaultOnrampClient = useOnrampClient()
435
- const onrampClient = trailsClient ?? defaultOnrampClient
436
-
437
- const { data, isLoading, error, refetch } = useQuery({
438
- queryKey: ["meld-service-providers", options],
439
- queryFn: async () => {
440
- if (!onrampClient) {
441
- throw new Error("No onramp client available")
442
- }
443
-
444
- logger.console.log(
445
- "[useMeldProviders] Fetching service providers with options:",
446
- options,
447
- )
448
-
449
- const response = await onrampClient.getMeldServiceProviders(options || {})
450
-
451
- const providersData = response.serviceProviders || []
452
-
453
- logger.console.log(
454
- `[useMeldProviders] Found ${providersData.length} providers:`,
455
- providersData,
456
- )
457
-
458
- return providersData
459
- },
460
- enabled: !!onrampClient,
461
- staleTime: DAY_MS, // 24 hours - service providers don't change frequently
462
- gcTime: DAY_MS, // 24 hours cache time
463
- retry: 2,
464
- refetchOnWindowFocus: false,
465
- refetchOnReconnect: false, // Don't refetch on reconnect since data is stable for 24h
466
- })
467
-
468
- return {
469
- providers: data || [],
470
- isLoading,
471
- error: error as Error | null,
472
- refetch,
473
- }
474
- }