@rash2x/bridge-widget 0.1.5 → 0.1.7

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.
@@ -4,7 +4,7 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
4
4
  import { jsx, jsxs, Fragment } from "react/jsx-runtime";
5
5
  import { useTranslation } from "react-i18next";
6
6
  import * as require$$0 from "react";
7
- import require$$0__default, { useState, useCallback, useRef, useEffect, useMemo, createContext, useContext, memo, forwardRef } from "react";
7
+ import require$$0__default, { useState, useCallback, createContext, useContext, useRef, useEffect, useMemo, memo, forwardRef } from "react";
8
8
  import { create as create$1 } from "zustand";
9
9
  import { Slot } from "@radix-ui/react-slot";
10
10
  import { cva } from "class-variance-authority";
@@ -550,6 +550,23 @@ const Button = require$$0.forwardRef(
550
550
  }
551
551
  );
552
552
  Button.displayName = "Button";
553
+ const ModalContainerContext = createContext(void 0);
554
+ const ModalContainerProvider = ({
555
+ containerId,
556
+ children
557
+ }) => {
558
+ return /* @__PURE__ */ jsx(ModalContainerContext.Provider, { value: containerId, children });
559
+ };
560
+ const useModalContainer = () => {
561
+ const containerId = useContext(ModalContainerContext);
562
+ if (typeof document === "undefined") {
563
+ return null;
564
+ }
565
+ if (!containerId) {
566
+ return document.body;
567
+ }
568
+ return document.getElementById(containerId) || document.body;
569
+ };
553
570
  const ModalContent = ({ children, className }) => {
554
571
  return /* @__PURE__ */ jsx("div", { className: cn("p-5 flex flex-col h-full", className), children });
555
572
  };
