0xtrails 0.13.0 → 0.13.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 (307) hide show
  1. package/dist/{ccip-Cg9-lJ6K.js → ccip-CT_An6eM.js} +39 -39
  2. package/dist/chains.d.ts +4 -3
  3. package/dist/chains.d.ts.map +1 -1
  4. package/dist/constants.d.ts +1 -0
  5. package/dist/constants.d.ts.map +1 -1
  6. package/dist/customTokens.d.ts.map +1 -1
  7. package/dist/error.d.ts +1 -0
  8. package/dist/error.d.ts.map +1 -1
  9. package/dist/gasless.d.ts +1 -2
  10. package/dist/gasless.d.ts.map +1 -1
  11. package/dist/{index-DEojZg7b.js → index-RfqL5Foz.js} +56672 -43550
  12. package/dist/index.d.ts +5 -2
  13. package/dist/index.d.ts.map +1 -1
  14. package/dist/index.js +385 -333
  15. package/dist/intents.d.ts +8 -2
  16. package/dist/intents.d.ts.map +1 -1
  17. package/dist/keyMachineClient.d.ts +9 -0
  18. package/dist/keyMachineClient.d.ts.map +1 -0
  19. package/dist/keymachine/index.d.ts +14 -0
  20. package/dist/keymachine/index.d.ts.map +1 -0
  21. package/dist/keymachine/key-machine.gen.d.ts +461 -0
  22. package/dist/keymachine/key-machine.gen.d.ts.map +1 -0
  23. package/dist/onramp/MeshConnectFlow.d.ts +18 -0
  24. package/dist/onramp/MeshConnectFlow.d.ts.map +1 -0
  25. package/dist/onramp/MeshConnectIframe.d.ts +13 -0
  26. package/dist/onramp/MeshConnectIframe.d.ts.map +1 -0
  27. package/dist/onramp/SendFromExchangeButton.d.ts +16 -0
  28. package/dist/onramp/SendFromExchangeButton.d.ts.map +1 -0
  29. package/dist/onramp/TrailsOnRampProvider.d.ts +31 -0
  30. package/dist/onramp/TrailsOnRampProvider.d.ts.map +1 -0
  31. package/dist/onramp/index.d.ts +13 -0
  32. package/dist/onramp/index.d.ts.map +1 -0
  33. package/dist/onramp/meshconnect.d.ts +30 -0
  34. package/dist/onramp/meshconnect.d.ts.map +1 -0
  35. package/dist/onramp/trailsOnramp.d.ts +24 -0
  36. package/dist/onramp/trailsOnramp.d.ts.map +1 -0
  37. package/dist/onramp-client/index.d.ts +3 -3
  38. package/dist/onramp-client/index.d.ts.map +1 -1
  39. package/dist/paymasterSend.d.ts.map +1 -1
  40. package/dist/prepareSend.d.ts.map +1 -1
  41. package/dist/query/balance.fetchers.d.ts +31 -2
  42. package/dist/query/balance.fetchers.d.ts.map +1 -1
  43. package/dist/query/balance.hooks.d.ts +21 -2
  44. package/dist/query/balance.hooks.d.ts.map +1 -1
  45. package/dist/query/balance.queries.d.ts +18 -1
  46. package/dist/query/balance.queries.d.ts.map +1 -1
  47. package/dist/query/chains.queries.d.ts.map +1 -1
  48. package/dist/query/meld.fetchers.d.ts +1 -1
  49. package/dist/query/meld.fetchers.d.ts.map +1 -1
  50. package/dist/query/meld.hooks.d.ts +3 -3
  51. package/dist/query/meld.hooks.d.ts.map +1 -1
  52. package/dist/query/meld.queries.d.ts +1 -1
  53. package/dist/query/meld.queries.d.ts.map +1 -1
  54. package/dist/query/price.fetchers.d.ts +15 -0
  55. package/dist/query/price.fetchers.d.ts.map +1 -0
  56. package/dist/query/price.hooks.d.ts +352 -0
  57. package/dist/query/price.hooks.d.ts.map +1 -0
  58. package/dist/query/price.queries.d.ts +34 -0
  59. package/dist/query/price.queries.d.ts.map +1 -0
  60. package/dist/query/tokenList.queries.d.ts +54 -0
  61. package/dist/query/tokenList.queries.d.ts.map +1 -0
  62. package/dist/recover.d.ts +6 -4
  63. package/dist/recover.d.ts.map +1 -1
  64. package/dist/tokens.d.ts +13 -0
  65. package/dist/tokens.d.ts.map +1 -1
  66. package/dist/transactionIntent/deposits/depositOrchestrator.d.ts +2 -2
  67. package/dist/transactionIntent/deposits/depositOrchestrator.d.ts.map +1 -1
  68. package/dist/transactionIntent/deposits/gaslessDeposit.d.ts +2 -2
  69. package/dist/transactionIntent/deposits/gaslessDeposit.d.ts.map +1 -1
  70. package/dist/transactionIntent/deposits/standardDeposit.d.ts +1 -1
  71. package/dist/transactionIntent/deposits/standardDeposit.d.ts.map +1 -1
  72. package/dist/transactionIntent/handlers/intentHandler.d.ts.map +1 -1
  73. package/dist/transactionIntent/helpers/transactionStateHelpers.d.ts.map +1 -1
  74. package/dist/transactionIntent/quote/normalizeQuote.d.ts.map +1 -1
  75. package/dist/transactionIntent/types.d.ts +1 -1
  76. package/dist/transactionIntent/types.d.ts.map +1 -1
  77. package/dist/transactions.d.ts +4 -0
  78. package/dist/transactions.d.ts.map +1 -1
  79. package/dist/umd/trails.min.js +291 -202
  80. package/dist/utils/format.d.ts +7 -0
  81. package/dist/utils/format.d.ts.map +1 -1
  82. package/dist/walletUtils.d.ts +2 -1
  83. package/dist/walletUtils.d.ts.map +1 -1
  84. package/dist/wallets.d.ts +13 -54
  85. package/dist/wallets.d.ts.map +1 -1
  86. package/dist/widget/components/AccountIntentTransactionHistory.d.ts.map +1 -1
  87. package/dist/widget/components/ClassicSwap.d.ts.map +1 -1
  88. package/dist/widget/components/ConnectWallet.d.ts.map +1 -1
  89. package/dist/widget/components/ConnectedWallets.d.ts.map +1 -1
  90. package/dist/widget/components/DirectTransfer.d.ts +1 -1
  91. package/dist/widget/components/DirectTransfer.d.ts.map +1 -1
  92. package/dist/widget/components/EarnPools.d.ts.map +1 -1
  93. package/dist/widget/components/ExecutionStatusBadge.d.ts.map +1 -1
  94. package/dist/widget/components/Fund.d.ts.map +1 -1
  95. package/dist/widget/components/FundMethods.d.ts.map +1 -1
  96. package/dist/widget/components/HighPriceImpactBlock.d.ts +7 -0
  97. package/dist/widget/components/HighPriceImpactBlock.d.ts.map +1 -0
  98. package/dist/widget/components/MeldHistory.d.ts.map +1 -1
  99. package/dist/widget/components/MeshExchangeSelection.d.ts +11 -0
  100. package/dist/widget/components/MeshExchangeSelection.d.ts.map +1 -0
  101. package/dist/widget/components/OnrampHistoryRow.d.ts +1 -1
  102. package/dist/widget/components/OnrampHistoryRow.d.ts.map +1 -1
  103. package/dist/widget/components/OnrampProviderConfirmation.d.ts.map +1 -1
  104. package/dist/widget/components/Pay.d.ts.map +1 -1
  105. package/dist/widget/components/PoolDeposit.d.ts.map +1 -1
  106. package/dist/widget/components/PoolWithdraw.d.ts.map +1 -1
  107. package/dist/widget/components/QRCodeWalletSelect.d.ts +1 -1
  108. package/dist/widget/components/QRCodeWalletSelect.d.ts.map +1 -1
  109. package/dist/widget/components/QuoteDetails.d.ts.map +1 -1
  110. package/dist/widget/components/Receipt.d.ts.map +1 -1
  111. package/dist/widget/components/Recipients.d.ts.map +1 -1
  112. package/dist/widget/components/RefundWarning.d.ts.map +1 -1
  113. package/dist/widget/components/TokenSelector.d.ts.map +1 -1
  114. package/dist/widget/components/TransactionDetails.d.ts.map +1 -1
  115. package/dist/widget/components/TransactionHistoryItem.d.ts +2 -0
  116. package/dist/widget/components/TransactionHistoryItem.d.ts.map +1 -1
  117. package/dist/widget/components/TransferPendingVertical.d.ts +1 -0
  118. package/dist/widget/components/TransferPendingVertical.d.ts.map +1 -1
  119. package/dist/widget/components/WaasFeeOptions.d.ts.map +1 -1
  120. package/dist/widget/components/WalletConnect.d.ts.map +1 -1
  121. package/dist/widget/components/WalletImage.d.ts.map +1 -1
  122. package/dist/widget/components/WalletList.d.ts.map +1 -1
  123. package/dist/widget/components/Withdraw.d.ts.map +1 -1
  124. package/dist/widget/css/compiled.css +1 -1
  125. package/dist/widget/hooks/useAddressWalletIcon.d.ts.map +1 -1
  126. package/dist/widget/hooks/useCombinedHistory.d.ts +6 -5
  127. package/dist/widget/hooks/useCombinedHistory.d.ts.map +1 -1
  128. package/dist/widget/hooks/useCustomTokenSearch.d.ts +6 -1
  129. package/dist/widget/hooks/useCustomTokenSearch.d.ts.map +1 -1
  130. package/dist/widget/hooks/useDefaultDestinationToken.d.ts.map +1 -1
  131. package/dist/widget/hooks/useDefaultOriginToken.d.ts.map +1 -1
  132. package/dist/widget/hooks/useFiatOnRampCurrencies.d.ts +1 -1
  133. package/dist/widget/hooks/useFiatOnRampCurrencies.d.ts.map +1 -1
  134. package/dist/widget/hooks/useGetIntent.d.ts +3 -2
  135. package/dist/widget/hooks/useGetIntent.d.ts.map +1 -1
  136. package/dist/widget/hooks/useIntentReceiptBalances.d.ts +1 -1
  137. package/dist/widget/hooks/useIntentReceiptBalances.d.ts.map +1 -1
  138. package/dist/widget/hooks/useIntentTransactionHistory.d.ts +3 -2
  139. package/dist/widget/hooks/useIntentTransactionHistory.d.ts.map +1 -1
  140. package/dist/widget/hooks/useMeldTransactionHistory.d.ts +1 -1
  141. package/dist/widget/hooks/useMeldTransactionHistory.d.ts.map +1 -1
  142. package/dist/widget/hooks/useMeldTransactionStatus.d.ts +1 -1
  143. package/dist/widget/hooks/useMeldTransactionStatus.d.ts.map +1 -1
  144. package/dist/widget/hooks/useOnRampQuote.d.ts +1 -1
  145. package/dist/widget/hooks/useOnRampQuote.d.ts.map +1 -1
  146. package/dist/widget/hooks/useOnRampTransactionStatus.d.ts +1 -1
  147. package/dist/widget/hooks/useOnRampTransactionStatus.d.ts.map +1 -1
  148. package/dist/widget/hooks/useQuote.d.ts +2 -2
  149. package/dist/widget/hooks/useQuote.d.ts.map +1 -1
  150. package/dist/widget/hooks/useSelectedFundMethod.d.ts +7 -0
  151. package/dist/widget/hooks/useSelectedFundMethod.d.ts.map +1 -1
  152. package/dist/widget/hooks/useSendForm.d.ts +0 -1
  153. package/dist/widget/hooks/useSendForm.d.ts.map +1 -1
  154. package/dist/widget/hooks/useTokenList.d.ts +7 -1
  155. package/dist/widget/hooks/useTokenList.d.ts.map +1 -1
  156. package/dist/widget/hooks/useViewManager.d.ts +1 -1
  157. package/dist/widget/hooks/useViewManager.d.ts.map +1 -1
  158. package/dist/widget/index.js +1 -1
  159. package/dist/widget/providers/TrailsProvider.d.ts +2 -0
  160. package/dist/widget/providers/TrailsProvider.d.ts.map +1 -1
  161. package/dist/widget/utils/createWagmiConfig.d.ts +2 -2
  162. package/dist/widget/utils/createWagmiConfig.d.ts.map +1 -1
  163. package/dist/widget/utils/fundMethodSwitchState.d.ts +1 -0
  164. package/dist/widget/utils/fundMethodSwitchState.d.ts.map +1 -1
  165. package/dist/widget/utils/historyFilters.d.ts +13 -0
  166. package/dist/widget/utils/historyFilters.d.ts.map +1 -0
  167. package/dist/widget/utils/meldProviderUtils.d.ts +1 -1
  168. package/dist/widget/utils/meldProviderUtils.d.ts.map +1 -1
  169. package/dist/widget/utils/meshSupportedTokens.d.ts +4 -0
  170. package/dist/widget/utils/meshSupportedTokens.d.ts.map +1 -0
  171. package/dist/widget/utils/onrampConfig.d.ts +11 -0
  172. package/dist/widget/utils/onrampConfig.d.ts.map +1 -0
  173. package/dist/widget/utils/statusLabel.d.ts +2 -0
  174. package/dist/widget/utils/statusLabel.d.ts.map +1 -0
  175. package/dist/widget/utils/trailsOnrampConfig.d.ts +18 -0
  176. package/dist/widget/utils/trailsOnrampConfig.d.ts.map +1 -0
  177. package/dist/widget/widget.d.ts +24 -8
  178. package/dist/widget/widget.d.ts.map +1 -1
  179. package/package.json +9 -7
  180. package/src/chains.ts +26 -9
  181. package/src/constants.ts +2 -0
  182. package/src/customTokens.ts +22 -7
  183. package/src/error.ts +7 -0
  184. package/src/gasless.ts +5 -2
  185. package/src/index.ts +8 -5
  186. package/src/intents.ts +56 -60
  187. package/src/keyMachineClient.ts +29 -0
  188. package/src/keymachine/index.ts +175 -0
  189. package/src/keymachine/key-machine.gen.ts +993 -0
  190. package/src/onramp/MeshConnectFlow.tsx +86 -0
  191. package/src/onramp/MeshConnectIframe.tsx +661 -0
  192. package/src/onramp/SendFromExchangeButton.tsx +81 -0
  193. package/src/onramp/TrailsOnRampProvider.tsx +59 -0
  194. package/src/onramp/index.ts +31 -0
  195. package/src/onramp/meshconnect.ts +277 -0
  196. package/src/onramp/trailsOnramp.tsx +130 -0
  197. package/src/onramp-client/index.ts +4 -6
  198. package/src/paymasterSend.ts +0 -5
  199. package/src/prepareSend.ts +45 -44
  200. package/src/query/balance.fetchers.ts +172 -17
  201. package/src/query/balance.hooks.ts +69 -6
  202. package/src/query/balance.queries.ts +63 -0
  203. package/src/query/chains.queries.ts +1 -6
  204. package/src/query/meld.fetchers.ts +1 -1
  205. package/src/query/meld.hooks.ts +1 -1
  206. package/src/query/meld.queries.ts +1 -1
  207. package/src/query/price.fetchers.ts +53 -0
  208. package/src/query/price.hooks.ts +46 -0
  209. package/src/query/price.queries.ts +364 -0
  210. package/src/query/tokenList.queries.ts +118 -0
  211. package/src/recover.ts +89 -26
  212. package/src/tokens.ts +108 -26
  213. package/src/transactionIntent/deposits/depositOrchestrator.ts +11 -11
  214. package/src/transactionIntent/deposits/gaslessDeposit.ts +38 -39
  215. package/src/transactionIntent/deposits/standardDeposit.ts +5 -30
  216. package/src/transactionIntent/handlers/intentHandler.ts +29 -12
  217. package/src/transactionIntent/helpers/transactionStateHelpers.ts +5 -2
  218. package/src/transactionIntent/quote/normalizeQuote.ts +11 -5
  219. package/src/transactionIntent/types.ts +1 -1
  220. package/src/transactions.ts +5 -1
  221. package/src/utils/format.ts +85 -1
  222. package/src/walletUtils.ts +2 -1
  223. package/src/wallets.ts +184 -380
  224. package/src/widget/compiled.css +1 -1
  225. package/src/widget/components/AccountIntentTransactionHistory.tsx +134 -109
  226. package/src/widget/components/ClassicSwap.tsx +26 -24
  227. package/src/widget/components/ConnectWallet.tsx +4 -2
  228. package/src/widget/components/ConnectedWallets.tsx +2 -5
  229. package/src/widget/components/DirectTransfer.tsx +5 -2
  230. package/src/widget/components/EarnPools.tsx +1 -2
  231. package/src/widget/components/ExecutionStatusBadge.tsx +10 -4
  232. package/src/widget/components/Fund.tsx +169 -110
  233. package/src/widget/components/FundMethods.tsx +5 -9
  234. package/src/widget/components/HighPriceImpactBlock.tsx +44 -0
  235. package/src/widget/components/MeldHistory.tsx +4 -28
  236. package/src/widget/components/MeshExchangeSelection.tsx +218 -0
  237. package/src/widget/components/OnrampHistoryRow.tsx +3 -27
  238. package/src/widget/components/OnrampProviderConfirmation.tsx +0 -25
  239. package/src/widget/components/Pay.tsx +20 -36
  240. package/src/widget/components/PoolDeposit.tsx +14 -24
  241. package/src/widget/components/PoolWithdraw.tsx +1 -63
  242. package/src/widget/components/QRCodeWalletSelect.tsx +5 -2
  243. package/src/widget/components/QuoteDetails.tsx +113 -106
  244. package/src/widget/components/Receipt.tsx +0 -11
  245. package/src/widget/components/Recipients.tsx +2 -1
  246. package/src/widget/components/RefundWarning.tsx +5 -10
  247. package/src/widget/components/ThemeProvider.tsx +4 -4
  248. package/src/widget/components/TokenSelector.tsx +85 -16
  249. package/src/widget/components/TransactionDetails.tsx +46 -0
  250. package/src/widget/components/TransactionHistoryItem.tsx +14 -23
  251. package/src/widget/components/TransferPendingVertical.tsx +17 -11
  252. package/src/widget/components/WaasFeeOptions.tsx +4 -42
  253. package/src/widget/components/WalletConnect.tsx +2 -5
  254. package/src/widget/components/WalletImage.tsx +6 -18
  255. package/src/widget/components/WalletList.tsx +1 -1
  256. package/src/widget/components/Withdraw.tsx +22 -23
  257. package/src/widget/hooks/useAddressWalletIcon.ts +2 -1
  258. package/src/widget/hooks/useAmountUsd.ts +1 -1
  259. package/src/widget/hooks/useCombinedHistory.ts +37 -93
  260. package/src/widget/hooks/useCustomTokenSearch.tsx +63 -33
  261. package/src/widget/hooks/useDefaultDestinationToken.tsx +2 -5
  262. package/src/widget/hooks/useDefaultOriginToken.tsx +2 -5
  263. package/src/widget/hooks/useFiatOnRampCurrencies.ts +1 -1
  264. package/src/widget/hooks/useGetIntent.ts +5 -4
  265. package/src/widget/hooks/useIntentReceiptBalances.ts +3 -3
  266. package/src/widget/hooks/useIntentTransactionHistory.ts +24 -47
  267. package/src/widget/hooks/useMeldTransactionHistory.ts +4 -2
  268. package/src/widget/hooks/useMeldTransactionStatus.ts +13 -11
  269. package/src/widget/hooks/useOnRampQuote.ts +3 -3
  270. package/src/widget/hooks/useOnRampTransactionStatus.ts +8 -6
  271. package/src/widget/hooks/useQuote.ts +56 -48
  272. package/src/widget/hooks/useSelectedFundMethod.tsx +14 -1
  273. package/src/widget/hooks/useSendForm.ts +52 -31
  274. package/src/widget/hooks/useTokenList.ts +209 -140
  275. package/src/widget/hooks/useTrailsSendTransaction.ts +1 -1
  276. package/src/widget/hooks/useViewManager.tsx +1 -0
  277. package/src/widget/providers/TrailsProvider.tsx +5 -0
  278. package/src/widget/styles.ts +1 -1
  279. package/src/widget/utils/createWagmiConfig.ts +7 -2
  280. package/src/widget/utils/fundMethodSwitchState.ts +2 -0
  281. package/src/widget/utils/historyFilters.ts +157 -0
  282. package/src/widget/utils/meldProviderUtils.ts +8 -2
  283. package/src/widget/utils/meshSupportedTokens.ts +28 -0
  284. package/src/widget/utils/onrampConfig.ts +15 -0
  285. package/src/widget/utils/statusLabel.ts +3 -0
  286. package/src/widget/utils/trailsOnrampConfig.ts +39 -0
  287. package/src/widget/widget.tsx +235 -185
  288. package/dist/onramp-client/trails-onramp.gen.d.ts +0 -570
  289. package/dist/onramp-client/trails-onramp.gen.d.ts.map +0 -1
  290. package/dist/prices.d.ts +0 -34
  291. package/dist/prices.d.ts.map +0 -1
  292. package/dist/useGasEstimation.d.ts +0 -34
  293. package/dist/useGasEstimation.d.ts.map +0 -1
  294. package/dist/widget/hooks/useCustomTokenFetch.d.ts +0 -19
  295. package/dist/widget/hooks/useCustomTokenFetch.d.ts.map +0 -1
  296. package/dist/widget/hooks/useTokenWithFreshBalance.d.ts +0 -18
  297. package/dist/widget/hooks/useTokenWithFreshBalance.d.ts.map +0 -1
  298. package/src/onramp-client/trails-onramp.gen.ts +0 -1320
  299. package/src/prices.ts +0 -528
  300. package/src/useGasEstimation.ts +0 -147
  301. package/src/widget/assets/Binance_Icon_Logo.svg +0 -14
  302. package/src/widget/assets/Bitfinex_Icon_Logo.svg +0 -5
  303. package/src/widget/assets/Coinbase_Icon_Logo.svg +0 -1
  304. package/src/widget/assets/WalletConnect-logo-blue-bg.svg +0 -11
  305. package/src/widget/assets/sequence-logo.svg +0 -15
  306. package/src/widget/hooks/useCustomTokenFetch.tsx +0 -74
  307. package/src/widget/hooks/useTokenWithFreshBalance.ts +0 -246
