@rash2x/bridge-widget 0.6.92 → 0.6.94

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.
@@ -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", "willChangeDestinationChain": "Will change destination network", "willChangeBothChains": "Will change both networks", "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": "TxHash", "finalFee": "Final Fee", "route": "Route", "routeTooltip": "Route is the path your transfer takes between networks. The bridge is powered by LayerZero, and the specific path can affect the fee, slippage, and estimated time.", "estTime": "Est. Time", "estTimeTooltip": "Estimated time is the approximate completion time. It depends on the route and network load; actual time may vary.", "slippage": "Slippage", "slippageTooltip": "If the received amount goes below this tolerance, the transaction will be reverted.", "minimumReceived": "Minimum received", "totalFee": "Total Fee", "totalFeeTooltip": "Total fee is the estimated total cost of the transfer. It includes network gas and bridge/route fees. The final fee may vary slightly.", "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", "approving": "Approving Token", "approvingNote": "Step {{current}} of {{total}}: Confirm approval in wallet", "bridging": "Bridging", "processing": "Processing", "processingNote": "Up to 2 minutes", "completed": "Completed" } };
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", "routeTooltip": "Route is the path your transfer takes between networks. The bridge is powered by LayerZero, and the specific path can affect the fee, slippage, and estimated time.", "estTime": "Est. Time", "estTimeTooltip": "Estimated time is the approximate completion time. It depends on the route and network load; actual time may vary.", "slippage": "Slippage", "slippageTooltip": "If the received amount goes below this tolerance, the transaction will be reverted.", "minimumReceived": "Minimum received", "messageFee": "Message Fee", "messageFeeTooltip": "Message fee is the LayerZero cross-chain messaging cost paid to relay your transaction between networks.", "bridgeFee": "Bridge Fee", "bridgeFeeTooltip": "Bridge fee is the difference between the amount you send and the amount you receive, charged by the bridge protocol.", "totalFee": "Total Fee", "totalFeeTooltip": "Total fee is the estimated total cost of the transfer, including message and bridge fees. The final fee may vary slightly.", "gasEstimate": "Gas: {{gas}}", "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", "approving": "Approving Token", "approvingNote": "Step {{current}} of {{total}}: Confirm approval in wallet", "bridging": "Bridging", "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", "gasOnDestinationTooltip": "Adds the destination network's native token to cover fees for transactions after bridging. Increases the total fee.", "slippageTolerance": "Slippage tolerance", "slippageToleranceTooltip": "If the received amount goes below this tolerance, the transaction will be reverted.", "routePriority": "Route Priority", "routePriorityTooltip": "Select how the bridge chooses a route. Recommended balances options to find the best overall cost. Fastest prioritizes completion speed over everything 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": "Сменит исходную сеть", "willChangeDestinationChain": "Сменит целевую сеть", "willChangeBothChains": "Сменит обе сети", "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": "TxHash", "finalFee": "Итоговая комиссия", "route": "Маршрут", "routeTooltip": "Маршрут — это путь, по которому будет выполнен перевод. Мост работает на базе LayerZero, а конкретный путь передачи между сетями может влиять на комиссию, проскальзывание и время.", "estTime": "Время", "estTimeTooltip": "Среднее время — примерное время завершения перевода. Зависит от маршрута и нагрузки сети; фактическое время может отличаться.", "slippage": "Проскальзывание", "slippageTooltip": "Если получаемая сумма окажется ниже этого допуска, транзакция будет отклонена.", "minimumReceived": "Минимум к получению", "totalFee": "Общая комиссия", "totalFeeTooltip": "Общая комиссия за перевод. Включает оценку комиссии сети (газ) и комиссии моста/маршрута. Фактическая сумма может немного измениться.", "noRouteFound": "Маршрут не найден", "notEnoughGas": "Недостаточно газа", "pasteAddressToTransfer": "Укажите адрес получателя", "noRouteFoundForSettings": "Маршрут не найден для текущих настроек.", "tryAdjustSettings": "Попробуйте отключить Gas on Destination или измените сумму/сети.", "quoteError": "Ошибка котировки", "steps": { "sent": "Отправлено", "approving": "Одобрение токена", "approvingNote": "Шаг {{current}} из {{total}}: Подтвердите одобрение в кошельке", "bridging": "Перевод через мост", "processing": "Обработка", "processingNote": "До 2 минут", "completed": "Завершено" } };
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": "Маршрут", "routeTooltip": "Маршрут — это путь, по которому будет выполнен перевод. Мост работает на базе LayerZero, а конкретный путь передачи между сетями может влиять на комиссию, проскальзывание и время.", "estTime": "Время", "estTimeTooltip": "Среднее время — примерное время завершения перевода. Зависит от маршрута и нагрузки сети; фактическое время может отличаться.", "slippage": "Проскальзывание", "slippageTooltip": "Если получаемая сумма окажется ниже этого допуска, транзакция будет отклонена.", "minimumReceived": "Минимум к получению", "messageFee": "Комиссия сообщения", "messageFeeTooltip": "Комиссия сообщения — стоимость кросс-чейн передачи через LayerZero для ретрансляции транзакции между сетями.", "bridgeFee": "Комиссия моста", "bridgeFeeTooltip": "Комиссия моста — разница между отправленной и полученной суммой, взимаемая протоколом моста.", "totalFee": "Общая комиссия", "totalFeeTooltip": "Общая комиссия за перевод, включая комиссию сообщения и моста. Фактическая сумма может немного измениться.", "gasEstimate": "Газ: {{gas}}", "noRouteFound": "Маршрут не найден", "notEnoughGas": "Недостаточно газа", "pasteAddressToTransfer": "Укажите адрес получателя", "noRouteFoundForSettings": "Маршрут не найден для текущих настроек.", "tryAdjustSettings": "Попробуйте отключить Gas on Destination или измените сумму/сети.", "quoteError": "Ошибка котировки", "steps": { "sent": "Отправлено", "approving": "Одобрение токена", "approvingNote": "Шаг {{current}} из {{total}}: Подтвердите одобрение в кошельке", "bridging": "Перевод через мост", "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": "Газ на назначении", "gasOnDestinationTooltip": "Добавляет нативный токен целевой сети для оплаты комиссий за транзакции после бриджа. Увеличивает общую комиссию.", "slippageTolerance": "Толерантность к проскальзыванию", "slippageToleranceTooltip": "Если получаемая сумма окажется ниже этого допуска, транзакция будет отклонена.", "routePriority": "Приоритет маршрута", "routePriorityTooltip": "Выберите маршрут перевода. Рекомендуемый — подбирает самый выгодный вариант по общей стоимости. Быстрый — выбирает маршрут с приоритетом скорости, даже если это дороже.", "highSlippageWarning": "Высокое проскальзывание", "gasPresets": { "auto": "Авто", "none": "Нет", "medium": "Средний", "max": "Макс" }, "routePresets": { "fastest": "Быстрый", "cheapest": "Дешевый", "recommended": "Рекомендуемый" } };
@@ -2286,62 +2286,6 @@ function lookupTokenMeta(tokens, chains, chainKey, tokenAddr) {
2286
2286
  priceUsd: void 0
2287
2287
  };