@@ -603,11 +620,11 @@ const Modal = ({
603
620
  isOpen,
604
621
  onClose,
605
622
  children,
606
- className,
607
- modalContainer
623
+ className
608
624
  }) => {
609
625
  const panelRef = useRef(null);
610
626
  const lastActiveRef = useRef(null);
627
+ const container = useModalContainer();
611
628
  useEffect(() => {
612
629
  if (!isOpen) return;
613
630
  lastActiveRef.current = document.activeElement;
@@ -629,39 +646,41 @@ const Modal = ({
629
646
  return () => window.removeEventListener("keydown", onKey);
630
647
  }, [isOpen, onClose]);
631
648
  if (typeof document === "undefined") return null;
632
- const container = modalContainer || document.body;
633
649
  return createPortal(
634
- /* @__PURE__ */ jsx(AnimatePresence, { children: isOpen && /* @__PURE__ */ jsx(
650
+ /* @__PURE__ */ jsx(AnimatePresence, { children: isOpen && /* @__PURE__ */ jsxs(
635
651
  motion.div,
636
652
  {
637
- className: "fixed inset-0 border border-border z-[100] bg-dialog sm:absolute sm:inset-0 sm:top-0 sm:bottom-0 sm:w-full sm:rounded-3xl",
653
+ className: "fixed m-auto border border-border max-w-md max-h-[80%] z-[100] bg-dialog sm:absolute sm:inset-0 sm:top-0 sm:bottom-0 sm:w-full rounded-xl",
638
654
  initial: { opacity: 0 },
639
655
  animate: { opacity: 1 },
640
656
  exit: { opacity: 0 },
641
- children: /* @__PURE__ */ jsx(
642
- motion.div,
643
- {
644
- ref: panelRef,
645
- role: "dialog",
646
- "aria-modal": "true",
647
- tabIndex: -1,
648
- className: cn(
649
- "outline-none overflow-auto w-screen h-screen rounded-none sm:w-full sm:h-full sm:rounded-3xl",
650
- className
651
- ),
652
- initial: { opacity: 0, scale: 0.9 },
653
- animate: { opacity: 1, scale: 1 },
654
- exit: { opacity: 0, scale: 0.9 },
655
- transition: {
656
- type: "spring",
657
- stiffness: 480,
658
- damping: 32,
659
- mass: 0.6
660
- },
661
- onMouseDown: (e) => e.stopPropagation(),
662
- children
663
- }
664
- )
657
+ children: [
658
+ /* @__PURE__ */ jsx(
659
+ motion.div,
660
+ {
661
+ ref: panelRef,
662
+ role: "dialog",
663
+ "aria-modal": "true",
664
+ tabIndex: -1,
665
+ className: cn(
666
+ "outline-none overflow-auto relative z-30 w-screen h-screen rounded-none sm:w-full sm:h-full sm:rounded-3xl",
667
+ className
668
+ ),
669
+ initial: { opacity: 0, scale: 0.9 },
670
+ animate: { opacity: 1, scale: 1 },
671
+ exit: { opacity: 0, scale: 0.9 },
672
+ transition: {
673
+ type: "spring",
674
+ stiffness: 480,
675
+ damping: 32,
676
+ mass: 0.6
677
+ },
678
+ onMouseDown: (e) => e.stopPropagation(),
679
+ children
680
+ }
681
+ ),
682
+ /* @__PURE__ */ jsx("div", { className: "fixed inset-0 backdrop-blur-sm bg-background/10 z-10" })
683
+ ]
665
684
  }
666
685
  ) }),
667
686
  container
@@ -1049,8 +1068,7 @@ const routePresets = [
1049
1068
  ];
1050
1069
  const SettingModal = ({
1051
1070
  isOpen,
1052
- onClose,
1053
- modalContainer
1071
+ onClose
1054
1072
  }) => {
1055
1073
  const { t: t2 } = useTranslation();
1056
1074
  const { toChain } = useChainsStore();
@@ -1084,7 +1102,7 @@ const SettingModal = ({
1084
1102
  );
1085
1103
  const activeBtn = "bg-settings-active hover:bg-settings-active/80 text-settings-active-foreground";
1086
1104
  const notActiveBtn = "bg-settings-button hover:bg-settings-button/80 text-settings-button-foreground";
1087
- return /* @__PURE__ */ jsx(Modal, { isOpen, onClose, modalContainer, children: /* @__PURE__ */ jsxs(ModalContent, { children: [
1105
+ return /* @__PURE__ */ jsx(Modal, { isOpen, onClose, children: /* @__PURE__ */ jsxs(ModalContent, { children: [
1088
1106
  /* @__PURE__ */ jsxs(ModalHeader, { children: [
1089
1107
  /* @__PURE__ */ jsx(ModalTitle, { children: t2("settings.title", { defaultValue: "Settings" }) }),
1090
1108
  /* @__PURE__ */ jsx(ModalClose, { className: "", onClick: onClose, children: /* @__PURE__ */ jsx(CloseIcon, { className: "size-6 p-0 [&>rect]:fill-modal-x [&>path]:stroke-modal-x-foreground" }) })
@@ -1415,7 +1433,7 @@ function sumFeeByTokenLD(fees, dstTokenAddr, dstChainKey) {
1415
1433
  }
1416
1434
  return acc.toString();
1417
1435
  }
1418
- function useBalances(chainKey, address) {
1436
+ function useBalances(chainKey, address, priorityTokenSymbol) {
1419
1437
  const { chainRegistry } = useChainStrategies();
1420
1438
  const { assetMatrix } = useTokensStore();
1421
1439
  const tokensOnChain = useMemo(() => {
@@ -1427,13 +1445,24 @@ function useBalances(chainKey, address) {
1427
1445
  }
1428
1446
  return tokensList;
1429
1447
  }, [assetMatrix, chainKey]);
1448
+ const priorityToken = useMemo(() => {
1449
+ if (!priorityTokenSymbol || !chainKey || !assetMatrix) return void 0;
1450
+ const normalizedSymbol = normalizeTickerSymbol$1(priorityTokenSymbol);
1451
+ const token = assetMatrix[normalizedSymbol]?.[chainKey];
1452
+ return token;
1453
+ }, [priorityTokenSymbol, chainKey, assetMatrix]);
1430
1454
  const query = useQuery({
1431
- queryKey: ["balances", chainKey, address],
1455
+ queryKey: ["balances", chainKey, address, priorityTokenSymbol],
1432
1456
  queryFn: async () => {
1433
1457
  if (!address || !chainKey)
1434
1458
  return {};
1435
1459
  if (!isAddressValidForChain(chainKey, address)) return {};
1436
- return await chainRegistry.getBalances(chainKey, address, tokensOnChain);
1460
+ return await chainRegistry.getBalances(
1461
+ chainKey,
1462
+ address,
1463
+ tokensOnChain,
1464
+ priorityToken
1465
+ );
1437
1466
  },
1438
1467
  enabled: !!address && !!chainKey && tokensOnChain.length > 0 && isAddressValidForChain(chainKey, address),
1439
1468
  staleTime: 6e4,
@@ -1687,8 +1716,7 @@ const TokenSelectModal = ({
1687
1716
  isOpen,
1688
1717
  onClose,
1689
1718
  items,
1690
- onChangeAsset,
1691
- modalContainer
1719
+ onChangeAsset
1692
1720
  }) => {
1693
1721
  const { t: t2 } = useTranslation();
1694
1722
  const {
@@ -1773,7 +1801,6 @@ const TokenSelectModal = ({
1773
1801
  {
1774
1802
  isOpen,
1775
1803
  onClose: handleClose,
1776
- modalContainer,
1777
1804
  children: /* @__PURE__ */ jsxs(ModalContent, { children: [
1778
1805
  /* @__PURE__ */ jsxs(ModalHeader, { children: [
1779
1806
  /* @__PURE__ */ jsx(ModalTitle, { children: t2("bridge.selectToken") }),
@@ -2031,7 +2058,7 @@ function CardFooter({ className, ...props }) {
2031
2058
  }
2032
2059
  );
2033
2060
  }
2034
- const FormHeaderComponent = ({ modalContainer }) => {
2061
+ const FormHeaderComponent = () => {
2035
2062
  const { t: t2 } = useTranslation();
2036
2063
  const { isOpen, onClose, onOpen } = useModal();
2037
2064
  const {
@@ -2047,7 +2074,7 @@ const FormHeaderComponent = ({ modalContainer }) => {
2047
2074
  const sum = selectedAssetSymbol.toUpperCase();
2048
2075
  return assets.find((a) => a.symbol.toUpperCase() === sum) ?? assets[0];
2049
2076
  }, [assets, selectedAssetSymbol]);
2050
- return /* @__PURE__ */ jsxs(CardHeader, { className: "gap-y-0", children: [
2077
+ return /* @__PURE__ */ jsxs(CardHeader, { className: "gap-y-0 flex justify-between items-center", children: [
2051
2078
  /* @__PURE__ */ jsxs(CardTitle, { className: "flex items-center gap-2.5", children: [
2052
2079
  /* @__PURE__ */ jsx("span", { className: "text-sm font-normal leading-3.5 text-muted-foreground", children: t2("bridge.selectToken") }),
2053
2080
  /* @__PURE__ */ jsx(SelectTokenButton, { token: current, onClick: onOpen })
@@ -2065,24 +2092,19 @@ const FormHeaderComponent = ({ modalContainer }) => {
2065
2092
  onChangeAsset: (symbol) => {
2066
2093
  setSelectedAssetSymbol(symbol);
2067
2094
  onClose();
2068
- },
2069
- modalContainer
2095
+ }
2070
2096
  }
2071
2097
  ),
2072
2098
  /* @__PURE__ */ jsx(
2073
2099
  SettingModal,
2074
2100
  {
2075
2101
  isOpen: isOpenSettings,
2076
- onClose: onCloseSettings,
2077
- modalContainer
2102
+ onClose: onCloseSettings
2078
2103
  }
2079
2104
  )
2080
2105
  ] });
2081
2106
  };
2082
- const FormHeader = memo(
2083
- FormHeaderComponent,
2084
- (prev, next) => prev.modalContainer === next.modalContainer
2085
- );
2107
+ const FormHeader = memo(FormHeaderComponent);
2086
2108
  async function fetchQuotes(req) {
2087
2109
  const params = {
2088
2110
  srcChainKey: req.srcChainKey,
@@ -2405,8 +2427,16 @@ function useSwapModel() {
2405
2427
  const tokensStore = useTokensStore();
2406
2428
  const { srcAddress, dstAddress } = useAddresses();
2407
2429
  const { allowedFromChains, allowedToChains, isLoadingToChains } = useChainDerivations();
2408
- const srcBalances = useBalances(chainsStore.fromChain?.chainKey, srcAddress);
2409
- const dstBalances = useBalances(chainsStore.toChain?.chainKey, dstAddress);
2430
+ const srcBalances = useBalances(
2431
+ chainsStore.fromChain?.chainKey,
2432
+ srcAddress,
2433
+ tokensStore.selectedAssetSymbol
2434
+ );
2435
+ const dstBalances = useBalances(
2436
+ chainsStore.toChain?.chainKey,
2437
+ dstAddress,
2438
+ tokensStore.selectedAssetSymbol
2439
+ );
2410
2440
  const { loading } = useBridgeQuote();
2411
2441
  const { inputAmount, setInputAmount, resetWithIdle } = useBridgeQuoteStore();
2412
2442
  const fromBalance = useMemo(
@@ -2489,10 +2519,10 @@ const SwapButton = () => {
2489
2519
  {
2490
2520
  onClick: handleSwap,
2491
2521
  disabled: !canSwap || isSwapping,
2522
+ variant: "secondary",
2523
+ size: "sm",
2492
2524
  className: cn(
2493
- "has-[>svg]:p-0 h-9 bg-swap rounded-full p-2 max-w-9 w-full",
2494
2525
  "absolute top-1/2 -translate-y-1/2 left-1/2 -translate-x-1/2",
2495
- "hover:bg-swap transition-all duration-200 shadow-none select-none",
2496
2526
  !canSwap || isSwapping ? "opacity-50 cursor-not-allowed" : "hover:scale-110"
2497
2527
  ),
2498
2528
  children: /* @__PURE__ */ jsx(
@@ -2501,8 +2531,7 @@ const SwapButton = () => {
2501
2531
  style: {
2502
2532
  transform: `rotate(${turns * 180}deg)`,
2503
2533
  transition: "transform 300ms linear"
2504
- },
2505
- className: "size-5 text-swap-foreground will-change-transform"
2534
+ }
2506
2535
  }
2507
2536
  )
2508
2537
  }
@@ -2533,7 +2562,6 @@ const NetworkSymbol = ({
2533
2562
  };
2534
2563
  const SelectNetworkButton = ({
2535
2564
  onClick,
2536
- className,
2537
2565
  network
2538
2566
  }) => {
2539
2567
  const { t: t2 } = useTranslation();
@@ -2544,7 +2572,8 @@ const SelectNetworkButton = ({
2544
2572
  Button,
2545
2573
  {
2546
2574
  onClick,
2547
- className: `cursor-pointer hover:scale-[1.1] p-1.5 h-8.5 pr-3 !pl-1.5 bg-secondary hover:bg-secondary shadow-none rounded-full flex items-center justify-between gap-3 w-fit shrink-0 ${className ?? ""}`,
2575
+ size: "sm",
2576
+ variant: "secondary",
2548
2577
  type: "button",
2549
2578
  "aria-label": label,
2550
2579
  children: [
@@ -2630,8 +2659,7 @@ const ChainSelectModal = ({
2630
2659
  onClose,
2631
2660
  items,
2632
2661
  allowedItems,
2633
- onChangeChain,
2634
- modalContainer
2662
+ onChangeChain
2635
2663
  }) => {
2636
2664
  const { t: t2 } = useTranslation();
2637
2665
  const [query, setQuery] = useState("");
@@ -2720,7 +2748,6 @@ const ChainSelectModal = ({
2720
2748
  {
2721
2749
  isOpen,
2722
2750
  onClose: handleClose,
2723
- modalContainer,
2724
2751
  children: /* @__PURE__ */ jsxs(ModalContent, { children: [
2725
2752
  /* @__PURE__ */ jsxs(ModalHeader, { children: [
2726
2753
  /* @__PURE__ */ jsx(ModalTitle, { children: t2("bridge.selectNetwork") }),
@@ -2858,8 +2885,7 @@ const SwapSection = ({
2858
2885
  disableNetworkSelect,
2859
2886
  isSource,
2860
2887
  onSelect,
2861
- onAmountChange,
2862
- modalContainer
2888
+ onAmountChange
2863
2889
  }) => {
2864
2890
  const { isOpen, onClose, onOpen } = useModal();
2865
2891
  const { assetMatrix, selectedAssetSymbol } = useTokensStore();
@@ -2892,9 +2918,9 @@ const SwapSection = ({
2892
2918
  "div",
2893
2919
  {
2894
2920
  className: cn(
2895
- "p-4 flex flex-col gap-4 transition-colors bg-muted",
2921
+ "p-4 flex flex-col gap-4 transition-colors bg-input",
2896
2922
  {
2897
- "bg-muted-focus": isSource && isFocused
2923
+ "bg-input-focus": isSource && isFocused
2898
2924
  },
2899
2925
  className
2900
2926
  ),
@@ -2914,8 +2940,7 @@ const SwapSection = ({
2914
2940
  SelectNetworkButton,
2915
2941
  {
2916
2942
  network: chain,
2917
- onClick: disableNetworkSelect ? void 0 : onOpen,
2918
- className: disableNetworkSelect ? "opacity-80 cursor-not-allowed" : ""
2943
+ onClick: disableNetworkSelect ? void 0 : onOpen
2919
2944
  }
2920
2945
  ),
2921
2946
  /* @__PURE__ */ jsx(
@@ -2954,8 +2979,7 @@ const SwapSection = ({
2954
2979
  onClose,
2955
2980
  items: chains,
2956
2981
  allowedItems: allowedChains,
2957
- onChangeChain,
2958
- modalContainer
2982
+ onChangeChain
2959
2983
  }
2960
2984
  )
2961
2985
  ] });
@@ -4041,9 +4065,7 @@ const SubmitButton = () => {
4041
4065
  function short(addr) {
4042
4066
  return addr.slice(0, 4) + "…" + addr.slice(-4);
4043
4067
  }
4044
- const WalletSelectModal = ({
4045
- modalContainer
4046
- }) => {
4068
+ const WalletSelectModal = () => {
4047
4069
  const { t: t2 } = useTranslation();
4048
4070
  const { isOpen, onClose } = useWalletSelectModal();
4049
4071
  const { connect, connectors, isPending } = useConnect();
@@ -4143,7 +4165,7 @@ const WalletSelectModal = ({
4143
4165
  console.error("Failed to connect wallet:", error);
4144
4166
  }
4145
4167
  };
4146
- return /* @__PURE__ */ jsx(Modal, { isOpen, onClose, modalContainer, children: /* @__PURE__ */ jsxs(ModalContent, { children: [
4168
+ return /* @__PURE__ */ jsx(Modal, { isOpen, onClose, children: /* @__PURE__ */ jsxs(ModalContent, { children: [
4147
4169
  /* @__PURE__ */ jsxs(ModalHeader, { children: [
4148
4170
  /* @__PURE__ */ jsx(ModalTitle, { children: t2("wallets.chooseWallet", { defaultValue: "Choose wallet" }) }),
4149
4171
  /* @__PURE__ */ jsx(ModalDescription, { children: t2("wallets.oneWalletPerEnv", {
@@ -6136,7 +6158,7 @@ const ConfirmStep = () => {
6136
6158
  /* @__PURE__ */ jsx("div", { className: "text-3xl font-black relative z-10", children: formatTime })
6137
6159
  ] }) });
6138
6160
  };
6139
- const TransactionManager = ({ modalContainer }) => {
6161
+ const TransactionManager = () => {
6140
6162
  const { current } = useTransactionStore();
6141
6163
  const status = current?.status;
6142
6164
  if (!status || status === "idle") return null;
@@ -6154,7 +6176,7 @@ const TransactionManager = ({ modalContainer }) => {
6154
6176
  step = /* @__PURE__ */ jsx(SuccessStep, {});
6155
6177
  }
6156
6178
  return /* @__PURE__ */ jsx(Modal, { isOpen: true, onClose: () => {
6157
- }, modalContainer, children: step });
6179
+ }, children: step });
6158
6180
  };
6159
6181
  const useTokensRequest = () => {
6160
6182
  const { setTokens, setSelectedToken, setSelectedAssetSymbol } = useTokensStore();
@@ -6245,10 +6267,10 @@ class ChainStrategyRegistry {
6245
6267
  const strategy = this.getStrategy(chainKey);
6246
6268
  return strategy?.isConnected() || false;
6247
6269
  }
6248
- async getBalances(chainKey, address, tokens) {
6270
+ async getBalances(chainKey, address, tokens, priorityToken) {
6249
6271
  const strategy = this.getStrategy(chainKey);
6250
6272
  if (!strategy) return {};
6251
- return await strategy.getBalances(address, tokens);
6273
+ return await strategy.getBalances(address, tokens, priorityToken);
6252
6274
  }
6253
6275
  isAddressValid(chainKey, address) {
6254
6276
  const strategy = this.getStrategy(chainKey);
@@ -6359,13 +6381,14 @@ function parseTonAddress(address) {
6359
6381
  }
6360
6382
  return Address$1.parse(address);
6361
6383
  }
6362
- async function getEvmBalances(publicClient, address, tokens) {
6384
+ async function getEvmBalances(publicClient, address, tokens, priorityToken) {
6363
6385
  const balances = {};
6364
6386
  try {
6365
6387
  console.log("start getEvmBalances");
6366
6388
  console.log("publicClient:", publicClient);
6367
6389
  console.log("isAddress:", isAddress(address));
6368
6390
  console.log("tokens:", tokens);
6391
+ console.log("priorityToken:", priorityToken);
6369
6392
  if (!address || !isAddress(address)) {
6370
6393
  console.warn(`Invalid EVM address provided: ${address}`);
6371
6394
  return balances;
@@ -6373,25 +6396,93 @@ async function getEvmBalances(publicClient, address, tokens) {
6373
6396
  if (!publicClient) {
6374
6397
  throw new Error("No public client provided");
6375
6398
  }
6376
- for (const token of tokens) {
6399
+ const nativeTokens = tokens.filter((t2) => isNativeAddress(t2.address));
6400
+ const erc20Tokens = tokens.filter((t2) => !isNativeAddress(t2.address) && isAddress(t2.address));
6401
+ if (priorityToken) {
6377
6402
  try {
6378
- let balance = 0;
6379
- const isNative = isNativeAddress(token.address);
6380
- if (isNative) {
6403
+ const isPriorityNative = isNativeAddress(priorityToken.address);
6404
+ if (isPriorityNative) {
6381
6405
  const ethBalance = await publicClient.getBalance({
6382
6406
  address
6383
6407
  });
6384
- balance = parseFloat(formatUnits(ethBalance, token.decimals));
6385
- } else {
6386
- if (!isAddress(token.address)) {
6387
- continue;
6408
+ const balance = parseFloat(formatUnits(ethBalance, priorityToken.decimals));
6409
+ if (balance > 0) {
6410
+ balances[priorityToken.symbol] = { balance, address };
6388
6411
  }
6389
- const bytecode = await publicClient.getBytecode({
6390
- address: token.address
6412
+ } else if (isAddress(priorityToken.address)) {
6413
+ const tokenBalance = await publicClient.readContract({
6414
+ address: priorityToken.address,
6415
+ abi: [
6416
+ {
6417
+ name: "balanceOf",
6418
+ type: "function",
6419
+ stateMutability: "view",
6420
+ inputs: [{ name: "owner", type: "address" }],
6421
+ outputs: [{ name: "balance", type: "uint256" }]
6422
+ }
6423
+ ],
6424
+ functionName: "balanceOf",
6425
+ args: [address]
6391
6426
  });
6392
- if (!bytecode || bytecode === "0x") {
6393
- continue;
6427
+ const balance = parseFloat(formatUnits(tokenBalance, priorityToken.decimals));
6428
+ if (balance > 0) {
6429
+ balances[priorityToken.symbol] = { balance, address };
6394
6430
  }
6431
+ }
6432
+ } catch (error) {
6433
+ console.debug(`Failed to get priority token balance for ${priorityToken.symbol}:`, error);
6434
+ }
6435
+ }
6436
+ for (const token of nativeTokens) {
6437
+ try {
6438
+ const ethBalance = await publicClient.getBalance({
6439
+ address
6440
+ });
6441
+ const balance = parseFloat(formatUnits(ethBalance, token.decimals));
6442
+ if (balance > 0) {
6443
+ balances[token.symbol] = { balance, address };
6444
+ }
6445
+ } catch (error) {
6446
+ console.debug(`Failed to get native balance for ${token.symbol}:`, error);
6447
+ }
6448
+ }
6449
+ if (erc20Tokens.length > 0) {
6450
+ try {
6451
+ const multicallContracts = erc20Tokens.map((token) => ({
6452
+ address: token.address,
6453
+ abi: [
6454
+ {
6455
+ name: "balanceOf",
6456
+ type: "function",
6457
+ stateMutability: "view",
6458
+ inputs: [{ name: "owner", type: "address" }],
6459
+ outputs: [{ name: "balance", type: "uint256" }]
6460
+ }
6461
+ ],
6462
+ functionName: "balanceOf",
6463
+ args: [address]
6464
+ }));
6465
+ const results = await publicClient.multicall({
6466
+ contracts: multicallContracts,
6467
+ allowFailure: true
6468
+ });
6469
+ results.forEach((result, index) => {
6470
+ const token = erc20Tokens[index];
6471
+ if (!token) return;
6472
+ if (result.status === "success" && result.result !== void 0) {
6473
+ try {
6474
+ const balance = parseFloat(formatUnits(result.result, token.decimals));
6475
+ if (balance > 0) {
6476
+ balances[token.symbol] = { balance, address };
6477
+ }
6478
+ } catch (error) {
6479
+ console.debug(`Failed to parse balance for ${token.symbol}:`, error);
6480
+ }
6481
+ }
6482
+ });
6483
+ } catch (error) {
6484
+ console.warn("Multicall failed, falling back to individual calls:", error);
6485
+ for (const token of erc20Tokens) {
6395
6486
  try {
6396
6487
  const tokenBalance = await publicClient.readContract({
6397
6488
  address: token.address,
@@ -6407,23 +6498,16 @@ async function getEvmBalances(publicClient, address, tokens) {
6407
6498
  functionName: "balanceOf",
6408
6499
  args: [address]
6409
6500
  });
6410
- balance = parseFloat(
6501
+ const balance = parseFloat(
6411
6502
  formatUnits(tokenBalance, token.decimals)
6412
6503
  );
6413
- } catch {
6414
- continue;
6504
+ if (balance > 0) {
6505
+ balances[token.symbol] = { balance, address };
6506
+ }
6507
+ } catch (error2) {
6508
+ console.debug(`Failed to get balance for ${token.symbol}:`, error2);
6415
6509
  }
6416
6510
  }
6417
- if (balance > 0) {
6418
- balances[token.symbol] = { balance, address };
6419
- }
6420
- } catch (error) {
6421
- if (error instanceof Error && !error.message.includes("could not decode")) {
6422
- console.warn(
6423
- `Network error fetching balance for ${token.symbol}:`,
6424
- error
6425
- );
6426
- }
6427
6511
  }
6428
6512
  }
6429
6513
  } catch (error) {
@@ -6485,7 +6569,11 @@ async function getTonBalances(address, tokens, customTonClient, tonApiKey) {
6485
6569
  }
6486
6570
  }
6487
6571
  } catch (error) {
6488
- console.debug(`Failed to get balance for ${token.symbol}:`, error);
6572
+ const errorMessage = error instanceof Error ? error.message : String(error);
6573
+ const isNoWalletError = errorMessage.includes("exit_code: -13") || errorMessage.includes("exit_code:-13") || errorMessage.includes("exitCode: -13");
6574
+ if (!isNoWalletError) {
6575
+ console.debug(`Failed to get balance for ${token.symbol}:`, error);
6576
+ }
6489
6577
  }
6490
6578
  }
6491
6579
  } catch (error) {
@@ -6586,12 +6674,12 @@ class EvmChainStrategy {
6586
6674
  getConnectLabel(t2) {
6587
6675
  return t2("wallets.connectEvmWallet");
6588
6676
  }
6589
- async getBalances(address, tokens) {
6677
+ async getBalances(address, tokens, priorityToken) {
6590
6678
  if (!this.publicClient) {
6591
6679
  console.warn("No publicClient available for balance query");
6592
6680
  return {};
6593
6681
  }
6594
- return await getEvmBalances(this.publicClient, address, tokens);
6682
+ return await getEvmBalances(this.publicClient, address, tokens, priorityToken);
6595
6683
  }
6596
6684
  isAddressValid(address) {
6597
6685
  if (!address) return false;
@@ -7857,7 +7945,7 @@ const EvaaBridgeWithProviders = (props) => {
7857
7945
  useEffect(() => {
7858
7946
  setTronConnected(!!tronConnected);
7859
7947
  }, [tronConnected, setTronConnected]);
7860
- return /* @__PURE__ */ jsx(
7948
+ return /* @__PURE__ */ jsx(ModalContainerProvider, { containerId: props.modalContainerId, children: /* @__PURE__ */ jsx(
7861
7949
  ChainStrategyProvider,
7862
7950
  {
7863
7951
  evmWallet: {
@@ -7882,7 +7970,7 @@ const EvaaBridgeWithProviders = (props) => {
7882
7970
  tonApiKey: props.tonApiKey,
7883
7971
  children: /* @__PURE__ */ jsx(EvaaBridgeContent, { ...props })
7884
7972
  }
7885
- );
7973
+ ) });
7886
7974
  };
7887
7975
  const EvaaBridgeContent = ({
7888
7976
  className,
@@ -7891,7 +7979,6 @@ const EvaaBridgeContent = ({
7891
7979
  onChainChange
7892
7980
  } = {}) => {
7893
7981
  const { t: t2 } = useTranslation();
7894
- const modalContainerRef = useRef(null);
7895
7982
  useTokensRequest();
7896
7983
  useChainsRequest();
7897
7984
  const [sendToAnother, setSendToAnother] = useState(false);
@@ -7990,9 +8077,8 @@ const EvaaBridgeContent = ({
7990
8077
  "max-w-md w-full mx-auto flex flex-col relative",
7991
8078
  className
7992
8079
  ),
7993
- ref: modalContainerRef,
7994
8080
  children: [
7995
- /* @__PURE__ */ jsx(FormHeader, { modalContainer: modalContainerRef.current }),
8081
+ /* @__PURE__ */ jsx(FormHeader, {}),
7996
8082
  /* @__PURE__ */ jsxs(CardContent, { className: "space-y-[1px]", children: [
7997
8083
  /* @__PURE__ */ jsx(
7998
8084
  SwapSection,
@@ -8006,8 +8092,7 @@ const EvaaBridgeContent = ({
8006
8092
  amount,
8007
8093
  isSource: true,
8008
8094
  onAmountChange: handleAmountChange,
8009
- onSelect: handleFromChainChange,
8010
- modalContainer: modalContainerRef.current || void 0
8095
+ onSelect: handleFromChainChange
8011
8096
  }
8012
8097
  ),
8013
8098
  /* @__PURE__ */ jsx(SwapButton, {}),
@@ -8021,8 +8106,7 @@ const EvaaBridgeContent = ({
8021
8106
  allowedChains: allowedToChains,
8022
8107
  amount: outputAmount,
8023
8108
  readOnlyAmount: true,
8024
- onSelect: handleToChainChange,
8025
- modalContainer: modalContainerRef.current || void 0
8109
+ onSelect: handleToChainChange
8026
8110
  }
8027
8111
  ),
8028
8112
  /* @__PURE__ */ jsx(
@@ -8038,8 +8122,8 @@ const EvaaBridgeContent = ({
8038
8122
  ]
8039
8123
  }
8040
8124
  ),
8041
- /* @__PURE__ */ jsx(WalletSelectModal, { modalContainer: modalContainerRef.current }),
8042
- /* @__PURE__ */ jsx(TransactionManager, { modalContainer: modalContainerRef.current }),
8125
+ /* @__PURE__ */ jsx(WalletSelectModal, {}),
8126
+ /* @__PURE__ */ jsx(TransactionManager, {}),
8043
8127
  /* @__PURE__ */ jsx(Toaster, { position: "top-right", richColors: true })
8044
8128
  ] });
8045
8129
  };