@rash2x/bridge-widget 0.2.10 → 0.2.11
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.
- package/README.md +57 -53
- package/dist/evaa-bridge.cjs +307 -103
- package/dist/evaa-bridge.cjs.map +1 -1
- package/dist/evaa-bridge.mjs +309 -105
- package/dist/evaa-bridge.mjs.map +1 -1
- package/dist/index.d.ts +6 -0
- package/dist/styles.css +1 -1
- package/package.json +1 -1
package/dist/evaa-bridge.mjs
CHANGED
|
@@ -10,27 +10,28 @@ import { create } from "zustand";
|
|
|
10
10
|
import { useAccount, useConnect, useDisconnect, useWalletClient, usePublicClient } from "wagmi";
|
|
11
11
|
import { useWallet } from "@tronweb3/tronwallet-adapter-react-hooks";
|
|
12
12
|
import { useTonAddress, useTonConnectUI } from "@tonconnect/ui-react";
|
|
13
|
-
import { Address, beginCell as beginCell$1, storeMessage
|
|
13
|
+
import { Address, loadMessage, Cell, beginCell as beginCell$1, storeMessage } from "@ton/core";
|
|
14
14
|
import { useQuery, useQueryClient } from "@tanstack/react-query";
|
|
15
15
|
import { cn } from "@/lib/utils";
|
|
16
16
|
import { Skeleton } from "@/components/ui/skeleton";
|
|
17
17
|
import { Input } from "@/components/ui/input";
|
|
18
|
-
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription } from "@/components/ui/dialog";
|
|
18
|
+
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter } from "@/components/ui/dialog";
|
|
19
19
|
import { Switch } from "@/components/ui/switch";
|
|
20
20
|
import { X, Loader2, AlertCircleIcon, CheckCircle2, Clock } from "lucide-react";
|
|
21
21
|
import { AnimatePresence, motion } from "framer-motion";
|
|
22
22
|
import { Accordion, AccordionItem, AccordionTrigger, AccordionContent } from "@/components/ui/accordion";
|
|
23
23
|
import { Tooltip, TooltipTrigger, TooltipContent } from "@/components/ui/tooltip";
|
|
24
|
+
import { TonClient, Address as Address$1, beginCell } from "@ton/ton";
|
|
24
25
|
import { toast, Toaster } from "sonner";
|
|
26
|
+
import { DialogDescription as DialogDescription$1 } from "@radix-ui/react-dialog";
|
|
25
27
|
import { BrowserProvider, Contract, parseUnits } from "ethers";
|
|
26
28
|
import { isAddress, formatUnits } from "viem";
|
|
27
|
-
import { TonClient, Address as Address$1, beginCell } from "@ton/ton";
|
|
28
29
|
import { TronLinkAdapterName } from "@tronweb3/tronwallet-adapters";
|
|
29
30
|
import { CardHeader, CardTitle, CardAction, Card, CardContent, CardFooter } from "@/components/ui/card";
|
|
30
31
|
import { Badge } from "@/components/ui/badge";
|
|
31
32
|
const common$1 = { "connecting": "Connecting…", "initializing": "Initializing...", "loading": "Loading...", "paste": "paste", "close": "Close", "zeroPlaceholder": "0", "nativeToken": "Native Token" };
|
|
32
33
|
const wallets$1 = { "addTonWallet": "Add TON wallet", "addEvmWallet": "Add EVM wallet", "connectTonWallet": "Connect TON wallet", "connectEvmWallet": "Connect EVM wallet", "initializingMetamask": "Initializing MetaMask SDK...", "initializingTronlink": "Initializing TronLink...", "failedToConnectTon": "Failed to connect to TON wallet", "failedToDisconnect": "Failed to disconnect", "metamaskConnectionError": "MetaMask connection error", "failedToConnectMetamask": "Failed to connect to MetaMask", "failedToDisconnectMetamask": "Failed to disconnect from MetaMask", "selectWallet": "Select Wallet", "tonWallets": "TON", "evmWallets": "EVM", "tronWallets": "TRON", "tonKeeper": "TonKeeper", "metaMask": "WalletConnect", "tronLink": "TronLink", "addTronWallet": "Add Tron wallet", "comingSoon": "Coming Soon", "connected": "CONNECTED", "disconnect": "Disconnect", "chooseWallet": "Choose wallet", "oneWalletPerEnv": "You can only connect one wallet per environment.", "connect": "Connect", "connectTronWallet": "Connect Tron wallet", "connectWallet": "Connect wallet" };
|
|
33
|
-
const bridge$1 = { "sourceNetwork": "Source network", "destinationNetwork": "Destination network", "selectToken": "Select token", "selectNetwork": "Select network", "searchToken": "Search token", "searchDestinationChain": "Search destination chain", "myTokens": "My tokens", "allTokens": "All tokens", "willChangeSourceChain": "Will Change Source Chain", "noBalancesFound": "No balances found.", "noResults": "No results", "sendToAnotherAddress": "Send to another address", "youWillReceive": "You will receive", "anotherAddressPlaceholder": "Address", "addressDoesntMatch": "Address doesn't match the {{network}} network", "checkBeforeTransfer": "Check correctness before transfer" };
|
|
34
|
+
const bridge$1 = { "max": "Max", "sourceNetwork": "Source network", "destinationNetwork": "Destination network", "selectToken": "Select token", "selectNetwork": "Select network", "searchToken": "Search token", "searchDestinationChain": "Search destination chain", "myTokens": "My tokens", "allTokens": "All tokens", "willChangeSourceChain": "Will Change Source Chain", "noBalancesFound": "No balances found.", "noResults": "No results", "sendToAnotherAddress": "Send to another address", "youWillReceive": "You will receive", "anotherAddressPlaceholder": "Address", "addressDoesntMatch": "Address doesn't match the {{network}} network", "checkBeforeTransfer": "Check correctness before transfer" };
|
|
34
35
|
const transaction$1 = { "enterAmount": "Enter amount", "transfer": "Transfer", "getQuote": "Get quote", "failed": "Transaction Failed", "confirm": "Confirm transaction", "signTransaction": "Sign in transaction in wallet", "quoting": "Quoting...", "inProgress": "Processing...", "checkingBalance": "Checking balance...", "insufficientBalance": "Insufficient balance", "amountTooSmall": "Min {{min}}", "amountTooLarge": "Max {{max}}", "success": "Success", "successTitle": "Success", "done": "Done", "hashCopied": "Hash copied to clipboard", "bridged": "Bridged", "transferTitle": "Transfer", "hash": "Hash", "finalFee": "Final Fee", "route": "Route", "estTime": "Est. Time", "slippage": "Slippage", "minimumReceived": "Minimum received", "totalFee": "Total Fee", "noRouteFound": "No route found", "notEnoughGas": "Not enough gas", "noRouteFoundForSettings": "No route found for current settings.", "tryAdjustSettings": "Try disabling Gas on Destination, or adjust amount/networks.", "quoteError": "Quote error" };
|
|
35
36
|
const app$1 = { "stargateWidgetName": "Stargate Bridge Widget", "liveWidget": "Live Widget", "getStarted": "Get Started" };
|
|
36
37
|
const settings$1 = { "title": "Settings", "gasOnDestination": "Gas on destination", "slippageTolerance": "Slippage tolerance", "routePriority": "Route Priority", "highSlippageWarning": "High slippage warning", "gasPresets": { "auto": "Auto", "none": "None", "medium": "Medium", "max": "Max" }, "routePresets": { "fastest": "Fastest", "cheapest": "Cheapest", "recommended": "Recommended" } };
|
|
@@ -46,7 +47,7 @@ const en = {
|
|
|
46
47
|
};
|
|
47
48
|
const common = { "connecting": "Подключение…", "initializing": "Инициализация...", "loading": "Загрузка...", "paste": "вставить", "close": "Закрыть", "zeroPlaceholder": "0", "nativeToken": "Нативный токен" };
|
|
48
49
|
const wallets = { "addTonWallet": "Добавить TON кошелёк", "addEvmWallet": "Добавить EVM кошелёк", "connectTonWallet": "Подключить TON кошелёк", "connectEvmWallet": "Подключить EVM кошелёк", "initializingMetamask": "Инициализация MetaMask SDK...", "initializingTronlink": "Инициализация TronLink...", "failedToConnectTon": "Не удалось подключиться к TON кошельку", "failedToDisconnect": "Не удалось отключиться", "metamaskConnectionError": "Ошибка подключения MetaMask", "failedToConnectMetamask": "Не удалось подключиться к MetaMask", "failedToDisconnectMetamask": "Не удалось отключиться от MetaMask", "selectWallet": "Выберите кошелёк", "tonWallets": "TON", "evmWallets": "EVM", "tronWallets": "TRON", "tonKeeper": "TonKeeper", "metaMask": "WalletConnect", "tronLink": "TronLink", "addTronWallet": "Добавить Tron кошелёк", "comingSoon": "Скоро", "connected": "ПОДКЛЮЧЕНО", "disconnect": "Отключить", "chooseWallet": "Выберите кошелёк", "oneWalletPerEnv": "Можно подключить только один кошелёк на окружение.", "connect": "Подключить", "connectTronWallet": "Подключить Tron кошелёк", "connectWallet": "Подключить кошелёк" };
|
|
49
|
-
const bridge = { "sourceNetwork": "Исходная сеть", "destinationNetwork": "Целевая сеть", "selectToken": "Выбрать токен", "selectNetwork": "Выбрать сеть", "searchToken": "Поиск токена", "searchDestinationChain": "Поиск целевой сети", "myTokens": "Мои токены", "allTokens": "Все токены", "willChangeSourceChain": "Сменит исходную сеть", "noBalancesFound": "Балансы не найдены.", "noResults": "Нет результатов", "sendToAnotherAddress": "Отправить на другой адрес", "youWillReceive": "Вы получите", "anotherAddressPlaceholder": "Адрес", "addressDoesntMatch": "Адрес не соответствует сети {{network}}", "checkBeforeTransfer": "Проверьте корректность перед переводом" };
|
|
50
|
+
const bridge = { "max": "Макс", "sourceNetwork": "Исходная сеть", "destinationNetwork": "Целевая сеть", "selectToken": "Выбрать токен", "selectNetwork": "Выбрать сеть", "searchToken": "Поиск токена", "searchDestinationChain": "Поиск целевой сети", "myTokens": "Мои токены", "allTokens": "Все токены", "willChangeSourceChain": "Сменит исходную сеть", "noBalancesFound": "Балансы не найдены.", "noResults": "Нет результатов", "sendToAnotherAddress": "Отправить на другой адрес", "youWillReceive": "Вы получите", "anotherAddressPlaceholder": "Адрес", "addressDoesntMatch": "Адрес не соответствует сети {{network}}", "checkBeforeTransfer": "Проверьте корректность перед переводом" };
|
|
50
51
|
const transaction = { "enterAmount": "Введите сумму", "transfer": "Перевести", "getQuote": "Получить котировку", "quoting": "Расчет котировки...", "failed": "Ошибка транзакции", "confirm": "Подтвердите транзакцию", "signTransaction": "Подпишите транзакцию в кошельке", "inProgress": "Выполнение...", "checkingBalance": "Проверка баланса...", "insufficientBalance": "Недостаточно средств", "amountTooSmall": "Минимум {{min}}", "amountTooLarge": "Максимум {{max}}", "success": "Успех", "successTitle": "Успех", "done": "Готово", "hashCopied": "Хэш скопирован в буфер обмена", "bridged": "Переведено", "transferTitle": "Перевод", "hash": "Хэш", "finalFee": "Итоговая комиссия", "route": "Маршрут", "estTime": "Время", "slippage": "Проскальзывание", "minimumReceived": "Минимум к получению", "totalFee": "Общая комиссия", "noRouteFound": "Маршрут не найден", "notEnoughGas": "Недостаточно газа", "noRouteFoundForSettings": "Маршрут не найден для текущих настроек.", "tryAdjustSettings": "Попробуйте отключить Gas on Destination или измените сумму/сети.", "quoteError": "Ошибка котировки" };
|
|
51
52
|
const app = { "stargateWidgetName": "Виджет Stargate Bridge", "liveWidget": "Живой виджет", "getStarted": "Начало работы" };
|
|
52
53
|
const settings = { "title": "Настройки", "gasOnDestination": "Газ на назначении", "slippageTolerance": "Толерантность к проскальзыванию", "routePriority": "Приоритет маршрута", "highSlippageWarning": "Высокое проскальзывание", "gasPresets": { "auto": "Авто", "none": "Нет", "medium": "Средний", "max": "Макс" }, "routePresets": { "fastest": "Быстрейший", "cheapest": "Дешевейший", "recommended": "Рекомендуемый" } };
|
|
@@ -1584,18 +1585,30 @@ const SwapButton = () => {
|
|
|
1584
1585
|
) });
|
|
1585
1586
|
};
|
|
1586
1587
|
const WalletBalance = (props) => {
|
|
1587
|
-
const { value, isLoading = false } = props;
|
|
1588
|
+
const { value, isLoading = false, showMax = false, onMaxClick } = props;
|
|
1589
|
+
const { t } = useBridgeTranslation();
|
|
1588
1590
|
const hasNoData = !value || value === "0" || value === "0.00" || value === "0.0";
|
|
1589
1591
|
const shouldShowSkeleton = isLoading && hasNoData;
|
|
1592
|
+
const shouldShowMaxButton = showMax && !hasNoData && !isLoading;
|
|
1590
1593
|
if (shouldShowSkeleton) {
|
|
1591
1594
|
return /* @__PURE__ */ jsxs("div", { className: "flex gap-2 items-center", children: [
|
|
1592
1595
|
/* @__PURE__ */ jsx(WalletIcon, { className: "text-muted-foreground" }),
|
|
1593
|
-
/* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-
|
|
1596
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-12 rounded-md" })
|
|
1594
1597
|
] });
|
|
1595
1598
|
}
|
|
1596
1599
|
return /* @__PURE__ */ jsxs("div", { className: "flex gap-2 items-center", children: [
|
|
1597
1600
|
/* @__PURE__ */ jsx(WalletIcon, { className: "text-muted-foreground" }),
|
|
1598
|
-
/* @__PURE__ */ jsx("span", { className: "text-sm leading-5 font-medium text-muted-foreground", children: value })
|
|
1601
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm leading-5 font-medium text-muted-foreground", children: value }),
|
|
1602
|
+
shouldShowMaxButton && /* @__PURE__ */ jsx(
|
|
1603
|
+
Button,
|
|
1604
|
+
{
|
|
1605
|
+
variant: "ghost",
|
|
1606
|
+
size: "sm",
|
|
1607
|
+
onClick: onMaxClick,
|
|
1608
|
+
className: "h-auto p-0 px-0 text-xs font-medium border-b border-foreground rounded-none",
|
|
1609
|
+
children: t("bridge.max")
|
|
1610
|
+
}
|
|
1611
|
+
)
|
|
1599
1612
|
] });
|
|
1600
1613
|
};
|
|
1601
1614
|
const BASE_URL$1 = "https://icons-ckg.pages.dev/stargate-light/networks";
|
|
@@ -1836,7 +1849,7 @@ const ChainSelectModal = ({
|
|
|
1836
1849
|
);
|
|
1837
1850
|
};
|
|
1838
1851
|
return /* @__PURE__ */ jsx(Dialog, { open: isOpen, onOpenChange: (open) => !open && handleClose(), children: /* @__PURE__ */ jsxs(DialogContent, { className: "max-h-[90dvh] h-[90dvh] overflow-hidden flex flex-col", children: [
|
|
1839
|
-
/* @__PURE__ */ jsx(DialogHeader, { children: /* @__PURE__ */ jsx(DialogTitle, { children: t("bridge.selectNetwork") }) }),
|
|
1852
|
+
/* @__PURE__ */ jsx(DialogHeader, { className: "text-left", children: /* @__PURE__ */ jsx(DialogTitle, { children: t("bridge.selectNetwork") }) }),
|
|
1840
1853
|
/* @__PURE__ */ jsx(
|
|
1841
1854
|
SearchInput,
|
|
1842
1855
|
{
|
|
@@ -1961,7 +1974,7 @@ const WalletInlineButton = ({
|
|
|
1961
1974
|
disabled: isButtonDisabled,
|
|
1962
1975
|
variant: "ghost",
|
|
1963
1976
|
size: "sm",
|
|
1964
|
-
className: "flex gap-1 cursor-pointer px-0 pr-1 h-5",
|
|
1977
|
+
className: "flex gap-1 cursor-pointer !px-0 pr-1 h-5",
|
|
1965
1978
|
children: [
|
|
1966
1979
|
/* @__PURE__ */ jsx("span", { children: isConnected ? prefixIcons[wallet] : null }),
|
|
1967
1980
|
/* @__PURE__ */ jsx("span", { className: "leading-3 text-sm border-b border-dotted border-link text-link", children: buttonText })
|
|
@@ -2026,6 +2039,11 @@ const SwapSection = ({
|
|
|
2026
2039
|
},
|
|
2027
2040
|
[onSelect, onClose]
|
|
2028
2041
|
);
|
|
2042
|
+
const handleMaxClick = useCallback(() => {
|
|
2043
|
+
if (balance.balance && onAmountChange) {
|
|
2044
|
+
onAmountChange(balance.balance.toString());
|
|
2045
|
+
}
|
|
2046
|
+
}, [balance.balance, onAmountChange]);
|
|
2029
2047
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2030
2048
|
/* @__PURE__ */ jsxs(
|
|
2031
2049
|
"div",
|
|
@@ -2042,7 +2060,9 @@ const SwapSection = ({
|
|
|
2042
2060
|
WalletBalance,
|
|
2043
2061
|
{
|
|
2044
2062
|
value: truncateToDecimals(balance.balance, 2),
|
|
2045
|
-
isLoading: balance.isLoading
|
|
2063
|
+
isLoading: balance.isLoading,
|
|
2064
|
+
showMax: isSource,
|
|
2065
|
+
onMaxClick: handleMaxClick
|
|
2046
2066
|
}
|
|
2047
2067
|
)
|
|
2048
2068
|
] }),
|
|
@@ -2292,6 +2312,53 @@ const TokenSymbol = ({
|
|
|
2292
2312
|
const src = `${BASE_URL}/${normalizedSymbol}.svg`;
|
|
2293
2313
|
return /* @__PURE__ */ jsx("img", { src, alt: alt ?? symbol, className });
|
|
2294
2314
|
};
|
|
2315
|
+
const EVM_CONFIG = {
|
|
2316
|
+
usdtAddress: "0xdAC17F958D2ee523a2206206994597C13D831ec7",
|
|
2317
|
+
gasEstimates: {
|
|
2318
|
+
approve: 65000n,
|
|
2319
|
+
bridge: 300000n
|
|
2320
|
+
},
|
|
2321
|
+
gasBuffer: 1.2,
|
|
2322
|
+
// 20% buffer
|
|
2323
|
+
timeout: 3e5,
|
|
2324
|
+
// 5 minutes (increased for slower networks)
|
|
2325
|
+
requiredConfirmations: 3
|
|
2326
|
+
// Wait for 3 confirmations for reorg protection
|
|
2327
|
+
};
|
|
2328
|
+
const TON_CONFIG = {
|
|
2329
|
+
apiUrl: "https://toncenter.com/api/v2",
|
|
2330
|
+
timeout: 36e4,
|
|
2331
|
+
// 6 minutes
|
|
2332
|
+
validUntil: 600,
|
|
2333
|
+
// 10 minutes
|
|
2334
|
+
pollingInterval: 5e3,
|
|
2335
|
+
// 5 seconds between transaction status checks
|
|
2336
|
+
estimatedNetworkFee: "100000000"
|
|
2337
|
+
// 0.1 TON in nanoton (conservative estimate)
|
|
2338
|
+
};
|
|
2339
|
+
const TRON_CONFIG = {
|
|
2340
|
+
timeout: 12e4,
|
|
2341
|
+
// 2 minutes (for 19 confirmations)
|
|
2342
|
+
feeLimit: 1e8,
|
|
2343
|
+
// 100 TRX in sun
|
|
2344
|
+
requiredConfirmations: 19,
|
|
2345
|
+
// TRON standard: 19 blocks for confirmation
|
|
2346
|
+
pollingInterval: 3e3
|
|
2347
|
+
// 3 seconds between checks
|
|
2348
|
+
};
|
|
2349
|
+
let tonClientInstance = null;
|
|
2350
|
+
function getTonClient(customClient, apiKey) {
|
|
2351
|
+
if (customClient) {
|
|
2352
|
+
return customClient;
|
|
2353
|
+
}
|
|
2354
|
+
if (!tonClientInstance) {
|
|
2355
|
+
tonClientInstance = new TonClient({
|
|
2356
|
+
endpoint: `${TON_CONFIG.apiUrl}/jsonRPC`,
|
|
2357
|
+
apiKey
|
|
2358
|
+
});
|
|
2359
|
+
}
|
|
2360
|
+
return tonClientInstance;
|
|
2361
|
+
}
|
|
2295
2362
|
function getQuoteAmounts(quote, srcToken, dstToken) {
|
|
2296
2363
|
if (!quote || !srcToken || !dstToken) {
|
|
2297
2364
|
return {
|
|
@@ -2371,6 +2438,34 @@ function calculateMinReceived(quote, slippageBps, dstToken) {
|
|
|
2371
2438
|
const minAmountLD = dstAmountLD * BigInt(1e4 - slippageBps) / BigInt(1e4);
|
|
2372
2439
|
return fromLD(minAmountLD.toString(), dstToken.decimals);
|
|
2373
2440
|
}
|
|
2441
|
+
function addTonNetworkFee(quote, chains) {
|
|
2442
|
+
if (!quote || quote.srcChainKey.toLowerCase() !== "ton") {
|
|
2443
|
+
return quote;
|
|
2444
|
+
}
|
|
2445
|
+
const tonChain = chains?.find(
|
|
2446
|
+
(c) => c.chainKey.toLowerCase() === "ton"
|
|
2447
|
+
);
|
|
2448
|
+
if (!tonChain?.nativeCurrency?.address) {
|
|
2449
|
+
console.warn("Could not find TON native currency address");
|
|
2450
|
+
return quote;
|
|
2451
|
+
}
|
|
2452
|
+
const networkFee = {
|
|
2453
|
+
token: tonChain.nativeCurrency.address,
|
|
2454
|
+
chainKey: "ton",
|
|
2455
|
+
amount: TON_CONFIG.estimatedNetworkFee,
|
|
2456
|
+
type: "network"
|
|
2457
|
+
};
|
|
2458
|
+
const hasNetworkFee = quote.fees?.some(
|
|
2459
|
+
(fee) => fee.type === "network" && fee.chainKey === "ton"
|
|
2460
|
+
);
|
|
2461
|
+
if (hasNetworkFee) {
|
|
2462
|
+
return quote;
|
|
2463
|
+
}
|
|
2464
|
+
return {
|
|
2465
|
+
...quote,
|
|
2466
|
+
fees: [...quote.fees || [], networkFee]
|
|
2467
|
+
};
|
|
2468
|
+
}
|
|
2374
2469
|
function getQuoteDetails(quote, srcToken, dstToken, tokens, chains, slippageBps) {
|
|
2375
2470
|
const amounts = getQuoteAmounts(quote, srcToken, dstToken);
|
|
2376
2471
|
const fees = getQuoteFees(quote, tokens, chains, srcToken, dstToken);
|
|
@@ -2409,8 +2504,9 @@ const Details = () => {
|
|
|
2409
2504
|
selectedAssetSymbol,
|
|
2410
2505
|
fromChain?.chainKey
|
|
2411
2506
|
);
|
|
2507
|
+
const quoteWithFees = addTonNetworkFee(quote, chains);
|
|
2412
2508
|
const quoteDetails = getQuoteDetails(
|
|
2413
|
-
quote,
|
|
2509
|
+
quoteWithFees || quote,
|
|
2414
2510
|
srcToken,
|
|
2415
2511
|
dstToken,
|
|
2416
2512
|
tokens,
|
|
@@ -2438,7 +2534,7 @@ const Details = () => {
|
|
|
2438
2534
|
})();
|
|
2439
2535
|
const currentSlippageText = formatPercentage(slippageBps);
|
|
2440
2536
|
const routeText = quote?.route ? getRouteDisplayName(quote.route) : t(`settings.routePresets.${routePriority}`);
|
|
2441
|
-
return /* @__PURE__ */ jsx(Accordion, { type: "single", collapsible: true, className: "w-full", children: /* @__PURE__ */ jsxs(AccordionItem, { value: "item-1", className: "bg-muted rounded-sm", children: [
|
|
2537
|
+
return /* @__PURE__ */ jsx(Accordion, { type: "single", collapsible: true, className: "w-full", children: /* @__PURE__ */ jsxs(AccordionItem, { value: "item-1", className: "bg-muted/50 rounded-sm", children: [
|
|
2442
2538
|
/* @__PURE__ */ jsx(AccordionTrigger, { className: "w-full gap-1 items-center py-6 px-5 rounded-b-sm data-[state=open]:pb-3", children: /* @__PURE__ */ jsxs("div", { className: "w-full flex items-center justify-between", children: [
|
|
2443
2539
|
/* @__PURE__ */ jsx("p", { className: "text-sm font-normal text-priority leading-4", children: t("bridge.youWillReceive", { defaultValue: "You will receive" }) }),
|
|
2444
2540
|
/* @__PURE__ */ jsxs("div", { className: "bg-transparent hover:bg-transparent shadow-none h-4 p-0 px-0 py-0 flex items-center gap-2", children: [
|
|
@@ -2755,8 +2851,9 @@ function useBridgeTransaction() {
|
|
|
2755
2851
|
}
|
|
2756
2852
|
const srcChain = chains?.find((c) => c.chainKey === quote.srcChainKey);
|
|
2757
2853
|
const dstChain = chains?.find((c) => c.chainKey === quote.dstChainKey);
|
|
2758
|
-
const
|
|
2759
|
-
const
|
|
2854
|
+
const quoteWithFees = addTonNetworkFee(quote, chains) || quote;
|
|
2855
|
+
const amounts = getQuoteAmounts(quoteWithFees, srcToken, dstToken);
|
|
2856
|
+
const fees = getQuoteFees(quoteWithFees, tokens, chains, srcToken, dstToken);
|
|
2760
2857
|
const metadata = {
|
|
2761
2858
|
srcChainName: srcChain?.name || quote.srcChainKey,
|
|
2762
2859
|
dstChainName: dstChain?.name || quote.dstChainKey,
|
|
@@ -3155,6 +3252,7 @@ const WalletModalButton = (props) => {
|
|
|
3155
3252
|
const { icon: IconComponent, name, onClose } = props;
|
|
3156
3253
|
const { chainRegistry } = useChainStrategies();
|
|
3157
3254
|
const { connect, isPending } = useConnect();
|
|
3255
|
+
const [isConnecting, setIsConnecting] = useState(false);
|
|
3158
3256
|
if (props.variant === "connected") {
|
|
3159
3257
|
const { address, onDisconnect } = props;
|
|
3160
3258
|
return /* @__PURE__ */ jsx("div", { className: "-mx-3", children: /* @__PURE__ */ jsxs("div", { className: buttonBaseClasses, children: [
|
|
@@ -3178,6 +3276,7 @@ const WalletModalButton = (props) => {
|
|
|
3178
3276
|
}
|
|
3179
3277
|
const { walletId, connector } = props;
|
|
3180
3278
|
const handleConnect = async () => {
|
|
3279
|
+
setIsConnecting(true);
|
|
3181
3280
|
try {
|
|
3182
3281
|
if (connector) {
|
|
3183
3282
|
connect({ connector });
|
|
@@ -3190,9 +3289,13 @@ const WalletModalButton = (props) => {
|
|
|
3190
3289
|
onClose?.();
|
|
3191
3290
|
} catch (error) {
|
|
3192
3291
|
console.error("Failed to connect wallet:", error);
|
|
3292
|
+
const errorMessage = error instanceof Error ? error.message : "Failed to connect wallet. Please try again.";
|
|
3293
|
+
toast.error(errorMessage);
|
|
3294
|
+
} finally {
|
|
3295
|
+
setIsConnecting(false);
|
|
3193
3296
|
}
|
|
3194
3297
|
};
|
|
3195
|
-
const isDisabled = connector ? isPending :
|
|
3298
|
+
const isDisabled = connector ? isPending : isConnecting;
|
|
3196
3299
|
return /* @__PURE__ */ jsxs(
|
|
3197
3300
|
Button,
|
|
3198
3301
|
{
|
|
@@ -3303,7 +3406,7 @@ const WalletSelectModal = () => {
|
|
|
3303
3406
|
}
|
|
3304
3407
|
].filter((category) => category.wallets.length > 0);
|
|
3305
3408
|
return /* @__PURE__ */ jsx(Dialog, { open: isOpen, onOpenChange: (open) => !open && onClose(), children: /* @__PURE__ */ jsxs(DialogContent, { children: [
|
|
3306
|
-
/* @__PURE__ */ jsxs(DialogHeader, { children: [
|
|
3409
|
+
/* @__PURE__ */ jsxs(DialogHeader, { className: "text-left", children: [
|
|
3307
3410
|
/* @__PURE__ */ jsx(DialogTitle, { children: t("wallets.chooseWallet") }),
|
|
3308
3411
|
/* @__PURE__ */ jsx(DialogDescription, { children: t("wallets.oneWalletPerEnv") })
|
|
3309
3412
|
] }),
|
|
@@ -3346,7 +3449,7 @@ const WalletSelectModal = () => {
|
|
|
3346
3449
|
] }) });
|
|
3347
3450
|
};
|
|
3348
3451
|
const ProgressStep = ({
|
|
3349
|
-
icon = /* @__PURE__ */ jsx(Loader2, { className: "w-
|
|
3452
|
+
icon = /* @__PURE__ */ jsx(Loader2, { className: "w-16 h-16 animate-spin" })
|
|
3350
3453
|
}) => {
|
|
3351
3454
|
const { t } = useBridgeTranslation();
|
|
3352
3455
|
return /* @__PURE__ */ jsx(DialogContent, { showCloseButton: false, children: /* @__PURE__ */ jsxs("div", { className: "flex relative flex-col gap-4 py-10 px-8 flex-1 items-center justify-start text-center noise bg-background", children: [
|
|
@@ -3356,33 +3459,123 @@ const ProgressStep = ({
|
|
|
3356
3459
|
] }) });
|
|
3357
3460
|
};
|
|
3358
3461
|
const FailedStep = ({
|
|
3359
|
-
icon = /* @__PURE__ */ jsx(AlertCircleIcon, { className: "w-
|
|
3462
|
+
icon = /* @__PURE__ */ jsx(AlertCircleIcon, { className: "w-16 h-16" })
|
|
3360
3463
|
}) => {
|
|
3361
3464
|
const { current, reset } = useTransactionStore();
|
|
3362
3465
|
const { t } = useBridgeTranslation();
|
|
3363
3466
|
return /* @__PURE__ */ jsxs(DialogContent, { showCloseButton: false, children: [
|
|
3364
|
-
/* @__PURE__ */ jsxs("div", { className: "flex flex-col relative gap-4
|
|
3467
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col relative gap-4 py-10 px-8 flex-1 items-center justify-start text-center noise", children: [
|
|
3365
3468
|
icon,
|
|
3366
|
-
/* @__PURE__ */
|
|
3367
|
-
|
|
3368
|
-
|
|
3369
|
-
|
|
3370
|
-
|
|
3469
|
+
/* @__PURE__ */ jsxs(DialogHeader, { children: [
|
|
3470
|
+
/* @__PURE__ */ jsx(DialogTitle, { children: t("transaction.failed") }),
|
|
3471
|
+
current?.errorCode && /* @__PURE__ */ jsx(DialogDescription$1, { children: t(
|
|
3472
|
+
`errors.${current.errorCode}`,
|
|
3473
|
+
current.errorParams || {}
|
|
3474
|
+
) })
|
|
3475
|
+
] })
|
|
3371
3476
|
] }),
|
|
3372
|
-
/* @__PURE__ */ jsx(
|
|
3477
|
+
/* @__PURE__ */ jsx(DialogFooter, { children: /* @__PURE__ */ jsx(Button, { variant: "outline", className: "w-full min-w-40", onClick: reset, children: t("common.close") }) })
|
|
3373
3478
|
] });
|
|
3374
3479
|
};
|
|
3480
|
+
const EXPLORER_CONFIGS = {
|
|
3481
|
+
// TON
|
|
3482
|
+
ton: {
|
|
3483
|
+
baseUrl: "https://tonscan.org",
|
|
3484
|
+
txPath: "/tx/"
|
|
3485
|
+
},
|
|
3486
|
+
// TRON
|
|
3487
|
+
tron: {
|
|
3488
|
+
baseUrl: "https://tronscan.org",
|
|
3489
|
+
txPath: "/#/transaction/"
|
|
3490
|
+
},
|
|
3491
|
+
// Ethereum & EVM chains
|
|
3492
|
+
ethereum: {
|
|
3493
|
+
baseUrl: "https://etherscan.io",
|
|
3494
|
+
txPath: "/tx/"
|
|
3495
|
+
},
|
|
3496
|
+
eth: {
|
|
3497
|
+
baseUrl: "https://etherscan.io",
|
|
3498
|
+
txPath: "/tx/"
|
|
3499
|
+
},
|
|
3500
|
+
// BSC (Binance Smart Chain)
|
|
3501
|
+
bsc: {
|
|
3502
|
+
baseUrl: "https://bscscan.com",
|
|
3503
|
+
txPath: "/tx/"
|
|
3504
|
+
},
|
|
3505
|
+
"binance-smart-chain": {
|
|
3506
|
+
baseUrl: "https://bscscan.com",
|
|
3507
|
+
txPath: "/tx/"
|
|
3508
|
+
},
|
|
3509
|
+
// Polygon
|
|
3510
|
+
polygon: {
|
|
3511
|
+
baseUrl: "https://polygonscan.com",
|
|
3512
|
+
txPath: "/tx/"
|
|
3513
|
+
},
|
|
3514
|
+
matic: {
|
|
3515
|
+
baseUrl: "https://polygonscan.com",
|
|
3516
|
+
txPath: "/tx/"
|
|
3517
|
+
},
|
|
3518
|
+
// Avalanche
|
|
3519
|
+
avalanche: {
|
|
3520
|
+
baseUrl: "https://snowtrace.io",
|
|
3521
|
+
txPath: "/tx/"
|
|
3522
|
+
},
|
|
3523
|
+
avax: {
|
|
3524
|
+
baseUrl: "https://snowtrace.io",
|
|
3525
|
+
txPath: "/tx/"
|
|
3526
|
+
},
|
|
3527
|
+
// Arbitrum
|
|
3528
|
+
arbitrum: {
|
|
3529
|
+
baseUrl: "https://arbiscan.io",
|
|
3530
|
+
txPath: "/tx/"
|
|
3531
|
+
},
|
|
3532
|
+
// Optimism
|
|
3533
|
+
optimism: {
|
|
3534
|
+
baseUrl: "https://optimistic.etherscan.io",
|
|
3535
|
+
txPath: "/tx/"
|
|
3536
|
+
},
|
|
3537
|
+
// Base
|
|
3538
|
+
base: {
|
|
3539
|
+
baseUrl: "https://basescan.org",
|
|
3540
|
+
txPath: "/tx/"
|
|
3541
|
+
},
|
|
3542
|
+
// Fantom
|
|
3543
|
+
fantom: {
|
|
3544
|
+
baseUrl: "https://ftmscan.com",
|
|
3545
|
+
txPath: "/tx/"
|
|
3546
|
+
}
|
|
3547
|
+
};
|
|
3548
|
+
function getExplorerTxUrl(chainKey, txHash) {
|
|
3549
|
+
if (!chainKey || !txHash) {
|
|
3550
|
+
return null;
|
|
3551
|
+
}
|
|
3552
|
+
const normalizedChainKey = chainKey.toLowerCase();
|
|
3553
|
+
const config = EXPLORER_CONFIGS[normalizedChainKey];
|
|
3554
|
+
if (!config) {
|
|
3555
|
+
console.warn(
|
|
3556
|
+
`No explorer config found for chain: ${chainKey}. Please add it to EXPLORER_CONFIGS.`
|
|
3557
|
+
);
|
|
3558
|
+
return null;
|
|
3559
|
+
}
|
|
3560
|
+
return `${config.baseUrl}${config.txPath}${txHash}`;
|
|
3561
|
+
}
|
|
3562
|
+
function openTransactionInExplorer(chainKey, txHash) {
|
|
3563
|
+
const url = getExplorerTxUrl(chainKey, txHash);
|
|
3564
|
+
if (url && typeof window !== "undefined") {
|
|
3565
|
+
window.open(url, "_blank", "noopener,noreferrer");
|
|
3566
|
+
}
|
|
3567
|
+
}
|
|
3375
3568
|
const SuccessStep = ({
|
|
3376
|
-
icon = /* @__PURE__ */ jsx(CheckCircle2, { className: "w-
|
|
3569
|
+
icon = /* @__PURE__ */ jsx(CheckCircle2, { className: "w-16 h-16" })
|
|
3377
3570
|
}) => {
|
|
3378
3571
|
const { current, reset } = useTransactionStore();
|
|
3379
3572
|
const { t } = useBridgeTranslation();
|
|
3380
3573
|
const metadata = current?.metadata;
|
|
3381
3574
|
const srcTxHash = current?.srcTxHash;
|
|
3382
|
-
const
|
|
3383
|
-
|
|
3384
|
-
|
|
3385
|
-
|
|
3575
|
+
const srcChainKey = current?.quote?.srcChainKey;
|
|
3576
|
+
const handleOpenExplorer = () => {
|
|
3577
|
+
if (srcTxHash && srcChainKey) {
|
|
3578
|
+
openTransactionInExplorer(srcChainKey, srcTxHash);
|
|
3386
3579
|
}
|
|
3387
3580
|
};
|
|
3388
3581
|
return /* @__PURE__ */ jsxs(DialogContent, { showCloseButton: false, children: [
|
|
@@ -3422,8 +3615,8 @@ const SuccessStep = ({
|
|
|
3422
3615
|
/* @__PURE__ */ jsx(
|
|
3423
3616
|
"button",
|
|
3424
3617
|
{
|
|
3425
|
-
onClick:
|
|
3426
|
-
className: "font-medium hover:underline cursor-pointer",
|
|
3618
|
+
onClick: handleOpenExplorer,
|
|
3619
|
+
className: "font-medium hover:underline cursor-pointer inline-flex items-center gap-1",
|
|
3427
3620
|
children: formatHash(srcTxHash)
|
|
3428
3621
|
}
|
|
3429
3622
|
)
|
|
@@ -3459,7 +3652,7 @@ const useCountdown = (initialSeconds) => {
|
|
|
3459
3652
|
};
|
|
3460
3653
|
};
|
|
3461
3654
|
const ConfirmStep = ({
|
|
3462
|
-
icon = /* @__PURE__ */ jsx(Clock, { className: "w-
|
|
3655
|
+
icon = /* @__PURE__ */ jsx(Clock, { className: "w-16 h-16" })
|
|
3463
3656
|
}) => {
|
|
3464
3657
|
const { t } = useBridgeTranslation();
|
|
3465
3658
|
const { formatTime } = useCountdown(90);
|
|
@@ -3613,49 +3806,6 @@ class ChainStrategyRegistry {
|
|
|
3613
3806
|
await strategy.disconnect();
|
|
3614
3807
|
}
|
|
3615
3808
|
}
|
|
3616
|
-
const EVM_CONFIG = {
|
|
3617
|
-
usdtAddress: "0xdAC17F958D2ee523a2206206994597C13D831ec7",
|
|
3618
|
-
gasEstimates: {
|
|
3619
|
-
approve: 65000n,
|
|
3620
|
-
bridge: 300000n
|
|
3621
|
-
},
|
|
3622
|
-
gasBuffer: 1.2,
|
|
3623
|
-
// 20% buffer
|
|
3624
|
-
timeout: 3e5,
|
|
3625
|
-
// 5 minutes (increased for slower networks)
|
|
3626
|
-
requiredConfirmations: 3
|
|
3627
|
-
// Wait for 3 confirmations for reorg protection
|
|
3628
|
-
};
|
|
3629
|
-
const TON_CONFIG = {
|
|
3630
|
-
apiUrl: "https://toncenter.com/api/v2",
|
|
3631
|
-
timeout: 36e4,
|
|
3632
|
-
// 6 minutes
|
|
3633
|
-
validUntil: 600
|
|
3634
|
-
// 10 minutes
|
|
3635
|
-
};
|
|
3636
|
-
const TRON_CONFIG = {
|
|
3637
|
-
timeout: 12e4,
|
|
3638
|
-
// 2 minutes (for 19 confirmations)
|
|
3639
|
-
feeLimit: 1e8,
|
|
3640
|
-
// 100 TRX in sun
|
|
3641
|
-
requiredConfirmations: 19,
|
|
3642
|
-
// TRON standard: 19 blocks for confirmation
|
|
3643
|
-
pollingInterval: 3e3
|
|
3644
|
-
// 3 seconds between checks
|
|
3645
|
-
};
|
|
3646
|
-
let tonClientInstance = null;
|
|
3647
|
-
function getTonClient(customClient, apiKey) {
|
|
3648
|
-
if (customClient) {
|
|
3649
|
-
return customClient;
|
|
3650
|
-
}
|
|
3651
|
-
if (!tonClientInstance) {
|
|
3652
|
-
tonClientInstance = new TonClient({
|
|
3653
|
-
endpoint: `${TON_CONFIG.apiUrl}/jsonRPC`,
|
|
3654
|
-
apiKey
|
|
3655
|
-
});
|
|
3656
|
-
}
|
|
3657
|
-
return tonClientInstance;
|
|
3658
|
-
}
|
|
3659
3809
|
function isNativeAddress(addr) {
|
|
3660
3810
|
if (!addr) return false;
|
|
3661
3811
|
const a = addr.toLowerCase();
|
|
@@ -4399,13 +4549,17 @@ class TonChainStrategy {
|
|
|
4399
4549
|
nativeTokenSymbol,
|
|
4400
4550
|
amount,
|
|
4401
4551
|
balances,
|
|
4552
|
+
nativeDecimals = 9,
|
|
4402
4553
|
reserveFallback
|
|
4403
4554
|
} = params;
|
|
4404
4555
|
const nativeSym = nativeTokenSymbol.toUpperCase();
|
|
4405
4556
|
const isNativeSelected = nativeSym === (selectedToken?.symbol ?? "").toUpperCase();
|
|
4406
4557
|
const nativeBalance = Number(balances[nativeSym]?.balance ?? 0);
|
|
4407
|
-
const
|
|
4408
|
-
const
|
|
4558
|
+
const { formatUnits: formatUnits2 } = await import("ethers");
|
|
4559
|
+
const estimatedGas = Number(
|
|
4560
|
+
formatUnits2(TON_CONFIG.estimatedNetworkFee, nativeDecimals)
|
|
4561
|
+
);
|
|
4562
|
+
const requiredNative = estimatedGas > 0 ? estimatedGas : reserveFallback;
|
|
4409
4563
|
const amountNum = amount ?? 0;
|
|
4410
4564
|
let hasEnoughGas = true;
|
|
4411
4565
|
if (isNativeSelected) {
|
|
@@ -4474,12 +4628,24 @@ class TonChainStrategy {
|
|
|
4474
4628
|
const result = await this.config.tonConnectUI.sendTransaction(
|
|
4475
4629
|
transaction2
|
|
4476
4630
|
);
|
|
4477
|
-
const
|
|
4478
|
-
|
|
4479
|
-
|
|
4480
|
-
|
|
4481
|
-
|
|
4482
|
-
|
|
4631
|
+
const bocBase64 = result.boc;
|
|
4632
|
+
try {
|
|
4633
|
+
const inMessage = loadMessage(Cell.fromBase64(bocBase64).beginParse());
|
|
4634
|
+
const messageHash = this.getNormalizedExtMessageHash(inMessage);
|
|
4635
|
+
const hexHash = messageHash.toString("hex");
|
|
4636
|
+
onFirstHash?.(hexHash);
|
|
4637
|
+
return {
|
|
4638
|
+
chainKey: "ton",
|
|
4639
|
+
hash: hexHash
|
|
4640
|
+
};
|
|
4641
|
+
} catch (error) {
|
|
4642
|
+
console.error("Error parsing BOC to hex hash:", error);
|
|
4643
|
+
onFirstHash?.(bocBase64);
|
|
4644
|
+
return {
|
|
4645
|
+
chainKey: "ton",
|
|
4646
|
+
hash: bocBase64
|
|
4647
|
+
};
|
|
4648
|
+
}
|
|
4483
4649
|
} catch (error) {
|
|
4484
4650
|
throw toChainStrategyError(error, "ton", "transaction");
|
|
4485
4651
|
}
|
|
@@ -4532,20 +4698,31 @@ class TonChainStrategy {
|
|
|
4532
4698
|
};
|
|
4533
4699
|
return beginCell$1().store(storeMessage(normalizedMessage, { forceRef: true })).endCell().hash();
|
|
4534
4700
|
}
|
|
4535
|
-
async checkTonTransaction(
|
|
4701
|
+
async checkTonTransaction(hashOrBoc, timeoutMs = 36e4) {
|
|
4536
4702
|
const deadline = Date.now() + timeoutMs;
|
|
4537
4703
|
const client = getTonClient(this.config.tonClient, this.config.tonApiKey);
|
|
4538
4704
|
try {
|
|
4539
|
-
|
|
4540
|
-
|
|
4541
|
-
|
|
4542
|
-
|
|
4543
|
-
|
|
4544
|
-
|
|
4545
|
-
|
|
4705
|
+
let targetMessageHash;
|
|
4706
|
+
let accountAddress;
|
|
4707
|
+
try {
|
|
4708
|
+
const inMessage = loadMessage(Cell.fromBase64(hashOrBoc).beginParse());
|
|
4709
|
+
if (inMessage.info.type !== "external-in") {
|
|
4710
|
+
console.debug(
|
|
4711
|
+
"Expected external-in message, got:",
|
|
4712
|
+
inMessage.info.type
|
|
4713
|
+
);
|
|
4714
|
+
return false;
|
|
4715
|
+
}
|
|
4716
|
+
accountAddress = inMessage.info.dest;
|
|
4717
|
+
targetMessageHash = this.getNormalizedExtMessageHash(inMessage);
|
|
4718
|
+
} catch {
|
|
4719
|
+
targetMessageHash = Buffer.from(hashOrBoc, "hex");
|
|
4720
|
+
if (!this.config.tonAddress) {
|
|
4721
|
+
console.debug("No wallet address available for hex hash lookup");
|
|
4722
|
+
return false;
|
|
4723
|
+
}
|
|
4724
|
+
accountAddress = Address.parse(this.config.tonAddress);
|
|
4546
4725
|
}
|
|
4547
|
-
const accountAddress = inMessage.info.dest;
|
|
4548
|
-
const targetMessageHash = this.getNormalizedExtMessageHash(inMessage);
|
|
4549
4726
|
let lt = void 0;
|
|
4550
4727
|
let hash = void 0;
|
|
4551
4728
|
while (Date.now() < deadline) {
|
|
@@ -4557,7 +4734,7 @@ class TonChainStrategy {
|
|
|
4557
4734
|
archival: true
|
|
4558
4735
|
});
|
|
4559
4736
|
if (transactions.length === 0) {
|
|
4560
|
-
await new Promise((r) => setTimeout(r,
|
|
4737
|
+
await new Promise((r) => setTimeout(r, TON_CONFIG.pollingInterval));
|
|
4561
4738
|
lt = void 0;
|
|
4562
4739
|
hash = void 0;
|
|
4563
4740
|
continue;
|
|
@@ -4576,9 +4753,10 @@ class TonChainStrategy {
|
|
|
4576
4753
|
const lastTx = transactions[transactions.length - 1];
|
|
4577
4754
|
lt = lastTx.lt.toString();
|
|
4578
4755
|
hash = lastTx.hash().toString("base64");
|
|
4756
|
+
await new Promise((r) => setTimeout(r, TON_CONFIG.pollingInterval));
|
|
4579
4757
|
} catch (error) {
|
|
4580
4758
|
console.debug("Error fetching transactions:", error);
|
|
4581
|
-
await new Promise((r) => setTimeout(r,
|
|
4759
|
+
await new Promise((r) => setTimeout(r, TON_CONFIG.pollingInterval));
|
|
4582
4760
|
lt = void 0;
|
|
4583
4761
|
hash = void 0;
|
|
4584
4762
|
}
|
|
@@ -4605,9 +4783,14 @@ class TronChainStrategy {
|
|
|
4605
4783
|
return "TRON Chain Strategy";
|
|
4606
4784
|
}
|
|
4607
4785
|
async connect() {
|
|
4608
|
-
|
|
4609
|
-
|
|
4610
|
-
|
|
4786
|
+
if (!this.isTronLinkInstalled()) {
|
|
4787
|
+
if (typeof window !== "undefined") {
|
|
4788
|
+
window.open("https://www.tronlink.org/", "_blank");
|
|
4789
|
+
}
|
|
4790
|
+
throw new WalletNotFoundError(
|
|
4791
|
+
"tron",
|
|
4792
|
+
"TronLink wallet is not installed. Please install TronLink extension and try again."
|
|
4793
|
+
);
|
|
4611
4794
|
}
|
|
4612
4795
|
this.config.tronSelect(TronLinkAdapterName);
|
|
4613
4796
|
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
@@ -4886,6 +5069,23 @@ class TronChainStrategy {
|
|
|
4886
5069
|
getTronWeb() {
|
|
4887
5070
|
return typeof window !== "undefined" ? window.tronWeb : void 0;
|
|
4888
5071
|
}
|
|
5072
|
+
/**
|
|
5073
|
+
* Check if TronLink wallet is actually installed
|
|
5074
|
+
* This excludes Bybit Wallet which also injects tronLink for compatibility
|
|
5075
|
+
*/
|
|
5076
|
+
isTronLinkInstalled() {
|
|
5077
|
+
if (typeof window === "undefined") {
|
|
5078
|
+
return false;
|
|
5079
|
+
}
|
|
5080
|
+
const hasBybitWallet = typeof window.bybitWallet !== "undefined" && typeof window.bybitWallet.tronLink !== "undefined";
|
|
5081
|
+
if (hasBybitWallet && !window.tronLink) {
|
|
5082
|
+
return false;
|
|
5083
|
+
}
|
|
5084
|
+
if (!window.tronLink) {
|
|
5085
|
+
return false;
|
|
5086
|
+
}
|
|
5087
|
+
return true;
|
|
5088
|
+
}
|
|
4889
5089
|
hexToAscii(h) {
|
|
4890
5090
|
if (!h) return null;
|
|
4891
5091
|
const clean = h.replace(/^0x/, "");
|
|
@@ -5289,7 +5489,7 @@ const routePresets = [
|
|
|
5289
5489
|
RoutePriority.CHEAPEST,
|
|
5290
5490
|
RoutePriority.RECOMMENDED
|
|
5291
5491
|
];
|
|
5292
|
-
const
|
|
5492
|
+
const SettingsModal = ({ isOpen, onClose }) => {
|
|
5293
5493
|
const { t } = useBridgeTranslation();
|
|
5294
5494
|
const { toChain } = useChainsStore();
|
|
5295
5495
|
const { tokens } = useTokensStore();
|
|
@@ -5322,8 +5522,8 @@ const SettingModal = ({ isOpen, onClose }) => {
|
|
|
5322
5522
|
);
|
|
5323
5523
|
const activeBtn = "bg-primary hover:bg-primary/80 text-primary-foreground transition-colors";
|
|
5324
5524
|
const notActiveBtn = "bg-accent hover:bg-accent/80 text-accent-foreground transition-colors";
|
|
5325
|
-
return /* @__PURE__ */ jsx(Dialog, { open: isOpen, onOpenChange: (open) => !open && onClose(), children: /* @__PURE__ */ jsxs(DialogContent, { children: [
|
|
5326
|
-
/* @__PURE__ */ jsx(DialogHeader, { children: /* @__PURE__ */ jsx(DialogTitle, { children: t("settings.title") }) }),
|
|
5525
|
+
return /* @__PURE__ */ jsx(Dialog, { open: isOpen, onOpenChange: (open) => !open && onClose(), children: /* @__PURE__ */ jsxs(DialogContent, { onOpenAutoFocus: (e) => e.preventDefault(), children: [
|
|
5526
|
+
/* @__PURE__ */ jsx(DialogHeader, { className: "text-left", children: /* @__PURE__ */ jsx(DialogTitle, { children: t("settings.title") }) }),
|
|
5327
5527
|
/* @__PURE__ */ jsxs("div", { className: "space-y-5", children: [
|
|
5328
5528
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-5", children: [
|
|
5329
5529
|
/* @__PURE__ */ jsxs("div", { className: "flex justify-between items-center", children: [
|
|
@@ -5351,6 +5551,7 @@ const SettingModal = ({ isOpen, onClose }) => {
|
|
|
5351
5551
|
Badge,
|
|
5352
5552
|
{
|
|
5353
5553
|
onClick: () => setGasPreset(g),
|
|
5554
|
+
size: "lg",
|
|
5354
5555
|
className: cn(
|
|
5355
5556
|
"cursor-pointer",
|
|
5356
5557
|
gasPreset === g ? activeBtn : notActiveBtn
|
|
@@ -5377,6 +5578,7 @@ const SettingModal = ({ isOpen, onClose }) => {
|
|
|
5377
5578
|
/* @__PURE__ */ jsx("div", { className: "flex items-center gap-2", children: slippagePresets.map((p) => /* @__PURE__ */ jsx(
|
|
5378
5579
|
Badge,
|
|
5379
5580
|
{
|
|
5581
|
+
size: "lg",
|
|
5380
5582
|
onClick: () => {
|
|
5381
5583
|
const bps = parseFloat(p.replace("%", "")) * 100;
|
|
5382
5584
|
setSlippageBps(bps);
|
|
@@ -5400,6 +5602,7 @@ const SettingModal = ({ isOpen, onClose }) => {
|
|
|
5400
5602
|
/* @__PURE__ */ jsx("div", { className: "flex items-center justify-end gap-2", children: routePresets.map((r) => /* @__PURE__ */ jsx(
|
|
5401
5603
|
Badge,
|
|
5402
5604
|
{
|
|
5605
|
+
size: "lg",
|
|
5403
5606
|
onClick: () => setRoutePriority(r),
|
|
5404
5607
|
className: cn(
|
|
5405
5608
|
"cursor-pointer",
|
|
@@ -5592,7 +5795,7 @@ const TokenSelectModal = ({
|
|
|
5592
5795
|
);
|
|
5593
5796
|
const hasNoResults = tokensToRender.length === 0 && willChangeSrcTokens.length === 0;
|
|
5594
5797
|
return /* @__PURE__ */ jsx(Dialog, { open: isOpen, onOpenChange: (open) => !open && handleClose(), children: /* @__PURE__ */ jsxs(DialogContent, { className: "max-h-[90dvh] h-[90dvh] overflow-hidden flex flex-col", children: [
|
|
5595
|
-
/* @__PURE__ */ jsx(DialogHeader, { children: /* @__PURE__ */ jsx(DialogTitle, { children: t("bridge.selectToken") }) }),
|
|
5798
|
+
/* @__PURE__ */ jsx(DialogHeader, { className: "text-left", children: /* @__PURE__ */ jsx(DialogTitle, { children: t("bridge.selectToken") }) }),
|
|
5596
5799
|
/* @__PURE__ */ jsx(
|
|
5597
5800
|
SearchInput,
|
|
5598
5801
|
{
|
|
@@ -5816,7 +6019,7 @@ const Toolbar = () => {
|
|
|
5816
6019
|
}
|
|
5817
6020
|
}
|
|
5818
6021
|
),
|
|
5819
|
-
/* @__PURE__ */ jsx(
|
|
6022
|
+
/* @__PURE__ */ jsx(SettingsModal, { isOpen: isOpenSettings, onClose: onCloseSettings })
|
|
5820
6023
|
] });
|
|
5821
6024
|
};
|
|
5822
6025
|
const EvaaBridgeWithProviders = (props) => {
|
|
@@ -6079,6 +6282,7 @@ export {
|
|
|
6079
6282
|
EvaaBridge,
|
|
6080
6283
|
RoutePriority,
|
|
6081
6284
|
RouteType,
|
|
6285
|
+
addTonNetworkFee,
|
|
6082
6286
|
addrForApi,
|
|
6083
6287
|
buildAssetMatrix,
|
|
6084
6288
|
calculateMinReceived,
|