@rash2x/bridge-widget 0.1.4 → 0.1.6

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";
@@ -13,19 +13,20 @@ import { twMerge } from "tailwind-merge";
13
13
  import { createPortal } from "react-dom";
14
14
  import { AnimatePresence, motion } from "framer-motion";
15
15
  import * as TooltipPrimitive from "@radix-ui/react-tooltip";
16
- import { useAccount, useDisconnect, useWalletClient } from "wagmi";
16
+ import { useAccount, useConnect, useDisconnect, useWalletClient, usePublicClient } from "wagmi";
17
17
  import { useWallet } from "@tronweb3/tronwallet-adapter-react-hooks";
18
18
  import { useTonAddress, useTonConnectUI } from "@tonconnect/ui-react";
19
19
  import { useQuery, useQueryClient } from "@tanstack/react-query";
20
- import { Address, Cell } from "@ton/core";
20
+ import { Address, beginCell as beginCell$1, storeMessage, loadMessage, Cell } from "@ton/core";
21
21
  import { VariableSizeList } from "react-window";
22
22
  import * as SwitchPrimitive from "@radix-ui/react-switch";
23
23
  import { X, ChevronDownIcon } from "lucide-react";
24
24
  import * as AccordionPrimitive from "@radix-ui/react-accordion";
25
- import { ConnectKitButton } from "connectkit";
26
25
  import { t } from "i18next";
27
26
  import { toast, Toaster } from "sonner";
28
- import { ethers, BrowserProvider, Contract, parseUnits } from "ethers";
27
+ import { BrowserProvider, Contract, parseUnits } from "ethers";
28
+ import { isAddress, formatUnits } from "viem";
29
+ import { TonClient, Address as Address$1, beginCell } from "@ton/ton";
29
30
  import { TronLinkAdapterName } from "@tronweb3/tronwallet-adapters";
30
31
  const norm = (s) => (s ?? "").toUpperCase().replace(/₮/g, "T").replace(/[^A-Z0-9]/g, "");
