@rash2x/bridge-widget 0.6.55 → 0.6.61
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/dist/evaa-bridge.cjs +1 -7
- package/dist/evaa-bridge.cjs.map +1 -1
- package/dist/evaa-bridge.mjs +29 -35
- package/dist/{index-BTwKvCVG.cjs → index-Bl9Q1m-4.cjs} +2 -2
- package/dist/{index-BTwKvCVG.cjs.map → index-Bl9Q1m-4.cjs.map} +1 -1
- package/dist/{index-CePOaHyN.js → index-D0OSdsmf.js} +743 -1163
- package/dist/index-D0OSdsmf.js.map +1 -0
- package/dist/{index-CTtu-a2U.cjs → index-rAch8BQe.cjs} +713 -1133
- package/dist/index-rAch8BQe.cjs.map +1 -0
- package/dist/{index-C_cDfEeV.js → index-yQkayDGz.js} +2 -2
- package/dist/{index-C_cDfEeV.js.map → index-yQkayDGz.js.map} +1 -1
- package/dist/index.d.ts +1 -40
- package/dist/styles.css +1 -1
- package/package.json +1 -1
- package/dist/index-CTtu-a2U.cjs.map +0 -1
- package/dist/index-CePOaHyN.js.map +0 -1
|
@@ -10,15 +10,14 @@ import { create } from "zustand";
|
|
|
10
10
|
import { useAccount, usePublicClient, useConnect, useDisconnect, useWalletClient } 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
|
|
14
|
-
import { TonClient, Address as Address$1, beginCell } from "@ton/ton";
|
|
13
|
+
import { Address, loadMessage, Cell, beginCell as beginCell$1, storeMessage } from "@ton/core";
|
|
15
14
|
import { useQuery, useQueryClient } from "@tanstack/react-query";
|
|
16
15
|
import { cn as cn$2 } from "@/lib/utils";
|
|
17
16
|
import { Skeleton } from "@/components/ui/skeleton";
|
|
18
17
|
import { Input } from "@/components/ui/input";
|
|
19
18
|
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter } from "@/components/ui/dialog";
|
|
19
|
+
import { XIcon, X as X$3, Loader2, AlertCircleIcon, ArrowRight, CheckCircle2, Clock } from "lucide-react";
|
|
20
20
|
import { Switch } from "@/components/ui/switch";
|
|
21
|
-
import { X as X$3, Loader2, AlertCircleIcon, ArrowRight, CheckCircle2, Clock } from "lucide-react";
|
|
22
21
|
import { AnimatePresence, motion } from "framer-motion";
|
|
23
22
|
import { Accordion, AccordionItem, AccordionTrigger, AccordionContent } from "@/components/ui/accordion";
|
|
24
23
|
import { Tooltip, TooltipTrigger, TooltipContent } from "@/components/ui/tooltip";
|
|
@@ -26,7 +25,8 @@ import { Alert, AlertDescription } from "@/components/ui/alert";
|
|
|
26
25
|
import { toast, Toaster } from "sonner";
|
|
27
26
|
import { Badge } from "@/components/ui/badge";
|
|
28
27
|
import { DialogDescription as DialogDescription$1 } from "@radix-ui/react-dialog";
|
|
29
|
-
import { isAddress, formatUnits, parseUnits } from "viem";
|
|
28
|
+
import { isAddress, formatUnits, parseAbi, parseUnits } from "viem";
|
|
29
|
+
import { TonClient, Address as Address$1, beginCell } from "@ton/ton";
|
|
30
30
|
import { TronLinkAdapterName } from "@tronweb3/tronwallet-adapters";
|
|
31
31
|
import { TronWeb } from "tronweb";
|
|
32
32
|
import { CardHeader, CardTitle, CardAction, Card, CardContent, CardFooter } from "@/components/ui/card";
|
|
@@ -34,7 +34,7 @@ import { FixedSizeList } from "react-window";
|
|
|
34
34
|
const common$1 = { "connecting": "Connecting…", "initializing": "Initializing...", "loading": "Loading...", "paste": "paste", "close": "Close", "zeroPlaceholder": "0", "nativeToken": "Native Token" };
|
|
35
35
|
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", "tonconnect": "TonConnect", "metaMask": "WalletConnect", "walletConnect": "WalletConnect", "tronLink": "TronLink", "addTronWallet": "Add Tron wallet", "comingSoon": "Coming Soon", "connected": "CONNECTED", "connectedStatus": "Connected", "disconnect": "Disconnect", "chooseWallet": "Connect wallet", "oneWalletPerEnv": "You can only connect one wallet per environment.", "connect": "Connect", "connectTronWallet": "Connect Tron wallet", "connectWallet": "Connect wallet" };
|
|
36
36
|
const bridge$1 = { "max": "Max", "sourceNetwork": "Source network", "destinationNetwork": "Destination network", "selectToken": "Select token", "selectNetwork": "Select network", "selectSourceNetwork": "Select source network", "selectDestinationNetwork": "Select destination network", "searchToken": "Search token", "myTokens": "My tokens", "allTokens": "All tokens", "search": "Search", "select": "Select", "willChangeSourceChain": "Will change source network", "willChangeSourceNetworkAndToken": "Will change source token", "noBalancesFound": "No balances found.", "noResults": "No results", "tokenNotFound": "We couldn't find a token with that name or symbol. Please try again.", "chainNotFound": "We couldn't find a chain with that name. Please try again.", "sendToAnotherAddress": "Send to another address", "youWillReceive": "You will receive", "anotherAddressPlaceholder": "Address", "addressDoesntMatch": "Address doesn't match the {{network}} network", "checkBeforeTransfer": "Check correctness before transfer" };
|
|
37
|
-
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": "Transaction in progress...", "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", "layerzeroScan": "
|
|
37
|
+
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": "Transaction in progress...", "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", "layerzeroScan": "TxHash", "finalFee": "Final Fee", "route": "Route", "estTime": "Est. Time", "slippage": "Slippage", "minimumReceived": "Minimum received", "totalFee": "Total Fee", "noRouteFound": "No route found", "notEnoughGas": "Not enough gas", "pasteAddressToTransfer": "Paste address to transfer", "noRouteFoundForSettings": "No route found for current settings.", "tryAdjustSettings": "Try disabling Gas on Destination, or adjust amount/networks.", "quoteError": "Quote error", "steps": { "sent": "Sent", "processing": "Processing", "processingNote": "Up to 2 minutes", "completed": "Completed" } };
|
|
38
38
|
const telegram$1 = { "openWebVersion": "Open EVAA Web to Bridge", "restrictionMessage": "You can bridge between the chosen networks on EVAA web version" };
|
|
39
39
|
const app$1 = { "stargateWidgetName": "Stargate Bridge Widget", "liveWidget": "Live Widget", "getStarted": "Get Started" };
|
|
40
40
|
const settings$1 = { "title": "Settings", "gasOnDestination": "Gas on destination", "gasOnDestinationDescription": "The default amount allows you to perform a couple of transactions (e.g. Approve and Swap).", "slippageTolerance": "Slippage tolerance", "slippageToleranceDescription": "Your transaction will revert if the amount you're receiving is outside of this tolerance", "routePriority": "Route Priority", "routePriorityDescription": "Choose how your transfer is routed. Recommended picks the best overall path for cost. Fastest prioritizes speed above all else.", "highSlippageWarning": "High slippage warning", "gasPresets": { "auto": "Auto", "none": "None", "medium": "Medium", "max": "Max" }, "routePresets": { "fastest": "Fastest", "cheapest": "Cheapest", "recommended": "Recommended" } };
|
|
@@ -52,7 +52,7 @@ const en$3 = {
|
|
|
52
52
|
const common = { "connecting": "Подключение…", "initializing": "Инициализация...", "loading": "Загрузка...", "paste": "вставить", "close": "Закрыть", "zeroPlaceholder": "0", "nativeToken": "Нативный токен" };
|
|
53
53
|
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", "tonconnect": "TonConnect", "metaMask": "WalletConnect", "walletConnect": "WalletConnect", "tronLink": "TronLink", "addTronWallet": "Добавить Tron кошелёк", "comingSoon": "Скоро", "connected": "ПОДКЛЮЧЕНО", "connectedStatus": "Подключён", "disconnect": "Отключить", "chooseWallet": "Подключите кошелек", "oneWalletPerEnv": "Можно подключить только один кошелёк на окружение.", "connect": "Подключить", "connectTronWallet": "Подключить Tron кошелёк", "connectWallet": "Подключить кошелёк" };
|
|
54
54
|
const bridge = { "max": "Макс", "sourceNetwork": "Исходная сеть", "destinationNetwork": "Целевая сеть", "selectToken": "Выбрать токен", "selectNetwork": "Выбрать сеть", "selectSourceNetwork": "Выбрать исходную сеть", "selectDestinationNetwork": "Выбрать целевую сеть", "searchToken": "Поиск токена", "myTokens": "Мои токены", "allTokens": "Все токены", "search": "Поиск", "select": "Выбрать", "willChangeSourceChain": "Сменит исходную сеть", "willChangeSourceNetworkAndToken": "Сменит исходный токен", "noBalancesFound": "Балансы не найдены.", "noResults": "Нет результатов", "tokenNotFound": "Мы не смогли найти токен с таким названием или символом. Пожалуйста, попробуйте снова.", "chainNotFound": "Мы не смогли найти сеть с таким названием. Пожалуйста, попробуйте снова.", "sendToAnotherAddress": "Отправить на другой адрес", "youWillReceive": "Вы получите", "anotherAddressPlaceholder": "Адрес", "addressDoesntMatch": "Адрес не соответствует сети {{network}}", "checkBeforeTransfer": "Проверьте корректность перед переводом" };
|
|
55
|
-
const transaction = { "enterAmount": "Введите сумму", "transfer": "Перевести", "getQuote": "Получить котировку", "quoting": "Расчет котировки...", "failed": "Ошибка транзакции", "confirm": "Подтвердите транзакцию", "signTransaction": "Подпишите транзакцию в кошельке", "inProgress": "Транзакция выполняется...", "checkingBalance": "Проверка баланса...", "insufficientBalance": "Недостаточно средств", "amountTooSmall": "Минимум {{min}}", "amountTooLarge": "Максимум {{max}}", "success": "Успех", "successTitle": "Успех", "done": "Готово", "hashCopied": "Хэш скопирован в буфер обмена", "bridged": "Переведено", "transferTitle": "Перевод", "hash": "Хэш", "layerzeroScan": "
|
|
55
|
+
const transaction = { "enterAmount": "Введите сумму", "transfer": "Перевести", "getQuote": "Получить котировку", "quoting": "Расчет котировки...", "failed": "Ошибка транзакции", "confirm": "Подтвердите транзакцию", "signTransaction": "Подпишите транзакцию в кошельке", "inProgress": "Транзакция выполняется...", "checkingBalance": "Проверка баланса...", "insufficientBalance": "Недостаточно средств", "amountTooSmall": "Минимум {{min}}", "amountTooLarge": "Максимум {{max}}", "success": "Успех", "successTitle": "Успех", "done": "Готово", "hashCopied": "Хэш скопирован в буфер обмена", "bridged": "Переведено", "transferTitle": "Перевод", "hash": "Хэш", "layerzeroScan": "TxHash", "finalFee": "Итоговая комиссия", "route": "Маршрут", "estTime": "Время", "slippage": "Проскальзывание", "minimumReceived": "Минимум к получению", "totalFee": "Общая комиссия", "noRouteFound": "Маршрут не найден", "notEnoughGas": "Недостаточно газа", "pasteAddressToTransfer": "Укажите адрес получателя", "noRouteFoundForSettings": "Маршрут не найден для текущих настроек.", "tryAdjustSettings": "Попробуйте отключить Gas on Destination или измените сумму/сети.", "quoteError": "Ошибка котировки", "steps": { "sent": "Отправлено", "processing": "Обработка", "processingNote": "До 2 минут", "completed": "Завершено" } };
|
|
56
56
|
const telegram = { "openWebVersion": "Открыть EVAA веб для трансфера", "restrictionMessage": "Трансфер между выбранными сетями доступен только в веб-версии EVAA" };
|
|
57
57
|
const app = { "stargateWidgetName": "Виджет Stargate Bridge", "liveWidget": "Живой виджет", "getStarted": "Начало работы" };
|
|
58
58
|
const settings = { "title": "Настройки", "gasOnDestination": "Газ на назначении", "gasOnDestinationDescription": "Значение по умолчанию позволяет выполнить пару транзакций (например, Approve и Swap).", "slippageTolerance": "Толерантность к проскальзыванию", "slippageToleranceDescription": "Ваша транзакция будет отклонена, если получаемая сумма выйдет за пределы этой допустимой погрешности.", "routePriority": "Приоритет маршрута", "routePriorityDescription": "Выберите, как будет выполняться ваш трансфер. Recommended — выбирает оптимальный маршрут с учётом общей стоимости. Fastest — отдаёт приоритет максимальной скорости.", "highSlippageWarning": "Высокое проскальзывание", "gasPresets": { "auto": "Авто", "none": "Нет", "medium": "Средний", "max": "Макс" }, "routePresets": { "fastest": "Быстрейший", "cheapest": "Дешевейший", "recommended": "Рекомендуемый" } };
|
|
@@ -940,375 +940,6 @@ function useChainStrategies() {
|
|
|
940
940
|
}
|
|
941
941
|
return context;
|
|
942
942
|
}
|
|
943
|
-
const truncateToDecimals = (num, decimals) => {
|
|
944
|
-
if (!isFinite(num) || isNaN(num)) return "0";
|
|
945
|
-
const multiplier = Math.pow(10, decimals);
|
|
946
|
-
const truncated = Math.floor(num * multiplier) / multiplier;
|
|
947
|
-
return truncated.toFixed(decimals).replace(/\.?0+$/, "");
|
|
948
|
-
};
|
|
949
|
-
const formatTokenAmount = (amount, symbol, options) => {
|
|
950
|
-
const normalizedSymbol = (symbol ?? "").toUpperCase();
|
|
951
|
-
if (["USDT", "USDC", "DAI", "BUSD"].includes(normalizedSymbol) && amount >= 1) {
|
|
952
|
-
return `${Math.floor(amount)} ${normalizedSymbol}`;
|
|
953
|
-
}
|
|
954
|
-
if (options?.decimals !== void 0) {
|
|
955
|
-
return `${amount.toFixed(options.decimals)} ${normalizedSymbol}`;
|
|
956
|
-
}
|
|
957
|
-
if (amount >= 1) {
|
|
958
|
-
return `${amount.toFixed(0)} ${normalizedSymbol}`;
|
|
959
|
-
} else if (amount >= 1e-3) {
|
|
960
|
-
return `${amount.toFixed(3)} ${normalizedSymbol}`;
|
|
961
|
-
} else {
|
|
962
|
-
return `${amount.toFixed(6)} ${normalizedSymbol}`;
|
|
963
|
-
}
|
|
964
|
-
};
|
|
965
|
-
const formatUsd = (value) => {
|
|
966
|
-
if (!value || !isFinite(value)) return "$0";
|
|
967
|
-
if (value >= 1) return `$${value.toFixed(2)}`;
|
|
968
|
-
return `$${value.toFixed(6).replace(/0+$/, "").replace(/\.$/, "")}`;
|
|
969
|
-
};
|
|
970
|
-
const formatPercentage = (bps, decimals = 2) => {
|
|
971
|
-
return `${(bps / 100).toFixed(decimals).replace(/0+$/, "").replace(/\.$/, "")}%`;
|
|
972
|
-
};
|
|
973
|
-
const formatBalance = (amount, decimals = 2) => {
|
|
974
|
-
if (!isFinite(amount) || isNaN(amount) || amount <= 0) {
|
|
975
|
-
return "0.00";
|
|
976
|
-
}
|
|
977
|
-
return amount.toFixed(decimals);
|
|
978
|
-
};
|
|
979
|
-
const formatHash = (hash, startChars = 4, endChars = 4) => {
|
|
980
|
-
if (!hash) return "";
|
|
981
|
-
if (hash.length <= startChars + endChars) return hash;
|
|
982
|
-
return `${hash.slice(0, startChars)}...${hash.slice(-endChars)}`;
|
|
983
|
-
};
|
|
984
|
-
const formatAddress = formatHash;
|
|
985
|
-
const EVM_CONFIG = {
|
|
986
|
-
usdtAddress: "0xdAC17F958D2ee523a2206206994597C13D831ec7",
|
|
987
|
-
gasEstimates: {
|
|
988
|
-
approve: 65000n,
|
|
989
|
-
bridge: 300000n
|
|
990
|
-
},
|
|
991
|
-
gasBuffer: 1.2,
|
|
992
|
-
// 20% buffer
|
|
993
|
-
timeout: 3e5,
|
|
994
|
-
// 5 minutes (increased for slower networks)
|
|
995
|
-
requiredConfirmations: 3
|
|
996
|
-
// Wait for 3 confirmations for reorg protection
|
|
997
|
-
};
|
|
998
|
-
const TON_CONFIG = {
|
|
999
|
-
apiUrl: "https://toncenter.com/api/v2",
|
|
1000
|
-
timeout: 36e4,
|
|
1001
|
-
// 6 minutes
|
|
1002
|
-
validUntil: 600,
|
|
1003
|
-
// 10 minutes
|
|
1004
|
-
pollingInterval: 5e3,
|
|
1005
|
-
// 5 seconds between transaction status checks
|
|
1006
|
-
estimatedNetworkFee: "100000000"
|
|
1007
|
-
// 0.1 TON in nanoton (conservative estimate)
|
|
1008
|
-
};
|
|
1009
|
-
const TRON_CONFIG = {
|
|
1010
|
-
timeout: 12e4,
|
|
1011
|
-
// 2 minutes (for 19 confirmations)
|
|
1012
|
-
feeLimit: 1e8,
|
|
1013
|
-
// 100 TRX in sun
|
|
1014
|
-
requiredConfirmations: 19,
|
|
1015
|
-
// TRON standard: 19 blocks for confirmation
|
|
1016
|
-
pollingInterval: 3e3,
|
|
1017
|
-
// 3 seconds between checks
|
|
1018
|
-
estimatedNetworkFee: "10000000"
|
|
1019
|
-
// 10 TRX in SUN (fallback estimate)
|
|
1020
|
-
};
|
|
1021
|
-
let tonClientInstance = null;
|
|
1022
|
-
function getTonClient(customClient, apiKey) {
|
|
1023
|
-
if (customClient) {
|
|
1024
|
-
return customClient;
|
|
1025
|
-
}
|
|
1026
|
-
if (!tonClientInstance) {
|
|
1027
|
-
tonClientInstance = new TonClient({
|
|
1028
|
-
endpoint: `${TON_CONFIG.apiUrl}/jsonRPC`,
|
|
1029
|
-
apiKey
|
|
1030
|
-
});
|
|
1031
|
-
}
|
|
1032
|
-
return tonClientInstance;
|
|
1033
|
-
}
|
|
1034
|
-
function getQuoteAmounts(quote, srcToken, dstToken) {
|
|
1035
|
-
if (!quote || !srcToken || !dstToken) {
|
|
1036
|
-
return {
|
|
1037
|
-
inputHuman: 0,
|
|
1038
|
-
outputHuman: 0,
|
|
1039
|
-
outputHumanRounded: "0",
|
|
1040
|
-
minReceivedHuman: 0
|
|
1041
|
-
};
|
|
1042
|
-
}
|
|
1043
|
-
const inputHuman = fromLD(quote.srcAmount, srcToken.decimals);
|
|
1044
|
-
const outputHuman = fromLD(quote.dstAmount, dstToken.decimals);
|
|
1045
|
-
const outputHumanRounded = truncateToDecimals(outputHuman, 2);
|
|
1046
|
-
const minReceivedHuman = fromLD(quote.dstAmountMin || "0", dstToken.decimals);
|
|
1047
|
-
return {
|
|
1048
|
-
inputHuman,
|
|
1049
|
-
outputHuman,
|
|
1050
|
-
outputHumanRounded,
|
|
1051
|
-
minReceivedHuman
|
|
1052
|
-
};
|
|
1053
|
-
}
|
|
1054
|
-
function getQuoteFees(quote, tokens, chains, srcToken, dstToken) {
|
|
1055
|
-
if (!quote || !tokens || !chains) {
|
|
1056
|
-
return {
|
|
1057
|
-
fees: { usd: /* @__PURE__ */ new Map(), original: /* @__PURE__ */ new Map(), formatted: /* @__PURE__ */ new Map() },
|
|
1058
|
-
inSrcToken: void 0,
|
|
1059
|
-
inDstToken: void 0
|
|
1060
|
-
};
|
|
1061
|
-
}
|
|
1062
|
-
const feeData = computeFeesUsdFromArray(quote.fees, tokens, chains);
|
|
1063
|
-
let inSrcToken = void 0;
|
|
1064
|
-
let inDstToken = void 0;
|
|
1065
|
-
if (srcToken && quote.srcChainKey) {
|
|
1066
|
-
const feeInSrcLD = sumFeeByTokenLD(
|
|
1067
|
-
quote.fees,
|
|
1068
|
-
srcToken.address,
|
|
1069
|
-
quote.srcChainKey
|
|
1070
|
-
);
|
|
1071
|
-
const feeInSrcHuman = fromLD(feeInSrcLD, srcToken.decimals);
|
|
1072
|
-
if (feeInSrcHuman > 0) {
|
|
1073
|
-
inSrcToken = Number(truncateToDecimals(feeInSrcHuman, 8));
|
|
1074
|
-
} else if ((feeData.usd.get("total") || 0) > 0 && srcToken.price?.usd) {
|
|
1075
|
-
const feeInSrcApprox = (feeData.usd.get("total") || 0) / srcToken.price.usd;
|
|
1076
|
-
inSrcToken = Number(truncateToDecimals(feeInSrcApprox, 8));
|
|
1077
|
-
}
|
|
1078
|
-
}
|
|
1079
|
-
if (dstToken && quote.dstChainKey) {
|
|
1080
|
-
const feeInDstLD = sumFeeByTokenLD(
|
|
1081
|
-
quote.fees,
|
|
1082
|
-
dstToken.address,
|
|
1083
|
-
quote.dstChainKey
|
|
1084
|
-
);
|
|
1085
|
-
const feeInDstHuman = fromLD(feeInDstLD, dstToken.decimals);
|
|
1086
|
-
if (feeInDstHuman > 0) {
|
|
1087
|
-
inDstToken = Number(truncateToDecimals(feeInDstHuman, 8));
|
|
1088
|
-
}
|
|
1089
|
-
}
|
|
1090
|
-
return {
|
|
1091
|
-
fees: feeData,
|
|
1092
|
-
inSrcToken,
|
|
1093
|
-
inDstToken
|
|
1094
|
-
};
|
|
1095
|
-
}
|
|
1096
|
-
function calculateMinReceived(quote, slippageBps, dstToken) {
|
|
1097
|
-
if (!quote || !dstToken) return 0;
|
|
1098
|
-
const dstAmountLD = BigInt(quote.dstAmount);
|
|
1099
|
-
const minAmountLD = dstAmountLD * BigInt(1e4 - slippageBps) / BigInt(1e4);
|
|
1100
|
-
return fromLD(minAmountLD.toString(), dstToken.decimals);
|
|
1101
|
-
}
|
|
1102
|
-
function estimateTonNetworkFee(quote) {
|
|
1103
|
-
try {
|
|
1104
|
-
const tonStep = quote.steps?.find(
|
|
1105
|
-
(s2) => s2.chainKey.toLowerCase() === "ton" && s2.type === "bridge"
|
|
1106
|
-
);
|
|
1107
|
-
if (!tonStep?.transaction?.messages) {
|
|
1108
|
-
console.warn("No TON messages found in quote, using fallback");
|
|
1109
|
-
return TON_CONFIG.estimatedNetworkFee;
|
|
1110
|
-
}
|
|
1111
|
-
const messages = tonStep.transaction.messages;
|
|
1112
|
-
const messageCount = messages.length;
|
|
1113
|
-
const baseFeePerMessage = 10000000n;
|
|
1114
|
-
let totalFee = 0n;
|
|
1115
|
-
for (const message of messages) {
|
|
1116
|
-
let messageFee = baseFeePerMessage;
|
|
1117
|
-
if (message.payload) {
|
|
1118
|
-
const payloadSize = message.payload.length;
|
|
1119
|
-
const sizeFee = BigInt(Math.floor(payloadSize / 100)) * 100000n;
|
|
1120
|
-
messageFee += sizeFee;
|
|
1121
|
-
}
|
|
1122
|
-
if (message.amount) {
|
|
1123
|
-
const amount = BigInt(message.amount);
|
|
1124
|
-
if (amount > 0n && message.payload) {
|
|
1125
|
-
messageFee += 5000000n;
|
|
1126
|
-
}
|
|
1127
|
-
}
|
|
1128
|
-
totalFee += messageFee;
|
|
1129
|
-
}
|
|
1130
|
-
const minBuffer = 50000000n;
|
|
1131
|
-
totalFee = totalFee > minBuffer ? totalFee : minBuffer;
|
|
1132
|
-
totalFee = totalFee * 120n / 100n;
|
|
1133
|
-
const maxFee = 1000000000n;
|
|
1134
|
-
if (totalFee > maxFee) {
|
|
1135
|
-
totalFee = maxFee;
|
|
1136
|
-
}
|
|
1137
|
-
console.log(
|
|
1138
|
-
`TON fee estimate: ${messageCount} messages = ${Number(totalFee) / 1e9} TON`
|
|
1139
|
-
);
|
|
1140
|
-
return totalFee.toString();
|
|
1141
|
-
} catch (error) {
|
|
1142
|
-
console.warn("Failed to estimate TON fee:", error);
|
|
1143
|
-
return TON_CONFIG.estimatedNetworkFee;
|
|
1144
|
-
}
|
|
1145
|
-
}
|
|
1146
|
-
function addTonNetworkFee(quote, chains, estimatedFee) {
|
|
1147
|
-
if (!quote || quote.srcChainKey.toLowerCase() !== "ton") {
|
|
1148
|
-
return quote;
|
|
1149
|
-
}
|
|
1150
|
-
const tonChain = chains?.find((c2) => c2.chainKey.toLowerCase() === "ton");
|
|
1151
|
-
if (!tonChain?.nativeCurrency?.address) {
|
|
1152
|
-
console.warn("Could not find TON native currency address");
|
|
1153
|
-
return quote;
|
|
1154
|
-
}
|
|
1155
|
-
const networkFee = {
|
|
1156
|
-
token: tonChain.nativeCurrency.address,
|
|
1157
|
-
chainKey: "ton",
|
|
1158
|
-
amount: estimatedFee || TON_CONFIG.estimatedNetworkFee,
|
|
1159
|
-
type: "network"
|
|
1160
|
-
};
|
|
1161
|
-
const hasNetworkFee = quote.fees?.some(
|
|
1162
|
-
(fee) => fee.type === "network" && fee.chainKey === "ton"
|
|
1163
|
-
);
|
|
1164
|
-
if (hasNetworkFee) {
|
|
1165
|
-
return quote;
|
|
1166
|
-
}
|
|
1167
|
-
return {
|
|
1168
|
-
...quote,
|
|
1169
|
-
fees: [...quote.fees || [], networkFee]
|
|
1170
|
-
};
|
|
1171
|
-
}
|
|
1172
|
-
async function estimateTronNetworkFee(tronWeb, quote, userAddress) {
|
|
1173
|
-
try {
|
|
1174
|
-
const accountResources = await tronWeb.trx.getAccountResources(userAddress);
|
|
1175
|
-
const availableEnergy = accountResources.EnergyLimit || 0;
|
|
1176
|
-
const tronStep = quote.steps?.find(
|
|
1177
|
-
(s2) => s2.chainKey.toLowerCase() === "tron" && s2.type === "bridge"
|
|
1178
|
-
);
|
|
1179
|
-
if (!tronStep?.transaction?.data || !tronStep.transaction.to) {
|
|
1180
|
-
console.warn("No TRON transaction data in quote, using fallback");
|
|
1181
|
-
return TRON_CONFIG.estimatedNetworkFee;
|
|
1182
|
-
}
|
|
1183
|
-
const contractAddress = tronWeb.address.fromHex(
|
|
1184
|
-
tronStep.transaction.to.startsWith("41") ? tronStep.transaction.to : "41" + tronStep.transaction.to.slice(2)
|
|
1185
|
-
);
|
|
1186
|
-
const simulation = await tronWeb.transactionBuilder.triggerSmartContract(
|
|
1187
|
-
contractAddress,
|
|
1188
|
-
"function signature doesn't matter for energy estimation",
|
|
1189
|
-
{
|
|
1190
|
-
feeLimit: TRON_CONFIG.feeLimit,
|
|
1191
|
-
callValue: tronStep.transaction.value ? Number(tronStep.transaction.value) : 0
|
|
1192
|
-
},
|
|
1193
|
-
[],
|
|
1194
|
-
userAddress
|
|
1195
|
-
);
|
|
1196
|
-
const requiredEnergy = simulation.energy_used || 0;
|
|
1197
|
-
const energyDeficit = Math.max(0, requiredEnergy - availableEnergy);
|
|
1198
|
-
if (energyDeficit === 0) {
|
|
1199
|
-
return "0";
|
|
1200
|
-
}
|
|
1201
|
-
const energyPriceInSun = 420;
|
|
1202
|
-
const feeSun = energyDeficit * energyPriceInSun;
|
|
1203
|
-
console.log(
|
|
1204
|
-
`TRON fee estimation: ${requiredEnergy} energy required, ${availableEnergy} available, ${feeSun / 1e6} TRX fee`
|
|
1205
|
-
);
|
|
1206
|
-
return feeSun.toString();
|
|
1207
|
-
} catch (error) {
|
|
1208
|
-
console.warn("Failed to estimate TRON network fee:", error);
|
|
1209
|
-
return TRON_CONFIG.estimatedNetworkFee;
|
|
1210
|
-
}
|
|
1211
|
-
}
|
|
1212
|
-
function addTronNetworkFee(quote, chains, estimatedFee) {
|
|
1213
|
-
if (!quote || quote.srcChainKey.toLowerCase() !== "tron") {
|
|
1214
|
-
return quote;
|
|
1215
|
-
}
|
|
1216
|
-
const tronChain = chains?.find((c2) => c2.chainKey.toLowerCase() === "tron");
|
|
1217
|
-
if (!tronChain?.nativeCurrency?.address) {
|
|
1218
|
-
console.warn("Could not find TRON native currency address");
|
|
1219
|
-
return quote;
|
|
1220
|
-
}
|
|
1221
|
-
const networkFee = {
|
|
1222
|
-
token: tronChain.nativeCurrency.address,
|
|
1223
|
-
chainKey: "tron",
|
|
1224
|
-
amount: estimatedFee || TRON_CONFIG.estimatedNetworkFee,
|
|
1225
|
-
type: "network"
|
|
1226
|
-
};
|
|
1227
|
-
const hasNetworkFee = quote.fees?.some(
|
|
1228
|
-
(fee) => fee.type === "network" && fee.chainKey === "tron"
|
|
1229
|
-
);
|
|
1230
|
-
if (hasNetworkFee) {
|
|
1231
|
-
return quote;
|
|
1232
|
-
}
|
|
1233
|
-
return {
|
|
1234
|
-
...quote,
|
|
1235
|
-
fees: [...quote.fees || [], networkFee]
|
|
1236
|
-
};
|
|
1237
|
-
}
|
|
1238
|
-
async function estimateEvmNetworkFee(publicClient, quote, chainKey) {
|
|
1239
|
-
try {
|
|
1240
|
-
let totalGasLimit = 0n;
|
|
1241
|
-
for (const step of quote.steps || []) {
|
|
1242
|
-
if (step.chainKey.toLowerCase() !== chainKey.toLowerCase()) continue;
|
|
1243
|
-
if (step.type === "approve") {
|
|
1244
|
-
totalGasLimit += EVM_CONFIG.gasEstimates.approve;
|
|
1245
|
-
} else if (step.type === "bridge") {
|
|
1246
|
-
totalGasLimit += EVM_CONFIG.gasEstimates.bridge;
|
|
1247
|
-
}
|
|
1248
|
-
}
|
|
1249
|
-
if (totalGasLimit === 0n) {
|
|
1250
|
-
return "0";
|
|
1251
|
-
}
|
|
1252
|
-
totalGasLimit = totalGasLimit * BigInt(Math.floor(EVM_CONFIG.gasBuffer * 100)) / 100n;
|
|
1253
|
-
const gasPrice = await publicClient.getGasPrice();
|
|
1254
|
-
const totalCostWei = totalGasLimit * gasPrice;
|
|
1255
|
-
return totalCostWei.toString();
|
|
1256
|
-
} catch (error) {
|
|
1257
|
-
console.warn("Failed to estimate EVM gas fee:", error);
|
|
1258
|
-
return "10000000000000000";
|
|
1259
|
-
}
|
|
1260
|
-
}
|
|
1261
|
-
function addEvmNetworkFee(quote, chains, estimatedFee) {
|
|
1262
|
-
if (!quote) return quote;
|
|
1263
|
-
const srcChainKey = quote.srcChainKey.toLowerCase();
|
|
1264
|
-
if (srcChainKey === "ton" || srcChainKey === "tron") {
|
|
1265
|
-
return quote;
|
|
1266
|
-
}
|
|
1267
|
-
const srcChain = chains?.find(
|
|
1268
|
-
(c2) => c2.chainKey.toLowerCase() === srcChainKey
|
|
1269
|
-
);
|
|
1270
|
-
if (!srcChain?.nativeCurrency?.address) {
|
|
1271
|
-
return quote;
|
|
1272
|
-
}
|
|
1273
|
-
const hasNetworkFee = quote.fees?.some(
|
|
1274
|
-
(fee) => fee.type === "network" && fee.chainKey.toLowerCase() === srcChainKey
|
|
1275
|
-
);
|
|
1276
|
-
if (hasNetworkFee) {
|
|
1277
|
-
return quote;
|
|
1278
|
-
}
|
|
1279
|
-
const networkFee = {
|
|
1280
|
-
token: srcChain.nativeCurrency.address,
|
|
1281
|
-
chainKey: quote.srcChainKey,
|
|
1282
|
-
amount: estimatedFee || "10000000000000000",
|
|
1283
|
-
type: "network"
|
|
1284
|
-
};
|
|
1285
|
-
return {
|
|
1286
|
-
...quote,
|
|
1287
|
-
fees: [...quote.fees || [], networkFee]
|
|
1288
|
-
};
|
|
1289
|
-
}
|
|
1290
|
-
function getQuoteDetails(quote, srcToken, dstToken, tokens, chains, slippageBps) {
|
|
1291
|
-
const amounts = getQuoteAmounts(quote, srcToken, dstToken);
|
|
1292
|
-
const fees = getQuoteFees(quote, tokens, chains, srcToken, dstToken);
|
|
1293
|
-
const minimumReceived = calculateMinReceived(quote, slippageBps, dstToken);
|
|
1294
|
-
return {
|
|
1295
|
-
inputAmount: amounts.inputHuman,
|
|
1296
|
-
outputAmount: amounts.outputHuman,
|
|
1297
|
-
outputAmountRounded: amounts.outputHumanRounded,
|
|
1298
|
-
minimumReceived,
|
|
1299
|
-
etaSeconds: quote?.duration?.estimated,
|
|
1300
|
-
fees
|
|
1301
|
-
};
|
|
1302
|
-
}
|
|
1303
|
-
function getRouteDisplayName(route) {
|
|
1304
|
-
if (!route) return "Stargate Bridge";
|
|
1305
|
-
const routeLower = route.toLowerCase();
|
|
1306
|
-
if (routeLower.includes("taxi")) return "Stargate V2 Fast";
|
|
1307
|
-
if (routeLower.includes("bus")) return "Stargate V2 Economy";
|
|
1308
|
-
if (routeLower.includes("oft")) return "OFT Bridge";
|
|
1309
|
-
if (routeLower.includes("v2")) return "Stargate V2";
|
|
1310
|
-
return route.split(/[/\-_]/).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(" ");
|
|
1311
|
-
}
|
|
1312
943
|
const toSharedDecimals = (amount, fromDecimals, toDecimals) => {
|
|
1313
944
|
const value = BigInt(amount);
|
|
1314
945
|
const diff = BigInt(toDecimals) - BigInt(fromDecimals);
|
|
@@ -1431,88 +1062,7 @@ function useBridgeQuote() {
|
|
|
1431
1062
|
return;
|
|
1432
1063
|
}
|
|
1433
1064
|
if (cancelled) return;
|
|
1434
|
-
|
|
1435
|
-
if (quoteRoute.srcChainKey.toLowerCase() === "ton") {
|
|
1436
|
-
try {
|
|
1437
|
-
const estimatedFee = estimateTonNetworkFee(quoteRoute);
|
|
1438
|
-
quoteWithFees = addTonNetworkFee(quoteRoute, chains, estimatedFee);
|
|
1439
|
-
} catch (error) {
|
|
1440
|
-
console.warn("Failed to estimate TON fee, using fallback:", error);
|
|
1441
|
-
quoteWithFees = addTonNetworkFee(quoteRoute, chains);
|
|
1442
|
-
}
|
|
1443
|
-
}
|
|
1444
|
-
if (quoteRoute.srcChainKey.toLowerCase() === "tron") {
|
|
1445
|
-
const tronStrategy = chainRegistry.getStrategy("tron");
|
|
1446
|
-
if (tronStrategy?.isConnected()) {
|
|
1447
|
-
const tronWeb = tronStrategy.getClient();
|
|
1448
|
-
const tronAddress = tronStrategy.getAccount();
|
|
1449
|
-
if (tronWeb && tronAddress) {
|
|
1450
|
-
try {
|
|
1451
|
-
const estimatedFee = await estimateTronNetworkFee(
|
|
1452
|
-
tronWeb,
|
|
1453
|
-
quoteRoute,
|
|
1454
|
-
tronAddress
|
|
1455
|
-
);
|
|
1456
|
-
quoteWithFees = addTronNetworkFee(
|
|
1457
|
-
quoteWithFees || quoteRoute,
|
|
1458
|
-
chains,
|
|
1459
|
-
estimatedFee
|
|
1460
|
-
);
|
|
1461
|
-
} catch (error) {
|
|
1462
|
-
console.warn(
|
|
1463
|
-
"Failed to estimate TRON fee, using fallback:",
|
|
1464
|
-
error
|
|
1465
|
-
);
|
|
1466
|
-
quoteWithFees = addTronNetworkFee(
|
|
1467
|
-
quoteWithFees || quoteRoute,
|
|
1468
|
-
chains
|
|
1469
|
-
);
|
|
1470
|
-
}
|
|
1471
|
-
} else {
|
|
1472
|
-
quoteWithFees = addTronNetworkFee(
|
|
1473
|
-
quoteWithFees || quoteRoute,
|
|
1474
|
-
chains
|
|
1475
|
-
);
|
|
1476
|
-
}
|
|
1477
|
-
} else {
|
|
1478
|
-
quoteWithFees = addTronNetworkFee(
|
|
1479
|
-
quoteWithFees || quoteRoute,
|
|
1480
|
-
chains
|
|
1481
|
-
);
|
|
1482
|
-
}
|
|
1483
|
-
}
|
|
1484
|
-
const srcChainKey = quoteRoute.srcChainKey.toLowerCase();
|
|
1485
|
-
if (srcChainKey !== "ton" && srcChainKey !== "tron") {
|
|
1486
|
-
if (publicClient) {
|
|
1487
|
-
try {
|
|
1488
|
-
const estimatedFee = await estimateEvmNetworkFee(
|
|
1489
|
-
publicClient,
|
|
1490
|
-
quoteRoute,
|
|
1491
|
-
quoteRoute.srcChainKey
|
|
1492
|
-
);
|
|
1493
|
-
quoteWithFees = addEvmNetworkFee(
|
|
1494
|
-
quoteWithFees || quoteRoute,
|
|
1495
|
-
chains,
|
|
1496
|
-
estimatedFee
|
|
1497
|
-
);
|
|
1498
|
-
} catch (error) {
|
|
1499
|
-
console.warn(
|
|
1500
|
-
"Failed to estimate EVM fee, using fallback:",
|
|
1501
|
-
error
|
|
1502
|
-
);
|
|
1503
|
-
quoteWithFees = addEvmNetworkFee(
|
|
1504
|
-
quoteWithFees || quoteRoute,
|
|
1505
|
-
chains
|
|
1506
|
-
);
|
|
1507
|
-
}
|
|
1508
|
-
} else {
|
|
1509
|
-
quoteWithFees = addEvmNetworkFee(
|
|
1510
|
-
quoteWithFees || quoteRoute,
|
|
1511
|
-
chains
|
|
1512
|
-
);
|
|
1513
|
-
}
|
|
1514
|
-
}
|
|
1515
|
-
setQuote(quoteWithFees || quoteRoute);
|
|
1065
|
+
setQuote(quoteRoute);
|
|
1516
1066
|
} catch {
|
|
1517
1067
|
if (!cancelled) {
|
|
1518
1068
|
resetUi();
|
|
@@ -2488,12 +2038,20 @@ const SearchInput = ({
|
|
|
2488
2038
|
placeholder,
|
|
2489
2039
|
className: cn$2(
|
|
2490
2040
|
"w-full outline-none px-5 py-4 relative pl-16 bg-input border transition-all border-transparent rounded-xs ring-0 leading-0 h-13 text-base focus-visible:border focus-visible:border-ring",
|
|
2041
|
+
value && "pr-16",
|
|
2491
2042
|
className
|
|
2492
2043
|
),
|
|
2493
2044
|
value,
|
|
2494
2045
|
onChange: (e2) => onChange(e2.target.value)
|
|
2495
2046
|
}
|
|
2496
|
-
)
|
|
2047
|
+
),
|
|
2048
|
+
value && /* @__PURE__ */ jsx("div", { className: "absolute z-10 right-4 top-0 bottom-0 my-auto h-5 w-5 bg-accent flex items-center justify-center rounded-full", children: /* @__PURE__ */ jsx(
|
|
2049
|
+
XIcon,
|
|
2050
|
+
{
|
|
2051
|
+
className: "w-4 h-4 text-foreground cursor-pointer hover:opacity-70 transition-opacity",
|
|
2052
|
+
onClick: () => onChange("")
|
|
2053
|
+
}
|
|
2054
|
+
) })
|
|
2497
2055
|
] });
|
|
2498
2056
|
};
|
|
2499
2057
|
const ChainSelectModal = ({
|
|
@@ -2643,49 +2201,58 @@ const ChainSelectModal = ({
|
|
|
2643
2201
|
chain2.chainKey
|
|
2644
2202
|
);
|
|
2645
2203
|
};
|
|
2646
|
-
return /* @__PURE__ */ jsx(Dialog, { open: isOpen, onOpenChange: (open) => !open && handleClose(), children: /* @__PURE__ */ jsxs(
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
|
|
2650
|
-
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
|
-
|
|
2654
|
-
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
}
|
|
2659
|
-
),
|
|
2660
|
-
/* @__PURE__ */ jsxs("div", { className: "flex-1 overflow-y-auto [&::-webkit-scrollbar]:w-1 [&::-webkit-scrollbar-track]:bg-transparent [&::-webkit-scrollbar-thumb]:bg-muted-foreground/20 [&::-webkit-scrollbar-thumb]:rounded-full hover:[&::-webkit-scrollbar-thumb]:bg-muted-foreground/30", children: [
|
|
2661
|
-
groupedChains.available.length > 0 && groupedChains.available.map((c2) => renderChainItem(c2, false)),
|
|
2662
|
-
groupedChains.willChangeSrc.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2663
|
-
/* @__PURE__ */ jsx(
|
|
2664
|
-
"p",
|
|
2665
|
-
{
|
|
2666
|
-
className: `px-5 py-2 leading-4 text-base font-semibold text-muted-foreground uppercase ${groupedChains.available.length > 0 ? "mt-10" : ""}`,
|
|
2667
|
-
children: t2("bridge.willChangeSourceChain")
|
|
2668
|
-
}
|
|
2669
|
-
),
|
|
2670
|
-
groupedChains.willChangeSrc.map(
|
|
2671
|
-
(c2) => renderChainItem(c2, true, false)
|
|
2672
|
-
)
|
|
2673
|
-
] }),
|
|
2674
|
-
groupedChains.willChangeTokenAndSrc.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2204
|
+
return /* @__PURE__ */ jsx(Dialog, { open: isOpen, onOpenChange: (open) => !open && handleClose(), children: /* @__PURE__ */ jsxs(
|
|
2205
|
+
DialogContent,
|
|
2206
|
+
{
|
|
2207
|
+
className: "md:max-h-[90dvh] md:h-[90dvh] fixed top-0 left-0 right-0 bottom-0 translate-x-0 translate-y-0 md:left-[50%] md:top-[50%] md:translate-x-[-50%] md:translate-y-[-50%] overflow-hidden flex flex-col p-6 md:p-10 md:pt-8 rounded-none md:rounded-lg",
|
|
2208
|
+
closeButtonClassName: "right-6 md:right-10",
|
|
2209
|
+
children: [
|
|
2210
|
+
/* @__PURE__ */ jsx(DialogHeader, { className: "text-left pb-2", children: /* @__PURE__ */ jsx(DialogTitle, { className: "text-xl leading-8", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-0", children: [
|
|
2211
|
+
/* @__PURE__ */ jsx("div", { children: t2("bridge.select") }),
|
|
2212
|
+
/* @__PURE__ */ jsx("div", { children: t2(
|
|
2213
|
+
isSource ? "bridge.sourceNetwork" : "bridge.destinationNetwork"
|
|
2214
|
+
) })
|
|
2215
|
+
] }) }) }),
|
|
2675
2216
|
/* @__PURE__ */ jsx(
|
|
2676
|
-
|
|
2217
|
+
SearchInput,
|
|
2677
2218
|
{
|
|
2678
|
-
|
|
2679
|
-
|
|
2219
|
+
placeholder: t2("bridge.search"),
|
|
2220
|
+
value: query,
|
|
2221
|
+
onChange: setQuery,
|
|
2222
|
+
className: "text-foreground placeholder:text-muted-foreground"
|
|
2680
2223
|
}
|
|
2681
2224
|
),
|
|
2682
|
-
|
|
2683
|
-
(c2) => renderChainItem(c2, false,
|
|
2684
|
-
|
|
2685
|
-
|
|
2686
|
-
|
|
2687
|
-
|
|
2688
|
-
|
|
2225
|
+
/* @__PURE__ */ jsxs("div", { className: "flex-1 overflow-y-auto [&::-webkit-scrollbar]:w-1 [&::-webkit-scrollbar-track]:bg-transparent [&::-webkit-scrollbar-thumb]:bg-muted-foreground/20 [&::-webkit-scrollbar-thumb]:rounded-full hover:[&::-webkit-scrollbar-thumb]:bg-muted-foreground/30", children: [
|
|
2226
|
+
groupedChains.available.length > 0 && groupedChains.available.map((c2) => renderChainItem(c2, false)),
|
|
2227
|
+
groupedChains.willChangeSrc.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2228
|
+
/* @__PURE__ */ jsx(
|
|
2229
|
+
"p",
|
|
2230
|
+
{
|
|
2231
|
+
className: `px-5 py-2 leading-4 text-base font-semibold text-muted-foreground uppercase ${groupedChains.available.length > 0 ? "mt-10" : ""}`,
|
|
2232
|
+
children: t2("bridge.willChangeSourceChain")
|
|
2233
|
+
}
|
|
2234
|
+
),
|
|
2235
|
+
groupedChains.willChangeSrc.map(
|
|
2236
|
+
(c2) => renderChainItem(c2, true, false)
|
|
2237
|
+
)
|
|
2238
|
+
] }),
|
|
2239
|
+
groupedChains.willChangeTokenAndSrc.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2240
|
+
/* @__PURE__ */ jsx(
|
|
2241
|
+
"p",
|
|
2242
|
+
{
|
|
2243
|
+
className: `px-5 py-2 leading-4 text-base font-semibold text-muted-foreground uppercase ${groupedChains.available.length > 0 || groupedChains.willChangeSrc.length > 0 ? "mt-10" : ""}`,
|
|
2244
|
+
children: t2("bridge.willChangeSourceNetworkAndToken")
|
|
2245
|
+
}
|
|
2246
|
+
),
|
|
2247
|
+
groupedChains.willChangeTokenAndSrc.map(
|
|
2248
|
+
(c2) => renderChainItem(c2, false, true)
|
|
2249
|
+
)
|
|
2250
|
+
] }),
|
|
2251
|
+
groupedChains.available.length === 0 && groupedChains.willChangeSrc.length === 0 && groupedChains.willChangeTokenAndSrc.length === 0 && /* @__PURE__ */ jsx("div", { className: "text-sm text-muted-foreground px-12 py-2 h-28 flex items-center justify-center text-center", children: t2("bridge.chainNotFound") })
|
|
2252
|
+
] })
|
|
2253
|
+
]
|
|
2254
|
+
}
|
|
2255
|
+
) });
|
|
2689
2256
|
};
|
|
2690
2257
|
const useWalletSelectModal = create((set2) => ({
|
|
2691
2258
|
isOpen: false,
|
|
@@ -2693,6 +2260,48 @@ const useWalletSelectModal = create((set2) => ({
|
|
|
2693
2260
|
onOpen: (addressType) => set2({ isOpen: true, addressType }),
|
|
2694
2261
|
onClose: () => set2({ isOpen: false, addressType: void 0 })
|
|
2695
2262
|
}));
|
|
2263
|
+
const truncateToDecimals = (num, decimals) => {
|
|
2264
|
+
if (!isFinite(num) || isNaN(num)) return "0";
|
|
2265
|
+
const multiplier = Math.pow(10, decimals);
|
|
2266
|
+
const truncated = Math.floor(num * multiplier) / multiplier;
|
|
2267
|
+
return truncated.toFixed(decimals).replace(/\.?0+$/, "");
|
|
2268
|
+
};
|
|
2269
|
+
const formatTokenAmount = (amount, symbol, options) => {
|
|
2270
|
+
const normalizedSymbol = (symbol ?? "").toUpperCase();
|
|
2271
|
+
if (["USDT", "USDC", "DAI", "BUSD"].includes(normalizedSymbol) && amount >= 1) {
|
|
2272
|
+
return `${Math.floor(amount)} ${normalizedSymbol}`;
|
|
2273
|
+
}
|
|
2274
|
+
if (options?.decimals !== void 0) {
|
|
2275
|
+
return `${amount.toFixed(options.decimals)} ${normalizedSymbol}`;
|
|
2276
|
+
}
|
|
2277
|
+
if (amount >= 1) {
|
|
2278
|
+
return `${amount.toFixed(0)} ${normalizedSymbol}`;
|
|
2279
|
+
} else if (amount >= 1e-3) {
|
|
2280
|
+
return `${amount.toFixed(3)} ${normalizedSymbol}`;
|
|
2281
|
+
} else {
|
|
2282
|
+
return `${amount.toFixed(6)} ${normalizedSymbol}`;
|
|
2283
|
+
}
|
|
2284
|
+
};
|
|
2285
|
+
const formatUsd = (value) => {
|
|
2286
|
+
if (!value || !isFinite(value)) return "$0";
|
|
2287
|
+
if (value >= 1) return `$${value.toFixed(2)}`;
|
|
2288
|
+
return `$${value.toFixed(6).replace(/0+$/, "").replace(/\.$/, "")}`;
|
|
2289
|
+
};
|
|
2290
|
+
const formatPercentage = (bps, decimals = 2) => {
|
|
2291
|
+
return `${(bps / 100).toFixed(decimals).replace(/0+$/, "").replace(/\.$/, "")}%`;
|
|
2292
|
+
};
|
|
2293
|
+
const formatBalance = (amount, decimals = 2) => {
|
|
2294
|
+
if (!isFinite(amount) || isNaN(amount) || amount <= 0) {
|
|
2295
|
+
return "0.00";
|
|
2296
|
+
}
|
|
2297
|
+
return amount.toFixed(decimals);
|
|
2298
|
+
};
|
|
2299
|
+
const formatHash = (hash, startChars = 4, endChars = 4) => {
|
|
2300
|
+
if (!hash) return "";
|
|
2301
|
+
if (hash.length <= startChars + endChars) return hash;
|
|
2302
|
+
return `${hash.slice(0, startChars)}...${hash.slice(-endChars)}`;
|
|
2303
|
+
};
|
|
2304
|
+
const formatAddress = formatHash;
|
|
2696
2305
|
const EditIcon = (props) => {
|
|
2697
2306
|
return /* @__PURE__ */ jsxs(
|
|
2698
2307
|
"svg",
|
|
@@ -3118,30 +2727,120 @@ const InfoIcon = (props) => {
|
|
|
3118
2727
|
{
|
|
3119
2728
|
d: "M6.56836 5.8519C6.56836 5.06104 7.20948 4.41992 8.00034 4.41992C8.7912 4.41992 9.43232 5.06104 9.43232 5.8519C9.43232 6.13698 9.34902 6.40259 9.20543 6.62574C8.77748 7.29081 8.00034 7.92501 8.00034 8.71587V9.07386M8.00034 11.3159V11.5798",
|
|
3120
2729
|
stroke: "currentColor",
|
|
3121
|
-
|
|
3122
|
-
|
|
2730
|
+
strokeWidth: "1.68349",
|
|
2731
|
+
strokeLinecap: "round"
|
|
3123
2732
|
}
|
|
3124
2733
|
)
|
|
3125
2734
|
}
|
|
3126
|
-
);
|
|
3127
|
-
};
|
|
3128
|
-
const Tip = (props) => {
|
|
3129
|
-
const { children, text } = props;
|
|
3130
|
-
return /* @__PURE__ */ jsxs(Tooltip, { children: [
|
|
3131
|
-
/* @__PURE__ */ jsx(TooltipTrigger, { className: "w-4 h-4 rounded-full bg-muted text-muted-foreground", children }),
|
|
3132
|
-
/* @__PURE__ */ jsx(TooltipContent, { className: "max-w-64", children: /* @__PURE__ */ jsx("p", { children: text }) })
|
|
3133
|
-
] });
|
|
3134
|
-
};
|
|
3135
|
-
const BASE_URL = "https://icons-ckg.pages.dev/stargate-light/tokens";
|
|
3136
|
-
const TokenSymbol = ({
|
|
3137
|
-
symbol,
|
|
3138
|
-
className = "w-4 h-4",
|
|
3139
|
-
alt
|
|
3140
|
-
}) => {
|
|
3141
|
-
const normalizedSymbol = normalizeTickerSymbol$1(symbol).toLowerCase();
|
|
3142
|
-
const src2 = `${BASE_URL}/${normalizedSymbol}.svg`;
|
|
3143
|
-
return /* @__PURE__ */ jsx("img", { src: src2, alt: alt ?? symbol, className });
|
|
3144
|
-
};
|
|
2735
|
+
);
|
|
2736
|
+
};
|
|
2737
|
+
const Tip = (props) => {
|
|
2738
|
+
const { children, text } = props;
|
|
2739
|
+
return /* @__PURE__ */ jsxs(Tooltip, { children: [
|
|
2740
|
+
/* @__PURE__ */ jsx(TooltipTrigger, { className: "w-4 h-4 rounded-full bg-muted text-muted-foreground", children }),
|
|
2741
|
+
/* @__PURE__ */ jsx(TooltipContent, { className: "max-w-64", children: /* @__PURE__ */ jsx("p", { children: text }) })
|
|
2742
|
+
] });
|
|
2743
|
+
};
|
|
2744
|
+
const BASE_URL = "https://icons-ckg.pages.dev/stargate-light/tokens";
|
|
2745
|
+
const TokenSymbol = ({
|
|
2746
|
+
symbol,
|
|
2747
|
+
className = "w-4 h-4",
|
|
2748
|
+
alt
|
|
2749
|
+
}) => {
|
|
2750
|
+
const normalizedSymbol = normalizeTickerSymbol$1(symbol).toLowerCase();
|
|
2751
|
+
const src2 = `${BASE_URL}/${normalizedSymbol}.svg`;
|
|
2752
|
+
return /* @__PURE__ */ jsx("img", { src: src2, alt: alt ?? symbol, className });
|
|
2753
|
+
};
|
|
2754
|
+
function getQuoteAmounts(quote, srcToken, dstToken) {
|
|
2755
|
+
if (!quote || !srcToken || !dstToken) {
|
|
2756
|
+
return {
|
|
2757
|
+
inputHuman: 0,
|
|
2758
|
+
outputHuman: 0,
|
|
2759
|
+
outputHumanRounded: "0",
|
|
2760
|
+
minReceivedHuman: 0
|
|
2761
|
+
};
|
|
2762
|
+
}
|
|
2763
|
+
const inputHuman = fromLD(quote.srcAmount, srcToken.decimals);
|
|
2764
|
+
const outputHuman = fromLD(quote.dstAmount, dstToken.decimals);
|
|
2765
|
+
const outputHumanRounded = truncateToDecimals(outputHuman, 2);
|
|
2766
|
+
const minReceivedHuman = fromLD(quote.dstAmountMin || "0", dstToken.decimals);
|
|
2767
|
+
return {
|
|
2768
|
+
inputHuman,
|
|
2769
|
+
outputHuman,
|
|
2770
|
+
outputHumanRounded,
|
|
2771
|
+
minReceivedHuman
|
|
2772
|
+
};
|
|
2773
|
+
}
|
|
2774
|
+
function getQuoteFees(quote, tokens, chains, srcToken, dstToken) {
|
|
2775
|
+
if (!quote || !tokens || !chains) {
|
|
2776
|
+
return {
|
|
2777
|
+
fees: { usd: /* @__PURE__ */ new Map(), original: /* @__PURE__ */ new Map(), formatted: /* @__PURE__ */ new Map() },
|
|
2778
|
+
inSrcToken: void 0,
|
|
2779
|
+
inDstToken: void 0
|
|
2780
|
+
};
|
|
2781
|
+
}
|
|
2782
|
+
const feeData = computeFeesUsdFromArray(quote.fees, tokens, chains);
|
|
2783
|
+
let inSrcToken = void 0;
|
|
2784
|
+
let inDstToken = void 0;
|
|
2785
|
+
if (srcToken && quote.srcChainKey) {
|
|
2786
|
+
const feeInSrcLD = sumFeeByTokenLD(
|
|
2787
|
+
quote.fees,
|
|
2788
|
+
srcToken.address,
|
|
2789
|
+
quote.srcChainKey
|
|
2790
|
+
);
|
|
2791
|
+
const feeInSrcHuman = fromLD(feeInSrcLD, srcToken.decimals);
|
|
2792
|
+
if (feeInSrcHuman > 0) {
|
|
2793
|
+
inSrcToken = Number(truncateToDecimals(feeInSrcHuman, 8));
|
|
2794
|
+
} else if ((feeData.usd.get("total") || 0) > 0 && srcToken.price?.usd) {
|
|
2795
|
+
const feeInSrcApprox = (feeData.usd.get("total") || 0) / srcToken.price.usd;
|
|
2796
|
+
inSrcToken = Number(truncateToDecimals(feeInSrcApprox, 8));
|
|
2797
|
+
}
|
|
2798
|
+
}
|
|
2799
|
+
if (dstToken && quote.dstChainKey) {
|
|
2800
|
+
const feeInDstLD = sumFeeByTokenLD(
|
|
2801
|
+
quote.fees,
|
|
2802
|
+
dstToken.address,
|
|
2803
|
+
quote.dstChainKey
|
|
2804
|
+
);
|
|
2805
|
+
const feeInDstHuman = fromLD(feeInDstLD, dstToken.decimals);
|
|
2806
|
+
if (feeInDstHuman > 0) {
|
|
2807
|
+
inDstToken = Number(truncateToDecimals(feeInDstHuman, 8));
|
|
2808
|
+
}
|
|
2809
|
+
}
|
|
2810
|
+
return {
|
|
2811
|
+
fees: feeData,
|
|
2812
|
+
inSrcToken,
|
|
2813
|
+
inDstToken
|
|
2814
|
+
};
|
|
2815
|
+
}
|
|
2816
|
+
function calculateMinReceived(quote, slippageBps, dstToken) {
|
|
2817
|
+
if (!quote || !dstToken) return 0;
|
|
2818
|
+
const dstAmountLD = BigInt(quote.dstAmount);
|
|
2819
|
+
const minAmountLD = dstAmountLD * BigInt(1e4 - slippageBps) / BigInt(1e4);
|
|
2820
|
+
return fromLD(minAmountLD.toString(), dstToken.decimals);
|
|
2821
|
+
}
|
|
2822
|
+
function getQuoteDetails(quote, srcToken, dstToken, tokens, chains, slippageBps) {
|
|
2823
|
+
const amounts = getQuoteAmounts(quote, srcToken, dstToken);
|
|
2824
|
+
const fees = getQuoteFees(quote, tokens, chains, srcToken, dstToken);
|
|
2825
|
+
const minimumReceived = calculateMinReceived(quote, slippageBps, dstToken);
|
|
2826
|
+
return {
|
|
2827
|
+
inputAmount: amounts.inputHuman,
|
|
2828
|
+
outputAmount: amounts.outputHuman,
|
|
2829
|
+
outputAmountRounded: amounts.outputHumanRounded,
|
|
2830
|
+
minimumReceived,
|
|
2831
|
+
etaSeconds: quote?.duration?.estimated,
|
|
2832
|
+
fees
|
|
2833
|
+
};
|
|
2834
|
+
}
|
|
2835
|
+
function getRouteDisplayName(route) {
|
|
2836
|
+
if (!route) return "Stargate Bridge";
|
|
2837
|
+
const routeLower = route.toLowerCase();
|
|
2838
|
+
if (routeLower.includes("taxi")) return "Stargate V2 Fast";
|
|
2839
|
+
if (routeLower.includes("bus")) return "Stargate V2 Economy";
|
|
2840
|
+
if (routeLower.includes("oft")) return "OFT Bridge";
|
|
2841
|
+
if (routeLower.includes("v2")) return "Stargate V2";
|
|
2842
|
+
return route.split(/[/\-_]/).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(" ");
|
|
2843
|
+
}
|
|
3145
2844
|
function useGasEstimate(amountNum) {
|
|
3146
2845
|
const { fromChain } = useChainsStore();
|
|
3147
2846
|
const { selectedAssetSymbol } = useTokensStore();
|
|
@@ -3151,6 +2850,9 @@ function useGasEstimate(amountNum) {
|
|
|
3151
2850
|
srcAddress
|
|
3152
2851
|
);
|
|
3153
2852
|
const { quote } = useBridgeQuoteStore();
|
|
2853
|
+
const { chainRegistry } = useChainStrategies();
|
|
2854
|
+
const [networkFeeEstimate, setNetworkFeeEstimate] = useState(0);
|
|
2855
|
+
const [networkFeeKnown, setNetworkFeeKnown] = useState(false);
|
|
3154
2856
|
const balancesKnown = !balancesLoading;
|
|
3155
2857
|
const chainKey = fromChain?.chainKey;
|
|
3156
2858
|
const nativeCurrencySymbol = fromChain?.nativeCurrency?.symbol;
|
|
@@ -3159,6 +2861,44 @@ function useGasEstimate(amountNum) {
|
|
|
3159
2861
|
const quoteFees = quote?.fees;
|
|
3160
2862
|
const quoteSrcChainKey = quote?.srcChainKey;
|
|
3161
2863
|
const nativeBalanceValue = nativeCurrencySymbol ? Number(balances[nativeCurrencySymbol.toUpperCase()]?.balance ?? 0) : 0;
|
|
2864
|
+
useEffect(() => {
|
|
2865
|
+
let cancelled = false;
|
|
2866
|
+
const estimate = async () => {
|
|
2867
|
+
setNetworkFeeEstimate(0);
|
|
2868
|
+
setNetworkFeeKnown(false);
|
|
2869
|
+
if (!chainKey || !quote?.steps?.length) {
|
|
2870
|
+
return;
|
|
2871
|
+
}
|
|
2872
|
+
const strategy = chainRegistry.getStrategy(chainKey);
|
|
2873
|
+
if (!strategy) {
|
|
2874
|
+
setNetworkFeeKnown(true);
|
|
2875
|
+
return;
|
|
2876
|
+
}
|
|
2877
|
+
const steps = quote.steps.filter((step) => step.chainKey === chainKey);
|
|
2878
|
+
if (!steps.length) {
|
|
2879
|
+
setNetworkFeeKnown(true);
|
|
2880
|
+
return;
|
|
2881
|
+
}
|
|
2882
|
+
try {
|
|
2883
|
+
const estimateValue = await strategy.estimateNetworkFee(steps);
|
|
2884
|
+
if (cancelled) return;
|
|
2885
|
+
setNetworkFeeEstimate(
|
|
2886
|
+
Number.isFinite(estimateValue) ? estimateValue : 0
|
|
2887
|
+
);
|
|
2888
|
+
} catch {
|
|
2889
|
+
if (cancelled) return;
|
|
2890
|
+
setNetworkFeeEstimate(0);
|
|
2891
|
+
} finally {
|
|
2892
|
+
if (!cancelled) {
|
|
2893
|
+
setNetworkFeeKnown(true);
|
|
2894
|
+
}
|
|
2895
|
+
}
|
|
2896
|
+
};
|
|
2897
|
+
void estimate();
|
|
2898
|
+
return () => {
|
|
2899
|
+
cancelled = true;
|
|
2900
|
+
};
|
|
2901
|
+
}, [chainKey, quote?.steps, chainRegistry]);
|
|
3162
2902
|
const result = useMemo(() => {
|
|
3163
2903
|
if (!chainKey || !nativeCurrencySymbol) {
|
|
3164
2904
|
return {
|
|
@@ -3178,7 +2918,7 @@ function useGasEstimate(amountNum) {
|
|
|
3178
2918
|
if (quoteFees && quoteSrcChainKey === chainKey) {
|
|
3179
2919
|
const fees = quoteFees;
|
|
3180
2920
|
const feesInNative = fees.filter(
|
|
3181
|
-
(f4) => f4.chainKey === chainKey && f4.token === nativeCurrencyAddress
|
|
2921
|
+
(f4) => f4.chainKey === chainKey && f4.token === nativeCurrencyAddress
|
|
3182
2922
|
).reduce(
|
|
3183
2923
|
(sum, f4) => sum + BigInt(f4.amount || "0"),
|
|
3184
2924
|
0n
|
|
@@ -3187,13 +2927,16 @@ function useGasEstimate(amountNum) {
|
|
|
3187
2927
|
requiredNative = Number(feesInNative) / Math.pow(10, decimals);
|
|
3188
2928
|
quoteFeesAvailable = true;
|
|
3189
2929
|
}
|
|
2930
|
+
if (networkFeeKnown) {
|
|
2931
|
+
requiredNative += networkFeeEstimate;
|
|
2932
|
+
}
|
|
3190
2933
|
let hasEnoughGas = true;
|
|
3191
2934
|
if (isNativeSelected) {
|
|
3192
2935
|
hasEnoughGas = nativeBalance - (amountNum ?? 0) >= requiredNative;
|
|
3193
2936
|
} else {
|
|
3194
2937
|
hasEnoughGas = nativeBalance >= requiredNative;
|
|
3195
2938
|
}
|
|
3196
|
-
const shouldCheckGas = balancesKnown && quoteFeesAvailable;
|
|
2939
|
+
const shouldCheckGas = balancesKnown && quoteFeesAvailable && networkFeeKnown;
|
|
3197
2940
|
return {
|
|
3198
2941
|
nativeSym,
|
|
3199
2942
|
nativeBalance,
|
|
@@ -3212,7 +2955,9 @@ function useGasEstimate(amountNum) {
|
|
|
3212
2955
|
quoteSrcChainKey,
|
|
3213
2956
|
amountNum,
|
|
3214
2957
|
balancesKnown,
|
|
3215
|
-
nativeBalanceValue
|
|
2958
|
+
nativeBalanceValue,
|
|
2959
|
+
networkFeeEstimate,
|
|
2960
|
+
networkFeeKnown
|
|
3216
2961
|
]);
|
|
3217
2962
|
return result;
|
|
3218
2963
|
}
|
|
@@ -3621,33 +3366,6 @@ class TransactionFailedError extends ChainStrategyError {
|
|
|
3621
3366
|
this.txHash = txHash;
|
|
3622
3367
|
}
|
|
3623
3368
|
}
|
|
3624
|
-
class TransactionTimeoutError extends ChainStrategyError {
|
|
3625
|
-
constructor(chainKey, txHash) {
|
|
3626
|
-
super(
|
|
3627
|
-
`${chainKey.toUpperCase()} transaction confirmation timeout: ${txHash}`,
|
|
3628
|
-
"TRANSACTION_TIMEOUT",
|
|
3629
|
-
chainKey
|
|
3630
|
-
);
|
|
3631
|
-
__publicField(this, "txHash");
|
|
3632
|
-
this.name = "TransactionTimeoutError";
|
|
3633
|
-
this.txHash = txHash;
|
|
3634
|
-
}
|
|
3635
|
-
}
|
|
3636
|
-
class TransactionRevertedError extends ChainStrategyError {
|
|
3637
|
-
constructor(chainKey, txHash, revertReason) {
|
|
3638
|
-
const reason = revertReason ? `: ${revertReason}` : "";
|
|
3639
|
-
super(
|
|
3640
|
-
`${chainKey.toUpperCase()} transaction reverted on-chain${reason}`,
|
|
3641
|
-
"TRANSACTION_REVERTED",
|
|
3642
|
-
chainKey
|
|
3643
|
-
);
|
|
3644
|
-
__publicField(this, "txHash");
|
|
3645
|
-
__publicField(this, "revertReason");
|
|
3646
|
-
this.name = "TransactionRevertedError";
|
|
3647
|
-
this.txHash = txHash;
|
|
3648
|
-
this.revertReason = revertReason;
|
|
3649
|
-
}
|
|
3650
|
-
}
|
|
3651
3369
|
class ProviderNotAvailableError extends ChainStrategyError {
|
|
3652
3370
|
constructor(chainKey, reason) {
|
|
3653
3371
|
const message = reason ? `${chainKey.toUpperCase()} provider not available: ${reason}` : `${chainKey.toUpperCase()} provider not available`;
|
|
@@ -3704,6 +3422,38 @@ async function getLayerZeroMessageByTx(txHash) {
|
|
|
3704
3422
|
return null;
|
|
3705
3423
|
}
|
|
3706
3424
|
}
|
|
3425
|
+
async function waitForLayerZeroCompletion(txHash, timeoutMs = 6e5, pollIntervalMs = 1e4) {
|
|
3426
|
+
const deadline = Date.now() + timeoutMs;
|
|
3427
|
+
while (Date.now() < deadline) {
|
|
3428
|
+
try {
|
|
3429
|
+
const message = await getLayerZeroMessageByTx(txHash);
|
|
3430
|
+
if (message) {
|
|
3431
|
+
const statusName = message.status?.name;
|
|
3432
|
+
if (statusName === "DELIVERED") {
|
|
3433
|
+
return {
|
|
3434
|
+
completed: true,
|
|
3435
|
+
status: "DELIVERED",
|
|
3436
|
+
dstTxHash: message.destination?.tx?.txHash,
|
|
3437
|
+
message
|
|
3438
|
+
};
|
|
3439
|
+
}
|
|
3440
|
+
if (statusName === "FAILED") {
|
|
3441
|
+
return {
|
|
3442
|
+
completed: false,
|
|
3443
|
+
status: "FAILED",
|
|
3444
|
+
message
|
|
3445
|
+
};
|
|
3446
|
+
}
|
|
3447
|
+
}
|
|
3448
|
+
} catch {
|
|
3449
|
+
}
|
|
3450
|
+
await new Promise((r2) => setTimeout(r2, pollIntervalMs));
|
|
3451
|
+
}
|
|
3452
|
+
return {
|
|
3453
|
+
completed: false,
|
|
3454
|
+
status: "TIMEOUT"
|
|
3455
|
+
};
|
|
3456
|
+
}
|
|
3707
3457
|
function useBridgeTransaction() {
|
|
3708
3458
|
const { quote } = useBridgeQuoteStore();
|
|
3709
3459
|
const { chainRegistry } = useChainStrategies();
|
|
@@ -3779,59 +3529,76 @@ function useBridgeTransaction() {
|
|
|
3779
3529
|
txStore.setSrcHash(hash);
|
|
3780
3530
|
txStore.updateStatus("processing");
|
|
3781
3531
|
});
|
|
3782
|
-
if (txResult?.tonTransactionHash) {
|
|
3783
|
-
txStore.setTonTransactionHash(txResult.tonTransactionHash);
|
|
3784
|
-
}
|
|
3785
3532
|
if (txResult?.hash) {
|
|
3786
|
-
|
|
3787
|
-
|
|
3788
|
-
|
|
3789
|
-
|
|
3533
|
+
const trackWithLayerZero = async () => {
|
|
3534
|
+
let hashForLayerZero = txResult.hash;
|
|
3535
|
+
const messageHash = txResult.hash;
|
|
3536
|
+
if (quote.srcChainKey === "ton" && strategy.convertMessageHashToTxHash) {
|
|
3537
|
+
const tonTxHash = await strategy.convertMessageHashToTxHash(
|
|
3538
|
+
messageHash,
|
|
3539
|
+
6e4
|
|
3540
|
+
);
|
|
3541
|
+
if (tonTxHash) {
|
|
3542
|
+
hashForLayerZero = tonTxHash;
|
|
3543
|
+
txStore.setTonTransactionHash(tonTxHash);
|
|
3544
|
+
} else {
|
|
3545
|
+
console.warn("Failed to convert TON message hash to tx hash");
|
|
3790
3546
|
}
|
|
3791
|
-
|
|
3792
|
-
|
|
3793
|
-
|
|
3794
|
-
|
|
3795
|
-
|
|
3796
|
-
|
|
3797
|
-
|
|
3798
|
-
|
|
3799
|
-
|
|
3800
|
-
|
|
3801
|
-
txStore.updateActualFee(feeValue, feeSymbol);
|
|
3802
|
-
}
|
|
3547
|
+
}
|
|
3548
|
+
const lzResult = await waitForLayerZeroCompletion(
|
|
3549
|
+
hashForLayerZero,
|
|
3550
|
+
6e5,
|
|
3551
|
+
1e4
|
|
3552
|
+
);
|
|
3553
|
+
console.log("LayerZero delivery status:", lzResult.status);
|
|
3554
|
+
if (lzResult.completed) {
|
|
3555
|
+
if (lzResult.dstTxHash) {
|
|
3556
|
+
txStore.setDstHash(lzResult.dstTxHash);
|
|
3803
3557
|
}
|
|
3804
|
-
|
|
3805
|
-
console.log("Transaction completed successfully");
|
|
3806
|
-
if (txResult.hash && strategy.getSourceCost) {
|
|
3558
|
+
if (strategy.getSourceCost) {
|
|
3807
3559
|
const srcChain2 = chains?.find(
|
|
3808
3560
|
(c2) => c2.chainKey === quote.srcChainKey
|
|
3809
3561
|
);
|
|
3810
3562
|
const feeSymbol = srcChain2?.nativeCurrency?.symbol || "";
|
|
3811
3563
|
const { priceUsd } = findNativeMeta(allTokens, srcChain2);
|
|
3812
|
-
const
|
|
3813
|
-
|
|
3814
|
-
|
|
3815
|
-
|
|
3816
|
-
|
|
3817
|
-
}).then((sourceTxHash) => getSourceCost(sourceTxHash)).then((sourceCost) => {
|
|
3564
|
+
const hashForSourceCost = quote.srcChainKey === "ton" ? messageHash : hashForLayerZero;
|
|
3565
|
+
try {
|
|
3566
|
+
const sourceCost = await strategy.getSourceCost(
|
|
3567
|
+
hashForSourceCost
|
|
3568
|
+
);
|
|
3818
3569
|
if (sourceCost?.totalNative !== void 0 && isFinite(sourceCost.totalNative)) {
|
|
3819
3570
|
const feeUsd = priceUsd && priceUsd > 0 ? sourceCost.totalNative * priceUsd : void 0;
|
|
3571
|
+
console.log("Source cost calculated:", {
|
|
3572
|
+
gasFee: sourceCost.breakdown?.gasFee + " " + feeSymbol,
|
|
3573
|
+
layerZeroFee: sourceCost.breakdown?.layerZeroFee + " " + feeSymbol,
|
|
3574
|
+
total: sourceCost.totalNative + " " + feeSymbol,
|
|
3575
|
+
totalUsd: feeUsd ? "$" + feeUsd.toFixed(2) : "N/A"
|
|
3576
|
+
});
|
|
3820
3577
|
txStore.updateLayerZeroTotalFee(
|
|
3821
3578
|
sourceCost.totalNative,
|
|
3822
3579
|
feeSymbol,
|
|
3823
3580
|
feeUsd
|
|
3824
3581
|
);
|
|
3825
3582
|
}
|
|
3826
|
-
}
|
|
3827
|
-
console.warn("Failed to compute
|
|
3828
|
-
}
|
|
3583
|
+
} catch (error) {
|
|
3584
|
+
console.warn("Failed to compute source cost:", error);
|
|
3585
|
+
}
|
|
3829
3586
|
}
|
|
3587
|
+
txStore.updateStatus("completed");
|
|
3588
|
+
console.log("Transaction completed successfully via LayerZero");
|
|
3830
3589
|
} else {
|
|
3831
|
-
|
|
3832
|
-
|
|
3590
|
+
if (lzResult.status === "FAILED") {
|
|
3591
|
+
txStore.setError("TRANSACTION_FAILED_TO_COMPLETE");
|
|
3592
|
+
console.error("LayerZero delivery failed");
|
|
3593
|
+
} else {
|
|
3594
|
+
txStore.updateStatus("completed");
|
|
3595
|
+
console.warn(
|
|
3596
|
+
"LayerZero tracking timed out, marking as completed"
|
|
3597
|
+
);
|
|
3598
|
+
}
|
|
3833
3599
|
}
|
|
3834
|
-
}
|
|
3600
|
+
};
|
|
3601
|
+
trackWithLayerZero().catch((err) => {
|
|
3835
3602
|
if (isUserRejection(err)) {
|
|
3836
3603
|
txStore.setError("TRANSACTION_REJECTED");
|
|
3837
3604
|
} else if (ChainStrategyError.isChainStrategyError(err)) {
|
|
@@ -4931,11 +4698,60 @@ class ChainStrategyRegistry {
|
|
|
4931
4698
|
await strategy.disconnect(options);
|
|
4932
4699
|
}
|
|
4933
4700
|
}
|
|
4701
|
+
const EVM_CONFIG = {
|
|
4702
|
+
usdtAddress: "0xdAC17F958D2ee523a2206206994597C13D831ec7",
|
|
4703
|
+
gasEstimates: {
|
|
4704
|
+
approve: 65000n,
|
|
4705
|
+
bridge: 300000n
|
|
4706
|
+
},
|
|
4707
|
+
gasBuffer: 1.2,
|
|
4708
|
+
// 20% buffer
|
|
4709
|
+
gasFeeMultiplier: 2,
|
|
4710
|
+
// Multiplier for wallet fee estimates
|
|
4711
|
+
timeout: 3e5,
|
|
4712
|
+
// 5 minutes (increased for slower networks)
|
|
4713
|
+
requiredConfirmations: 3
|
|
4714
|
+
// Wait for 3 confirmations for reorg protection
|
|
4715
|
+
};
|
|
4716
|
+
const TON_CONFIG = {
|
|
4717
|
+
apiUrl: "https://toncenter.com/api/v2",
|
|
4718
|
+
timeout: 36e4,
|
|
4719
|
+
// 6 minutes
|
|
4720
|
+
validUntil: 600,
|
|
4721
|
+
// 10 minutes
|
|
4722
|
+
pollingInterval: 5e3,
|
|
4723
|
+
// 5 seconds between transaction status checks
|
|
4724
|
+
estimatedNetworkFee: "1000000000"
|
|
4725
|
+
// 1 TON in nanoton (conservative estimate)
|
|
4726
|
+
};
|
|
4727
|
+
const TRON_CONFIG = {
|
|
4728
|
+
// 2 minutes (for 19 confirmations)
|
|
4729
|
+
feeLimit: 1e8,
|
|
4730
|
+
// 3 seconds between checks
|
|
4731
|
+
estimatedNetworkFee: "10000000"
|
|
4732
|
+
// 10 TRX in SUN (fallback estimate)
|
|
4733
|
+
};
|
|
4734
|
+
let tonClientInstance = null;
|
|
4735
|
+
function getTonClient(customClient, apiKey) {
|
|
4736
|
+
if (customClient) {
|
|
4737
|
+
return customClient;
|
|
4738
|
+
}
|
|
4739
|
+
if (!tonClientInstance) {
|
|
4740
|
+
tonClientInstance = new TonClient({
|
|
4741
|
+
endpoint: `${TON_CONFIG.apiUrl}/jsonRPC`,
|
|
4742
|
+
apiKey
|
|
4743
|
+
});
|
|
4744
|
+
}
|
|
4745
|
+
return tonClientInstance;
|
|
4746
|
+
}
|
|
4934
4747
|
function isNativeAddress(addr) {
|
|
4935
4748
|
if (!addr) return false;
|
|
4936
4749
|
const a2 = addr.toLowerCase();
|
|
4937
4750
|
return a2 === "native" || a2 === "0x0000000000000000000000000000000000000000" || a2 === "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" || addr === "T9yD14Nj9j7xAB4dbGeiX9h8unkKHxuWwb";
|
|
4938
4751
|
}
|
|
4752
|
+
function sleep(ms2) {
|
|
4753
|
+
return new Promise((resolve) => setTimeout(resolve, ms2));
|
|
4754
|
+
}
|
|
4939
4755
|
function toTronBase58(addr, tronWeb) {
|
|
4940
4756
|
if (!addr) throw new Error("Empty TRON address");
|
|
4941
4757
|
if (addr.startsWith("T")) return addr;
|
|
@@ -4982,24 +4798,27 @@ async function getEvmBalances(publicClient, address, tokens) {
|
|
|
4982
4798
|
if (!publicClient) {
|
|
4983
4799
|
throw new Error("No public client provided");
|
|
4984
4800
|
}
|
|
4985
|
-
const nativeTokens = tokens.filter((t2) => isNativeAddress(t2.address));
|
|
4986
4801
|
const erc20Tokens = tokens.filter(
|
|
4987
4802
|
(t2) => !isNativeAddress(t2.address) && isAddress(t2.address)
|
|
4988
4803
|
);
|
|
4989
|
-
|
|
4804
|
+
const chainNative = publicClient.chain?.nativeCurrency;
|
|
4805
|
+
const nativeSymbol = chainNative?.symbol ?? "ETH";
|
|
4806
|
+
const nativeDecimals = chainNative?.decimals ?? 18;
|
|
4807
|
+
const maxAttempts = 2;
|
|
4808
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
4990
4809
|
try {
|
|
4991
|
-
const
|
|
4810
|
+
const nativeBalance = await publicClient.getBalance({
|
|
4992
4811
|
address
|
|
4993
4812
|
});
|
|
4994
|
-
const balance = parseFloat(formatUnits(
|
|
4813
|
+
const balance = parseFloat(formatUnits(nativeBalance, nativeDecimals));
|
|
4995
4814
|
if (balance > 0) {
|
|
4996
|
-
balances[
|
|
4815
|
+
balances[nativeSymbol] = { balance, address };
|
|
4816
|
+
}
|
|
4817
|
+
break;
|
|
4818
|
+
} catch {
|
|
4819
|
+
if (attempt !== maxAttempts) {
|
|
4820
|
+
await sleep(250 * attempt);
|
|
4997
4821
|
}
|
|
4998
|
-
} catch (error) {
|
|
4999
|
-
console.debug(
|
|
5000
|
-
`Failed to get native balance for ${token.symbol}:`,
|
|
5001
|
-
error
|
|
5002
|
-
);
|
|
5003
4822
|
}
|
|
5004
4823
|
}
|
|
5005
4824
|
if (erc20Tokens.length > 0) {
|
|
@@ -5033,11 +4852,7 @@ async function getEvmBalances(publicClient, address, tokens) {
|
|
|
5033
4852
|
if (balance > 0) {
|
|
5034
4853
|
balances[token.symbol] = { balance, address };
|
|
5035
4854
|
}
|
|
5036
|
-
} catch
|
|
5037
|
-
console.debug(
|
|
5038
|
-
`Failed to parse balance for ${token.symbol}:`,
|
|
5039
|
-
error
|
|
5040
|
-
);
|
|
4855
|
+
} catch {
|
|
5041
4856
|
}
|
|
5042
4857
|
}
|
|
5043
4858
|
});
|
|
@@ -5068,8 +4883,7 @@ async function getEvmBalances(publicClient, address, tokens) {
|
|
|
5068
4883
|
if (balance > 0) {
|
|
5069
4884
|
balances[token.symbol] = { balance, address };
|
|
5070
4885
|
}
|
|
5071
|
-
} catch
|
|
5072
|
-
console.debug(`Failed to get balance for ${token.symbol}:`, error2);
|
|
4886
|
+
} catch {
|
|
5073
4887
|
}
|
|
5074
4888
|
}
|
|
5075
4889
|
}
|
|
@@ -5129,12 +4943,7 @@ async function getTonBalances(address, tokens, customTonClient, tonApiKey) {
|
|
|
5129
4943
|
balances[symbolNorm] = entry;
|
|
5130
4944
|
}
|
|
5131
4945
|
}
|
|
5132
|
-
} catch
|
|
5133
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
5134
|
-
const isNoWalletError = errorMessage.includes("exit_code: -13") || errorMessage.includes("exit_code:-13") || errorMessage.includes("exitCode: -13");
|
|
5135
|
-
if (!isNoWalletError) {
|
|
5136
|
-
console.debug(`Failed to get balance for ${token.symbol}:`, error);
|
|
5137
|
-
}
|
|
4946
|
+
} catch {
|
|
5138
4947
|
}
|
|
5139
4948
|
}
|
|
5140
4949
|
} catch (error) {
|
|
@@ -5156,8 +4965,7 @@ async function getTronBalances(tronWeb, address, tokens) {
|
|
|
5156
4965
|
if (trxBalance > 0) {
|
|
5157
4966
|
balances.TRX = { balance: trxBalance, address: ownerB58 };
|
|
5158
4967
|
}
|
|
5159
|
-
} catch
|
|
5160
|
-
console.warn("Failed to get native TRX balance:", error);
|
|
4968
|
+
} catch {
|
|
5161
4969
|
}
|
|
5162
4970
|
for (const token of tokens) {
|
|
5163
4971
|
try {
|
|
@@ -5191,21 +4999,19 @@ async function getTronBalances(tronWeb, address, tokens) {
|
|
|
5191
4999
|
if (balance > 0) {
|
|
5192
5000
|
balances[token.symbol] = { balance, address: ownerB58 };
|
|
5193
5001
|
}
|
|
5194
|
-
} catch
|
|
5195
|
-
console.warn(`Failed to get TRON balance for ${token.symbol}:`, error);
|
|
5002
|
+
} catch {
|
|
5196
5003
|
}
|
|
5197
5004
|
}
|
|
5198
|
-
} catch
|
|
5199
|
-
console.error("Failed to get Tron balances:", error);
|
|
5005
|
+
} catch {
|
|
5200
5006
|
}
|
|
5201
5007
|
return balances;
|
|
5202
5008
|
}
|
|
5203
|
-
const ERC20_ABI = [
|
|
5009
|
+
const ERC20_ABI = parseAbi([
|
|
5204
5010
|
"function approve(address spender, uint256 amount) returns (bool)",
|
|
5205
5011
|
"function allowance(address owner, address spender) view returns (uint256)",
|
|
5206
5012
|
"function decimals() view returns (uint8)",
|
|
5207
5013
|
"function balanceOf(address owner) view returns (uint256)"
|
|
5208
|
-
];
|
|
5014
|
+
]);
|
|
5209
5015
|
class EvmChainStrategy {
|
|
5210
5016
|
constructor(config) {
|
|
5211
5017
|
__publicField(this, "config");
|
|
@@ -5253,14 +5059,9 @@ class EvmChainStrategy {
|
|
|
5253
5059
|
}
|
|
5254
5060
|
async getBalances(address, tokens) {
|
|
5255
5061
|
if (!this.publicClient) {
|
|
5256
|
-
console.warn("No publicClient available for balance query");
|
|
5257
5062
|
return {};
|
|
5258
5063
|
}
|
|
5259
|
-
return await getEvmBalances(
|
|
5260
|
-
this.publicClient,
|
|
5261
|
-
address,
|
|
5262
|
-
tokens
|
|
5263
|
-
);
|
|
5064
|
+
return await getEvmBalances(this.publicClient, address, tokens);
|
|
5264
5065
|
}
|
|
5265
5066
|
isAddressValid(address) {
|
|
5266
5067
|
if (!address) return false;
|
|
@@ -5296,7 +5097,6 @@ class EvmChainStrategy {
|
|
|
5296
5097
|
}
|
|
5297
5098
|
async getSourceCost(txHash) {
|
|
5298
5099
|
if (!this.publicClient) {
|
|
5299
|
-
console.warn("No publicClient available for source cost query");
|
|
5300
5100
|
return null;
|
|
5301
5101
|
}
|
|
5302
5102
|
try {
|
|
@@ -5311,18 +5111,61 @@ class EvmChainStrategy {
|
|
|
5311
5111
|
const gasFeeWei = gasUsed * gasPrice;
|
|
5312
5112
|
const txValueWei = tx.value ?? 0n;
|
|
5313
5113
|
const totalWei = gasFeeWei + txValueWei;
|
|
5314
|
-
|
|
5114
|
+
const sourceCost = {
|
|
5315
5115
|
totalNative: Number(formatUnits(totalWei, 18)),
|
|
5316
5116
|
breakdown: {
|
|
5317
5117
|
gasFee: Number(formatUnits(gasFeeWei, 18)),
|
|
5318
5118
|
layerZeroFee: Number(formatUnits(txValueWei, 18))
|
|
5319
5119
|
}
|
|
5320
5120
|
};
|
|
5121
|
+
return sourceCost;
|
|
5321
5122
|
} catch (error) {
|
|
5322
5123
|
console.warn("Failed to compute EVM source cost:", error);
|
|
5323
5124
|
return null;
|
|
5324
5125
|
}
|
|
5325
5126
|
}
|
|
5127
|
+
async estimateNetworkFee(steps) {
|
|
5128
|
+
if (!this.walletClient) {
|
|
5129
|
+
return 0;
|
|
5130
|
+
}
|
|
5131
|
+
const account = this.config.evmAddress;
|
|
5132
|
+
const txSteps = steps.filter((step) => step.transaction?.to);
|
|
5133
|
+
if (!txSteps.length) {
|
|
5134
|
+
return 0;
|
|
5135
|
+
}
|
|
5136
|
+
const applyFeeMultiplier = (feePerGas) => {
|
|
5137
|
+
const multiplier = EVM_CONFIG.gasFeeMultiplier;
|
|
5138
|
+
if (!Number.isFinite(multiplier) || multiplier <= 1) {
|
|
5139
|
+
return feePerGas;
|
|
5140
|
+
}
|
|
5141
|
+
const scaled = BigInt(Math.round(multiplier * 100));
|
|
5142
|
+
return (feePerGas * scaled + 99n) / 100n;
|
|
5143
|
+
};
|
|
5144
|
+
let totalFeeWei = 0n;
|
|
5145
|
+
for (const step of txSteps) {
|
|
5146
|
+
const tx = step.transaction;
|
|
5147
|
+
if (!tx?.to) continue;
|
|
5148
|
+
try {
|
|
5149
|
+
const request = await this.walletClient.prepareTransactionRequest({
|
|
5150
|
+
account: tx.from || account,
|
|
5151
|
+
to: tx.to,
|
|
5152
|
+
data: tx.data,
|
|
5153
|
+
value: tx.value ? BigInt(tx.value) : void 0,
|
|
5154
|
+
chain: this.walletClient.chain
|
|
5155
|
+
});
|
|
5156
|
+
const gasLimit = request.gas;
|
|
5157
|
+
const maxFeePerGas = request.maxFeePerGas ?? request.gasPrice;
|
|
5158
|
+
if (gasLimit && maxFeePerGas) {
|
|
5159
|
+
totalFeeWei += gasLimit * applyFeeMultiplier(maxFeePerGas);
|
|
5160
|
+
}
|
|
5161
|
+
} catch {
|
|
5162
|
+
}
|
|
5163
|
+
}
|
|
5164
|
+
if (totalFeeWei === 0n) {
|
|
5165
|
+
return 0;
|
|
5166
|
+
}
|
|
5167
|
+
return Number(formatUnits(totalFeeWei, 18));
|
|
5168
|
+
}
|
|
5326
5169
|
async executeSteps(steps, _context, onFirstHash) {
|
|
5327
5170
|
if (!this.isConnected() || !this.walletClient) {
|
|
5328
5171
|
throw new WalletNotConnectedError("evm");
|
|
@@ -5336,134 +5179,32 @@ class EvmChainStrategy {
|
|
|
5336
5179
|
);
|
|
5337
5180
|
if (step.type === "approve") {
|
|
5338
5181
|
const hash = await this.approveTransaction(step);
|
|
5339
|
-
console.log(`Approval transaction hash: ${hash}`);
|
|
5340
5182
|
if (!firstTxHash) {
|
|
5341
5183
|
firstTxHash = hash;
|
|
5342
5184
|
onFirstHash?.(hash);
|
|
5343
5185
|
}
|
|
5344
5186
|
} else if (step.type === "bridge") {
|
|
5345
5187
|
const hash = await this.executeTransaction(step);
|
|
5346
|
-
console.log(`Bridge transaction hash: ${hash}`);
|
|
5347
5188
|
if (!firstTxHash) {
|
|
5348
5189
|
firstTxHash = hash;
|
|
5349
5190
|
onFirstHash?.(hash);
|
|
5350
5191
|
}
|
|
5351
5192
|
} else {
|
|
5352
|
-
throw new InvalidStepsError(
|
|
5353
|
-
"evm",
|
|
5354
|
-
`Unsupported step type: ${step.type}`
|
|
5355
|
-
);
|
|
5356
|
-
}
|
|
5357
|
-
}
|
|
5358
|
-
return {
|
|
5359
|
-
hash: firstTxHash,
|
|
5360
|
-
chainKey: steps[0]?.chainKey
|
|
5361
|
-
};
|
|
5362
|
-
} catch (error) {
|
|
5363
|
-
if (error instanceof Error && error.name.includes("Error")) {
|
|
5364
|
-
throw error;
|
|
5365
|
-
}
|
|
5366
|
-
throw toChainStrategyError(error, "evm", "transaction");
|
|
5367
|
-
}
|
|
5368
|
-
}
|
|
5369
|
-
async waitForCompletion(txHash) {
|
|
5370
|
-
try {
|
|
5371
|
-
const publicClient = this.publicClient;
|
|
5372
|
-
if (!publicClient) {
|
|
5373
|
-
throw new ProviderNotAvailableError("evm");
|
|
5374
|
-
}
|
|
5375
|
-
console.log(
|
|
5376
|
-
`Waiting for ${EVM_CONFIG.requiredConfirmations} confirmations for tx: ${txHash}`
|
|
5377
|
-
);
|
|
5378
|
-
const receipt = await publicClient.waitForTransactionReceipt({
|
|
5379
|
-
hash: txHash,
|
|
5380
|
-
confirmations: EVM_CONFIG.requiredConfirmations,
|
|
5381
|
-
timeout: EVM_CONFIG.timeout
|
|
5382
|
-
});
|
|
5383
|
-
if (!receipt) {
|
|
5384
|
-
const error = new TransactionTimeoutError("evm", txHash);
|
|
5385
|
-
return {
|
|
5386
|
-
completed: false,
|
|
5387
|
-
error: error.message
|
|
5388
|
-
};
|
|
5389
|
-
}
|
|
5390
|
-
if (receipt.status !== "success") {
|
|
5391
|
-
const error = new TransactionRevertedError("evm", txHash);
|
|
5392
|
-
return {
|
|
5393
|
-
completed: false,
|
|
5394
|
-
error: error.message
|
|
5395
|
-
};
|
|
5396
|
-
}
|
|
5397
|
-
console.log(
|
|
5398
|
-
`EVM transaction confirmed in block ${receipt.blockNumber} with ${EVM_CONFIG.requiredConfirmations} confirmations`
|
|
5399
|
-
);
|
|
5400
|
-
let actualFeeValue;
|
|
5401
|
-
try {
|
|
5402
|
-
const gasUsed = receipt.gasUsed;
|
|
5403
|
-
const effectiveGasPrice = receipt.effectiveGasPrice;
|
|
5404
|
-
if (gasUsed && effectiveGasPrice) {
|
|
5405
|
-
const feeWei = gasUsed * effectiveGasPrice;
|
|
5406
|
-
const feeInNative = formatUnits(feeWei, 18);
|
|
5407
|
-
actualFeeValue = feeInNative;
|
|
5408
|
-
console.log(`EVM transaction fee: ${feeInNative} (native token)`);
|
|
5193
|
+
throw new InvalidStepsError(
|
|
5194
|
+
"evm",
|
|
5195
|
+
`Unsupported step type: ${step.type}`
|
|
5196
|
+
);
|
|
5409
5197
|
}
|
|
5410
|
-
} catch (error) {
|
|
5411
|
-
console.warn("Failed to calculate actual fee:", error);
|
|
5412
5198
|
}
|
|
5413
5199
|
return {
|
|
5414
|
-
|
|
5415
|
-
|
|
5416
|
-
// Symbol will be determined by the caller based on chain info
|
|
5200
|
+
hash: firstTxHash,
|
|
5201
|
+
chainKey: steps[0]?.chainKey
|
|
5417
5202
|
};
|
|
5418
5203
|
} catch (error) {
|
|
5419
|
-
if (error
|
|
5420
|
-
|
|
5421
|
-
`Transaction was replaced: ${"reason" in error ? String(error.reason) : "unknown"}`
|
|
5422
|
-
);
|
|
5423
|
-
if ("receipt" in error && error.receipt) {
|
|
5424
|
-
const replacementReceipt = error.receipt;
|
|
5425
|
-
if (replacementReceipt.status === 1) {
|
|
5426
|
-
console.log(
|
|
5427
|
-
`Replacement transaction succeeded in block ${replacementReceipt.blockNumber}`
|
|
5428
|
-
);
|
|
5429
|
-
let actualFeeValue;
|
|
5430
|
-
try {
|
|
5431
|
-
const receipt = error.receipt;
|
|
5432
|
-
const gasUsed = receipt.gasUsed;
|
|
5433
|
-
const effectiveGasPrice = receipt.effectiveGasPrice;
|
|
5434
|
-
if (gasUsed && effectiveGasPrice) {
|
|
5435
|
-
const feeWei = gasUsed * effectiveGasPrice;
|
|
5436
|
-
const feeInNative = formatUnits(feeWei, 18);
|
|
5437
|
-
actualFeeValue = feeInNative;
|
|
5438
|
-
console.log(
|
|
5439
|
-
`Replacement transaction fee: ${feeInNative} (native token)`
|
|
5440
|
-
);
|
|
5441
|
-
}
|
|
5442
|
-
} catch (feeError) {
|
|
5443
|
-
console.warn("Failed to calculate replacement transaction fee:", feeError);
|
|
5444
|
-
}
|
|
5445
|
-
return {
|
|
5446
|
-
completed: true,
|
|
5447
|
-
actualFeeValue
|
|
5448
|
-
};
|
|
5449
|
-
} else {
|
|
5450
|
-
const chainError2 = new TransactionRevertedError("evm", txHash);
|
|
5451
|
-
return {
|
|
5452
|
-
completed: false,
|
|
5453
|
-
error: chainError2.message
|
|
5454
|
-
};
|
|
5455
|
-
}
|
|
5456
|
-
}
|
|
5204
|
+
if (error instanceof Error && error.name.includes("Error")) {
|
|
5205
|
+
throw error;
|
|
5457
5206
|
}
|
|
5458
|
-
|
|
5459
|
-
error,
|
|
5460
|
-
"evm",
|
|
5461
|
-
"waitForCompletion"
|
|
5462
|
-
);
|
|
5463
|
-
return {
|
|
5464
|
-
completed: false,
|
|
5465
|
-
error: chainError.message
|
|
5466
|
-
};
|
|
5207
|
+
throw toChainStrategyError(error, "evm", "transaction");
|
|
5467
5208
|
}
|
|
5468
5209
|
}
|
|
5469
5210
|
async executeTransaction(step) {
|
|
@@ -5620,88 +5361,14 @@ class EvmChainStrategy {
|
|
|
5620
5361
|
blockTag: "finalized"
|
|
5621
5362
|
});
|
|
5622
5363
|
if (!finalizedBlock) {
|
|
5623
|
-
console.debug(
|
|
5624
|
-
"Finalized block not available (pre-merge or unsupported)"
|
|
5625
|
-
);
|
|
5626
5364
|
return false;
|
|
5627
5365
|
}
|
|
5628
|
-
|
|
5629
|
-
|
|
5630
|
-
console.log(
|
|
5631
|
-
`Block ${blockNumber} has reached finality (finalized block: ${finalizedBlock.number})`
|
|
5632
|
-
);
|
|
5633
|
-
} else {
|
|
5634
|
-
console.debug(
|
|
5635
|
-
`Block ${blockNumber} not yet finalized (finalized block: ${finalizedBlock.number})`
|
|
5636
|
-
);
|
|
5637
|
-
}
|
|
5638
|
-
return isFinalized;
|
|
5639
|
-
} catch (error) {
|
|
5640
|
-
console.debug("Error checking finality:", error);
|
|
5366
|
+
return blockNumber <= finalizedBlock.number;
|
|
5367
|
+
} catch {
|
|
5641
5368
|
return false;
|
|
5642
5369
|
}
|
|
5643
5370
|
}
|
|
5644
5371
|
}
|
|
5645
|
-
function getNormalizedExtMessageHash(message) {
|
|
5646
|
-
if (message.info.type !== "external-in") {
|
|
5647
|
-
throw new Error(`Expected external-in message, got ${message.info.type}`);
|
|
5648
|
-
}
|
|
5649
|
-
const normalizedInfo = {
|
|
5650
|
-
...message.info,
|
|
5651
|
-
src: void 0,
|
|
5652
|
-
importFee: 0n
|
|
5653
|
-
};
|
|
5654
|
-
const normalizedMessage = {
|
|
5655
|
-
...message,
|
|
5656
|
-
info: normalizedInfo,
|
|
5657
|
-
init: null
|
|
5658
|
-
};
|
|
5659
|
-
return beginCell$1().store(storeMessage(normalizedMessage, { forceRef: true })).endCell().hash();
|
|
5660
|
-
}
|
|
5661
|
-
async function getTonTransactionHash(messageHash, userAddress, searchLimit = 20, options) {
|
|
5662
|
-
try {
|
|
5663
|
-
const client = options?.client ?? new TonClient({
|
|
5664
|
-
endpoint: "https://toncenter.com/api/v2/jsonRPC",
|
|
5665
|
-
apiKey: process.env.TONCENTER_API_KEY
|
|
5666
|
-
// Optional: for rate limit increase
|
|
5667
|
-
});
|
|
5668
|
-
const messageHasher = options?.messageHasher ?? getNormalizedExtMessageHash;
|
|
5669
|
-
const address = Address.parse(userAddress);
|
|
5670
|
-
const transactions = await client.getTransactions(address, {
|
|
5671
|
-
limit: searchLimit
|
|
5672
|
-
});
|
|
5673
|
-
for (const tx of transactions) {
|
|
5674
|
-
const inMsg = tx.inMessage;
|
|
5675
|
-
if (!inMsg) continue;
|
|
5676
|
-
try {
|
|
5677
|
-
const inMsgHash = messageHasher(inMsg).toString("hex");
|
|
5678
|
-
if (inMsgHash === messageHash.replace("0x", "")) {
|
|
5679
|
-
const txHash = tx.hash().toString("hex");
|
|
5680
|
-
return {
|
|
5681
|
-
transactionHash: `0x${txHash}`,
|
|
5682
|
-
messageHash,
|
|
5683
|
-
found: true
|
|
5684
|
-
};
|
|
5685
|
-
}
|
|
5686
|
-
} catch {
|
|
5687
|
-
continue;
|
|
5688
|
-
}
|
|
5689
|
-
}
|
|
5690
|
-
console.warn(`TON transaction not found for message hash: ${messageHash}`);
|
|
5691
|
-
return {
|
|
5692
|
-
transactionHash: null,
|
|
5693
|
-
messageHash,
|
|
5694
|
-
found: false
|
|
5695
|
-
};
|
|
5696
|
-
} catch (error) {
|
|
5697
|
-
console.error("Failed to get TON transaction hash:", error);
|
|
5698
|
-
return {
|
|
5699
|
-
transactionHash: null,
|
|
5700
|
-
messageHash,
|
|
5701
|
-
found: false
|
|
5702
|
-
};
|
|
5703
|
-
}
|
|
5704
|
-
}
|
|
5705
5372
|
class TonChainStrategy {
|
|
5706
5373
|
constructor(config) {
|
|
5707
5374
|
__publicField(this, "config");
|
|
@@ -5814,40 +5481,17 @@ class TonChainStrategy {
|
|
|
5814
5481
|
validUntil: Math.floor(Date.now() / 1e3) + TON_CONFIG.validUntil,
|
|
5815
5482
|
messages: tonMessages
|
|
5816
5483
|
};
|
|
5817
|
-
const result = await this.config.tonConnectUI.sendTransaction(
|
|
5818
|
-
transaction2
|
|
5819
|
-
);
|
|
5484
|
+
const result = await this.config.tonConnectUI.sendTransaction(transaction2);
|
|
5820
5485
|
const bocBase64 = result.boc;
|
|
5821
5486
|
try {
|
|
5822
5487
|
const inMessage = loadMessage(Cell.fromBase64(bocBase64).beginParse());
|
|
5823
5488
|
const messageHash = this.getNormalizedExtMessageHash(inMessage);
|
|
5824
5489
|
const hexHash = messageHash.toString("hex");
|
|
5825
5490
|
onFirstHash?.(hexHash);
|
|
5826
|
-
let tonTransactionHash;
|
|
5827
|
-
if (this.config.tonAddress) {
|
|
5828
|
-
try {
|
|
5829
|
-
const tonTxResult = await getTonTransactionHash(
|
|
5830
|
-
hexHash,
|
|
5831
|
-
this.config.tonAddress,
|
|
5832
|
-
20
|
|
5833
|
-
);
|
|
5834
|
-
if (tonTxResult.found && tonTxResult.transactionHash) {
|
|
5835
|
-
tonTransactionHash = tonTxResult.transactionHash;
|
|
5836
|
-
} else {
|
|
5837
|
-
console.warn(
|
|
5838
|
-
`TON transaction hash not found for message hash: ${hexHash}`
|
|
5839
|
-
);
|
|
5840
|
-
}
|
|
5841
|
-
} catch (error) {
|
|
5842
|
-
console.error("Failed to convert TON message hash:", error);
|
|
5843
|
-
}
|
|
5844
|
-
}
|
|
5845
5491
|
return {
|
|
5846
5492
|
chainKey: "ton",
|
|
5847
|
-
hash: hexHash
|
|
5848
|
-
// Message hash for TONScan
|
|
5849
|
-
tonTransactionHash
|
|
5850
|
-
// Transaction hash for LayerZero (if found)
|
|
5493
|
+
hash: hexHash
|
|
5494
|
+
// Message hash for TONScan and for finding tx later
|
|
5851
5495
|
};
|
|
5852
5496
|
} catch (error) {
|
|
5853
5497
|
console.error("Error parsing BOC to hex hash:", error);
|
|
@@ -5861,39 +5505,45 @@ class TonChainStrategy {
|
|
|
5861
5505
|
throw toChainStrategyError(error, "ton", "transaction");
|
|
5862
5506
|
}
|
|
5863
5507
|
}
|
|
5864
|
-
|
|
5865
|
-
|
|
5866
|
-
|
|
5867
|
-
|
|
5868
|
-
|
|
5869
|
-
|
|
5870
|
-
|
|
5871
|
-
|
|
5872
|
-
|
|
5873
|
-
|
|
5874
|
-
|
|
5875
|
-
|
|
5876
|
-
|
|
5877
|
-
|
|
5878
|
-
|
|
5879
|
-
|
|
5508
|
+
/**
|
|
5509
|
+
* Convert TON message hash to transaction hash.
|
|
5510
|
+
* LayerZero uses transaction hash, but TonConnect returns message hash.
|
|
5511
|
+
*/
|
|
5512
|
+
async convertMessageHashToTxHash(messageHash, timeoutMs = 6e4) {
|
|
5513
|
+
const deadline = Date.now() + timeoutMs;
|
|
5514
|
+
const client = getTonClient(this.config.tonClient, this.config.tonApiKey);
|
|
5515
|
+
if (!this.config.tonAddress) {
|
|
5516
|
+
return null;
|
|
5517
|
+
}
|
|
5518
|
+
const targetMessageHash = Buffer.from(messageHash, "hex");
|
|
5519
|
+
const accountAddress = Address.parse(this.config.tonAddress);
|
|
5520
|
+
while (Date.now() < deadline) {
|
|
5521
|
+
try {
|
|
5522
|
+
const transactions = await client.getTransactions(accountAddress, {
|
|
5523
|
+
limit: 20,
|
|
5524
|
+
archival: true
|
|
5525
|
+
});
|
|
5526
|
+
for (const tx of transactions) {
|
|
5527
|
+
if (tx.inMessage?.info.type === "external-in") {
|
|
5528
|
+
try {
|
|
5529
|
+
const txInMessageHash = this.getNormalizedExtMessageHash(
|
|
5530
|
+
tx.inMessage
|
|
5531
|
+
);
|
|
5532
|
+
if (txInMessageHash.equals(targetMessageHash)) {
|
|
5533
|
+
const txHash = `0x${tx.hash().toString("hex")}`;
|
|
5534
|
+
return txHash;
|
|
5535
|
+
}
|
|
5536
|
+
} catch {
|
|
5537
|
+
continue;
|
|
5538
|
+
}
|
|
5539
|
+
}
|
|
5540
|
+
}
|
|
5541
|
+
await new Promise((r2) => setTimeout(r2, 3e3));
|
|
5542
|
+
} catch {
|
|
5543
|
+
await new Promise((r2) => setTimeout(r2, 3e3));
|
|
5880
5544
|
}
|
|
5881
|
-
return {
|
|
5882
|
-
completed: true,
|
|
5883
|
-
actualFeeValue: result.fee,
|
|
5884
|
-
actualFeeSymbol: "TON"
|
|
5885
|
-
};
|
|
5886
|
-
} catch (error) {
|
|
5887
|
-
const chainError = toChainStrategyError(
|
|
5888
|
-
error,
|
|
5889
|
-
"ton",
|
|
5890
|
-
"waitForCompletion"
|
|
5891
|
-
);
|
|
5892
|
-
return {
|
|
5893
|
-
completed: false,
|
|
5894
|
-
error: chainError.message
|
|
5895
|
-
};
|
|
5896
5545
|
}
|
|
5546
|
+
return null;
|
|
5897
5547
|
}
|
|
5898
5548
|
getNormalizedExtMessageHash(message) {
|
|
5899
5549
|
if (message.info.type !== "external-in") {
|
|
@@ -5916,6 +5566,9 @@ class TonChainStrategy {
|
|
|
5916
5566
|
if (typeof value === "number" && Number.isFinite(value)) {
|
|
5917
5567
|
return BigInt(Math.trunc(value));
|
|
5918
5568
|
}
|
|
5569
|
+
if (typeof value === "object" && value !== null && "coins" in value) {
|
|
5570
|
+
return this.toBigInt(value.coins);
|
|
5571
|
+
}
|
|
5919
5572
|
if (typeof value === "string" && value.trim() !== "") {
|
|
5920
5573
|
try {
|
|
5921
5574
|
return BigInt(value);
|
|
@@ -5929,12 +5582,16 @@ class TonChainStrategy {
|
|
|
5929
5582
|
const candidate = tx.outMessages;
|
|
5930
5583
|
if (!candidate) return [];
|
|
5931
5584
|
if (Array.isArray(candidate)) return candidate;
|
|
5932
|
-
if (candidate instanceof Map) return Array.from(candidate.values());
|
|
5933
5585
|
if (typeof candidate === "object" && candidate !== null && "values" in candidate && typeof candidate.values === "function") {
|
|
5934
|
-
|
|
5935
|
-
|
|
5936
|
-
|
|
5586
|
+
const values = candidate.values();
|
|
5587
|
+
if (Array.isArray(values)) {
|
|
5588
|
+
return [...values];
|
|
5589
|
+
}
|
|
5590
|
+
if (values && typeof values === "object" && Symbol.iterator in values) {
|
|
5591
|
+
return Array.from(values);
|
|
5592
|
+
}
|
|
5937
5593
|
}
|
|
5594
|
+
if (candidate instanceof Map) return Array.from(candidate.values());
|
|
5938
5595
|
return [];
|
|
5939
5596
|
}
|
|
5940
5597
|
getMessageValue(message) {
|
|
@@ -5946,27 +5603,49 @@ class TonChainStrategy {
|
|
|
5946
5603
|
}
|
|
5947
5604
|
return this.toBigInt(value);
|
|
5948
5605
|
}
|
|
5949
|
-
|
|
5606
|
+
getTotalOutMessageValue(tx) {
|
|
5950
5607
|
const outMessages = this.getOutMessages(tx);
|
|
5951
5608
|
if (!outMessages.length) return 0n;
|
|
5952
|
-
|
|
5953
|
-
|
|
5609
|
+
let total = 0n;
|
|
5610
|
+
for (const message of outMessages) {
|
|
5611
|
+
const value = this.getMessageValue(message);
|
|
5612
|
+
if (value) {
|
|
5613
|
+
total += value;
|
|
5614
|
+
}
|
|
5615
|
+
}
|
|
5616
|
+
return total;
|
|
5954
5617
|
}
|
|
5955
|
-
async getSourceCost(
|
|
5956
|
-
const timeoutMs =
|
|
5957
|
-
const result = await this.checkTonTransaction(
|
|
5958
|
-
if (!result.confirmed)
|
|
5618
|
+
async getSourceCost(messageHash) {
|
|
5619
|
+
const timeoutMs = 3e4;
|
|
5620
|
+
const result = await this.checkTonTransaction(messageHash, timeoutMs);
|
|
5621
|
+
if (!result.confirmed) {
|
|
5622
|
+
console.warn("Transaction not found for source cost calculation");
|
|
5623
|
+
return null;
|
|
5624
|
+
}
|
|
5959
5625
|
const totalFees = result.totalFees ?? 0n;
|
|
5960
5626
|
const outValue = result.outValue ?? 0n;
|
|
5961
5627
|
const totalNanotons = totalFees + outValue;
|
|
5962
5628
|
const toTon = (value) => Number(value) / 1e9;
|
|
5963
|
-
|
|
5629
|
+
const sourceCost = {
|
|
5964
5630
|
totalNative: toTon(totalNanotons),
|
|
5965
5631
|
breakdown: {
|
|
5966
5632
|
gasFee: toTon(totalFees),
|
|
5967
5633
|
layerZeroFee: toTon(outValue)
|
|
5968
5634
|
}
|
|
5969
5635
|
};
|
|
5636
|
+
console.log("TON source cost:", {
|
|
5637
|
+
gasFee: `${sourceCost.breakdown.gasFee} TON`,
|
|
5638
|
+
layerZeroFee: `${sourceCost.breakdown.layerZeroFee} TON`,
|
|
5639
|
+
total: `${sourceCost.totalNative} TON`
|
|
5640
|
+
});
|
|
5641
|
+
return sourceCost;
|
|
5642
|
+
}
|
|
5643
|
+
async estimateNetworkFee() {
|
|
5644
|
+
const fee = Number(TON_CONFIG.estimatedNetworkFee);
|
|
5645
|
+
if (!Number.isFinite(fee) || fee <= 0) {
|
|
5646
|
+
return 0;
|
|
5647
|
+
}
|
|
5648
|
+
return fee / 1e9;
|
|
5970
5649
|
}
|
|
5971
5650
|
async checkTonTransaction(hashOrBoc, timeoutMs = 36e4) {
|
|
5972
5651
|
const deadline = Date.now() + timeoutMs;
|
|
@@ -5977,10 +5656,6 @@ class TonChainStrategy {
|
|
|
5977
5656
|
try {
|
|
5978
5657
|
const inMessage = loadMessage(Cell.fromBase64(hashOrBoc).beginParse());
|
|
5979
5658
|
if (inMessage.info.type !== "external-in") {
|
|
5980
|
-
console.debug(
|
|
5981
|
-
"Expected external-in message, got:",
|
|
5982
|
-
inMessage.info.type
|
|
5983
|
-
);
|
|
5984
5659
|
return { confirmed: false };
|
|
5985
5660
|
}
|
|
5986
5661
|
accountAddress = inMessage.info.dest;
|
|
@@ -5988,63 +5663,50 @@ class TonChainStrategy {
|
|
|
5988
5663
|
} catch {
|
|
5989
5664
|
targetMessageHash = Buffer.from(hashOrBoc, "hex");
|
|
5990
5665
|
if (!this.config.tonAddress) {
|
|
5991
|
-
console.debug("No wallet address available for hex hash lookup");
|
|
5992
5666
|
return { confirmed: false };
|
|
5993
5667
|
}
|
|
5994
5668
|
accountAddress = Address.parse(this.config.tonAddress);
|
|
5995
5669
|
}
|
|
5996
|
-
let lt2 = void 0;
|
|
5997
|
-
let hash = void 0;
|
|
5998
5670
|
while (Date.now() < deadline) {
|
|
5999
5671
|
try {
|
|
6000
5672
|
const transactions = await client.getTransactions(accountAddress, {
|
|
6001
|
-
|
|
6002
|
-
|
|
6003
|
-
limit: 10,
|
|
5673
|
+
limit: 20,
|
|
5674
|
+
// Check last 20 transactions
|
|
6004
5675
|
archival: true
|
|
6005
5676
|
});
|
|
6006
|
-
if (transactions.length === 0) {
|
|
6007
|
-
await new Promise((r2) => setTimeout(r2, TON_CONFIG.pollingInterval));
|
|
6008
|
-
lt2 = void 0;
|
|
6009
|
-
hash = void 0;
|
|
6010
|
-
continue;
|
|
6011
|
-
}
|
|
6012
5677
|
for (const tx of transactions) {
|
|
6013
5678
|
if (tx.inMessage?.info.type === "external-in") {
|
|
6014
|
-
|
|
6015
|
-
|
|
6016
|
-
|
|
6017
|
-
|
|
6018
|
-
|
|
6019
|
-
|
|
6020
|
-
|
|
6021
|
-
|
|
6022
|
-
|
|
6023
|
-
|
|
6024
|
-
|
|
6025
|
-
|
|
6026
|
-
|
|
6027
|
-
|
|
6028
|
-
|
|
6029
|
-
|
|
6030
|
-
|
|
5679
|
+
try {
|
|
5680
|
+
const txInMessageHash = this.getNormalizedExtMessageHash(
|
|
5681
|
+
tx.inMessage
|
|
5682
|
+
);
|
|
5683
|
+
if (txInMessageHash.equals(targetMessageHash)) {
|
|
5684
|
+
const totalFees = this.toBigInt(tx.totalFees) ?? this.toBigInt(
|
|
5685
|
+
tx.total_fees
|
|
5686
|
+
) ?? 0n;
|
|
5687
|
+
const outValue = this.getTotalOutMessageValue(tx);
|
|
5688
|
+
const feeInTon = Number(totalFees) / 1e9;
|
|
5689
|
+
const transactionHash = tx.hash().toString("hex");
|
|
5690
|
+
return {
|
|
5691
|
+
confirmed: true,
|
|
5692
|
+
fee: feeInTon.toString(),
|
|
5693
|
+
totalFees,
|
|
5694
|
+
outValue,
|
|
5695
|
+
transactionHash
|
|
5696
|
+
};
|
|
5697
|
+
}
|
|
5698
|
+
} catch {
|
|
5699
|
+
continue;
|
|
6031
5700
|
}
|
|
6032
5701
|
}
|
|
6033
5702
|
}
|
|
6034
|
-
const lastTx = transactions[transactions.length - 1];
|
|
6035
|
-
lt2 = lastTx.lt.toString();
|
|
6036
|
-
hash = lastTx.hash().toString("base64");
|
|
6037
5703
|
await new Promise((r2) => setTimeout(r2, TON_CONFIG.pollingInterval));
|
|
6038
|
-
} catch
|
|
6039
|
-
console.debug("Error fetching transactions:", error);
|
|
5704
|
+
} catch {
|
|
6040
5705
|
await new Promise((r2) => setTimeout(r2, TON_CONFIG.pollingInterval));
|
|
6041
|
-
lt2 = void 0;
|
|
6042
|
-
hash = void 0;
|
|
6043
5706
|
}
|
|
6044
5707
|
}
|
|
6045
5708
|
return { confirmed: false };
|
|
6046
|
-
} catch
|
|
6047
|
-
console.debug("Error parsing BOC or checking transaction:", error);
|
|
5709
|
+
} catch {
|
|
6048
5710
|
return { confirmed: false };
|
|
6049
5711
|
}
|
|
6050
5712
|
}
|
|
@@ -6054,6 +5716,7 @@ class TronChainStrategy {
|
|
|
6054
5716
|
constructor(config) {
|
|
6055
5717
|
__publicField(this, "config");
|
|
6056
5718
|
__publicField(this, "fallbackClient");
|
|
5719
|
+
__publicField(this, "apiKeyApplied", /* @__PURE__ */ new WeakSet());
|
|
6057
5720
|
this.config = config;
|
|
6058
5721
|
}
|
|
6059
5722
|
canHandle(chainKey) {
|
|
@@ -6219,18 +5882,31 @@ class TronChainStrategy {
|
|
|
6219
5882
|
const feeTrx = feeSun / 1e6;
|
|
6220
5883
|
const lzFeeTrx = callValueSun / 1e6;
|
|
6221
5884
|
const totalTrx = (feeSun + callValueSun) / 1e6;
|
|
6222
|
-
|
|
5885
|
+
const sourceCost = {
|
|
6223
5886
|
totalNative: totalTrx,
|
|
6224
5887
|
breakdown: {
|
|
6225
5888
|
gasFee: feeTrx,
|
|
6226
5889
|
layerZeroFee: lzFeeTrx
|
|
6227
5890
|
}
|
|
6228
5891
|
};
|
|
5892
|
+
console.log("TRON source cost:", {
|
|
5893
|
+
gasFee: `${sourceCost.breakdown.gasFee} TRX`,
|
|
5894
|
+
layerZeroFee: `${sourceCost.breakdown.layerZeroFee} TRX`,
|
|
5895
|
+
total: `${sourceCost.totalNative} TRX`
|
|
5896
|
+
});
|
|
5897
|
+
return sourceCost;
|
|
6229
5898
|
} catch (error) {
|
|
6230
5899
|
console.warn("Failed to compute TRON source cost:", error);
|
|
6231
5900
|
return null;
|
|
6232
5901
|
}
|
|
6233
5902
|
}
|
|
5903
|
+
async estimateNetworkFee() {
|
|
5904
|
+
const fee = Number(TRON_CONFIG.estimatedNetworkFee);
|
|
5905
|
+
if (!Number.isFinite(fee) || fee <= 0) {
|
|
5906
|
+
return 0;
|
|
5907
|
+
}
|
|
5908
|
+
return fee / 1e6;
|
|
5909
|
+
}
|
|
6234
5910
|
async executeSteps(steps, _context, onFirstHash) {
|
|
6235
5911
|
const tronWeb = this.getClient();
|
|
6236
5912
|
if (!tronWeb) {
|
|
@@ -6327,137 +6003,59 @@ class TronChainStrategy {
|
|
|
6327
6003
|
}
|
|
6328
6004
|
return { hash: lastTxId, chainKey: "tron" };
|
|
6329
6005
|
}
|
|
6330
|
-
async waitForCompletion(txHash) {
|
|
6331
|
-
try {
|
|
6332
|
-
const tronWeb = this.getClient();
|
|
6333
|
-
if (!tronWeb) {
|
|
6334
|
-
throw new ProviderNotAvailableError("tron");
|
|
6335
|
-
}
|
|
6336
|
-
console.log(
|
|
6337
|
-
`Waiting for ${TRON_CONFIG.requiredConfirmations} confirmations for TRON tx: ${txHash}`
|
|
6338
|
-
);
|
|
6339
|
-
const deadline = Date.now() + TRON_CONFIG.timeout;
|
|
6340
|
-
let txBlockNumber = null;
|
|
6341
|
-
let actualFeeTrx = null;
|
|
6342
|
-
while (Date.now() < deadline && !txBlockNumber) {
|
|
6343
|
-
try {
|
|
6344
|
-
const info = await tronWeb.trx.getTransactionInfo(txHash);
|
|
6345
|
-
if (info && info.blockNumber) {
|
|
6346
|
-
const result = info.receipt?.result;
|
|
6347
|
-
if (result !== "SUCCESS") {
|
|
6348
|
-
const msg = this.hexToAscii(info.resMessage) || null;
|
|
6349
|
-
let reason = msg;
|
|
6350
|
-
const cr2 = info.contractResult?.[0];
|
|
6351
|
-
if (cr2 && /^0x?08c379a0/i.test(cr2)) {
|
|
6352
|
-
try {
|
|
6353
|
-
const clean2 = cr2.replace(/^0x/, "");
|
|
6354
|
-
const len = parseInt(clean2.slice(8 + 64, 8 + 64 + 64), 16);
|
|
6355
|
-
const strHex = clean2.slice(
|
|
6356
|
-
8 + 64 + 64,
|
|
6357
|
-
8 + 64 + 64 + len * 2
|
|
6358
|
-
);
|
|
6359
|
-
const str = this.hexToAscii("0x" + strHex);
|
|
6360
|
-
if (str) reason = str;
|
|
6361
|
-
} catch (e2) {
|
|
6362
|
-
console.debug("TRON revert string decode error", e2);
|
|
6363
|
-
}
|
|
6364
|
-
}
|
|
6365
|
-
const error2 = new TransactionRevertedError(
|
|
6366
|
-
"tron",
|
|
6367
|
-
txHash,
|
|
6368
|
-
reason || "Unknown error"
|
|
6369
|
-
);
|
|
6370
|
-
return {
|
|
6371
|
-
completed: false,
|
|
6372
|
-
error: error2.message
|
|
6373
|
-
};
|
|
6374
|
-
}
|
|
6375
|
-
txBlockNumber = info.blockNumber;
|
|
6376
|
-
const feeSun = info.fee || 0;
|
|
6377
|
-
actualFeeTrx = feeSun / 1e6;
|
|
6378
|
-
console.log(
|
|
6379
|
-
`TRON transaction found in block ${txBlockNumber}, fee: ${actualFeeTrx} TRX`
|
|
6380
|
-
);
|
|
6381
|
-
}
|
|
6382
|
-
} catch (e2) {
|
|
6383
|
-
console.debug("TRON getTransactionInfo error:", e2);
|
|
6384
|
-
}
|
|
6385
|
-
if (!txBlockNumber) {
|
|
6386
|
-
await new Promise((r2) => setTimeout(r2, TRON_CONFIG.pollingInterval));
|
|
6387
|
-
}
|
|
6388
|
-
}
|
|
6389
|
-
if (!txBlockNumber) {
|
|
6390
|
-
const error2 = new TransactionTimeoutError("tron", txHash);
|
|
6391
|
-
return {
|
|
6392
|
-
completed: false,
|
|
6393
|
-
error: error2.message
|
|
6394
|
-
};
|
|
6395
|
-
}
|
|
6396
|
-
let confirmations = 0;
|
|
6397
|
-
while (Date.now() < deadline) {
|
|
6398
|
-
try {
|
|
6399
|
-
const currentBlock = await tronWeb.trx.getCurrentBlock();
|
|
6400
|
-
const currentBlockNumber = currentBlock?.block_header?.raw_data?.number;
|
|
6401
|
-
if (currentBlockNumber) {
|
|
6402
|
-
confirmations = currentBlockNumber - txBlockNumber;
|
|
6403
|
-
if (confirmations >= TRON_CONFIG.requiredConfirmations) {
|
|
6404
|
-
console.log(
|
|
6405
|
-
`TRON transaction confirmed in block ${txBlockNumber} with ${confirmations} confirmations`
|
|
6406
|
-
);
|
|
6407
|
-
return {
|
|
6408
|
-
completed: true,
|
|
6409
|
-
actualFeeValue: actualFeeTrx?.toString(),
|
|
6410
|
-
actualFeeSymbol: "TRX"
|
|
6411
|
-
};
|
|
6412
|
-
}
|
|
6413
|
-
console.log(
|
|
6414
|
-
`TRON transaction confirmations: ${confirmations}/${TRON_CONFIG.requiredConfirmations}`
|
|
6415
|
-
);
|
|
6416
|
-
}
|
|
6417
|
-
} catch (e2) {
|
|
6418
|
-
console.debug("TRON getCurrentBlock error:", e2);
|
|
6419
|
-
}
|
|
6420
|
-
await new Promise((r2) => setTimeout(r2, TRON_CONFIG.pollingInterval));
|
|
6421
|
-
}
|
|
6422
|
-
const error = new TransactionTimeoutError("tron", txHash);
|
|
6423
|
-
return {
|
|
6424
|
-
completed: false,
|
|
6425
|
-
error: error.message
|
|
6426
|
-
};
|
|
6427
|
-
} catch (error) {
|
|
6428
|
-
const chainError = toChainStrategyError(
|
|
6429
|
-
error,
|
|
6430
|
-
"tron",
|
|
6431
|
-
"waitForCompletion"
|
|
6432
|
-
);
|
|
6433
|
-
return {
|
|
6434
|
-
completed: false,
|
|
6435
|
-
error: chainError.message
|
|
6436
|
-
};
|
|
6437
|
-
}
|
|
6438
|
-
}
|
|
6439
6006
|
getClient() {
|
|
6440
6007
|
if (typeof window !== "undefined" && window.tronWeb) {
|
|
6008
|
+
this.applyTronApiKey(window.tronWeb);
|
|
6441
6009
|
return window.tronWeb;
|
|
6442
6010
|
}
|
|
6443
6011
|
if (!this.fallbackClient) {
|
|
6444
6012
|
this.fallbackClient = this.createFallbackClient();
|
|
6445
6013
|
}
|
|
6014
|
+
if (this.fallbackClient) {
|
|
6015
|
+
this.applyTronApiKey(this.fallbackClient);
|
|
6016
|
+
}
|
|
6446
6017
|
return this.fallbackClient;
|
|
6447
6018
|
}
|
|
6448
6019
|
createFallbackClient() {
|
|
6449
6020
|
try {
|
|
6450
|
-
|
|
6451
|
-
|
|
6452
|
-
|
|
6453
|
-
|
|
6454
|
-
|
|
6021
|
+
if (!this.config.apiKey) {
|
|
6022
|
+
throw new Error("TRON API key is required");
|
|
6023
|
+
}
|
|
6024
|
+
const headers = { "TRON-PRO-API-KEY": this.config.apiKey };
|
|
6025
|
+
const tronWeb = new TronWeb({
|
|
6026
|
+
fullHost: DEFAULT_TRON_NODE,
|
|
6027
|
+
headers
|
|
6028
|
+
});
|
|
6455
6029
|
return tronWeb;
|
|
6456
6030
|
} catch (error) {
|
|
6457
6031
|
console.warn("Failed to create fallback TronWeb client", error);
|
|
6458
6032
|
return void 0;
|
|
6459
6033
|
}
|
|
6460
6034
|
}
|
|
6035
|
+
applyTronApiKey(tronWeb) {
|
|
6036
|
+
if (!this.config.apiKey) {
|
|
6037
|
+
return;
|
|
6038
|
+
}
|
|
6039
|
+
const target = tronWeb;
|
|
6040
|
+
if (this.apiKeyApplied.has(target)) {
|
|
6041
|
+
return;
|
|
6042
|
+
}
|
|
6043
|
+
try {
|
|
6044
|
+
const headers = { "TRON-PRO-API-KEY": this.config.apiKey };
|
|
6045
|
+
if (typeof target.setHeader === "function") {
|
|
6046
|
+
target.setHeader(headers);
|
|
6047
|
+
} else {
|
|
6048
|
+
if (typeof target.setFullNodeHeader === "function") {
|
|
6049
|
+
target.setFullNodeHeader(headers);
|
|
6050
|
+
}
|
|
6051
|
+
if (typeof target.setEventHeader === "function") {
|
|
6052
|
+
target.setEventHeader(headers);
|
|
6053
|
+
}
|
|
6054
|
+
}
|
|
6055
|
+
this.apiKeyApplied.add(target);
|
|
6056
|
+
} catch {
|
|
6057
|
+
}
|
|
6058
|
+
}
|
|
6461
6059
|
/**
|
|
6462
6060
|
* Check if TronLink wallet is actually installed
|
|
6463
6061
|
* This excludes Bybit Wallet which also injects tronLink for compatibility
|
|
@@ -6466,14 +6064,8 @@ class TronChainStrategy {
|
|
|
6466
6064
|
if (typeof window === "undefined") {
|
|
6467
6065
|
return false;
|
|
6468
6066
|
}
|
|
6469
|
-
const
|
|
6470
|
-
|
|
6471
|
-
return false;
|
|
6472
|
-
}
|
|
6473
|
-
if (!window.tronLink) {
|
|
6474
|
-
return false;
|
|
6475
|
-
}
|
|
6476
|
-
return true;
|
|
6067
|
+
const win = window;
|
|
6068
|
+
return !!(win.tronLink || win.tronWeb || win.tron);
|
|
6477
6069
|
}
|
|
6478
6070
|
ensureDefaultAddress(tronWeb, address) {
|
|
6479
6071
|
if (!address) return;
|
|
@@ -6486,18 +6078,7 @@ class TronChainStrategy {
|
|
|
6486
6078
|
hex
|
|
6487
6079
|
};
|
|
6488
6080
|
}
|
|
6489
|
-
} catch (error) {
|
|
6490
|
-
console.debug("Failed to set TronWeb default address:", error);
|
|
6491
|
-
}
|
|
6492
|
-
}
|
|
6493
|
-
hexToAscii(h4) {
|
|
6494
|
-
if (!h4) return null;
|
|
6495
|
-
const clean2 = h4.replace(/^0x/, "");
|
|
6496
|
-
const bytes = clean2.match(/.{1,2}/g) || [];
|
|
6497
|
-
try {
|
|
6498
|
-
return bytes.map((b2) => String.fromCharCode(parseInt(b2, 16))).join("");
|
|
6499
6081
|
} catch {
|
|
6500
|
-
return null;
|
|
6501
6082
|
}
|
|
6502
6083
|
}
|
|
6503
6084
|
toBase58(addr, tronWeb) {
|
|
@@ -6804,22 +6385,14 @@ class TronChainStrategy {
|
|
|
6804
6385
|
}
|
|
6805
6386
|
const info = await tronWeb.trx.getTransactionInfo(txHash);
|
|
6806
6387
|
if (!info || !info.blockNumber) {
|
|
6807
|
-
console.debug(
|
|
6808
|
-
"Transaction not yet solidified (no blockNumber in info)"
|
|
6809
|
-
);
|
|
6810
6388
|
return false;
|
|
6811
6389
|
}
|
|
6812
6390
|
const result = info.receipt?.result;
|
|
6813
6391
|
if (result === "SUCCESS") {
|
|
6814
|
-
console.log(
|
|
6815
|
-
`Transaction ${txHash} is solidified in block ${info.blockNumber}`
|
|
6816
|
-
);
|
|
6817
6392
|
return true;
|
|
6818
6393
|
}
|
|
6819
|
-
console.debug(`Transaction solidified but result is: ${result}`);
|
|
6820
6394
|
return false;
|
|
6821
|
-
} catch
|
|
6822
|
-
console.debug("Error checking solidified status:", error);
|
|
6395
|
+
} catch {
|
|
6823
6396
|
return false;
|
|
6824
6397
|
}
|
|
6825
6398
|
}
|
|
@@ -6830,7 +6403,8 @@ function ChainStrategyProvider({
|
|
|
6830
6403
|
tonWallet,
|
|
6831
6404
|
tronWallet,
|
|
6832
6405
|
tonClient,
|
|
6833
|
-
tonApiKey
|
|
6406
|
+
tonApiKey,
|
|
6407
|
+
tronApiKey
|
|
6834
6408
|
}) {
|
|
6835
6409
|
const evmStrategy = useMemo(
|
|
6836
6410
|
() => new EvmChainStrategy({
|
|
@@ -6873,7 +6447,8 @@ function ChainStrategyProvider({
|
|
|
6873
6447
|
connect: tronWallet.walletConnect.connect,
|
|
6874
6448
|
disconnect: tronWallet.walletConnect.disconnect,
|
|
6875
6449
|
signTransaction: tronWallet.walletConnect.signTransaction
|
|
6876
|
-
} : void 0
|
|
6450
|
+
} : void 0,
|
|
6451
|
+
apiKey: tronApiKey
|
|
6877
6452
|
}),
|
|
6878
6453
|
[
|
|
6879
6454
|
tronWallet.tronLink.address,
|
|
@@ -6881,7 +6456,8 @@ function ChainStrategyProvider({
|
|
|
6881
6456
|
tronWallet.tronLink.select,
|
|
6882
6457
|
tronWallet.tronLink.connect,
|
|
6883
6458
|
tronWallet.tronLink.disconnect,
|
|
6884
|
-
tronWallet.walletConnect
|
|
6459
|
+
tronWallet.walletConnect,
|
|
6460
|
+
tronApiKey
|
|
6885
6461
|
]
|
|
6886
6462
|
);
|
|
6887
6463
|
const chainRegistry = useMemo(
|
|
@@ -7066,6 +6642,7 @@ const SettingsModal = ({ isOpen, onClose }) => {
|
|
|
7066
6642
|
const TOKEN_ROW_HEIGHT = 52;
|
|
7067
6643
|
const TokenRow = ({
|
|
7068
6644
|
symbol,
|
|
6645
|
+
willChangeSrc,
|
|
7069
6646
|
name,
|
|
7070
6647
|
isSelected,
|
|
7071
6648
|
hasAnyWallet,
|
|
@@ -7078,7 +6655,7 @@ const TokenRow = ({
|
|
|
7078
6655
|
Button,
|
|
7079
6656
|
{
|
|
7080
6657
|
onClick: onPick,
|
|
7081
|
-
className: `w-full px-5 rounded-xs bg-transparent flex items-center justify-between gap-3 hover:bg-accent hover:scale-100 ${isSelected ? "border border-primary" : ""}`,
|
|
6658
|
+
className: `w-full px-5 rounded-xs bg-transparent flex items-center justify-between gap-3 hover:bg-accent hover:scale-100 ${isSelected ? "border border-primary" : ""} ${willChangeSrc ? "opacity-50 hover:opacity-100" : ""}`,
|
|
7082
6659
|
children: [
|
|
7083
6660
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
|
|
7084
6661
|
/* @__PURE__ */ jsx(
|
|
@@ -7314,7 +6891,7 @@ const TokenSelectModal = ({
|
|
|
7314
6891
|
"div",
|
|
7315
6892
|
{
|
|
7316
6893
|
style: { ...style, height: TOKEN_ROW_HEIGHT },
|
|
7317
|
-
className: "px-5 flex leading-4 text-base py-2 text-muted-foreground uppercase mt-
|
|
6894
|
+
className: "px-5 flex leading-4 text-base py-2 text-muted-foreground uppercase mt-3",
|
|
7318
6895
|
children: /* @__PURE__ */ jsx("p", { children: item.text })
|
|
7319
6896
|
}
|
|
7320
6897
|
);
|
|
@@ -7333,6 +6910,7 @@ const TokenSelectModal = ({
|
|
|
7333
6910
|
balance: bal,
|
|
7334
6911
|
usdValue: usd,
|
|
7335
6912
|
isBalanceLoading: balancesQuery.isLoading || balancesQuery.isFetching,
|
|
6913
|
+
willChangeSrc,
|
|
7336
6914
|
onPick: () => onPick(token.symbol, willChangeSrc)
|
|
7337
6915
|
}
|
|
7338
6916
|
) });
|
|
@@ -7357,67 +6935,74 @@ const TokenSelectModal = ({
|
|
|
7357
6935
|
},
|
|
7358
6936
|
[effectiveTab, virtualItems]
|
|
7359
6937
|
);
|
|
7360
|
-
return /* @__PURE__ */ jsx(Dialog, { open: isOpen, onOpenChange: (open) => !open && handleClose(), children: /* @__PURE__ */ jsxs(
|
|
7361
|
-
|
|
7362
|
-
|
|
7363
|
-
|
|
7364
|
-
|
|
7365
|
-
|
|
7366
|
-
|
|
7367
|
-
|
|
7368
|
-
|
|
7369
|
-
|
|
7370
|
-
|
|
7371
|
-
|
|
7372
|
-
|
|
7373
|
-
|
|
7374
|
-
|
|
7375
|
-
|
|
7376
|
-
|
|
7377
|
-
|
|
7378
|
-
|
|
7379
|
-
|
|
7380
|
-
|
|
7381
|
-
|
|
7382
|
-
|
|
7383
|
-
|
|
7384
|
-
|
|
7385
|
-
|
|
7386
|
-
|
|
7387
|
-
|
|
7388
|
-
|
|
7389
|
-
|
|
7390
|
-
|
|
7391
|
-
onClick: () => {
|
|
7392
|
-
setTab("all");
|
|
7393
|
-
setManualTabSwitch(true);
|
|
7394
|
-
},
|
|
7395
|
-
size: "sm",
|
|
7396
|
-
className: cn$2(
|
|
7397
|
-
"px-4 cursor-pointer",
|
|
7398
|
-
effectiveTab !== "all" && "bg-muted hover:bg-accent"
|
|
6938
|
+
return /* @__PURE__ */ jsx(Dialog, { open: isOpen, onOpenChange: (open) => !open && handleClose(), children: /* @__PURE__ */ jsxs(
|
|
6939
|
+
DialogContent,
|
|
6940
|
+
{
|
|
6941
|
+
className: "md:max-h-[90dvh] md:h-[90dvh] overflow-hidden flex flex-col fixed top-0 left-0 right-0 bottom-0 translate-x-0 translate-y-0 md:left-[50%] md:top-[50%] md:translate-x-[-50%] md:translate-y-[-50%] p-6 md:p-10 md:pt-8 rounded-none md:rounded-lg",
|
|
6942
|
+
closeButtonClassName: "right-6 md:right-10",
|
|
6943
|
+
children: [
|
|
6944
|
+
/* @__PURE__ */ jsx(DialogHeader, { className: "text-left pb-2", children: /* @__PURE__ */ jsx(DialogTitle, { className: "text-2xl leading-8", children: t2("bridge.selectToken") }) }),
|
|
6945
|
+
/* @__PURE__ */ jsx(
|
|
6946
|
+
SearchInput,
|
|
6947
|
+
{
|
|
6948
|
+
placeholder: t2("bridge.searchToken"),
|
|
6949
|
+
value: query,
|
|
6950
|
+
onChange: setQuery
|
|
6951
|
+
}
|
|
6952
|
+
),
|
|
6953
|
+
hasSourceWallet() && /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
|
|
6954
|
+
/* @__PURE__ */ jsx(
|
|
6955
|
+
Button,
|
|
6956
|
+
{
|
|
6957
|
+
variant: effectiveTab === "my" ? "default" : "ghost",
|
|
6958
|
+
onClick: () => {
|
|
6959
|
+
setTab("my");
|
|
6960
|
+
setManualTabSwitch(true);
|
|
6961
|
+
},
|
|
6962
|
+
size: "sm",
|
|
6963
|
+
className: cn$2(
|
|
6964
|
+
"px-4 h-9 cursor-pointer",
|
|
6965
|
+
effectiveTab !== "my" && "bg-muted hover:bg-accent"
|
|
6966
|
+
),
|
|
6967
|
+
children: t2("bridge.myTokens")
|
|
6968
|
+
}
|
|
7399
6969
|
),
|
|
7400
|
-
|
|
7401
|
-
|
|
7402
|
-
|
|
7403
|
-
|
|
7404
|
-
|
|
7405
|
-
|
|
7406
|
-
|
|
7407
|
-
|
|
7408
|
-
|
|
7409
|
-
|
|
7410
|
-
|
|
7411
|
-
|
|
7412
|
-
|
|
7413
|
-
|
|
7414
|
-
|
|
7415
|
-
|
|
7416
|
-
|
|
7417
|
-
}
|
|
7418
|
-
|
|
7419
|
-
|
|
7420
|
-
|
|
6970
|
+
/* @__PURE__ */ jsx(
|
|
6971
|
+
Button,
|
|
6972
|
+
{
|
|
6973
|
+
variant: effectiveTab === "all" ? "default" : "ghost",
|
|
6974
|
+
onClick: () => {
|
|
6975
|
+
setTab("all");
|
|
6976
|
+
setManualTabSwitch(true);
|
|
6977
|
+
},
|
|
6978
|
+
size: "sm",
|
|
6979
|
+
className: cn$2(
|
|
6980
|
+
"px-4 h-9 cursor-pointer",
|
|
6981
|
+
effectiveTab !== "all" && "bg-muted hover:bg-accent"
|
|
6982
|
+
),
|
|
6983
|
+
children: t2("bridge.allTokens")
|
|
6984
|
+
}
|
|
6985
|
+
)
|
|
6986
|
+
] }),
|
|
6987
|
+
/* @__PURE__ */ jsx("div", { id: "token-select-list", className: "flex-1 -mx-5 min-h-0", children: hasNoResults ? /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground px-12 py-2 h-28 flex items-center justify-center text-center", children: t2("bridge.tokenNotFound") }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
6988
|
+
effectiveTab === "my" && myTokens.length === 0 && /* @__PURE__ */ jsx("p", { className: "leading-4 px-5 text-base text-muted-foreground uppercase py-2", children: t2("bridge.noBalancesFound") }),
|
|
6989
|
+
/* @__PURE__ */ jsx(
|
|
6990
|
+
FixedSizeList,
|
|
6991
|
+
{
|
|
6992
|
+
height: listHeight,
|
|
6993
|
+
itemCount: virtualItems.length,
|
|
6994
|
+
itemSize: TOKEN_ROW_HEIGHT,
|
|
6995
|
+
width: "100%",
|
|
6996
|
+
itemKey,
|
|
6997
|
+
className: "[&::-webkit-scrollbar]:w-1 [&::-webkit-scrollbar-track]:bg-transparent [&::-webkit-scrollbar-thumb]:bg-muted-foreground/20 [&::-webkit-scrollbar-thumb]:rounded-full hover:[&::-webkit-scrollbar-thumb]:bg-muted-foreground/30",
|
|
6998
|
+
overscanCount: 5,
|
|
6999
|
+
children: VirtualRow
|
|
7000
|
+
}
|
|
7001
|
+
)
|
|
7002
|
+
] }) })
|
|
7003
|
+
]
|
|
7004
|
+
}
|
|
7005
|
+
) });
|
|
7421
7006
|
};
|
|
7422
7007
|
function useBridgeRefresh() {
|
|
7423
7008
|
const qc = useQueryClient();
|
|
@@ -26236,7 +25821,7 @@ class WalletConnectModal {
|
|
|
26236
25821
|
}
|
|
26237
25822
|
async initUi() {
|
|
26238
25823
|
if (typeof window !== "undefined") {
|
|
26239
|
-
await import("./index-
|
|
25824
|
+
await import("./index-yQkayDGz.js");
|
|
26240
25825
|
const modal = document.createElement("wcm-modal");
|
|
26241
25826
|
document.body.insertAdjacentElement("beforeend", modal);
|
|
26242
25827
|
OptionsCtrl.setIsUiLoaded(true);
|
|
@@ -26729,6 +26314,7 @@ const EvaaBridgeWithProviders = (props) => {
|
|
|
26729
26314
|
},
|
|
26730
26315
|
tonClient: props.tonClient,
|
|
26731
26316
|
tonApiKey: props.tonApiKey,
|
|
26317
|
+
tronApiKey: props.tronApiKey,
|
|
26732
26318
|
children: /* @__PURE__ */ jsx(EvaaBridgeContent, { ...props })
|
|
26733
26319
|
}
|
|
26734
26320
|
) });
|
|
@@ -26942,47 +26528,41 @@ async function pollUntilDelivered(args) {
|
|
|
26942
26528
|
}
|
|
26943
26529
|
}
|
|
26944
26530
|
export {
|
|
26945
|
-
|
|
26946
|
-
|
|
26947
|
-
|
|
26531
|
+
getQuotesByPriority as $,
|
|
26532
|
+
getQuoteDetails as A,
|
|
26533
|
+
getRouteDisplayName as B,
|
|
26948
26534
|
ConfigCtrl as C,
|
|
26949
|
-
|
|
26535
|
+
toLD as D,
|
|
26950
26536
|
EventsCtrl as E,
|
|
26951
|
-
|
|
26952
|
-
|
|
26953
|
-
|
|
26954
|
-
|
|
26955
|
-
|
|
26956
|
-
|
|
26957
|
-
|
|
26537
|
+
fromLD as F,
|
|
26538
|
+
buildAssetMatrix as G,
|
|
26539
|
+
listAssetsForSelect as H,
|
|
26540
|
+
resolveTokenOnChain as I,
|
|
26541
|
+
resolveTokenOnChainFromMatrix$2 as J,
|
|
26542
|
+
DEFAULT_SLIPPAGE_BPS as K,
|
|
26543
|
+
tonNorm as L,
|
|
26958
26544
|
ModalCtrl as M,
|
|
26959
|
-
|
|
26545
|
+
isZeroAddr as N,
|
|
26960
26546
|
OptionsCtrl as O,
|
|
26961
|
-
|
|
26962
|
-
|
|
26547
|
+
addrForApi as P,
|
|
26548
|
+
isNativeAddrEqual as Q,
|
|
26963
26549
|
RouterCtrl as R,
|
|
26964
|
-
|
|
26550
|
+
findNativeMeta as S,
|
|
26965
26551
|
ToastCtrl as T,
|
|
26966
|
-
|
|
26967
|
-
|
|
26968
|
-
|
|
26969
|
-
|
|
26970
|
-
|
|
26971
|
-
|
|
26972
|
-
|
|
26552
|
+
lookupTokenMeta as U,
|
|
26553
|
+
computeFeesUsdFromArray as V,
|
|
26554
|
+
sumFeeByTokenLD as W,
|
|
26555
|
+
normalizeTickerSymbol$1 as X,
|
|
26556
|
+
getChains as Y,
|
|
26557
|
+
getTokens as Z,
|
|
26558
|
+
getDestTokens as _,
|
|
26973
26559
|
ThemeCtrl as a,
|
|
26974
|
-
|
|
26975
|
-
|
|
26976
|
-
|
|
26977
|
-
|
|
26978
|
-
|
|
26979
|
-
|
|
26980
|
-
isNativeAddress as a6,
|
|
26981
|
-
getEvmBalances as a7,
|
|
26982
|
-
getTonBalances as a8,
|
|
26983
|
-
getTronBalances as a9,
|
|
26984
|
-
getDeliveryStatus as aa,
|
|
26985
|
-
pollUntilDelivered as ab,
|
|
26560
|
+
isNativeAddress as a0,
|
|
26561
|
+
getEvmBalances as a1,
|
|
26562
|
+
getTonBalances as a2,
|
|
26563
|
+
getTronBalances as a3,
|
|
26564
|
+
getDeliveryStatus as a4,
|
|
26565
|
+
pollUntilDelivered as a5,
|
|
26986
26566
|
ExplorerCtrl as b,
|
|
26987
26567
|
CoreUtil as c,
|
|
26988
26568
|
EvaaBridge as d,
|
|
@@ -27009,4 +26589,4 @@ export {
|
|
|
27009
26589
|
getQuoteFees as y,
|
|
27010
26590
|
calculateMinReceived as z
|
|
27011
26591
|
};
|
|
27012
|
-
//# sourceMappingURL=index-
|
|
26592
|
+
//# sourceMappingURL=index-D0OSdsmf.js.map
|