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