31
32
  const POPULAR_ORDER = [
@@ -509,7 +510,7 @@ function cn(...inputs) {
509
510
  return twMerge(clsx(inputs));
510
511
  }
511
512
  const buttonVariants = cva(
512
- "inline-flex items-center rounded-full justify-center gap-2 whitespace-nowrap text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
513
+ "inline-flex items-center rounded-full text-lg justify-center gap-2 whitespace-nowrap text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
513
514
  {
514
515
  variants: {
515
516
  variant: {
@@ -549,6 +550,23 @@ const Button = require$$0.forwardRef(
549
550
  }
550
551
  );
551
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
+ };
552
570
  const ModalContent = ({ children, className }) => {
553
571
  return /* @__PURE__ */ jsx("div", { className: cn("p-5 flex flex-col h-full", className), children });
554
572
  };
@@ -602,11 +620,11 @@ const Modal = ({
602
620
  isOpen,
603
621
  onClose,
604
622
  children,
605
- className,
606
- modalContainer
623
+ className
607
624
  }) => {
608
625
  const panelRef = useRef(null);
609
626
  const lastActiveRef = useRef(null);
627
+ const container = useModalContainer();
610
628
  useEffect(() => {
611
629
  if (!isOpen) return;
612
630
  lastActiveRef.current = document.activeElement;
@@ -628,7 +646,6 @@ const Modal = ({
628
646
  return () => window.removeEventListener("keydown", onKey);
629
647
  }, [isOpen, onClose]);
630
648
  if (typeof document === "undefined") return null;
631
- const container = modalContainer || document.body;
632
649
  return createPortal(
633
650
  /* @__PURE__ */ jsx(AnimatePresence, { children: isOpen && /* @__PURE__ */ jsx(
634
651
  motion.div,
@@ -782,19 +799,6 @@ const Tip = (props) => {
782
799
  /* @__PURE__ */ jsx(TooltipContent, { children: /* @__PURE__ */ jsx("p", { children: text }) })
783
800
  ] });
784
801
  };
785
- function toLD(human, decimals) {
786
- const [i = "0", f = ""] = human.replace(",", ".").split(".");
787
- const frac = (f + "0".repeat(decimals)).slice(0, decimals);
788
- return BigInt(i + frac).toString();
789
- }
790
- function fromLD(ld, decimals) {
791
- const bi = BigInt(ld || "0");
792
- if (decimals === 0) return Number(bi);
793
- const base = BigInt(10) ** BigInt(decimals);
794
- const int = bi / base;
795
- const frac = Number(bi % base) / Number(base);
796
- return Number(int) + frac;
797
- }
798
802
  async function getChains() {
799
803
  const res = await fetch("https://stargate.finance/api/v1/chains", {
800
804
  credentials: "same-origin"
@@ -842,49 +846,16 @@ async function getDestTokens(srcChainKey, srcTokenAddr) {
842
846
  });
843
847
  return unique;
844
848
  }
845
- const isTonFriendly = (a) => !!a && /^[A-Za-z0-9_-]{48,}$/.test(a);
846
- function normalizeTickerSymbol(s) {
849
+ function normalizeTickerSymbol$1(s) {
847
850
  return s.toUpperCase().replace(/₮/g, "T").replace(/[^A-Z0-9]/g, "");
848
851
  }
849
- async function getSwapBalances(accountFriendly) {
850
- if (!isTonFriendly(accountFriendly)) throw new Error("Invalid TON address");
851
- const accRes = await fetch(
852
- `https://tonapi.io/v2/accounts/${accountFriendly}`
853
- );
854
- if (!accRes.ok) throw new Error(`TON account fetch failed: ${accRes.status}`);
855
- const acc = await accRes.json();
856
- const ton = fromLD(String(acc?.balance ?? "0"), 9);
857
- const result = {
858
- TON: { balance: ton, address: "ton-native" }
859
- };
860
- const jetsRes = await fetch(
861
- `https://tonapi.io/v2/accounts/${accountFriendly}/jettons?limit=200`
862
- );
863
- if (!jetsRes.ok) return result;
864
- const jets = await jetsRes.json();
865
- const items = jets?.balances ?? jets?.jettons ?? jets?.items ?? [];
866
- for (const it of items) {
867
- const rawSym = (it?.jetton?.symbol ?? it?.symbol ?? "").toString();
868
- if (!rawSym) continue;
869
- const symUpper = rawSym.toUpperCase();
870
- const symNorm = normalizeTickerSymbol(symUpper);
871
- const master = (it?.jetton?.address ?? it?.address ?? "").toString();
872
- const decimals = Number(it?.jetton?.decimals ?? it?.decimals ?? 9) || 9;
873
- const raw = (it?.balance ?? "0").toString();
874
- const human = fromLD(raw, decimals);
875
- const entry = { balance: human, address: master };
876
- result[symUpper] = entry;
877
- if (symNorm !== symUpper) result[symNorm] = entry;
878
- }
879
- return result;
880
- }
881
852
  const BASE_URL$1 = "https://icons-ckg.pages.dev/stargate-light/tokens";
882
853
  const TokenSymbol = ({
883
854
  symbol,
884
855
  className = "w-4 h-4",
885
856
  alt
886
857
  }) => {
887
- const normalizedSymbol = normalizeTickerSymbol(symbol).toLowerCase();
858
+ const normalizedSymbol = normalizeTickerSymbol$1(symbol).toLowerCase();
888
859
  const src = `${BASE_URL$1}/${normalizedSymbol}.svg`;
889
860
  return /* @__PURE__ */ jsx("img", { src, alt: alt ?? symbol, className });
890
861
  };
@@ -1094,8 +1065,7 @@ const routePresets = [
1094
1065
  ];
1095
1066
  const SettingModal = ({
1096
1067
  isOpen,
1097
- onClose,
1098
- modalContainer
1068
+ onClose
1099
1069
  }) => {
1100
1070
  const { t: t2 } = useTranslation();
1101
1071
  const { toChain } = useChainsStore();
@@ -1129,7 +1099,7 @@ const SettingModal = ({
1129
1099
  );
1130
1100
  const activeBtn = "bg-settings-active hover:bg-settings-active/80 text-settings-active-foreground";
1131
1101
  const notActiveBtn = "bg-settings-button hover:bg-settings-button/80 text-settings-button-foreground";
1132
- return /* @__PURE__ */ jsx(Modal, { isOpen, onClose, modalContainer, children: /* @__PURE__ */ jsxs(ModalContent, { children: [
1102
+ return /* @__PURE__ */ jsx(Modal, { isOpen, onClose, children: /* @__PURE__ */ jsxs(ModalContent, { children: [
1133
1103
  /* @__PURE__ */ jsxs(ModalHeader, { children: [
1134
1104
  /* @__PURE__ */ jsx(ModalTitle, { children: t2("settings.title", { defaultValue: "Settings" }) }),
1135
1105
  /* @__PURE__ */ jsx(ModalClose, { className: "", onClick: onClose, children: /* @__PURE__ */ jsx(CloseIcon, { className: "size-6 p-0 [&>rect]:fill-modal-x [&>path]:stroke-modal-x-foreground" }) })
@@ -1298,6 +1268,19 @@ function useChainStrategies() {
1298
1268
  }
1299
1269
  return context;
1300
1270
  }
1271
+ function toLD(human, decimals) {
1272
+ const [i = "0", f = ""] = human.replace(",", ".").split(".");
1273
+ const frac = (f + "0".repeat(decimals)).slice(0, decimals);
1274
+ return BigInt(i + frac).toString();
1275
+ }
1276
+ function fromLD(ld, decimals) {
1277
+ const bi = BigInt(ld || "0");
1278
+ if (decimals === 0) return Number(bi);
1279
+ const base = BigInt(10) ** BigInt(decimals);
1280
+ const int = bi / base;
1281
+ const frac = Number(bi % base) / Number(base);
1282
+ return Number(int) + frac;
1283
+ }
1301
1284
  function resolveTokenOnChainFromMatrix$2(assetMatrix, assetSymbol, chainKey) {
1302
1285
  if (!assetMatrix || !assetSymbol || !chainKey) return void 0;
1303
1286
  const byChain = assetMatrix[assetSymbol.toUpperCase()];
@@ -1479,20 +1462,17 @@ function useBalances(chainKey, address) {
1479
1462
  const data = query.data;
1480
1463
  if (data) {
1481
1464
  for (const [sum, v] of Object.entries(data)) {
1482
- map.set(normalizeTickerSymbol(sum), Number(v.balance ?? 0));
1465
+ map.set(normalizeTickerSymbol$1(sum), Number(v.balance ?? 0));
1483
1466
  }
1484
1467
  }
1485
1468
  return map;
1486
1469
  }, [query.data]);
1487
1470
  const getBalance = useCallback(
1488
- (symbol) => balanceBySymbol.get(normalizeTickerSymbol(symbol)) ?? 0,
1471
+ (symbol) => balanceBySymbol.get(normalizeTickerSymbol$1(symbol)) ?? 0,
1489
1472
  [balanceBySymbol]
1490
1473
  );
1491
1474
  const isLoading = query.isLoading || query.isFetching;
1492
- const balances = useMemo(
1493
- () => query.data || {},
1494
- [query.data]
1495
- );
1475
+ const balances = useMemo(() => query.data || {}, [query.data]);
1496
1476
  return {
1497
1477
  balances,
1498
1478
  getBalance,
@@ -1722,8 +1702,7 @@ const TokenSelectModal = ({
1722
1702
  isOpen,
1723
1703
  onClose,
1724
1704
  items,
1725
- onChangeAsset,
1726
- modalContainer
1705
+ onChangeAsset
1727
1706
  }) => {
1728
1707
  const { t: t2 } = useTranslation();
1729
1708
  const {
@@ -1808,7 +1787,6 @@ const TokenSelectModal = ({
1808
1787
  {
1809
1788
  isOpen,
1810
1789
  onClose: handleClose,
1811
- modalContainer,
1812
1790
  children: /* @__PURE__ */ jsxs(ModalContent, { children: [
1813
1791
  /* @__PURE__ */ jsxs(ModalHeader, { children: [
1814
1792
  /* @__PURE__ */ jsx(ModalTitle, { children: t2("bridge.selectToken") }),
@@ -1948,17 +1926,17 @@ const RefreshButton = () => {
1948
1926
  return /* @__PURE__ */ jsx(
1949
1927
  Button,
1950
1928
  {
1951
- className: `cursor-pointer py-1.5 h-8.5 hover:scale-110 shadow-none px-8.5 hover:bg-secondary bg-secondary !rounded-40 ${spinning ? "opacity-70" : ""}`,
1952
1929
  onClick: handleRefresh,
1953
1930
  disabled: spinning,
1931
+ variant: "secondary",
1932
+ size: "sm",
1954
1933
  children: /* @__PURE__ */ jsx(
1955
1934
  ReloadIcon,
1956
1935
  {
1957
1936
  style: {
1958
1937
  transform: `rotate(${turns * 180}deg)`,
1959
1938
  transition: "transform 300ms linear"
1960
- },
1961
- className: "size-4 text-foreground m-1 will-change-transform"
1939
+ }
1962
1940
  }
1963
1941
  )
1964
1942
  }
@@ -1966,7 +1944,6 @@ const RefreshButton = () => {
1966
1944
  };
1967
1945
  const SelectTokenButton = ({
1968
1946
  onClick,
1969
- className,
1970
1947
  token
1971
1948
  }) => {
1972
1949
  const { t: t2 } = useTranslation();
@@ -1977,7 +1954,8 @@ const SelectTokenButton = ({
1977
1954
  Button,
1978
1955
  {
1979
1956
  onClick,
1980
- 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 ?? ""}`,
1957
+ size: "sm",
1958
+ variant: "secondary",
1981
1959
  type: "button",
1982
1960
  "aria-label": label,
1983
1961
  children: [
@@ -1997,7 +1975,76 @@ const SelectTokenButton = ({
1997
1975
  }
1998
1976
  );
1999
1977
  };
2000
- const FormHeaderComponent = ({ modalContainer }) => {
1978
+ function Card({ className, ...props }) {
1979
+ return /* @__PURE__ */ jsx(
1980
+ "div",
1981
+ {
1982
+ "data-slot": "card",
1983
+ className: cn(
1984
+ "bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm",
1985
+ className
1986
+ ),
1987
+ ...props
1988
+ }
1989
+ );
1990
+ }
1991
+ function CardHeader({ className, ...props }) {
1992
+ return /* @__PURE__ */ jsx(
1993
+ "div",
1994
+ {
1995
+ "data-slot": "card-header",
1996
+ className: cn(
1997
+ "@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-2 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6",
1998
+ className
1999
+ ),
2000
+ ...props
2001
+ }
2002
+ );
2003
+ }
2004
+ function CardTitle({ className, ...props }) {
2005
+ return /* @__PURE__ */ jsx(
2006
+ "div",
2007
+ {
2008
+ "data-slot": "card-title",
2009
+ className: cn("leading-none font-semibold", className),
2010
+ ...props
2011
+ }
2012
+ );
2013
+ }
2014
+ function CardAction({ className, ...props }) {
2015
+ return /* @__PURE__ */ jsx(
2016
+ "div",
2017
+ {
2018
+ "data-slot": "card-action",
2019
+ className: cn(
2020
+ "col-start-2 row-span-2 row-start-1 self-start justify-self-end",
2021
+ className
2022
+ ),
2023
+ ...props
2024
+ }
2025
+ );
2026
+ }
2027
+ function CardContent({ className, ...props }) {
2028
+ return /* @__PURE__ */ jsx(
2029
+ "div",
2030
+ {
2031
+ "data-slot": "card-content",
2032
+ className: cn("px-6", className),
2033
+ ...props
2034
+ }
2035
+ );
2036
+ }
2037
+ function CardFooter({ className, ...props }) {
2038
+ return /* @__PURE__ */ jsx(
2039
+ "div",
2040
+ {
2041
+ "data-slot": "card-footer",
2042
+ className: cn("flex items-center px-6 [.border-t]:pt-6", className),
2043
+ ...props
2044
+ }
2045
+ );
2046
+ }
2047
+ const FormHeaderComponent = () => {
2001
2048
  const { t: t2 } = useTranslation();
2002
2049
  const { isOpen, onClose, onOpen } = useModal();
2003
2050
  const {
@@ -2013,29 +2060,14 @@ const FormHeaderComponent = ({ modalContainer }) => {
2013
2060
  const sum = selectedAssetSymbol.toUpperCase();
2014
2061
  return assets.find((a) => a.symbol.toUpperCase() === sum) ?? assets[0];
2015
2062
  }, [assets, selectedAssetSymbol]);
2016
- return /* @__PURE__ */ jsxs(Fragment, { children: [
2017
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
2018
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2.5", children: [
2019
- /* @__PURE__ */ jsx("span", { className: "text-sm font-normal leading-3.5 text-muted-foreground", children: t2("bridge.selectToken") }),
2020
- /* @__PURE__ */ jsx(SelectTokenButton, { token: current, onClick: onOpen })
2021
- ] }),
2022
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2.5", children: [
2023
- /* @__PURE__ */ jsx(RefreshButton, {}),
2024
- /* @__PURE__ */ jsx(
2025
- Button,
2026
- {
2027
- className: "cursor-pointer py-1.5 h-8.5 hover:scale-110 shadow-none px-8.5 hover:bg-secondary bg-secondary !rounded-40",
2028
- onClick: onOpenSettings,
2029
- children: /* @__PURE__ */ jsx(
2030
- BoltIcon,
2031
- {
2032
- className: "size-4 text-foreground m-1",
2033
- stroke: "currentColor"
2034
- }
2035
- )
2036
- }
2037
- )
2038
- ] })
2063
+ return /* @__PURE__ */ jsxs(CardHeader, { className: "gap-y-0 flex justify-between items-center", children: [
2064
+ /* @__PURE__ */ jsxs(CardTitle, { className: "flex items-center gap-2.5", children: [
2065
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-normal leading-3.5 text-muted-foreground", children: t2("bridge.selectToken") }),
2066
+ /* @__PURE__ */ jsx(SelectTokenButton, { token: current, onClick: onOpen })
2067
+ ] }),
2068
+ /* @__PURE__ */ jsxs(CardAction, { className: "flex items-center gap-2.5", children: [
2069
+ /* @__PURE__ */ jsx(RefreshButton, {}),
2070
+ /* @__PURE__ */ jsx(Button, { onClick: onOpenSettings, size: "sm", variant: "secondary", children: /* @__PURE__ */ jsx(BoltIcon, { stroke: "currentColor" }) })
2039
2071
  ] }),
2040
2072
  /* @__PURE__ */ jsx(
2041
2073
  TokenSelectModal,
@@ -2046,24 +2078,19 @@ const FormHeaderComponent = ({ modalContainer }) => {
2046
2078
  onChangeAsset: (symbol) => {
2047
2079
  setSelectedAssetSymbol(symbol);
2048
2080
  onClose();
2049
- },
2050
- modalContainer
2081
+ }
2051
2082
  }
2052
2083
  ),
2053
2084
  /* @__PURE__ */ jsx(
2054
2085
  SettingModal,
2055
2086
  {
2056
2087
  isOpen: isOpenSettings,
2057
- onClose: onCloseSettings,
2058
- modalContainer
2088
+ onClose: onCloseSettings
2059
2089
  }
2060
2090
  )
2061
2091
  ] });
2062
2092
  };
2063
- const FormHeader = memo(
2064
- FormHeaderComponent,
2065
- (prev, next) => prev.modalContainer === next.modalContainer
2066
- );
2093
+ const FormHeader = memo(FormHeaderComponent);
2067
2094
  async function fetchQuotes(req) {
2068
2095
  const params = {
2069
2096
  srcChainKey: req.srcChainKey,
@@ -2611,8 +2638,7 @@ const ChainSelectModal = ({
2611
2638
  onClose,
2612
2639
  items,
2613
2640
  allowedItems,
2614
- onChangeChain,
2615
- modalContainer
2641
+ onChangeChain
2616
2642
  }) => {
2617
2643
  const { t: t2 } = useTranslation();
2618
2644
  const [query, setQuery] = useState("");
@@ -2701,7 +2727,6 @@ const ChainSelectModal = ({
2701
2727
  {
2702
2728
  isOpen,
2703
2729
  onClose: handleClose,
2704
- modalContainer,
2705
2730
  children: /* @__PURE__ */ jsxs(ModalContent, { children: [
2706
2731
  /* @__PURE__ */ jsxs(ModalHeader, { children: [
2707
2732
  /* @__PURE__ */ jsx(ModalTitle, { children: t2("bridge.selectNetwork") }),
@@ -2839,8 +2864,7 @@ const SwapSection = ({
2839
2864
  disableNetworkSelect,
2840
2865
  isSource,
2841
2866
  onSelect,
2842
- onAmountChange,
2843
- modalContainer
2867
+ onAmountChange
2844
2868
  }) => {
2845
2869
  const { isOpen, onClose, onOpen } = useModal();
2846
2870
  const { assetMatrix, selectedAssetSymbol } = useTokensStore();
@@ -2873,9 +2897,9 @@ const SwapSection = ({
2873
2897
  "div",
2874
2898
  {
2875
2899
  className: cn(
2876
- "p-4 flex flex-col gap-4 transition-colors bg-muted",
2900
+ "p-4 flex flex-col gap-4 transition-colors bg-input",
2877
2901
  {
2878
- "bg-muted-focus": isSource && isFocused
2902
+ "bg-input-focus": isSource && isFocused
2879
2903
  },
2880
2904
  className
2881
2905
  ),
@@ -2935,8 +2959,7 @@ const SwapSection = ({
2935
2959
  onClose,
2936
2960
  items: chains,
2937
2961
  allowedItems: allowedChains,
2938
- onChangeChain,
2939
- modalContainer
2962
+ onChangeChain
2940
2963
  }
2941
2964
  )
2942
2965
  ] });
@@ -3921,7 +3944,7 @@ function useSilentValidations(amountString) {
3921
3944
  ]);
3922
3945
  return validationResult;
3923
3946
  }
3924
- function useTransferAction() {
3947
+ const SubmitButton = () => {
3925
3948
  const { t: t2 } = useTranslation();
3926
3949
  const { chainRegistry } = useChainStrategies();
3927
3950
  const { srcAddress, dstAddress } = useAddresses();
@@ -3997,7 +4020,7 @@ function useTransferAction() {
3997
4020
  maximumAmountFormatted,
3998
4021
  chainRegistry
3999
4022
  ]);
4000
- const onClick = async () => {
4023
+ const handleClick = async () => {
4001
4024
  if (isBusy) return;
4002
4025
  if (missingSrc && srcChainKey) {
4003
4026
  onOpen("src");
@@ -4017,33 +4040,15 @@ function useTransferAction() {
4017
4040
  }
4018
4041
  };
4019
4042
  const disabled = isBusy || amountNum <= 0 || status === "loading" || isBalanceLoading || hasInsufficientBalance || hasAmountTooLarge || !gas.hasEnoughGas || noRoute || !isValidForTransfer;
4020
- return {
4021
- // состояния
4022
- isBusy,
4023
- canTransfer,
4024
- missingSrc,
4025
- missingDst,
4026
- hasEnoughGas: gas.hasEnoughGas,
4027
- noRoute,
4028
- // представление
4029
- label,
4030
- disabled,
4031
- // действие
4032
- onClick
4033
- };
4034
- }
4035
- const SubmitButton = () => {
4036
- const { label, disabled, onClick } = useTransferAction();
4037
- return /* @__PURE__ */ jsx(Button, { onClick, disabled, size: "lg", children: label });
4043
+ return /* @__PURE__ */ jsx(Button, { onClick: handleClick, disabled, className: "w-full", children: label });
4038
4044
  };
4039
4045
  function short(addr) {
4040
4046
  return addr.slice(0, 4) + "…" + addr.slice(-4);
4041
4047
  }
4042
- const WalletSelectModal = ({
4043
- modalContainer
4044
- }) => {
4048
+ const WalletSelectModal = () => {
4045
4049
  const { t: t2 } = useTranslation();
4046
4050
  const { isOpen, onClose } = useWalletSelectModal();
4051
+ const { connect, connectors, isPending } = useConnect();
4047
4052
  const { chainRegistry } = useChainStrategies();
4048
4053
  const tonWallet = chainRegistry.getStrategyByType("ton");
4049
4054
  const metaMaskWallet = chainRegistry.getStrategyByType("evm");
@@ -4076,7 +4081,13 @@ const WalletSelectModal = ({
4076
4081
  onDisconnect: () => tronWallet.disconnect()
4077
4082
  });
4078
4083
  }
4079
- const isWalletConnected = (walletId) => connectedWallets.some((w) => w.id === walletId);
4084
+ const isWalletConnected = (walletId) => {
4085
+ const isEvmConnector = connectors.some((c) => c.id === walletId);
4086
+ if (isEvmConnector && metaMaskWallet?.isConnected()) {
4087
+ return true;
4088
+ }
4089
+ return connectedWallets.some((w) => w.id === walletId);
4090
+ };
4080
4091
  const tonWallets = [
4081
4092
  {
4082
4093
  id: "ton",
@@ -4085,14 +4096,15 @@ const WalletSelectModal = ({
4085
4096
  enabled: true
4086
4097
  }
4087
4098
  ];
4088
- const evmWallets = [
4089
- {
4090
- id: "metamask",
4091
- name: t2("wallets.metaMask"),
4092
- icon: MetaMaskIcon,
4093
- enabled: true
4094
- }
4095
- ];
4099
+ const evmWallets = connectors.filter(
4100
+ (connector) => connector.id === "walletConnect" || connector.id === "metaMaskSDK"
4101
+ ).map((connector) => ({
4102
+ id: connector.id,
4103
+ name: connector.name,
4104
+ icon: MetaMaskIcon,
4105
+ // You can add a WalletConnect icon here
4106
+ enabled: true
4107
+ }));
4096
4108
  const tronWallets = [
4097
4109
  {
4098
4110
  id: "tronlink",
@@ -4122,9 +4134,6 @@ const WalletSelectModal = ({
4122
4134
  case "ton":
4123
4135
  await tonWallet?.connect();
4124
4136
  break;
4125
- case "metamask":
4126
- await metaMaskWallet?.connect();
4127
- break;
4128
4137
  case "tronlink":
4129
4138
  await tronWallet?.connect();
4130
4139
  break;
@@ -4136,7 +4145,7 @@ const WalletSelectModal = ({
4136
4145
  console.error("Failed to connect wallet:", error);
4137
4146
  }
4138
4147
  };
4139
- return /* @__PURE__ */ jsx(Modal, { isOpen, onClose, modalContainer, children: /* @__PURE__ */ jsxs(ModalContent, { children: [
4148
+ return /* @__PURE__ */ jsx(Modal, { isOpen, onClose, children: /* @__PURE__ */ jsxs(ModalContent, { children: [
4140
4149
  /* @__PURE__ */ jsxs(ModalHeader, { children: [
4141
4150
  /* @__PURE__ */ jsx(ModalTitle, { children: t2("wallets.chooseWallet", { defaultValue: "Choose wallet" }) }),
4142
4151
  /* @__PURE__ */ jsx(ModalDescription, { children: t2("wallets.oneWalletPerEnv", {
@@ -4149,56 +4158,47 @@ const WalletSelectModal = ({
4149
4158
  /* @__PURE__ */ jsx("div", { className: "px-5 py-2 leading-4 text-base font-semibold text-muted-foreground uppercase", children: t2("wallets.connected") }),
4150
4159
  /* @__PURE__ */ jsx("div", { className: "", children: connectedWallets.map((wallet) => {
4151
4160
  const IconComponent = wallet.icon;
4152
- return /* @__PURE__ */ jsx("div", { className: "", children: /* @__PURE__ */ jsxs(
4153
- Button,
4154
- {
4155
- className: "w-full cursor-pointer bg-transparent flex shadow-none items-center justify-between gap-2.5 px-5 py-2.5 hover:bg-muted h-auto rounded-12 transition-[300]",
4156
- children: [
4157
- /* @__PURE__ */ jsx("div", { className: "flex items-center gap-3 min-w-0", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2.5", children: [
4158
- /* @__PURE__ */ jsx("div", { className: "w-7.5 h-7.5 flex items-center justify-center", children: /* @__PURE__ */ jsx(IconComponent, { className: "size-7.5" }) }),
4159
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-start min-w-0", children: [
4160
- /* @__PURE__ */ jsx("p", { className: "font-extrabold text-foreground text-sm leading-4 truncate", children: short(wallet.address) }),
4161
- /* @__PURE__ */ jsx("div", { className: "text-xs leading-3 font-semibold text-muted-foreground", children: wallet.name })
4162
- ] })
4163
- ] }) }),
4164
- /* @__PURE__ */ jsx("div", { onClick: () => {
4161
+ return /* @__PURE__ */ jsx("div", { className: "", children: /* @__PURE__ */ jsxs(Button, { className: "w-full cursor-pointer bg-transparent flex shadow-none items-center justify-between gap-2.5 px-5 py-2.5 hover:bg-muted h-auto rounded-12 transition-[300]", children: [
4162
+ /* @__PURE__ */ jsx("div", { className: "flex items-center gap-3 min-w-0", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2.5", children: [
4163
+ /* @__PURE__ */ jsx("div", { className: "w-7.5 h-7.5 flex items-center justify-center", children: /* @__PURE__ */ jsx(IconComponent, { className: "size-7.5" }) }),
4164
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-start min-w-0", children: [
4165
+ /* @__PURE__ */ jsx("p", { className: "font-extrabold text-foreground text-sm leading-4 truncate", children: short(wallet.address) }),
4166
+ /* @__PURE__ */ jsx("div", { className: "text-xs leading-3 font-semibold text-muted-foreground", children: wallet.name })
4167
+ ] })
4168
+ ] }) }),
4169
+ /* @__PURE__ */ jsx(
4170
+ "div",
4171
+ {
4172
+ onClick: () => {
4165
4173
  wallet.onDisconnect();
4166
4174
  onClose();
4167
- }, className: "text-sm font-medium text-muted-foreground", children: /* @__PURE__ */ jsx(ExitIcon, { className: "text-[#808080] size-6" }) })
4168
- ]
4169
- }
4170
- ) }, wallet.id);
4175
+ },
4176
+ className: "text-sm font-medium text-muted-foreground",
4177
+ children: /* @__PURE__ */ jsx(ExitIcon, { className: "text-[#808080] size-6" })
4178
+ }
4179
+ )
4180
+ ] }) }, wallet.id);
4171
4181
  }) })
4172
4182
  ] }),
4173
4183
  categories.map((category) => /* @__PURE__ */ jsxs("div", { children: [
4174
4184
  /* @__PURE__ */ jsx("div", { className: "px-5 py-2 leading-4 text-base font-semibold text-muted-foreground uppercase", children: category.title }),
4175
4185
  /* @__PURE__ */ jsx("div", { className: "", children: category.wallets.map((wallet) => {
4176
4186
  const IconComponent = wallet.icon;
4177
- if (wallet.id === "metamask") {
4178
- return /* @__PURE__ */ jsx("div", { id: wallet.id, children: /* @__PURE__ */ jsx(ConnectKitButton.Custom, { children: ({ isConnecting, show }) => {
4179
- return /* @__PURE__ */ jsx(
4180
- Button,
4181
- {
4182
- type: "button",
4183
- onClick: show,
4184
- disabled: isConnecting,
4185
- className: "w-full cursor-pointer bg-transparent flex shadow-none items-center justify-between gap-2.5 px-5 py-2.5 hover:bg-muted h-auto rounded-12 transition-[300] disabled:opacity-50 disabled:cursor-not-allowed",
4186
- children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 min-w-0", children: [
4187
- /* @__PURE__ */ jsx("div", { className: "w-7.5 h-7.5 flex items-center justify-center", children: /* @__PURE__ */ jsx(IconComponent, { className: "size-7.5" }) }),
4188
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-start min-w-0", children: [
4189
- /* @__PURE__ */ jsx("p", { className: "font-extrabold text-foreground text-sm leading-4 truncate", children: wallet.name }),
4190
- wallet.comingSoon ? /* @__PURE__ */ jsx("div", { className: "text-xs leading-3 font-semibold text-muted-foreground", children: t2("wallets.comingSoon") }) : /* @__PURE__ */ jsx("div", { className: "text-xs leading-3 font-semibold text-muted-foreground", children: t2("wallets.connect") })
4191
- ] })
4192
- ] })
4193
- }
4194
- );
4195
- } }) }, wallet.id);
4196
- }
4187
+ const isEvmConnector = category.title === t2("wallets.evmWallets");
4188
+ const connector = isEvmConnector ? connectors.find((c) => c.id === wallet.id) : null;
4197
4189
  return /* @__PURE__ */ jsx("div", { className: "", children: /* @__PURE__ */ jsx(
4198
4190
  Button,
4199
4191
  {
4200
- onClick: () => handleWalletSelect(wallet.id),
4201
- disabled: !wallet.enabled,
4192
+ type: "button",
4193
+ onClick: () => {
4194
+ if (connector) {
4195
+ connect({ connector });
4196
+ onClose();
4197
+ } else {
4198
+ handleWalletSelect(wallet.id);
4199
+ }
4200
+ },
4201
+ disabled: isEvmConnector ? isPending : !wallet.enabled,
4202
4202
  className: "w-full cursor-pointer bg-transparent flex shadow-none items-center justify-between gap-2.5 px-5 py-2.5 hover:bg-muted h-auto rounded-12 transition-[300] disabled:opacity-50 disabled:cursor-not-allowed",
4203
4203
  children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 min-w-0", children: [
4204
4204
  /* @__PURE__ */ jsx("div", { className: "w-7.5 h-7.5 flex items-center justify-center", children: /* @__PURE__ */ jsx(IconComponent, { className: "size-7.5" }) }),
@@ -4214,39 +4214,6 @@ const WalletSelectModal = ({
4214
4214
  ] })
4215
4215
  ] }) });
4216
4216
  };
4217
- function Card({ className, ...props }) {
4218
- return /* @__PURE__ */ jsx(
4219
- "div",
4220
- {
4221
- "data-slot": "card",
4222
- className: cn(
4223
- "bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm",
4224
- className
4225
- ),
4226
- ...props
4227
- }
4228
- );
4229
- }
4230
- function CardContent({ className, ...props }) {
4231
- return /* @__PURE__ */ jsx(
4232
- "div",
4233
- {
4234
- "data-slot": "card-content",
4235
- className: cn("px-6", className),
4236
- ...props
4237
- }
4238
- );
4239
- }
4240
- function CardFooter({ className, ...props }) {
4241
- return /* @__PURE__ */ jsx(
4242
- "div",
4243
- {
4244
- "data-slot": "card-footer",
4245
- className: cn("flex items-center px-6 [.border-t]:pt-6", className),
4246
- ...props
4247
- }
4248
- );
4249
- }
4250
4217
  const TransactionProgressVector = (props) => {
4251
4218
  return /* @__PURE__ */ jsxs("svg", { width: "200", height: "200", viewBox: "0 0 200 200", fill: "none", xmlns: "http://www.w3.org/2000/svg", ...props, children: [
4252
4219
  /* @__PURE__ */ jsx(
@@ -6171,7 +6138,7 @@ const ConfirmStep = () => {
6171
6138
  /* @__PURE__ */ jsx("div", { className: "text-3xl font-black relative z-10", children: formatTime })
6172
6139
  ] }) });
6173
6140
  };
6174
- const TransactionManager = ({ modalContainer }) => {
6141
+ const TransactionManager = () => {
6175
6142
  const { current } = useTransactionStore();
6176
6143
  const status = current?.status;
6177
6144
  if (!status || status === "idle") return null;
@@ -6189,7 +6156,7 @@ const TransactionManager = ({ modalContainer }) => {
6189
6156
  step = /* @__PURE__ */ jsx(SuccessStep, {});
6190
6157
  }
6191
6158
  return /* @__PURE__ */ jsx(Modal, { isOpen: true, onClose: () => {
6192
- }, modalContainer, children: step });
6159
+ }, children: step });
6193
6160
  };
6194
6161
  const useTokensRequest = () => {
6195
6162
  const { setTokens, setSelectedToken, setSelectedAssetSymbol } = useTokensStore();
@@ -6310,6 +6277,49 @@ class ChainStrategyRegistry {
6310
6277
  await strategy.disconnect();
6311
6278
  }
6312
6279
  }
6280
+ const EVM_CONFIG = {
6281
+ usdtAddress: "0xdAC17F958D2ee523a2206206994597C13D831ec7",
6282
+ gasEstimates: {
6283
+ approve: 65000n,
6284
+ bridge: 300000n
6285
+ },
6286
+ gasBuffer: 1.2,
6287
+ // 20% buffer
6288
+ timeout: 3e5,
6289
+ // 5 minutes (increased for slower networks)
6290
+ requiredConfirmations: 3
6291
+ // Wait for 3 confirmations for reorg protection
6292
+ };
6293
+ const TON_CONFIG = {
6294
+ apiUrl: "https://toncenter.com/api/v2",
6295
+ timeout: 36e4,
6296
+ // 6 minutes
6297
+ validUntil: 600
6298
+ // 10 minutes
6299
+ };
6300
+ const TRON_CONFIG = {
6301
+ timeout: 12e4,
6302
+ // 2 minutes (for 19 confirmations)
6303
+ feeLimit: 1e8,
6304
+ // 100 TRX in sun
6305
+ requiredConfirmations: 19,
6306
+ // TRON standard: 19 blocks for confirmation
6307
+ pollingInterval: 3e3
6308
+ // 3 seconds between checks
6309
+ };
6310
+ let tonClientInstance = null;
6311
+ function getTonClient(customClient, apiKey) {
6312
+ if (customClient) {
6313
+ return customClient;
6314
+ }
6315
+ if (!tonClientInstance) {
6316
+ tonClientInstance = new TonClient({
6317
+ endpoint: `${TON_CONFIG.apiUrl}/jsonRPC`,
6318
+ apiKey
6319
+ });
6320
+ }
6321
+ return tonClientInstance;
6322
+ }
6313
6323
  function isNativeAddress(addr) {
6314
6324
  if (!addr) return false;
6315
6325
  const a = addr.toLowerCase();
@@ -6335,44 +6345,72 @@ function formatUnitsFromBigIntStr(valueStr, decimals) {
6335
6345
  const tail = s.slice(s.length - decimals).replace(/0+$/, "");
6336
6346
  return Number(tail ? `${head}.${tail}` : head);
6337
6347
  }
6338
- async function getEvmBalances(address, tokens) {
6348
+ function isTonFriendlyAddress(address) {
6349
+ return !!address && /^[A-Za-z0-9_-]{48,}$/.test(address);
6350
+ }
6351
+ function normalizeTickerSymbol(symbol) {
6352
+ return symbol.toUpperCase().replace(/₮/g, "T").replace(/[^A-Z0-9]/g, "");
6353
+ }
6354
+ function parseTonAddress(address) {
6355
+ if (address.startsWith("0x")) {
6356
+ const hex = address.slice(2);
6357
+ return Address$1.parseRaw(`0:${hex}`);
6358
+ }
6359
+ if (address.includes(":")) {
6360
+ return Address$1.parseRaw(address);
6361
+ }
6362
+ return Address$1.parse(address);
6363
+ }
6364
+ async function getEvmBalances(publicClient, address, tokens) {
6339
6365
  const balances = {};
6340
6366
  try {
6341
- if (!address || !ethers.isAddress(address)) {
6367
+ console.log("start getEvmBalances");
6368
+ console.log("publicClient:", publicClient);
6369
+ console.log("isAddress:", isAddress(address));
6370
+ console.log("tokens:", tokens);
6371
+ if (!address || !isAddress(address)) {
6342
6372
  console.warn(`Invalid EVM address provided: ${address}`);
6343
6373
  return balances;
6344
6374
  }
6345
- if (typeof window === "undefined" || !window.ethereum) {
6346
- throw new Error("No ethereum provider found");
6375
+ if (!publicClient) {
6376
+ throw new Error("No public client provided");
6347
6377
  }
6348
- const provider = new ethers.BrowserProvider(window.ethereum);
6349
6378
  for (const token of tokens) {
6350
6379
  try {
6351
6380
  let balance = 0;
6352
6381
  const isNative = isNativeAddress(token.address);
6353
6382
  if (isNative) {
6354
- const ethBalance = await provider.getBalance(address);
6355
- balance = parseFloat(ethers.formatUnits(ethBalance, token.decimals));
6383
+ const ethBalance = await publicClient.getBalance({
6384
+ address
6385
+ });
6386
+ balance = parseFloat(formatUnits(ethBalance, token.decimals));
6356
6387
  } else {
6357
- if (!ethers.isAddress(token.address)) {
6388
+ if (!isAddress(token.address)) {
6358
6389
  continue;
6359
6390
  }
6360
- const code = await provider.getCode(token.address);
6361
- if (code === "0x") {
6391
+ const bytecode = await publicClient.getBytecode({
6392
+ address: token.address
6393
+ });
6394
+ if (!bytecode || bytecode === "0x") {
6362
6395
  continue;
6363
6396
  }
6364
- const contract = new ethers.Contract(
6365
- token.address,
6366
- [
6367
- "function balanceOf(address owner) view returns (uint256)",
6368
- "function decimals() view returns (uint8)"
6369
- ],
6370
- provider
6371
- );
6372
6397
  try {
6373
- const tokenBalance = await contract.balanceOf(address);
6398
+ const tokenBalance = await publicClient.readContract({
6399
+ address: token.address,
6400
+ abi: [
6401
+ {
6402
+ name: "balanceOf",
6403
+ type: "function",
6404
+ stateMutability: "view",
6405
+ inputs: [{ name: "owner", type: "address" }],
6406
+ outputs: [{ name: "balance", type: "uint256" }]
6407
+ }
6408
+ ],
6409
+ functionName: "balanceOf",
6410
+ args: [address]
6411
+ });
6374
6412
  balance = parseFloat(
6375
- ethers.formatUnits(tokenBalance, token.decimals)
6413
+ formatUnits(tokenBalance, token.decimals)
6376
6414
  );
6377
6415
  } catch {
6378
6416
  continue;
@@ -6395,6 +6433,68 @@ async function getEvmBalances(address, tokens) {
6395
6433
  }
6396
6434
  return balances;
6397
6435
  }
6436
+ async function getTonBalances(address, tokens, customTonClient, tonApiKey) {
6437
+ const balances = {};
6438
+ try {
6439
+ if (!isTonFriendlyAddress(address)) {
6440
+ console.warn(`Invalid TON address provided: ${address}`);
6441
+ return balances;
6442
+ }
6443
+ const client = getTonClient(customTonClient, tonApiKey);
6444
+ const accountAddress = Address$1.parse(address);
6445
+ console.log(address);
6446
+ console.log(tokens);
6447
+ try {
6448
+ const balance = await client.getBalance(accountAddress);
6449
+ const tonBalance = Number(balance) / 1e9;
6450
+ console.log("tonBalance", tonBalance);
6451
+ if (tonBalance > 0) {
6452
+ balances.TON = { balance: tonBalance, address: "ton-native" };
6453
+ }
6454
+ } catch (error) {
6455
+ console.warn("Failed to get native TON balance:", error);
6456
+ }
6457
+ for (const token of tokens) {
6458
+ try {
6459
+ if (isNativeAddress(token.address) || token.symbol.toUpperCase() === "TON") {
6460
+ continue;
6461
+ }
6462
+ const jettonMasterAddress = parseTonAddress(token.address);
6463
+ const jettonWalletAddress = await client.runMethod(
6464
+ jettonMasterAddress,
6465
+ "get_wallet_address",
6466
+ [
6467
+ {
6468
+ type: "slice",
6469
+ cell: beginCell().storeAddress(accountAddress).endCell()
6470
+ }
6471
+ ]
6472
+ );
6473
+ const jettonWalletAddr = jettonWalletAddress.stack.readAddress();
6474
+ const jettonData = await client.runMethod(
6475
+ jettonWalletAddr,
6476
+ "get_wallet_data"
6477
+ );
6478
+ const jettonBalance = jettonData.stack.readBigNumber();
6479
+ const humanBalance = Number(jettonBalance) / Math.pow(10, token.decimals);
6480
+ if (humanBalance > 0) {
6481
+ const symbolUpper = token.symbol.toUpperCase();
6482
+ const symbolNorm = normalizeTickerSymbol(symbolUpper);
6483
+ const entry = { balance: humanBalance, address: token.address };
6484
+ balances[symbolUpper] = entry;
6485
+ if (symbolNorm !== symbolUpper) {
6486
+ balances[symbolNorm] = entry;
6487
+ }
6488
+ }
6489
+ } catch (error) {
6490
+ console.debug(`Failed to get balance for ${token.symbol}:`, error);
6491
+ }
6492
+ }
6493
+ } catch (error) {
6494
+ console.error("Failed to get TON balances:", error);
6495
+ }
6496
+ return balances;
6497
+ }
6398
6498
  async function getTronBalances(tronWeb, address, tokens) {
6399
6499
  const balances = {};
6400
6500
  try {
@@ -6438,30 +6538,6 @@ async function getTronBalances(tronWeb, address, tokens) {
6438
6538
  }
6439
6539
  return balances;
6440
6540
  }
6441
- const EVM_CONFIG = {
6442
- usdtAddress: "0xdAC17F958D2ee523a2206206994597C13D831ec7",
6443
- gasEstimates: {
6444
- approve: 65000n,
6445
- bridge: 300000n
6446
- },
6447
- gasBuffer: 1.2,
6448
- // 20% buffer
6449
- timeout: 12e4
6450
- // 2 minutes
6451
- };
6452
- const TON_CONFIG = {
6453
- apiUrl: "https://toncenter.com/api/v2",
6454
- timeout: 36e4,
6455
- // 6 minutes
6456
- validUntil: 600
6457
- // 10 minutes
6458
- };
6459
- const TRON_CONFIG = {
6460
- timeout: 6e4,
6461
- // 1 minute
6462
- feeLimit: 1e8
6463
- // 100 TRX in sun
6464
- };
6465
6541
  const ERC20_ABI = [
6466
6542
  "function approve(address spender, uint256 amount) returns (bool)",
6467
6543
  "function allowance(address owner, address spender) view returns (uint256)",
@@ -6472,7 +6548,9 @@ class EvmChainStrategy {
6472
6548
  constructor(config) {
6473
6549
  __publicField(this, "config");
6474
6550
  __publicField(this, "provider");
6551
+ __publicField(this, "publicClient");
6475
6552
  this.config = config;
6553
+ this.publicClient = config.publicClient;
6476
6554
  if (config.walletClient) {
6477
6555
  this.provider = new BrowserProvider(config.walletClient.transport);
6478
6556
  }
@@ -6511,7 +6589,11 @@ class EvmChainStrategy {
6511
6589
  return t2("wallets.connectEvmWallet");
6512
6590
  }
6513
6591
  async getBalances(address, tokens) {
6514
- return await getEvmBalances(address, tokens);
6592
+ if (!this.publicClient) {
6593
+ console.warn("No publicClient available for balance query");
6594
+ return {};
6595
+ }
6596
+ return await getEvmBalances(this.publicClient, address, tokens);
6515
6597
  }
6516
6598
  isAddressValid(address) {
6517
6599
  if (!address) return false;
@@ -6540,8 +6622,8 @@ class EvmChainStrategy {
6540
6622
  const totalGas = approveGas + bridgeGas;
6541
6623
  const bufferMultiplier = BigInt(Math.floor(EVM_CONFIG.gasBuffer * 100));
6542
6624
  const requiredWei = gasPrice * totalGas * bufferMultiplier / 100n;
6543
- const { formatUnits } = await import("ethers");
6544
- estimatedGas = Number(formatUnits(requiredWei, nativeDecimals));
6625
+ const { formatUnits: formatUnits2 } = await import("ethers");
6626
+ estimatedGas = Number(formatUnits2(requiredWei, nativeDecimals));
6545
6627
  } catch {
6546
6628
  estimatedGas = null;
6547
6629
  }
@@ -6624,17 +6706,14 @@ class EvmChainStrategy {
6624
6706
  if (!provider) {
6625
6707
  throw new ProviderNotAvailableError("evm");
6626
6708
  }
6627
- const deadline = Date.now() + EVM_CONFIG.timeout;
6628
- let receipt = null;
6629
- while (Date.now() < deadline) {
6630
- try {
6631
- receipt = await provider.getTransactionReceipt(txHash);
6632
- if (receipt) break;
6633
- } catch (e) {
6634
- console.debug("Error fetching receipt:", e);
6635
- }
6636
- await new Promise((r) => setTimeout(r, 2500));
6637
- }
6709
+ console.log(
6710
+ `Waiting for ${EVM_CONFIG.requiredConfirmations} confirmations for tx: ${txHash}`
6711
+ );
6712
+ const receipt = await provider.waitForTransaction(
6713
+ txHash,
6714
+ EVM_CONFIG.requiredConfirmations,
6715
+ EVM_CONFIG.timeout
6716
+ );
6638
6717
  if (!receipt) {
6639
6718
  const error = new TransactionTimeoutError("evm", txHash);
6640
6719
  return {
@@ -6649,11 +6728,35 @@ class EvmChainStrategy {
6649
6728
  error: error.message
6650
6729
  };
6651
6730
  }
6652
- console.log("EVM transaction confirmed on-chain");
6731
+ console.log(
6732
+ `EVM transaction confirmed in block ${receipt.blockNumber} with ${EVM_CONFIG.requiredConfirmations} confirmations`
6733
+ );
6653
6734
  return {
6654
6735
  completed: true
6655
6736
  };
6656
6737
  } catch (error) {
6738
+ if (error && typeof error === "object" && "code" in error && error.code === "TRANSACTION_REPLACED") {
6739
+ console.log(
6740
+ `Transaction was replaced: ${"reason" in error ? String(error.reason) : "unknown"}`
6741
+ );
6742
+ if ("receipt" in error && error.receipt) {
6743
+ const replacementReceipt = error.receipt;
6744
+ if (replacementReceipt.status === 1) {
6745
+ console.log(
6746
+ `Replacement transaction succeeded in block ${replacementReceipt.blockNumber}`
6747
+ );
6748
+ return {
6749
+ completed: true
6750
+ };
6751
+ } else {
6752
+ const chainError2 = new TransactionRevertedError("evm", txHash);
6753
+ return {
6754
+ completed: false,
6755
+ error: chainError2.message
6756
+ };
6757
+ }
6758
+ }
6759
+ }
6657
6760
  const chainError = toChainStrategyError(
6658
6761
  error,
6659
6762
  "evm",
@@ -6767,13 +6870,52 @@ class EvmChainStrategy {
6767
6870
  return false;
6768
6871
  }
6769
6872
  }
6873
+ /**
6874
+ * Check if a block has reached finality status (optional, for critical transactions)
6875
+ * This is more stringent than confirmations and protects against long-range reorgs
6876
+ *
6877
+ * Usage: Call this method after waitForCompletion if you need additional security
6878
+ * for high-value transactions. The method checks if the block has been marked as
6879
+ * "finalized" by the Ethereum consensus layer (2/3 of validators).
6880
+ *
6881
+ * @param blockNumber - The block number to check for finality
6882
+ * @returns true if the block is finalized, false otherwise
6883
+ */
6884
+ async checkFinality(blockNumber) {
6885
+ try {
6886
+ const provider = this.provider;
6887
+ if (!provider) {
6888
+ return false;
6889
+ }
6890
+ const finalizedBlock = await provider.getBlock("finalized");
6891
+ if (!finalizedBlock) {
6892
+ console.debug(
6893
+ "Finalized block not available (pre-merge or unsupported)"
6894
+ );
6895
+ return false;
6896
+ }
6897
+ const isFinalized = blockNumber <= finalizedBlock.number;
6898
+ if (isFinalized) {
6899
+ console.log(
6900
+ `Block ${blockNumber} has reached finality (finalized block: ${finalizedBlock.number})`
6901
+ );
6902
+ } else {
6903
+ console.debug(
6904
+ `Block ${blockNumber} not yet finalized (finalized block: ${finalizedBlock.number})`
6905
+ );
6906
+ }
6907
+ return isFinalized;
6908
+ } catch (error) {
6909
+ console.debug("Error checking finality:", error);
6910
+ return false;
6911
+ }
6912
+ }
6770
6913
  }
6771
6914
  class TonChainStrategy {
6772
6915
  constructor(config) {
6773
6916
  __publicField(this, "config");
6774
6917
  this.config = config;
6775
6918
  }
6776
- // ========== Identity ==========
6777
6919
  canHandle(chainKey) {
6778
6920
  return chainKey.toLowerCase() === "ton";
6779
6921
  }
@@ -6783,7 +6925,6 @@ class TonChainStrategy {
6783
6925
  getName() {
6784
6926
  return "TON Chain Strategy";
6785
6927
  }
6786
- // ========== Wallet Management ==========
6787
6928
  async connect() {
6788
6929
  await this.config.tonConnectUI?.openModal();
6789
6930
  }
@@ -6808,17 +6949,26 @@ class TonChainStrategy {
6808
6949
  getConnectLabel(t2) {
6809
6950
  return t2("wallets.connectTonWallet");
6810
6951
  }
6811
- // ========== Balance & Validation ==========
6812
- async getBalances(address) {
6813
- return await getSwapBalances(address);
6952
+ async getBalances(address, tokens) {
6953
+ return await getTonBalances(
6954
+ address,
6955
+ tokens,
6956
+ this.config.tonClient,
6957
+ this.config.tonApiKey
6958
+ );
6814
6959
  }
6815
6960
  isAddressValid(address) {
6816
6961
  if (!address) return false;
6817
6962
  return true;
6818
6963
  }
6819
- // ========== Gas Estimation ==========
6820
6964
  async estimateGasRequirement(params) {
6821
- const { selectedToken, nativeTokenSymbol, amount, balances, reserveFallback } = params;
6965
+ const {
6966
+ selectedToken,
6967
+ nativeTokenSymbol,
6968
+ amount,
6969
+ balances,
6970
+ reserveFallback
6971
+ } = params;
6822
6972
  const nativeSym = nativeTokenSymbol.toUpperCase();
6823
6973
  const isNativeSelected = nativeSym === (selectedToken?.symbol ?? "").toUpperCase();
6824
6974
  const nativeBalance = Number(balances[nativeSym]?.balance ?? 0);
@@ -6840,7 +6990,6 @@ class TonChainStrategy {
6840
6990
  isNativeSelected
6841
6991
  };
6842
6992
  }
6843
- // ========== Transaction Execution ==========
6844
6993
  validateSteps(steps) {
6845
6994
  if (!steps || steps.length === 0) {
6846
6995
  throw new InvalidStepsError("ton", "No transaction steps provided");
@@ -6893,19 +7042,17 @@ class TonChainStrategy {
6893
7042
  const result = await this.config.tonConnectUI.sendTransaction(
6894
7043
  transaction
6895
7044
  );
6896
- const hash = this.getTxHash(result.boc);
6897
7045
  return {
6898
7046
  chainKey: "ton",
6899
- hash
7047
+ hash: result.boc
6900
7048
  };
6901
7049
  } catch (error) {
6902
7050
  throw toChainStrategyError(error, "ton", "transaction");
6903
7051
  }
6904
7052
  }
6905
- async waitForCompletion(txHash, context) {
7053
+ async waitForCompletion(txHash) {
6906
7054
  try {
6907
7055
  const confirmed = await this.checkTonTransaction(
6908
- context.srcAddress,
6909
7056
  txHash,
6910
7057
  TON_CONFIG.timeout
6911
7058
  );
@@ -6935,39 +7082,78 @@ class TonChainStrategy {
6935
7082
  };
6936
7083
  }
6937
7084
  }
6938
- // ========== Private Helper Methods ==========
6939
- getTxHash(boc) {
6940
- const cell = Cell.fromBase64(boc);
6941
- const buffer = cell.hash();
6942
- return buffer.toString("hex");
7085
+ getNormalizedExtMessageHash(message) {
7086
+ if (message.info.type !== "external-in") {
7087
+ throw new Error(`Expected external-in message, got ${message.info.type}`);
7088
+ }
7089
+ const normalizedInfo = {
7090
+ ...message.info,
7091
+ src: void 0,
7092
+ importFee: 0n
7093
+ };
7094
+ const normalizedMessage = {
7095
+ ...message,
7096
+ info: normalizedInfo,
7097
+ init: null
7098
+ };
7099
+ return beginCell$1().store(storeMessage(normalizedMessage, { forceRef: true })).endCell().hash();
6943
7100
  }
6944
- async checkTonTransaction(address, txHash, timeoutMs = 36e4) {
7101
+ async checkTonTransaction(bocBase64, timeoutMs = 36e4) {
6945
7102
  const deadline = Date.now() + timeoutMs;
6946
- const normalizedHash = txHash.toLowerCase();
6947
- while (Date.now() < deadline) {
6948
- try {
6949
- const response = await fetch(
6950
- `${TON_CONFIG.apiUrl}/getTransactions?address=${address}&limit=20`
7103
+ const client = getTonClient(this.config.tonClient, this.config.tonApiKey);
7104
+ try {
7105
+ const inMessage = loadMessage(Cell.fromBase64(bocBase64).beginParse());
7106
+ if (inMessage.info.type !== "external-in") {
7107
+ console.debug(
7108
+ "Expected external-in message, got:",
7109
+ inMessage.info.type
6951
7110
  );
6952
- if (!response.ok) {
6953
- console.debug("TonCenter API error:", response.status);
6954
- await new Promise((r) => setTimeout(r, 3e3));
6955
- continue;
6956
- }
6957
- const data = await response.json();
6958
- const transactions = data.result || [];
6959
- for (const tx of transactions) {
6960
- const txIdHash = tx.transaction_id?.hash;
6961
- if (txIdHash && txIdHash.toLowerCase() === normalizedHash) {
6962
- return true;
7111
+ return false;
7112
+ }
7113
+ const accountAddress = inMessage.info.dest;
7114
+ const targetMessageHash = this.getNormalizedExtMessageHash(inMessage);
7115
+ let lt = void 0;
7116
+ let hash = void 0;
7117
+ while (Date.now() < deadline) {
7118
+ try {
7119
+ const transactions = await client.getTransactions(accountAddress, {
7120
+ lt,
7121
+ hash,
7122
+ limit: 10,
7123
+ archival: true
7124
+ });
7125
+ if (transactions.length === 0) {
7126
+ await new Promise((r) => setTimeout(r, 3e3));
7127
+ lt = void 0;
7128
+ hash = void 0;
7129
+ continue;
6963
7130
  }
7131
+ for (const tx of transactions) {
7132
+ if (tx.inMessage?.info.type === "external-in") {
7133
+ const txInMessageHash = this.getNormalizedExtMessageHash(
7134
+ tx.inMessage
7135
+ );
7136
+ if (txInMessageHash.equals(targetMessageHash)) {
7137
+ console.debug("Transaction found by in-message hash");
7138
+ return true;
7139
+ }
7140
+ }
7141
+ }
7142
+ const lastTx = transactions[transactions.length - 1];
7143
+ lt = lastTx.lt.toString();
7144
+ hash = lastTx.hash().toString("base64");
7145
+ } catch (error) {
7146
+ console.debug("Error fetching transactions:", error);
7147
+ await new Promise((r) => setTimeout(r, 3e3));
7148
+ lt = void 0;
7149
+ hash = void 0;
6964
7150
  }
6965
- } catch (e) {
6966
- console.debug("TonCenter polling error:", e);
6967
7151
  }
6968
- await new Promise((r) => setTimeout(r, 3e3));
7152
+ return false;
7153
+ } catch (error) {
7154
+ console.debug("Error parsing BOC or checking transaction:", error);
7155
+ return false;
6969
7156
  }
6970
- return false;
6971
7157
  }
6972
7158
  }
6973
7159
  class TronChainStrategy {
@@ -7028,7 +7214,13 @@ class TronChainStrategy {
7028
7214
  }
7029
7215
  // ========== Gas Estimation ==========
7030
7216
  async estimateGasRequirement(params) {
7031
- const { selectedToken, nativeTokenSymbol, amount, balances, reserveFallback } = params;
7217
+ const {
7218
+ selectedToken,
7219
+ nativeTokenSymbol,
7220
+ amount,
7221
+ balances,
7222
+ reserveFallback
7223
+ } = params;
7032
7224
  const nativeSym = nativeTokenSymbol.toUpperCase();
7033
7225
  const isNativeSelected = nativeSym === (selectedToken?.symbol ?? "").toUpperCase();
7034
7226
  const nativeBalance = Number(balances[nativeSym]?.balance ?? 0);
@@ -7050,7 +7242,6 @@ class TronChainStrategy {
7050
7242
  isNativeSelected
7051
7243
  };
7052
7244
  }
7053
- // ========== Transaction Execution ==========
7054
7245
  validateSteps(steps) {
7055
7246
  console.log("validateSteps");
7056
7247
  if (!steps?.length) {
@@ -7085,7 +7276,10 @@ class TronChainStrategy {
7085
7276
  if (String(step.chainKey).toLowerCase() !== "tron") continue;
7086
7277
  const tx = step.transaction;
7087
7278
  if (!tx) {
7088
- throw new InvalidTransactionDataError("tron", "Missing transaction data");
7279
+ throw new InvalidTransactionDataError(
7280
+ "tron",
7281
+ "Missing transaction data"
7282
+ );
7089
7283
  }
7090
7284
  const hexData = typeof tx?.data === "string" ? tx.data : "";
7091
7285
  const parsed = this.parseTronStep(step, tx, hexData);
@@ -7136,13 +7330,19 @@ class TronChainStrategy {
7136
7330
  break;
7137
7331
  }
7138
7332
  default:
7139
- throw new InvalidStepsError("tron", "Unsupported TRON parsed tx kind");
7333
+ throw new InvalidStepsError(
7334
+ "tron",
7335
+ "Unsupported TRON parsed tx kind"
7336
+ );
7140
7337
  }
7141
7338
  const { txid } = await this.signAndBroadcast(tronWeb, unsigned);
7142
7339
  lastTxId = txid;
7143
7340
  }
7144
7341
  if (!lastTxId) {
7145
- throw new TransactionFailedError("tron", "No TRON transaction was executed");
7342
+ throw new TransactionFailedError(
7343
+ "tron",
7344
+ "No TRON transaction was executed"
7345
+ );
7146
7346
  }
7147
7347
  return { hash: lastTxId, chainKey: "tron" };
7148
7348
  }
@@ -7152,47 +7352,84 @@ class TronChainStrategy {
7152
7352
  if (!tronWeb) {
7153
7353
  throw new ProviderNotAvailableError("tron");
7154
7354
  }
7355
+ console.log(
7356
+ `Waiting for ${TRON_CONFIG.requiredConfirmations} confirmations for TRON tx: ${txHash}`
7357
+ );
7155
7358
  const deadline = Date.now() + TRON_CONFIG.timeout;
7156
- while (Date.now() < deadline) {
7359
+ let txBlockNumber = null;
7360
+ while (Date.now() < deadline && !txBlockNumber) {
7157
7361
  try {
7158
7362
  const info = await tronWeb.trx.getTransactionInfo(txHash);
7159
- console.log("TRON transaction info:", info);
7160
- if (info) {
7363
+ if (info && info.blockNumber) {
7161
7364
  const result = info.receipt?.result;
7162
- if (result === "SUCCESS") {
7163
- console.log("TRON transaction confirmed on-chain");
7365
+ if (result !== "SUCCESS") {
7366
+ const msg = this.hexToAscii(info.resMessage) || null;
7367
+ let reason = msg;
7368
+ const cr = info.contractResult?.[0];
7369
+ if (cr && /^0x?08c379a0/i.test(cr)) {
7370
+ try {
7371
+ const clean = cr.replace(/^0x/, "");
7372
+ const len = parseInt(clean.slice(8 + 64, 8 + 64 + 64), 16);
7373
+ const strHex = clean.slice(
7374
+ 8 + 64 + 64,
7375
+ 8 + 64 + 64 + len * 2
7376
+ );
7377
+ const str = this.hexToAscii("0x" + strHex);
7378
+ if (str) reason = str;
7379
+ } catch (e) {
7380
+ console.debug("TRON revert string decode error", e);
7381
+ }
7382
+ }
7383
+ const error2 = new TransactionRevertedError(
7384
+ "tron",
7385
+ txHash,
7386
+ reason || "Unknown error"
7387
+ );
7164
7388
  return {
7165
- completed: true
7389
+ completed: false,
7390
+ error: error2.message
7166
7391
  };
7167
7392
  }
7168
- const msg = this.hexToAscii(info.resMessage) || null;
7169
- let reason = msg;
7170
- const cr = info.contractResult?.[0];
7171
- if (cr && /^0x?08c379a0/i.test(cr)) {
7172
- try {
7173
- const clean = cr.replace(/^0x/, "");
7174
- const len = parseInt(clean.slice(8 + 64, 8 + 64 + 64), 16);
7175
- const strHex = clean.slice(8 + 64 + 64, 8 + 64 + 64 + len * 2);
7176
- const str = this.hexToAscii("0x" + strHex);
7177
- if (str) reason = str;
7178
- } catch (e) {
7179
- console.debug("TRON revert string decode error", e);
7180
- }
7393
+ txBlockNumber = info.blockNumber;
7394
+ console.log(`TRON transaction found in block ${txBlockNumber}`);
7395
+ }
7396
+ } catch (e) {
7397
+ console.debug("TRON getTransactionInfo error:", e);
7398
+ }
7399
+ if (!txBlockNumber) {
7400
+ await new Promise((r) => setTimeout(r, TRON_CONFIG.pollingInterval));
7401
+ }
7402
+ }
7403
+ if (!txBlockNumber) {
7404
+ const error2 = new TransactionTimeoutError("tron", txHash);
7405
+ return {
7406
+ completed: false,
7407
+ error: error2.message
7408
+ };
7409
+ }
7410
+ let confirmations = 0;
7411
+ while (Date.now() < deadline) {
7412
+ try {
7413
+ const currentBlock = await tronWeb.trx.getCurrentBlock();
7414
+ const currentBlockNumber = currentBlock?.block_header?.raw_data?.number;
7415
+ if (currentBlockNumber) {
7416
+ confirmations = currentBlockNumber - txBlockNumber;
7417
+ if (confirmations >= TRON_CONFIG.requiredConfirmations) {
7418
+ console.log(
7419
+ `TRON transaction confirmed in block ${txBlockNumber} with ${confirmations} confirmations`
7420
+ );
7421
+ return {
7422
+ completed: true
7423
+ };
7181
7424
  }
7182
- const error2 = new TransactionRevertedError(
7183
- "tron",
7184
- txHash,
7185
- reason || "Unknown error"
7425
+ console.log(
7426
+ `TRON transaction confirmations: ${confirmations}/${TRON_CONFIG.requiredConfirmations}`
7186
7427
  );
7187
- return {
7188
- completed: false,
7189
- error: error2.message
7190
- };
7191
7428
  }
7192
7429
  } catch (e) {
7193
- console.debug("TRON getTransactionInfo error:", e);
7430
+ console.debug("TRON getCurrentBlock error:", e);
7194
7431
  }
7195
- await new Promise((r) => setTimeout(r, 3e3));
7432
+ await new Promise((r) => setTimeout(r, TRON_CONFIG.pollingInterval));
7196
7433
  }
7197
7434
  const error = new TransactionTimeoutError("tron", txHash);
7198
7435
  return {
@@ -7200,14 +7437,17 @@ class TronChainStrategy {
7200
7437
  error: error.message
7201
7438
  };
7202
7439
  } catch (error) {
7203
- const chainError = toChainStrategyError(error, "tron", "waitForCompletion");
7440
+ const chainError = toChainStrategyError(
7441
+ error,
7442
+ "tron",
7443
+ "waitForCompletion"
7444
+ );
7204
7445
  return {
7205
7446
  completed: false,
7206
7447
  error: chainError.message
7207
7448
  };
7208
7449
  }
7209
7450
  }
7210
- // ========== Private Helper Methods ==========
7211
7451
  getTronWeb() {
7212
7452
  return typeof window !== "undefined" ? window.tronWeb : void 0;
7213
7453
  }
@@ -7260,7 +7500,10 @@ class TronChainStrategy {
7260
7500
  amount: this.extractAmountFromTxData(tx.data)
7261
7501
  };
7262
7502
  }
7263
- throw new InvalidTransactionDataError("tron", "Cannot parse approve transaction");
7503
+ throw new InvalidTransactionDataError(
7504
+ "tron",
7505
+ "Cannot parse approve transaction"
7506
+ );
7264
7507
  }
7265
7508
  if (step?.type === "transfer" || step?.type === "bridge") {
7266
7509
  const s = step;
@@ -7290,7 +7533,10 @@ class TronChainStrategy {
7290
7533
  feeLimit: raw2.feeLimit
7291
7534
  };
7292
7535
  }
7293
- throw new InvalidTransactionDataError("tron", "Cannot parse transfer/bridge transaction");
7536
+ throw new InvalidTransactionDataError(
7537
+ "tron",
7538
+ "Cannot parse transfer/bridge transaction"
7539
+ );
7294
7540
  }
7295
7541
  if (tx?.to && tx?.value && !tx?.data) {
7296
7542
  const v = BigInt(tx.value.toString());
@@ -7310,19 +7556,28 @@ class TronChainStrategy {
7310
7556
  feeLimit: raw.feeLimit
7311
7557
  };
7312
7558
  }
7313
- throw new InvalidTransactionDataError("tron", `Unsupported TRON step type: ${step?.type ?? "unknown"}`);
7559
+ throw new InvalidTransactionDataError(
7560
+ "tron",
7561
+ `Unsupported TRON step type: ${step?.type ?? "unknown"}`
7562
+ );
7314
7563
  }
7315
7564
  extractSpenderFromTxData(data) {
7316
7565
  const clean = data.replace(/^0x/, "");
7317
7566
  if (clean.length < 74) {
7318
- throw new InvalidTransactionDataError("tron", "Invalid transaction data length");
7567
+ throw new InvalidTransactionDataError(
7568
+ "tron",
7569
+ "Invalid transaction data length"
7570
+ );
7319
7571
  }
7320
7572
  return "41" + clean.slice(32, 72);
7321
7573
  }
7322
7574
  extractAmountFromTxData(data) {
7323
7575
  const clean = data.replace(/^0x/, "");
7324
7576
  if (clean.length < 138) {
7325
- throw new InvalidTransactionDataError("tron", "Invalid transaction data length");
7577
+ throw new InvalidTransactionDataError(
7578
+ "tron",
7579
+ "Invalid transaction data length"
7580
+ );
7326
7581
  }
7327
7582
  const amountHex = clean.slice(72, 136);
7328
7583
  return BigInt("0x" + amountHex).toString();
@@ -7330,7 +7585,10 @@ class TronChainStrategy {
7330
7585
  extractRecipientFromTxData(data) {
7331
7586
  const clean = data.replace(/^0x/, "");
7332
7587
  if (clean.length < 74) {
7333
- throw new InvalidTransactionDataError("tron", "Invalid transaction data length");
7588
+ throw new InvalidTransactionDataError(
7589
+ "tron",
7590
+ "Invalid transaction data length"
7591
+ );
7334
7592
  }
7335
7593
  return "41" + clean.slice(32, 72);
7336
7594
  }
@@ -7405,7 +7663,6 @@ class TronChainStrategy {
7405
7663
  return null;
7406
7664
  }
7407
7665
  }
7408
- // ========== Transaction Builders ==========
7409
7666
  async buildApprove(tronWeb, p) {
7410
7667
  const res = await tronWeb.transactionBuilder.triggerSmartContract(
7411
7668
  p.token,
@@ -7418,7 +7675,10 @@ class TronChainStrategy {
7418
7675
  p.from
7419
7676
  );
7420
7677
  if (!res?.transaction) {
7421
- throw new TransactionFailedError("tron", "Failed to build approve transaction");
7678
+ throw new TransactionFailedError(
7679
+ "tron",
7680
+ "Failed to build approve transaction"
7681
+ );
7422
7682
  }
7423
7683
  return res.transaction;
7424
7684
  }
@@ -7434,7 +7694,10 @@ class TronChainStrategy {
7434
7694
  p.from
7435
7695
  );
7436
7696
  if (!res?.transaction) {
7437
- throw new TransactionFailedError("tron", "Failed to build transfer transaction");
7697
+ throw new TransactionFailedError(
7698
+ "tron",
7699
+ "Failed to build transfer transaction"
7700
+ );
7438
7701
  }
7439
7702
  return res.transaction;
7440
7703
  }
@@ -7454,12 +7717,13 @@ class TronChainStrategy {
7454
7717
  p.from
7455
7718
  );
7456
7719
  if (!res?.transaction) {
7457
- throw new TransactionFailedError("tron", "Failed to build raw call transaction");
7720
+ throw new TransactionFailedError(
7721
+ "tron",
7722
+ "Failed to build raw call transaction"
7723
+ );
7458
7724
  }
7459
7725
  return res.transaction;
7460
7726
  }
7461
- // ========== Transaction Sender ==========
7462
- /* eslint-disable @typescript-eslint/no-explicit-any */
7463
7727
  async signAndBroadcast(tronWeb, unsignedTx) {
7464
7728
  const signed = await tronWeb.trx.sign(unsignedTx);
7465
7729
  const sent = await tronWeb.trx.sendRawTransaction(signed);
@@ -7471,33 +7735,77 @@ class TronChainStrategy {
7471
7735
  }
7472
7736
  return { txid: sent.txid };
7473
7737
  }
7738
+ /**
7739
+ * Check if a transaction has been solidified (confirmed by solidityNode)
7740
+ * This is an additional check for critical transactions to ensure they are
7741
+ * truly confirmed and available through the solidityNode API.
7742
+ *
7743
+ * Usage: Call this method after waitForCompletion for high-value transactions
7744
+ * to get additional assurance that the transaction is solidified.
7745
+ *
7746
+ * @param txHash - Transaction hash to check
7747
+ * @returns true if the transaction is solidified, false otherwise
7748
+ */
7749
+ async checkSolidified(txHash) {
7750
+ try {
7751
+ const tronWeb = this.getTronWeb();
7752
+ if (!tronWeb) {
7753
+ return false;
7754
+ }
7755
+ const info = await tronWeb.trx.getTransactionInfo(txHash);
7756
+ if (!info || !info.blockNumber) {
7757
+ console.debug(
7758
+ "Transaction not yet solidified (no blockNumber in info)"
7759
+ );
7760
+ return false;
7761
+ }
7762
+ const result = info.receipt?.result;
7763
+ if (result === "SUCCESS") {
7764
+ console.log(
7765
+ `Transaction ${txHash} is solidified in block ${info.blockNumber}`
7766
+ );
7767
+ return true;
7768
+ }
7769
+ console.debug(`Transaction solidified but result is: ${result}`);
7770
+ return false;
7771
+ } catch (error) {
7772
+ console.debug("Error checking solidified status:", error);
7773
+ return false;
7774
+ }
7775
+ }
7474
7776
  }
7475
7777
  function ChainStrategyProvider({
7476
7778
  children,
7477
7779
  evmWallet,
7478
7780
  tonWallet,
7479
- tronWallet
7781
+ tronWallet,
7782
+ tonClient,
7783
+ tonApiKey
7480
7784
  }) {
7481
7785
  const evmStrategy = useMemo(
7482
7786
  () => new EvmChainStrategy({
7483
7787
  evmAddress: evmWallet.address,
7484
7788
  evmIsConnected: evmWallet.isConnected,
7485
7789
  evmDisconnect: evmWallet.disconnect,
7486
- walletClient: evmWallet.walletClient
7790
+ walletClient: evmWallet.walletClient,
7791
+ publicClient: evmWallet.publicClient
7487
7792
  }),
7488
7793
  [
7489
7794
  evmWallet.address,
7490
7795
  evmWallet.isConnected,
7491
7796
  evmWallet.disconnect,
7492
- evmWallet.walletClient
7797
+ evmWallet.walletClient,
7798
+ evmWallet.publicClient
7493
7799
  ]
7494
7800
  );
7495
7801
  const tonStrategy = useMemo(
7496
7802
  () => new TonChainStrategy({
7497
7803
  tonConnectUI: tonWallet.tonConnectUI,
7498
- tonAddress: tonWallet.address
7804
+ tonAddress: tonWallet.address,
7805
+ tonClient,
7806
+ tonApiKey
7499
7807
  }),
7500
- [tonWallet.tonConnectUI, tonWallet.address]
7808
+ [tonWallet.tonConnectUI, tonWallet.address, tonClient, tonApiKey]
7501
7809
  );
7502
7810
  const tronStrategy = useMemo(
7503
7811
  () => new TronChainStrategy({
@@ -7533,6 +7841,7 @@ const EvaaBridgeWithProviders = (props) => {
7533
7841
  const { address: evmAddress, isConnected: evmIsConnected } = useAccount();
7534
7842
  const { disconnect: evmDisconnect } = useDisconnect();
7535
7843
  const { data: walletClient } = useWalletClient();
7844
+ const publicClient = usePublicClient();
7536
7845
  const {
7537
7846
  address: tronAddress,
7538
7847
  connected: tronConnected,
@@ -7550,14 +7859,15 @@ const EvaaBridgeWithProviders = (props) => {
7550
7859
  useEffect(() => {
7551
7860
  setTronConnected(!!tronConnected);
7552
7861
  }, [tronConnected, setTronConnected]);
7553
- return /* @__PURE__ */ jsx(
7862
+ return /* @__PURE__ */ jsx(ModalContainerProvider, { containerId: props.modalContainerId, children: /* @__PURE__ */ jsx(
7554
7863
  ChainStrategyProvider,
7555
7864
  {
7556
7865
  evmWallet: {
7557
7866
  address: evmAddress,
7558
7867
  isConnected: evmIsConnected,
7559
7868
  disconnect: evmDisconnect,
7560
- walletClient
7869
+ walletClient,
7870
+ publicClient
7561
7871
  },
7562
7872
  tonWallet: {
7563
7873
  tonConnectUI,
@@ -7570,9 +7880,11 @@ const EvaaBridgeWithProviders = (props) => {
7570
7880
  connect: tronConnect,
7571
7881
  disconnect: tronDisconnect
7572
7882
  },
7883
+ tonClient: props.tonClient,
7884
+ tonApiKey: props.tonApiKey,
7573
7885
  children: /* @__PURE__ */ jsx(EvaaBridgeContent, { ...props })
7574
7886
  }
7575
- );
7887
+ ) });
7576
7888
  };
7577
7889
  const EvaaBridgeContent = ({
7578
7890
  className,
@@ -7581,7 +7893,6 @@ const EvaaBridgeContent = ({
7581
7893
  onChainChange
7582
7894
  } = {}) => {
7583
7895
  const { t: t2 } = useTranslation();
7584
- const modalContainerRef = useRef(null);
7585
7896
  useTokensRequest();
7586
7897
  useChainsRequest();
7587
7898
  const [sendToAnother, setSendToAnother] = useState(false);
@@ -7674,16 +7985,15 @@ const EvaaBridgeContent = ({
7674
7985
  }, [chains, assetMatrix, allowedFromChains]);
7675
7986
  return /* @__PURE__ */ jsxs(Fragment, { children: [
7676
7987
  /* @__PURE__ */ jsxs(
7677
- "section",
7988
+ Card,
7678
7989
  {
7679
7990
  className: cn(
7680
- "p-5 bg-card max-w-md w-full rounded-3xl mx-auto flex flex-col gap-4 relative",
7991
+ "max-w-md w-full mx-auto flex flex-col relative",
7681
7992
  className
7682
7993
  ),
7683
- ref: modalContainerRef,
7684
7994
  children: [
7685
- /* @__PURE__ */ jsx(FormHeader, { modalContainer: modalContainerRef.current }),
7686
- /* @__PURE__ */ jsxs("div", { className: "space-y-[1px]", children: [
7995
+ /* @__PURE__ */ jsx(FormHeader, {}),
7996
+ /* @__PURE__ */ jsxs(CardContent, { className: "space-y-[1px]", children: [
7687
7997
  /* @__PURE__ */ jsx(
7688
7998
  SwapSection,
7689
7999
  {
@@ -7696,8 +8006,7 @@ const EvaaBridgeContent = ({
7696
8006
  amount,
7697
8007
  isSource: true,
7698
8008
  onAmountChange: handleAmountChange,
7699
- onSelect: handleFromChainChange,
7700
- modalContainer: modalContainerRef.current || void 0
8009
+ onSelect: handleFromChainChange
7701
8010
  }
7702
8011
  ),
7703
8012
  /* @__PURE__ */ jsx(SwapButton, {}),
@@ -7711,8 +8020,7 @@ const EvaaBridgeContent = ({
7711
8020
  allowedChains: allowedToChains,
7712
8021
  amount: outputAmount,
7713
8022
  readOnlyAmount: true,
7714
- onSelect: handleToChainChange,
7715
- modalContainer: modalContainerRef.current || void 0
8023
+ onSelect: handleToChainChange
7716
8024
  }
7717
8025
  ),
7718
8026
  /* @__PURE__ */ jsx(
@@ -7721,15 +8029,15 @@ const EvaaBridgeContent = ({
7721
8029
  enabled: sendToAnother,
7722
8030
  onToggle: () => setSendToAnother((v) => !v)
7723
8031
  }
7724
- )
8032
+ ),
8033
+ /* @__PURE__ */ jsx(SubmitButton, {})
7725
8034
  ] }),
7726
- /* @__PURE__ */ jsx(SubmitButton, {}),
7727
- /* @__PURE__ */ jsx(ReceiveRow, {})
8035
+ /* @__PURE__ */ jsx(CardFooter, { children: /* @__PURE__ */ jsx(ReceiveRow, {}) })
7728
8036
  ]
7729
8037
  }
7730
8038
  ),
7731
- /* @__PURE__ */ jsx(WalletSelectModal, { modalContainer: modalContainerRef.current }),
7732
- /* @__PURE__ */ jsx(TransactionManager, { modalContainer: modalContainerRef.current }),
8039
+ /* @__PURE__ */ jsx(WalletSelectModal, {}),
8040
+ /* @__PURE__ */ jsx(TransactionManager, {}),
7733
8041
  /* @__PURE__ */ jsx(Toaster, { position: "top-right", richColors: true })
7734
8042
  ] });
7735
8043
  };
@@ -7813,8 +8121,8 @@ export {
7813
8121
  getQuoteDetails,
7814
8122
  getQuoteFees,
7815
8123
  getQuotesByPriority,
7816
- getSwapBalances,
7817
8124
  getTokens,
8125
+ getTonBalances,
7818
8126
  getTronBalances,
7819
8127
  isAddressValidForChain,
7820
8128
  isEvmAddress,
@@ -7823,7 +8131,7 @@ export {
7823
8131
  isZeroAddr,
7824
8132
  listAssetsForSelect,
7825
8133
  lookupTokenMeta,
7826
- normalizeTickerSymbol,
8134
+ normalizeTickerSymbol$1 as normalizeTickerSymbol,
7827
8135
  pollUntilDelivered,
7828
8136
  resolveTokenOnChain,
7829
8137
  resolveTokenOnChainFromMatrix$2 as resolveTokenOnChainFromMatrix,