2288
2288
  }
2289
- function computeFeesUsdFromArray(fees, tokens, chains) {
2290
- const emptyResult = {
2291
- usd: /* @__PURE__ */ new Map(),
2292
- human: /* @__PURE__ */ new Map(),
2293
- original: void 0
2294
- };
2295
- if (!fees?.length) return emptyResult;
2296
- let totalUsd = 0;
2297
- const byTypeUsd = /* @__PURE__ */ new Map();
2298
- const byTypeHuman = /* @__PURE__ */ new Map();
2299
- for (const f4 of fees) {
2300
- let usd = Number(f4.usd ?? 0);
2301
- let human = 0;
2302
- const amount = String(f4.amount ?? "0");
2303
- if (!usd) {
2304
- const { decimals, priceUsd } = lookupTokenMeta(
2305
- tokens,
2306
- chains,
2307
- f4.chainKey,
2308
- f4.token
2309
- );
2310
- human = fromLD(amount, decimals);
2311
- usd = (priceUsd ?? 0) * human;
2312
- }
2313
- totalUsd += usd;
2314
- const type = (f4.type ?? "other").toLowerCase();
2315
- byTypeUsd.set(type, (byTypeUsd.get(type) ?? 0) + usd);
2316
- const existing = byTypeHuman.get(type);
2317
- if (existing) {
2318
- existing.amount += human;
2319
- } else {
2320
- byTypeHuman.set(type, {
2321
- amount: human,
2322
- token: f4.token,
2323
- chainKey: f4.chainKey
2324
- });
2325
- }
2326
- }
2327
- byTypeUsd.set("total", totalUsd);
2328
- return {
2329
- usd: byTypeUsd,
2330
- human: byTypeHuman,
2331
- original: fees
2332
- };
2333
- }
2334
- function sumFeeByTokenLD(fees, dstTokenAddr, dstChainKey) {
2335
- if (!fees?.length || !dstTokenAddr || !dstChainKey) return "0";
2336
- let acc = 0n;
2337
- for (const f4 of fees) {
2338
- if (f4.chainKey !== dstChainKey) continue;
2339
- const same = dstChainKey === "ton" ? tonNorm(f4.token) === tonNorm(dstTokenAddr) : lower(f4.token) === lower(dstTokenAddr);
2340
- if (!same) continue;
2341
- acc += BigInt(f4.amount ?? "0");
2342
- }
2343
- return acc.toString();
2344
- }
2345
2289
  function getQuoteAmounts(quote, srcToken, dstToken) {
2346
2290
  if (!quote || !srcToken || !dstToken) {
2347
2291
  return {
@@ -2362,48 +2306,6 @@ function getQuoteAmounts(quote, srcToken, dstToken) {
2362
2306
  minReceivedHuman
2363
2307
  };
2364
2308
  }
2365
- function getQuoteFees(quote, tokens, chains, srcToken, dstToken) {
2366
- if (!quote || !tokens || !chains) {
2367
- return {
2368
- fees: { usd: /* @__PURE__ */ new Map(), original: /* @__PURE__ */ new Map(), formatted: /* @__PURE__ */ new Map() },
2369
- inSrcToken: void 0,
2370
- inDstToken: void 0
2371
- };
2372
- }
2373
- const feeData = computeFeesUsdFromArray(quote.fees, tokens, chains);
2374
- let inSrcToken = void 0;
2375
- let inDstToken = void 0;
2376
- if (srcToken && quote.srcChainKey) {
2377
- const feeInSrcLD = sumFeeByTokenLD(
2378
- quote.fees,
2379
- srcToken.address,
2380
- quote.srcChainKey
2381
- );
2382
- const feeInSrcHuman = fromLD(feeInSrcLD, srcToken.decimals);
2383
- if (feeInSrcHuman > 0) {
2384
- inSrcToken = Number(truncateToDecimals(feeInSrcHuman, 8));
2385
- } else if ((feeData.usd.get("total") || 0) > 0 && srcToken.price?.usd) {
2386
- const feeInSrcApprox = (feeData.usd.get("total") || 0) / srcToken.price.usd;
2387
- inSrcToken = Number(truncateToDecimals(feeInSrcApprox, 8));
2388
- }
2389
- }
2390
- if (dstToken && quote.dstChainKey) {
2391
- const feeInDstLD = sumFeeByTokenLD(
2392
- quote.fees,
2393
- dstToken.address,
2394
- quote.dstChainKey
2395
- );
2396
- const feeInDstHuman = fromLD(feeInDstLD, dstToken.decimals);
2397
- if (feeInDstHuman > 0) {
2398
- inDstToken = Number(truncateToDecimals(feeInDstHuman, 8));
2399
- }
2400
- }
2401
- return {
2402
- fees: feeData,
2403
- inSrcToken,
2404
- inDstToken
2405
- };
2406
- }
2407
2309
  function calculateMinReceived(quote, slippageBps, dstToken) {
2408
2310
  if (!quote || !dstToken) return 0;
2409
2311
  const dstAmountLD = BigInt(quote.dstAmount);
@@ -2412,7 +2314,7 @@ function calculateMinReceived(quote, slippageBps, dstToken) {
2412
2314
  }
2413
2315
  function getQuoteDetails(quote, srcToken, dstToken, tokens, chains, slippageBps) {
2414
2316
  const amounts = getQuoteAmounts(quote, srcToken, dstToken);
2415
- const fees = getQuoteFees(quote, tokens, chains, srcToken, dstToken);
2317
+ const fees = computeFeeBreakdownUsd(quote, srcToken, tokens, chains);
2416
2318
  const minimumReceived = calculateMinReceived(quote, slippageBps, dstToken);
2417
2319
  return {
2418
2320
  inputAmount: amounts.inputHuman,
@@ -2432,6 +2334,28 @@ function getRouteDisplayName(route) {
2432
2334
  if (routeLower.includes("v2")) return "Stargate V2";
2433
2335
  return route.split(/[/\-_]/).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(" ");
2434
2336
  }
2337
+ function computeFeeBreakdownUsd(quote, srcToken, tokens, chains) {
2338
+ const empty = { messageFeeUsd: 0, bridgeFeeUsd: 0, totalFeeUsd: 0 };
2339
+ if (!quote || !srcToken) return empty;
2340
+ let messageFeeUsd = 0;
2341
+ const messageFees = quote.fees.filter((f4) => f4.type === "message");
2342
+ for (const f4 of messageFees) {
2343
+ const { decimals, priceUsd } = lookupTokenMeta(tokens, chains, f4.chainKey, f4.token);
2344
+ const human = fromLD(f4.amount || "0", decimals);
2345
+ messageFeeUsd += human * (priceUsd ?? 0);
2346
+ }
2347
+ let bridgeFeeUsd = 0;
2348
+ if (srcToken.price?.usd) {
2349
+ const srcHuman = fromLD(quote.srcAmount, srcToken.decimals);
2350
+ const dstHuman = fromLD(quote.dstAmount, srcToken.decimals);
2351
+ const diff = srcHuman - dstHuman;
2352
+ if (diff > 0) {
2353
+ bridgeFeeUsd = diff * srcToken.price.usd;
2354
+ }
2355
+ }
2356
+ const totalFeeUsd = messageFeeUsd + bridgeFeeUsd;
2357
+ return { messageFeeUsd, bridgeFeeUsd, totalFeeUsd };
2358
+ }
2435
2359
  async function addNetworkFeesToQuote(quote, chainRegistry, chains) {
2436
2360
  if (!quote || !chains) {
2437
2361
  return quote;
@@ -2937,79 +2861,18 @@ const TokenSymbol = ({
2937
2861
  const src2 = `${BASE_URL}/${normalizedSymbol}.svg`;
2938
2862
  return /* @__PURE__ */ jsxRuntime.jsx("img", { src: src2, alt: alt ?? symbol, className });
2939
2863
  };
2940
- function useGasEstimate(amountNum) {
2941
- const { fromChain } = useChainsStore();
2942
- const { selectedAssetSymbol } = useTokensStore();
2943
- const { srcAddress } = useAddresses();
2944
- const { balances, isLoading: balancesLoading } = useBalances(
2945
- fromChain?.chainKey,
2946
- srcAddress
2947
- );
2864
+ function useFeeBreakdown() {
2948
2865
  const { quote } = useBridgeQuoteStore();
2949
- const balancesKnown = !balancesLoading;
2950
- const chainKey = fromChain?.chainKey;
2951
- const nativeCurrencySymbol = fromChain?.nativeCurrency?.symbol;
2952
- const nativeCurrencyAddress = fromChain?.nativeCurrency?.address;
2953
- const nativeCurrencyDecimals = fromChain?.nativeCurrency?.decimals;
2954
- const quoteFees = quote?.fees;
2955
- const quoteSrcChainKey = quote?.srcChainKey;
2956
- const nativeBalanceValue = nativeCurrencySymbol ? Number(balances[nativeCurrencySymbol.toUpperCase()]?.balance ?? 0) : 0;
2957
- const result = react.useMemo(() => {
2958
- if (!chainKey || !nativeCurrencySymbol) {
2959
- return {
2960
- nativeSym: "",
2961
- nativeBalance: 0,
2962
- requiredNative: 0,
2963
- balancesKnown,
2964
- isNativeSelected: false,
2965
- hasEnoughGas: true
2966
- };
2967
- }
2968
- const nativeSym = nativeCurrencySymbol.toUpperCase();
2969
- const nativeBalance = nativeBalanceValue;
2970
- const isNativeSelected = nativeSym === (selectedAssetSymbol || "").toUpperCase();
2971
- let requiredNative = 0;
2972
- let quoteFeesAvailable = false;
2973
- if (quoteFees && quoteSrcChainKey === chainKey) {
2974
- const fees = quoteFees;
2975
- const feesInNative = fees.filter(
2976
- (f4) => f4.chainKey === chainKey && f4.token === nativeCurrencyAddress
2977
- ).reduce(
2978
- (sum, f4) => sum + BigInt(f4.amount || "0"),
2979
- 0n
2980
- );
2981
- const decimals = nativeCurrencyDecimals || 18;
2982
- requiredNative = Number(feesInNative) / Math.pow(10, decimals);
2983
- quoteFeesAvailable = true;
2984
- }
2985
- let hasEnoughGas = true;
2986
- if (isNativeSelected) {
2987
- hasEnoughGas = nativeBalance - (amountNum ?? 0) >= requiredNative;
2988
- } else {
2989
- hasEnoughGas = nativeBalance >= requiredNative;
2990
- }
2991
- const shouldCheckGas = balancesKnown && quoteFeesAvailable;
2992
- return {
2993
- nativeSym,
2994
- nativeBalance,
2995
- requiredNative,
2996
- balancesKnown,
2997
- isNativeSelected,
2998
- hasEnoughGas: shouldCheckGas ? hasEnoughGas : true
2999
- };
3000
- }, [
3001
- chainKey,
3002
- nativeCurrencySymbol,
3003
- nativeCurrencyAddress,
3004
- nativeCurrencyDecimals,
3005
- selectedAssetSymbol,
3006
- quoteFees,
3007
- quoteSrcChainKey,
3008
- amountNum,
3009
- balancesKnown,
3010
- nativeBalanceValue
3011
- ]);
3012
- return result;
2866
+ const { tokens, selectedAssetSymbol, assetMatrix } = useTokensStore();
2867
+ const { fromChain, chains } = useChainsStore();
2868
+ return react.useMemo(() => {
2869
+ const srcToken = resolveTokenOnChainFromMatrix$1(
2870
+ assetMatrix,
2871
+ selectedAssetSymbol,
2872
+ fromChain?.chainKey
2873
+ );
2874
+ return computeFeeBreakdownUsd(quote, srcToken, tokens, chains);
2875
+ }, [quote, tokens, chains, selectedAssetSymbol, assetMatrix, fromChain]);
3013
2876
  }
3014
2877
  function useBridgeExternalData(options) {
3015
2878
  const selectedAssetSymbol = useTokensStore(
@@ -3149,7 +3012,7 @@ const Details = () => {
3149
3012
  const { selectedAssetSymbol } = useTokensStore();
3150
3013
  const { quote, status } = useBridgeQuoteStore();
3151
3014
  const { slippageBps } = useSettingsStore();
3152
- const gas = useGasEstimate();
3015
+ const fees = useFeeBreakdown();
3153
3016
  const bridgeData = useBridgeExternalData();
3154
3017
  const symbol = (selectedAssetSymbol ?? bridgeData.dstToken?.symbol ?? "—").toUpperCase();
3155
3018
  const isLoading = status === "loading";
@@ -3158,7 +3021,9 @@ const Details = () => {
3158
3021
  1,
3159
3022
  Math.round(bridgeData.quoteDetails?.etaSeconds / 60)
3160
3023
  )}m` : "—";
3161
- const totalFeeDisplay = !quote ? "—" : gas.requiredNative > 0 ? `${truncateToDecimals(gas.requiredNative, 6)} ${gas.nativeSym}` : "—";
3024
+ const messageFeeDisplay = !quote ? "—" : formatUsd(fees.messageFeeUsd);
3025
+ const bridgeFeeDisplay = !quote ? "—" : formatUsd(fees.bridgeFeeUsd);
3026
+ const totalFeeDisplay = !quote ? "—" : formatUsd(fees.totalFeeUsd);
3162
3027
  const currentSlippageText = !quote ? "—" : formatPercentage(slippageBps);
3163
3028
  const routeText = getRouteDisplayName(quote?.route);
3164
3029
  return /* @__PURE__ */ jsxRuntime.jsx(accordion.Accordion, { type: "single", collapsible: true, className: "w-full border-none", children: /* @__PURE__ */ jsxRuntime.jsxs(accordion.AccordionItem, { value: "item-1", className: "bg-muted rounded-sm", children: [
@@ -3199,22 +3064,30 @@ const Details = () => {
3199
3064
  value: currentSlippageText
3200
3065
  }
3201
3066
  ),
3067
+ /* @__PURE__ */ jsxRuntime.jsx(
3068
+ DetailsRow,
3069
+ {
3070
+ label: t2("transaction.messageFee"),
3071
+ tooltip: t2("transaction.messageFeeTooltip"),
3072
+ value: messageFeeDisplay,
3073
+ isLoading
3074
+ }
3075
+ ),
3076
+ /* @__PURE__ */ jsxRuntime.jsx(
3077
+ DetailsRow,
3078
+ {
3079
+ label: t2("transaction.bridgeFee"),
3080
+ tooltip: t2("transaction.bridgeFeeTooltip"),
3081
+ value: bridgeFeeDisplay,
3082
+ isLoading
3083
+ }
3084
+ ),
3202
3085
  /* @__PURE__ */ jsxRuntime.jsx(
3203
3086
  DetailsRow,
3204
3087
  {
3205
3088
  label: t2("transaction.totalFee"),
3206
3089
  tooltip: t2("transaction.totalFeeTooltip"),
3207
- value: /* @__PURE__ */ jsxRuntime.jsxs("strong", { className: "inline-flex items-center gap-1", children: [
3208
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: totalFeeDisplay }),
3209
- /* @__PURE__ */ jsxRuntime.jsx(
3210
- TokenSymbol,
3211
- {
3212
- symbol: gas.nativeSym,
3213
- className: "w-4 h-4",
3214
- alt: "token"
3215
- }
3216
- )
3217
- ] }),
3090
+ value: /* @__PURE__ */ jsxRuntime.jsx("strong", { children: totalFeeDisplay }),
3218
3091
  isLoading
3219
3092
  }
3220
3093
  )
@@ -3608,6 +3481,93 @@ async function reportBridgeTransaction(params, config) {
3608
3481
  };
3609
3482
  }
3610
3483
  }
3484
+ function useGasEstimate(amountNum) {
3485
+ const { fromChain } = useChainsStore();
3486
+ const { selectedAssetSymbol } = useTokensStore();
3487
+ const { srcAddress } = useAddresses();
3488
+ const { balances, isLoading: balancesLoading } = useBalances(
3489
+ fromChain?.chainKey,
3490
+ srcAddress
3491
+ );
3492
+ const { quote } = useBridgeQuoteStore();
3493
+ const balancesKnown = !balancesLoading;
3494
+ const chainKey = fromChain?.chainKey;
3495
+ const nativeCurrencySymbol = fromChain?.nativeCurrency?.symbol;
3496
+ const nativeCurrencyAddress = fromChain?.nativeCurrency?.address;
3497
+ const nativeCurrencyDecimals = fromChain?.nativeCurrency?.decimals;
3498
+ const quoteFees = quote?.fees;
3499
+ const quoteSrcChainKey = quote?.srcChainKey;
3500
+ const nativeBalanceValue = nativeCurrencySymbol ? Number(balances[nativeCurrencySymbol.toUpperCase()]?.balance ?? 0) : 0;
3501
+ const result = react.useMemo(() => {
3502
+ if (!chainKey || !nativeCurrencySymbol) {
3503
+ return {
3504
+ nativeSym: "",
3505
+ nativeBalance: 0,
3506
+ requiredNative: 0,
3507
+ gasOnlyNative: 0,
3508
+ gasDisplayText: "",
3509
+ balancesKnown,
3510
+ isNativeSelected: false,
3511
+ hasEnoughGas: true
3512
+ };
3513
+ }
3514
+ const nativeSym = nativeCurrencySymbol.toUpperCase();
3515
+ const nativeBalance = nativeBalanceValue;
3516
+ const isNativeSelected = nativeSym === (selectedAssetSymbol || "").toUpperCase();
3517
+ let requiredNative = 0;
3518
+ let quoteFeesAvailable = false;
3519
+ let gasOnlyNative = 0;
3520
+ if (quoteFees && quoteSrcChainKey === chainKey) {
3521
+ const fees = quoteFees;
3522
+ const feesInNative = fees.filter(
3523
+ (f4) => f4.chainKey === chainKey && f4.token === nativeCurrencyAddress
3524
+ ).reduce(
3525
+ (sum, f4) => sum + BigInt(f4.amount || "0"),
3526
+ 0n
3527
+ );
3528
+ const decimals = nativeCurrencyDecimals || 18;
3529
+ requiredNative = Number(feesInNative) / Math.pow(10, decimals);
3530
+ const networkFeesInNative = fees.filter(
3531
+ (f4) => f4.chainKey === chainKey && f4.token === nativeCurrencyAddress && f4.type === "network"
3532
+ ).reduce(
3533
+ (sum, f4) => sum + BigInt(f4.amount || "0"),
3534
+ 0n
3535
+ );
3536
+ gasOnlyNative = Number(networkFeesInNative) / Math.pow(10, decimals);
3537
+ quoteFeesAvailable = true;
3538
+ }
3539
+ let hasEnoughGas = true;
3540
+ if (isNativeSelected) {
3541
+ hasEnoughGas = nativeBalance - (amountNum ?? 0) >= requiredNative;
3542
+ } else {
3543
+ hasEnoughGas = nativeBalance >= requiredNative;
3544
+ }
3545
+ const shouldCheckGas = balancesKnown && quoteFeesAvailable;
3546
+ const gasDisplayText = gasOnlyNative > 0 ? `~${gasOnlyNative.toFixed(6).replace(/0+$/, "").replace(/\.$/, "")} ${nativeSym}` : "";
3547
+ return {
3548
+ nativeSym,
3549
+ nativeBalance,
3550
+ requiredNative,
3551
+ gasOnlyNative,
3552
+ gasDisplayText,
3553
+ balancesKnown,
3554
+ isNativeSelected,
3555
+ hasEnoughGas: shouldCheckGas ? hasEnoughGas : true
3556
+ };
3557
+ }, [
3558
+ chainKey,
3559
+ nativeCurrencySymbol,
3560
+ nativeCurrencyAddress,
3561
+ nativeCurrencyDecimals,
3562
+ selectedAssetSymbol,
3563
+ quoteFees,
3564
+ quoteSrcChainKey,
3565
+ amountNum,
3566
+ balancesKnown,
3567
+ nativeBalanceValue
3568
+ ]);
3569
+ return result;
3570
+ }
3611
3571
  function useBridgeTransaction() {
3612
3572
  const { quote } = useBridgeQuoteStore();
3613
3573
  const { chainRegistry } = useChainStrategies();
@@ -4138,7 +4098,8 @@ const MainButton = ({
4138
4098
  className: "w-full",
4139
4099
  children: label
4140
4100
  }
4141
- )
4101
+ ),
4102
+ gas.gasDisplayText && quote && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground text-center", children: t2("transaction.gasEstimate", { gas: gas.gasDisplayText }) })
4142
4103
  ] });
4143
4104
  };
4144
4105
  const WalletModalButton = (props) => {
@@ -5306,6 +5267,15 @@ class EvmChainStrategy {
5306
5267
  throw toChainStrategyError(error, "evm", "transaction");
5307
5268
  }
5308
5269
  }
5270
+ async getNextNonce() {
5271
+ if (!this.publicClient || !this.config.evmAddress) {
5272
+ throw new WalletNotConnectedError("evm");
5273
+ }
5274
+ return await this.publicClient.getTransactionCount({
5275
+ address: this.config.evmAddress,
5276
+ blockTag: "pending"
5277
+ });
5278
+ }
5309
5279
  async executeTransaction(step) {
5310
5280
  const walletClient = this.walletClient;
5311
5281
  if (!walletClient) {
@@ -5318,12 +5288,14 @@ class EvmChainStrategy {
5318
5288
  );
5319
5289
  }
5320
5290
  const tx = step.transaction;
5291
+ const nonce = await this.getNextNonce();
5321
5292
  const hash = await walletClient.sendTransaction({
5322
5293
  to: tx.to,
5323
5294
  data: tx.data,
5324
5295
  account: tx.from || this.config.evmAddress,
5325
5296
  value: tx.value ? BigInt(tx.value) : void 0,
5326
- chain: walletClient.chain
5297
+ chain: walletClient.chain,
5298
+ nonce
5327
5299
  });
5328
5300
  return hash;
5329
5301
  }
@@ -5365,13 +5337,15 @@ class EvmChainStrategy {
5365
5337
  });
5366
5338
  if (currentAllowance > 0n) {
5367
5339
  try {
5340
+ const resetNonce = await this.getNextNonce();
5368
5341
  const resetHash = await walletClient.writeContract({
5369
5342
  address: tokenAddress,
5370
5343
  abi: ERC20_ABI,
5371
5344
  functionName: "approve",
5372
5345
  args: [spenderAddress, 0n],
5373
5346
  account: this.config.evmAddress,
5374
- chain: walletClient.chain
5347
+ chain: walletClient.chain,
5348
+ nonce: resetNonce
5375
5349
  });
5376
5350
  await publicClient.waitForTransactionReceipt({
5377
5351
  hash: resetHash
@@ -5388,13 +5362,15 @@ class EvmChainStrategy {
5388
5362
  console.log("USDT allowance is 0, no reset needed");
5389
5363
  }
5390
5364
  try {
5365
+ const approveNonce = await this.getNextNonce();
5391
5366
  const approveHash = await walletClient.writeContract({
5392
5367
  address: tokenAddress,
5393
5368
  abi: ERC20_ABI,
5394
5369
  functionName: "approve",
5395
5370
  args: [spenderAddress, amount],
5396
5371
  account: this.config.evmAddress,
5397
- chain: walletClient.chain
5372
+ chain: walletClient.chain,
5373
+ nonce: approveNonce
5398
5374
  });
5399
5375
  return approveHash;
5400
5376
  } catch (approveError) {
@@ -6259,6 +6235,13 @@ class TronChainStrategy {
6259
6235
  } else {
6260
6236
  signedTx = await tronWeb.trx.sign(unsignedTx);
6261
6237
  }
6238
+ const signatures = signedTx.signature;
6239
+ if (!Array.isArray(signatures) || signatures.length === 0) {
6240
+ throw new TransactionFailedError(
6241
+ "tron",
6242
+ "Wallet returned unsigned transaction"
6243
+ );
6244
+ }
6262
6245
  const sent = await tronWeb.trx.sendRawTransaction(signedTx);
6263
6246
  if (!sent?.result || !sent?.txid) {
6264
6247
  throw new TransactionFailedError(
@@ -25761,7 +25744,7 @@ class WalletConnectModal {
25761
25744
  }
25762
25745
  async initUi() {
25763
25746
  if (typeof window !== "undefined") {
25764
- await Promise.resolve().then(() => require("./index-B8oK1IHg.cjs"));
25747
+ await Promise.resolve().then(() => require("./index-Dda0d9GW.cjs"));
25765
25748
  const modal = document.createElement("wcm-modal");
25766
25749
  document.body.insertAdjacentElement("beforeend", modal);
25767
25750
  OptionsCtrl.setIsUiLoaded(true);
@@ -25807,6 +25790,59 @@ const useThemeStore = zustand.create((set2) => ({
25807
25790
  }));
25808
25791
  const TRON_MAINNET_CHAIN_ID = "tron:0x2b6653dc";
25809
25792
  const CONNECTION_TIMEOUT = 6e4;
25793
+ function isRecord(value) {
25794
+ return typeof value === "object" && value !== null;
25795
+ }
25796
+ function hasValidSignature(transaction2) {
25797
+ if (!isRecord(transaction2)) return false;
25798
+ const signature = transaction2.signature;
25799
+ return Array.isArray(signature) && signature.length > 0 && signature.every((item) => typeof item === "string" && item.length > 0);
25800
+ }
25801
+ function normalizeSignature(signature) {
25802
+ return signature.replace(/^0x/i, "");
25803
+ }
25804
+ function toSignedTransaction(result, unsignedTx) {
25805
+ if (hasValidSignature(result)) {
25806
+ return result;
25807
+ }
25808
+ if (isRecord(result)) {
25809
+ const nestedTx = result.transaction;
25810
+ if (hasValidSignature(nestedTx)) {
25811
+ return nestedTx;
25812
+ }
25813
+ const nestedSignedTx = result.signedTransaction;
25814
+ if (hasValidSignature(nestedSignedTx)) {
25815
+ return nestedSignedTx;
25816
+ }
25817
+ const signature = result.signature;
25818
+ if (typeof signature === "string" && signature.length > 0) {
25819
+ return {
25820
+ ...unsignedTx,
25821
+ signature: [normalizeSignature(signature)]
25822
+ };
25823
+ }
25824
+ if (Array.isArray(signature) && signature.length > 0 && signature.every((item) => typeof item === "string" && item.length > 0)) {
25825
+ return {
25826
+ ...unsignedTx,
25827
+ signature: signature.map((item) => normalizeSignature(item))
25828
+ };
25829
+ }
25830
+ }
25831
+ if (typeof result === "string" && result.length > 0) {
25832
+ return {
25833
+ ...unsignedTx,
25834
+ signature: [normalizeSignature(result)]
25835
+ };
25836
+ }
25837
+ return null;
25838
+ }
25839
+ function isUserRejectedError(error) {
25840
+ if (isRecord(error) && typeof error.code === "number" && error.code === 4001) {
25841
+ return true;
25842
+ }
25843
+ const msg = error instanceof Error ? error.message.toLowerCase() : "";
25844
+ return msg.includes("user rejected") || msg.includes("rejected by user");
25845
+ }
25810
25846
  function useTronWalletConnect(projectId) {
25811
25847
  const { address, isConnected, isConnecting } = useTronWalletConnectStore();
25812
25848
  const { setAddress, setActions, reset } = useTronWalletConnectStore();
@@ -25987,11 +26023,41 @@ function useTronWalletConnect(projectId) {
25987
26023
  throw new Error("WalletConnect not connected");
25988
26024
  }
25989
26025
  try {
25990
- const result = await providerRef.current.request({
25991
- method: "tron_signTransaction",
25992
- params: [transaction2]
25993
- });
25994
- return result;
26026
+ const requestVariants = [
26027
+ [transaction2],
26028
+ [transaction2, address],
26029
+ [{ transaction: transaction2, address }],
26030
+ { transaction: transaction2, address }
26031
+ ];
26032
+ let lastResponse;
26033
+ let lastError;
26034
+ for (const params of requestVariants) {
26035
+ try {
26036
+ const result = await providerRef.current.request(
26037
+ {
26038
+ method: "tron_signTransaction",
26039
+ params
26040
+ },
26041
+ TRON_MAINNET_CHAIN_ID
26042
+ );
26043
+ lastResponse = result;
26044
+ const signedTx = toSignedTransaction(result, transaction2);
26045
+ if (signedTx) {
26046
+ return signedTx;
26047
+ }
26048
+ } catch (error) {
26049
+ if (isUserRejectedError(error)) {
26050
+ throw error;
26051
+ }
26052
+ lastError = error;
26053
+ }
26054
+ }
26055
+ if (lastError) {
26056
+ throw lastError;
26057
+ }
26058
+ throw new Error(
26059
+ `WalletConnect returned unsigned transaction: ${JSON.stringify(lastResponse)}`
26060
+ );
25995
26061
  } catch (error) {
25996
26062
  console.error("TRON WalletConnect transaction signing failed:", error);
25997
26063
  throw error;
@@ -26470,7 +26536,7 @@ exports.addNetworkFeesToQuote = addNetworkFeesToQuote;
26470
26536
  exports.addrForApi = addrForApi;
26471
26537
  exports.buildAssetMatrix = buildAssetMatrix;
26472
26538
  exports.calculateMinReceived = calculateMinReceived;
26473
- exports.computeFeesUsdFromArray = computeFeesUsdFromArray;
26539
+ exports.computeFeeBreakdownUsd = computeFeeBreakdownUsd;
26474
26540
  exports.findNativeMeta = findNativeMeta;
26475
26541
  exports.formatAddress = formatAddress;
26476
26542
  exports.formatBalance = formatBalance;
@@ -26486,7 +26552,6 @@ exports.getDestTokens = getDestTokens;
26486
26552
  exports.getEvmBalances = getEvmBalances;
26487
26553
  exports.getQuoteAmounts = getQuoteAmounts;
26488
26554
  exports.getQuoteDetails = getQuoteDetails;
26489
- exports.getQuoteFees = getQuoteFees;
26490
26555
  exports.getQuotesByPriority = getQuotesByPriority;
26491
26556
  exports.getRouteDisplayName = getRouteDisplayName;
26492
26557
  exports.getTokens = getTokens;
@@ -26502,7 +26567,6 @@ exports.pollUntilDelivered = pollUntilDelivered;
26502
26567
  exports.reportBridgeTransaction = reportBridgeTransaction;
26503
26568
  exports.resolveTokenOnChain = resolveTokenOnChain;
26504
26569
  exports.resolveTokenOnChainFromMatrix = resolveTokenOnChainFromMatrix$1;
26505
- exports.sumFeeByTokenLD = sumFeeByTokenLD;
26506
26570
  exports.toLD = toLD;
26507
26571
  exports.tonNorm = tonNorm;
26508
26572
  exports.truncateToDecimals = truncateToDecimals;
@@ -26515,4 +26579,4 @@ exports.useSettingsStore = useSettingsStore;
26515
26579
  exports.useSwapModel = useSwapModel;
26516
26580
  exports.useTokensStore = useTokensStore;
26517
26581
  exports.useTransactionStore = useTransactionStore;
26518
- //# sourceMappingURL=index-p9NMtKHb.cjs.map
26582
+ //# sourceMappingURL=index-Db2959hv.cjs.map