@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.
@@ -592,6 +592,23 @@ const Button = require$$0__namespace.forwardRef(
592
592
  }
593
593
  );
594
594
  Button.displayName = "Button";
595
+ const ModalContainerContext = require$$0.createContext(void 0);
596
+ const ModalContainerProvider = ({
597
+ containerId,
598
+ children
599
+ }) => {
600
+ return /* @__PURE__ */ jsxRuntime.jsx(ModalContainerContext.Provider, { value: containerId, children });
601
+ };
602
+ const useModalContainer = () => {
603
+ const containerId = require$$0.useContext(ModalContainerContext);
604
+ if (typeof document === "undefined") {
605
+ return null;
606
+ }
607
+ if (!containerId) {
608
+ return document.body;
609
+ }
610
+ return document.getElementById(containerId) || document.body;
611
+ };
595
612
  const ModalContent = ({ children, className }) => {
596
613
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("p-5 flex flex-col h-full", className), children });
597
614
  };
@@ -645,11 +662,11 @@ const Modal = ({
645
662
  isOpen,
646
663
  onClose,
647
664
  children,
648
- className,
649
- modalContainer
665
+ className
650
666
  }) => {
651
667
  const panelRef = require$$0.useRef(null);
652
668
  const lastActiveRef = require$$0.useRef(null);
669
+ const container = useModalContainer();
653
670
  require$$0.useEffect(() => {
654
671
  if (!isOpen) return;
655
672
  lastActiveRef.current = document.activeElement;
@@ -671,39 +688,41 @@ const Modal = ({
671
688
  return () => window.removeEventListener("keydown", onKey);
672
689
  }, [isOpen, onClose]);
673
690
  if (typeof document === "undefined") return null;
674
- const container = modalContainer || document.body;
675
691
  return reactDom.createPortal(
676
- /* @__PURE__ */ jsxRuntime.jsx(framerMotion.AnimatePresence, { children: isOpen && /* @__PURE__ */ jsxRuntime.jsx(
692
+ /* @__PURE__ */ jsxRuntime.jsx(framerMotion.AnimatePresence, { children: isOpen && /* @__PURE__ */ jsxRuntime.jsxs(
677
693
  framerMotion.motion.div,
678
694
  {
679
- 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",
695
+ 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",
680
696
  initial: { opacity: 0 },
681
697
  animate: { opacity: 1 },
682
698
  exit: { opacity: 0 },
683
- children: /* @__PURE__ */ jsxRuntime.jsx(
684
- framerMotion.motion.div,
685
- {
686
- ref: panelRef,
687
- role: "dialog",
688
- "aria-modal": "true",
689
- tabIndex: -1,
690
- className: cn(
691
- "outline-none overflow-auto w-screen h-screen rounded-none sm:w-full sm:h-full sm:rounded-3xl",
692
- className
693
- ),
694
- initial: { opacity: 0, scale: 0.9 },
695
- animate: { opacity: 1, scale: 1 },
696
- exit: { opacity: 0, scale: 0.9 },
697
- transition: {
698
- type: "spring",
699
- stiffness: 480,
700
- damping: 32,
701
- mass: 0.6
702
- },
703
- onMouseDown: (e) => e.stopPropagation(),
704
- children
705
- }
706
- )
699
+ children: [
700
+ /* @__PURE__ */ jsxRuntime.jsx(
701
+ framerMotion.motion.div,
702
+ {
703
+ ref: panelRef,
704
+ role: "dialog",
705
+ "aria-modal": "true",
706
+ tabIndex: -1,
707
+ className: cn(
708
+ "outline-none overflow-auto relative z-30 w-screen h-screen rounded-none sm:w-full sm:h-full sm:rounded-3xl",
709
+ className
710
+ ),
711
+ initial: { opacity: 0, scale: 0.9 },
712
+ animate: { opacity: 1, scale: 1 },
713
+ exit: { opacity: 0, scale: 0.9 },
714
+ transition: {
715
+ type: "spring",
716
+ stiffness: 480,
717
+ damping: 32,
718
+ mass: 0.6
719
+ },
720
+ onMouseDown: (e) => e.stopPropagation(),
721
+ children
722
+ }
723
+ ),
724
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "fixed inset-0 backdrop-blur-sm bg-background/10 z-10" })
725
+ ]
707
726
  }
708
727
  ) }),
709
728
  container
@@ -1091,8 +1110,7 @@ const routePresets = [
1091
1110
  ];
1092
1111
  const SettingModal = ({
1093
1112
  isOpen,
1094
- onClose,
1095
- modalContainer
1113
+ onClose
1096
1114
  }) => {
1097
1115
  const { t } = reactI18next.useTranslation();
1098
1116
  const { toChain } = useChainsStore();
@@ -1126,7 +1144,7 @@ const SettingModal = ({
1126
1144
  );
1127
1145
  const activeBtn = "bg-settings-active hover:bg-settings-active/80 text-settings-active-foreground";
1128
1146
  const notActiveBtn = "bg-settings-button hover:bg-settings-button/80 text-settings-button-foreground";
1129
- return /* @__PURE__ */ jsxRuntime.jsx(Modal, { isOpen, onClose, modalContainer, children: /* @__PURE__ */ jsxRuntime.jsxs(ModalContent, { children: [
1147
+ return /* @__PURE__ */ jsxRuntime.jsx(Modal, { isOpen, onClose, children: /* @__PURE__ */ jsxRuntime.jsxs(ModalContent, { children: [
1130
1148
  /* @__PURE__ */ jsxRuntime.jsxs(ModalHeader, { children: [
1131
1149
  /* @__PURE__ */ jsxRuntime.jsx(ModalTitle, { children: t("settings.title", { defaultValue: "Settings" }) }),
1132
1150
  /* @__PURE__ */ jsxRuntime.jsx(ModalClose, { className: "", onClick: onClose, children: /* @__PURE__ */ jsxRuntime.jsx(CloseIcon, { className: "size-6 p-0 [&>rect]:fill-modal-x [&>path]:stroke-modal-x-foreground" }) })
@@ -1457,7 +1475,7 @@ function sumFeeByTokenLD(fees, dstTokenAddr, dstChainKey) {
1457
1475
  }
1458
1476
  return acc.toString();
1459
1477
  }
1460
- function useBalances(chainKey, address) {
1478
+ function useBalances(chainKey, address, priorityTokenSymbol) {
1461
1479
  const { chainRegistry } = useChainStrategies();
1462
1480
  const { assetMatrix } = useTokensStore();
1463
1481
  const tokensOnChain = require$$0.useMemo(() => {
@@ -1469,13 +1487,24 @@ function useBalances(chainKey, address) {
1469
1487
  }
1470
1488
  return tokensList;
1471
1489
  }, [assetMatrix, chainKey]);
1490
+ const priorityToken = require$$0.useMemo(() => {
1491
+ if (!priorityTokenSymbol || !chainKey || !assetMatrix) return void 0;
1492
+ const normalizedSymbol = normalizeTickerSymbol$1(priorityTokenSymbol);
1493
+ const token = assetMatrix[normalizedSymbol]?.[chainKey];
1494
+ return token;
1495
+ }, [priorityTokenSymbol, chainKey, assetMatrix]);
1472
1496
  const query = reactQuery.useQuery({
1473
- queryKey: ["balances", chainKey, address],
1497
+ queryKey: ["balances", chainKey, address, priorityTokenSymbol],
1474
1498
  queryFn: async () => {
1475
1499
  if (!address || !chainKey)
1476
1500
  return {};
1477
1501
  if (!isAddressValidForChain(chainKey, address)) return {};
1478
- return await chainRegistry.getBalances(chainKey, address, tokensOnChain);
1502
+ return await chainRegistry.getBalances(
1503
+ chainKey,
1504
+ address,
1505
+ tokensOnChain,
1506
+ priorityToken
1507
+ );
1479
1508
  },
1480
1509
  enabled: !!address && !!chainKey && tokensOnChain.length > 0 && isAddressValidForChain(chainKey, address),
1481
1510
  staleTime: 6e4,
@@ -1729,8 +1758,7 @@ const TokenSelectModal = ({
1729
1758
  isOpen,
1730
1759
  onClose,
1731
1760
  items,
1732
- onChangeAsset,
1733
- modalContainer
1761
+ onChangeAsset
1734
1762
  }) => {
1735
1763
  const { t } = reactI18next.useTranslation();
1736
1764
  const {
@@ -1815,7 +1843,6 @@ const TokenSelectModal = ({
1815
1843
  {
1816
1844
  isOpen,
1817
1845
  onClose: handleClose,
1818
- modalContainer,
1819
1846
  children: /* @__PURE__ */ jsxRuntime.jsxs(ModalContent, { children: [
1820
1847
  /* @__PURE__ */ jsxRuntime.jsxs(ModalHeader, { children: [
1821
1848
  /* @__PURE__ */ jsxRuntime.jsx(ModalTitle, { children: t("bridge.selectToken") }),
@@ -2073,7 +2100,7 @@ function CardFooter({ className, ...props }) {
2073
2100
  }
2074
2101
  );
2075
2102
  }
2076
- const FormHeaderComponent = ({ modalContainer }) => {
2103
+ const FormHeaderComponent = () => {
2077
2104
  const { t } = reactI18next.useTranslation();
2078
2105
  const { isOpen, onClose, onOpen } = useModal();
2079
2106
  const {
@@ -2089,7 +2116,7 @@ const FormHeaderComponent = ({ modalContainer }) => {
2089
2116
  const sum = selectedAssetSymbol.toUpperCase();
2090
2117
  return assets.find((a) => a.symbol.toUpperCase() === sum) ?? assets[0];
2091
2118
  }, [assets, selectedAssetSymbol]);
2092
- return /* @__PURE__ */ jsxRuntime.jsxs(CardHeader, { className: "gap-y-0", children: [
2119
+ return /* @__PURE__ */ jsxRuntime.jsxs(CardHeader, { className: "gap-y-0 flex justify-between items-center", children: [
2093
2120
  /* @__PURE__ */ jsxRuntime.jsxs(CardTitle, { className: "flex items-center gap-2.5", children: [
2094
2121
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-normal leading-3.5 text-muted-foreground", children: t("bridge.selectToken") }),
2095
2122
  /* @__PURE__ */ jsxRuntime.jsx(SelectTokenButton, { token: current, onClick: onOpen })
@@ -2107,24 +2134,19 @@ const FormHeaderComponent = ({ modalContainer }) => {
2107
2134
  onChangeAsset: (symbol) => {
2108
2135
  setSelectedAssetSymbol(symbol);
2109
2136
  onClose();
2110
- },
2111
- modalContainer
2137
+ }
2112
2138
  }
2113
2139
  ),
2114
2140
  /* @__PURE__ */ jsxRuntime.jsx(
2115
2141
  SettingModal,
2116
2142
  {
2117
2143
  isOpen: isOpenSettings,
2118
- onClose: onCloseSettings,
2119
- modalContainer
2144
+ onClose: onCloseSettings
2120
2145
  }
2121
2146
  )
2122
2147
  ] });
2123
2148
  };
2124
- const FormHeader = require$$0.memo(
2125
- FormHeaderComponent,
2126
- (prev, next) => prev.modalContainer === next.modalContainer
2127
- );
2149
+ const FormHeader = require$$0.memo(FormHeaderComponent);
2128
2150
  async function fetchQuotes(req) {
2129
2151
  const params = {
2130
2152
  srcChainKey: req.srcChainKey,
@@ -2447,8 +2469,16 @@ function useSwapModel() {
2447
2469
  const tokensStore = useTokensStore();
2448
2470
  const { srcAddress, dstAddress } = useAddresses();
2449
2471
  const { allowedFromChains, allowedToChains, isLoadingToChains } = useChainDerivations();
2450
- const srcBalances = useBalances(chainsStore.fromChain?.chainKey, srcAddress);
2451
- const dstBalances = useBalances(chainsStore.toChain?.chainKey, dstAddress);
2472
+ const srcBalances = useBalances(
2473
+ chainsStore.fromChain?.chainKey,
2474
+ srcAddress,
2475
+ tokensStore.selectedAssetSymbol
2476
+ );
2477
+ const dstBalances = useBalances(
2478
+ chainsStore.toChain?.chainKey,
2479
+ dstAddress,
2480
+ tokensStore.selectedAssetSymbol
2481
+ );
2452
2482
  const { loading } = useBridgeQuote();
2453
2483
  const { inputAmount, setInputAmount, resetWithIdle } = useBridgeQuoteStore();
2454
2484
  const fromBalance = require$$0.useMemo(
@@ -2531,10 +2561,10 @@ const SwapButton = () => {
2531
2561
  {
2532
2562
  onClick: handleSwap,
2533
2563
  disabled: !canSwap || isSwapping,
2564
+ variant: "secondary",
2565
+ size: "sm",
2534
2566
  className: cn(
2535
- "has-[>svg]:p-0 h-9 bg-swap rounded-full p-2 max-w-9 w-full",
2536
2567
  "absolute top-1/2 -translate-y-1/2 left-1/2 -translate-x-1/2",
2537
- "hover:bg-swap transition-all duration-200 shadow-none select-none",
2538
2568
  !canSwap || isSwapping ? "opacity-50 cursor-not-allowed" : "hover:scale-110"
2539
2569
  ),
2540
2570
  children: /* @__PURE__ */ jsxRuntime.jsx(
@@ -2543,8 +2573,7 @@ const SwapButton = () => {
2543
2573
  style: {
2544
2574
  transform: `rotate(${turns * 180}deg)`,
2545
2575
  transition: "transform 300ms linear"
2546
- },
2547
- className: "size-5 text-swap-foreground will-change-transform"
2576
+ }
2548
2577
  }
2549
2578
  )
2550
2579
  }
@@ -2575,7 +2604,6 @@ const NetworkSymbol = ({
2575
2604
  };
2576
2605
  const SelectNetworkButton = ({
2577
2606
  onClick,
2578
- className,
2579
2607
  network
2580
2608
  }) => {
2581
2609
  const { t } = reactI18next.useTranslation();
@@ -2586,7 +2614,8 @@ const SelectNetworkButton = ({
2586
2614
  Button,
2587
2615
  {
2588
2616
  onClick,
2589
- 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 ?? ""}`,
2617
+ size: "sm",
2618
+ variant: "secondary",
2590
2619
  type: "button",
2591
2620
  "aria-label": label,
2592
2621
  children: [
@@ -2672,8 +2701,7 @@ const ChainSelectModal = ({
2672
2701
  onClose,
2673
2702
  items,
2674
2703
  allowedItems,
2675
- onChangeChain,
2676
- modalContainer
2704
+ onChangeChain
2677
2705
  }) => {
2678
2706
  const { t } = reactI18next.useTranslation();
2679
2707
  const [query, setQuery] = require$$0.useState("");
@@ -2762,7 +2790,6 @@ const ChainSelectModal = ({
2762
2790
  {
2763
2791
  isOpen,
2764
2792
  onClose: handleClose,
2765
- modalContainer,
2766
2793
  children: /* @__PURE__ */ jsxRuntime.jsxs(ModalContent, { children: [
2767
2794
  /* @__PURE__ */ jsxRuntime.jsxs(ModalHeader, { children: [
2768
2795
  /* @__PURE__ */ jsxRuntime.jsx(ModalTitle, { children: t("bridge.selectNetwork") }),
@@ -2900,8 +2927,7 @@ const SwapSection = ({
2900
2927
  disableNetworkSelect,
2901
2928
  isSource,
2902
2929
  onSelect,
2903
- onAmountChange,
2904
- modalContainer
2930
+ onAmountChange
2905
2931
  }) => {
2906
2932
  const { isOpen, onClose, onOpen } = useModal();
2907
2933
  const { assetMatrix, selectedAssetSymbol } = useTokensStore();
@@ -2934,9 +2960,9 @@ const SwapSection = ({
2934
2960
  "div",
2935
2961
  {
2936
2962
  className: cn(
2937
- "p-4 flex flex-col gap-4 transition-colors bg-muted",
2963
+ "p-4 flex flex-col gap-4 transition-colors bg-input",
2938
2964
  {
2939
- "bg-muted-focus": isSource && isFocused
2965
+ "bg-input-focus": isSource && isFocused
2940
2966
  },
2941
2967
  className
2942
2968
  ),
@@ -2956,8 +2982,7 @@ const SwapSection = ({
2956
2982
  SelectNetworkButton,
2957
2983
  {
2958
2984
  network: chain,
2959
- onClick: disableNetworkSelect ? void 0 : onOpen,
2960
- className: disableNetworkSelect ? "opacity-80 cursor-not-allowed" : ""
2985
+ onClick: disableNetworkSelect ? void 0 : onOpen
2961
2986
  }
2962
2987
  ),
2963
2988
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -2996,8 +3021,7 @@ const SwapSection = ({
2996
3021
  onClose,
2997
3022
  items: chains,
2998
3023
  allowedItems: allowedChains,
2999
- onChangeChain,
3000
- modalContainer
3024
+ onChangeChain
3001
3025
  }
3002
3026
  )
3003
3027
  ] });
@@ -4083,9 +4107,7 @@ const SubmitButton = () => {
4083
4107
  function short(addr) {
4084
4108
  return addr.slice(0, 4) + "…" + addr.slice(-4);
4085
4109
  }
4086
- const WalletSelectModal = ({
4087
- modalContainer
4088
- }) => {
4110
+ const WalletSelectModal = () => {
4089
4111
  const { t } = reactI18next.useTranslation();
4090
4112
  const { isOpen, onClose } = useWalletSelectModal();
4091
4113
  const { connect, connectors, isPending } = wagmi.useConnect();
@@ -4185,7 +4207,7 @@ const WalletSelectModal = ({
4185
4207
  console.error("Failed to connect wallet:", error);
4186
4208
  }
4187
4209
  };
4188
- return /* @__PURE__ */ jsxRuntime.jsx(Modal, { isOpen, onClose, modalContainer, children: /* @__PURE__ */ jsxRuntime.jsxs(ModalContent, { children: [
4210
+ return /* @__PURE__ */ jsxRuntime.jsx(Modal, { isOpen, onClose, children: /* @__PURE__ */ jsxRuntime.jsxs(ModalContent, { children: [
4189
4211
  /* @__PURE__ */ jsxRuntime.jsxs(ModalHeader, { children: [
4190
4212
  /* @__PURE__ */ jsxRuntime.jsx(ModalTitle, { children: t("wallets.chooseWallet", { defaultValue: "Choose wallet" }) }),
4191
4213
  /* @__PURE__ */ jsxRuntime.jsx(ModalDescription, { children: t("wallets.oneWalletPerEnv", {
@@ -6178,7 +6200,7 @@ const ConfirmStep = () => {
6178
6200
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-3xl font-black relative z-10", children: formatTime })
6179
6201
  ] }) });
6180
6202
  };
6181
- const TransactionManager = ({ modalContainer }) => {
6203
+ const TransactionManager = () => {
6182
6204
  const { current } = useTransactionStore();
6183
6205
  const status = current?.status;
6184
6206
  if (!status || status === "idle") return null;
@@ -6196,7 +6218,7 @@ const TransactionManager = ({ modalContainer }) => {
6196
6218
  step = /* @__PURE__ */ jsxRuntime.jsx(SuccessStep, {});
6197
6219
  }
6198
6220
  return /* @__PURE__ */ jsxRuntime.jsx(Modal, { isOpen: true, onClose: () => {
6199
- }, modalContainer, children: step });
6221
+ }, children: step });
6200
6222
  };
6201
6223
  const useTokensRequest = () => {
6202
6224
  const { setTokens, setSelectedToken, setSelectedAssetSymbol } = useTokensStore();
@@ -6287,10 +6309,10 @@ class ChainStrategyRegistry {
6287
6309
  const strategy = this.getStrategy(chainKey);
6288
6310
  return strategy?.isConnected() || false;
6289
6311
  }
6290
- async getBalances(chainKey, address, tokens) {
6312
+ async getBalances(chainKey, address, tokens, priorityToken) {
6291
6313
  const strategy = this.getStrategy(chainKey);
6292
6314
  if (!strategy) return {};
6293
- return await strategy.getBalances(address, tokens);
6315
+ return await strategy.getBalances(address, tokens, priorityToken);
6294
6316
  }
6295
6317
  isAddressValid(chainKey, address) {
6296
6318
  const strategy = this.getStrategy(chainKey);
@@ -6401,13 +6423,14 @@ function parseTonAddress(address) {
6401
6423
  }
6402
6424
  return ton.Address.parse(address);
6403
6425
  }
6404
- async function getEvmBalances(publicClient, address, tokens) {
6426
+ async function getEvmBalances(publicClient, address, tokens, priorityToken) {
6405
6427
  const balances = {};
6406
6428
  try {
6407
6429
  console.log("start getEvmBalances");
6408
6430
  console.log("publicClient:", publicClient);
6409
6431
  console.log("isAddress:", viem.isAddress(address));
6410
6432
  console.log("tokens:", tokens);
6433
+ console.log("priorityToken:", priorityToken);
6411
6434
  if (!address || !viem.isAddress(address)) {
6412
6435
  console.warn(`Invalid EVM address provided: ${address}`);
6413
6436
  return balances;
@@ -6415,25 +6438,93 @@ async function getEvmBalances(publicClient, address, tokens) {
6415
6438
  if (!publicClient) {
6416
6439
  throw new Error("No public client provided");
6417
6440
  }
6418
- for (const token of tokens) {
6441
+ const nativeTokens = tokens.filter((t) => isNativeAddress(t.address));
6442
+ const erc20Tokens = tokens.filter((t) => !isNativeAddress(t.address) && viem.isAddress(t.address));
6443
+ if (priorityToken) {
6419
6444
  try {
6420
- let balance = 0;
6421
- const isNative = isNativeAddress(token.address);
6422
- if (isNative) {
6445
+ const isPriorityNative = isNativeAddress(priorityToken.address);
6446
+ if (isPriorityNative) {
6423
6447
  const ethBalance = await publicClient.getBalance({
6424
6448
  address
6425
6449
  });
6426
- balance = parseFloat(viem.formatUnits(ethBalance, token.decimals));
6427
- } else {
6428
- if (!viem.isAddress(token.address)) {
6429
- continue;
6450
+ const balance = parseFloat(viem.formatUnits(ethBalance, priorityToken.decimals));
6451
+ if (balance > 0) {
6452
+ balances[priorityToken.symbol] = { balance, address };
6430
6453
  }
6431
- const bytecode = await publicClient.getBytecode({
6432
- address: token.address
6454
+ } else if (viem.isAddress(priorityToken.address)) {
6455
+ const tokenBalance = await publicClient.readContract({
6456
+ address: priorityToken.address,
6457
+ abi: [
6458
+ {
6459
+ name: "balanceOf",
6460
+ type: "function",
6461
+ stateMutability: "view",
6462
+ inputs: [{ name: "owner", type: "address" }],
6463
+ outputs: [{ name: "balance", type: "uint256" }]
6464
+ }
6465
+ ],
6466
+ functionName: "balanceOf",
6467
+ args: [address]
6433
6468
  });
6434
- if (!bytecode || bytecode === "0x") {
6435
- continue;
6469
+ const balance = parseFloat(viem.formatUnits(tokenBalance, priorityToken.decimals));
6470
+ if (balance > 0) {
6471
+ balances[priorityToken.symbol] = { balance, address };
6436
6472
  }
6473
+ }
6474
+ } catch (error) {
6475
+ console.debug(`Failed to get priority token balance for ${priorityToken.symbol}:`, error);
6476
+ }
6477
+ }
6478
+ for (const token of nativeTokens) {
6479
+ try {
6480
+ const ethBalance = await publicClient.getBalance({
6481
+ address
6482
+ });
6483
+ const balance = parseFloat(viem.formatUnits(ethBalance, token.decimals));
6484
+ if (balance > 0) {
6485
+ balances[token.symbol] = { balance, address };
6486
+ }
6487
+ } catch (error) {
6488
+ console.debug(`Failed to get native balance for ${token.symbol}:`, error);
6489
+ }
6490
+ }
6491
+ if (erc20Tokens.length > 0) {
6492
+ try {
6493
+ const multicallContracts = erc20Tokens.map((token) => ({
6494
+ address: token.address,
6495
+ abi: [
6496
+ {
6497
+ name: "balanceOf",
6498
+ type: "function",
6499
+ stateMutability: "view",
6500
+ inputs: [{ name: "owner", type: "address" }],
6501
+ outputs: [{ name: "balance", type: "uint256" }]
6502
+ }
6503
+ ],
6504
+ functionName: "balanceOf",
6505
+ args: [address]
6506
+ }));
6507
+ const results = await publicClient.multicall({
6508
+ contracts: multicallContracts,
6509
+ allowFailure: true
6510
+ });
6511
+ results.forEach((result, index) => {
6512
+ const token = erc20Tokens[index];
6513
+ if (!token) return;
6514
+ if (result.status === "success" && result.result !== void 0) {
6515
+ try {
6516
+ const balance = parseFloat(viem.formatUnits(result.result, token.decimals));
6517
+ if (balance > 0) {
6518
+ balances[token.symbol] = { balance, address };
6519
+ }
6520
+ } catch (error) {
6521
+ console.debug(`Failed to parse balance for ${token.symbol}:`, error);
6522
+ }
6523
+ }
6524
+ });
6525
+ } catch (error) {
6526
+ console.warn("Multicall failed, falling back to individual calls:", error);
6527
+ for (const token of erc20Tokens) {
6437
6528
  try {
6438
6529
  const tokenBalance = await publicClient.readContract({
6439
6530
  address: token.address,
@@ -6449,23 +6540,16 @@ async function getEvmBalances(publicClient, address, tokens) {
6449
6540
  functionName: "balanceOf",
6450
6541
  args: [address]
6451
6542
  });
6452
- balance = parseFloat(
6543
+ const balance = parseFloat(
6453
6544
  viem.formatUnits(tokenBalance, token.decimals)
6454
6545
  );
6455
- } catch {
6456
- continue;
6546
+ if (balance > 0) {
6547
+ balances[token.symbol] = { balance, address };
6548
+ }
6549
+ } catch (error2) {
6550
+ console.debug(`Failed to get balance for ${token.symbol}:`, error2);
6457
6551
  }
6458
6552
  }
6459
- if (balance > 0) {
6460
- balances[token.symbol] = { balance, address };
6461
- }
6462
- } catch (error) {
6463
- if (error instanceof Error && !error.message.includes("could not decode")) {
6464
- console.warn(
6465
- `Network error fetching balance for ${token.symbol}:`,
6466
- error
6467
- );
6468
- }
6469
6553
  }
6470
6554
  }
6471
6555
  } catch (error) {
@@ -6527,7 +6611,11 @@ async function getTonBalances(address, tokens, customTonClient, tonApiKey) {
6527
6611
  }
6528
6612
  }
6529
6613
  } catch (error) {
6530
- console.debug(`Failed to get balance for ${token.symbol}:`, error);
6614
+ const errorMessage = error instanceof Error ? error.message : String(error);
6615
+ const isNoWalletError = errorMessage.includes("exit_code: -13") || errorMessage.includes("exit_code:-13") || errorMessage.includes("exitCode: -13");
6616
+ if (!isNoWalletError) {
6617
+ console.debug(`Failed to get balance for ${token.symbol}:`, error);
6618
+ }
6531
6619
  }
6532
6620
  }
6533
6621
  } catch (error) {
@@ -6628,12 +6716,12 @@ class EvmChainStrategy {
6628
6716
  getConnectLabel(t) {
6629
6717
  return t("wallets.connectEvmWallet");
6630
6718
  }
6631
- async getBalances(address, tokens) {
6719
+ async getBalances(address, tokens, priorityToken) {
6632
6720
  if (!this.publicClient) {
6633
6721
  console.warn("No publicClient available for balance query");
6634
6722
  return {};
6635
6723
  }
6636
- return await getEvmBalances(this.publicClient, address, tokens);
6724
+ return await getEvmBalances(this.publicClient, address, tokens, priorityToken);
6637
6725
  }
6638
6726
  isAddressValid(address) {
6639
6727
  if (!address) return false;
@@ -7899,7 +7987,7 @@ const EvaaBridgeWithProviders = (props) => {
7899
7987
  require$$0.useEffect(() => {
7900
7988
  setTronConnected(!!tronConnected);
7901
7989
  }, [tronConnected, setTronConnected]);
7902
- return /* @__PURE__ */ jsxRuntime.jsx(
7990
+ return /* @__PURE__ */ jsxRuntime.jsx(ModalContainerProvider, { containerId: props.modalContainerId, children: /* @__PURE__ */ jsxRuntime.jsx(
7903
7991
  ChainStrategyProvider,
7904
7992
  {
7905
7993
  evmWallet: {
@@ -7924,7 +8012,7 @@ const EvaaBridgeWithProviders = (props) => {
7924
8012
  tonApiKey: props.tonApiKey,
7925
8013
  children: /* @__PURE__ */ jsxRuntime.jsx(EvaaBridgeContent, { ...props })
7926
8014
  }
7927
- );
8015
+ ) });
7928
8016
  };
7929
8017
  const EvaaBridgeContent = ({
7930
8018
  className,
@@ -7933,7 +8021,6 @@ const EvaaBridgeContent = ({
7933
8021
  onChainChange
7934
8022
  } = {}) => {
7935
8023
  const { t } = reactI18next.useTranslation();
7936
- const modalContainerRef = require$$0.useRef(null);
7937
8024
  useTokensRequest();
7938
8025
  useChainsRequest();
7939
8026
  const [sendToAnother, setSendToAnother] = require$$0.useState(false);
@@ -8032,9 +8119,8 @@ const EvaaBridgeContent = ({
8032
8119
  "max-w-md w-full mx-auto flex flex-col relative",
8033
8120
  className
8034
8121
  ),
8035
- ref: modalContainerRef,
8036
8122
  children: [
8037
- /* @__PURE__ */ jsxRuntime.jsx(FormHeader, { modalContainer: modalContainerRef.current }),
8123
+ /* @__PURE__ */ jsxRuntime.jsx(FormHeader, {}),
8038
8124
  /* @__PURE__ */ jsxRuntime.jsxs(CardContent, { className: "space-y-[1px]", children: [
8039
8125
  /* @__PURE__ */ jsxRuntime.jsx(
8040
8126
  SwapSection,
@@ -8048,8 +8134,7 @@ const EvaaBridgeContent = ({
8048
8134
  amount,
8049
8135
  isSource: true,
8050
8136
  onAmountChange: handleAmountChange,
8051
- onSelect: handleFromChainChange,
8052
- modalContainer: modalContainerRef.current || void 0
8137
+ onSelect: handleFromChainChange
8053
8138
  }
8054
8139
  ),
8055
8140
  /* @__PURE__ */ jsxRuntime.jsx(SwapButton, {}),
@@ -8063,8 +8148,7 @@ const EvaaBridgeContent = ({
8063
8148
  allowedChains: allowedToChains,
8064
8149
  amount: outputAmount,
8065
8150
  readOnlyAmount: true,
8066
- onSelect: handleToChainChange,
8067
- modalContainer: modalContainerRef.current || void 0
8151
+ onSelect: handleToChainChange
8068
8152
  }
8069
8153
  ),
8070
8154
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -8080,8 +8164,8 @@ const EvaaBridgeContent = ({
8080
8164
  ]
8081
8165
  }
8082
8166
  ),
8083
- /* @__PURE__ */ jsxRuntime.jsx(WalletSelectModal, { modalContainer: modalContainerRef.current }),
8084
- /* @__PURE__ */ jsxRuntime.jsx(TransactionManager, { modalContainer: modalContainerRef.current }),
8167
+ /* @__PURE__ */ jsxRuntime.jsx(WalletSelectModal, {}),
8168
+ /* @__PURE__ */ jsxRuntime.jsx(TransactionManager, {}),
8085
8169
  /* @__PURE__ */ jsxRuntime.jsx(sonner.Toaster, { position: "top-right", richColors: true })
8086
8170
  ] });
8087
8171
  };