@rash2x/bridge-widget 0.1.3 → 0.1.5

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.
@@ -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: {
@@ -782,19 +783,6 @@ const Tip = (props) => {
782
783
  /* @__PURE__ */ jsx(TooltipContent, { children: /* @__PURE__ */ jsx("p", { children: text }) })
783
784
  ] });
784
785
  };
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
786
  async function getChains() {
799
787
  const res = await fetch("https://stargate.finance/api/v1/chains", {
800
788
  credentials: "same-origin"
@@ -842,49 +830,16 @@ async function getDestTokens(srcChainKey, srcTokenAddr) {
842
830
  });
843
831
  return unique;
844
832
  }
845
- const isTonFriendly = (a) => !!a && /^[A-Za-z0-9_-]{48,}$/.test(a);
846
- function normalizeTickerSymbol(s) {
833
+ function normalizeTickerSymbol$1(s) {
847
834
  return s.toUpperCase().replace(/₮/g, "T").replace(/[^A-Z0-9]/g, "");
848
835
  }
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
836
  const BASE_URL$1 = "https://icons-ckg.pages.dev/stargate-light/tokens";
882
837
  const TokenSymbol = ({
883
838
  symbol,
884
839
  className = "w-4 h-4",
885
840
  alt
886
841
  }) => {
887
- const normalizedSymbol = normalizeTickerSymbol(symbol).toLowerCase();
842
+ const normalizedSymbol = normalizeTickerSymbol$1(symbol).toLowerCase();
888
843
  const src = `${BASE_URL$1}/${normalizedSymbol}.svg`;
889
844
  return /* @__PURE__ */ jsx("img", { src, alt: alt ?? symbol, className });
890
845
  };
@@ -1298,6 +1253,19 @@ function useChainStrategies() {
1298
1253
  }
1299
1254
  return context;
1300
1255
  }
1256
+ function toLD(human, decimals) {
1257
+ const [i = "0", f = ""] = human.replace(",", ".").split(".");
1258
+ const frac = (f + "0".repeat(decimals)).slice(0, decimals);
1259
+ return BigInt(i + frac).toString();
1260
+ }
1261
+ function fromLD(ld, decimals) {
1262
+ const bi = BigInt(ld || "0");
1263
+ if (decimals === 0) return Number(bi);
1264
+ const base = BigInt(10) ** BigInt(decimals);
1265
+ const int = bi / base;
1266
+ const frac = Number(bi % base) / Number(base);
1267
+ return Number(int) + frac;
1268
+ }
1301
1269
  function resolveTokenOnChainFromMatrix$2(assetMatrix, assetSymbol, chainKey) {
1302
1270
  if (!assetMatrix || !assetSymbol || !chainKey) return void 0;
1303
1271
  const byChain = assetMatrix[assetSymbol.toUpperCase()];
@@ -1479,18 +1447,19 @@ function useBalances(chainKey, address) {
1479
1447
  const data = query.data;
1480
1448
  if (data) {
1481
1449
  for (const [sum, v] of Object.entries(data)) {
1482
- map.set(normalizeTickerSymbol(sum), Number(v.balance ?? 0));
1450
+ map.set(normalizeTickerSymbol$1(sum), Number(v.balance ?? 0));
1483
1451
  }
1484
1452
  }
1485
1453
  return map;
1486
1454
  }, [query.data]);
1487
1455
  const getBalance = useCallback(
1488
- (symbol) => balanceBySymbol.get(normalizeTickerSymbol(symbol)) ?? 0,
1456
+ (symbol) => balanceBySymbol.get(normalizeTickerSymbol$1(symbol)) ?? 0,
1489
1457
  [balanceBySymbol]
1490
1458
  );
1491
1459
  const isLoading = query.isLoading || query.isFetching;
1460
+ const balances = useMemo(() => query.data || {}, [query.data]);
1492
1461
  return {
1493
- balances: query.data || {},
1462
+ balances,
1494
1463
  getBalance,
1495
1464
  isLoading,
1496
1465
  query
@@ -1944,17 +1913,17 @@ const RefreshButton = () => {
1944
1913
  return /* @__PURE__ */ jsx(
1945
1914
  Button,
1946
1915
  {
1947
- 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" : ""}`,
1948
1916
  onClick: handleRefresh,
1949
1917
  disabled: spinning,
1918
+ variant: "secondary",
1919
+ size: "sm",
1950
1920
  children: /* @__PURE__ */ jsx(
1951
1921
  ReloadIcon,
1952
1922
  {
1953
1923
  style: {
1954
1924
  transform: `rotate(${turns * 180}deg)`,
1955
1925
  transition: "transform 300ms linear"
1956
- },
1957
- className: "size-4 text-foreground m-1 will-change-transform"
1926
+ }
1958
1927
  }
1959
1928
  )
1960
1929
  }
@@ -1962,7 +1931,6 @@ const RefreshButton = () => {
1962
1931
  };
1963
1932
  const SelectTokenButton = ({
1964
1933
  onClick,
1965
- className,
1966
1934
  token
1967
1935
  }) => {
1968
1936
  const { t: t2 } = useTranslation();
@@ -1973,7 +1941,8 @@ const SelectTokenButton = ({
1973
1941
  Button,
1974
1942
  {
1975
1943
  onClick,
1976
- 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 ?? ""}`,
1944
+ size: "sm",
1945
+ variant: "secondary",
1977
1946
  type: "button",
1978
1947
  "aria-label": label,
1979
1948
  children: [
@@ -1993,6 +1962,75 @@ const SelectTokenButton = ({
1993
1962
  }
1994
1963
  );
1995
1964
  };
1965
+ function Card({ className, ...props }) {
1966
+ return /* @__PURE__ */ jsx(
1967
+ "div",
1968
+ {
1969
+ "data-slot": "card",
1970
+ className: cn(
1971
+ "bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm",
1972
+ className
1973
+ ),
1974
+ ...props
1975
+ }
1976
+ );
1977
+ }
1978
+ function CardHeader({ className, ...props }) {
1979
+ return /* @__PURE__ */ jsx(
1980
+ "div",
1981
+ {
1982
+ "data-slot": "card-header",
1983
+ className: cn(
1984
+ "@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",
1985
+ className
1986
+ ),
1987
+ ...props
1988
+ }
1989
+ );
1990
+ }
1991
+ function CardTitle({ className, ...props }) {
1992
+ return /* @__PURE__ */ jsx(
1993
+ "div",
1994
+ {
1995
+ "data-slot": "card-title",
1996
+ className: cn("leading-none font-semibold", className),
1997
+ ...props
1998
+ }
1999
+ );
2000
+ }
2001
+ function CardAction({ className, ...props }) {
2002
+ return /* @__PURE__ */ jsx(
2003
+ "div",
2004
+ {
2005
+ "data-slot": "card-action",
2006
+ className: cn(
2007
+ "col-start-2 row-span-2 row-start-1 self-start justify-self-end",
2008
+ className
2009
+ ),
2010
+ ...props
2011
+ }
2012
+ );
2013
+ }
2014
+ function CardContent({ className, ...props }) {
2015
+ return /* @__PURE__ */ jsx(
2016
+ "div",
2017
+ {
2018
+ "data-slot": "card-content",
2019
+ className: cn("px-6", className),
2020
+ ...props
2021
+ }
2022
+ );
2023
+ }
2024
+ function CardFooter({ className, ...props }) {
2025
+ return /* @__PURE__ */ jsx(
2026
+ "div",
2027
+ {
2028
+ "data-slot": "card-footer",
2029
+ className: cn("flex items-center px-6 [.border-t]:pt-6", className),
2030
+ ...props
2031
+ }
2032
+ );
2033
+ }
1996
2034
  const FormHeaderComponent = ({ modalContainer }) => {
1997
2035
  const { t: t2 } = useTranslation();
1998
2036
  const { isOpen, onClose, onOpen } = useModal();
@@ -2009,29 +2047,14 @@ const FormHeaderComponent = ({ modalContainer }) => {
2009
2047
  const sum = selectedAssetSymbol.toUpperCase();
2010
2048
  return assets.find((a) => a.symbol.toUpperCase() === sum) ?? assets[0];
2011
2049
  }, [assets, selectedAssetSymbol]);
2012
- return /* @__PURE__ */ jsxs(Fragment, { children: [
2013
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
2014
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2.5", children: [
2015
- /* @__PURE__ */ jsx("span", { className: "text-sm font-normal leading-3.5 text-muted-foreground", children: t2("bridge.selectToken") }),
2016
- /* @__PURE__ */ jsx(SelectTokenButton, { token: current, onClick: onOpen })
2017
- ] }),
2018
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2.5", children: [
2019
- /* @__PURE__ */ jsx(RefreshButton, {}),
2020
- /* @__PURE__ */ jsx(
2021
- Button,
2022
- {
2023
- className: "cursor-pointer py-1.5 h-8.5 hover:scale-110 shadow-none px-8.5 hover:bg-secondary bg-secondary !rounded-40",
2024
- onClick: onOpenSettings,
2025
- children: /* @__PURE__ */ jsx(
2026
- BoltIcon,
2027
- {
2028
- className: "size-4 text-foreground m-1",
2029
- stroke: "currentColor"
2030
- }
2031
- )
2032
- }
2033
- )
2034
- ] })
2050
+ return /* @__PURE__ */ jsxs(CardHeader, { className: "gap-y-0", children: [
2051
+ /* @__PURE__ */ jsxs(CardTitle, { className: "flex items-center gap-2.5", children: [
2052
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-normal leading-3.5 text-muted-foreground", children: t2("bridge.selectToken") }),
2053
+ /* @__PURE__ */ jsx(SelectTokenButton, { token: current, onClick: onOpen })
2054
+ ] }),
2055
+ /* @__PURE__ */ jsxs(CardAction, { className: "flex items-center gap-2.5", children: [
2056
+ /* @__PURE__ */ jsx(RefreshButton, {}),
2057
+ /* @__PURE__ */ jsx(Button, { onClick: onOpenSettings, size: "sm", variant: "secondary", children: /* @__PURE__ */ jsx(BoltIcon, { stroke: "currentColor" }) })
2035
2058
  ] }),
2036
2059
  /* @__PURE__ */ jsx(
2037
2060
  TokenSelectModal,
@@ -3721,7 +3744,9 @@ function useBridgeTransaction() {
3721
3744
  function useGasEstimate(amountNum) {
3722
3745
  const { fromChain } = useChainsStore();
3723
3746
  const { selectedAssetSymbol, tokens } = useTokensStore();
3724
- const { getSourceGasReserveHuman } = useSettingsStore();
3747
+ const getSourceGasReserveHuman = useSettingsStore(
3748
+ (state) => state.getSourceGasReserveHuman
3749
+ );
3725
3750
  const { srcAddress } = useAddresses();
3726
3751
  const { balances, isLoading: balancesLoading } = useBalances(
3727
3752
  fromChain?.chainKey,
@@ -3729,59 +3754,44 @@ function useGasEstimate(amountNum) {
3729
3754
  );
3730
3755
  const { chainRegistry } = useChainStrategies();
3731
3756
  const balancesKnown = !balancesLoading;
3732
- const [gasRequirement, setGasRequirement] = useState(
3733
- null
3734
- );
3735
- useEffect(() => {
3736
- let cancelled = false;
3737
- async function estimateGas() {
3738
- if (!fromChain) {
3739
- setGasRequirement(null);
3740
- return;
3741
- }
3742
- const strategy = chainRegistry.getStrategy(fromChain.chainKey);
3743
- if (!strategy) {
3744
- setGasRequirement(null);
3745
- return;
3746
- }
3747
- try {
3748
- const selectedToken = tokens?.find(
3749
- (t2) => t2.symbol.toUpperCase() === selectedAssetSymbol?.toUpperCase()
3750
- ) || null;
3751
- const nativeTokenSymbol = fromChain.nativeCurrency?.symbol ?? "";
3752
- const nativeDecimals = fromChain.nativeCurrency?.decimals || 18;
3753
- const reserveFallback = getSourceGasReserveHuman(fromChain.chainKey);
3754
- const result = await strategy.estimateGasRequirement({
3755
- selectedToken,
3756
- nativeTokenSymbol,
3757
- amount: amountNum,
3758
- balances,
3759
- nativeDecimals,
3760
- reserveFallback
3761
- });
3762
- if (!cancelled) {
3763
- setGasRequirement(result);
3764
- }
3765
- } catch (error) {
3766
- console.error("Error estimating gas:", error);
3767
- if (!cancelled) {
3768
- setGasRequirement(null);
3769
- }
3770
- }
3771
- }
3772
- estimateGas();
3773
- return () => {
3774
- cancelled = true;
3775
- };
3776
- }, [
3777
- fromChain,
3778
- selectedAssetSymbol,
3779
- tokens,
3780
- amountNum,
3781
- balances,
3782
- chainRegistry,
3783
- getSourceGasReserveHuman
3784
- ]);
3757
+ const strategy = useMemo(() => {
3758
+ if (!fromChain) return null;
3759
+ return chainRegistry.getStrategy(fromChain.chainKey);
3760
+ }, [fromChain, chainRegistry]);
3761
+ const { data: gasRequirement } = useQuery({
3762
+ queryKey: [
3763
+ "gas-estimate",
3764
+ fromChain?.chainKey,
3765
+ selectedAssetSymbol,
3766
+ amountNum,
3767
+ balances
3768
+ ],
3769
+ queryFn: async () => {
3770
+ if (!fromChain || !strategy) {
3771
+ return null;
3772
+ }
3773
+ const selectedToken = tokens?.find(
3774
+ (t2) => t2.symbol.toUpperCase() === selectedAssetSymbol?.toUpperCase()
3775
+ ) || null;
3776
+ const nativeTokenSymbol = fromChain.nativeCurrency?.symbol ?? "";
3777
+ const nativeDecimals = fromChain.nativeCurrency?.decimals || 18;
3778
+ const reserveFallback = getSourceGasReserveHuman(fromChain.chainKey);
3779
+ const result = await strategy.estimateGasRequirement({
3780
+ selectedToken,
3781
+ nativeTokenSymbol,
3782
+ amount: amountNum,
3783
+ balances,
3784
+ nativeDecimals,
3785
+ reserveFallback
3786
+ });
3787
+ return result;
3788
+ },
3789
+ enabled: !!fromChain && !!strategy,
3790
+ staleTime: 3e4,
3791
+ gcTime: 5 * 6e4,
3792
+ refetchOnWindowFocus: false,
3793
+ retry: 1
3794
+ });
3785
3795
  return {
3786
3796
  nativeSym: gasRequirement?.nativeSym || "",
3787
3797
  nativeBalance: gasRequirement?.nativeBalance || 0,
@@ -3930,7 +3940,7 @@ function useSilentValidations(amountString) {
3930
3940
  ]);
3931
3941
  return validationResult;
3932
3942
  }
3933
- function useTransferAction() {
3943
+ const SubmitButton = () => {
3934
3944
  const { t: t2 } = useTranslation();
3935
3945
  const { chainRegistry } = useChainStrategies();
3936
3946
  const { srcAddress, dstAddress } = useAddresses();
@@ -4006,7 +4016,7 @@ function useTransferAction() {
4006
4016
  maximumAmountFormatted,
4007
4017
  chainRegistry
4008
4018
  ]);
4009
- const onClick = async () => {
4019
+ const handleClick = async () => {
4010
4020
  if (isBusy) return;
4011
4021
  if (missingSrc && srcChainKey) {
4012
4022
  onOpen("src");
@@ -4026,24 +4036,7 @@ function useTransferAction() {
4026
4036
  }
4027
4037
  };
4028
4038
  const disabled = isBusy || amountNum <= 0 || status === "loading" || isBalanceLoading || hasInsufficientBalance || hasAmountTooLarge || !gas.hasEnoughGas || noRoute || !isValidForTransfer;
4029
- return {
4030
- // состояния
4031
- isBusy,
4032
- canTransfer,
4033
- missingSrc,
4034
- missingDst,
4035
- hasEnoughGas: gas.hasEnoughGas,
4036
- noRoute,
4037
- // представление
4038
- label,
4039
- disabled,
4040
- // действие
4041
- onClick
4042
- };
4043
- }
4044
- const SubmitButton = () => {
4045
- const { label, disabled, onClick } = useTransferAction();
4046
- return /* @__PURE__ */ jsx(Button, { onClick, disabled, size: "lg", children: label });
4039
+ return /* @__PURE__ */ jsx(Button, { onClick: handleClick, disabled, className: "w-full", children: label });
4047
4040
  };
4048
4041
  function short(addr) {
4049
4042
  return addr.slice(0, 4) + "…" + addr.slice(-4);
@@ -4053,6 +4046,7 @@ const WalletSelectModal = ({
4053
4046
  }) => {
4054
4047
  const { t: t2 } = useTranslation();
4055
4048
  const { isOpen, onClose } = useWalletSelectModal();
4049
+ const { connect, connectors, isPending } = useConnect();
4056
4050
  const { chainRegistry } = useChainStrategies();
4057
4051
  const tonWallet = chainRegistry.getStrategyByType("ton");
4058
4052
  const metaMaskWallet = chainRegistry.getStrategyByType("evm");
@@ -4085,7 +4079,13 @@ const WalletSelectModal = ({
4085
4079
  onDisconnect: () => tronWallet.disconnect()
4086
4080
  });
4087
4081
  }
4088
- const isWalletConnected = (walletId) => connectedWallets.some((w) => w.id === walletId);
4082
+ const isWalletConnected = (walletId) => {
4083
+ const isEvmConnector = connectors.some((c) => c.id === walletId);
4084
+ if (isEvmConnector && metaMaskWallet?.isConnected()) {
4085
+ return true;
4086
+ }
4087
+ return connectedWallets.some((w) => w.id === walletId);
4088
+ };
4089
4089
  const tonWallets = [
4090
4090
  {
4091
4091
  id: "ton",
@@ -4094,14 +4094,15 @@ const WalletSelectModal = ({
4094
4094
  enabled: true
4095
4095
  }
4096
4096
  ];
4097
- const evmWallets = [
4098
- {
4099
- id: "metamask",
4100
- name: t2("wallets.metaMask"),
4101
- icon: MetaMaskIcon,
4102
- enabled: true
4103
- }
4104
- ];
4097
+ const evmWallets = connectors.filter(
4098
+ (connector) => connector.id === "walletConnect" || connector.id === "metaMaskSDK"
4099
+ ).map((connector) => ({
4100
+ id: connector.id,
4101
+ name: connector.name,
4102
+ icon: MetaMaskIcon,
4103
+ // You can add a WalletConnect icon here
4104
+ enabled: true
4105
+ }));
4105
4106
  const tronWallets = [
4106
4107
  {
4107
4108
  id: "tronlink",
@@ -4131,9 +4132,6 @@ const WalletSelectModal = ({
4131
4132
  case "ton":
4132
4133
  await tonWallet?.connect();
4133
4134
  break;
4134
- case "metamask":
4135
- await metaMaskWallet?.connect();
4136
- break;
4137
4135
  case "tronlink":
4138
4136
  await tronWallet?.connect();
4139
4137
  break;
@@ -4158,56 +4156,47 @@ const WalletSelectModal = ({
4158
4156
  /* @__PURE__ */ jsx("div", { className: "px-5 py-2 leading-4 text-base font-semibold text-muted-foreground uppercase", children: t2("wallets.connected") }),
4159
4157
  /* @__PURE__ */ jsx("div", { className: "", children: connectedWallets.map((wallet) => {
4160
4158
  const IconComponent = wallet.icon;
4161
- return /* @__PURE__ */ jsx("div", { className: "", children: /* @__PURE__ */ jsxs(
4162
- Button,
4163
- {
4164
- 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]",
4165
- children: [
4166
- /* @__PURE__ */ jsx("div", { className: "flex items-center gap-3 min-w-0", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2.5", children: [
4167
- /* @__PURE__ */ jsx("div", { className: "w-7.5 h-7.5 flex items-center justify-center", children: /* @__PURE__ */ jsx(IconComponent, { className: "size-7.5" }) }),
4168
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-start min-w-0", children: [
4169
- /* @__PURE__ */ jsx("p", { className: "font-extrabold text-foreground text-sm leading-4 truncate", children: short(wallet.address) }),
4170
- /* @__PURE__ */ jsx("div", { className: "text-xs leading-3 font-semibold text-muted-foreground", children: wallet.name })
4171
- ] })
4172
- ] }) }),
4173
- /* @__PURE__ */ jsx("div", { onClick: () => {
4159
+ 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: [
4160
+ /* @__PURE__ */ jsx("div", { className: "flex items-center gap-3 min-w-0", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2.5", children: [
4161
+ /* @__PURE__ */ jsx("div", { className: "w-7.5 h-7.5 flex items-center justify-center", children: /* @__PURE__ */ jsx(IconComponent, { className: "size-7.5" }) }),
4162
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-start min-w-0", children: [
4163
+ /* @__PURE__ */ jsx("p", { className: "font-extrabold text-foreground text-sm leading-4 truncate", children: short(wallet.address) }),
4164
+ /* @__PURE__ */ jsx("div", { className: "text-xs leading-3 font-semibold text-muted-foreground", children: wallet.name })
4165
+ ] })
4166
+ ] }) }),
4167
+ /* @__PURE__ */ jsx(
4168
+ "div",
4169
+ {
4170
+ onClick: () => {
4174
4171
  wallet.onDisconnect();
4175
4172
  onClose();
4176
- }, className: "text-sm font-medium text-muted-foreground", children: /* @__PURE__ */ jsx(ExitIcon, { className: "text-[#808080] size-6" }) })
4177
- ]
4178
- }
4179
- ) }, wallet.id);
4173
+ },
4174
+ className: "text-sm font-medium text-muted-foreground",
4175
+ children: /* @__PURE__ */ jsx(ExitIcon, { className: "text-[#808080] size-6" })
4176
+ }
4177
+ )
4178
+ ] }) }, wallet.id);
4180
4179
  }) })
4181
4180
  ] }),
4182
4181
  categories.map((category) => /* @__PURE__ */ jsxs("div", { children: [
4183
4182
  /* @__PURE__ */ jsx("div", { className: "px-5 py-2 leading-4 text-base font-semibold text-muted-foreground uppercase", children: category.title }),
4184
4183
  /* @__PURE__ */ jsx("div", { className: "", children: category.wallets.map((wallet) => {
4185
4184
  const IconComponent = wallet.icon;
4186
- if (wallet.id === "metamask") {
4187
- return /* @__PURE__ */ jsx("div", { id: wallet.id, children: /* @__PURE__ */ jsx(ConnectKitButton.Custom, { children: ({ isConnecting, show }) => {
4188
- return /* @__PURE__ */ jsx(
4189
- Button,
4190
- {
4191
- type: "button",
4192
- onClick: show,
4193
- disabled: isConnecting,
4194
- 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",
4195
- children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 min-w-0", children: [
4196
- /* @__PURE__ */ jsx("div", { className: "w-7.5 h-7.5 flex items-center justify-center", children: /* @__PURE__ */ jsx(IconComponent, { className: "size-7.5" }) }),
4197
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-start min-w-0", children: [
4198
- /* @__PURE__ */ jsx("p", { className: "font-extrabold text-foreground text-sm leading-4 truncate", children: wallet.name }),
4199
- 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") })
4200
- ] })
4201
- ] })
4202
- }
4203
- );
4204
- } }) }, wallet.id);
4205
- }
4185
+ const isEvmConnector = category.title === t2("wallets.evmWallets");
4186
+ const connector = isEvmConnector ? connectors.find((c) => c.id === wallet.id) : null;
4206
4187
  return /* @__PURE__ */ jsx("div", { className: "", children: /* @__PURE__ */ jsx(
4207
4188
  Button,
4208
4189
  {
4209
- onClick: () => handleWalletSelect(wallet.id),
4210
- disabled: !wallet.enabled,
4190
+ type: "button",
4191
+ onClick: () => {
4192
+ if (connector) {
4193
+ connect({ connector });
4194
+ onClose();
4195
+ } else {
4196
+ handleWalletSelect(wallet.id);
4197
+ }
4198
+ },
4199
+ disabled: isEvmConnector ? isPending : !wallet.enabled,
4211
4200
  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",
4212
4201
  children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 min-w-0", children: [
4213
4202
  /* @__PURE__ */ jsx("div", { className: "w-7.5 h-7.5 flex items-center justify-center", children: /* @__PURE__ */ jsx(IconComponent, { className: "size-7.5" }) }),
@@ -4223,39 +4212,6 @@ const WalletSelectModal = ({
4223
4212
  ] })
4224
4213
  ] }) });
4225
4214
  };
4226
- function Card({ className, ...props }) {
4227
- return /* @__PURE__ */ jsx(
4228
- "div",
4229
- {
4230
- "data-slot": "card",
4231
- className: cn(
4232
- "bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm",
4233
- className
4234
- ),
4235
- ...props
4236
- }
4237
- );
4238
- }
4239
- function CardContent({ className, ...props }) {
4240
- return /* @__PURE__ */ jsx(
4241
- "div",
4242
- {
4243
- "data-slot": "card-content",
4244
- className: cn("px-6", className),
4245
- ...props
4246
- }
4247
- );
4248
- }
4249
- function CardFooter({ className, ...props }) {
4250
- return /* @__PURE__ */ jsx(
4251
- "div",
4252
- {
4253
- "data-slot": "card-footer",
4254
- className: cn("flex items-center px-6 [.border-t]:pt-6", className),
4255
- ...props
4256
- }
4257
- );
4258
- }
4259
4215
  const TransactionProgressVector = (props) => {
4260
4216
  return /* @__PURE__ */ jsxs("svg", { width: "200", height: "200", viewBox: "0 0 200 200", fill: "none", xmlns: "http://www.w3.org/2000/svg", ...props, children: [
4261
4217
  /* @__PURE__ */ jsx(
@@ -6319,6 +6275,49 @@ class ChainStrategyRegistry {
6319
6275
  await strategy.disconnect();
6320
6276
  }
6321
6277
  }
6278
+ const EVM_CONFIG = {
6279
+ usdtAddress: "0xdAC17F958D2ee523a2206206994597C13D831ec7",
6280
+ gasEstimates: {
6281
+ approve: 65000n,
6282
+ bridge: 300000n
6283
+ },
6284
+ gasBuffer: 1.2,
6285
+ // 20% buffer
6286
+ timeout: 3e5,
6287
+ // 5 minutes (increased for slower networks)
6288
+ requiredConfirmations: 3
6289
+ // Wait for 3 confirmations for reorg protection
6290
+ };
6291
+ const TON_CONFIG = {
6292
+ apiUrl: "https://toncenter.com/api/v2",
6293
+ timeout: 36e4,
6294
+ // 6 minutes
6295
+ validUntil: 600
6296
+ // 10 minutes
6297
+ };
6298
+ const TRON_CONFIG = {
6299
+ timeout: 12e4,
6300
+ // 2 minutes (for 19 confirmations)
6301
+ feeLimit: 1e8,
6302
+ // 100 TRX in sun
6303
+ requiredConfirmations: 19,
6304
+ // TRON standard: 19 blocks for confirmation
6305
+ pollingInterval: 3e3
6306
+ // 3 seconds between checks
6307
+ };
6308
+ let tonClientInstance = null;
6309
+ function getTonClient(customClient, apiKey) {
6310
+ if (customClient) {
6311
+ return customClient;
6312
+ }
6313
+ if (!tonClientInstance) {
6314
+ tonClientInstance = new TonClient({
6315
+ endpoint: `${TON_CONFIG.apiUrl}/jsonRPC`,
6316
+ apiKey
6317
+ });
6318
+ }
6319
+ return tonClientInstance;
6320
+ }
6322
6321
  function isNativeAddress(addr) {
6323
6322
  if (!addr) return false;
6324
6323
  const a = addr.toLowerCase();
@@ -6344,44 +6343,72 @@ function formatUnitsFromBigIntStr(valueStr, decimals) {
6344
6343
  const tail = s.slice(s.length - decimals).replace(/0+$/, "");
6345
6344
  return Number(tail ? `${head}.${tail}` : head);
6346
6345
  }
6347
- async function getEvmBalances(address, tokens) {
6346
+ function isTonFriendlyAddress(address) {
6347
+ return !!address && /^[A-Za-z0-9_-]{48,}$/.test(address);
6348
+ }
6349
+ function normalizeTickerSymbol(symbol) {
6350
+ return symbol.toUpperCase().replace(/₮/g, "T").replace(/[^A-Z0-9]/g, "");
6351
+ }
6352
+ function parseTonAddress(address) {
6353
+ if (address.startsWith("0x")) {
6354
+ const hex = address.slice(2);
6355
+ return Address$1.parseRaw(`0:${hex}`);
6356
+ }
6357
+ if (address.includes(":")) {
6358
+ return Address$1.parseRaw(address);
6359
+ }
6360
+ return Address$1.parse(address);
6361
+ }
6362
+ async function getEvmBalances(publicClient, address, tokens) {
6348
6363
  const balances = {};
6349
6364
  try {
6350
- if (!address || !ethers.isAddress(address)) {
6365
+ console.log("start getEvmBalances");
6366
+ console.log("publicClient:", publicClient);
6367
+ console.log("isAddress:", isAddress(address));
6368
+ console.log("tokens:", tokens);
6369
+ if (!address || !isAddress(address)) {
6351
6370
  console.warn(`Invalid EVM address provided: ${address}`);
6352
6371
  return balances;
6353
6372
  }
6354
- if (typeof window === "undefined" || !window.ethereum) {
6355
- throw new Error("No ethereum provider found");
6373
+ if (!publicClient) {
6374
+ throw new Error("No public client provided");
6356
6375
  }
6357
- const provider = new ethers.BrowserProvider(window.ethereum);
6358
6376
  for (const token of tokens) {
6359
6377
  try {
6360
6378
  let balance = 0;
6361
6379
  const isNative = isNativeAddress(token.address);
6362
6380
  if (isNative) {
6363
- const ethBalance = await provider.getBalance(address);
6364
- balance = parseFloat(ethers.formatUnits(ethBalance, token.decimals));
6381
+ const ethBalance = await publicClient.getBalance({
6382
+ address
6383
+ });
6384
+ balance = parseFloat(formatUnits(ethBalance, token.decimals));
6365
6385
  } else {
6366
- if (!ethers.isAddress(token.address)) {
6386
+ if (!isAddress(token.address)) {
6367
6387
  continue;
6368
6388
  }
6369
- const code = await provider.getCode(token.address);
6370
- if (code === "0x") {
6389
+ const bytecode = await publicClient.getBytecode({
6390
+ address: token.address
6391
+ });
6392
+ if (!bytecode || bytecode === "0x") {
6371
6393
  continue;
6372
6394
  }
6373
- const contract = new ethers.Contract(
6374
- token.address,
6375
- [
6376
- "function balanceOf(address owner) view returns (uint256)",
6377
- "function decimals() view returns (uint8)"
6378
- ],
6379
- provider
6380
- );
6381
6395
  try {
6382
- const tokenBalance = await contract.balanceOf(address);
6396
+ const tokenBalance = await publicClient.readContract({
6397
+ address: token.address,
6398
+ abi: [
6399
+ {
6400
+ name: "balanceOf",
6401
+ type: "function",
6402
+ stateMutability: "view",
6403
+ inputs: [{ name: "owner", type: "address" }],
6404
+ outputs: [{ name: "balance", type: "uint256" }]
6405
+ }
6406
+ ],
6407
+ functionName: "balanceOf",
6408
+ args: [address]
6409
+ });
6383
6410
  balance = parseFloat(
6384
- ethers.formatUnits(tokenBalance, token.decimals)
6411
+ formatUnits(tokenBalance, token.decimals)
6385
6412
  );
6386
6413
  } catch {
6387
6414
  continue;
@@ -6404,6 +6431,68 @@ async function getEvmBalances(address, tokens) {
6404
6431
  }
6405
6432
  return balances;
6406
6433
  }
6434
+ async function getTonBalances(address, tokens, customTonClient, tonApiKey) {
6435
+ const balances = {};
6436
+ try {
6437
+ if (!isTonFriendlyAddress(address)) {
6438
+ console.warn(`Invalid TON address provided: ${address}`);
6439
+ return balances;
6440
+ }
6441
+ const client = getTonClient(customTonClient, tonApiKey);
6442
+ const accountAddress = Address$1.parse(address);
6443
+ console.log(address);
6444
+ console.log(tokens);
6445
+ try {
6446
+ const balance = await client.getBalance(accountAddress);
6447
+ const tonBalance = Number(balance) / 1e9;
6448
+ console.log("tonBalance", tonBalance);
6449
+ if (tonBalance > 0) {
6450
+ balances.TON = { balance: tonBalance, address: "ton-native" };
6451
+ }
6452
+ } catch (error) {
6453
+ console.warn("Failed to get native TON balance:", error);
6454
+ }
6455
+ for (const token of tokens) {
6456
+ try {
6457
+ if (isNativeAddress(token.address) || token.symbol.toUpperCase() === "TON") {
6458
+ continue;
6459
+ }
6460
+ const jettonMasterAddress = parseTonAddress(token.address);
6461
+ const jettonWalletAddress = await client.runMethod(
6462
+ jettonMasterAddress,
6463
+ "get_wallet_address",
6464
+ [
6465
+ {
6466
+ type: "slice",
6467
+ cell: beginCell().storeAddress(accountAddress).endCell()
6468
+ }
6469
+ ]
6470
+ );
6471
+ const jettonWalletAddr = jettonWalletAddress.stack.readAddress();
6472
+ const jettonData = await client.runMethod(
6473
+ jettonWalletAddr,
6474
+ "get_wallet_data"
6475
+ );
6476
+ const jettonBalance = jettonData.stack.readBigNumber();
6477
+ const humanBalance = Number(jettonBalance) / Math.pow(10, token.decimals);
6478
+ if (humanBalance > 0) {
6479
+ const symbolUpper = token.symbol.toUpperCase();
6480
+ const symbolNorm = normalizeTickerSymbol(symbolUpper);
6481
+ const entry = { balance: humanBalance, address: token.address };
6482
+ balances[symbolUpper] = entry;
6483
+ if (symbolNorm !== symbolUpper) {
6484
+ balances[symbolNorm] = entry;
6485
+ }
6486
+ }
6487
+ } catch (error) {
6488
+ console.debug(`Failed to get balance for ${token.symbol}:`, error);
6489
+ }
6490
+ }
6491
+ } catch (error) {
6492
+ console.error("Failed to get TON balances:", error);
6493
+ }
6494
+ return balances;
6495
+ }
6407
6496
  async function getTronBalances(tronWeb, address, tokens) {
6408
6497
  const balances = {};
6409
6498
  try {
@@ -6447,30 +6536,6 @@ async function getTronBalances(tronWeb, address, tokens) {
6447
6536
  }
6448
6537
  return balances;
6449
6538
  }
6450
- const EVM_CONFIG = {
6451
- usdtAddress: "0xdAC17F958D2ee523a2206206994597C13D831ec7",
6452
- gasEstimates: {
6453
- approve: 65000n,
6454
- bridge: 300000n
6455
- },
6456
- gasBuffer: 1.2,
6457
- // 20% buffer
6458
- timeout: 12e4
6459
- // 2 minutes
6460
- };
6461
- const TON_CONFIG = {
6462
- apiUrl: "https://toncenter.com/api/v2",
6463
- timeout: 36e4,
6464
- // 6 minutes
6465
- validUntil: 600
6466
- // 10 minutes
6467
- };
6468
- const TRON_CONFIG = {
6469
- timeout: 6e4,
6470
- // 1 minute
6471
- feeLimit: 1e8
6472
- // 100 TRX in sun
6473
- };
6474
6539
  const ERC20_ABI = [
6475
6540
  "function approve(address spender, uint256 amount) returns (bool)",
6476
6541
  "function allowance(address owner, address spender) view returns (uint256)",
@@ -6481,12 +6546,13 @@ class EvmChainStrategy {
6481
6546
  constructor(config) {
6482
6547
  __publicField(this, "config");
6483
6548
  __publicField(this, "provider");
6549
+ __publicField(this, "publicClient");
6484
6550
  this.config = config;
6551
+ this.publicClient = config.publicClient;
6485
6552
  if (config.walletClient) {
6486
6553
  this.provider = new BrowserProvider(config.walletClient.transport);
6487
6554
  }
6488
6555
  }
6489
- // ========== Identity ==========
6490
6556
  canHandle(chainKey) {
6491
6557
  const key = chainKey.toLowerCase();
6492
6558
  return key !== "ton" && key !== "tron";
@@ -6497,7 +6563,6 @@ class EvmChainStrategy {
6497
6563
  getName() {
6498
6564
  return "EVM Chain Strategy";
6499
6565
  }
6500
- // ========== Wallet Management ==========
6501
6566
  async connect() {
6502
6567
  }
6503
6568
  async disconnect() {
@@ -6521,15 +6586,17 @@ class EvmChainStrategy {
6521
6586
  getConnectLabel(t2) {
6522
6587
  return t2("wallets.connectEvmWallet");
6523
6588
  }
6524
- // ========== Balance & Validation ==========
6525
6589
  async getBalances(address, tokens) {
6526
- return await getEvmBalances(address, tokens);
6590
+ if (!this.publicClient) {
6591
+ console.warn("No publicClient available for balance query");
6592
+ return {};
6593
+ }
6594
+ return await getEvmBalances(this.publicClient, address, tokens);
6527
6595
  }
6528
6596
  isAddressValid(address) {
6529
6597
  if (!address) return false;
6530
6598
  return /^0x[0-9a-fA-F]{40}$/.test(address);
6531
6599
  }
6532
- // ========== Gas Estimation ==========
6533
6600
  async estimateGasRequirement(params) {
6534
6601
  const provider = this.provider;
6535
6602
  const {
@@ -6553,8 +6620,8 @@ class EvmChainStrategy {
6553
6620
  const totalGas = approveGas + bridgeGas;
6554
6621
  const bufferMultiplier = BigInt(Math.floor(EVM_CONFIG.gasBuffer * 100));
6555
6622
  const requiredWei = gasPrice * totalGas * bufferMultiplier / 100n;
6556
- const { formatUnits } = await import("ethers");
6557
- estimatedGas = Number(formatUnits(requiredWei, nativeDecimals));
6623
+ const { formatUnits: formatUnits2 } = await import("ethers");
6624
+ estimatedGas = Number(formatUnits2(requiredWei, nativeDecimals));
6558
6625
  } catch {
6559
6626
  estimatedGas = null;
6560
6627
  }
@@ -6576,7 +6643,6 @@ class EvmChainStrategy {
6576
6643
  isNativeSelected
6577
6644
  };
6578
6645
  }
6579
- // ========== Transaction Execution ==========
6580
6646
  validateSteps(steps) {
6581
6647
  if (!steps || steps.length === 0) {
6582
6648
  throw new InvalidStepsError("evm", "No transaction steps provided");
@@ -6638,17 +6704,14 @@ class EvmChainStrategy {
6638
6704
  if (!provider) {
6639
6705
  throw new ProviderNotAvailableError("evm");
6640
6706
  }
6641
- const deadline = Date.now() + EVM_CONFIG.timeout;
6642
- let receipt = null;
6643
- while (Date.now() < deadline) {
6644
- try {
6645
- receipt = await provider.getTransactionReceipt(txHash);
6646
- if (receipt) break;
6647
- } catch (e) {
6648
- console.debug("Error fetching receipt:", e);
6649
- }
6650
- await new Promise((r) => setTimeout(r, 2500));
6651
- }
6707
+ console.log(
6708
+ `Waiting for ${EVM_CONFIG.requiredConfirmations} confirmations for tx: ${txHash}`
6709
+ );
6710
+ const receipt = await provider.waitForTransaction(
6711
+ txHash,
6712
+ EVM_CONFIG.requiredConfirmations,
6713
+ EVM_CONFIG.timeout
6714
+ );
6652
6715
  if (!receipt) {
6653
6716
  const error = new TransactionTimeoutError("evm", txHash);
6654
6717
  return {
@@ -6663,11 +6726,35 @@ class EvmChainStrategy {
6663
6726
  error: error.message
6664
6727
  };
6665
6728
  }
6666
- console.log("EVM transaction confirmed on-chain");
6729
+ console.log(
6730
+ `EVM transaction confirmed in block ${receipt.blockNumber} with ${EVM_CONFIG.requiredConfirmations} confirmations`
6731
+ );
6667
6732
  return {
6668
6733
  completed: true
6669
6734
  };
6670
6735
  } catch (error) {
6736
+ if (error && typeof error === "object" && "code" in error && error.code === "TRANSACTION_REPLACED") {
6737
+ console.log(
6738
+ `Transaction was replaced: ${"reason" in error ? String(error.reason) : "unknown"}`
6739
+ );
6740
+ if ("receipt" in error && error.receipt) {
6741
+ const replacementReceipt = error.receipt;
6742
+ if (replacementReceipt.status === 1) {
6743
+ console.log(
6744
+ `Replacement transaction succeeded in block ${replacementReceipt.blockNumber}`
6745
+ );
6746
+ return {
6747
+ completed: true
6748
+ };
6749
+ } else {
6750
+ const chainError2 = new TransactionRevertedError("evm", txHash);
6751
+ return {
6752
+ completed: false,
6753
+ error: chainError2.message
6754
+ };
6755
+ }
6756
+ }
6757
+ }
6671
6758
  const chainError = toChainStrategyError(
6672
6759
  error,
6673
6760
  "evm",
@@ -6679,7 +6766,6 @@ class EvmChainStrategy {
6679
6766
  };
6680
6767
  }
6681
6768
  }
6682
- // ========== Private Helper Methods ==========
6683
6769
  async executeTransaction(step) {
6684
6770
  const provider = this.provider;
6685
6771
  const signer = await provider?.getSigner();
@@ -6782,13 +6868,52 @@ class EvmChainStrategy {
6782
6868
  return false;
6783
6869
  }
6784
6870
  }
6871
+ /**
6872
+ * Check if a block has reached finality status (optional, for critical transactions)
6873
+ * This is more stringent than confirmations and protects against long-range reorgs
6874
+ *
6875
+ * Usage: Call this method after waitForCompletion if you need additional security
6876
+ * for high-value transactions. The method checks if the block has been marked as
6877
+ * "finalized" by the Ethereum consensus layer (2/3 of validators).
6878
+ *
6879
+ * @param blockNumber - The block number to check for finality
6880
+ * @returns true if the block is finalized, false otherwise
6881
+ */
6882
+ async checkFinality(blockNumber) {
6883
+ try {
6884
+ const provider = this.provider;
6885
+ if (!provider) {
6886
+ return false;
6887
+ }
6888
+ const finalizedBlock = await provider.getBlock("finalized");
6889
+ if (!finalizedBlock) {
6890
+ console.debug(
6891
+ "Finalized block not available (pre-merge or unsupported)"
6892
+ );
6893
+ return false;
6894
+ }
6895
+ const isFinalized = blockNumber <= finalizedBlock.number;
6896
+ if (isFinalized) {
6897
+ console.log(
6898
+ `Block ${blockNumber} has reached finality (finalized block: ${finalizedBlock.number})`
6899
+ );
6900
+ } else {
6901
+ console.debug(
6902
+ `Block ${blockNumber} not yet finalized (finalized block: ${finalizedBlock.number})`
6903
+ );
6904
+ }
6905
+ return isFinalized;
6906
+ } catch (error) {
6907
+ console.debug("Error checking finality:", error);
6908
+ return false;
6909
+ }
6910
+ }
6785
6911
  }
6786
6912
  class TonChainStrategy {
6787
6913
  constructor(config) {
6788
6914
  __publicField(this, "config");
6789
6915
  this.config = config;
6790
6916
  }
6791
- // ========== Identity ==========
6792
6917
  canHandle(chainKey) {
6793
6918
  return chainKey.toLowerCase() === "ton";
6794
6919
  }
@@ -6798,7 +6923,6 @@ class TonChainStrategy {
6798
6923
  getName() {
6799
6924
  return "TON Chain Strategy";
6800
6925
  }
6801
- // ========== Wallet Management ==========
6802
6926
  async connect() {
6803
6927
  await this.config.tonConnectUI?.openModal();
6804
6928
  }
@@ -6823,17 +6947,26 @@ class TonChainStrategy {
6823
6947
  getConnectLabel(t2) {
6824
6948
  return t2("wallets.connectTonWallet");
6825
6949
  }
6826
- // ========== Balance & Validation ==========
6827
- async getBalances(address) {
6828
- return await getSwapBalances(address);
6950
+ async getBalances(address, tokens) {
6951
+ return await getTonBalances(
6952
+ address,
6953
+ tokens,
6954
+ this.config.tonClient,
6955
+ this.config.tonApiKey
6956
+ );
6829
6957
  }
6830
6958
  isAddressValid(address) {
6831
6959
  if (!address) return false;
6832
6960
  return true;
6833
6961
  }
6834
- // ========== Gas Estimation ==========
6835
6962
  async estimateGasRequirement(params) {
6836
- const { selectedToken, nativeTokenSymbol, amount, balances, reserveFallback } = params;
6963
+ const {
6964
+ selectedToken,
6965
+ nativeTokenSymbol,
6966
+ amount,
6967
+ balances,
6968
+ reserveFallback
6969
+ } = params;
6837
6970
  const nativeSym = nativeTokenSymbol.toUpperCase();
6838
6971
  const isNativeSelected = nativeSym === (selectedToken?.symbol ?? "").toUpperCase();
6839
6972
  const nativeBalance = Number(balances[nativeSym]?.balance ?? 0);
@@ -6855,7 +6988,6 @@ class TonChainStrategy {
6855
6988
  isNativeSelected
6856
6989
  };
6857
6990
  }
6858
- // ========== Transaction Execution ==========
6859
6991
  validateSteps(steps) {
6860
6992
  if (!steps || steps.length === 0) {
6861
6993
  throw new InvalidStepsError("ton", "No transaction steps provided");
@@ -6908,19 +7040,17 @@ class TonChainStrategy {
6908
7040
  const result = await this.config.tonConnectUI.sendTransaction(
6909
7041
  transaction
6910
7042
  );
6911
- const hash = this.getTxHash(result.boc);
6912
7043
  return {
6913
7044
  chainKey: "ton",
6914
- hash
7045
+ hash: result.boc
6915
7046
  };
6916
7047
  } catch (error) {
6917
7048
  throw toChainStrategyError(error, "ton", "transaction");
6918
7049
  }
6919
7050
  }
6920
- async waitForCompletion(txHash, context) {
7051
+ async waitForCompletion(txHash) {
6921
7052
  try {
6922
7053
  const confirmed = await this.checkTonTransaction(
6923
- context.srcAddress,
6924
7054
  txHash,
6925
7055
  TON_CONFIG.timeout
6926
7056
  );
@@ -6950,39 +7080,78 @@ class TonChainStrategy {
6950
7080
  };
6951
7081
  }
6952
7082
  }
6953
- // ========== Private Helper Methods ==========
6954
- getTxHash(boc) {
6955
- const cell = Cell.fromBase64(boc);
6956
- const buffer = cell.hash();
6957
- return buffer.toString("hex");
7083
+ getNormalizedExtMessageHash(message) {
7084
+ if (message.info.type !== "external-in") {
7085
+ throw new Error(`Expected external-in message, got ${message.info.type}`);
7086
+ }
7087
+ const normalizedInfo = {
7088
+ ...message.info,
7089
+ src: void 0,
7090
+ importFee: 0n
7091
+ };
7092
+ const normalizedMessage = {
7093
+ ...message,
7094
+ info: normalizedInfo,
7095
+ init: null
7096
+ };
7097
+ return beginCell$1().store(storeMessage(normalizedMessage, { forceRef: true })).endCell().hash();
6958
7098
  }
6959
- async checkTonTransaction(address, txHash, timeoutMs = 36e4) {
7099
+ async checkTonTransaction(bocBase64, timeoutMs = 36e4) {
6960
7100
  const deadline = Date.now() + timeoutMs;
6961
- const normalizedHash = txHash.toLowerCase();
6962
- while (Date.now() < deadline) {
6963
- try {
6964
- const response = await fetch(
6965
- `${TON_CONFIG.apiUrl}/getTransactions?address=${address}&limit=20`
7101
+ const client = getTonClient(this.config.tonClient, this.config.tonApiKey);
7102
+ try {
7103
+ const inMessage = loadMessage(Cell.fromBase64(bocBase64).beginParse());
7104
+ if (inMessage.info.type !== "external-in") {
7105
+ console.debug(
7106
+ "Expected external-in message, got:",
7107
+ inMessage.info.type
6966
7108
  );
6967
- if (!response.ok) {
6968
- console.debug("TonCenter API error:", response.status);
6969
- await new Promise((r) => setTimeout(r, 3e3));
6970
- continue;
6971
- }
6972
- const data = await response.json();
6973
- const transactions = data.result || [];
6974
- for (const tx of transactions) {
6975
- const txIdHash = tx.transaction_id?.hash;
6976
- if (txIdHash && txIdHash.toLowerCase() === normalizedHash) {
6977
- return true;
7109
+ return false;
7110
+ }
7111
+ const accountAddress = inMessage.info.dest;
7112
+ const targetMessageHash = this.getNormalizedExtMessageHash(inMessage);
7113
+ let lt = void 0;
7114
+ let hash = void 0;
7115
+ while (Date.now() < deadline) {
7116
+ try {
7117
+ const transactions = await client.getTransactions(accountAddress, {
7118
+ lt,
7119
+ hash,
7120
+ limit: 10,
7121
+ archival: true
7122
+ });
7123
+ if (transactions.length === 0) {
7124
+ await new Promise((r) => setTimeout(r, 3e3));
7125
+ lt = void 0;
7126
+ hash = void 0;
7127
+ continue;
7128
+ }
7129
+ for (const tx of transactions) {
7130
+ if (tx.inMessage?.info.type === "external-in") {
7131
+ const txInMessageHash = this.getNormalizedExtMessageHash(
7132
+ tx.inMessage
7133
+ );
7134
+ if (txInMessageHash.equals(targetMessageHash)) {
7135
+ console.debug("Transaction found by in-message hash");
7136
+ return true;
7137
+ }
7138
+ }
6978
7139
  }
7140
+ const lastTx = transactions[transactions.length - 1];
7141
+ lt = lastTx.lt.toString();
7142
+ hash = lastTx.hash().toString("base64");
7143
+ } catch (error) {
7144
+ console.debug("Error fetching transactions:", error);
7145
+ await new Promise((r) => setTimeout(r, 3e3));
7146
+ lt = void 0;
7147
+ hash = void 0;
6979
7148
  }
6980
- } catch (e) {
6981
- console.debug("TonCenter polling error:", e);
6982
7149
  }
6983
- await new Promise((r) => setTimeout(r, 3e3));
7150
+ return false;
7151
+ } catch (error) {
7152
+ console.debug("Error parsing BOC or checking transaction:", error);
7153
+ return false;
6984
7154
  }
6985
- return false;
6986
7155
  }
6987
7156
  }
6988
7157
  class TronChainStrategy {
@@ -7043,7 +7212,13 @@ class TronChainStrategy {
7043
7212
  }
7044
7213
  // ========== Gas Estimation ==========
7045
7214
  async estimateGasRequirement(params) {
7046
- const { selectedToken, nativeTokenSymbol, amount, balances, reserveFallback } = params;
7215
+ const {
7216
+ selectedToken,
7217
+ nativeTokenSymbol,
7218
+ amount,
7219
+ balances,
7220
+ reserveFallback
7221
+ } = params;
7047
7222
  const nativeSym = nativeTokenSymbol.toUpperCase();
7048
7223
  const isNativeSelected = nativeSym === (selectedToken?.symbol ?? "").toUpperCase();
7049
7224
  const nativeBalance = Number(balances[nativeSym]?.balance ?? 0);
@@ -7065,7 +7240,6 @@ class TronChainStrategy {
7065
7240
  isNativeSelected
7066
7241
  };
7067
7242
  }
7068
- // ========== Transaction Execution ==========
7069
7243
  validateSteps(steps) {
7070
7244
  console.log("validateSteps");
7071
7245
  if (!steps?.length) {
@@ -7100,7 +7274,10 @@ class TronChainStrategy {
7100
7274
  if (String(step.chainKey).toLowerCase() !== "tron") continue;
7101
7275
  const tx = step.transaction;
7102
7276
  if (!tx) {
7103
- throw new InvalidTransactionDataError("tron", "Missing transaction data");
7277
+ throw new InvalidTransactionDataError(
7278
+ "tron",
7279
+ "Missing transaction data"
7280
+ );
7104
7281
  }
7105
7282
  const hexData = typeof tx?.data === "string" ? tx.data : "";
7106
7283
  const parsed = this.parseTronStep(step, tx, hexData);
@@ -7151,13 +7328,19 @@ class TronChainStrategy {
7151
7328
  break;
7152
7329
  }
7153
7330
  default:
7154
- throw new InvalidStepsError("tron", "Unsupported TRON parsed tx kind");
7331
+ throw new InvalidStepsError(
7332
+ "tron",
7333
+ "Unsupported TRON parsed tx kind"
7334
+ );
7155
7335
  }
7156
7336
  const { txid } = await this.signAndBroadcast(tronWeb, unsigned);
7157
7337
  lastTxId = txid;
7158
7338
  }
7159
7339
  if (!lastTxId) {
7160
- throw new TransactionFailedError("tron", "No TRON transaction was executed");
7340
+ throw new TransactionFailedError(
7341
+ "tron",
7342
+ "No TRON transaction was executed"
7343
+ );
7161
7344
  }
7162
7345
  return { hash: lastTxId, chainKey: "tron" };
7163
7346
  }
@@ -7167,47 +7350,84 @@ class TronChainStrategy {
7167
7350
  if (!tronWeb) {
7168
7351
  throw new ProviderNotAvailableError("tron");
7169
7352
  }
7353
+ console.log(
7354
+ `Waiting for ${TRON_CONFIG.requiredConfirmations} confirmations for TRON tx: ${txHash}`
7355
+ );
7170
7356
  const deadline = Date.now() + TRON_CONFIG.timeout;
7171
- while (Date.now() < deadline) {
7357
+ let txBlockNumber = null;
7358
+ while (Date.now() < deadline && !txBlockNumber) {
7172
7359
  try {
7173
7360
  const info = await tronWeb.trx.getTransactionInfo(txHash);
7174
- console.log("TRON transaction info:", info);
7175
- if (info) {
7361
+ if (info && info.blockNumber) {
7176
7362
  const result = info.receipt?.result;
7177
- if (result === "SUCCESS") {
7178
- console.log("TRON transaction confirmed on-chain");
7363
+ if (result !== "SUCCESS") {
7364
+ const msg = this.hexToAscii(info.resMessage) || null;
7365
+ let reason = msg;
7366
+ const cr = info.contractResult?.[0];
7367
+ if (cr && /^0x?08c379a0/i.test(cr)) {
7368
+ try {
7369
+ const clean = cr.replace(/^0x/, "");
7370
+ const len = parseInt(clean.slice(8 + 64, 8 + 64 + 64), 16);
7371
+ const strHex = clean.slice(
7372
+ 8 + 64 + 64,
7373
+ 8 + 64 + 64 + len * 2
7374
+ );
7375
+ const str = this.hexToAscii("0x" + strHex);
7376
+ if (str) reason = str;
7377
+ } catch (e) {
7378
+ console.debug("TRON revert string decode error", e);
7379
+ }
7380
+ }
7381
+ const error2 = new TransactionRevertedError(
7382
+ "tron",
7383
+ txHash,
7384
+ reason || "Unknown error"
7385
+ );
7179
7386
  return {
7180
- completed: true
7387
+ completed: false,
7388
+ error: error2.message
7181
7389
  };
7182
7390
  }
7183
- const msg = this.hexToAscii(info.resMessage) || null;
7184
- let reason = msg;
7185
- const cr = info.contractResult?.[0];
7186
- if (cr && /^0x?08c379a0/i.test(cr)) {
7187
- try {
7188
- const clean = cr.replace(/^0x/, "");
7189
- const len = parseInt(clean.slice(8 + 64, 8 + 64 + 64), 16);
7190
- const strHex = clean.slice(8 + 64 + 64, 8 + 64 + 64 + len * 2);
7191
- const str = this.hexToAscii("0x" + strHex);
7192
- if (str) reason = str;
7193
- } catch (e) {
7194
- console.debug("TRON revert string decode error", e);
7195
- }
7391
+ txBlockNumber = info.blockNumber;
7392
+ console.log(`TRON transaction found in block ${txBlockNumber}`);
7393
+ }
7394
+ } catch (e) {
7395
+ console.debug("TRON getTransactionInfo error:", e);
7396
+ }
7397
+ if (!txBlockNumber) {
7398
+ await new Promise((r) => setTimeout(r, TRON_CONFIG.pollingInterval));
7399
+ }
7400
+ }
7401
+ if (!txBlockNumber) {
7402
+ const error2 = new TransactionTimeoutError("tron", txHash);
7403
+ return {
7404
+ completed: false,
7405
+ error: error2.message
7406
+ };
7407
+ }
7408
+ let confirmations = 0;
7409
+ while (Date.now() < deadline) {
7410
+ try {
7411
+ const currentBlock = await tronWeb.trx.getCurrentBlock();
7412
+ const currentBlockNumber = currentBlock?.block_header?.raw_data?.number;
7413
+ if (currentBlockNumber) {
7414
+ confirmations = currentBlockNumber - txBlockNumber;
7415
+ if (confirmations >= TRON_CONFIG.requiredConfirmations) {
7416
+ console.log(
7417
+ `TRON transaction confirmed in block ${txBlockNumber} with ${confirmations} confirmations`
7418
+ );
7419
+ return {
7420
+ completed: true
7421
+ };
7196
7422
  }
7197
- const error2 = new TransactionRevertedError(
7198
- "tron",
7199
- txHash,
7200
- reason || "Unknown error"
7423
+ console.log(
7424
+ `TRON transaction confirmations: ${confirmations}/${TRON_CONFIG.requiredConfirmations}`
7201
7425
  );
7202
- return {
7203
- completed: false,
7204
- error: error2.message
7205
- };
7206
7426
  }
7207
7427
  } catch (e) {
7208
- console.debug("TRON getTransactionInfo error:", e);
7428
+ console.debug("TRON getCurrentBlock error:", e);
7209
7429
  }
7210
- await new Promise((r) => setTimeout(r, 3e3));
7430
+ await new Promise((r) => setTimeout(r, TRON_CONFIG.pollingInterval));
7211
7431
  }
7212
7432
  const error = new TransactionTimeoutError("tron", txHash);
7213
7433
  return {
@@ -7215,14 +7435,17 @@ class TronChainStrategy {
7215
7435
  error: error.message
7216
7436
  };
7217
7437
  } catch (error) {
7218
- const chainError = toChainStrategyError(error, "tron", "waitForCompletion");
7438
+ const chainError = toChainStrategyError(
7439
+ error,
7440
+ "tron",
7441
+ "waitForCompletion"
7442
+ );
7219
7443
  return {
7220
7444
  completed: false,
7221
7445
  error: chainError.message
7222
7446
  };
7223
7447
  }
7224
7448
  }
7225
- // ========== Private Helper Methods ==========
7226
7449
  getTronWeb() {
7227
7450
  return typeof window !== "undefined" ? window.tronWeb : void 0;
7228
7451
  }
@@ -7275,7 +7498,10 @@ class TronChainStrategy {
7275
7498
  amount: this.extractAmountFromTxData(tx.data)
7276
7499
  };
7277
7500
  }
7278
- throw new InvalidTransactionDataError("tron", "Cannot parse approve transaction");
7501
+ throw new InvalidTransactionDataError(
7502
+ "tron",
7503
+ "Cannot parse approve transaction"
7504
+ );
7279
7505
  }
7280
7506
  if (step?.type === "transfer" || step?.type === "bridge") {
7281
7507
  const s = step;
@@ -7305,7 +7531,10 @@ class TronChainStrategy {
7305
7531
  feeLimit: raw2.feeLimit
7306
7532
  };
7307
7533
  }
7308
- throw new InvalidTransactionDataError("tron", "Cannot parse transfer/bridge transaction");
7534
+ throw new InvalidTransactionDataError(
7535
+ "tron",
7536
+ "Cannot parse transfer/bridge transaction"
7537
+ );
7309
7538
  }
7310
7539
  if (tx?.to && tx?.value && !tx?.data) {
7311
7540
  const v = BigInt(tx.value.toString());
@@ -7325,19 +7554,28 @@ class TronChainStrategy {
7325
7554
  feeLimit: raw.feeLimit
7326
7555
  };
7327
7556
  }
7328
- throw new InvalidTransactionDataError("tron", `Unsupported TRON step type: ${step?.type ?? "unknown"}`);
7557
+ throw new InvalidTransactionDataError(
7558
+ "tron",
7559
+ `Unsupported TRON step type: ${step?.type ?? "unknown"}`
7560
+ );
7329
7561
  }
7330
7562
  extractSpenderFromTxData(data) {
7331
7563
  const clean = data.replace(/^0x/, "");
7332
7564
  if (clean.length < 74) {
7333
- throw new InvalidTransactionDataError("tron", "Invalid transaction data length");
7565
+ throw new InvalidTransactionDataError(
7566
+ "tron",
7567
+ "Invalid transaction data length"
7568
+ );
7334
7569
  }
7335
7570
  return "41" + clean.slice(32, 72);
7336
7571
  }
7337
7572
  extractAmountFromTxData(data) {
7338
7573
  const clean = data.replace(/^0x/, "");
7339
7574
  if (clean.length < 138) {
7340
- throw new InvalidTransactionDataError("tron", "Invalid transaction data length");
7575
+ throw new InvalidTransactionDataError(
7576
+ "tron",
7577
+ "Invalid transaction data length"
7578
+ );
7341
7579
  }
7342
7580
  const amountHex = clean.slice(72, 136);
7343
7581
  return BigInt("0x" + amountHex).toString();
@@ -7345,7 +7583,10 @@ class TronChainStrategy {
7345
7583
  extractRecipientFromTxData(data) {
7346
7584
  const clean = data.replace(/^0x/, "");
7347
7585
  if (clean.length < 74) {
7348
- throw new InvalidTransactionDataError("tron", "Invalid transaction data length");
7586
+ throw new InvalidTransactionDataError(
7587
+ "tron",
7588
+ "Invalid transaction data length"
7589
+ );
7349
7590
  }
7350
7591
  return "41" + clean.slice(32, 72);
7351
7592
  }
@@ -7420,7 +7661,6 @@ class TronChainStrategy {
7420
7661
  return null;
7421
7662
  }
7422
7663
  }
7423
- // ========== Transaction Builders ==========
7424
7664
  async buildApprove(tronWeb, p) {
7425
7665
  const res = await tronWeb.transactionBuilder.triggerSmartContract(
7426
7666
  p.token,
@@ -7433,7 +7673,10 @@ class TronChainStrategy {
7433
7673
  p.from
7434
7674
  );
7435
7675
  if (!res?.transaction) {
7436
- throw new TransactionFailedError("tron", "Failed to build approve transaction");
7676
+ throw new TransactionFailedError(
7677
+ "tron",
7678
+ "Failed to build approve transaction"
7679
+ );
7437
7680
  }
7438
7681
  return res.transaction;
7439
7682
  }
@@ -7449,7 +7692,10 @@ class TronChainStrategy {
7449
7692
  p.from
7450
7693
  );
7451
7694
  if (!res?.transaction) {
7452
- throw new TransactionFailedError("tron", "Failed to build transfer transaction");
7695
+ throw new TransactionFailedError(
7696
+ "tron",
7697
+ "Failed to build transfer transaction"
7698
+ );
7453
7699
  }
7454
7700
  return res.transaction;
7455
7701
  }
@@ -7469,12 +7715,13 @@ class TronChainStrategy {
7469
7715
  p.from
7470
7716
  );
7471
7717
  if (!res?.transaction) {
7472
- throw new TransactionFailedError("tron", "Failed to build raw call transaction");
7718
+ throw new TransactionFailedError(
7719
+ "tron",
7720
+ "Failed to build raw call transaction"
7721
+ );
7473
7722
  }
7474
7723
  return res.transaction;
7475
7724
  }
7476
- // ========== Transaction Sender ==========
7477
- /* eslint-disable @typescript-eslint/no-explicit-any */
7478
7725
  async signAndBroadcast(tronWeb, unsignedTx) {
7479
7726
  const signed = await tronWeb.trx.sign(unsignedTx);
7480
7727
  const sent = await tronWeb.trx.sendRawTransaction(signed);
@@ -7486,33 +7733,77 @@ class TronChainStrategy {
7486
7733
  }
7487
7734
  return { txid: sent.txid };
7488
7735
  }
7736
+ /**
7737
+ * Check if a transaction has been solidified (confirmed by solidityNode)
7738
+ * This is an additional check for critical transactions to ensure they are
7739
+ * truly confirmed and available through the solidityNode API.
7740
+ *
7741
+ * Usage: Call this method after waitForCompletion for high-value transactions
7742
+ * to get additional assurance that the transaction is solidified.
7743
+ *
7744
+ * @param txHash - Transaction hash to check
7745
+ * @returns true if the transaction is solidified, false otherwise
7746
+ */
7747
+ async checkSolidified(txHash) {
7748
+ try {
7749
+ const tronWeb = this.getTronWeb();
7750
+ if (!tronWeb) {
7751
+ return false;
7752
+ }
7753
+ const info = await tronWeb.trx.getTransactionInfo(txHash);
7754
+ if (!info || !info.blockNumber) {
7755
+ console.debug(
7756
+ "Transaction not yet solidified (no blockNumber in info)"
7757
+ );
7758
+ return false;
7759
+ }
7760
+ const result = info.receipt?.result;
7761
+ if (result === "SUCCESS") {
7762
+ console.log(
7763
+ `Transaction ${txHash} is solidified in block ${info.blockNumber}`
7764
+ );
7765
+ return true;
7766
+ }
7767
+ console.debug(`Transaction solidified but result is: ${result}`);
7768
+ return false;
7769
+ } catch (error) {
7770
+ console.debug("Error checking solidified status:", error);
7771
+ return false;
7772
+ }
7773
+ }
7489
7774
  }
7490
7775
  function ChainStrategyProvider({
7491
7776
  children,
7492
7777
  evmWallet,
7493
7778
  tonWallet,
7494
- tronWallet
7779
+ tronWallet,
7780
+ tonClient,
7781
+ tonApiKey
7495
7782
  }) {
7496
7783
  const evmStrategy = useMemo(
7497
7784
  () => new EvmChainStrategy({
7498
7785
  evmAddress: evmWallet.address,
7499
7786
  evmIsConnected: evmWallet.isConnected,
7500
7787
  evmDisconnect: evmWallet.disconnect,
7501
- walletClient: evmWallet.walletClient
7788
+ walletClient: evmWallet.walletClient,
7789
+ publicClient: evmWallet.publicClient
7502
7790
  }),
7503
7791
  [
7504
7792
  evmWallet.address,
7505
7793
  evmWallet.isConnected,
7506
7794
  evmWallet.disconnect,
7507
- evmWallet.walletClient
7795
+ evmWallet.walletClient,
7796
+ evmWallet.publicClient
7508
7797
  ]
7509
7798
  );
7510
7799
  const tonStrategy = useMemo(
7511
7800
  () => new TonChainStrategy({
7512
7801
  tonConnectUI: tonWallet.tonConnectUI,
7513
- tonAddress: tonWallet.address
7802
+ tonAddress: tonWallet.address,
7803
+ tonClient,
7804
+ tonApiKey
7514
7805
  }),
7515
- [tonWallet.tonConnectUI, tonWallet.address]
7806
+ [tonWallet.tonConnectUI, tonWallet.address, tonClient, tonApiKey]
7516
7807
  );
7517
7808
  const tronStrategy = useMemo(
7518
7809
  () => new TronChainStrategy({
@@ -7534,9 +7825,12 @@ function ChainStrategyProvider({
7534
7825
  () => new ChainStrategyRegistry([evmStrategy, tonStrategy, tronStrategy]),
7535
7826
  [evmStrategy, tonStrategy, tronStrategy]
7536
7827
  );
7537
- const value = {
7538
- chainRegistry
7539
- };
7828
+ const value = useMemo(
7829
+ () => ({
7830
+ chainRegistry
7831
+ }),
7832
+ [chainRegistry]
7833
+ );
7540
7834
  return /* @__PURE__ */ jsx(ChainStrategyContext.Provider, { value, children });
7541
7835
  }
7542
7836
  const EvaaBridgeWithProviders = (props) => {
@@ -7545,6 +7839,7 @@ const EvaaBridgeWithProviders = (props) => {
7545
7839
  const { address: evmAddress, isConnected: evmIsConnected } = useAccount();
7546
7840
  const { disconnect: evmDisconnect } = useDisconnect();
7547
7841
  const { data: walletClient } = useWalletClient();
7842
+ const publicClient = usePublicClient();
7548
7843
  const {
7549
7844
  address: tronAddress,
7550
7845
  connected: tronConnected,
@@ -7569,7 +7864,8 @@ const EvaaBridgeWithProviders = (props) => {
7569
7864
  address: evmAddress,
7570
7865
  isConnected: evmIsConnected,
7571
7866
  disconnect: evmDisconnect,
7572
- walletClient
7867
+ walletClient,
7868
+ publicClient
7573
7869
  },
7574
7870
  tonWallet: {
7575
7871
  tonConnectUI,
@@ -7582,6 +7878,8 @@ const EvaaBridgeWithProviders = (props) => {
7582
7878
  connect: tronConnect,
7583
7879
  disconnect: tronDisconnect
7584
7880
  },
7881
+ tonClient: props.tonClient,
7882
+ tonApiKey: props.tonApiKey,
7585
7883
  children: /* @__PURE__ */ jsx(EvaaBridgeContent, { ...props })
7586
7884
  }
7587
7885
  );
@@ -7686,16 +7984,16 @@ const EvaaBridgeContent = ({
7686
7984
  }, [chains, assetMatrix, allowedFromChains]);
7687
7985
  return /* @__PURE__ */ jsxs(Fragment, { children: [
7688
7986
  /* @__PURE__ */ jsxs(
7689
- "section",
7987
+ Card,
7690
7988
  {
7691
7989
  className: cn(
7692
- "p-5 bg-card max-w-md w-full rounded-3xl mx-auto flex flex-col gap-4 relative",
7990
+ "max-w-md w-full mx-auto flex flex-col relative",
7693
7991
  className
7694
7992
  ),
7695
7993
  ref: modalContainerRef,
7696
7994
  children: [
7697
7995
  /* @__PURE__ */ jsx(FormHeader, { modalContainer: modalContainerRef.current }),
7698
- /* @__PURE__ */ jsxs("div", { className: "space-y-[1px]", children: [
7996
+ /* @__PURE__ */ jsxs(CardContent, { className: "space-y-[1px]", children: [
7699
7997
  /* @__PURE__ */ jsx(
7700
7998
  SwapSection,
7701
7999
  {
@@ -7733,10 +8031,10 @@ const EvaaBridgeContent = ({
7733
8031
  enabled: sendToAnother,
7734
8032
  onToggle: () => setSendToAnother((v) => !v)
7735
8033
  }
7736
- )
8034
+ ),
8035
+ /* @__PURE__ */ jsx(SubmitButton, {})
7737
8036
  ] }),
7738
- /* @__PURE__ */ jsx(SubmitButton, {}),
7739
- /* @__PURE__ */ jsx(ReceiveRow, {})
8037
+ /* @__PURE__ */ jsx(CardFooter, { children: /* @__PURE__ */ jsx(ReceiveRow, {}) })
7740
8038
  ]
7741
8039
  }
7742
8040
  ),
@@ -7825,8 +8123,8 @@ export {
7825
8123
  getQuoteDetails,
7826
8124
  getQuoteFees,
7827
8125
  getQuotesByPriority,
7828
- getSwapBalances,
7829
8126
  getTokens,
8127
+ getTonBalances,
7830
8128
  getTronBalances,
7831
8129
  isAddressValidForChain,
7832
8130
  isEvmAddress,
@@ -7835,7 +8133,7 @@ export {
7835
8133
  isZeroAddr,
7836
8134
  listAssetsForSelect,
7837
8135
  lookupTokenMeta,
7838
- normalizeTickerSymbol,
8136
+ normalizeTickerSymbol$1 as normalizeTickerSymbol,
7839
8137
  pollUntilDelivered,
7840
8138
  resolveTokenOnChain,
7841
8139
  resolveTokenOnChainFromMatrix$2 as resolveTokenOnChainFromMatrix,