@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.
@@ -44,10 +44,11 @@ const reactWindow = require("react-window");
44
44
  const SwitchPrimitive = require("@radix-ui/react-switch");
45
45
  const lucideReact = require("lucide-react");
46
46
  const AccordionPrimitive = require("@radix-ui/react-accordion");
47
- const connectkit = require("connectkit");
48
47
  const i18next = require("i18next");
49
48
  const sonner = require("sonner");
50
49
  const ethers = require("ethers");
50
+ const viem = require("viem");
51
+ const ton = require("@ton/ton");
51
52
  const tronwalletAdapters = require("@tronweb3/tronwallet-adapters");
52
53
  function _interopNamespaceDefault(e) {
53
54
  const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
@@ -551,7 +552,7 @@ function cn(...inputs) {
551
552
  return tailwindMerge.twMerge(clsx.clsx(inputs));
552
553
  }
553
554
  const buttonVariants = classVarianceAuthority.cva(
554
- "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",
555
+ "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",
555
556
  {
556
557
  variants: {
557
558
  variant: {
@@ -591,6 +592,23 @@ const Button = require$$0__namespace.forwardRef(
591
592
  }
592
593
  );
593
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
+ };
594
612
  const ModalContent = ({ children, className }) => {
595
613
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("p-5 flex flex-col h-full", className), children });
596
614
  };
@@ -644,11 +662,11 @@ const Modal = ({
644
662
  isOpen,
645
663
  onClose,
646
664
  children,
647
- className,
648
- modalContainer
665
+ className
649
666
  }) => {
650
667
  const panelRef = require$$0.useRef(null);
651
668
  const lastActiveRef = require$$0.useRef(null);
669
+ const container = useModalContainer();
652
670
  require$$0.useEffect(() => {
653
671
  if (!isOpen) return;
654
672
  lastActiveRef.current = document.activeElement;
@@ -670,7 +688,6 @@ const Modal = ({
670
688
  return () => window.removeEventListener("keydown", onKey);
671
689
  }, [isOpen, onClose]);
672
690
  if (typeof document === "undefined") return null;
673
- const container = modalContainer || document.body;
674
691
  return reactDom.createPortal(
675
692
  /* @__PURE__ */ jsxRuntime.jsx(framerMotion.AnimatePresence, { children: isOpen && /* @__PURE__ */ jsxRuntime.jsx(
676
693
  framerMotion.motion.div,
@@ -824,19 +841,6 @@ const Tip = (props) => {
824
841
  /* @__PURE__ */ jsxRuntime.jsx(TooltipContent, { children: /* @__PURE__ */ jsxRuntime.jsx("p", { children: text }) })
825
842
  ] });
826
843
  };
827
- function toLD(human, decimals) {
828
- const [i = "0", f = ""] = human.replace(",", ".").split(".");
829
- const frac = (f + "0".repeat(decimals)).slice(0, decimals);
830
- return BigInt(i + frac).toString();
831
- }
832
- function fromLD(ld, decimals) {
833
- const bi = BigInt(ld || "0");
834
- if (decimals === 0) return Number(bi);
835
- const base = BigInt(10) ** BigInt(decimals);
836
- const int = bi / base;
837
- const frac = Number(bi % base) / Number(base);
838
- return Number(int) + frac;
839
- }
840
844
  async function getChains() {
841
845
  const res = await fetch("https://stargate.finance/api/v1/chains", {
842
846
  credentials: "same-origin"
@@ -884,49 +888,16 @@ async function getDestTokens(srcChainKey, srcTokenAddr) {
884
888
  });
885
889
  return unique;
886
890
  }
887
- const isTonFriendly = (a) => !!a && /^[A-Za-z0-9_-]{48,}$/.test(a);
888
- function normalizeTickerSymbol(s) {
891
+ function normalizeTickerSymbol$1(s) {
889
892
  return s.toUpperCase().replace(/₮/g, "T").replace(/[^A-Z0-9]/g, "");
890
893
  }
891
- async function getSwapBalances(accountFriendly) {
892
- if (!isTonFriendly(accountFriendly)) throw new Error("Invalid TON address");
893
- const accRes = await fetch(
894
- `https://tonapi.io/v2/accounts/${accountFriendly}`
895
- );
896
- if (!accRes.ok) throw new Error(`TON account fetch failed: ${accRes.status}`);
897
- const acc = await accRes.json();
898
- const ton = fromLD(String(acc?.balance ?? "0"), 9);
899
- const result = {
900
- TON: { balance: ton, address: "ton-native" }
901
- };
902
- const jetsRes = await fetch(
903
- `https://tonapi.io/v2/accounts/${accountFriendly}/jettons?limit=200`
904
- );
905
- if (!jetsRes.ok) return result;
906
- const jets = await jetsRes.json();
907
- const items = jets?.balances ?? jets?.jettons ?? jets?.items ?? [];
908
- for (const it of items) {
909
- const rawSym = (it?.jetton?.symbol ?? it?.symbol ?? "").toString();
910
- if (!rawSym) continue;
911
- const symUpper = rawSym.toUpperCase();
912
- const symNorm = normalizeTickerSymbol(symUpper);
913
- const master = (it?.jetton?.address ?? it?.address ?? "").toString();
914
- const decimals = Number(it?.jetton?.decimals ?? it?.decimals ?? 9) || 9;
915
- const raw = (it?.balance ?? "0").toString();
916
- const human = fromLD(raw, decimals);
917
- const entry = { balance: human, address: master };
918
- result[symUpper] = entry;
919
- if (symNorm !== symUpper) result[symNorm] = entry;
920
- }
921
- return result;
922
- }
923
894
  const BASE_URL$1 = "https://icons-ckg.pages.dev/stargate-light/tokens";
924
895
  const TokenSymbol = ({
925
896
  symbol,
926
897
  className = "w-4 h-4",
927
898
  alt
928
899
  }) => {
929
- const normalizedSymbol = normalizeTickerSymbol(symbol).toLowerCase();
900
+ const normalizedSymbol = normalizeTickerSymbol$1(symbol).toLowerCase();
930
901
  const src = `${BASE_URL$1}/${normalizedSymbol}.svg`;
931
902
  return /* @__PURE__ */ jsxRuntime.jsx("img", { src, alt: alt ?? symbol, className });
932
903
  };
@@ -1136,8 +1107,7 @@ const routePresets = [
1136
1107
  ];
1137
1108
  const SettingModal = ({
1138
1109
  isOpen,
1139
- onClose,
1140
- modalContainer
1110
+ onClose
1141
1111
  }) => {
1142
1112
  const { t } = reactI18next.useTranslation();
1143
1113
  const { toChain } = useChainsStore();
@@ -1171,7 +1141,7 @@ const SettingModal = ({
1171
1141
  );
1172
1142
  const activeBtn = "bg-settings-active hover:bg-settings-active/80 text-settings-active-foreground";
1173
1143
  const notActiveBtn = "bg-settings-button hover:bg-settings-button/80 text-settings-button-foreground";
1174
- return /* @__PURE__ */ jsxRuntime.jsx(Modal, { isOpen, onClose, modalContainer, children: /* @__PURE__ */ jsxRuntime.jsxs(ModalContent, { children: [
1144
+ return /* @__PURE__ */ jsxRuntime.jsx(Modal, { isOpen, onClose, children: /* @__PURE__ */ jsxRuntime.jsxs(ModalContent, { children: [
1175
1145
  /* @__PURE__ */ jsxRuntime.jsxs(ModalHeader, { children: [
1176
1146
  /* @__PURE__ */ jsxRuntime.jsx(ModalTitle, { children: t("settings.title", { defaultValue: "Settings" }) }),
1177
1147
  /* @__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" }) })
@@ -1340,6 +1310,19 @@ function useChainStrategies() {
1340
1310
  }
1341
1311
  return context;
1342
1312
  }
1313
+ function toLD(human, decimals) {
1314
+ const [i = "0", f = ""] = human.replace(",", ".").split(".");
1315
+ const frac = (f + "0".repeat(decimals)).slice(0, decimals);
1316
+ return BigInt(i + frac).toString();
1317
+ }
1318
+ function fromLD(ld, decimals) {
1319
+ const bi = BigInt(ld || "0");
1320
+ if (decimals === 0) return Number(bi);
1321
+ const base = BigInt(10) ** BigInt(decimals);
1322
+ const int = bi / base;
1323
+ const frac = Number(bi % base) / Number(base);
1324
+ return Number(int) + frac;
1325
+ }
1343
1326
  function resolveTokenOnChainFromMatrix$2(assetMatrix, assetSymbol, chainKey) {
1344
1327
  if (!assetMatrix || !assetSymbol || !chainKey) return void 0;
1345
1328
  const byChain = assetMatrix[assetSymbol.toUpperCase()];
@@ -1521,20 +1504,17 @@ function useBalances(chainKey, address) {
1521
1504
  const data = query.data;
1522
1505
  if (data) {
1523
1506
  for (const [sum, v] of Object.entries(data)) {
1524
- map.set(normalizeTickerSymbol(sum), Number(v.balance ?? 0));
1507
+ map.set(normalizeTickerSymbol$1(sum), Number(v.balance ?? 0));
1525
1508
  }
1526
1509
  }
1527
1510
  return map;
1528
1511
  }, [query.data]);
1529
1512
  const getBalance = require$$0.useCallback(
1530
- (symbol) => balanceBySymbol.get(normalizeTickerSymbol(symbol)) ?? 0,
1513
+ (symbol) => balanceBySymbol.get(normalizeTickerSymbol$1(symbol)) ?? 0,
1531
1514
  [balanceBySymbol]
1532
1515
  );
1533
1516
  const isLoading = query.isLoading || query.isFetching;
1534
- const balances = require$$0.useMemo(
1535
- () => query.data || {},
1536
- [query.data]
1537
- );
1517
+ const balances = require$$0.useMemo(() => query.data || {}, [query.data]);
1538
1518
  return {
1539
1519
  balances,
1540
1520
  getBalance,
@@ -1764,8 +1744,7 @@ const TokenSelectModal = ({
1764
1744
  isOpen,
1765
1745
  onClose,
1766
1746
  items,
1767
- onChangeAsset,
1768
- modalContainer
1747
+ onChangeAsset
1769
1748
  }) => {
1770
1749
  const { t } = reactI18next.useTranslation();
1771
1750
  const {
@@ -1850,7 +1829,6 @@ const TokenSelectModal = ({
1850
1829
  {
1851
1830
  isOpen,
1852
1831
  onClose: handleClose,
1853
- modalContainer,
1854
1832
  children: /* @__PURE__ */ jsxRuntime.jsxs(ModalContent, { children: [
1855
1833
  /* @__PURE__ */ jsxRuntime.jsxs(ModalHeader, { children: [
1856
1834
  /* @__PURE__ */ jsxRuntime.jsx(ModalTitle, { children: t("bridge.selectToken") }),
@@ -1990,17 +1968,17 @@ const RefreshButton = () => {
1990
1968
  return /* @__PURE__ */ jsxRuntime.jsx(
1991
1969
  Button,
1992
1970
  {
1993
- 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" : ""}`,
1994
1971
  onClick: handleRefresh,
1995
1972
  disabled: spinning,
1973
+ variant: "secondary",
1974
+ size: "sm",
1996
1975
  children: /* @__PURE__ */ jsxRuntime.jsx(
1997
1976
  ReloadIcon,
1998
1977
  {
1999
1978
  style: {
2000
1979
  transform: `rotate(${turns * 180}deg)`,
2001
1980
  transition: "transform 300ms linear"
2002
- },
2003
- className: "size-4 text-foreground m-1 will-change-transform"
1981
+ }
2004
1982
  }
2005
1983
  )
2006
1984
  }
@@ -2008,7 +1986,6 @@ const RefreshButton = () => {
2008
1986
  };
2009
1987
  const SelectTokenButton = ({
2010
1988
  onClick,
2011
- className,
2012
1989
  token
2013
1990
  }) => {
2014
1991
  const { t } = reactI18next.useTranslation();
@@ -2019,7 +1996,8 @@ const SelectTokenButton = ({
2019
1996
  Button,
2020
1997
  {
2021
1998
  onClick,
2022
- 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 ?? ""}`,
1999
+ size: "sm",
2000
+ variant: "secondary",
2023
2001
  type: "button",
2024
2002
  "aria-label": label,
2025
2003
  children: [
@@ -2039,7 +2017,76 @@ const SelectTokenButton = ({
2039
2017
  }
2040
2018
  );
2041
2019
  };
2042
- const FormHeaderComponent = ({ modalContainer }) => {
2020
+ function Card({ className, ...props }) {
2021
+ return /* @__PURE__ */ jsxRuntime.jsx(
2022
+ "div",
2023
+ {
2024
+ "data-slot": "card",
2025
+ className: cn(
2026
+ "bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm",
2027
+ className
2028
+ ),
2029
+ ...props
2030
+ }
2031
+ );
2032
+ }
2033
+ function CardHeader({ className, ...props }) {
2034
+ return /* @__PURE__ */ jsxRuntime.jsx(
2035
+ "div",
2036
+ {
2037
+ "data-slot": "card-header",
2038
+ className: cn(
2039
+ "@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",
2040
+ className
2041
+ ),
2042
+ ...props
2043
+ }
2044
+ );
2045
+ }
2046
+ function CardTitle({ className, ...props }) {
2047
+ return /* @__PURE__ */ jsxRuntime.jsx(
2048
+ "div",
2049
+ {
2050
+ "data-slot": "card-title",
2051
+ className: cn("leading-none font-semibold", className),
2052
+ ...props
2053
+ }
2054
+ );
2055
+ }
2056
+ function CardAction({ className, ...props }) {
2057
+ return /* @__PURE__ */ jsxRuntime.jsx(
2058
+ "div",
2059
+ {
2060
+ "data-slot": "card-action",
2061
+ className: cn(
2062
+ "col-start-2 row-span-2 row-start-1 self-start justify-self-end",
2063
+ className
2064
+ ),
2065
+ ...props
2066
+ }
2067
+ );
2068
+ }
2069
+ function CardContent({ className, ...props }) {
2070
+ return /* @__PURE__ */ jsxRuntime.jsx(
2071
+ "div",
2072
+ {
2073
+ "data-slot": "card-content",
2074
+ className: cn("px-6", className),
2075
+ ...props
2076
+ }
2077
+ );
2078
+ }
2079
+ function CardFooter({ className, ...props }) {
2080
+ return /* @__PURE__ */ jsxRuntime.jsx(
2081
+ "div",
2082
+ {
2083
+ "data-slot": "card-footer",
2084
+ className: cn("flex items-center px-6 [.border-t]:pt-6", className),
2085
+ ...props
2086
+ }
2087
+ );
2088
+ }
2089
+ const FormHeaderComponent = () => {
2043
2090
  const { t } = reactI18next.useTranslation();
2044
2091
  const { isOpen, onClose, onOpen } = useModal();
2045
2092
  const {
@@ -2055,29 +2102,14 @@ const FormHeaderComponent = ({ modalContainer }) => {
2055
2102
  const sum = selectedAssetSymbol.toUpperCase();
2056
2103
  return assets.find((a) => a.symbol.toUpperCase() === sum) ?? assets[0];
2057
2104
  }, [assets, selectedAssetSymbol]);
2058
- return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2059
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
2060
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2.5", children: [
2061
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-normal leading-3.5 text-muted-foreground", children: t("bridge.selectToken") }),
2062
- /* @__PURE__ */ jsxRuntime.jsx(SelectTokenButton, { token: current, onClick: onOpen })
2063
- ] }),
2064
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2.5", children: [
2065
- /* @__PURE__ */ jsxRuntime.jsx(RefreshButton, {}),
2066
- /* @__PURE__ */ jsxRuntime.jsx(
2067
- Button,
2068
- {
2069
- className: "cursor-pointer py-1.5 h-8.5 hover:scale-110 shadow-none px-8.5 hover:bg-secondary bg-secondary !rounded-40",
2070
- onClick: onOpenSettings,
2071
- children: /* @__PURE__ */ jsxRuntime.jsx(
2072
- BoltIcon,
2073
- {
2074
- className: "size-4 text-foreground m-1",
2075
- stroke: "currentColor"
2076
- }
2077
- )
2078
- }
2079
- )
2080
- ] })
2105
+ return /* @__PURE__ */ jsxRuntime.jsxs(CardHeader, { className: "gap-y-0 flex justify-between items-center", children: [
2106
+ /* @__PURE__ */ jsxRuntime.jsxs(CardTitle, { className: "flex items-center gap-2.5", children: [
2107
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-normal leading-3.5 text-muted-foreground", children: t("bridge.selectToken") }),
2108
+ /* @__PURE__ */ jsxRuntime.jsx(SelectTokenButton, { token: current, onClick: onOpen })
2109
+ ] }),
2110
+ /* @__PURE__ */ jsxRuntime.jsxs(CardAction, { className: "flex items-center gap-2.5", children: [
2111
+ /* @__PURE__ */ jsxRuntime.jsx(RefreshButton, {}),
2112
+ /* @__PURE__ */ jsxRuntime.jsx(Button, { onClick: onOpenSettings, size: "sm", variant: "secondary", children: /* @__PURE__ */ jsxRuntime.jsx(BoltIcon, { stroke: "currentColor" }) })
2081
2113
  ] }),
2082
2114
  /* @__PURE__ */ jsxRuntime.jsx(
2083
2115
  TokenSelectModal,
@@ -2088,24 +2120,19 @@ const FormHeaderComponent = ({ modalContainer }) => {
2088
2120
  onChangeAsset: (symbol) => {
2089
2121
  setSelectedAssetSymbol(symbol);
2090
2122
  onClose();
2091
- },
2092
- modalContainer
2123
+ }
2093
2124
  }
2094
2125
  ),
2095
2126
  /* @__PURE__ */ jsxRuntime.jsx(
2096
2127
  SettingModal,
2097
2128
  {
2098
2129
  isOpen: isOpenSettings,
2099
- onClose: onCloseSettings,
2100
- modalContainer
2130
+ onClose: onCloseSettings
2101
2131
  }
2102
2132
  )
2103
2133
  ] });
2104
2134
  };
2105
- const FormHeader = require$$0.memo(
2106
- FormHeaderComponent,
2107
- (prev, next) => prev.modalContainer === next.modalContainer
2108
- );
2135
+ const FormHeader = require$$0.memo(FormHeaderComponent);
2109
2136
  async function fetchQuotes(req) {
2110
2137
  const params = {
2111
2138
  srcChainKey: req.srcChainKey,
@@ -2653,8 +2680,7 @@ const ChainSelectModal = ({
2653
2680
  onClose,
2654
2681
  items,
2655
2682
  allowedItems,
2656
- onChangeChain,
2657
- modalContainer
2683
+ onChangeChain
2658
2684
  }) => {
2659
2685
  const { t } = reactI18next.useTranslation();
2660
2686
  const [query, setQuery] = require$$0.useState("");
@@ -2743,7 +2769,6 @@ const ChainSelectModal = ({
2743
2769
  {
2744
2770
  isOpen,
2745
2771
  onClose: handleClose,
2746
- modalContainer,
2747
2772
  children: /* @__PURE__ */ jsxRuntime.jsxs(ModalContent, { children: [
2748
2773
  /* @__PURE__ */ jsxRuntime.jsxs(ModalHeader, { children: [
2749
2774
  /* @__PURE__ */ jsxRuntime.jsx(ModalTitle, { children: t("bridge.selectNetwork") }),
@@ -2881,8 +2906,7 @@ const SwapSection = ({
2881
2906
  disableNetworkSelect,
2882
2907
  isSource,
2883
2908
  onSelect,
2884
- onAmountChange,
2885
- modalContainer
2909
+ onAmountChange
2886
2910
  }) => {
2887
2911
  const { isOpen, onClose, onOpen } = useModal();
2888
2912
  const { assetMatrix, selectedAssetSymbol } = useTokensStore();
@@ -2915,9 +2939,9 @@ const SwapSection = ({
2915
2939
  "div",
2916
2940
  {
2917
2941
  className: cn(
2918
- "p-4 flex flex-col gap-4 transition-colors bg-muted",
2942
+ "p-4 flex flex-col gap-4 transition-colors bg-input",
2919
2943
  {
2920
- "bg-muted-focus": isSource && isFocused
2944
+ "bg-input-focus": isSource && isFocused
2921
2945
  },
2922
2946
  className
2923
2947
  ),
@@ -2977,8 +3001,7 @@ const SwapSection = ({
2977
3001
  onClose,
2978
3002
  items: chains,
2979
3003
  allowedItems: allowedChains,
2980
- onChangeChain,
2981
- modalContainer
3004
+ onChangeChain
2982
3005
  }
2983
3006
  )
2984
3007
  ] });
@@ -3963,7 +3986,7 @@ function useSilentValidations(amountString) {
3963
3986
  ]);
3964
3987
  return validationResult;
3965
3988
  }
3966
- function useTransferAction() {
3989
+ const SubmitButton = () => {
3967
3990
  const { t } = reactI18next.useTranslation();
3968
3991
  const { chainRegistry } = useChainStrategies();
3969
3992
  const { srcAddress, dstAddress } = useAddresses();
@@ -4039,7 +4062,7 @@ function useTransferAction() {
4039
4062
  maximumAmountFormatted,
4040
4063
  chainRegistry
4041
4064
  ]);
4042
- const onClick = async () => {
4065
+ const handleClick = async () => {
4043
4066
  if (isBusy) return;
4044
4067
  if (missingSrc && srcChainKey) {
4045
4068
  onOpen("src");
@@ -4059,33 +4082,15 @@ function useTransferAction() {
4059
4082
  }
4060
4083
  };
4061
4084
  const disabled = isBusy || amountNum <= 0 || status === "loading" || isBalanceLoading || hasInsufficientBalance || hasAmountTooLarge || !gas.hasEnoughGas || noRoute || !isValidForTransfer;
4062
- return {
4063
- // состояния
4064
- isBusy,
4065
- canTransfer,
4066
- missingSrc,
4067
- missingDst,
4068
- hasEnoughGas: gas.hasEnoughGas,
4069
- noRoute,
4070
- // представление
4071
- label,
4072
- disabled,
4073
- // действие
4074
- onClick
4075
- };
4076
- }
4077
- const SubmitButton = () => {
4078
- const { label, disabled, onClick } = useTransferAction();
4079
- return /* @__PURE__ */ jsxRuntime.jsx(Button, { onClick, disabled, size: "lg", children: label });
4085
+ return /* @__PURE__ */ jsxRuntime.jsx(Button, { onClick: handleClick, disabled, className: "w-full", children: label });
4080
4086
  };
4081
4087
  function short(addr) {
4082
4088
  return addr.slice(0, 4) + "…" + addr.slice(-4);
4083
4089
  }
4084
- const WalletSelectModal = ({
4085
- modalContainer
4086
- }) => {
4090
+ const WalletSelectModal = () => {
4087
4091
  const { t } = reactI18next.useTranslation();
4088
4092
  const { isOpen, onClose } = useWalletSelectModal();
4093
+ const { connect, connectors, isPending } = wagmi.useConnect();
4089
4094
  const { chainRegistry } = useChainStrategies();
4090
4095
  const tonWallet = chainRegistry.getStrategyByType("ton");
4091
4096
  const metaMaskWallet = chainRegistry.getStrategyByType("evm");
@@ -4118,7 +4123,13 @@ const WalletSelectModal = ({
4118
4123
  onDisconnect: () => tronWallet.disconnect()
4119
4124
  });
4120
4125
  }
4121
- const isWalletConnected = (walletId) => connectedWallets.some((w) => w.id === walletId);
4126
+ const isWalletConnected = (walletId) => {
4127
+ const isEvmConnector = connectors.some((c) => c.id === walletId);
4128
+ if (isEvmConnector && metaMaskWallet?.isConnected()) {
4129
+ return true;
4130
+ }
4131
+ return connectedWallets.some((w) => w.id === walletId);
4132
+ };
4122
4133
  const tonWallets = [
4123
4134
  {
4124
4135
  id: "ton",
@@ -4127,14 +4138,15 @@ const WalletSelectModal = ({
4127
4138
  enabled: true
4128
4139
  }
4129
4140
  ];
4130
- const evmWallets = [
4131
- {
4132
- id: "metamask",
4133
- name: t("wallets.metaMask"),
4134
- icon: MetaMaskIcon,
4135
- enabled: true
4136
- }
4137
- ];
4141
+ const evmWallets = connectors.filter(
4142
+ (connector) => connector.id === "walletConnect" || connector.id === "metaMaskSDK"
4143
+ ).map((connector) => ({
4144
+ id: connector.id,
4145
+ name: connector.name,
4146
+ icon: MetaMaskIcon,
4147
+ // You can add a WalletConnect icon here
4148
+ enabled: true
4149
+ }));
4138
4150
  const tronWallets = [
4139
4151
  {
4140
4152
  id: "tronlink",
@@ -4164,9 +4176,6 @@ const WalletSelectModal = ({
4164
4176
  case "ton":
4165
4177
  await tonWallet?.connect();
4166
4178
  break;
4167
- case "metamask":
4168
- await metaMaskWallet?.connect();
4169
- break;
4170
4179
  case "tronlink":
4171
4180
  await tronWallet?.connect();
4172
4181
  break;
@@ -4178,7 +4187,7 @@ const WalletSelectModal = ({
4178
4187
  console.error("Failed to connect wallet:", error);
4179
4188
  }
4180
4189
  };
4181
- return /* @__PURE__ */ jsxRuntime.jsx(Modal, { isOpen, onClose, modalContainer, children: /* @__PURE__ */ jsxRuntime.jsxs(ModalContent, { children: [
4190
+ return /* @__PURE__ */ jsxRuntime.jsx(Modal, { isOpen, onClose, children: /* @__PURE__ */ jsxRuntime.jsxs(ModalContent, { children: [
4182
4191
  /* @__PURE__ */ jsxRuntime.jsxs(ModalHeader, { children: [
4183
4192
  /* @__PURE__ */ jsxRuntime.jsx(ModalTitle, { children: t("wallets.chooseWallet", { defaultValue: "Choose wallet" }) }),
4184
4193
  /* @__PURE__ */ jsxRuntime.jsx(ModalDescription, { children: t("wallets.oneWalletPerEnv", {
@@ -4191,56 +4200,47 @@ const WalletSelectModal = ({
4191
4200
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-5 py-2 leading-4 text-base font-semibold text-muted-foreground uppercase", children: t("wallets.connected") }),
4192
4201
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "", children: connectedWallets.map((wallet) => {
4193
4202
  const IconComponent = wallet.icon;
4194
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "", children: /* @__PURE__ */ jsxRuntime.jsxs(
4195
- Button,
4196
- {
4197
- 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]",
4198
- children: [
4199
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-3 min-w-0", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2.5", children: [
4200
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-7.5 h-7.5 flex items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(IconComponent, { className: "size-7.5" }) }),
4201
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-start min-w-0", children: [
4202
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-extrabold text-foreground text-sm leading-4 truncate", children: short(wallet.address) }),
4203
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs leading-3 font-semibold text-muted-foreground", children: wallet.name })
4204
- ] })
4205
- ] }) }),
4206
- /* @__PURE__ */ jsxRuntime.jsx("div", { onClick: () => {
4203
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "", children: /* @__PURE__ */ jsxRuntime.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: [
4204
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-3 min-w-0", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2.5", children: [
4205
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-7.5 h-7.5 flex items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(IconComponent, { className: "size-7.5" }) }),
4206
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-start min-w-0", children: [
4207
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-extrabold text-foreground text-sm leading-4 truncate", children: short(wallet.address) }),
4208
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs leading-3 font-semibold text-muted-foreground", children: wallet.name })
4209
+ ] })
4210
+ ] }) }),
4211
+ /* @__PURE__ */ jsxRuntime.jsx(
4212
+ "div",
4213
+ {
4214
+ onClick: () => {
4207
4215
  wallet.onDisconnect();
4208
4216
  onClose();
4209
- }, className: "text-sm font-medium text-muted-foreground", children: /* @__PURE__ */ jsxRuntime.jsx(ExitIcon, { className: "text-[#808080] size-6" }) })
4210
- ]
4211
- }
4212
- ) }, wallet.id);
4217
+ },
4218
+ className: "text-sm font-medium text-muted-foreground",
4219
+ children: /* @__PURE__ */ jsxRuntime.jsx(ExitIcon, { className: "text-[#808080] size-6" })
4220
+ }
4221
+ )
4222
+ ] }) }, wallet.id);
4213
4223
  }) })
4214
4224
  ] }),
4215
4225
  categories.map((category) => /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
4216
4226
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-5 py-2 leading-4 text-base font-semibold text-muted-foreground uppercase", children: category.title }),
4217
4227
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "", children: category.wallets.map((wallet) => {
4218
4228
  const IconComponent = wallet.icon;
4219
- if (wallet.id === "metamask") {
4220
- return /* @__PURE__ */ jsxRuntime.jsx("div", { id: wallet.id, children: /* @__PURE__ */ jsxRuntime.jsx(connectkit.ConnectKitButton.Custom, { children: ({ isConnecting, show }) => {
4221
- return /* @__PURE__ */ jsxRuntime.jsx(
4222
- Button,
4223
- {
4224
- type: "button",
4225
- onClick: show,
4226
- disabled: isConnecting,
4227
- 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",
4228
- children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 min-w-0", children: [
4229
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-7.5 h-7.5 flex items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(IconComponent, { className: "size-7.5" }) }),
4230
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-start min-w-0", children: [
4231
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-extrabold text-foreground text-sm leading-4 truncate", children: wallet.name }),
4232
- wallet.comingSoon ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs leading-3 font-semibold text-muted-foreground", children: t("wallets.comingSoon") }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs leading-3 font-semibold text-muted-foreground", children: t("wallets.connect") })
4233
- ] })
4234
- ] })
4235
- }
4236
- );
4237
- } }) }, wallet.id);
4238
- }
4229
+ const isEvmConnector = category.title === t("wallets.evmWallets");
4230
+ const connector = isEvmConnector ? connectors.find((c) => c.id === wallet.id) : null;
4239
4231
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "", children: /* @__PURE__ */ jsxRuntime.jsx(
4240
4232
  Button,
4241
4233
  {
4242
- onClick: () => handleWalletSelect(wallet.id),
4243
- disabled: !wallet.enabled,
4234
+ type: "button",
4235
+ onClick: () => {
4236
+ if (connector) {
4237
+ connect({ connector });
4238
+ onClose();
4239
+ } else {
4240
+ handleWalletSelect(wallet.id);
4241
+ }
4242
+ },
4243
+ disabled: isEvmConnector ? isPending : !wallet.enabled,
4244
4244
  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",
4245
4245
  children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 min-w-0", children: [
4246
4246
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-7.5 h-7.5 flex items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(IconComponent, { className: "size-7.5" }) }),
@@ -4256,39 +4256,6 @@ const WalletSelectModal = ({
4256
4256
  ] })
4257
4257
  ] }) });
4258
4258
  };
4259
- function Card({ className, ...props }) {
4260
- return /* @__PURE__ */ jsxRuntime.jsx(
4261
- "div",
4262
- {
4263
- "data-slot": "card",
4264
- className: cn(
4265
- "bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm",
4266
- className
4267
- ),
4268
- ...props
4269
- }
4270
- );
4271
- }
4272
- function CardContent({ className, ...props }) {
4273
- return /* @__PURE__ */ jsxRuntime.jsx(
4274
- "div",
4275
- {
4276
- "data-slot": "card-content",
4277
- className: cn("px-6", className),
4278
- ...props
4279
- }
4280
- );
4281
- }
4282
- function CardFooter({ className, ...props }) {
4283
- return /* @__PURE__ */ jsxRuntime.jsx(
4284
- "div",
4285
- {
4286
- "data-slot": "card-footer",
4287
- className: cn("flex items-center px-6 [.border-t]:pt-6", className),
4288
- ...props
4289
- }
4290
- );
4291
- }
4292
4259
  const TransactionProgressVector = (props) => {
4293
4260
  return /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "200", height: "200", viewBox: "0 0 200 200", fill: "none", xmlns: "http://www.w3.org/2000/svg", ...props, children: [
4294
4261
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -6213,7 +6180,7 @@ const ConfirmStep = () => {
6213
6180
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-3xl font-black relative z-10", children: formatTime })
6214
6181
  ] }) });
6215
6182
  };
6216
- const TransactionManager = ({ modalContainer }) => {
6183
+ const TransactionManager = () => {
6217
6184
  const { current } = useTransactionStore();
6218
6185
  const status = current?.status;
6219
6186
  if (!status || status === "idle") return null;
@@ -6231,7 +6198,7 @@ const TransactionManager = ({ modalContainer }) => {
6231
6198
  step = /* @__PURE__ */ jsxRuntime.jsx(SuccessStep, {});
6232
6199
  }
6233
6200
  return /* @__PURE__ */ jsxRuntime.jsx(Modal, { isOpen: true, onClose: () => {
6234
- }, modalContainer, children: step });
6201
+ }, children: step });
6235
6202
  };
6236
6203
  const useTokensRequest = () => {
6237
6204
  const { setTokens, setSelectedToken, setSelectedAssetSymbol } = useTokensStore();
@@ -6352,6 +6319,49 @@ class ChainStrategyRegistry {
6352
6319
  await strategy.disconnect();
6353
6320
  }
6354
6321
  }
6322
+ const EVM_CONFIG = {
6323
+ usdtAddress: "0xdAC17F958D2ee523a2206206994597C13D831ec7",
6324
+ gasEstimates: {
6325
+ approve: 65000n,
6326
+ bridge: 300000n
6327
+ },
6328
+ gasBuffer: 1.2,
6329
+ // 20% buffer
6330
+ timeout: 3e5,
6331
+ // 5 minutes (increased for slower networks)
6332
+ requiredConfirmations: 3
6333
+ // Wait for 3 confirmations for reorg protection
6334
+ };
6335
+ const TON_CONFIG = {
6336
+ apiUrl: "https://toncenter.com/api/v2",
6337
+ timeout: 36e4,
6338
+ // 6 minutes
6339
+ validUntil: 600
6340
+ // 10 minutes
6341
+ };
6342
+ const TRON_CONFIG = {
6343
+ timeout: 12e4,
6344
+ // 2 minutes (for 19 confirmations)
6345
+ feeLimit: 1e8,
6346
+ // 100 TRX in sun
6347
+ requiredConfirmations: 19,
6348
+ // TRON standard: 19 blocks for confirmation
6349
+ pollingInterval: 3e3
6350
+ // 3 seconds between checks
6351
+ };
6352
+ let tonClientInstance = null;
6353
+ function getTonClient(customClient, apiKey) {
6354
+ if (customClient) {
6355
+ return customClient;
6356
+ }
6357
+ if (!tonClientInstance) {
6358
+ tonClientInstance = new ton.TonClient({
6359
+ endpoint: `${TON_CONFIG.apiUrl}/jsonRPC`,
6360
+ apiKey
6361
+ });
6362
+ }
6363
+ return tonClientInstance;
6364
+ }
6355
6365
  function isNativeAddress(addr) {
6356
6366
  if (!addr) return false;
6357
6367
  const a = addr.toLowerCase();
@@ -6377,44 +6387,72 @@ function formatUnitsFromBigIntStr(valueStr, decimals) {
6377
6387
  const tail = s.slice(s.length - decimals).replace(/0+$/, "");
6378
6388
  return Number(tail ? `${head}.${tail}` : head);
6379
6389
  }
6380
- async function getEvmBalances(address, tokens) {
6390
+ function isTonFriendlyAddress(address) {
6391
+ return !!address && /^[A-Za-z0-9_-]{48,}$/.test(address);
6392
+ }
6393
+ function normalizeTickerSymbol(symbol) {
6394
+ return symbol.toUpperCase().replace(/₮/g, "T").replace(/[^A-Z0-9]/g, "");
6395
+ }
6396
+ function parseTonAddress(address) {
6397
+ if (address.startsWith("0x")) {
6398
+ const hex = address.slice(2);
6399
+ return ton.Address.parseRaw(`0:${hex}`);
6400
+ }
6401
+ if (address.includes(":")) {
6402
+ return ton.Address.parseRaw(address);
6403
+ }
6404
+ return ton.Address.parse(address);
6405
+ }
6406
+ async function getEvmBalances(publicClient, address, tokens) {
6381
6407
  const balances = {};
6382
6408
  try {
6383
- if (!address || !ethers.ethers.isAddress(address)) {
6409
+ console.log("start getEvmBalances");
6410
+ console.log("publicClient:", publicClient);
6411
+ console.log("isAddress:", viem.isAddress(address));
6412
+ console.log("tokens:", tokens);
6413
+ if (!address || !viem.isAddress(address)) {
6384
6414
  console.warn(`Invalid EVM address provided: ${address}`);
6385
6415
  return balances;
6386
6416
  }
6387
- if (typeof window === "undefined" || !window.ethereum) {
6388
- throw new Error("No ethereum provider found");
6417
+ if (!publicClient) {
6418
+ throw new Error("No public client provided");
6389
6419
  }
6390
- const provider = new ethers.ethers.BrowserProvider(window.ethereum);
6391
6420
  for (const token of tokens) {
6392
6421
  try {
6393
6422
  let balance = 0;
6394
6423
  const isNative = isNativeAddress(token.address);
6395
6424
  if (isNative) {
6396
- const ethBalance = await provider.getBalance(address);
6397
- balance = parseFloat(ethers.ethers.formatUnits(ethBalance, token.decimals));
6425
+ const ethBalance = await publicClient.getBalance({
6426
+ address
6427
+ });
6428
+ balance = parseFloat(viem.formatUnits(ethBalance, token.decimals));
6398
6429
  } else {
6399
- if (!ethers.ethers.isAddress(token.address)) {
6430
+ if (!viem.isAddress(token.address)) {
6400
6431
  continue;
6401
6432
  }
6402
- const code = await provider.getCode(token.address);
6403
- if (code === "0x") {
6433
+ const bytecode = await publicClient.getBytecode({
6434
+ address: token.address
6435
+ });
6436
+ if (!bytecode || bytecode === "0x") {
6404
6437
  continue;
6405
6438
  }
6406
- const contract = new ethers.ethers.Contract(
6407
- token.address,
6408
- [
6409
- "function balanceOf(address owner) view returns (uint256)",
6410
- "function decimals() view returns (uint8)"
6411
- ],
6412
- provider
6413
- );
6414
6439
  try {
6415
- const tokenBalance = await contract.balanceOf(address);
6440
+ const tokenBalance = await publicClient.readContract({
6441
+ address: token.address,
6442
+ abi: [
6443
+ {
6444
+ name: "balanceOf",
6445
+ type: "function",
6446
+ stateMutability: "view",
6447
+ inputs: [{ name: "owner", type: "address" }],
6448
+ outputs: [{ name: "balance", type: "uint256" }]
6449
+ }
6450
+ ],
6451
+ functionName: "balanceOf",
6452
+ args: [address]
6453
+ });
6416
6454
  balance = parseFloat(
6417
- ethers.ethers.formatUnits(tokenBalance, token.decimals)
6455
+ viem.formatUnits(tokenBalance, token.decimals)
6418
6456
  );
6419
6457
  } catch {
6420
6458
  continue;
@@ -6437,6 +6475,68 @@ async function getEvmBalances(address, tokens) {
6437
6475
  }
6438
6476
  return balances;
6439
6477
  }
6478
+ async function getTonBalances(address, tokens, customTonClient, tonApiKey) {
6479
+ const balances = {};
6480
+ try {
6481
+ if (!isTonFriendlyAddress(address)) {
6482
+ console.warn(`Invalid TON address provided: ${address}`);
6483
+ return balances;
6484
+ }
6485
+ const client = getTonClient(customTonClient, tonApiKey);
6486
+ const accountAddress = ton.Address.parse(address);
6487
+ console.log(address);
6488
+ console.log(tokens);
6489
+ try {
6490
+ const balance = await client.getBalance(accountAddress);
6491
+ const tonBalance = Number(balance) / 1e9;
6492
+ console.log("tonBalance", tonBalance);
6493
+ if (tonBalance > 0) {
6494
+ balances.TON = { balance: tonBalance, address: "ton-native" };
6495
+ }
6496
+ } catch (error) {
6497
+ console.warn("Failed to get native TON balance:", error);
6498
+ }
6499
+ for (const token of tokens) {
6500
+ try {
6501
+ if (isNativeAddress(token.address) || token.symbol.toUpperCase() === "TON") {
6502
+ continue;
6503
+ }
6504
+ const jettonMasterAddress = parseTonAddress(token.address);
6505
+ const jettonWalletAddress = await client.runMethod(
6506
+ jettonMasterAddress,
6507
+ "get_wallet_address",
6508
+ [
6509
+ {
6510
+ type: "slice",
6511
+ cell: ton.beginCell().storeAddress(accountAddress).endCell()
6512
+ }
6513
+ ]
6514
+ );
6515
+ const jettonWalletAddr = jettonWalletAddress.stack.readAddress();
6516
+ const jettonData = await client.runMethod(
6517
+ jettonWalletAddr,
6518
+ "get_wallet_data"
6519
+ );
6520
+ const jettonBalance = jettonData.stack.readBigNumber();
6521
+ const humanBalance = Number(jettonBalance) / Math.pow(10, token.decimals);
6522
+ if (humanBalance > 0) {
6523
+ const symbolUpper = token.symbol.toUpperCase();
6524
+ const symbolNorm = normalizeTickerSymbol(symbolUpper);
6525
+ const entry = { balance: humanBalance, address: token.address };
6526
+ balances[symbolUpper] = entry;
6527
+ if (symbolNorm !== symbolUpper) {
6528
+ balances[symbolNorm] = entry;
6529
+ }
6530
+ }
6531
+ } catch (error) {
6532
+ console.debug(`Failed to get balance for ${token.symbol}:`, error);
6533
+ }
6534
+ }
6535
+ } catch (error) {
6536
+ console.error("Failed to get TON balances:", error);
6537
+ }
6538
+ return balances;
6539
+ }
6440
6540
  async function getTronBalances(tronWeb, address, tokens) {
6441
6541
  const balances = {};
6442
6542
  try {
@@ -6480,30 +6580,6 @@ async function getTronBalances(tronWeb, address, tokens) {
6480
6580
  }
6481
6581
  return balances;
6482
6582
  }
6483
- const EVM_CONFIG = {
6484
- usdtAddress: "0xdAC17F958D2ee523a2206206994597C13D831ec7",
6485
- gasEstimates: {
6486
- approve: 65000n,
6487
- bridge: 300000n
6488
- },
6489
- gasBuffer: 1.2,
6490
- // 20% buffer
6491
- timeout: 12e4
6492
- // 2 minutes
6493
- };
6494
- const TON_CONFIG = {
6495
- apiUrl: "https://toncenter.com/api/v2",
6496
- timeout: 36e4,
6497
- // 6 minutes
6498
- validUntil: 600
6499
- // 10 minutes
6500
- };
6501
- const TRON_CONFIG = {
6502
- timeout: 6e4,
6503
- // 1 minute
6504
- feeLimit: 1e8
6505
- // 100 TRX in sun
6506
- };
6507
6583
  const ERC20_ABI = [
6508
6584
  "function approve(address spender, uint256 amount) returns (bool)",
6509
6585
  "function allowance(address owner, address spender) view returns (uint256)",
@@ -6514,7 +6590,9 @@ class EvmChainStrategy {
6514
6590
  constructor(config) {
6515
6591
  __publicField(this, "config");
6516
6592
  __publicField(this, "provider");
6593
+ __publicField(this, "publicClient");
6517
6594
  this.config = config;
6595
+ this.publicClient = config.publicClient;
6518
6596
  if (config.walletClient) {
6519
6597
  this.provider = new ethers.BrowserProvider(config.walletClient.transport);
6520
6598
  }
@@ -6553,7 +6631,11 @@ class EvmChainStrategy {
6553
6631
  return t("wallets.connectEvmWallet");
6554
6632
  }
6555
6633
  async getBalances(address, tokens) {
6556
- return await getEvmBalances(address, tokens);
6634
+ if (!this.publicClient) {
6635
+ console.warn("No publicClient available for balance query");
6636
+ return {};
6637
+ }
6638
+ return await getEvmBalances(this.publicClient, address, tokens);
6557
6639
  }
6558
6640
  isAddressValid(address) {
6559
6641
  if (!address) return false;
@@ -6666,17 +6748,14 @@ class EvmChainStrategy {
6666
6748
  if (!provider) {
6667
6749
  throw new ProviderNotAvailableError("evm");
6668
6750
  }
6669
- const deadline = Date.now() + EVM_CONFIG.timeout;
6670
- let receipt = null;
6671
- while (Date.now() < deadline) {
6672
- try {
6673
- receipt = await provider.getTransactionReceipt(txHash);
6674
- if (receipt) break;
6675
- } catch (e) {
6676
- console.debug("Error fetching receipt:", e);
6677
- }
6678
- await new Promise((r) => setTimeout(r, 2500));
6679
- }
6751
+ console.log(
6752
+ `Waiting for ${EVM_CONFIG.requiredConfirmations} confirmations for tx: ${txHash}`
6753
+ );
6754
+ const receipt = await provider.waitForTransaction(
6755
+ txHash,
6756
+ EVM_CONFIG.requiredConfirmations,
6757
+ EVM_CONFIG.timeout
6758
+ );
6680
6759
  if (!receipt) {
6681
6760
  const error = new TransactionTimeoutError("evm", txHash);
6682
6761
  return {
@@ -6691,11 +6770,35 @@ class EvmChainStrategy {
6691
6770
  error: error.message
6692
6771
  };
6693
6772
  }
6694
- console.log("EVM transaction confirmed on-chain");
6773
+ console.log(
6774
+ `EVM transaction confirmed in block ${receipt.blockNumber} with ${EVM_CONFIG.requiredConfirmations} confirmations`
6775
+ );
6695
6776
  return {
6696
6777
  completed: true
6697
6778
  };
6698
6779
  } catch (error) {
6780
+ if (error && typeof error === "object" && "code" in error && error.code === "TRANSACTION_REPLACED") {
6781
+ console.log(
6782
+ `Transaction was replaced: ${"reason" in error ? String(error.reason) : "unknown"}`
6783
+ );
6784
+ if ("receipt" in error && error.receipt) {
6785
+ const replacementReceipt = error.receipt;
6786
+ if (replacementReceipt.status === 1) {
6787
+ console.log(
6788
+ `Replacement transaction succeeded in block ${replacementReceipt.blockNumber}`
6789
+ );
6790
+ return {
6791
+ completed: true
6792
+ };
6793
+ } else {
6794
+ const chainError2 = new TransactionRevertedError("evm", txHash);
6795
+ return {
6796
+ completed: false,
6797
+ error: chainError2.message
6798
+ };
6799
+ }
6800
+ }
6801
+ }
6699
6802
  const chainError = toChainStrategyError(
6700
6803
  error,
6701
6804
  "evm",
@@ -6809,13 +6912,52 @@ class EvmChainStrategy {
6809
6912
  return false;
6810
6913
  }
6811
6914
  }
6915
+ /**
6916
+ * Check if a block has reached finality status (optional, for critical transactions)
6917
+ * This is more stringent than confirmations and protects against long-range reorgs
6918
+ *
6919
+ * Usage: Call this method after waitForCompletion if you need additional security
6920
+ * for high-value transactions. The method checks if the block has been marked as
6921
+ * "finalized" by the Ethereum consensus layer (2/3 of validators).
6922
+ *
6923
+ * @param blockNumber - The block number to check for finality
6924
+ * @returns true if the block is finalized, false otherwise
6925
+ */
6926
+ async checkFinality(blockNumber) {
6927
+ try {
6928
+ const provider = this.provider;
6929
+ if (!provider) {
6930
+ return false;
6931
+ }
6932
+ const finalizedBlock = await provider.getBlock("finalized");
6933
+ if (!finalizedBlock) {
6934
+ console.debug(
6935
+ "Finalized block not available (pre-merge or unsupported)"
6936
+ );
6937
+ return false;
6938
+ }
6939
+ const isFinalized = blockNumber <= finalizedBlock.number;
6940
+ if (isFinalized) {
6941
+ console.log(
6942
+ `Block ${blockNumber} has reached finality (finalized block: ${finalizedBlock.number})`
6943
+ );
6944
+ } else {
6945
+ console.debug(
6946
+ `Block ${blockNumber} not yet finalized (finalized block: ${finalizedBlock.number})`
6947
+ );
6948
+ }
6949
+ return isFinalized;
6950
+ } catch (error) {
6951
+ console.debug("Error checking finality:", error);
6952
+ return false;
6953
+ }
6954
+ }
6812
6955
  }
6813
6956
  class TonChainStrategy {
6814
6957
  constructor(config) {
6815
6958
  __publicField(this, "config");
6816
6959
  this.config = config;
6817
6960
  }
6818
- // ========== Identity ==========
6819
6961
  canHandle(chainKey) {
6820
6962
  return chainKey.toLowerCase() === "ton";
6821
6963
  }
@@ -6825,7 +6967,6 @@ class TonChainStrategy {
6825
6967
  getName() {
6826
6968
  return "TON Chain Strategy";
6827
6969
  }
6828
- // ========== Wallet Management ==========
6829
6970
  async connect() {
6830
6971
  await this.config.tonConnectUI?.openModal();
6831
6972
  }
@@ -6850,17 +6991,26 @@ class TonChainStrategy {
6850
6991
  getConnectLabel(t) {
6851
6992
  return t("wallets.connectTonWallet");
6852
6993
  }
6853
- // ========== Balance & Validation ==========
6854
- async getBalances(address) {
6855
- return await getSwapBalances(address);
6994
+ async getBalances(address, tokens) {
6995
+ return await getTonBalances(
6996
+ address,
6997
+ tokens,
6998
+ this.config.tonClient,
6999
+ this.config.tonApiKey
7000
+ );
6856
7001
  }
6857
7002
  isAddressValid(address) {
6858
7003
  if (!address) return false;
6859
7004
  return true;
6860
7005
  }
6861
- // ========== Gas Estimation ==========
6862
7006
  async estimateGasRequirement(params) {
6863
- const { selectedToken, nativeTokenSymbol, amount, balances, reserveFallback } = params;
7007
+ const {
7008
+ selectedToken,
7009
+ nativeTokenSymbol,
7010
+ amount,
7011
+ balances,
7012
+ reserveFallback
7013
+ } = params;
6864
7014
  const nativeSym = nativeTokenSymbol.toUpperCase();
6865
7015
  const isNativeSelected = nativeSym === (selectedToken?.symbol ?? "").toUpperCase();
6866
7016
  const nativeBalance = Number(balances[nativeSym]?.balance ?? 0);
@@ -6882,7 +7032,6 @@ class TonChainStrategy {
6882
7032
  isNativeSelected
6883
7033
  };
6884
7034
  }
6885
- // ========== Transaction Execution ==========
6886
7035
  validateSteps(steps) {
6887
7036
  if (!steps || steps.length === 0) {
6888
7037
  throw new InvalidStepsError("ton", "No transaction steps provided");
@@ -6935,19 +7084,17 @@ class TonChainStrategy {
6935
7084
  const result = await this.config.tonConnectUI.sendTransaction(
6936
7085
  transaction
6937
7086
  );
6938
- const hash = this.getTxHash(result.boc);
6939
7087
  return {
6940
7088
  chainKey: "ton",
6941
- hash
7089
+ hash: result.boc
6942
7090
  };
6943
7091
  } catch (error) {
6944
7092
  throw toChainStrategyError(error, "ton", "transaction");
6945
7093
  }
6946
7094
  }
6947
- async waitForCompletion(txHash, context) {
7095
+ async waitForCompletion(txHash) {
6948
7096
  try {
6949
7097
  const confirmed = await this.checkTonTransaction(
6950
- context.srcAddress,
6951
7098
  txHash,
6952
7099
  TON_CONFIG.timeout
6953
7100
  );
@@ -6977,39 +7124,78 @@ class TonChainStrategy {
6977
7124
  };
6978
7125
  }
6979
7126
  }
6980
- // ========== Private Helper Methods ==========
6981
- getTxHash(boc) {
6982
- const cell = core.Cell.fromBase64(boc);
6983
- const buffer = cell.hash();
6984
- return buffer.toString("hex");
7127
+ getNormalizedExtMessageHash(message) {
7128
+ if (message.info.type !== "external-in") {
7129
+ throw new Error(`Expected external-in message, got ${message.info.type}`);
7130
+ }
7131
+ const normalizedInfo = {
7132
+ ...message.info,
7133
+ src: void 0,
7134
+ importFee: 0n
7135
+ };
7136
+ const normalizedMessage = {
7137
+ ...message,
7138
+ info: normalizedInfo,
7139
+ init: null
7140
+ };
7141
+ return core.beginCell().store(core.storeMessage(normalizedMessage, { forceRef: true })).endCell().hash();
6985
7142
  }
6986
- async checkTonTransaction(address, txHash, timeoutMs = 36e4) {
7143
+ async checkTonTransaction(bocBase64, timeoutMs = 36e4) {
6987
7144
  const deadline = Date.now() + timeoutMs;
6988
- const normalizedHash = txHash.toLowerCase();
6989
- while (Date.now() < deadline) {
6990
- try {
6991
- const response = await fetch(
6992
- `${TON_CONFIG.apiUrl}/getTransactions?address=${address}&limit=20`
7145
+ const client = getTonClient(this.config.tonClient, this.config.tonApiKey);
7146
+ try {
7147
+ const inMessage = core.loadMessage(core.Cell.fromBase64(bocBase64).beginParse());
7148
+ if (inMessage.info.type !== "external-in") {
7149
+ console.debug(
7150
+ "Expected external-in message, got:",
7151
+ inMessage.info.type
6993
7152
  );
6994
- if (!response.ok) {
6995
- console.debug("TonCenter API error:", response.status);
6996
- await new Promise((r) => setTimeout(r, 3e3));
6997
- continue;
6998
- }
6999
- const data = await response.json();
7000
- const transactions = data.result || [];
7001
- for (const tx of transactions) {
7002
- const txIdHash = tx.transaction_id?.hash;
7003
- if (txIdHash && txIdHash.toLowerCase() === normalizedHash) {
7004
- return true;
7153
+ return false;
7154
+ }
7155
+ const accountAddress = inMessage.info.dest;
7156
+ const targetMessageHash = this.getNormalizedExtMessageHash(inMessage);
7157
+ let lt = void 0;
7158
+ let hash = void 0;
7159
+ while (Date.now() < deadline) {
7160
+ try {
7161
+ const transactions = await client.getTransactions(accountAddress, {
7162
+ lt,
7163
+ hash,
7164
+ limit: 10,
7165
+ archival: true
7166
+ });
7167
+ if (transactions.length === 0) {
7168
+ await new Promise((r) => setTimeout(r, 3e3));
7169
+ lt = void 0;
7170
+ hash = void 0;
7171
+ continue;
7005
7172
  }
7173
+ for (const tx of transactions) {
7174
+ if (tx.inMessage?.info.type === "external-in") {
7175
+ const txInMessageHash = this.getNormalizedExtMessageHash(
7176
+ tx.inMessage
7177
+ );
7178
+ if (txInMessageHash.equals(targetMessageHash)) {
7179
+ console.debug("Transaction found by in-message hash");
7180
+ return true;
7181
+ }
7182
+ }
7183
+ }
7184
+ const lastTx = transactions[transactions.length - 1];
7185
+ lt = lastTx.lt.toString();
7186
+ hash = lastTx.hash().toString("base64");
7187
+ } catch (error) {
7188
+ console.debug("Error fetching transactions:", error);
7189
+ await new Promise((r) => setTimeout(r, 3e3));
7190
+ lt = void 0;
7191
+ hash = void 0;
7006
7192
  }
7007
- } catch (e) {
7008
- console.debug("TonCenter polling error:", e);
7009
7193
  }
7010
- await new Promise((r) => setTimeout(r, 3e3));
7194
+ return false;
7195
+ } catch (error) {
7196
+ console.debug("Error parsing BOC or checking transaction:", error);
7197
+ return false;
7011
7198
  }
7012
- return false;
7013
7199
  }
7014
7200
  }
7015
7201
  class TronChainStrategy {
@@ -7070,7 +7256,13 @@ class TronChainStrategy {
7070
7256
  }
7071
7257
  // ========== Gas Estimation ==========
7072
7258
  async estimateGasRequirement(params) {
7073
- const { selectedToken, nativeTokenSymbol, amount, balances, reserveFallback } = params;
7259
+ const {
7260
+ selectedToken,
7261
+ nativeTokenSymbol,
7262
+ amount,
7263
+ balances,
7264
+ reserveFallback
7265
+ } = params;
7074
7266
  const nativeSym = nativeTokenSymbol.toUpperCase();
7075
7267
  const isNativeSelected = nativeSym === (selectedToken?.symbol ?? "").toUpperCase();
7076
7268
  const nativeBalance = Number(balances[nativeSym]?.balance ?? 0);
@@ -7092,7 +7284,6 @@ class TronChainStrategy {
7092
7284
  isNativeSelected
7093
7285
  };
7094
7286
  }
7095
- // ========== Transaction Execution ==========
7096
7287
  validateSteps(steps) {
7097
7288
  console.log("validateSteps");
7098
7289
  if (!steps?.length) {
@@ -7127,7 +7318,10 @@ class TronChainStrategy {
7127
7318
  if (String(step.chainKey).toLowerCase() !== "tron") continue;
7128
7319
  const tx = step.transaction;
7129
7320
  if (!tx) {
7130
- throw new InvalidTransactionDataError("tron", "Missing transaction data");
7321
+ throw new InvalidTransactionDataError(
7322
+ "tron",
7323
+ "Missing transaction data"
7324
+ );
7131
7325
  }
7132
7326
  const hexData = typeof tx?.data === "string" ? tx.data : "";
7133
7327
  const parsed = this.parseTronStep(step, tx, hexData);
@@ -7178,13 +7372,19 @@ class TronChainStrategy {
7178
7372
  break;
7179
7373
  }
7180
7374
  default:
7181
- throw new InvalidStepsError("tron", "Unsupported TRON parsed tx kind");
7375
+ throw new InvalidStepsError(
7376
+ "tron",
7377
+ "Unsupported TRON parsed tx kind"
7378
+ );
7182
7379
  }
7183
7380
  const { txid } = await this.signAndBroadcast(tronWeb, unsigned);
7184
7381
  lastTxId = txid;
7185
7382
  }
7186
7383
  if (!lastTxId) {
7187
- throw new TransactionFailedError("tron", "No TRON transaction was executed");
7384
+ throw new TransactionFailedError(
7385
+ "tron",
7386
+ "No TRON transaction was executed"
7387
+ );
7188
7388
  }
7189
7389
  return { hash: lastTxId, chainKey: "tron" };
7190
7390
  }
@@ -7194,47 +7394,84 @@ class TronChainStrategy {
7194
7394
  if (!tronWeb) {
7195
7395
  throw new ProviderNotAvailableError("tron");
7196
7396
  }
7397
+ console.log(
7398
+ `Waiting for ${TRON_CONFIG.requiredConfirmations} confirmations for TRON tx: ${txHash}`
7399
+ );
7197
7400
  const deadline = Date.now() + TRON_CONFIG.timeout;
7198
- while (Date.now() < deadline) {
7401
+ let txBlockNumber = null;
7402
+ while (Date.now() < deadline && !txBlockNumber) {
7199
7403
  try {
7200
7404
  const info = await tronWeb.trx.getTransactionInfo(txHash);
7201
- console.log("TRON transaction info:", info);
7202
- if (info) {
7405
+ if (info && info.blockNumber) {
7203
7406
  const result = info.receipt?.result;
7204
- if (result === "SUCCESS") {
7205
- console.log("TRON transaction confirmed on-chain");
7407
+ if (result !== "SUCCESS") {
7408
+ const msg = this.hexToAscii(info.resMessage) || null;
7409
+ let reason = msg;
7410
+ const cr = info.contractResult?.[0];
7411
+ if (cr && /^0x?08c379a0/i.test(cr)) {
7412
+ try {
7413
+ const clean = cr.replace(/^0x/, "");
7414
+ const len = parseInt(clean.slice(8 + 64, 8 + 64 + 64), 16);
7415
+ const strHex = clean.slice(
7416
+ 8 + 64 + 64,
7417
+ 8 + 64 + 64 + len * 2
7418
+ );
7419
+ const str = this.hexToAscii("0x" + strHex);
7420
+ if (str) reason = str;
7421
+ } catch (e) {
7422
+ console.debug("TRON revert string decode error", e);
7423
+ }
7424
+ }
7425
+ const error2 = new TransactionRevertedError(
7426
+ "tron",
7427
+ txHash,
7428
+ reason || "Unknown error"
7429
+ );
7206
7430
  return {
7207
- completed: true
7431
+ completed: false,
7432
+ error: error2.message
7208
7433
  };
7209
7434
  }
7210
- const msg = this.hexToAscii(info.resMessage) || null;
7211
- let reason = msg;
7212
- const cr = info.contractResult?.[0];
7213
- if (cr && /^0x?08c379a0/i.test(cr)) {
7214
- try {
7215
- const clean = cr.replace(/^0x/, "");
7216
- const len = parseInt(clean.slice(8 + 64, 8 + 64 + 64), 16);
7217
- const strHex = clean.slice(8 + 64 + 64, 8 + 64 + 64 + len * 2);
7218
- const str = this.hexToAscii("0x" + strHex);
7219
- if (str) reason = str;
7220
- } catch (e) {
7221
- console.debug("TRON revert string decode error", e);
7222
- }
7435
+ txBlockNumber = info.blockNumber;
7436
+ console.log(`TRON transaction found in block ${txBlockNumber}`);
7437
+ }
7438
+ } catch (e) {
7439
+ console.debug("TRON getTransactionInfo error:", e);
7440
+ }
7441
+ if (!txBlockNumber) {
7442
+ await new Promise((r) => setTimeout(r, TRON_CONFIG.pollingInterval));
7443
+ }
7444
+ }
7445
+ if (!txBlockNumber) {
7446
+ const error2 = new TransactionTimeoutError("tron", txHash);
7447
+ return {
7448
+ completed: false,
7449
+ error: error2.message
7450
+ };
7451
+ }
7452
+ let confirmations = 0;
7453
+ while (Date.now() < deadline) {
7454
+ try {
7455
+ const currentBlock = await tronWeb.trx.getCurrentBlock();
7456
+ const currentBlockNumber = currentBlock?.block_header?.raw_data?.number;
7457
+ if (currentBlockNumber) {
7458
+ confirmations = currentBlockNumber - txBlockNumber;
7459
+ if (confirmations >= TRON_CONFIG.requiredConfirmations) {
7460
+ console.log(
7461
+ `TRON transaction confirmed in block ${txBlockNumber} with ${confirmations} confirmations`
7462
+ );
7463
+ return {
7464
+ completed: true
7465
+ };
7223
7466
  }
7224
- const error2 = new TransactionRevertedError(
7225
- "tron",
7226
- txHash,
7227
- reason || "Unknown error"
7467
+ console.log(
7468
+ `TRON transaction confirmations: ${confirmations}/${TRON_CONFIG.requiredConfirmations}`
7228
7469
  );
7229
- return {
7230
- completed: false,
7231
- error: error2.message
7232
- };
7233
7470
  }
7234
7471
  } catch (e) {
7235
- console.debug("TRON getTransactionInfo error:", e);
7472
+ console.debug("TRON getCurrentBlock error:", e);
7236
7473
  }
7237
- await new Promise((r) => setTimeout(r, 3e3));
7474
+ await new Promise((r) => setTimeout(r, TRON_CONFIG.pollingInterval));
7238
7475
  }
7239
7476
  const error = new TransactionTimeoutError("tron", txHash);
7240
7477
  return {
@@ -7242,14 +7479,17 @@ class TronChainStrategy {
7242
7479
  error: error.message
7243
7480
  };
7244
7481
  } catch (error) {
7245
- const chainError = toChainStrategyError(error, "tron", "waitForCompletion");
7482
+ const chainError = toChainStrategyError(
7483
+ error,
7484
+ "tron",
7485
+ "waitForCompletion"
7486
+ );
7246
7487
  return {
7247
7488
  completed: false,
7248
7489
  error: chainError.message
7249
7490
  };
7250
7491
  }
7251
7492
  }
7252
- // ========== Private Helper Methods ==========
7253
7493
  getTronWeb() {
7254
7494
  return typeof window !== "undefined" ? window.tronWeb : void 0;
7255
7495
  }
@@ -7302,7 +7542,10 @@ class TronChainStrategy {
7302
7542
  amount: this.extractAmountFromTxData(tx.data)
7303
7543
  };
7304
7544
  }
7305
- throw new InvalidTransactionDataError("tron", "Cannot parse approve transaction");
7545
+ throw new InvalidTransactionDataError(
7546
+ "tron",
7547
+ "Cannot parse approve transaction"
7548
+ );
7306
7549
  }
7307
7550
  if (step?.type === "transfer" || step?.type === "bridge") {
7308
7551
  const s = step;
@@ -7332,7 +7575,10 @@ class TronChainStrategy {
7332
7575
  feeLimit: raw2.feeLimit
7333
7576
  };
7334
7577
  }
7335
- throw new InvalidTransactionDataError("tron", "Cannot parse transfer/bridge transaction");
7578
+ throw new InvalidTransactionDataError(
7579
+ "tron",
7580
+ "Cannot parse transfer/bridge transaction"
7581
+ );
7336
7582
  }
7337
7583
  if (tx?.to && tx?.value && !tx?.data) {
7338
7584
  const v = BigInt(tx.value.toString());
@@ -7352,19 +7598,28 @@ class TronChainStrategy {
7352
7598
  feeLimit: raw.feeLimit
7353
7599
  };
7354
7600
  }
7355
- throw new InvalidTransactionDataError("tron", `Unsupported TRON step type: ${step?.type ?? "unknown"}`);
7601
+ throw new InvalidTransactionDataError(
7602
+ "tron",
7603
+ `Unsupported TRON step type: ${step?.type ?? "unknown"}`
7604
+ );
7356
7605
  }
7357
7606
  extractSpenderFromTxData(data) {
7358
7607
  const clean = data.replace(/^0x/, "");
7359
7608
  if (clean.length < 74) {
7360
- throw new InvalidTransactionDataError("tron", "Invalid transaction data length");
7609
+ throw new InvalidTransactionDataError(
7610
+ "tron",
7611
+ "Invalid transaction data length"
7612
+ );
7361
7613
  }
7362
7614
  return "41" + clean.slice(32, 72);
7363
7615
  }
7364
7616
  extractAmountFromTxData(data) {
7365
7617
  const clean = data.replace(/^0x/, "");
7366
7618
  if (clean.length < 138) {
7367
- throw new InvalidTransactionDataError("tron", "Invalid transaction data length");
7619
+ throw new InvalidTransactionDataError(
7620
+ "tron",
7621
+ "Invalid transaction data length"
7622
+ );
7368
7623
  }
7369
7624
  const amountHex = clean.slice(72, 136);
7370
7625
  return BigInt("0x" + amountHex).toString();
@@ -7372,7 +7627,10 @@ class TronChainStrategy {
7372
7627
  extractRecipientFromTxData(data) {
7373
7628
  const clean = data.replace(/^0x/, "");
7374
7629
  if (clean.length < 74) {
7375
- throw new InvalidTransactionDataError("tron", "Invalid transaction data length");
7630
+ throw new InvalidTransactionDataError(
7631
+ "tron",
7632
+ "Invalid transaction data length"
7633
+ );
7376
7634
  }
7377
7635
  return "41" + clean.slice(32, 72);
7378
7636
  }
@@ -7447,7 +7705,6 @@ class TronChainStrategy {
7447
7705
  return null;
7448
7706
  }
7449
7707
  }
7450
- // ========== Transaction Builders ==========
7451
7708
  async buildApprove(tronWeb, p) {
7452
7709
  const res = await tronWeb.transactionBuilder.triggerSmartContract(
7453
7710
  p.token,
@@ -7460,7 +7717,10 @@ class TronChainStrategy {
7460
7717
  p.from
7461
7718
  );
7462
7719
  if (!res?.transaction) {
7463
- throw new TransactionFailedError("tron", "Failed to build approve transaction");
7720
+ throw new TransactionFailedError(
7721
+ "tron",
7722
+ "Failed to build approve transaction"
7723
+ );
7464
7724
  }
7465
7725
  return res.transaction;
7466
7726
  }
@@ -7476,7 +7736,10 @@ class TronChainStrategy {
7476
7736
  p.from
7477
7737
  );
7478
7738
  if (!res?.transaction) {
7479
- throw new TransactionFailedError("tron", "Failed to build transfer transaction");
7739
+ throw new TransactionFailedError(
7740
+ "tron",
7741
+ "Failed to build transfer transaction"
7742
+ );
7480
7743
  }
7481
7744
  return res.transaction;
7482
7745
  }
@@ -7496,12 +7759,13 @@ class TronChainStrategy {
7496
7759
  p.from
7497
7760
  );
7498
7761
  if (!res?.transaction) {
7499
- throw new TransactionFailedError("tron", "Failed to build raw call transaction");
7762
+ throw new TransactionFailedError(
7763
+ "tron",
7764
+ "Failed to build raw call transaction"
7765
+ );
7500
7766
  }
7501
7767
  return res.transaction;
7502
7768
  }
7503
- // ========== Transaction Sender ==========
7504
- /* eslint-disable @typescript-eslint/no-explicit-any */
7505
7769
  async signAndBroadcast(tronWeb, unsignedTx) {
7506
7770
  const signed = await tronWeb.trx.sign(unsignedTx);
7507
7771
  const sent = await tronWeb.trx.sendRawTransaction(signed);
@@ -7513,33 +7777,77 @@ class TronChainStrategy {
7513
7777
  }
7514
7778
  return { txid: sent.txid };
7515
7779
  }
7780
+ /**
7781
+ * Check if a transaction has been solidified (confirmed by solidityNode)
7782
+ * This is an additional check for critical transactions to ensure they are
7783
+ * truly confirmed and available through the solidityNode API.
7784
+ *
7785
+ * Usage: Call this method after waitForCompletion for high-value transactions
7786
+ * to get additional assurance that the transaction is solidified.
7787
+ *
7788
+ * @param txHash - Transaction hash to check
7789
+ * @returns true if the transaction is solidified, false otherwise
7790
+ */
7791
+ async checkSolidified(txHash) {
7792
+ try {
7793
+ const tronWeb = this.getTronWeb();
7794
+ if (!tronWeb) {
7795
+ return false;
7796
+ }
7797
+ const info = await tronWeb.trx.getTransactionInfo(txHash);
7798
+ if (!info || !info.blockNumber) {
7799
+ console.debug(
7800
+ "Transaction not yet solidified (no blockNumber in info)"
7801
+ );
7802
+ return false;
7803
+ }
7804
+ const result = info.receipt?.result;
7805
+ if (result === "SUCCESS") {
7806
+ console.log(
7807
+ `Transaction ${txHash} is solidified in block ${info.blockNumber}`
7808
+ );
7809
+ return true;
7810
+ }
7811
+ console.debug(`Transaction solidified but result is: ${result}`);
7812
+ return false;
7813
+ } catch (error) {
7814
+ console.debug("Error checking solidified status:", error);
7815
+ return false;
7816
+ }
7817
+ }
7516
7818
  }
7517
7819
  function ChainStrategyProvider({
7518
7820
  children,
7519
7821
  evmWallet,
7520
7822
  tonWallet,
7521
- tronWallet
7823
+ tronWallet,
7824
+ tonClient,
7825
+ tonApiKey
7522
7826
  }) {
7523
7827
  const evmStrategy = require$$0.useMemo(
7524
7828
  () => new EvmChainStrategy({
7525
7829
  evmAddress: evmWallet.address,
7526
7830
  evmIsConnected: evmWallet.isConnected,
7527
7831
  evmDisconnect: evmWallet.disconnect,
7528
- walletClient: evmWallet.walletClient
7832
+ walletClient: evmWallet.walletClient,
7833
+ publicClient: evmWallet.publicClient
7529
7834
  }),
7530
7835
  [
7531
7836
  evmWallet.address,
7532
7837
  evmWallet.isConnected,
7533
7838
  evmWallet.disconnect,
7534
- evmWallet.walletClient
7839
+ evmWallet.walletClient,
7840
+ evmWallet.publicClient
7535
7841
  ]
7536
7842
  );
7537
7843
  const tonStrategy = require$$0.useMemo(
7538
7844
  () => new TonChainStrategy({
7539
7845
  tonConnectUI: tonWallet.tonConnectUI,
7540
- tonAddress: tonWallet.address
7846
+ tonAddress: tonWallet.address,
7847
+ tonClient,
7848
+ tonApiKey
7541
7849
  }),
7542
- [tonWallet.tonConnectUI, tonWallet.address]
7850
+ [tonWallet.tonConnectUI, tonWallet.address, tonClient, tonApiKey]
7543
7851
  );
7544
7852
  const tronStrategy = require$$0.useMemo(
7545
7853
  () => new TronChainStrategy({
@@ -7575,6 +7883,7 @@ const EvaaBridgeWithProviders = (props) => {
7575
7883
  const { address: evmAddress, isConnected: evmIsConnected } = wagmi.useAccount();
7576
7884
  const { disconnect: evmDisconnect } = wagmi.useDisconnect();
7577
7885
  const { data: walletClient } = wagmi.useWalletClient();
7886
+ const publicClient = wagmi.usePublicClient();
7578
7887
  const {
7579
7888
  address: tronAddress,
7580
7889
  connected: tronConnected,
@@ -7592,14 +7901,15 @@ const EvaaBridgeWithProviders = (props) => {
7592
7901
  require$$0.useEffect(() => {
7593
7902
  setTronConnected(!!tronConnected);
7594
7903
  }, [tronConnected, setTronConnected]);
7595
- return /* @__PURE__ */ jsxRuntime.jsx(
7904
+ return /* @__PURE__ */ jsxRuntime.jsx(ModalContainerProvider, { containerId: props.modalContainerId, children: /* @__PURE__ */ jsxRuntime.jsx(
7596
7905
  ChainStrategyProvider,
7597
7906
  {
7598
7907
  evmWallet: {
7599
7908
  address: evmAddress,
7600
7909
  isConnected: evmIsConnected,
7601
7910
  disconnect: evmDisconnect,
7602
- walletClient
7911
+ walletClient,
7912
+ publicClient
7603
7913
  },
7604
7914
  tonWallet: {
7605
7915
  tonConnectUI,
@@ -7612,9 +7922,11 @@ const EvaaBridgeWithProviders = (props) => {
7612
7922
  connect: tronConnect,
7613
7923
  disconnect: tronDisconnect
7614
7924
  },
7925
+ tonClient: props.tonClient,
7926
+ tonApiKey: props.tonApiKey,
7615
7927
  children: /* @__PURE__ */ jsxRuntime.jsx(EvaaBridgeContent, { ...props })
7616
7928
  }
7617
- );
7929
+ ) });
7618
7930
  };
7619
7931
  const EvaaBridgeContent = ({
7620
7932
  className,
@@ -7623,7 +7935,6 @@ const EvaaBridgeContent = ({
7623
7935
  onChainChange
7624
7936
  } = {}) => {
7625
7937
  const { t } = reactI18next.useTranslation();
7626
- const modalContainerRef = require$$0.useRef(null);
7627
7938
  useTokensRequest();
7628
7939
  useChainsRequest();
7629
7940
  const [sendToAnother, setSendToAnother] = require$$0.useState(false);
@@ -7716,16 +8027,15 @@ const EvaaBridgeContent = ({
7716
8027
  }, [chains, assetMatrix, allowedFromChains]);
7717
8028
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
7718
8029
  /* @__PURE__ */ jsxRuntime.jsxs(
7719
- "section",
8030
+ Card,
7720
8031
  {
7721
8032
  className: cn(
7722
- "p-5 bg-card max-w-md w-full rounded-3xl mx-auto flex flex-col gap-4 relative",
8033
+ "max-w-md w-full mx-auto flex flex-col relative",
7723
8034
  className
7724
8035
  ),
7725
- ref: modalContainerRef,
7726
8036
  children: [
7727
- /* @__PURE__ */ jsxRuntime.jsx(FormHeader, { modalContainer: modalContainerRef.current }),
7728
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-[1px]", children: [
8037
+ /* @__PURE__ */ jsxRuntime.jsx(FormHeader, {}),
8038
+ /* @__PURE__ */ jsxRuntime.jsxs(CardContent, { className: "space-y-[1px]", children: [
7729
8039
  /* @__PURE__ */ jsxRuntime.jsx(
7730
8040
  SwapSection,
7731
8041
  {
@@ -7738,8 +8048,7 @@ const EvaaBridgeContent = ({
7738
8048
  amount,
7739
8049
  isSource: true,
7740
8050
  onAmountChange: handleAmountChange,
7741
- onSelect: handleFromChainChange,
7742
- modalContainer: modalContainerRef.current || void 0
8051
+ onSelect: handleFromChainChange
7743
8052
  }
7744
8053
  ),
7745
8054
  /* @__PURE__ */ jsxRuntime.jsx(SwapButton, {}),
@@ -7753,8 +8062,7 @@ const EvaaBridgeContent = ({
7753
8062
  allowedChains: allowedToChains,
7754
8063
  amount: outputAmount,
7755
8064
  readOnlyAmount: true,
7756
- onSelect: handleToChainChange,
7757
- modalContainer: modalContainerRef.current || void 0
8065
+ onSelect: handleToChainChange
7758
8066
  }
7759
8067
  ),
7760
8068
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -7763,15 +8071,15 @@ const EvaaBridgeContent = ({
7763
8071
  enabled: sendToAnother,
7764
8072
  onToggle: () => setSendToAnother((v) => !v)
7765
8073
  }
7766
- )
8074
+ ),
8075
+ /* @__PURE__ */ jsxRuntime.jsx(SubmitButton, {})
7767
8076
  ] }),
7768
- /* @__PURE__ */ jsxRuntime.jsx(SubmitButton, {}),
7769
- /* @__PURE__ */ jsxRuntime.jsx(ReceiveRow, {})
8077
+ /* @__PURE__ */ jsxRuntime.jsx(CardFooter, { children: /* @__PURE__ */ jsxRuntime.jsx(ReceiveRow, {}) })
7770
8078
  ]
7771
8079
  }
7772
8080
  ),
7773
- /* @__PURE__ */ jsxRuntime.jsx(WalletSelectModal, { modalContainer: modalContainerRef.current }),
7774
- /* @__PURE__ */ jsxRuntime.jsx(TransactionManager, { modalContainer: modalContainerRef.current }),
8081
+ /* @__PURE__ */ jsxRuntime.jsx(WalletSelectModal, {}),
8082
+ /* @__PURE__ */ jsxRuntime.jsx(TransactionManager, {}),
7775
8083
  /* @__PURE__ */ jsxRuntime.jsx(sonner.Toaster, { position: "top-right", richColors: true })
7776
8084
  ] });
7777
8085
  };
@@ -7854,8 +8162,8 @@ exports.getQuoteAmounts = getQuoteAmounts;
7854
8162
  exports.getQuoteDetails = getQuoteDetails;
7855
8163
  exports.getQuoteFees = getQuoteFees;
7856
8164
  exports.getQuotesByPriority = getQuotesByPriority;
7857
- exports.getSwapBalances = getSwapBalances;
7858
8165
  exports.getTokens = getTokens;
8166
+ exports.getTonBalances = getTonBalances;
7859
8167
  exports.getTronBalances = getTronBalances;
7860
8168
  exports.isAddressValidForChain = isAddressValidForChain;
7861
8169
  exports.isEvmAddress = isEvmAddress;
@@ -7864,7 +8172,7 @@ exports.isTronAddress = isTronAddress;
7864
8172
  exports.isZeroAddr = isZeroAddr;
7865
8173
  exports.listAssetsForSelect = listAssetsForSelect;
7866
8174
  exports.lookupTokenMeta = lookupTokenMeta;
7867
- exports.normalizeTickerSymbol = normalizeTickerSymbol;
8175
+ exports.normalizeTickerSymbol = normalizeTickerSymbol$1;
7868
8176
  exports.pollUntilDelivered = pollUntilDelivered;
7869
8177
  exports.resolveTokenOnChain = resolveTokenOnChain;
7870
8178
  exports.resolveTokenOnChainFromMatrix = resolveTokenOnChainFromMatrix$2;