@layerswap/widget 1.1.0 → 1.1.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 (187) hide show
  1. package/dist/esm/components/ErrorFallback.js +1 -1
  2. package/dist/esm/components/Icons/CircularLoader.js +5 -0
  3. package/dist/esm/components/Icons/FailIcon.js +2 -2
  4. package/dist/esm/components/Icons/GlobeIcon.js +3 -0
  5. package/dist/esm/components/Icons/MenuIcon.js +5 -0
  6. package/dist/esm/components/Icons/TokenIcon.js +1 -1
  7. package/dist/esm/components/Icons/Wallets/index.js +0 -2
  8. package/dist/esm/components/Input/Address/AddressNote.js +2 -2
  9. package/dist/esm/components/Input/Address/AddressPicker/AddressWithIcon.js +5 -2
  10. package/dist/esm/components/Input/Address/ContractAddressNote.js +17 -0
  11. package/dist/esm/components/Input/Address/UrlAddressNote.js +10 -0
  12. package/dist/esm/components/Input/Amount/ExchangeReceiveAmount.js +1 -1
  13. package/dist/esm/components/Input/Amount/PriceImpact.js +3 -5
  14. package/dist/esm/components/Input/Amount/ReceiveAmount.js +1 -1
  15. package/dist/esm/components/Input/RoutePicker/Content.js +17 -1
  16. package/dist/esm/components/Input/RoutePicker/RouteTokenSwitch.js +4 -4
  17. package/dist/esm/components/Input/RoutePicker/Routes.js +12 -11
  18. package/dist/esm/components/Input/RoutePicker/TokenTitleDetails.js +10 -0
  19. package/dist/esm/components/Input/RoutePicker/index.js +1 -1
  20. package/dist/esm/components/Menu/MenuList.js +11 -19
  21. package/dist/esm/components/Menu/index.js +16 -7
  22. package/dist/esm/components/Modal/modalWithoutAnimation.js +3 -3
  23. package/dist/esm/components/Pages/Campaigns/Details/index.js +1 -1
  24. package/dist/esm/components/Pages/Swap/Form/FeeDetails/Rate.js +3 -2
  25. package/dist/esm/components/Pages/Swap/Form/FeeDetails/Refuel.js +6 -1
  26. package/dist/esm/components/Pages/Swap/Form/FeeDetails/index.js +2 -2
  27. package/dist/esm/components/Pages/Swap/Form/FormWrapper.js +29 -2
  28. package/dist/esm/components/Pages/Swap/Form/NetworkForm.js +4 -3
  29. package/dist/esm/components/Pages/Swap/Form/SecondaryComponents/FormButton.js +1 -1
  30. package/dist/esm/components/Pages/Swap/Form/SecondaryComponents/validationError/ContractAddressValidationCache.js +19 -0
  31. package/dist/esm/components/Pages/Swap/Withdraw/Processing/Processing.js +9 -5
  32. package/dist/esm/components/Pages/Swap/Withdraw/Summary/Summary.js +2 -3
  33. package/dist/esm/components/Pages/Swap/Withdraw/Wallet/Common/buttons.js +13 -6
  34. package/dist/esm/components/Pages/Swap/Withdraw/WalletTransferButton.js +1 -1
  35. package/dist/esm/components/Pages/Swap/Withdraw/messages/Message.js +4 -4
  36. package/dist/esm/components/Pages/SwapHistory/History.js +1 -1
  37. package/dist/esm/components/Pages/SwapHistory/HistorySummary.js +1 -1
  38. package/dist/esm/components/Select/Selector/SelectItem.js +1 -1
  39. package/dist/esm/components/Wallet/WalletComponents/ConnectedWallets.js +4 -4
  40. package/dist/esm/components/Wallet/WalletModal/ConnectorsList.js +74 -125
  41. package/dist/esm/components/Wallet/WalletModal/InstalledExtensionNotFound.js +16 -0
  42. package/dist/esm/components/Wallet/WalletModal/LoadingConnect.js +27 -0
  43. package/dist/esm/components/Wallet/WalletModal/MultichainConnectorPicker.js +23 -0
  44. package/dist/esm/components/Wallet/WalletModal/ProviderPicker.js +26 -0
  45. package/dist/esm/components/Wallet/WalletModal/WalletQrCode.js +18 -0
  46. package/dist/esm/components/Wallet/WalletModal/index.js +1 -1
  47. package/dist/esm/components/Wallet/WalletProviders/index.js +1 -1
  48. package/dist/esm/components/Widget/Footer.js +20 -20
  49. package/dist/esm/components/Widget/Index.js +1 -1
  50. package/dist/esm/components/shadcn/checkbox.js +1 -1
  51. package/dist/esm/context/callbackProvider.js +6 -0
  52. package/dist/esm/context/resolverContext.js +5 -1
  53. package/dist/esm/hooks/useAllWithdrawalBalances.js +5 -0
  54. package/dist/esm/hooks/useConnectors.js +72 -0
  55. package/dist/esm/lib/address/contractAddressResolver.js +12 -0
  56. package/dist/esm/lib/apiClients/layerSwapApiClient.js +8 -1
  57. package/dist/esm/lib/balances/balanceResolver.js +52 -2
  58. package/dist/esm/lib/balances/errorUtils.js +13 -0
  59. package/dist/esm/lib/balances/nodeErrorClassifier.js +22 -0
  60. package/dist/esm/lib/fees.js +2 -2
  61. package/dist/esm/lib/generateSwapInitialValues.js +2 -2
  62. package/dist/esm/lib/isNewListed.js +8 -0
  63. package/dist/esm/lib/knownIds.js +1 -0
  64. package/dist/esm/lib/resolvers/resolverService.js +10 -1
  65. package/dist/esm/stores/balanceStore.js +39 -17
  66. package/dist/esm/stores/contractAddressStore.js +178 -0
  67. package/dist/esm/types/balance.js +15 -2
  68. package/dist/esm/types/contract.js +1 -0
  69. package/dist/esm/types/index.js +1 -0
  70. package/dist/index.css +1 -1
  71. package/dist/tsconfig.tsbuildinfo +1 -1
  72. package/dist/types/Models/Balance.d.ts +13 -1
  73. package/dist/types/Models/Balance.d.ts.map +1 -1
  74. package/dist/types/components/Icons/CircularLoader.d.ts +4 -0
  75. package/dist/types/components/Icons/CircularLoader.d.ts.map +1 -0
  76. package/dist/types/components/Icons/FailIcon.d.ts.map +1 -1
  77. package/dist/types/components/Icons/GasIcon.d.ts.map +1 -1
  78. package/dist/types/components/Icons/GlobeIcon.d.ts +4 -0
  79. package/dist/types/components/Icons/GlobeIcon.d.ts.map +1 -0
  80. package/dist/types/components/Icons/MenuIcon.d.ts +4 -0
  81. package/dist/types/components/Icons/MenuIcon.d.ts.map +1 -0
  82. package/dist/types/components/Icons/TokenIcon.d.ts.map +1 -1
  83. package/dist/types/components/Icons/Wallets/index.d.ts +0 -2
  84. package/dist/types/components/Icons/Wallets/index.d.ts.map +1 -1
  85. package/dist/types/components/Input/Address/AddressNote.d.ts +3 -3
  86. package/dist/types/components/Input/Address/AddressNote.d.ts.map +1 -1
  87. package/dist/types/components/Input/Address/AddressPicker/AddressWithIcon.d.ts +1 -0
  88. package/dist/types/components/Input/Address/AddressPicker/AddressWithIcon.d.ts.map +1 -1
  89. package/dist/types/components/Input/Address/ContractAddressNote.d.ts +9 -0
  90. package/dist/types/components/Input/Address/ContractAddressNote.d.ts.map +1 -0
  91. package/dist/types/components/Input/Address/UrlAddressNote.d.ts +10 -0
  92. package/dist/types/components/Input/Address/UrlAddressNote.d.ts.map +1 -0
  93. package/dist/types/components/Input/Amount/PriceImpact.d.ts +2 -1
  94. package/dist/types/components/Input/Amount/PriceImpact.d.ts.map +1 -1
  95. package/dist/types/components/Input/RoutePicker/Content.d.ts.map +1 -1
  96. package/dist/types/components/Input/RoutePicker/RouterPickerWalletConnect.d.ts.map +1 -1
  97. package/dist/types/components/Input/RoutePicker/Routes.d.ts.map +1 -1
  98. package/dist/types/components/Input/RoutePicker/TokenTitleDetails.d.ts +18 -0
  99. package/dist/types/components/Input/RoutePicker/TokenTitleDetails.d.ts.map +1 -0
  100. package/dist/types/components/Menu/MenuList.d.ts.map +1 -1
  101. package/dist/types/components/Menu/index.d.ts.map +1 -1
  102. package/dist/types/components/Modal/modalWithoutAnimation.d.ts +4 -2
  103. package/dist/types/components/Modal/modalWithoutAnimation.d.ts.map +1 -1
  104. package/dist/types/components/Pages/Swap/Form/FeeDetails/Rate.d.ts.map +1 -1
  105. package/dist/types/components/Pages/Swap/Form/FeeDetails/Refuel.d.ts +0 -1
  106. package/dist/types/components/Pages/Swap/Form/FeeDetails/Refuel.d.ts.map +1 -1
  107. package/dist/types/components/Pages/Swap/Form/FeeDetails/index.d.ts.map +1 -1
  108. package/dist/types/components/Pages/Swap/Form/FormWrapper.d.ts.map +1 -1
  109. package/dist/types/components/Pages/Swap/Form/NetworkForm.d.ts.map +1 -1
  110. package/dist/types/components/Pages/Swap/Form/SecondaryComponents/FormButton.d.ts.map +1 -1
  111. package/dist/types/components/Pages/Swap/Form/SecondaryComponents/validationError/ContractAddressValidationCache.d.ts +10 -0
  112. package/dist/types/components/Pages/Swap/Form/SecondaryComponents/validationError/ContractAddressValidationCache.d.ts.map +1 -0
  113. package/dist/types/components/Pages/Swap/Withdraw/Processing/Processing.d.ts.map +1 -1
  114. package/dist/types/components/Pages/Swap/Withdraw/Summary/Summary.d.ts.map +1 -1
  115. package/dist/types/components/Pages/Swap/Withdraw/Wallet/Common/buttons.d.ts.map +1 -1
  116. package/dist/types/components/Pages/Swap/Withdraw/WalletTransferButton.d.ts.map +1 -1
  117. package/dist/types/components/Pages/Swap/Withdraw/messages/Message.d.ts.map +1 -1
  118. package/dist/types/components/Pages/SwapHistory/HistorySummary.d.ts.map +1 -1
  119. package/dist/types/components/Select/Command/commandSelect.d.ts.map +1 -1
  120. package/dist/types/components/Select/Selector/SelectItem.d.ts.map +1 -1
  121. package/dist/types/components/Wallet/WalletModal/ConnectorsList.d.ts.map +1 -1
  122. package/dist/types/components/Wallet/WalletModal/InstalledExtensionNotFound.d.ts +7 -0
  123. package/dist/types/components/Wallet/WalletModal/InstalledExtensionNotFound.d.ts.map +1 -0
  124. package/dist/types/components/Wallet/WalletModal/LoadingConnect.d.ts +8 -0
  125. package/dist/types/components/Wallet/WalletModal/LoadingConnect.d.ts.map +1 -0
  126. package/dist/types/components/Wallet/WalletModal/MultichainConnectorPicker.d.ts +12 -0
  127. package/dist/types/components/Wallet/WalletModal/MultichainConnectorPicker.d.ts.map +1 -0
  128. package/dist/types/components/Wallet/WalletModal/ProviderPicker.d.ts +8 -0
  129. package/dist/types/components/Wallet/WalletModal/ProviderPicker.d.ts.map +1 -0
  130. package/dist/types/components/Wallet/WalletModal/WalletQrCode.d.ts +6 -0
  131. package/dist/types/components/Wallet/WalletModal/WalletQrCode.d.ts.map +1 -0
  132. package/dist/types/components/Wallet/WalletModal/index.d.ts +1 -0
  133. package/dist/types/components/Wallet/WalletModal/index.d.ts.map +1 -1
  134. package/dist/types/components/Widget/Footer.d.ts.map +1 -1
  135. package/dist/types/context/callbackProvider.d.ts +1 -0
  136. package/dist/types/context/callbackProvider.d.ts.map +1 -1
  137. package/dist/types/context/resolverContext.d.ts.map +1 -1
  138. package/dist/types/context/swapAccounts.d.ts.map +1 -1
  139. package/dist/types/context/walletProviders.d.ts.map +1 -1
  140. package/dist/types/hooks/useAllWithdrawalBalances.d.ts.map +1 -1
  141. package/dist/types/hooks/useConnectors.d.ts +28 -0
  142. package/dist/types/hooks/useConnectors.d.ts.map +1 -0
  143. package/dist/types/lib/address/contractAddressResolver.d.ts +7 -0
  144. package/dist/types/lib/address/contractAddressResolver.d.ts.map +1 -0
  145. package/dist/types/lib/apiClients/layerSwapApiClient.d.ts.map +1 -1
  146. package/dist/types/lib/balances/balanceResolver.d.ts.map +1 -1
  147. package/dist/types/lib/balances/errorUtils.d.ts +12 -0
  148. package/dist/types/lib/balances/errorUtils.d.ts.map +1 -0
  149. package/dist/types/lib/balances/nodeErrorClassifier.d.ts +4 -0
  150. package/dist/types/lib/balances/nodeErrorClassifier.d.ts.map +1 -0
  151. package/dist/types/lib/fees.d.ts +2 -2
  152. package/dist/types/lib/fees.d.ts.map +1 -1
  153. package/dist/types/lib/isNewListed.d.ts +4 -0
  154. package/dist/types/lib/isNewListed.d.ts.map +1 -0
  155. package/dist/types/lib/knownIds.d.ts +1 -0
  156. package/dist/types/lib/knownIds.d.ts.map +1 -1
  157. package/dist/types/lib/resolvers/resolverService.d.ts +5 -2
  158. package/dist/types/lib/resolvers/resolverService.d.ts.map +1 -1
  159. package/dist/types/stores/balanceStore.d.ts +3 -0
  160. package/dist/types/stores/balanceStore.d.ts.map +1 -1
  161. package/dist/types/stores/contractAddressStore.d.ts +43 -0
  162. package/dist/types/stores/contractAddressStore.d.ts.map +1 -0
  163. package/dist/types/types/balance.d.ts.map +1 -1
  164. package/dist/types/types/contract.d.ts +6 -0
  165. package/dist/types/types/contract.d.ts.map +1 -0
  166. package/dist/types/types/index.d.ts +1 -0
  167. package/dist/types/types/index.d.ts.map +1 -1
  168. package/dist/types/types/logEvents.d.ts +19 -1
  169. package/dist/types/types/logEvents.d.ts.map +1 -1
  170. package/dist/types/types/wallet.d.ts +6 -3
  171. package/dist/types/types/wallet.d.ts.map +1 -1
  172. package/package.json +1 -1
  173. package/dist/esm/components/Icons/Wallets/Keplr.js +0 -3
  174. package/dist/esm/components/Icons/Wallets/Xverse.js +0 -3
  175. package/dist/esm/components/Modal/popover.js +0 -15
  176. package/dist/esm/components/Wallet/WalletModal/utils.js +0 -23
  177. package/dist/esm/lib/sorting.js +0 -63
  178. package/dist/types/components/Icons/Wallets/Keplr.d.ts +0 -4
  179. package/dist/types/components/Icons/Wallets/Keplr.d.ts.map +0 -1
  180. package/dist/types/components/Icons/Wallets/Xverse.d.ts +0 -4
  181. package/dist/types/components/Icons/Wallets/Xverse.d.ts.map +0 -1
  182. package/dist/types/components/Modal/popover.d.ts +0 -12
  183. package/dist/types/components/Modal/popover.d.ts.map +0 -1
  184. package/dist/types/components/Wallet/WalletModal/utils.d.ts +0 -2
  185. package/dist/types/components/Wallet/WalletModal/utils.d.ts.map +0 -1
  186. package/dist/types/lib/sorting.d.ts +0 -22
  187. package/dist/types/lib/sorting.d.ts.map +0 -1