package/src/prices.ts DELETED
@@ -1,528 +0,0 @@
1
- import type { Token, TokenPrice } from "@0xtrails/api"
2
- import { type QueryClient, useQuery } from "@tanstack/react-query"
3
- import { zeroAddress } from "viem"
4
- import { logger } from "./logger.js"
5
- import { parseLocaleNumber } from "./localeUtils.js"
6
- import { queryClient as defaultQueryClient } from "./query/client.js"
7
- import { useTrailsClient, type TrailsClient } from "./trailsClient.js"
8
- import { MINUTE_MS, SECOND_MS, retryDelay } from "./utils/time.js"
9
- import { useUserActivityContext } from "./widget/providers/UserActivityProvider.js"
10
- import { isValidNumber, isNonNegativeNumber } from "./utils/validation.js"
11
-
12
- import { normalizeAddress } from "./utils/address.js"
13
-
14
- export const priceKeys = {
15
- all: ["tokenPrices"] as const,
16
- }
17
- // Local storage cache configuration
18
- const LOCAL_STORAGE_CACHE_KEY = "trails_token_prices_cache"
19
- const LOCAL_STORAGE_CACHE_DURATION = MINUTE_MS
20
-
21
- // Global caching configuration
22
- const CACHE_CONFIG = {
23
- // Time configurations - matches API cache of 90 seconds
24
- staleTime: 90 * SECOND_MS,
25
- gcTime: 90 * SECOND_MS,
26
- refetchInterval: 90 * SECOND_MS,
27
-
28
- // Retry configurations
29
- retry: 2,
30
- retryDelay,
31
-
32
- // Refetch behaviors
33
- refetchOnWindowFocus: false,
34
- refetchOnReconnect: true,
35
- refetchIntervalInBackground: false,
36
-
37
- // Retry logic for specific error types
38
- shouldRetry: (failureCount: number, error: any) => {
39
- if (error && "status" in error && error.status === 404) return false
40
- if (failureCount < 2) return true
41
- return false
42
- },
43
- } as const
44
-
45
- // Extract common query options for reuse
46
- const COMMON_QUERY_OPTIONS = {
47
- staleTime: CACHE_CONFIG.staleTime,
48
- gcTime: CACHE_CONFIG.gcTime,
49
- retry: CACHE_CONFIG.shouldRetry,
50
- retryDelay: CACHE_CONFIG.retryDelay,
51
- refetchOnWindowFocus: CACHE_CONFIG.refetchOnWindowFocus,
52
- refetchOnReconnect: CACHE_CONFIG.refetchOnReconnect,
53
- refetchInterval: CACHE_CONFIG.refetchInterval,
54
- refetchIntervalInBackground: CACHE_CONFIG.refetchIntervalInBackground,
55
- } as const
56
-
57
- // Local storage cache helpers
58
- interface TokenPriceEntry {
59
- price: TokenPrice
60
- timestamp: number
61
- }
62
-
63
- interface TokenPriceCache {
64
- // Indexed by chainId -> tokenAddress (lowercase) -> price data
65
- prices: Record<number, Record<string, TokenPriceEntry>>
66
- lastCleanup: number
67
- }
68
-
69
- const getLocalStorageCache = (): TokenPriceCache => {
70
- try {
71
- const cached = localStorage.getItem(LOCAL_STORAGE_CACHE_KEY)
72
- if (!cached) {
73
- return {
74
- prices: {},
75
- lastCleanup: Date.now(),
76
- }
77
- }
78
-
79
- const parsed = JSON.parse(cached) as TokenPriceCache
80
- // Ensure structure is correct
81
- if (!parsed.prices) {
82
- return {
83
- prices: {},
84
- lastCleanup: Date.now(),
85
- }
86
- }
87
- return parsed
88
- } catch (error) {
89
- logger.console.warn(
90
- "[trails-sdk] Failed to parse localStorage cache:",
91
- error,
92
- )
93
- return {
94
- prices: {},
95
- lastCleanup: Date.now(),
96
- }
97
- }
98
- }
99
-
100
- const setLocalStorageCache = (cache: TokenPriceCache): void => {
101
- try {
102
- localStorage.setItem(LOCAL_STORAGE_CACHE_KEY, JSON.stringify(cache))
103
- } catch (error) {
104
- logger.console.warn(
105
- "[trails-sdk] Failed to save localStorage cache:",
106
- error,
107
- )
108
- }
109
- }
110
-
111
- const getCachedTokenPrice = (
112
- chainId: number,
113
- tokenAddress: string,
114
- ): TokenPrice | null => {
115
- const cache = getLocalStorageCache()
116
- const chainPrices = cache.prices[chainId]
117
- if (!chainPrices) return null
118
-
119
- const entry = chainPrices[normalizeAddress(tokenAddress)]
120
- if (!entry) return null
121
-
122
- const now = Date.now()
123
- const age = now - entry.timestamp
124
-
125
- // Check if cache is still valid (within 60 seconds)
126
- if (age > LOCAL_STORAGE_CACHE_DURATION) {
127
- logger.console.debug(
128
- `[trails-sdk] Cache expired for ${chainId}:${tokenAddress}, age: ${age}ms`,
129
- )
130
- return null
131
- }
132
-
133
- logger.console.debug(
134
- `[trails-sdk] Using cached price for ${chainId}:${tokenAddress}, age: ${age}ms`,
135
- )
136
- return entry.price
137
- }
138
-
139
- const getCachedPricesForTokens = (tokens: Token[]): TokenPrice[] | null => {
140
- if (tokens.length === 0) return []
141
-
142
- const cache = getLocalStorageCache()
143
- const now = Date.now()
144
- const results: TokenPrice[] = []
145
-
146
- // Check if all tokens have valid cached prices
147
- for (const token of tokens) {
148
- const chainPrices = cache.prices[token.chainId]
149
- if (!chainPrices) return null // Missing chain data
150
-
151
- const tokenAddress = (token.tokenAddress || zeroAddress).toLowerCase()
152
- const entry = chainPrices[tokenAddress]
153
-
154
- if (!entry) return null // Missing token price
155
-
156
- const age = now - entry.timestamp
157
- if (age > LOCAL_STORAGE_CACHE_DURATION) {
158
- return null // Expired price found
159
- }
160
-
161
- results.push(entry.price)
162
- }
163
-
164
- logger.console.debug(
165
- `[trails-sdk] Using ${results.length} cached prices for batch request`,
166
- )
167
- return results
168
- }
169
-
170
- const setCachedTokenPrices = (prices: TokenPrice[]): void => {
171
- const cache = getLocalStorageCache()
172
- const now = Date.now()
173
-
174
- // Store each price individually
175
- for (const price of prices) {
176
- const chainId = price.token.chainId
177
- const tokenAddress = (price.token.tokenAddress || zeroAddress).toLowerCase()
178
-
179
- // Ensure chain object exists
180
- if (!cache.prices[chainId]) {
181
- cache.prices[chainId] = {}
182
- }
183
-
184
- // Store the price entry
185
- cache.prices[chainId][tokenAddress] = {
186
- price,
187
- timestamp: now,
188
- }
189
- }
190
-
191
- // Clean up old entries periodically (every 5 minutes)
192
- if (now - cache.lastCleanup > 5 * MINUTE_MS) {
193
- cleanupExpiredEntries(cache)
194
- cache.lastCleanup = now
195
- }
196
-
197
- setLocalStorageCache(cache)
198
- logger.console.debug(`[trails-sdk] Cached ${prices.length} token prices`)
199
- }
200
-
201
- const cleanupExpiredEntries = (cache: TokenPriceCache): void => {
202
- const now = Date.now()
203
- let removed = 0
204
-
205
- for (const chainId in cache.prices) {
206
- const chainPrices = cache.prices[chainId]
207
- if (!chainPrices) continue
208
-
209
- for (const tokenAddress in chainPrices) {
210
- const entry = chainPrices[tokenAddress]
211
- if (entry && now - entry.timestamp > LOCAL_STORAGE_CACHE_DURATION) {
212
- delete chainPrices[tokenAddress]
213
- removed++
214
- }
215
- }
216
- // Remove empty chain objects
217
- if (Object.keys(chainPrices).length === 0) {
218
- delete cache.prices[chainId]
219
- }
220
- }
221
-
222
- if (removed > 0) {
223
- logger.console.debug(
224
- `[trails-sdk] Cleaned up ${removed} expired cache entries`,
225
- )
226
- }
227
- }
228
-
229
- // Periodic cleanup is now handled in setCachedTokenPrices when needed
230
-
231
- // Cache key generation methods
232
- const createTokenCacheKey = (token: Token): string => {
233
- const tokenAddress = (token.tokenAddress || "").toLowerCase()
234
- const chainId = Number(token.chainId || 0)
235
- const tokenSymbol = (token.tokenSymbol || "").toUpperCase()
236
- return `${tokenAddress}-${chainId}-${tokenSymbol}`
237
- }
238
-
239
- const createBatchCacheKey = (
240
- tokens: Token[],
241
- ): (string | number | string[])[] => {
242
- return [
243
- "tokenPrices",
244
- "batch",
245
- tokens.length,
246
- tokens.map(createTokenCacheKey).sort(),
247
- ]
248
- }
249
-
250
- const createSingleCacheKey = (token?: Token | null): (string | null)[] => {
251
- return ["tokenPrices", "single", token ? createTokenCacheKey(token) : null]
252
- }
253
-
254
- // Separate fetch function for token prices
255
- export const fetchGetTokenPrices = async (
256
- trailsClient: TrailsClient,
257
- tokens: Token[],
258
- ): Promise<TokenPrice[]> => {
259
- if (!trailsClient) {
260
- throw new Error("Trails client is required")
261
- }
262
-
263
- if (tokens.length === 0) {
264
- return [] as TokenPrice[]
265
- }
266
-
267
- // First, check if all tokens have cached prices
268
- const cachedPrices = getCachedPricesForTokens(tokens)
269
- if (cachedPrices) {
270
- return cachedPrices
271
- }
272
-
273
- // If not all cached, check which ones we need to fetch
274
- const tokensToFetch: Token[] = []
275
- const cachedResults: TokenPrice[] = []
276
-
277
- for (const token of tokens) {
278
- const cached = getCachedTokenPrice(
279
- token.chainId,
280
- token.tokenAddress || zeroAddress,
281
- )
282
- if (cached) {
283
- cachedResults.push(cached)
284
- } else {
285
- tokensToFetch.push(token)
286
- }
287
- }
288
-
289
- // If all tokens were cached individually
290
- if (tokensToFetch.length === 0) {
291
- logger.console.debug(
292
- `[trails-sdk] All ${tokens.length} token prices found in cache`,
293
- )
294
- return cachedResults
295
- }
296
-
297
- // Fetch only the missing prices
298
- logger.console.debug(
299
- `[trails-sdk] Fetching ${tokensToFetch.length} prices, ${cachedResults.length} from cache`,
300
- )
301
-
302
- try {
303
- const res = await trailsClient.getTokenPrices({ tokens: tokensToFetch })
304
- const fetchedPrices = res?.tokenPrices || []
305
-
306
- // Store all fetched prices in cache
307
- if (fetchedPrices.length > 0) {
308
- setCachedTokenPrices(fetchedPrices)
309
- }
310
-
311
- // Combine cached and fetched results, maintaining original order
312
- const allPrices: TokenPrice[] = []
313
- for (const token of tokens) {
314
- const cached = cachedResults.find(
315
- (p) =>
316
- p.token.chainId === token.chainId &&
317
- p.token.tokenAddress?.toLowerCase() ===
318
- (token.tokenAddress || zeroAddress).toLowerCase(),
319
- )
320
- if (cached) {
321
- allPrices.push(cached)
322
- } else {
323
- const fetched = fetchedPrices.find(
324
- (p) =>
325
- p.token.chainId === token.chainId &&
326
- p.token.tokenAddress?.toLowerCase() ===
327
- (token.tokenAddress || zeroAddress).toLowerCase(),
328
- )
329
- if (fetched) {
330
- allPrices.push(fetched)
331
- }
332
- }
333
- }
334
-
335
- return allPrices
336
- } catch (error) {
337
- logger.console.error("[trails-sdk] Failed to fetch token prices:", error)
338
- throw error
339
- }
340
- }
341
-
342
- export function normalizeToken(
343
- token: Token & {
344
- tokenID?: string
345
- symbol?: string
346
- contractAddress?: string
347
- tokenId?: string
348
- },
349
- ): Token {
350
- return {
351
- chainId: token.chainId,
352
- tokenAddress: token.tokenAddress || token.contractAddress || zeroAddress,
353
- tokenSymbol:
354
- token.tokenSymbol || token.tokenId || token.tokenID || token.symbol,
355
- }
356
- }
357
-
358
- export const getTokenPrices = async (
359
- trailsClient: TrailsClient,
360
- tokens: Token[],
361
- ): Promise<TokenPrice[]> => {
362
- tokens = tokens.map(normalizeToken)
363
- return fetchGetTokenPrices(trailsClient, tokens)
364
- }
365
-
366
- export const getTokenPrice = async (
367
- trailsClient: TrailsClient,
368
- token: Token,
369
- ): Promise<TokenPrice | null> => {
370
- token = normalizeToken(token)
371
- const prices = await fetchGetTokenPrices(trailsClient, [token])
372
- return prices?.length ? (prices[0] ?? null) : null
373
- }
374
-
375
- export const useTokenPrices = (tokens: Token[], disabled?: boolean) => {
376
- const trailsClient = useTrailsClient()
377
- const { isUserActive } = useUserActivityContext()
378
- tokens = tokens.map(normalizeToken)
379
-
380
- const { data: tokenPrices, isLoading: isLoadingTokenPrices } = useQuery({
381
- queryKey: createBatchCacheKey(tokens),
382
- queryFn: () => getTokenPrices(trailsClient, tokens),
383
- enabled: !disabled && tokens.length > 0 && !!trailsClient,
384
- ...COMMON_QUERY_OPTIONS,
385
- refetchInterval: isUserActive ? CACHE_CONFIG.refetchInterval : false, // Pause polling when user is inactive
386
- })
387
-
388
- return {
389
- tokenPrices,
390
- isLoadingTokenPrices,
391
- }
392
- }
393
-
394
- export const useTokenPrice = (token?: Token | null) => {
395
- const trailsClient = useTrailsClient()
396
- const { isUserActive } = useUserActivityContext()
397
-
398
- const { data: tokenPrice, isLoading: isLoadingTokenPrice } = useQuery({
399
- queryKey: createSingleCacheKey(token),
400
- queryFn: () =>
401
- token && trailsClient ? getTokenPrice(trailsClient, token) : null,
402
- enabled: !!token && !!trailsClient,
403
- ...COMMON_QUERY_OPTIONS,
404
- refetchInterval: isUserActive ? CACHE_CONFIG.refetchInterval : false, // Pause polling when user is inactive
405
- })
406
-
407
- return {
408
- tokenPrice,
409
- isLoadingTokenPrice,
410
- }
411
- }
412
-
413
- // Cache invalidation utility function
414
- export function invalidateTokenPricesCache(token?: Token, qc?: QueryClient) {
415
- const client = qc ?? defaultQueryClient
416
- if (token) {
417
- // Invalidate specific token price using consistent cache key
418
- client.invalidateQueries({
419
- queryKey: createSingleCacheKey(token),
420
- })
421
- } else {
422
- // Invalidate all token price queries
423
- client.invalidateQueries({
424
- queryKey: ["tokenPrices"],
425
- })
426
- }
427
-
428
- // Also clear localStorage cache
429
- clearLocalStoragePriceCache()
430
- }
431
-
432
- // Clear all localStorage price cache
433
- export function clearLocalStoragePriceCache(): void {
434
- try {
435
- localStorage.removeItem(LOCAL_STORAGE_CACHE_KEY)
436
- logger.console.debug("[trails-sdk] Cleared localStorage price cache")
437
- } catch (error) {
438
- logger.console.warn(
439
- "[trails-sdk] Failed to clear localStorage cache:",
440
- error,
441
- )
442
- }
443
- }
444
-
445
- // Export function to manually trigger cleanup if needed
446
- export function cleanupExpiredPriceCache(): void {
447
- const cache = getLocalStorageCache()
448
- cleanupExpiredEntries(cache)
449
- setLocalStorageCache(cache)
450
- }
451
-
452
- export function calcAmountUsdPrice({
453
- amount,
454
- usdPrice,
455
- }: {
456
- amount: number | string
457
- usdPrice: string | number | null | undefined
458
- }) {
459
- const sanitizedAmount = normalizeNumber(amount)
460
- const sanitizedPrice = normalizeNumber(usdPrice)
461
-
462
- // Validate inputs
463
- if (!isNonNegativeNumber(sanitizedAmount)) {
464
- return 0
465
- }
466
- if (!isNonNegativeNumber(sanitizedPrice)) {
467
- return 0
468
- }
469
-
470
- const result = sanitizedAmount * sanitizedPrice
471
-
472
- // Validate result
473
- if (!isValidNumber(result)) {
474
- logger.console.error("[trails-sdk] Error calculating amount USD:", {
475
- sanitizedAmount,
476
- sanitizedPrice,
477
- result,
478
- amount,
479
- usdPrice,
480
- })
481
- return 0
482
- }
483
-
484
- return result
485
- }
486
-
487
- export function normalizeNumber(
488
- number: number | string | null | undefined,
489
- ): number {
490
- if (number === null || number === undefined) {
491
- return 0
492
- }
493
-
494
- // If already a number, return it directly
495
- if (typeof number === "number") {
496
- // Validate the number
497
- if (!isValidNumber(number)) {
498
- logger.console.error("[trails-sdk] Invalid number value:", number)
499
- return 0
500
- }
501
- return number
502
- }
503
-
504
- // Only parse strings that might be locale-formatted
505
- // This should ideally only be used for user input, not internal calculations
506
- const normalized = parseLocaleNumber(number)
507
-
508
- // Return 0 for invalid numbers
509
- if (!isValidNumber(normalized)) {
510
- logger.console.error("[trails-sdk] Error normalizing number string:", {
511
- number,
512
- normalized,
513
- })
514
- return 0
515
- }
516
-
517
- return normalized
518
- }
519
-
520
- // Format TVL (Total Value Locked) for display
521
- export function formatTvl(tvl: number): string {
522
- if (tvl >= 1e9) return `$${(tvl / 1e9).toFixed(1)}B`
523
- if (tvl >= 1e6) return `$${(tvl / 1e6).toFixed(1)}M`
524
- if (tvl >= 1e3) return `$${(tvl / 1e3).toFixed(1)}K`
525
- return `$${tvl.toFixed(0)}`
526
- }
527
-
528
- export { isValidNumeric, isValidInteger } from "./utils/validation.js"
@@ -1,147 +0,0 @@
1
- import { useQuery } from "@tanstack/react-query"
2
- import type { QueryClient } from "@tanstack/react-query"
3
- import type { PublicClient } from "viem"
4
- import { estimateGasLimit, getFeeData } from "./estimate.js"
5
- import { MINUTE_MS, SECOND_MS } from "./utils/time.js"
6
-
7
- /**
8
- * Parameters for gas limit estimation
9
- */
10
- export interface GasEstimationParams {
11
- account: string
12
- to: string | bigint | number
13
- data: string | bigint | number
14
- value: bigint | string | number
15
- }
16
-
17
- /**
18
- * Helper to create a consistent query key for gas estimation
19
- */
20
- function createGasEstimationQueryKey(
21
- chainId: number | undefined,
22
- params: GasEstimationParams | null | undefined,
23
- ) {
24
- return [
25
- "gas-limit",
26
- chainId,
27
- params?.account,
28
- params?.to,
29
- params?.data,
30
- params?.value?.toString(),
31
- ] as const
32
- }
33
-
34
- /**
35
- * Hook to estimate gas limit with caching
36
- *
37
- * Gas LIMIT is cached for 60 seconds
38
- */
39
- export async function fetchCachedGasLimit(
40
- queryClient: QueryClient,
41
- publicClient: PublicClient,
42
- params: GasEstimationParams,
43
- logContext: string = "transaction",
44
- ): Promise<bigint | undefined> {
45
- try {
46
- const result = await queryClient.fetchQuery({
47
- queryKey: createGasEstimationQueryKey(publicClient.chain?.id, params),
48
- queryFn: async () => {
49
- const gasLimit = await estimateGasLimit(
50
- publicClient,
51
- params,
52
- logContext,
53
- )
54
- // React Query doesn't allow undefined return values
55
- // Return null instead and convert back to undefined outside
56
- if (gasLimit === undefined) {
57
- return null
58
- }
59
- return gasLimit
60
- },
61
- staleTime: MINUTE_MS, // 60 seconds
62
- gcTime: 2 * MINUTE_MS, // Keep in cache for 2 minutes
63
- retry: 2, // Retry up to 2 times on failure
64
- })
65
- // Convert null back to undefined for the caller
66
- return result === null ? undefined : result
67
- } catch (_error) {
68
- // If query fails, return undefined to allow caller to handle gracefully
69
- return undefined
70
- }
71
- }
72
-
73
- export function useGasEstimation(
74
- publicClient: PublicClient | null | undefined,
75
- params: GasEstimationParams | null | undefined,
76
- enabled: boolean = true,
77
- ) {
78
- return useQuery({
79
- queryKey: createGasEstimationQueryKey(publicClient?.chain?.id, params),
80
- queryFn: async () => {
81
- if (!publicClient || !params) {
82
- throw new Error("Missing publicClient or params for gas estimation")
83
- }
84
- const gasLimit = await estimateGasLimit(publicClient, params)
85
- if (gasLimit === undefined) {
86
- return null
87
- }
88
- return gasLimit
89
- },
90
- enabled: enabled && !!publicClient && !!params,
91
- staleTime: MINUTE_MS, // 60 seconds
92
- gcTime: 2 * MINUTE_MS, // Keep in cache for 2 minutes
93
- retry: 2, // Retry up to 2 times on failure
94
- retryDelay: SECOND_MS, // Wait 1 second between retries
95
- })
96
- }
97
-
98
- /**
99
- * Helper function to create gas estimation params
100
- * Useful for ensuring type safety and consistency
101
- */
102
- export function createGasEstimationParams(
103
- account: string,
104
- to: string,
105
- data: string,
106
- value: bigint | string | number,
107
- ): GasEstimationParams {
108
- return {
109
- account,
110
- to,
111
- data,
112
- value,
113
- }
114
- }
115
-
116
- /**
117
- * Helper to create a consistent query key for fee data
118
- */
119
- function createFeeDataQueryKey(chainId: number | undefined, context: string) {
120
- return ["gas-fee-data", chainId, context] as const
121
- }
122
-
123
- /**
124
- * Fetch gas fee data (prices) with SHORT-TERM caching
125
- *
126
- * Gas PRICES are cached for only 5 seconds
127
- */
128
- export async function fetchCachedFeeData(
129
- queryClient: QueryClient,
130
- publicClient: PublicClient,
131
- context: string = "default",
132
- ): Promise<{
133
- maxFeePerGas?: bigint
134
- maxPriorityFeePerGas?: bigint
135
- gasPrice?: bigint
136
- }> {
137
- return await queryClient.fetchQuery({
138
- queryKey: createFeeDataQueryKey(publicClient.chain?.id, context),
139
- queryFn: async () => {
140
- const feeData = await getFeeData(publicClient)
141
- return feeData
142
- },
143
- staleTime: 5 * SECOND_MS, // 5 seconds
144
- gcTime: 10 * SECOND_MS, // Keep in cache for 10 seconds
145
- retry: 2,
146
- })
147
- }
@@ -1,14 +0,0 @@
1
- <?xml version="1.0" encoding="utf-8"?>
2
- <!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
3
- <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
4
- <svg version="1.1" id="Your_design" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px"
5
- y="0px" width="126.611px" height="126.611px" viewBox="0 0 126.611 126.611" enable-background="new 0 0 126.611 126.611"
6
- xml:space="preserve">
7
- <polygon fill="#F3BA2F" points="38.171,53.203 62.759,28.616 87.36,53.216 101.667,38.909 62.759,0 23.864,38.896 "/>
8
- <rect x="3.644" y="53.188" transform="matrix(0.7071 0.7071 -0.7071 0.7071 48.7933 8.8106)" fill="#F3BA2F" width="20.233" height="20.234"/>
9
- <polygon fill="#F3BA2F" points="38.171,73.408 62.759,97.995 87.359,73.396 101.674,87.695 101.667,87.703 62.759,126.611
10
- 23.863,87.716 23.843,87.696 "/>
11
- <rect x="101.64" y="53.189" transform="matrix(-0.7071 0.7071 -0.7071 -0.7071 235.5457 29.0503)" fill="#F3BA2F" width="20.234" height="20.233"/>
12
- <polygon fill="#F3BA2F" points="77.271,63.298 77.277,63.298 62.759,48.78 52.03,59.509 52.029,59.509 50.797,60.742 48.254,63.285
13
- 48.254,63.285 48.234,63.305 48.254,63.326 62.759,77.831 77.277,63.313 77.284,63.305 "/>
14
- </svg>
@@ -1,5 +0,0 @@
1
- <?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
2
- <svg width="800px" height="800px" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg">
3
- <circle cx="512" cy="512" r="512" style="fill:#03ca9b"/>
4
- <path d="M732.81 275c-1.67-.73-173.51-24.6-343.39 86.88C284 431.22 270 532.68 274.81 600.36c247.08-27.89 452.41-317.29 458-325.36zM291.57 675.53c21.24 38.14 181.77 124.6 323.87 5.35S745.62 344.66 732.81 275c-4.47 10.11-159.62 356.89-441.24 400.51" style="fill:#fff"/>
5
- </svg>
@@ -1 +0,0 @@
1
- <svg width="500" height="500" viewBox="0 0 400 400" xmlns="http://www.w3.org/2000/svg"><path fill="#1652f0" d="m0 0l400 0 0 400-400 0 0-400m168.23 107.38c-24.43 9.85-44.5 29.84-54.56 54.17-7.56 17.87-9.39 37.96-5.94 56.99 4.91 27.2 21.92 51.86 45.41 66.37 17.89 11.27 39.44 16.5 60.5 14.81 23.61-1.56 46.36-12.19 63.08-28.89-10.16-10.4-20.52-20.61-30.81-30.88-12.44 12.02-30.31 18.47-47.55 15.82-12.8-1.69-24.88-8.02-33.6-17.54-11.77-12.48-17.22-30.64-14.2-47.54 1.96-12.42 8.41-24.01 17.75-32.39 12.77-11.76 31.23-17 48.27-13.58 11.09 1.95 21.16 7.72 29.33 15.36 10.31-10.26 20.62-20.52 30.84-30.88-10.58-10.46-23.42-18.68-37.5-23.57-22.82-8.1-48.62-7.47-71.02 1.75"/><path fill="#fff" d="m168.23 107.38c22.4-9.22 48.2-9.85 71.02-1.75 14.08 4.89 26.92 13.11 37.5 23.57-10.22 10.36-20.53 20.62-30.84 30.88-8.17-7.64-18.24-13.41-29.33-15.36-17.04-3.42-35.5 1.82-48.27 13.58-9.34 8.38-15.79 19.97-17.75 32.39-3.02 16.9 2.43 35.06 14.2 47.54 8.72 9.52 20.8 15.85 33.6 17.54 17.24 2.65 35.11-3.8 47.55-15.82 10.29 10.27 20.65 20.48 30.81 30.88-16.72 16.7-39.47 27.33-63.08 28.89-21.06 1.69-42.61-3.54-60.5-14.81-23.49-14.51-40.5-39.17-45.41-66.37-3.45-19.03-1.62-39.12 5.94-56.99 10.06-24.33 30.13-44.32 54.56-54.17"/></svg>