@@ -0,0 +1,12 @@
1
+ export class ContractAddressResolver {
2
+ constructor(providers) {
3
+ this.providers = providers || [];
4
+ }
5
+ async isContractAddress(network, address) {
6
+ const provider = this.providers.find(p => p.supportsNetwork(network));
7
+ if (!provider) {
8
+ return false;
9
+ }
10
+ return provider.isContractAddress(address, network);
11
+ }
12
+ }
@@ -40,7 +40,14 @@ class LayerSwapApiClient {
40
40
  return Promise.resolve(new EmptyApiResponse());
41
41
  }
42
42
  else {
43
- const error = reason;
43
+ let error;
44
+ if (reason instanceof Error) {
45
+ error = reason;
46
+ }
47
+ else {
48
+ error = new Error(String(reason));
49
+ error.name = "APIError";
50
+ }
44
51
  ErrorHandler({
45
52
  type: 'APIError',
46
53
  message: error.message,
@@ -1,4 +1,24 @@
1
1
  import { ErrorHandler } from "../../lib/ErrorHandler";
2
+ import { classifyNodeError } from "./nodeErrorClassifier";
3
+ import { extractErrorDetails } from "./errorUtils";
4
+ function formatErrorBalances(errorBalances) {
5
+ return errorBalances.map(b => ({
6
+ token: b.token,
7
+ error_message: b.error?.message,
8
+ error_name: b.error?.name,
9
+ error_code: b.error?.code,
10
+ error_category: b.error?.category,
11
+ response_status: b.error?.status,
12
+ response_status_text: b.error?.statusText,
13
+ request_url: b.error?.requestUrl,
14
+ // Include first 500 chars of stack trace for debugging
15
+ error_stack: b.error?.stack?.substring(0, 500),
16
+ // Include response data if available (truncated for size)
17
+ response_data: b.error?.responseData
18
+ ? JSON.stringify(b.error.responseData).substring(0, 1000)
19
+ : undefined
20
+ }));
21
+ }
2
22
  export class BalanceResolver {
3
23
  constructor(providers) {
4
24
  this.providers = providers || [];
@@ -13,16 +33,46 @@ export class BalanceResolver {
13
33
  if (!provider)
14
34
  throw new Error(`No balance provider found for network ${network.name}`);
15
35
  const balances = await provider.fetchBalance(address, network, { timeoutMs: options?.timeoutMs, retryCount: options?.retryCount });
36
+ const errorBalances = balances?.filter(b => b.error);
37
+ if (errorBalances?.length) {
38
+ const balanceError = new Error(`Could not fetch balance for ${errorBalances.map(t => t.token).join(", ")} in ${network.name}`);
39
+ ErrorHandler({
40
+ type: 'BalanceResolverError',
41
+ name: balanceError.name,
42
+ stack: balanceError.stack,
43
+ cause: balanceError.cause,
44
+ message: balanceError.message,
45
+ network: network.name,
46
+ node_url: network.node_url,
47
+ address: address,
48
+ error_categories: [...new Set(errorBalances.map(b => classifyNodeError(b.error)))],
49
+ error_codes: [...new Set(errorBalances.map(b => b.error?.code).filter(Boolean))],
50
+ http_statuses: [...new Set(errorBalances.map(b => b.error?.status).filter(Boolean))],
51
+ failed_tokens: formatErrorBalances(errorBalances),
52
+ });
53
+ }
16
54
  return { balances };
17
55
  }
18
56
  catch (e) {
19
- const error = e;
57
+ const errorDetails = extractErrorDetails(e);
58
+ const error = new Error(errorDetails.message);
59
+ error.name = "BalanceError";
60
+ error.cause = e;
20
61
  ErrorHandler({
21
62
  type: 'BalanceResolverError',
22
63
  message: error.message,
23
64
  name: error.name,
24
65
  stack: error.stack,
25
- cause: error
66
+ cause: error.cause,
67
+ network: network.name,
68
+ node_url: network.node_url,
69
+ address: address,
70
+ error_category: classifyNodeError(e),
71
+ error_code: errorDetails.code,
72
+ response_status: errorDetails.status,
73
+ response_status_text: errorDetails.statusText,
74
+ response_data: errorDetails.responseData,
75
+ request_url: errorDetails.requestUrl,
26
76
  });
27
77
  return { balances: [] };
28
78
  }
@@ -0,0 +1,13 @@
1
+ export function extractErrorDetails(error) {
2
+ const err = error;
3
+ return {
4
+ message: err?.message || String(error),
5
+ name: err?.name,
6
+ stack: err?.stack,
7
+ status: err?.response?.status,
8
+ statusText: err?.response?.statusText,
9
+ responseData: err?.response?.data,
10
+ requestUrl: err?.request?.url,
11
+ code: err?.code,
12
+ };
13
+ }
@@ -0,0 +1,22 @@
1
+ export function classifyNodeError(error) {
2
+ // If it's already a structured error with category, return it
3
+ if (typeof error === 'object' && error !== null && 'category' in error) {
4
+ const category = error.category;
5
+ if (category) {
6
+ return category;
7
+ }
8
+ }
9
+ // Otherwise classify from message
10
+ const message = (error?.message || String(error)).toLowerCase();
11
+ if (message.includes('timeout') || message.includes('timed out'))
12
+ return 'timeout';
13
+ if (message.includes('econnrefused') || message.includes('connection refused'))
14
+ return 'connection_refused';
15
+ if (message.includes('429') || message.includes('rate limit'))
16
+ return 'rate_limited';
17
+ if (message.includes('invalid json') || message.includes('unexpected token'))
18
+ return 'invalid_response';
19
+ if (message.includes('network') || message.includes('fetch failed'))
20
+ return 'network_error';
21
+ return 'unknown';
22
+ }
@@ -1,7 +1,7 @@
1
1
  export function CalculateMinimalAuthorizeAmount(usd_price, amount) {
2
2
  return Math.ceil((usd_price * amount) + (usd_price * amount * 0.02));
3
3
  }
4
- export const resolvePriceImpactValues = (quote) => {
4
+ export const resolvePriceImpactValues = (quote, refuel) => {
5
5
  const receiveAmount = quote?.receive_amount;
6
6
  const requestedAmount = quote?.requested_amount;
7
7
  const sourceTokenPriceUsd = quote?.source_token?.price_in_usd;
@@ -24,7 +24,7 @@ export const resolvePriceImpactValues = (quote) => {
24
24
  ? bridgeFee * sourceTokenPriceUsd
25
25
  : undefined;
26
26
  const marketImpact = priceImpact !== undefined && layerswapFees !== undefined && bridgeExpenses !== undefined
27
- ? priceImpact + Number(layerswapFees) + Number(bridgeExpenses)
27
+ ? priceImpact + Number(layerswapFees) + Number(bridgeExpenses) + Number(refuel?.amount_in_usd || 0)
28
28
  : undefined;
29
29
  const priceImpactPercentage = requestedAmountUSD !== undefined && receiveAmountUSD !== undefined
30
30
  ? Number((((receiveAmountUSD - requestedAmountUSD) / requestedAmountUSD) * 100).toFixed(2))
@@ -24,11 +24,11 @@ export function generateSwapInitialValues(settings, queryParams, type) {
24
24
  let initialAddress = destination_address && initialDestination && isValidAddress(destination_address, destinationNetwork) ? destination_address : "";
25
25
  let initialSourceCurrency = filteredSourceCurrencies?.find(c => c.symbol?.toUpperCase() == fromAsset?.toUpperCase());
26
26
  if (!initialSourceCurrency && !fromAsset && sourceNetwork) {
27
- initialSourceCurrency = filteredSourceCurrencies?.[0];
27
+ initialSourceCurrency = filteredSourceCurrencies?.sort((a, b) => a.symbol.localeCompare(b.symbol))?.find(c => c.status === "active");
28
28
  }
29
29
  let initialDestinationCurrency = filteredDestinationCurrencies?.find(c => c.symbol?.toUpperCase() == toAsset?.toUpperCase());
30
30
  if (!initialDestinationCurrency && !toAsset && destinationNetwork) {
31
- initialDestinationCurrency = filteredDestinationCurrencies?.[0];
31
+ initialDestinationCurrency = filteredDestinationCurrencies?.sort((a, b) => a.symbol.localeCompare(b.symbol))?.find(c => c.status === "active");
32
32
  }
33
33
  //TODO this looks wrong
34
34
  let initialAmount = (lockedDestinationCurrency && amount) || (initialDestinationCurrency ? amount : '');
@@ -0,0 +1,8 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ export const ONE_WEEK = 7 * 24 * 60 * 60 * 1000;
3
+ export const isNewListed = (date) => {
4
+ return new Date(date)?.getTime() >= new Date().getTime() - ONE_WEEK;
5
+ };
6
+ export const NewBadge = () => {
7
+ return (_jsx("div", { className: "text-primary-text text-xs py-0.5 px-1.5 bg-linear-90 from-primary-800 to-primary-600 rounded-md", children: "New" }));
8
+ };
@@ -140,6 +140,7 @@ KnownInternalNames.Networks = (_b = class {
140
140
  _b.BitcoinTestnet = "BITCOIN_TESTNET",
141
141
  _b.HyperliquidMainnet = "HYPERLIQUID_MAINNET",
142
142
  _b.HyperliquidTestnet = "HYPERLIQUID_TESTNET",
143
+ _b.MonadMainnet = "MONAD_MAINNET",
143
144
  _b);
144
145
  KnownInternalNames.Currencies = (_c = class {
145
146
  },
@@ -3,6 +3,7 @@ import { GasResolver } from "../../lib/gases/gasResolver";
3
3
  import { AddressUtilsResolver } from '../../lib/address/addressUtilsResolver';
4
4
  import { NftBalanceResolver } from "../nft/nftBalanceResolver";
5
5
  import { TransferResolver } from "../transfers/transferResolver";
6
+ import { ContractAddressResolver } from "../../lib/address/contractAddressResolver";
6
7
  class UtilsResolverService {
7
8
  constructor() {
8
9
  this.balanceResolver = null;
@@ -10,13 +11,15 @@ class UtilsResolverService {
10
11
  this.addressUtilsResolver = null;
11
12
  this.nftResolver = null;
12
13
  this.transferResolver = null;
14
+ this.contractAddressResolver = null;
13
15
  }
14
- setProviders(balanceProviders, gasProviders, addressUtilsProviders, nftProviders, transferProviders) {
16
+ setProviders(balanceProviders, gasProviders, addressUtilsProviders, nftProviders, transferProviders, contractAddressProviders) {
15
17
  this.balanceResolver = new BalanceResolver(balanceProviders);
16
18
  this.gasResolver = new GasResolver(gasProviders);
17
19
  this.addressUtilsResolver = new AddressUtilsResolver(addressUtilsProviders);
18
20
  this.nftResolver = new NftBalanceResolver(nftProviders);
19
21
  this.transferResolver = new TransferResolver(transferProviders);
22
+ this.contractAddressResolver = new ContractAddressResolver(contractAddressProviders);
20
23
  }
21
24
  getBalanceResolver() {
22
25
  if (!this.balanceResolver) {
@@ -48,5 +51,11 @@ class UtilsResolverService {
48
51
  }
49
52
  return this.transferResolver;
50
53
  }
54
+ getContractAddressResolver() {
55
+ if (!this.contractAddressResolver) {
56
+ throw new Error('ContractAddressResolver not initialized. Make sure to call setProviders first.');
57
+ }
58
+ return this.contractAddressResolver;
59
+ }
51
60
  }
52
61
  export const resolverService = new UtilsResolverService();
@@ -24,6 +24,19 @@ export const useBalanceStore = create()(subscribeWithSelector((set, get, api) =>
24
24
  sortingDataIsLoading: false,
25
25
  partialPublished: false,
26
26
  startTimeOfInit: undefined,
27
+ sortingTimerId: undefined,
28
+ sortingUnsubscribe: undefined,
29
+ cleanupSortingBalances: () => {
30
+ const { sortingTimerId, sortingUnsubscribe } = get();
31
+ if (sortingTimerId) {
32
+ clearTimeout(sortingTimerId);
33
+ set({ sortingTimerId: undefined });
34
+ }
35
+ if (sortingUnsubscribe) {
36
+ sortingUnsubscribe();
37
+ set({ sortingUnsubscribe: undefined });
38
+ }
39
+ },
27
40
  fetchBalance: (address, network, options) => {
28
41
  const key = getKey(address, network);
29
42
  const entry = get().balances[key];
@@ -80,6 +93,8 @@ export const useBalanceStore = create()(subscribeWithSelector((set, get, api) =>
80
93
  return queuedPromise;
81
94
  },
82
95
  initSortingBalances: pairs => {
96
+ get().cleanupSortingBalances();
97
+ // Setup initiated balances and start fetches
83
98
  const initiatedBalances = pairs.reduce((acc, { address, network }) => {
84
99
  const key = getKey(address, network);
85
100
  acc[network.name] = key;
@@ -93,29 +108,36 @@ export const useBalanceStore = create()(subscribeWithSelector((set, get, api) =>
93
108
  set({ initiatedBalances });
94
109
  set({ startTimeOfInit: Date.now() });
95
110
  set({ partialPublished: false });
96
- api.subscribe(state => state.balances, balances => {
111
+ // Active timer - fires at 3 seconds
112
+ const timerId = setTimeout(() => {
113
+ const state = get();
114
+ // Only publish if not already published and still loading
115
+ if (!state.partialPublished && state.sortingDataIsLoading) {
116
+ const partial = {};
117
+ const balances = state.balances;
118
+ Object.entries(state.initiatedBalances || {}).forEach(([networkName, key]) => {
119
+ if (balances[key]?.data) {
120
+ partial[networkName] = key;
121
+ }
122
+ });
123
+ set({ balanceKeysForSorting: partial });
124
+ set({ partialPublished: true });
125
+ }
126
+ }, 3000);
127
+ set({ sortingTimerId: timerId });
128
+ //Subscribe for completion detection
129
+ const unsubscribe = api.subscribe(state => state.balances, balances => {
97
130
  const keysArray = Object.entries(get().initiatedBalances || {});
98
- const done = keysArray.every(([_, key]) => balances[key].data);
131
+ const done = keysArray.every(([_, key]) => balances[key]?.data);
99
132
  if (done) {
133
+ // All complete - cleanup and finalize
134
+ get().cleanupSortingBalances();
100
135
  set({ sortingDataIsLoading: false });
101
136
  set({ balanceKeysForSorting: get().initiatedBalances });
102
- set({ partialPublished: false });
103
- }
104
- else {
105
- const startedAt = get().startTimeOfInit ?? 0;
106
- const elapsed = Date.now() - startedAt;
107
- if (!get().partialPublished && elapsed >= 3000) {
108
- const partial = {};
109
- keysArray.forEach(([networkName, key]) => {
110
- if (balances[key]?.data) {
111
- partial[networkName] = key;
112
- }
113
- });
114
- set({ balanceKeysForSorting: partial });
115
- set({ partialPublished: true });
116
- }
137
+ set({ partialPublished: false }); // Reset for next time
117
138
  }
118
139
  }, { fireImmediately: true });
140
+ set({ sortingUnsubscribe: unsubscribe });
119
141
  }
120
142
  })));
121
143
  export const selectResolvedSortingBalances = (state) => {
@@ -0,0 +1,178 @@
1
+ import { create } from 'zustand';
2
+ import { createJSONStorage, persist } from 'zustand/middleware';
3
+ import { resolverService } from '../lib/resolvers/resolverService';
4
+ const isContractAddress = async (address, network) => {
5
+ if (!network || !address) {
6
+ return false;
7
+ }
8
+ try {
9
+ const resolver = resolverService.getContractAddressResolver();
10
+ return await resolver.isContractAddress(network, address);
11
+ }
12
+ catch (error) {
13
+ console.log(error);
14
+ return false;
15
+ }
16
+ };
17
+ export const useContractAddressStore = create()(persist((set, get) => ({
18
+ contractStatuses: [],
19
+ confirmedAddresses: [],
20
+ isChecking: false,
21
+ pendingChecks: new Map(),
22
+ checkContractStatus: async (address, sourceNetwork, destinationNetwork) => {
23
+ if (!address || !sourceNetwork || !destinationNetwork) {
24
+ return { sourceIsContract: false, destinationIsContract: false, isContractInAnyNetwork: false };
25
+ }
26
+ const { hasStatus, isContractInNetwork, isContractInAnyNetwork } = get();
27
+ // Check if we already have cached results for both networks
28
+ const hasSourceStatus = hasStatus(address, sourceNetwork.name);
29
+ const hasDestStatus = hasStatus(address, destinationNetwork.name);
30
+ if (hasSourceStatus && hasDestStatus) {
31
+ return {
32
+ sourceIsContract: isContractInNetwork(address, sourceNetwork.name),
33
+ destinationIsContract: isContractInNetwork(address, destinationNetwork.name),
34
+ isContractInAnyNetwork: isContractInAnyNetwork(address)
35
+ };
36
+ }
37
+ const checkKey = `${address.toLowerCase()}-${sourceNetwork.name}-${destinationNetwork.name}`;
38
+ // If there's already a pending check for these params, return that promise
39
+ const pendingCheck = get().pendingChecks.get(checkKey);
40
+ if (pendingCheck) {
41
+ return pendingCheck;
42
+ }
43
+ set({ isChecking: true });
44
+ const checkPromise = (async () => {
45
+ try {
46
+ // Check source network only if not already cached
47
+ let sourceIsContract = false;
48
+ if (hasSourceStatus) {
49
+ sourceIsContract = isContractInNetwork(address, sourceNetwork.name);
50
+ }
51
+ else {
52
+ sourceIsContract = await isContractAddress(address, sourceNetwork);
53
+ set((state) => {
54
+ const existingIndex = state.contractStatuses.findIndex((cs) => cs.address.toLowerCase() === address.toLowerCase() &&
55
+ cs.network === sourceNetwork.name);
56
+ if (existingIndex >= 0) {
57
+ const updated = [...state.contractStatuses];
58
+ updated[existingIndex] = { address, network: sourceNetwork.name, isContract: sourceIsContract };
59
+ return { contractStatuses: updated };
60
+ }
61
+ return {
62
+ contractStatuses: [...state.contractStatuses, { address, network: sourceNetwork.name, isContract: sourceIsContract }]
63
+ };
64
+ });
65
+ }
66
+ // Check destination network only if not already cached
67
+ let destinationIsContract = false;
68
+ if (hasDestStatus) {
69
+ destinationIsContract = isContractInNetwork(address, destinationNetwork.name);
70
+ }
71
+ else {
72
+ destinationIsContract = await isContractAddress(address, destinationNetwork);
73
+ set((state) => {
74
+ const existingIndex = state.contractStatuses.findIndex((cs) => cs.address.toLowerCase() === address.toLowerCase() &&
75
+ cs.network === destinationNetwork.name);
76
+ if (existingIndex >= 0) {
77
+ const updated = [...state.contractStatuses];
78
+ updated[existingIndex] = { address, network: destinationNetwork.name, isContract: destinationIsContract };
79
+ return { contractStatuses: updated };
80
+ }
81
+ return {
82
+ contractStatuses: [...state.contractStatuses, { address, network: destinationNetwork.name, isContract: destinationIsContract }]
83
+ };
84
+ });
85
+ }
86
+ // Check if contract in any network after updates
87
+ const isInAnyNetwork = get().isContractInAnyNetwork(address);
88
+ return { sourceIsContract, destinationIsContract, isContractInAnyNetwork: isInAnyNetwork };
89
+ }
90
+ catch (error) {
91
+ console.error('Error checking contract status:', error);
92
+ return { sourceIsContract: false, destinationIsContract: false, isContractInAnyNetwork: false };
93
+ }
94
+ finally {
95
+ set((state) => {
96
+ const newPendingChecks = new Map(state.pendingChecks);
97
+ newPendingChecks.delete(checkKey);
98
+ return { pendingChecks: newPendingChecks, isChecking: false };
99
+ });
100
+ }
101
+ })();
102
+ set((state) => {
103
+ const newPendingChecks = new Map(state.pendingChecks);
104
+ newPendingChecks.set(checkKey, checkPromise);
105
+ return { pendingChecks: newPendingChecks };
106
+ });
107
+ return checkPromise;
108
+ },
109
+ hasStatus: (address, network) => {
110
+ return get().contractStatuses.some((cs) => cs.address.toLowerCase() === address.toLowerCase() &&
111
+ cs.network === network);
112
+ },
113
+ isContractInNetwork: (address, network) => {
114
+ const status = get().contractStatuses.find((cs) => cs.address.toLowerCase() === address.toLowerCase() &&
115
+ cs.network === network);
116
+ return status?.isContract ?? false;
117
+ },
118
+ isContractInAnyNetwork: (address) => {
119
+ return get().contractStatuses.some((cs) => cs.address.toLowerCase() === address.toLowerCase() &&
120
+ cs.isContract === true);
121
+ },
122
+ getContractNetworks: (address) => {
123
+ return get().contractStatuses
124
+ .filter((cs) => cs.address.toLowerCase() === address.toLowerCase() &&
125
+ cs.isContract === true)
126
+ .map((cs) => cs.network);
127
+ },
128
+ clearContractStatus: (address, network) => set((state) => {
129
+ if (network) {
130
+ return {
131
+ contractStatuses: state.contractStatuses.filter((cs) => !(cs.address.toLowerCase() === address.toLowerCase() &&
132
+ cs.network === network))
133
+ };
134
+ }
135
+ else {
136
+ return {
137
+ contractStatuses: state.contractStatuses.filter((cs) => cs.address.toLowerCase() !== address.toLowerCase())
138
+ };
139
+ }
140
+ }),
141
+ setConfirmed: (address, network) => set((state) => {
142
+ const exists = state.confirmedAddresses.some((ca) => ca.address.toLowerCase() === address.toLowerCase() &&
143
+ ca.network === network);
144
+ if (exists) {
145
+ return state;
146
+ }
147
+ return {
148
+ confirmedAddresses: [
149
+ ...state.confirmedAddresses,
150
+ { address, network }
151
+ ]
152
+ };
153
+ }),
154
+ isConfirmed: (address, network) => {
155
+ return get().confirmedAddresses.some((ca) => ca.address.toLowerCase() === address.toLowerCase() &&
156
+ ca.network === network);
157
+ },
158
+ clearConfirmed: (address, network) => set((state) => {
159
+ if (network) {
160
+ return {
161
+ confirmedAddresses: state.confirmedAddresses.filter((ca) => !(ca.address.toLowerCase() === address.toLowerCase() &&
162
+ ca.network === network))
163
+ };
164
+ }
165
+ else {
166
+ return {
167
+ confirmedAddresses: state.confirmedAddresses.filter((ca) => ca.address.toLowerCase() !== address.toLowerCase())
168
+ };
169
+ }
170
+ }),
171
+ }), {
172
+ name: 'contractAddress',
173
+ storage: createJSONStorage(() => localStorage),
174
+ partialize: (state) => ({
175
+ contractStatuses: state.contractStatuses,
176
+ confirmedAddresses: state.confirmedAddresses,
177
+ }),
178
+ }));
@@ -1,8 +1,9 @@
1
1
  import { ErrorHandler } from "../lib/ErrorHandler";
2
+ import { extractErrorDetails } from "../lib/balances/errorUtils";
3
+ import { classifyNodeError } from "../lib/balances/nodeErrorClassifier";
2
4
  export class BalanceProvider {
3
5
  constructor() {
4
6
  this.resolveTokenBalanceFetchError = (err, token, network, isNativeCurrency) => {
5
- const errorMessage = `${err.message || err}`;
6
7
  ErrorHandler({
7
8
  type: 'BalanceProviderError',
8
9
  message: err.message,
@@ -10,6 +11,8 @@ export class BalanceProvider {
10
11
  stack: err.stack,
11
12
  cause: err
12
13
  });
14
+ const errorDetails = extractErrorDetails(err);
15
+ const category = classifyNodeError(err);
13
16
  const tokenBalance = {
14
17
  network: network.name,
15
18
  token: token.symbol,
@@ -17,7 +20,17 @@ export class BalanceProvider {
17
20
  request_time: new Date().toJSON(),
18
21
  decimals: Number(token?.decimals),
19
22
  isNativeCurrency: isNativeCurrency ?? !token.contract,
20
- error: errorMessage
23
+ error: {
24
+ message: errorDetails.message,
25
+ name: errorDetails.name,
26
+ stack: errorDetails.stack,
27
+ code: errorDetails.code,
28
+ status: errorDetails.status,
29
+ statusText: errorDetails.statusText,
30
+ responseData: errorDetails.responseData,
31
+ requestUrl: errorDetails.requestUrl,
32
+ category: category
33
+ }
21
34
  };
22
35
  return tokenBalance;
23
36
  };
@@ -0,0 +1 @@
1
+ export {};
@@ -3,6 +3,7 @@ export * from './logEvents';
3
3
  export * from './balance';
4
4
  export * from './gas';
5
5
  export * from './addressUtils';
6
+ export * from './contract';
6
7
  export * from './transfer';
7
8
  export * from './nft';
8
9
  export * from './multiStepTransfer';