@rash2x/bridge-widget 0.1.13 → 0.1.16
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 +481 -583
- package/dist/evaa-bridge.cjs.map +1 -1
- package/dist/evaa-bridge.mjs +482 -584
- package/dist/evaa-bridge.mjs.map +1 -1
- package/dist/index.d.ts +2 -10
- package/package.json +1 -1
package/dist/evaa-bridge.mjs
CHANGED
|
@@ -2,22 +2,22 @@ var __defProp = Object.defineProperty;
|
|
|
2
2
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
3
|
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
4
4
|
import { jsx, jsxs, Fragment } from "react/jsx-runtime";
|
|
5
|
-
import require$$0, { useEffect, useState, useCallback, useMemo, createContext, useContext, memo, forwardRef
|
|
5
|
+
import require$$0, { useEffect, useState, useCallback, useMemo, createContext, useContext, memo, forwardRef } from "react";
|
|
6
6
|
import { initReactI18next, useTranslation, I18nextProvider } from "react-i18next";
|
|
7
7
|
import i18n, { t } from "i18next";
|
|
8
8
|
import { create as create$1 } from "zustand";
|
|
9
9
|
import { Button } from "@/components/ui/button";
|
|
10
10
|
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription } from "@/components/ui/dialog";
|
|
11
|
+
import { Badge } from "@/components/ui/badge";
|
|
11
12
|
import { Tooltip, TooltipTrigger, TooltipContent } from "@/components/ui/tooltip";
|
|
12
13
|
import { cn } from "@/lib/utils";
|
|
13
|
-
import {
|
|
14
|
+
import { Skeleton } from "@/components/ui/skeleton";
|
|
14
15
|
import { useAccount, useConnect, useDisconnect, useWalletClient, usePublicClient } from "wagmi";
|
|
15
16
|
import { useWallet } from "@tronweb3/tronwallet-adapter-react-hooks";
|
|
16
17
|
import { useTonAddress, useTonConnectUI } from "@tonconnect/ui-react";
|
|
17
18
|
import { useQuery, useQueryClient } from "@tanstack/react-query";
|
|
18
19
|
import { Address, beginCell as beginCell$1, storeMessage, loadMessage, Cell } from "@ton/core";
|
|
19
|
-
import {
|
|
20
|
-
import { Skeleton } from "@/components/ui/skeleton";
|
|
20
|
+
import { Input } from "@/components/ui/input";
|
|
21
21
|
import { CardHeader, CardTitle, CardAction, Card, CardContent, CardFooter } from "@/components/ui/card";
|
|
22
22
|
import { Switch } from "@/components/ui/switch";
|
|
23
23
|
import { X } from "lucide-react";
|
|
@@ -30,7 +30,7 @@ import { TonClient, Address as Address$1, beginCell } from "@ton/ton";
|
|
|
30
30
|
import { TronLinkAdapterName } from "@tronweb3/tronwallet-adapters";
|
|
31
31
|
const common$1 = { "connecting": "Connecting…", "initializing": "Initializing...", "loading": "Loading...", "paste": "paste", "close": "Close", "zeroPlaceholder": "0", "nativeToken": "Native Token" };
|
|
32
32
|
const wallets$1 = { "addTonWallet": "Add TON wallet", "addEvmWallet": "Add EVM wallet", "connectTonWallet": "Connect TON wallet", "connectEvmWallet": "Connect EVM wallet", "initializingMetamask": "Initializing MetaMask SDK...", "initializingTronlink": "Initializing TronLink...", "failedToConnectTon": "Failed to connect to TON wallet", "failedToDisconnect": "Failed to disconnect", "metamaskConnectionError": "MetaMask connection error", "failedToConnectMetamask": "Failed to connect to MetaMask", "failedToDisconnectMetamask": "Failed to disconnect from MetaMask", "selectWallet": "Select Wallet", "tonWallets": "TON", "evmWallets": "EVM", "tronWallets": "TRON", "tonKeeper": "TonKeeper", "metaMask": "WalletConnect", "tronLink": "TronLink", "addTronWallet": "Add Tron wallet", "comingSoon": "Coming Soon", "connected": "CONNECTED", "disconnect": "Disconnect", "chooseWallet": "Choose wallet", "oneWalletPerEnv": "You can only connect one wallet per environment.", "connect": "Connect", "connectTronWallet": "Connect Tron wallet", "connectWallet": "Connect wallet" };
|
|
33
|
-
const bridge$1 = { "sourceNetwork": "Source network", "destinationNetwork": "Destination network", "selectToken": "Select token", "selectNetwork": "Select network", "searchToken": "Search token", "searchDestinationChain": "Search destination chain", "myTokens": "My tokens", "allTokens": "All tokens", "willChangeSourceChain": "Will Change Source Chain", "noBalancesFound": "No balances found.", "noResults": "No results", "sendToAnotherAddress": "Send to another address", "youWillReceive": "You will receive", "
|
|
33
|
+
const bridge$1 = { "sourceNetwork": "Source network", "destinationNetwork": "Destination network", "selectToken": "Select token", "selectNetwork": "Select network", "searchToken": "Search token", "searchDestinationChain": "Search destination chain", "myTokens": "My tokens", "allTokens": "All tokens", "willChangeSourceChain": "Will Change Source Chain", "noBalancesFound": "No balances found.", "noResults": "No results", "sendToAnotherAddress": "Send to another address", "youWillReceive": "You will receive", "anotherAddressPlaceholder": "Address", "addressDoesntMatch": "Address doesn't match the {{network}} network", "checkBeforeTransfer": "Check correctness before transfer" };
|
|
34
34
|
const transaction$1 = { "enterAmount": "Enter amount", "transfer": "Transfer", "getQuote": "Get quote", "failed": "Transaction Failed", "confirm": "Confirm transaction", "signTransaction": "Sign in transaction in wallet", "quoting": "Quoting...", "inProgress": "Processing...", "checkingBalance": "Checking balance...", "insufficientBalance": "Insufficient balance", "amountTooSmall": "Min {{min}}", "amountTooLarge": "Max {{max}}", "successTitle": "Success", "bridged": "Bridged", "transferTitle": "Transfer", "hash": "Hash", "route": "Route", "estTime": "Est. Time", "slippage": "Slippage", "minimumReceived": "Minimum received", "totalFee": "Total Fee", "noRouteFound": "No route found", "notEnoughGas": "Not enough gas", "noRouteFoundForSettings": "No route found for current settings.", "tryAdjustSettings": "Try disabling Gas on Destination, or adjust amount/networks.", "quoteError": "Quote error" };
|
|
35
35
|
const app$1 = { "stargateWidgetName": "Stargate Bridge Widget", "liveWidget": "Live Widget", "getStarted": "Get Started" };
|
|
36
36
|
const settings$1 = { "title": "Settings", "gasOnDestination": "Gas on destination", "slippageTolerance": "Slippage tolerance", "routePriority": "Route Priority", "highSlippageWarning": "High slippage warning", "gasPresets": { "auto": "Auto", "none": "None", "medium": "Medium", "max": "Max" }, "routePresets": { "fastest": "Fastest", "cheapest": "Cheapest", "recommended": "Recommended" } };
|
|
@@ -44,7 +44,7 @@ const en = {
|
|
|
44
44
|
};
|
|
45
45
|
const common = { "connecting": "Подключение…", "initializing": "Инициализация...", "loading": "Загрузка...", "paste": "вставить", "close": "Закрыть", "zeroPlaceholder": "0", "nativeToken": "Нативный токен" };
|
|
46
46
|
const wallets = { "addTonWallet": "Добавить TON кошелёк", "addEvmWallet": "Добавить EVM кошелёк", "connectTonWallet": "Подключить TON кошелёк", "connectEvmWallet": "Подключить EVM кошелёк", "initializingMetamask": "Инициализация MetaMask SDK...", "initializingTronlink": "Инициализация TronLink...", "failedToConnectTon": "Не удалось подключиться к TON кошельку", "failedToDisconnect": "Не удалось отключиться", "metamaskConnectionError": "Ошибка подключения MetaMask", "failedToConnectMetamask": "Не удалось подключиться к MetaMask", "failedToDisconnectMetamask": "Не удалось отключиться от MetaMask", "selectWallet": "Выберите кошелёк", "tonWallets": "TON", "evmWallets": "EVM", "tronWallets": "TRON", "tonKeeper": "TonKeeper", "metaMask": "WalletConnect", "tronLink": "TronLink", "addTronWallet": "Добавить Tron кошелёк", "comingSoon": "Скоро", "connected": "ПОДКЛЮЧЕНО", "disconnect": "Отключить", "chooseWallet": "Выберите кошелёк", "oneWalletPerEnv": "Можно подключить только один кошелёк на окружение.", "connect": "Подключить", "connectTronWallet": "Подключить Tron кошелёк", "connectWallet": "Подключить кошелёк" };
|
|
47
|
-
const bridge = { "sourceNetwork": "Исходная сеть", "destinationNetwork": "Целевая сеть", "selectToken": "Выбрать токен", "selectNetwork": "Выбрать сеть", "searchToken": "Поиск токена", "searchDestinationChain": "Поиск целевой сети", "myTokens": "Мои токены", "allTokens": "Все токены", "willChangeSourceChain": "Сменит исходную сеть", "noBalancesFound": "Балансы не найдены.", "noResults": "Нет результатов", "sendToAnotherAddress": "Отправить на другой адрес", "youWillReceive": "Вы получите", "
|
|
47
|
+
const bridge = { "sourceNetwork": "Исходная сеть", "destinationNetwork": "Целевая сеть", "selectToken": "Выбрать токен", "selectNetwork": "Выбрать сеть", "searchToken": "Поиск токена", "searchDestinationChain": "Поиск целевой сети", "myTokens": "Мои токены", "allTokens": "Все токены", "willChangeSourceChain": "Сменит исходную сеть", "noBalancesFound": "Балансы не найдены.", "noResults": "Нет результатов", "sendToAnotherAddress": "Отправить на другой адрес", "youWillReceive": "Вы получите", "anotherAddressPlaceholder": "Адрес", "addressDoesntMatch": "Адрес не соответствует сети {{network}}", "checkBeforeTransfer": "Проверьте корректность перед переводом" };
|
|
48
48
|
const transaction = { "enterAmount": "Введите сумму", "transfer": "Перевести", "getQuote": "Получить котировку", "quoting": "Расчет котировки...", "failed": "Ошибка транзакции", "confirm": "Подтвердите транзакцию", "signTransaction": "Подпишите транзакцию в кошельке", "inProgress": "Выполнение...", "checkingBalance": "Проверка баланса...", "insufficientBalance": "Недостаточно средств", "amountTooSmall": "Минимум {{min}}", "amountTooLarge": "Максимум {{max}}", "successTitle": "Успех", "bridged": "Переведено", "transferTitle": "Перевод", "hash": "Хэш", "route": "Маршрут", "estTime": "Время", "slippage": "Проскальзывание", "minimumReceived": "Минимум к получению", "totalFee": "Общая комиссия", "noRouteFound": "Маршрут не найден", "notEnoughGas": "Недостаточно газа", "noRouteFoundForSettings": "Маршрут не найден для текущих настроек.", "tryAdjustSettings": "Попробуйте отключить Gas on Destination или измените сумму/сети.", "quoteError": "Ошибка котировки" };
|
|
49
49
|
const app = { "stargateWidgetName": "Виджет Stargate Bridge", "liveWidget": "Живой виджет", "getStarted": "Начало работы" };
|
|
50
50
|
const settings = { "title": "Настройки", "gasOnDestination": "Газ на назначении", "slippageTolerance": "Толерантность к проскальзыванию", "routePriority": "Приоритет маршрута", "highSlippageWarning": "Высокое проскальзывание", "gasPresets": { "auto": "Авто", "none": "Нет", "medium": "Средний", "max": "Макс" }, "routePresets": { "fastest": "Быстрейший", "cheapest": "Дешевейший", "recommended": "Рекомендуемый" } };
|
|
@@ -903,21 +903,21 @@ const SettingModal = ({ isOpen, onClose }) => {
|
|
|
903
903
|
toChain?.chainKey,
|
|
904
904
|
dstNativeToken?.decimals || 18
|
|
905
905
|
);
|
|
906
|
-
const activeBtn = "bg-
|
|
907
|
-
const notActiveBtn = "bg-
|
|
906
|
+
const activeBtn = "bg-primary hover:bg-primary/80 text-primary-foreground transition-colors";
|
|
907
|
+
const notActiveBtn = "bg-accent hover:bg-accent/80 text-accent-foreground transition-colors";
|
|
908
908
|
return /* @__PURE__ */ jsx(Dialog, { open: isOpen, onOpenChange: (open) => !open && onClose(), children: /* @__PURE__ */ jsxs(DialogContent, { children: [
|
|
909
|
-
/* @__PURE__ */ jsx(DialogHeader, { children: /* @__PURE__ */ jsx(DialogTitle, { children: t2("settings.title"
|
|
909
|
+
/* @__PURE__ */ jsx(DialogHeader, { children: /* @__PURE__ */ jsx(DialogTitle, { children: t2("settings.title") }) }),
|
|
910
910
|
/* @__PURE__ */ jsxs("div", { className: "space-y-5", children: [
|
|
911
911
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-5", children: [
|
|
912
912
|
/* @__PURE__ */ jsxs("div", { className: "flex justify-between items-center", children: [
|
|
913
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-
|
|
914
|
-
/* @__PURE__ */ jsx("p", { className: "text-muted-foreground text-sm font-medium leading-
|
|
913
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
914
|
+
/* @__PURE__ */ jsx("p", { className: "text-muted-foreground text-sm font-medium leading-4", children: t2("settings.gasOnDestination") }),
|
|
915
915
|
/* @__PURE__ */ jsx(Tip, { text: t2("settings.gasOnDestination"), children: /* @__PURE__ */ jsx(TipIcon, { className: "size-4 text-muted-foreground" }) })
|
|
916
916
|
] }),
|
|
917
|
-
/* @__PURE__ */ jsx("p", { className: "text-foreground text-sm font-medium leading-
|
|
917
|
+
/* @__PURE__ */ jsx("p", { className: "text-foreground text-sm font-medium leading-4", children: formatUsd(gasUsdValue) })
|
|
918
918
|
] }),
|
|
919
919
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-3", children: [
|
|
920
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center w-1/3 gap-
|
|
920
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center w-1/3 gap-2 shrink-0", children: [
|
|
921
921
|
/* @__PURE__ */ jsx(
|
|
922
922
|
TokenSymbol,
|
|
923
923
|
{
|
|
@@ -930,13 +930,12 @@ const SettingModal = ({ isOpen, onClose }) => {
|
|
|
930
930
|
gasDisplayAmount < 1e-3 ? 6 : 3
|
|
931
931
|
) }) })
|
|
932
932
|
] }),
|
|
933
|
-
/* @__PURE__ */ jsx("div", { className: "flex items-center gap-
|
|
934
|
-
|
|
933
|
+
/* @__PURE__ */ jsx("div", { className: "flex items-center gap-2", children: gasPresets.map((g) => /* @__PURE__ */ jsx(
|
|
934
|
+
Badge,
|
|
935
935
|
{
|
|
936
|
-
type: "button",
|
|
937
936
|
onClick: () => setGasPreset(g),
|
|
938
937
|
className: cn(
|
|
939
|
-
|
|
938
|
+
"cursor-pointer",
|
|
940
939
|
gasPreset === g ? activeBtn : notActiveBtn
|
|
941
940
|
),
|
|
942
941
|
children: t2(`settings.gasPresets.${g}`)
|
|
@@ -948,26 +947,25 @@ const SettingModal = ({ isOpen, onClose }) => {
|
|
|
948
947
|
/* @__PURE__ */ jsx("hr", {}),
|
|
949
948
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-5", children: [
|
|
950
949
|
/* @__PURE__ */ jsxs("div", { className: "flex justify-between items-center", children: [
|
|
951
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-
|
|
950
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
952
951
|
/* @__PURE__ */ jsx("p", { className: "text-muted-foreground text-sm font-medium leading-3.5", children: t2("settings.slippageTolerance") }),
|
|
953
952
|
/* @__PURE__ */ jsx(Tip, { text: t2("settings.slippageTolerance"), children: /* @__PURE__ */ jsx(TipIcon, { className: "size-4 text-muted-foreground" }) })
|
|
954
953
|
] }),
|
|
955
|
-
slippageBps >= 500 && /* @__PURE__ */ jsx("p", { className: "text-
|
|
954
|
+
slippageBps >= 500 && /* @__PURE__ */ jsx("p", { className: "text-destructive text-xs font-medium", children: t2("settings.highSlippageWarning", {
|
|
956
955
|
defaultValue: "High slippage warning"
|
|
957
956
|
}) })
|
|
958
957
|
] }),
|
|
959
958
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-6", children: [
|
|
960
959
|
/* @__PURE__ */ jsx("div", { className: "flex items-center gap-2", children: /* @__PURE__ */ jsx("p", { className: "text-lg text-foreground leading-4.5 font-semibold h-4.5", children: slippagePercent }) }),
|
|
961
960
|
/* @__PURE__ */ jsx("div", { className: "flex items-center gap-2", children: slippagePresets.map((p) => /* @__PURE__ */ jsx(
|
|
962
|
-
|
|
961
|
+
Badge,
|
|
963
962
|
{
|
|
964
|
-
type: "button",
|
|
965
963
|
onClick: () => {
|
|
966
964
|
const bps = parseFloat(p.replace("%", "")) * 100;
|
|
967
965
|
setSlippageBps(bps);
|
|
968
966
|
},
|
|
969
967
|
className: cn(
|
|
970
|
-
|
|
968
|
+
"cursor-pointer",
|
|
971
969
|
activeSlippagePreset === p ? activeBtn : notActiveBtn
|
|
972
970
|
),
|
|
973
971
|
children: p
|
|
@@ -978,17 +976,16 @@ const SettingModal = ({ isOpen, onClose }) => {
|
|
|
978
976
|
] }),
|
|
979
977
|
/* @__PURE__ */ jsx("hr", {}),
|
|
980
978
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-5", children: [
|
|
981
|
-
/* @__PURE__ */ jsx("div", { className: "flex justify-between items-center", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-
|
|
979
|
+
/* @__PURE__ */ jsx("div", { className: "flex justify-between items-center", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
982
980
|
/* @__PURE__ */ jsx("p", { className: "text-muted-foreground text-sm font-medium leading-3.5", children: t2("settings.routePriority") }),
|
|
983
981
|
/* @__PURE__ */ jsx(Tip, { text: t2("settings.routePriority"), children: /* @__PURE__ */ jsx(TipIcon, { className: "size-4 text-muted-foreground" }) })
|
|
984
982
|
] }) }),
|
|
985
983
|
/* @__PURE__ */ jsx("div", { className: "flex items-center justify-end gap-2", children: routePresets.map((r) => /* @__PURE__ */ jsx(
|
|
986
|
-
|
|
984
|
+
Badge,
|
|
987
985
|
{
|
|
988
|
-
type: "button",
|
|
989
986
|
onClick: () => setRoutePriority(r),
|
|
990
987
|
className: cn(
|
|
991
|
-
|
|
988
|
+
"cursor-pointer",
|
|
992
989
|
routePriority === r ? activeBtn : notActiveBtn
|
|
993
990
|
),
|
|
994
991
|
children: t2(`settings.routePresets.${r}`)
|
|
@@ -1056,168 +1053,31 @@ function useChainStrategies() {
|
|
|
1056
1053
|
}
|
|
1057
1054
|
return context;
|
|
1058
1055
|
}
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
}
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
if (
|
|
1067
|
-
const base = BigInt(10) ** BigInt(decimals);
|
|
1068
|
-
const int = bi / base;
|
|
1069
|
-
const frac = Number(bi % base) / Number(base);
|
|
1070
|
-
return Number(int) + frac;
|
|
1071
|
-
}
|
|
1072
|
-
function resolveTokenOnChainFromMatrix$2(assetMatrix, assetSymbol, chainKey) {
|
|
1073
|
-
if (!assetMatrix || !assetSymbol || !chainKey) return void 0;
|
|
1074
|
-
const byChain = assetMatrix[assetSymbol.toUpperCase()];
|
|
1075
|
-
return byChain?.[chainKey];
|
|
1076
|
-
}
|
|
1077
|
-
const DEFAULT_SLIPPAGE_BPS = 50;
|
|
1078
|
-
const lower = (s) => (s ?? "").toLowerCase();
|
|
1079
|
-
const normSym = (s) => (s ?? "").toUpperCase().replace(/₮/g, "T").replace(/[^A-Z0-9]/g, "");
|
|
1080
|
-
function tonNorm(addr) {
|
|
1081
|
-
if (!addr) return null;
|
|
1056
|
+
const isEvmAddress = (addr) => {
|
|
1057
|
+
return /^0x[0-9a-fA-F]{40}$/.test(addr ?? "");
|
|
1058
|
+
};
|
|
1059
|
+
const isTronAddress = (addr) => {
|
|
1060
|
+
return /^T[1-9A-HJ-NP-Za-km-z]{33}$/.test(addr ?? "");
|
|
1061
|
+
};
|
|
1062
|
+
const isTonAddress = (addr) => {
|
|
1063
|
+
if (!addr) return false;
|
|
1082
1064
|
try {
|
|
1083
1065
|
if (addr.includes(":")) {
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
urlSafe: true
|
|
1087
|
-
});
|
|
1066
|
+
Address.parseRaw(addr);
|
|
1067
|
+
return true;
|
|
1088
1068
|
}
|
|
1089
|
-
|
|
1069
|
+
Address.parse(addr);
|
|
1070
|
+
return true;
|
|
1090
1071
|
} catch {
|
|
1091
|
-
return
|
|
1072
|
+
return false;
|
|
1092
1073
|
}
|
|
1093
|
-
}
|
|
1094
|
-
const isEvmAddress = (a) => /^0x[0-9a-fA-F]{40}$/.test(a ?? "");
|
|
1095
|
-
const isTronAddress = (a) => /^T[1-9A-HJ-NP-Za-km-z]{33}$/.test(a ?? "");
|
|
1096
|
-
const isZeroAddr = (a) => (
|
|
1097
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1098
|
-
!!a && /^0x0{40}$/i.test(a) || /^0x[eE]{4}e{36}$/i.test(a)
|
|
1099
|
-
);
|
|
1074
|
+
};
|
|
1100
1075
|
function isAddressValidForChain(chainKey, addr) {
|
|
1101
1076
|
if (!chainKey || !addr) return false;
|
|
1102
|
-
if (chainKey === "ton") return
|
|
1077
|
+
if (chainKey === "ton") return isTonAddress(addr);
|
|
1103
1078
|
if (chainKey === "tron") return isTronAddress(addr);
|
|
1104
1079
|
return isEvmAddress(addr);
|
|
1105
1080
|
}
|
|
1106
|
-
function addrForApi(chainKey, addr) {
|
|
1107
|
-
if (chainKey === "ton") return tonNorm(addr);
|
|
1108
|
-
return addr;
|
|
1109
|
-
}
|
|
1110
|
-
function isNativeAddrEqual(chain, tokenAddr) {
|
|
1111
|
-
if (!chain) return false;
|
|
1112
|
-
if (!tokenAddr) return false;
|
|
1113
|
-
if (isZeroAddr(tokenAddr)) return true;
|
|
1114
|
-
const nativeAddr = chain.nativeCurrency?.address;
|
|
1115
|
-
if (!nativeAddr) return false;
|
|
1116
|
-
if (chain.chainKey === "ton") {
|
|
1117
|
-
const a = tonNorm(tokenAddr);
|
|
1118
|
-
const b = tonNorm(nativeAddr);
|
|
1119
|
-
return !!a && !!b && a === b;
|
|
1120
|
-
}
|
|
1121
|
-
return lower(nativeAddr) === lower(tokenAddr);
|
|
1122
|
-
}
|
|
1123
|
-
function findNativeMeta(tokens, chain) {
|
|
1124
|
-
if (!chain) return { decimals: 18, priceUsd: void 0 };
|
|
1125
|
-
const sym = normSym(chain.nativeCurrency?.symbol);
|
|
1126
|
-
if (!sym) {
|
|
1127
|
-
return { decimals: chain.chainKey === "ton" ? 9 : 18, priceUsd: void 0 };
|
|
1128
|
-
}
|
|
1129
|
-
const sameChain = tokens?.find(
|
|
1130
|
-
(t2) => t2.chainKey === chain.chainKey && normSym(t2.symbol) === sym
|
|
1131
|
-
) ?? void 0;
|
|
1132
|
-
if (sameChain)
|
|
1133
|
-
return { decimals: sameChain.decimals, priceUsd: sameChain.price?.usd };
|
|
1134
|
-
const anyChain = tokens?.find((t2) => normSym(t2.symbol) === sym);
|
|
1135
|
-
if (anyChain)
|
|
1136
|
-
return { decimals: anyChain.decimals, priceUsd: anyChain.price?.usd };
|
|
1137
|
-
return { decimals: chain.chainKey === "ton" ? 9 : 18, priceUsd: void 0 };
|
|
1138
|
-
}
|
|
1139
|
-
function lookupTokenMeta(tokens, chains, chainKey, tokenAddr) {
|
|
1140
|
-
if (!chainKey) return { decimals: 18, priceUsd: void 0 };
|
|
1141
|
-
const chain = chains?.find((c) => c.chainKey === chainKey);
|
|
1142
|
-
const hit = tokens?.find((t2) => {
|
|
1143
|
-
if (t2.chainKey !== chainKey) return false;
|
|
1144
|
-
if (chainKey === "ton") {
|
|
1145
|
-
const a = tonNorm(t2.address);
|
|
1146
|
-
const b = tonNorm(tokenAddr);
|
|
1147
|
-
return !!a && !!b && a === b;
|
|
1148
|
-
}
|
|
1149
|
-
return lower(t2.address) === lower(tokenAddr);
|
|
1150
|
-
}) ?? void 0;
|
|
1151
|
-
if (hit) return { decimals: hit.decimals, priceUsd: hit.price?.usd };
|
|
1152
|
-
if (isNativeAddrEqual(chain, tokenAddr)) {
|
|
1153
|
-
return findNativeMeta(tokens, chain);
|
|
1154
|
-
}
|
|
1155
|
-
return { decimals: chainKey === "ton" ? 9 : 18, priceUsd: void 0 };
|
|
1156
|
-
}
|
|
1157
|
-
function computeFeesUsdFromArray(fees, tokens, chains) {
|
|
1158
|
-
if (!fees?.length) return { totalUsd: 0 };
|
|
1159
|
-
let total = 0;
|
|
1160
|
-
let protocolFeeUsd = 0;
|
|
1161
|
-
let messageFeeUsd = 0;
|
|
1162
|
-
const byType = /* @__PURE__ */ new Map();
|
|
1163
|
-
for (const f of fees) {
|
|
1164
|
-
let usd = Number(f.usd ?? 0);
|
|
1165
|
-
if (!usd) {
|
|
1166
|
-
const { decimals, priceUsd } = lookupTokenMeta(
|
|
1167
|
-
tokens,
|
|
1168
|
-
chains,
|
|
1169
|
-
f.chainKey,
|
|
1170
|
-
f.token
|
|
1171
|
-
);
|
|
1172
|
-
const human = fromLD(String(f.amount ?? "0"), decimals);
|
|
1173
|
-
usd = (priceUsd ?? 0) * human;
|
|
1174
|
-
}
|
|
1175
|
-
total += usd;
|
|
1176
|
-
const type = (f.type ?? "other").toLowerCase();
|
|
1177
|
-
byType.set(type, (byType.get(type) ?? 0) + usd);
|
|
1178
|
-
if (type === "protocol" || type === "service") {
|
|
1179
|
-
protocolFeeUsd += usd;
|
|
1180
|
-
} else if (type === "message" || type === "gas" || type === "network") {
|
|
1181
|
-
messageFeeUsd += usd;
|
|
1182
|
-
}
|
|
1183
|
-
}
|
|
1184
|
-
const serviceUsd = byType.get("protocol") ?? byType.get("service") ?? void 0;
|
|
1185
|
-
const blockchainUsd = byType.get("gas") ?? byType.get("network") ?? byType.get("message") ?? void 0;
|
|
1186
|
-
return {
|
|
1187
|
-
totalUsd: total,
|
|
1188
|
-
protocolFeeUsd: protocolFeeUsd > 0 ? protocolFeeUsd : void 0,
|
|
1189
|
-
messageFeeUsd: messageFeeUsd > 0 ? messageFeeUsd : void 0,
|
|
1190
|
-
serviceUsd,
|
|
1191
|
-
blockchainUsd
|
|
1192
|
-
};
|
|
1193
|
-
}
|
|
1194
|
-
function dollarsFromNativeFees(feeNative, feeLzToken, chain, tokens) {
|
|
1195
|
-
let total = 0;
|
|
1196
|
-
if (feeNative && chain) {
|
|
1197
|
-
const { decimals, priceUsd } = findNativeMeta(tokens, chain);
|
|
1198
|
-
const human = fromLD(String(feeNative), decimals);
|
|
1199
|
-
total += (priceUsd ?? 0) * human;
|
|
1200
|
-
}
|
|
1201
|
-
if (feeLzToken) {
|
|
1202
|
-
const lz = tokens?.find((t2) => normSym(t2.symbol) === "LZ");
|
|
1203
|
-
if (lz?.price?.usd && lz.decimals != null) {
|
|
1204
|
-
const human = fromLD(String(feeLzToken), lz.decimals);
|
|
1205
|
-
total += lz.price.usd * human;
|
|
1206
|
-
}
|
|
1207
|
-
}
|
|
1208
|
-
return total;
|
|
1209
|
-
}
|
|
1210
|
-
function sumFeeByTokenLD(fees, dstTokenAddr, dstChainKey) {
|
|
1211
|
-
if (!fees?.length || !dstTokenAddr || !dstChainKey) return "0";
|
|
1212
|
-
let acc = 0n;
|
|
1213
|
-
for (const f of fees) {
|
|
1214
|
-
if (f.chainKey !== dstChainKey) continue;
|
|
1215
|
-
const same = dstChainKey === "ton" ? tonNorm(f.token) === tonNorm(dstTokenAddr) : lower(f.token) === lower(dstTokenAddr);
|
|
1216
|
-
if (!same) continue;
|
|
1217
|
-
acc += BigInt(f.amount ?? "0");
|
|
1218
|
-
}
|
|
1219
|
-
return acc.toString();
|
|
1220
|
-
}
|
|
1221
1081
|
function useBalances(chainKey, address, priorityTokenSymbol) {
|
|
1222
1082
|
const { chainRegistry } = useChainStrategies();
|
|
1223
1083
|
const { assetMatrix } = useTokensStore();
|
|
@@ -1279,10 +1139,92 @@ function useBalances(chainKey, address, priorityTokenSymbol) {
|
|
|
1279
1139
|
query
|
|
1280
1140
|
};
|
|
1281
1141
|
}
|
|
1282
|
-
|
|
1142
|
+
const SearchInput = ({
|
|
1143
|
+
placeholder,
|
|
1144
|
+
value,
|
|
1145
|
+
onChange,
|
|
1146
|
+
className,
|
|
1147
|
+
containerClassName
|
|
1148
|
+
}) => {
|
|
1149
|
+
const [isFocused, setIsFocused] = useState(false);
|
|
1150
|
+
return /* @__PURE__ */ jsxs(
|
|
1151
|
+
"div",
|
|
1152
|
+
{
|
|
1153
|
+
className: cn(
|
|
1154
|
+
"flex items-center gap-3 px-5 py-4 bg-input rounded-md h-13 transition-all duration-200",
|
|
1155
|
+
isFocused ? "border border-ring" : "border border-transparent",
|
|
1156
|
+
containerClassName
|
|
1157
|
+
),
|
|
1158
|
+
children: [
|
|
1159
|
+
/* @__PURE__ */ jsx(SearchIcon, { className: "size-6 text-input-icon" }),
|
|
1160
|
+
/* @__PURE__ */ jsx(
|
|
1161
|
+
Input,
|
|
1162
|
+
{
|
|
1163
|
+
placeholder,
|
|
1164
|
+
className: cn(
|
|
1165
|
+
"w-full outline-none bg-transparent border-none ring-0 leading-0 p-0 h-6 text-base text-input-text placeholder:text-input-placeholder bg-none dark:bg-transparent",
|
|
1166
|
+
className
|
|
1167
|
+
),
|
|
1168
|
+
value,
|
|
1169
|
+
onChange: (e) => onChange(e.target.value),
|
|
1170
|
+
onFocus: () => setIsFocused(true),
|
|
1171
|
+
onBlur: () => setIsFocused(false)
|
|
1172
|
+
}
|
|
1173
|
+
)
|
|
1174
|
+
]
|
|
1175
|
+
}
|
|
1176
|
+
);
|
|
1177
|
+
};
|
|
1178
|
+
const TokenRow = ({
|
|
1179
|
+
symbol,
|
|
1180
|
+
name,
|
|
1181
|
+
isSelected,
|
|
1182
|
+
hasAnyWallet,
|
|
1183
|
+
balance,
|
|
1184
|
+
usdValue,
|
|
1185
|
+
isBalanceLoading,
|
|
1186
|
+
onPick
|
|
1187
|
+
}) => {
|
|
1188
|
+
return /* @__PURE__ */ jsxs(
|
|
1189
|
+
Button,
|
|
1190
|
+
{
|
|
1191
|
+
onClick: onPick,
|
|
1192
|
+
className: `w-full bg-transparent flex items-center justify-between gap-3 px-5 hover:bg-accent hover:scale-100 ${isSelected ? "border border-ring" : ""}`,
|
|
1193
|
+
children: [
|
|
1194
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
|
|
1195
|
+
/* @__PURE__ */ jsx(
|
|
1196
|
+
TokenSymbol,
|
|
1197
|
+
{
|
|
1198
|
+
symbol,
|
|
1199
|
+
className: "size-8 rounded-full",
|
|
1200
|
+
alt: symbol
|
|
1201
|
+
}
|
|
1202
|
+
),
|
|
1203
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col items-start gap-1", children: [
|
|
1204
|
+
/* @__PURE__ */ jsx("p", { className: "font-extrabold text-foreground text-lg leading-4 truncate flex items-center gap-1", children: symbol }),
|
|
1205
|
+
/* @__PURE__ */ jsx("div", { className: "text-xs leading-3 font-semibold text-muted-foreground truncate", children: name })
|
|
1206
|
+
] })
|
|
1207
|
+
] }),
|
|
1208
|
+
/* @__PURE__ */ jsx("div", { className: "text-right space-y-1", children: isBalanceLoading && hasAnyWallet ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-end gap-1", children: [
|
|
1209
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-5 w-16 rounded-md" }),
|
|
1210
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-3 w-12 rounded-md" })
|
|
1211
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1212
|
+
/* @__PURE__ */ jsx("div", { className: "font-extrabold text-foreground text-lg leading-4 truncate", children: hasAnyWallet ? formatBalance(balance) : "—" }),
|
|
1213
|
+
/* @__PURE__ */ jsx("div", { className: "text-xs leading-3 text-muted-foreground", children: hasAnyWallet && balance > 0 && usdValue > 0 ? formatUsd(usdValue) : "—" })
|
|
1214
|
+
] }) })
|
|
1215
|
+
]
|
|
1216
|
+
}
|
|
1217
|
+
);
|
|
1218
|
+
};
|
|
1219
|
+
const TokenSelectModal = ({
|
|
1220
|
+
isOpen,
|
|
1221
|
+
onClose,
|
|
1222
|
+
items,
|
|
1223
|
+
onChangeAsset
|
|
1224
|
+
}) => {
|
|
1225
|
+
const { t: t2 } = useBridgeTranslation();
|
|
1283
1226
|
const [query, setQuery] = useState("");
|
|
1284
1227
|
const [tab, setTab] = useState("my");
|
|
1285
|
-
const [isFocused, setIsFocused] = useState(false);
|
|
1286
1228
|
const { srcAddress } = useAddresses();
|
|
1287
1229
|
const { fromChain, setFromChain, chains } = useChainsStore();
|
|
1288
1230
|
const { assetMatrix, selectedAssetSymbol } = useTokensStore();
|
|
@@ -1367,159 +1309,7 @@ function useTokenSelectData(items) {
|
|
|
1367
1309
|
const resetState = useCallback(() => {
|
|
1368
1310
|
setQuery("");
|
|
1369
1311
|
setTab("my");
|
|
1370
|
-
setIsFocused(false);
|
|
1371
1312
|
}, []);
|
|
1372
|
-
return {
|
|
1373
|
-
query,
|
|
1374
|
-
setQuery,
|
|
1375
|
-
tab,
|
|
1376
|
-
setTab,
|
|
1377
|
-
isFocused,
|
|
1378
|
-
setIsFocused,
|
|
1379
|
-
effectiveTab,
|
|
1380
|
-
resetState,
|
|
1381
|
-
fromChain,
|
|
1382
|
-
setFromChain,
|
|
1383
|
-
selectedAssetSymbol,
|
|
1384
|
-
balancesQuery,
|
|
1385
|
-
groupedTokens,
|
|
1386
|
-
myTokens,
|
|
1387
|
-
getBalance,
|
|
1388
|
-
getTokenUsdValue,
|
|
1389
|
-
findFirstAvailableChain,
|
|
1390
|
-
hasAnyWallet
|
|
1391
|
-
};
|
|
1392
|
-
}
|
|
1393
|
-
const TokenRow = ({
|
|
1394
|
-
symbol,
|
|
1395
|
-
name,
|
|
1396
|
-
isSelected,
|
|
1397
|
-
hasAnyWallet,
|
|
1398
|
-
balance,
|
|
1399
|
-
usdValue,
|
|
1400
|
-
isBalanceLoading,
|
|
1401
|
-
onPick
|
|
1402
|
-
}) => {
|
|
1403
|
-
return /* @__PURE__ */ jsxs(
|
|
1404
|
-
Button,
|
|
1405
|
-
{
|
|
1406
|
-
onClick: onPick,
|
|
1407
|
-
className: `w-full h-12.5 rounded-md cursor-pointer bg-transparent flex shadow-none items-center justify-between gap-2.5 px-5 py-2.5 hover:bg-modal-item-hover transition-[300] ${isSelected ? "border border-ring" : ""}`,
|
|
1408
|
-
children: [
|
|
1409
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
|
|
1410
|
-
/* @__PURE__ */ jsx(
|
|
1411
|
-
TokenSymbol,
|
|
1412
|
-
{
|
|
1413
|
-
symbol,
|
|
1414
|
-
className: "size-7.5 max-w-7.5 rounded-full",
|
|
1415
|
-
alt: symbol
|
|
1416
|
-
}
|
|
1417
|
-
),
|
|
1418
|
-
/* @__PURE__ */ jsxs("div", { className: "flex flex-col items-start gap-1", children: [
|
|
1419
|
-
/* @__PURE__ */ jsx("p", { className: "font-extrabold text-foreground text-lg leading-4 truncate flex items-center gap-1", children: symbol }),
|
|
1420
|
-
/* @__PURE__ */ jsx("div", { className: "text-xs leading-3 font-semibold text-muted-foreground truncate", children: name })
|
|
1421
|
-
] })
|
|
1422
|
-
] }),
|
|
1423
|
-
/* @__PURE__ */ jsx("div", { className: "text-right space-y-1", children: isBalanceLoading && hasAnyWallet ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-end gap-1", children: [
|
|
1424
|
-
/* @__PURE__ */ jsx(Skeleton, { className: "h-5 w-16 rounded-md" }),
|
|
1425
|
-
/* @__PURE__ */ jsx(Skeleton, { className: "h-3 w-12 rounded-md" })
|
|
1426
|
-
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1427
|
-
/* @__PURE__ */ jsx("div", { className: "font-extrabold text-foreground text-lg leading-4 truncate", children: hasAnyWallet ? formatBalance(balance) : "—" }),
|
|
1428
|
-
/* @__PURE__ */ jsx("div", { className: "text-xs leading-3 text-muted-foreground", children: hasAnyWallet && balance > 0 && usdValue > 0 ? formatUsd(usdValue) : "—" })
|
|
1429
|
-
] }) })
|
|
1430
|
-
]
|
|
1431
|
-
}
|
|
1432
|
-
);
|
|
1433
|
-
};
|
|
1434
|
-
const HEADER_H = 30;
|
|
1435
|
-
const ROW_H = 50;
|
|
1436
|
-
const HEADER_TOP_GAP = 30;
|
|
1437
|
-
const VirtualizedTokenList = ({
|
|
1438
|
-
nodes,
|
|
1439
|
-
balancesLoading,
|
|
1440
|
-
hasAnyWallet,
|
|
1441
|
-
selectedAssetSymbol,
|
|
1442
|
-
getBalance,
|
|
1443
|
-
getTokenUsdValue,
|
|
1444
|
-
onPick
|
|
1445
|
-
}) => {
|
|
1446
|
-
const Row = ({ index, style }) => {
|
|
1447
|
-
const node = nodes[index];
|
|
1448
|
-
if (node.kind === "header") {
|
|
1449
|
-
const gap = index === 0 ? 0 : HEADER_TOP_GAP;
|
|
1450
|
-
return /* @__PURE__ */ jsx(
|
|
1451
|
-
"div",
|
|
1452
|
-
{
|
|
1453
|
-
style: { ...style, paddingTop: gap },
|
|
1454
|
-
className: "px-5 flex leading-4 text-base py-1.5 font-semibold text-muted-foreground uppercase",
|
|
1455
|
-
children: /* @__PURE__ */ jsx("p", { children: node.title })
|
|
1456
|
-
}
|
|
1457
|
-
);
|
|
1458
|
-
}
|
|
1459
|
-
const bal = getBalance(node.token.symbol);
|
|
1460
|
-
const usd = getTokenUsdValue(node.token.symbol, node.token.price?.usd);
|
|
1461
|
-
const isSelected = selectedAssetSymbol?.toUpperCase() === node.token.symbol.toUpperCase();
|
|
1462
|
-
return /* @__PURE__ */ jsx(
|
|
1463
|
-
TokenRow,
|
|
1464
|
-
{
|
|
1465
|
-
symbol: node.token.symbol,
|
|
1466
|
-
name: node.token.name,
|
|
1467
|
-
isSelected: !!isSelected,
|
|
1468
|
-
hasAnyWallet,
|
|
1469
|
-
balance: bal,
|
|
1470
|
-
usdValue: usd,
|
|
1471
|
-
isBalanceLoading: balancesLoading,
|
|
1472
|
-
onPick: () => onPick(node.token.symbol, node.willChangeSrc)
|
|
1473
|
-
}
|
|
1474
|
-
);
|
|
1475
|
-
};
|
|
1476
|
-
const getItemSize = (index) => {
|
|
1477
|
-
const node = nodes[index];
|
|
1478
|
-
if (node.kind === "header") {
|
|
1479
|
-
const gap = index === 0 ? 0 : HEADER_TOP_GAP;
|
|
1480
|
-
return HEADER_H + gap;
|
|
1481
|
-
}
|
|
1482
|
-
return ROW_H;
|
|
1483
|
-
};
|
|
1484
|
-
return /* @__PURE__ */ jsx(
|
|
1485
|
-
VariableSizeList,
|
|
1486
|
-
{
|
|
1487
|
-
height: 480,
|
|
1488
|
-
width: "100%",
|
|
1489
|
-
itemCount: nodes.length,
|
|
1490
|
-
itemSize: getItemSize,
|
|
1491
|
-
overscanCount: 8,
|
|
1492
|
-
style: { willChange: "transform", paddingBottom: "40px" },
|
|
1493
|
-
children: Row
|
|
1494
|
-
}
|
|
1495
|
-
);
|
|
1496
|
-
};
|
|
1497
|
-
const TokenSelectModal = ({
|
|
1498
|
-
isOpen,
|
|
1499
|
-
onClose,
|
|
1500
|
-
items,
|
|
1501
|
-
onChangeAsset
|
|
1502
|
-
}) => {
|
|
1503
|
-
const { t: t2 } = useBridgeTranslation();
|
|
1504
|
-
const {
|
|
1505
|
-
query,
|
|
1506
|
-
setQuery,
|
|
1507
|
-
tab,
|
|
1508
|
-
setTab,
|
|
1509
|
-
isFocused,
|
|
1510
|
-
setIsFocused,
|
|
1511
|
-
effectiveTab,
|
|
1512
|
-
resetState,
|
|
1513
|
-
setFromChain,
|
|
1514
|
-
selectedAssetSymbol,
|
|
1515
|
-
balancesQuery,
|
|
1516
|
-
groupedTokens,
|
|
1517
|
-
myTokens,
|
|
1518
|
-
getBalance,
|
|
1519
|
-
getTokenUsdValue,
|
|
1520
|
-
findFirstAvailableChain,
|
|
1521
|
-
hasAnyWallet
|
|
1522
|
-
} = useTokenSelectData(items);
|
|
1523
1313
|
const handleClose = useCallback(() => {
|
|
1524
1314
|
resetState();
|
|
1525
1315
|
onClose();
|
|
@@ -1536,68 +1326,41 @@ const TokenSelectModal = ({
|
|
|
1536
1326
|
onChangeAsset(sym);
|
|
1537
1327
|
handleClose();
|
|
1538
1328
|
};
|
|
1539
|
-
const
|
|
1540
|
-
const out = [];
|
|
1329
|
+
const tokensToRender = useMemo(() => {
|
|
1541
1330
|
if (effectiveTab === "my") {
|
|
1542
|
-
|
|
1543
|
-
out.push({
|
|
1544
|
-
kind: "token",
|
|
1545
|
-
key: `my:${token.symbol}`,
|
|
1546
|
-
token,
|
|
1547
|
-
willChangeSrc: false
|
|
1548
|
-
});
|
|
1549
|
-
}
|
|
1550
|
-
return out;
|
|
1551
|
-
}
|
|
1552
|
-
const mainTokens = [
|
|
1553
|
-
...groupedTokens.withBalance,
|
|
1554
|
-
...groupedTokens.onSrcChain
|
|
1555
|
-
];
|
|
1556
|
-
for (const token of mainTokens) {
|
|
1557
|
-
out.push({
|
|
1558
|
-
kind: "token",
|
|
1559
|
-
key: `main:${token.symbol}`,
|
|
1331
|
+
return myTokens.map((token) => ({
|
|
1560
1332
|
token,
|
|
1561
1333
|
willChangeSrc: false
|
|
1562
|
-
});
|
|
1563
|
-
}
|
|
1564
|
-
if (groupedTokens.willChangeSrcChain.length > 0) {
|
|
1565
|
-
out.push({
|
|
1566
|
-
kind: "header",
|
|
1567
|
-
key: "hdr:willChange",
|
|
1568
|
-
title: t2("bridge.willChangeSourceChain")
|
|
1569
|
-
});
|
|
1570
|
-
for (const token of groupedTokens.willChangeSrcChain) {
|
|
1571
|
-
out.push({
|
|
1572
|
-
kind: "token",
|
|
1573
|
-
key: `will:${token.symbol}`,
|
|
1574
|
-
token,
|
|
1575
|
-
willChangeSrc: true
|
|
1576
|
-
});
|
|
1577
|
-
}
|
|
1334
|
+
}));
|
|
1578
1335
|
}
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1336
|
+
const mainTokens = [
|
|
1337
|
+
...groupedTokens.withBalance.map((token) => ({
|
|
1338
|
+
token,
|
|
1339
|
+
willChangeSrc: false
|
|
1340
|
+
})),
|
|
1341
|
+
...groupedTokens.onSrcChain.map((token) => ({
|
|
1342
|
+
token,
|
|
1343
|
+
willChangeSrc: false
|
|
1344
|
+
}))
|
|
1345
|
+
];
|
|
1346
|
+
return mainTokens;
|
|
1347
|
+
}, [effectiveTab, myTokens, groupedTokens]);
|
|
1348
|
+
const willChangeSrcTokens = useMemo(
|
|
1349
|
+
() => groupedTokens.willChangeSrcChain.map((token) => ({
|
|
1350
|
+
token,
|
|
1351
|
+
willChangeSrc: true
|
|
1352
|
+
})),
|
|
1353
|
+
[groupedTokens.willChangeSrcChain]
|
|
1354
|
+
);
|
|
1355
|
+
const hasNoResults = tokensToRender.length === 0 && willChangeSrcTokens.length === 0;
|
|
1356
|
+
return /* @__PURE__ */ jsx(Dialog, { open: isOpen, onOpenChange: (open) => !open && handleClose(), children: /* @__PURE__ */ jsxs(DialogContent, { className: "!h-[90dvh] overflow-hidden flex flex-col", children: [
|
|
1582
1357
|
/* @__PURE__ */ jsx(DialogHeader, { children: /* @__PURE__ */ jsx(DialogTitle, { children: t2("bridge.selectToken") }) }),
|
|
1583
|
-
/* @__PURE__ */
|
|
1584
|
-
|
|
1358
|
+
/* @__PURE__ */ jsx(
|
|
1359
|
+
SearchInput,
|
|
1585
1360
|
{
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
/* @__PURE__ */ jsx(
|
|
1590
|
-
Input,
|
|
1591
|
-
{
|
|
1592
|
-
placeholder: t2("bridge.searchToken"),
|
|
1593
|
-
className: "w-full outline-none leading-0 p-0 h-6 text-base text-input-text placeholder:text-input-placeholder bg-none dark:bg-transparent",
|
|
1594
|
-
value: query,
|
|
1595
|
-
onChange: (e) => setQuery(e.target.value),
|
|
1596
|
-
onFocus: () => setIsFocused(true),
|
|
1597
|
-
onBlur: () => setIsFocused(false)
|
|
1598
|
-
}
|
|
1599
|
-
)
|
|
1600
|
-
]
|
|
1361
|
+
placeholder: t2("bridge.searchToken"),
|
|
1362
|
+
value: query,
|
|
1363
|
+
onChange: setQuery
|
|
1601
1364
|
}
|
|
1602
1365
|
),
|
|
1603
1366
|
hasAnyWallet() && /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
|
|
@@ -1620,20 +1383,52 @@ const TokenSelectModal = ({
|
|
|
1620
1383
|
}
|
|
1621
1384
|
)
|
|
1622
1385
|
] }),
|
|
1623
|
-
/* @__PURE__ */ jsx("div", { className: "flex-1 overflow-
|
|
1386
|
+
/* @__PURE__ */ jsx("div", { className: "flex-1 overflow-auto -mx-5", children: hasNoResults ? /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground px-5 py-4", children: t2("bridge.noResults") }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1624
1387
|
effectiveTab === "my" && myTokens.length === 0 && /* @__PURE__ */ jsx("p", { className: "leading-4 text-base font-semibold text-muted-foreground uppercase px-5 py-2", children: t2("bridge.noBalancesFound") }),
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1388
|
+
tokensToRender.map(({ token, willChangeSrc }) => {
|
|
1389
|
+
const bal = getBalance(token.symbol);
|
|
1390
|
+
const usd = getTokenUsdValue(token.symbol, token.price?.usd);
|
|
1391
|
+
const isSelected = selectedAssetSymbol?.toUpperCase() === token.symbol.toUpperCase();
|
|
1392
|
+
return /* @__PURE__ */ jsx(
|
|
1393
|
+
TokenRow,
|
|
1394
|
+
{
|
|
1395
|
+
symbol: token.symbol,
|
|
1396
|
+
name: token.name,
|
|
1397
|
+
isSelected: !!isSelected,
|
|
1398
|
+
hasAnyWallet: hasAnyWallet(),
|
|
1399
|
+
balance: bal,
|
|
1400
|
+
usdValue: usd,
|
|
1401
|
+
isBalanceLoading: balancesQuery.isLoading || balancesQuery.isFetching,
|
|
1402
|
+
onPick: () => onPick(token.symbol, willChangeSrc)
|
|
1403
|
+
},
|
|
1404
|
+
`${effectiveTab}:${token.symbol}`
|
|
1405
|
+
);
|
|
1406
|
+
}),
|
|
1407
|
+
effectiveTab === "all" && willChangeSrcTokens.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1408
|
+
/* @__PURE__ */ jsx("div", { className: "px-5 flex leading-4 text-base py-2 font-semibold text-muted-foreground uppercase mt-8", children: /* @__PURE__ */ jsx("p", { children: t2("bridge.willChangeSourceChain") }) }),
|
|
1409
|
+
willChangeSrcTokens.map(({ token, willChangeSrc }) => {
|
|
1410
|
+
const bal = getBalance(token.symbol);
|
|
1411
|
+
const usd = getTokenUsdValue(
|
|
1412
|
+
token.symbol,
|
|
1413
|
+
token.price?.usd
|
|
1414
|
+
);
|
|
1415
|
+
const isSelected = selectedAssetSymbol?.toUpperCase() === token.symbol.toUpperCase();
|
|
1416
|
+
return /* @__PURE__ */ jsx(
|
|
1417
|
+
TokenRow,
|
|
1418
|
+
{
|
|
1419
|
+
symbol: token.symbol,
|
|
1420
|
+
name: token.name,
|
|
1421
|
+
isSelected: !!isSelected,
|
|
1422
|
+
hasAnyWallet: hasAnyWallet(),
|
|
1423
|
+
balance: bal,
|
|
1424
|
+
usdValue: usd,
|
|
1425
|
+
isBalanceLoading: balancesQuery.isLoading || balancesQuery.isFetching,
|
|
1426
|
+
onPick: () => onPick(token.symbol, willChangeSrc)
|
|
1427
|
+
},
|
|
1428
|
+
`will:${token.symbol}`
|
|
1429
|
+
);
|
|
1430
|
+
})
|
|
1431
|
+
] })
|
|
1637
1432
|
] }) })
|
|
1638
1433
|
] }) });
|
|
1639
1434
|
};
|
|
@@ -1747,7 +1542,7 @@ const SelectTokenButton = ({
|
|
|
1747
1542
|
type: "button",
|
|
1748
1543
|
"aria-label": label,
|
|
1749
1544
|
children: [
|
|
1750
|
-
/* @__PURE__ */ jsxs("div", { className: "flex gap-
|
|
1545
|
+
/* @__PURE__ */ jsxs("div", { className: "flex gap-2 items-center", children: [
|
|
1751
1546
|
/* @__PURE__ */ jsx(
|
|
1752
1547
|
TokenSymbol,
|
|
1753
1548
|
{
|
|
@@ -1756,7 +1551,7 @@ const SelectTokenButton = ({
|
|
|
1756
1551
|
alt: label
|
|
1757
1552
|
}
|
|
1758
1553
|
),
|
|
1759
|
-
/* @__PURE__ */ jsx("span", { className: "text-secondary-foreground text-sm
|
|
1554
|
+
/* @__PURE__ */ jsx("span", { className: "text-secondary-foreground text-sm font-semibold", children: label })
|
|
1760
1555
|
] }),
|
|
1761
1556
|
/* @__PURE__ */ jsx(ArrowDownIcon, { className: "size-4 text-secondary-foreground" })
|
|
1762
1557
|
]
|
|
@@ -1779,12 +1574,12 @@ const FormHeaderComponent = () => {
|
|
|
1779
1574
|
const sum = selectedAssetSymbol.toUpperCase();
|
|
1780
1575
|
return assets.find((a) => a.symbol.toUpperCase() === sum) ?? assets[0];
|
|
1781
1576
|
}, [assets, selectedAssetSymbol]);
|
|
1782
|
-
return /* @__PURE__ */ jsxs(CardHeader, { className: "gap-y-0 flex justify-between items-center", children: [
|
|
1783
|
-
/* @__PURE__ */ jsxs(CardTitle, { className: "flex items-center gap-
|
|
1784
|
-
/* @__PURE__ */ jsx("span", { className: "text-sm font-normal leading-
|
|
1577
|
+
return /* @__PURE__ */ jsxs(CardHeader, { className: "gap-y-0 flex flex-row justify-between items-center", children: [
|
|
1578
|
+
/* @__PURE__ */ jsxs(CardTitle, { className: "flex items-center gap-3", children: [
|
|
1579
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm font-normal leading-4 text-muted-foreground", children: t2("bridge.selectToken") }),
|
|
1785
1580
|
/* @__PURE__ */ jsx(SelectTokenButton, { token: current, onClick: onOpen })
|
|
1786
1581
|
] }),
|
|
1787
|
-
/* @__PURE__ */ jsxs(CardAction, { className: "flex items-center gap-
|
|
1582
|
+
/* @__PURE__ */ jsxs(CardAction, { className: "flex items-center gap-3", children: [
|
|
1788
1583
|
/* @__PURE__ */ jsx(RefreshButton, {}),
|
|
1789
1584
|
/* @__PURE__ */ jsx(Button, { onClick: onOpenSettings, size: "sm", variant: "secondary", children: /* @__PURE__ */ jsx(BoltIcon, { stroke: "currentColor" }) })
|
|
1790
1585
|
] }),
|
|
@@ -1800,16 +1595,23 @@ const FormHeaderComponent = () => {
|
|
|
1800
1595
|
}
|
|
1801
1596
|
}
|
|
1802
1597
|
),
|
|
1803
|
-
/* @__PURE__ */ jsx(
|
|
1804
|
-
SettingModal,
|
|
1805
|
-
{
|
|
1806
|
-
isOpen: isOpenSettings,
|
|
1807
|
-
onClose: onCloseSettings
|
|
1808
|
-
}
|
|
1809
|
-
)
|
|
1598
|
+
/* @__PURE__ */ jsx(SettingModal, { isOpen: isOpenSettings, onClose: onCloseSettings })
|
|
1810
1599
|
] });
|
|
1811
1600
|
};
|
|
1812
1601
|
const FormHeader = memo(FormHeaderComponent);
|
|
1602
|
+
function toLD(human, decimals) {
|
|
1603
|
+
const [i = "0", f = ""] = human.replace(",", ".").split(".");
|
|
1604
|
+
const frac = (f + "0".repeat(decimals)).slice(0, decimals);
|
|
1605
|
+
return BigInt(i + frac).toString();
|
|
1606
|
+
}
|
|
1607
|
+
function fromLD(ld, decimals) {
|
|
1608
|
+
const bi = BigInt(ld || "0");
|
|
1609
|
+
if (decimals === 0) return Number(bi);
|
|
1610
|
+
const base = BigInt(10) ** BigInt(decimals);
|
|
1611
|
+
const int = bi / base;
|
|
1612
|
+
const frac = Number(bi % base) / Number(base);
|
|
1613
|
+
return Number(int) + frac;
|
|
1614
|
+
}
|
|
1813
1615
|
async function fetchQuotes(req) {
|
|
1814
1616
|
const params = {
|
|
1815
1617
|
srcChainKey: req.srcChainKey,
|
|
@@ -1868,6 +1670,131 @@ async function getQuotesByPriority(req) {
|
|
|
1868
1670
|
const priority = req.routePriority || RoutePriority.RECOMMENDED;
|
|
1869
1671
|
return selectQuoteByPriority(routes, priority);
|
|
1870
1672
|
}
|
|
1673
|
+
function resolveTokenOnChainFromMatrix$2(assetMatrix, assetSymbol, chainKey) {
|
|
1674
|
+
if (!assetMatrix || !assetSymbol || !chainKey) return void 0;
|
|
1675
|
+
const byChain = assetMatrix[assetSymbol.toUpperCase()];
|
|
1676
|
+
return byChain?.[chainKey];
|
|
1677
|
+
}
|
|
1678
|
+
const DEFAULT_SLIPPAGE_BPS = 50;
|
|
1679
|
+
const lower = (s) => (s ?? "").toLowerCase();
|
|
1680
|
+
const normSym = (s) => (s ?? "").toUpperCase().replace(/₮/g, "T").replace(/[^A-Z0-9]/g, "");
|
|
1681
|
+
function tonNorm(addr) {
|
|
1682
|
+
if (!addr) return null;
|
|
1683
|
+
try {
|
|
1684
|
+
if (addr.includes(":")) {
|
|
1685
|
+
return Address.parseRaw(addr).toString({
|
|
1686
|
+
bounceable: false,
|
|
1687
|
+
urlSafe: true
|
|
1688
|
+
});
|
|
1689
|
+
}
|
|
1690
|
+
return Address.parse(addr).toString({ bounceable: false, urlSafe: true });
|
|
1691
|
+
} catch {
|
|
1692
|
+
return null;
|
|
1693
|
+
}
|
|
1694
|
+
}
|
|
1695
|
+
const isZeroAddr = (a) => (
|
|
1696
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1697
|
+
!!a && /^0x0{40}$/i.test(a) || /^0x[eE]{4}e{36}$/i.test(a)
|
|
1698
|
+
);
|
|
1699
|
+
function addrForApi(chainKey, addr) {
|
|
1700
|
+
if (chainKey === "ton") return tonNorm(addr);
|
|
1701
|
+
return addr;
|
|
1702
|
+
}
|
|
1703
|
+
function isNativeAddrEqual(chain, tokenAddr) {
|
|
1704
|
+
if (!chain) return false;
|
|
1705
|
+
if (!tokenAddr) return false;
|
|
1706
|
+
if (isZeroAddr(tokenAddr)) return true;
|
|
1707
|
+
const nativeAddr = chain.nativeCurrency?.address;
|
|
1708
|
+
if (!nativeAddr) return false;
|
|
1709
|
+
if (chain.chainKey === "ton") {
|
|
1710
|
+
const a = tonNorm(tokenAddr);
|
|
1711
|
+
const b = tonNorm(nativeAddr);
|
|
1712
|
+
return !!a && !!b && a === b;
|
|
1713
|
+
}
|
|
1714
|
+
return lower(nativeAddr) === lower(tokenAddr);
|
|
1715
|
+
}
|
|
1716
|
+
function findNativeMeta(tokens, chain) {
|
|
1717
|
+
if (!chain) return { decimals: 18, priceUsd: void 0 };
|
|
1718
|
+
const sym = normSym(chain.nativeCurrency?.symbol);
|
|
1719
|
+
if (!sym) {
|
|
1720
|
+
return { decimals: chain.chainKey === "ton" ? 9 : 18, priceUsd: void 0 };
|
|
1721
|
+
}
|
|
1722
|
+
const sameChain = tokens?.find(
|
|
1723
|
+
(t2) => t2.chainKey === chain.chainKey && normSym(t2.symbol) === sym
|
|
1724
|
+
) ?? void 0;
|
|
1725
|
+
if (sameChain)
|
|
1726
|
+
return { decimals: sameChain.decimals, priceUsd: sameChain.price?.usd };
|
|
1727
|
+
const anyChain = tokens?.find((t2) => normSym(t2.symbol) === sym);
|
|
1728
|
+
if (anyChain)
|
|
1729
|
+
return { decimals: anyChain.decimals, priceUsd: anyChain.price?.usd };
|
|
1730
|
+
return { decimals: chain.chainKey === "ton" ? 9 : 18, priceUsd: void 0 };
|
|
1731
|
+
}
|
|
1732
|
+
function lookupTokenMeta(tokens, chains, chainKey, tokenAddr) {
|
|
1733
|
+
if (!chainKey) return { decimals: 18, priceUsd: void 0 };
|
|
1734
|
+
const chain = chains?.find((c) => c.chainKey === chainKey);
|
|
1735
|
+
const hit = tokens?.find((t2) => {
|
|
1736
|
+
if (t2.chainKey !== chainKey) return false;
|
|
1737
|
+
if (chainKey === "ton") {
|
|
1738
|
+
const a = tonNorm(t2.address);
|
|
1739
|
+
const b = tonNorm(tokenAddr);
|
|
1740
|
+
return !!a && !!b && a === b;
|
|
1741
|
+
}
|
|
1742
|
+
return lower(t2.address) === lower(tokenAddr);
|
|
1743
|
+
}) ?? void 0;
|
|
1744
|
+
if (hit) return { decimals: hit.decimals, priceUsd: hit.price?.usd };
|
|
1745
|
+
if (isNativeAddrEqual(chain, tokenAddr)) {
|
|
1746
|
+
return findNativeMeta(tokens, chain);
|
|
1747
|
+
}
|
|
1748
|
+
return { decimals: chainKey === "ton" ? 9 : 18, priceUsd: void 0 };
|
|
1749
|
+
}
|
|
1750
|
+
function computeFeesUsdFromArray(fees, tokens, chains) {
|
|
1751
|
+
if (!fees?.length) return { totalUsd: 0 };
|
|
1752
|
+
let total = 0;
|
|
1753
|
+
let protocolFeeUsd = 0;
|
|
1754
|
+
let messageFeeUsd = 0;
|
|
1755
|
+
const byType = /* @__PURE__ */ new Map();
|
|
1756
|
+
for (const f of fees) {
|
|
1757
|
+
let usd = Number(f.usd ?? 0);
|
|
1758
|
+
if (!usd) {
|
|
1759
|
+
const { decimals, priceUsd } = lookupTokenMeta(
|
|
1760
|
+
tokens,
|
|
1761
|
+
chains,
|
|
1762
|
+
f.chainKey,
|
|
1763
|
+
f.token
|
|
1764
|
+
);
|
|
1765
|
+
const human = fromLD(String(f.amount ?? "0"), decimals);
|
|
1766
|
+
usd = (priceUsd ?? 0) * human;
|
|
1767
|
+
}
|
|
1768
|
+
total += usd;
|
|
1769
|
+
const type = (f.type ?? "other").toLowerCase();
|
|
1770
|
+
byType.set(type, (byType.get(type) ?? 0) + usd);
|
|
1771
|
+
if (type === "protocol" || type === "service") {
|
|
1772
|
+
protocolFeeUsd += usd;
|
|
1773
|
+
} else if (type === "message" || type === "gas" || type === "network") {
|
|
1774
|
+
messageFeeUsd += usd;
|
|
1775
|
+
}
|
|
1776
|
+
}
|
|
1777
|
+
const serviceUsd = byType.get("protocol") ?? byType.get("service") ?? void 0;
|
|
1778
|
+
const blockchainUsd = byType.get("gas") ?? byType.get("network") ?? byType.get("message") ?? void 0;
|
|
1779
|
+
return {
|
|
1780
|
+
totalUsd: total,
|
|
1781
|
+
protocolFeeUsd: protocolFeeUsd > 0 ? protocolFeeUsd : void 0,
|
|
1782
|
+
messageFeeUsd: messageFeeUsd > 0 ? messageFeeUsd : void 0,
|
|
1783
|
+
serviceUsd,
|
|
1784
|
+
blockchainUsd
|
|
1785
|
+
};
|
|
1786
|
+
}
|
|
1787
|
+
function sumFeeByTokenLD(fees, dstTokenAddr, dstChainKey) {
|
|
1788
|
+
if (!fees?.length || !dstTokenAddr || !dstChainKey) return "0";
|
|
1789
|
+
let acc = 0n;
|
|
1790
|
+
for (const f of fees) {
|
|
1791
|
+
if (f.chainKey !== dstChainKey) continue;
|
|
1792
|
+
const same = dstChainKey === "ton" ? tonNorm(f.token) === tonNorm(dstTokenAddr) : lower(f.token) === lower(dstTokenAddr);
|
|
1793
|
+
if (!same) continue;
|
|
1794
|
+
acc += BigInt(f.amount ?? "0");
|
|
1795
|
+
}
|
|
1796
|
+
return acc.toString();
|
|
1797
|
+
}
|
|
1871
1798
|
function useBridgeQuote() {
|
|
1872
1799
|
const { assetMatrix, selectedAssetSymbol } = useTokensStore();
|
|
1873
1800
|
const { fromChain, toChain } = useChainsStore();
|
|
@@ -2245,14 +2172,14 @@ const SwapButton = () => {
|
|
|
2245
2172
|
const WalletBalance = (props) => {
|
|
2246
2173
|
const { value, isLoading = false } = props;
|
|
2247
2174
|
if (isLoading) {
|
|
2248
|
-
return /* @__PURE__ */ jsxs("div", { className: "flex gap-
|
|
2175
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex gap-2 items-center", children: [
|
|
2249
2176
|
/* @__PURE__ */ jsx(WalletIcon, { className: "text-muted-foreground" }),
|
|
2250
2177
|
/* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-16 rounded-md" })
|
|
2251
2178
|
] });
|
|
2252
2179
|
}
|
|
2253
|
-
return /* @__PURE__ */ jsxs("div", { className: "flex gap-
|
|
2180
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex gap-2 items-center", children: [
|
|
2254
2181
|
/* @__PURE__ */ jsx(WalletIcon, { className: "text-muted-foreground" }),
|
|
2255
|
-
/* @__PURE__ */ jsx("span", { className: "text-sm leading-
|
|
2182
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm leading-5 font-medium text-muted-foreground", children: value })
|
|
2256
2183
|
] });
|
|
2257
2184
|
};
|
|
2258
2185
|
const BASE_URL = "https://icons-ckg.pages.dev/stargate-light/networks";
|
|
@@ -2282,7 +2209,7 @@ const SelectNetworkButton = ({
|
|
|
2282
2209
|
type: "button",
|
|
2283
2210
|
"aria-label": label,
|
|
2284
2211
|
children: [
|
|
2285
|
-
/* @__PURE__ */ jsxs("div", { className: "flex gap-
|
|
2212
|
+
/* @__PURE__ */ jsxs("div", { className: "flex gap-2 items-center", children: [
|
|
2286
2213
|
/* @__PURE__ */ jsx(
|
|
2287
2214
|
NetworkSymbol,
|
|
2288
2215
|
{
|
|
@@ -2291,7 +2218,7 @@ const SelectNetworkButton = ({
|
|
|
2291
2218
|
alt: label
|
|
2292
2219
|
}
|
|
2293
2220
|
),
|
|
2294
|
-
/* @__PURE__ */ jsx("span", { className: "text-secondary-foreground text-sm leading-
|
|
2221
|
+
/* @__PURE__ */ jsx("span", { className: "text-secondary-foreground text-sm leading-5 font-semibold ", children: label })
|
|
2295
2222
|
] }),
|
|
2296
2223
|
/* @__PURE__ */ jsx(ArrowDownIcon, { className: "size-4 text-secondary-foreground" })
|
|
2297
2224
|
]
|
|
@@ -2349,7 +2276,7 @@ const CurrencyInput = forwardRef(
|
|
|
2349
2276
|
pattern: "[0-9]*[.,]?[0-9]*",
|
|
2350
2277
|
readOnly,
|
|
2351
2278
|
className: cn(
|
|
2352
|
-
"text-[32px] h-
|
|
2279
|
+
"text-[32px] h-12 font-medium leading-9 rounded-none text-end bg-transparent dark:bg-transparent text-foreground shadow-none border-none outline-none ring-0 focus:outline-none",
|
|
2353
2280
|
className
|
|
2354
2281
|
),
|
|
2355
2282
|
max,
|
|
@@ -2368,12 +2295,10 @@ const ChainSelectModal = ({
|
|
|
2368
2295
|
}) => {
|
|
2369
2296
|
const { t: t2 } = useBridgeTranslation();
|
|
2370
2297
|
const [query, setQuery] = useState("");
|
|
2371
|
-
const [isFocused, setIsFocused] = useState(false);
|
|
2372
2298
|
const { setFromChain, chains, fromChain, toChain } = useChainsStore();
|
|
2373
2299
|
const { assetMatrix, selectedAssetSymbol } = useTokensStore();
|
|
2374
2300
|
const handleClose = useCallback(() => {
|
|
2375
2301
|
setQuery("");
|
|
2376
|
-
setIsFocused(false);
|
|
2377
2302
|
onClose();
|
|
2378
2303
|
}, [onClose]);
|
|
2379
2304
|
const findCompatibleSrcChain = useCallback(
|
|
@@ -2433,8 +2358,8 @@ const ChainSelectModal = ({
|
|
|
2433
2358
|
Button,
|
|
2434
2359
|
{
|
|
2435
2360
|
onClick: () => onChainPick(chain, willChangeSrc),
|
|
2436
|
-
className: `w-full cursor-pointer flex shadow-none items-center justify-between gap-
|
|
2437
|
-
children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-
|
|
2361
|
+
className: `w-full cursor-pointer flex shadow-none items-center justify-between gap-3 px-5 py-3.5 h-12.5 font-extrabold capitalize hover:bg-muted bg-transparent rounded-md transition-[300] ${isSelected ? "border border-ring" : ""}`,
|
|
2362
|
+
children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
|
|
2438
2363
|
/* @__PURE__ */ jsx(
|
|
2439
2364
|
NetworkSymbol,
|
|
2440
2365
|
{
|
|
@@ -2449,26 +2374,16 @@ const ChainSelectModal = ({
|
|
|
2449
2374
|
chain.chainKey
|
|
2450
2375
|
);
|
|
2451
2376
|
};
|
|
2452
|
-
return /* @__PURE__ */ jsx(Dialog, { open: isOpen, onOpenChange: (open) => !open && handleClose(), children: /* @__PURE__ */ jsxs(DialogContent, { className: "!
|
|
2377
|
+
return /* @__PURE__ */ jsx(Dialog, { open: isOpen, onOpenChange: (open) => !open && handleClose(), children: /* @__PURE__ */ jsxs(DialogContent, { className: "!h-[90dvh] flex flex-col", children: [
|
|
2453
2378
|
/* @__PURE__ */ jsx(DialogHeader, { children: /* @__PURE__ */ jsx(DialogTitle, { children: t2("bridge.selectNetwork") }) }),
|
|
2454
|
-
/* @__PURE__ */
|
|
2455
|
-
|
|
2379
|
+
/* @__PURE__ */ jsx(
|
|
2380
|
+
SearchInput,
|
|
2456
2381
|
{
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
{
|
|
2463
|
-
placeholder: t2("bridge.searchDestinationChain"),
|
|
2464
|
-
className: "w-full outline-none leading-0 p-0 h-6 text-base text-foreground placeholder:text-muted-foreground bg-none dark:bg-transparent",
|
|
2465
|
-
value: query,
|
|
2466
|
-
onChange: (e) => setQuery(e.target.value),
|
|
2467
|
-
onFocus: () => setIsFocused(true),
|
|
2468
|
-
onBlur: () => setIsFocused(false)
|
|
2469
|
-
}
|
|
2470
|
-
)
|
|
2471
|
-
]
|
|
2382
|
+
placeholder: t2("bridge.searchDestinationChain"),
|
|
2383
|
+
value: query,
|
|
2384
|
+
onChange: setQuery,
|
|
2385
|
+
containerClassName: "rounded-md",
|
|
2386
|
+
className: "text-foreground placeholder:text-muted-foreground"
|
|
2472
2387
|
}
|
|
2473
2388
|
),
|
|
2474
2389
|
/* @__PURE__ */ jsxs("div", { className: "flex-1 overflow-y-auto", children: [
|
|
@@ -2493,9 +2408,9 @@ function short$1(addr) {
|
|
|
2493
2408
|
return addr.slice(0, 4) + "…" + addr.slice(-4);
|
|
2494
2409
|
}
|
|
2495
2410
|
const prefixIcons = {
|
|
2496
|
-
tronlink: /* @__PURE__ */ jsx(TronLinkIcon, { className: "size-
|
|
2497
|
-
metamask: /* @__PURE__ */ jsx(MetaMaskIcon, { className: "size-
|
|
2498
|
-
ton: /* @__PURE__ */ jsx(TonKeeperIcon, { className: "size-
|
|
2411
|
+
tronlink: /* @__PURE__ */ jsx(TronLinkIcon, { className: "size-5" }),
|
|
2412
|
+
metamask: /* @__PURE__ */ jsx(MetaMaskIcon, { className: "size-5" }),
|
|
2413
|
+
ton: /* @__PURE__ */ jsx(TonKeeperIcon, { className: "size-5" })
|
|
2499
2414
|
};
|
|
2500
2415
|
const mapWalletToType = (wallet) => {
|
|
2501
2416
|
switch (wallet) {
|
|
@@ -2544,7 +2459,7 @@ const WalletButton = ({
|
|
|
2544
2459
|
e.preventDefault();
|
|
2545
2460
|
},
|
|
2546
2461
|
disabled: isButtonDisabled,
|
|
2547
|
-
className: "p-0 !px-0 py-0 flex gap-1 cursor-pointer shadow-none hover:bg-transparent bg-transparent rounded-none h-
|
|
2462
|
+
className: "p-0 !px-0 py-0 flex gap-1 cursor-pointer shadow-none hover:bg-transparent bg-transparent rounded-none h-5",
|
|
2548
2463
|
children: [
|
|
2549
2464
|
isConnected ? prefixIcons[wallet] : null,
|
|
2550
2465
|
/* @__PURE__ */ jsx("p", { className: "leading-4 text-sm font-medium text-link border-b-2 border-dotted border-link", children: buttonText })
|
|
@@ -2620,7 +2535,7 @@ const SwapSection = ({
|
|
|
2620
2535
|
),
|
|
2621
2536
|
children: [
|
|
2622
2537
|
/* @__PURE__ */ jsxs("div", { className: "flex justify-between items-center", children: [
|
|
2623
|
-
/* @__PURE__ */ jsx("span", { className: "text-sm leading-
|
|
2538
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm leading-5 font-medium text-muted-foreground", children: label }),
|
|
2624
2539
|
/* @__PURE__ */ jsx(
|
|
2625
2540
|
WalletBalance,
|
|
2626
2541
|
{
|
|
@@ -2683,63 +2598,30 @@ const useCustomAddressStore = create$1((set) => ({
|
|
|
2683
2598
|
setCustomDstAddress: (address) => set({ customDstAddress: address }),
|
|
2684
2599
|
clearCustomDstAddress: () => set({ customDstAddress: void 0 })
|
|
2685
2600
|
}));
|
|
2686
|
-
const
|
|
2687
|
-
|
|
2688
|
-
|
|
2689
|
-
|
|
2690
|
-
|
|
2691
|
-
bounceable: false,
|
|
2692
|
-
urlSafe: true
|
|
2693
|
-
});
|
|
2694
|
-
}
|
|
2695
|
-
return Address.parse(addr).toString({ bounceable: false, urlSafe: true });
|
|
2696
|
-
} catch {
|
|
2697
|
-
return null;
|
|
2698
|
-
}
|
|
2601
|
+
const useIsAddressValid = (address, chainKey) => {
|
|
2602
|
+
const isValid = useMemo(() => {
|
|
2603
|
+
return isAddressValidForChain(chainKey, address);
|
|
2604
|
+
}, [address, chainKey]);
|
|
2605
|
+
return { isValid };
|
|
2699
2606
|
};
|
|
2700
|
-
const
|
|
2607
|
+
const AnotherAddress = () => {
|
|
2608
|
+
const [enabled, setEnabled] = useState(false);
|
|
2609
|
+
const [isFocused, setIsFocused] = useState(false);
|
|
2701
2610
|
const { t: t2 } = useBridgeTranslation();
|
|
2702
2611
|
const { toChain } = useChainsStore();
|
|
2703
|
-
const {
|
|
2704
|
-
const { setCustomDstAddress, clearCustomDstAddress } = useCustomAddressStore();
|
|
2612
|
+
const { setCustomDstAddress } = useCustomAddressStore();
|
|
2705
2613
|
const [value, setValue] = useState("");
|
|
2706
|
-
const
|
|
2707
|
-
const
|
|
2708
|
-
const prevEnabledRef = useRef(enabled);
|
|
2709
|
-
useEffect(() => {
|
|
2710
|
-
const wasEnabled = prevEnabledRef.current;
|
|
2711
|
-
if (enabled && !wasEnabled) {
|
|
2712
|
-
prevDstRef.current = dstAddress;
|
|
2713
|
-
setValue(dstAddress ?? "");
|
|
2714
|
-
setInvalid(false);
|
|
2715
|
-
}
|
|
2716
|
-
if (!enabled && wasEnabled) {
|
|
2717
|
-
clearCustomDstAddress();
|
|
2718
|
-
setInvalid(false);
|
|
2719
|
-
}
|
|
2720
|
-
prevEnabledRef.current = enabled;
|
|
2721
|
-
}, [enabled]);
|
|
2614
|
+
const { isValid } = useIsAddressValid(value.trim(), toChain?.chainKey);
|
|
2615
|
+
const invalid = value.trim() && !isValid;
|
|
2722
2616
|
const pushToStoreIfValid = (raw) => {
|
|
2723
2617
|
if (!enabled) return;
|
|
2724
2618
|
const v = raw.trim();
|
|
2725
2619
|
if (!v) {
|
|
2726
2620
|
setCustomDstAddress(void 0);
|
|
2727
|
-
setInvalid(false);
|
|
2728
|
-
return;
|
|
2729
|
-
}
|
|
2730
|
-
const ck = toChain?.chainKey;
|
|
2731
|
-
if (!ck) {
|
|
2732
|
-
setInvalid(true);
|
|
2733
2621
|
return;
|
|
2734
2622
|
}
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
if (valid && valueForStore) {
|
|
2738
|
-
setInvalid(false);
|
|
2739
|
-
setCustomDstAddress(valueForStore);
|
|
2740
|
-
if (ck === "ton") setValue(valueForStore);
|
|
2741
|
-
} else {
|
|
2742
|
-
setInvalid(true);
|
|
2623
|
+
if (isValid) {
|
|
2624
|
+
setCustomDstAddress(v);
|
|
2743
2625
|
}
|
|
2744
2626
|
};
|
|
2745
2627
|
const onChange = (text) => {
|
|
@@ -2754,16 +2636,16 @@ const ToggleRow = ({ enabled, onToggle }) => {
|
|
|
2754
2636
|
} catch {
|
|
2755
2637
|
}
|
|
2756
2638
|
};
|
|
2757
|
-
return /* @__PURE__ */ jsxs("div", { className: "p-4 flex flex-col rounded-b-lg
|
|
2639
|
+
return /* @__PURE__ */ jsxs("div", { className: "p-4 flex flex-col rounded-b-lg bg-muted", children: [
|
|
2758
2640
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
|
|
2759
|
-
/* @__PURE__ */ jsx("p", { className: "text-sm leading-
|
|
2641
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm leading-5 font-medium text-muted-foreground", children: t2("bridge.sendToAnotherAddress") }),
|
|
2760
2642
|
/* @__PURE__ */ jsx(
|
|
2761
2643
|
Switch,
|
|
2762
2644
|
{
|
|
2763
2645
|
className: "data-[state=unchecked]:bg-switch-inactive data-[state=checked]:bg-switch-active",
|
|
2764
2646
|
"aria-pressed": enabled,
|
|
2765
2647
|
checked: enabled,
|
|
2766
|
-
onClick:
|
|
2648
|
+
onClick: () => setEnabled((v) => !v)
|
|
2767
2649
|
}
|
|
2768
2650
|
)
|
|
2769
2651
|
] }),
|
|
@@ -2778,16 +2660,27 @@ const ToggleRow = ({ enabled, onToggle }) => {
|
|
|
2778
2660
|
children: /* @__PURE__ */ jsxs(
|
|
2779
2661
|
"div",
|
|
2780
2662
|
{
|
|
2781
|
-
className:
|
|
2663
|
+
className: cn(
|
|
2664
|
+
"bg-input py-2 px-4 mt-2 w-full flex items-center gap-4 rounded-md justify-between border border-transparent transition-all",
|
|
2665
|
+
{
|
|
2666
|
+
"py-4": value,
|
|
2667
|
+
"border border-ring": isFocused,
|
|
2668
|
+
"border-destructive": invalid
|
|
2669
|
+
}
|
|
2670
|
+
),
|
|
2782
2671
|
children: [
|
|
2783
|
-
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-
|
|
2672
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2 w-full", children: [
|
|
2784
2673
|
/* @__PURE__ */ jsx(
|
|
2785
2674
|
Input,
|
|
2786
2675
|
{
|
|
2787
|
-
className:
|
|
2788
|
-
|
|
2676
|
+
className: cn(
|
|
2677
|
+
"p-0 h-auto text-base leading-5 font-semibold w-full bg-transparent dark:bg-transparent placeholder:text-muted-foreground/50 border-none"
|
|
2678
|
+
),
|
|
2679
|
+
placeholder: t2("bridge.anotherAddressPlaceholder"),
|
|
2789
2680
|
type: "text",
|
|
2790
2681
|
value,
|
|
2682
|
+
onFocus: () => setIsFocused(true),
|
|
2683
|
+
onBlur: () => setIsFocused(false),
|
|
2791
2684
|
onChange: (e) => onChange(e.target.value)
|
|
2792
2685
|
}
|
|
2793
2686
|
),
|
|
@@ -2797,21 +2690,14 @@ const ToggleRow = ({ enabled, onToggle }) => {
|
|
|
2797
2690
|
defaultValue: "Check correctness before transfer"
|
|
2798
2691
|
}) }) })
|
|
2799
2692
|
] }),
|
|
2800
|
-
!value ? /* @__PURE__ */ jsx(
|
|
2801
|
-
Button,
|
|
2802
|
-
{
|
|
2803
|
-
variant: "default",
|
|
2804
|
-
className: "self-center py-2 h-8.5 px-3 hover:bg-input-button bg-input-button text-input-button-foreground text-sm leading-4.5 font-semibold uppercase !rounded-40",
|
|
2805
|
-
onClick: onPaste,
|
|
2806
|
-
children: t2("common.paste")
|
|
2807
|
-
}
|
|
2808
|
-
) : /* @__PURE__ */ jsx(
|
|
2693
|
+
!value ? /* @__PURE__ */ jsx(Button, { variant: "secondary", size: "sm", onClick: onPaste, children: t2("common.paste") }) : /* @__PURE__ */ jsx(
|
|
2809
2694
|
Button,
|
|
2810
2695
|
{
|
|
2811
2696
|
variant: "ghost",
|
|
2812
|
-
|
|
2697
|
+
size: "sm",
|
|
2698
|
+
className: "rounded-full p-0 size-5 self-start",
|
|
2813
2699
|
onClick: () => setValue(""),
|
|
2814
|
-
children: /* @__PURE__ */ jsx(X, { className: "size-
|
|
2700
|
+
children: /* @__PURE__ */ jsx(X, { className: "size-4" })
|
|
2815
2701
|
}
|
|
2816
2702
|
)
|
|
2817
2703
|
]
|
|
@@ -2970,10 +2856,10 @@ const Details = () => {
|
|
|
2970
2856
|
const routeText = quote?.route ? getRouteDisplayName(quote.route) : t2(`settings.routePresets.${routePriority}`);
|
|
2971
2857
|
return /* @__PURE__ */ jsx(Accordion, { type: "single", collapsible: true, className: "w-full", children: /* @__PURE__ */ jsxs(AccordionItem, { value: "item-1", className: "bg-muted rounded-lg", children: [
|
|
2972
2858
|
/* @__PURE__ */ jsx(AccordionTrigger, { className: "w-full gap-1 items-center py-6 px-5 rounded-b-lg data-[state=open]:pb-3", children: /* @__PURE__ */ jsxs("div", { className: "w-full flex items-center justify-between", children: [
|
|
2973
|
-
/* @__PURE__ */ jsx("p", { className: "text-sm font-normal text-priority leading-
|
|
2974
|
-
/* @__PURE__ */ jsxs("div", { className: "bg-transparent hover:bg-transparent shadow-none h-4 p-0 px-0 py-0 flex items-center gap-
|
|
2859
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm font-normal text-priority leading-4", children: t2("bridge.youWillReceive", { defaultValue: "You will receive" }) }),
|
|
2860
|
+
/* @__PURE__ */ jsxs("div", { className: "bg-transparent hover:bg-transparent shadow-none h-4 p-0 px-0 py-0 flex items-center gap-2", children: [
|
|
2975
2861
|
/* @__PURE__ */ jsx(TokenSymbol, { symbol, className: "w-4 h-4", alt: "token" }),
|
|
2976
|
-
isLoading ? /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-24 rounded-md" }) : /* @__PURE__ */ jsxs("span", { className: "text-sm font-semibold leading-
|
|
2862
|
+
isLoading ? /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-24 rounded-md" }) : /* @__PURE__ */ jsxs("span", { className: "text-sm font-semibold leading-4 text-foreground", children: [
|
|
2977
2863
|
receiveText,
|
|
2978
2864
|
" ",
|
|
2979
2865
|
symbol
|
|
@@ -2985,7 +2871,7 @@ const Details = () => {
|
|
|
2985
2871
|
DetailsRow,
|
|
2986
2872
|
{
|
|
2987
2873
|
label: t2("transaction.route"),
|
|
2988
|
-
value: /* @__PURE__ */ jsxs("strong", { className: "flex items-center gap-
|
|
2874
|
+
value: /* @__PURE__ */ jsxs("strong", { className: "flex items-center gap-2", children: [
|
|
2989
2875
|
/* @__PURE__ */ jsx(StargateIcon, { className: "size-4" }),
|
|
2990
2876
|
/* @__PURE__ */ jsx("p", { className: "", children: routeText })
|
|
2991
2877
|
] })
|
|
@@ -3025,7 +2911,7 @@ const DetailsRow = ({
|
|
|
3025
2911
|
value,
|
|
3026
2912
|
isLoading = false
|
|
3027
2913
|
}) => /* @__PURE__ */ jsxs("div", { className: "flex justify-between items-center", children: [
|
|
3028
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-
|
|
2914
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
3029
2915
|
/* @__PURE__ */ jsx("p", { className: "text-sm text-priority font-normal", children: label }),
|
|
3030
2916
|
/* @__PURE__ */ jsx(Tip, { text: label, children: /* @__PURE__ */ jsx(TipIcon, { className: "size-4 text-receive-icon" }) })
|
|
3031
2917
|
] }),
|
|
@@ -3789,9 +3675,9 @@ const WalletSelectModal = () => {
|
|
|
3789
3675
|
/* @__PURE__ */ jsx("div", { className: "py-2 font-semibold text-muted-foreground uppercase", children: t2("wallets.connected") }),
|
|
3790
3676
|
/* @__PURE__ */ jsx("div", { className: "", children: connectedWallets.map((wallet) => {
|
|
3791
3677
|
const IconComponent = wallet.icon;
|
|
3792
|
-
return /* @__PURE__ */ jsx("div", { className: "-mx-5", children: /* @__PURE__ */ jsxs(Button, { className: "w-full cursor-pointer bg-transparent flex shadow-none items-center justify-between gap-
|
|
3793
|
-
/* @__PURE__ */ jsx("div", { className: "flex items-center gap-3 min-w-0", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-
|
|
3794
|
-
/* @__PURE__ */ jsx("div", { className: "
|
|
3678
|
+
return /* @__PURE__ */ jsx("div", { className: "-mx-5", children: /* @__PURE__ */ jsxs(Button, { className: "w-full cursor-pointer bg-transparent flex shadow-none items-center justify-between gap-3 px-5 py-3 hover:bg-muted h-auto rounded-md transition-[300]", children: [
|
|
3679
|
+
/* @__PURE__ */ jsx("div", { className: "flex items-center gap-3 min-w-0", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
|
|
3680
|
+
/* @__PURE__ */ jsx("div", { className: "size-8 flex items-center justify-center", children: /* @__PURE__ */ jsx(IconComponent, { className: "size-8" }) }),
|
|
3795
3681
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-col items-start min-w-0", children: [
|
|
3796
3682
|
/* @__PURE__ */ jsx("p", { className: "font-extrabold text-foreground text-sm leading-4 truncate", children: short(wallet.address) }),
|
|
3797
3683
|
/* @__PURE__ */ jsx("div", { className: "text-xs leading-3 font-semibold text-muted-foreground", children: wallet.name })
|
|
@@ -3830,9 +3716,9 @@ const WalletSelectModal = () => {
|
|
|
3830
3716
|
}
|
|
3831
3717
|
},
|
|
3832
3718
|
disabled: isEvmConnector ? isPending : !wallet.enabled,
|
|
3833
|
-
className: "w-full cursor-pointer bg-transparent flex shadow-none items-center justify-between gap-
|
|
3719
|
+
className: "w-full cursor-pointer bg-transparent flex shadow-none items-center justify-between gap-3 px-5 py-3 hover:bg-muted h-auto rounded-md transition-[300] disabled:opacity-50 disabled:cursor-not-allowed",
|
|
3834
3720
|
children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 min-w-0", children: [
|
|
3835
|
-
/* @__PURE__ */ jsx("div", { className: "w-
|
|
3721
|
+
/* @__PURE__ */ jsx("div", { className: "w-8 flex items-center justify-center", children: /* @__PURE__ */ jsx(IconComponent, { className: "size-8" }) }),
|
|
3836
3722
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-col items-start min-w-0", children: [
|
|
3837
3723
|
/* @__PURE__ */ jsx("p", { className: "font-extrabold text-foreground text-sm leading-4 truncate", children: wallet.name }),
|
|
3838
3724
|
wallet.comingSoon ? /* @__PURE__ */ jsx("div", { className: "text-xs leading-3 font-semibold text-muted-foreground", children: t2("wallets.comingSoon") }) : /* @__PURE__ */ jsx("div", { className: "text-xs leading-3 font-semibold text-muted-foreground", children: t2("wallets.connect") })
|
|
@@ -5881,7 +5767,7 @@ class ChainStrategyRegistry {
|
|
|
5881
5767
|
async getBalances(chainKey, address, tokens, priorityToken) {
|
|
5882
5768
|
const strategy = this.getStrategy(chainKey);
|
|
5883
5769
|
if (!strategy) return {};
|
|
5884
|
-
return await strategy.getBalances(address, tokens, priorityToken);
|
|
5770
|
+
return await strategy.getBalances(address, tokens, chainKey, priorityToken);
|
|
5885
5771
|
}
|
|
5886
5772
|
isAddressValid(chainKey, address) {
|
|
5887
5773
|
const strategy = this.getStrategy(chainKey);
|
|
@@ -5992,14 +5878,9 @@ function parseTonAddress(address) {
|
|
|
5992
5878
|
}
|
|
5993
5879
|
return Address$1.parse(address);
|
|
5994
5880
|
}
|
|
5995
|
-
async function getEvmBalances(publicClient, address, tokens, priorityToken) {
|
|
5881
|
+
async function getEvmBalances(publicClient, address, tokens, chainKey, priorityToken) {
|
|
5996
5882
|
const balances = {};
|
|
5997
5883
|
try {
|
|
5998
|
-
console.log("start getEvmBalances");
|
|
5999
|
-
console.log("publicClient:", publicClient);
|
|
6000
|
-
console.log("isAddress:", isAddress(address));
|
|
6001
|
-
console.log("tokens:", tokens);
|
|
6002
|
-
console.log("priorityToken:", priorityToken);
|
|
6003
5884
|
if (!address || !isAddress(address)) {
|
|
6004
5885
|
console.warn(`Invalid EVM address provided: ${address}`);
|
|
6005
5886
|
return balances;
|
|
@@ -6008,40 +5889,55 @@ async function getEvmBalances(publicClient, address, tokens, priorityToken) {
|
|
|
6008
5889
|
throw new Error("No public client provided");
|
|
6009
5890
|
}
|
|
6010
5891
|
const nativeTokens = tokens.filter((t2) => isNativeAddress(t2.address));
|
|
6011
|
-
const erc20Tokens = tokens.filter(
|
|
5892
|
+
const erc20Tokens = tokens.filter(
|
|
5893
|
+
(t2) => !isNativeAddress(t2.address) && isAddress(t2.address)
|
|
5894
|
+
);
|
|
6012
5895
|
if (priorityToken) {
|
|
6013
|
-
|
|
6014
|
-
|
|
6015
|
-
|
|
6016
|
-
|
|
6017
|
-
|
|
6018
|
-
|
|
6019
|
-
const
|
|
6020
|
-
if (
|
|
6021
|
-
|
|
6022
|
-
|
|
6023
|
-
|
|
6024
|
-
|
|
6025
|
-
|
|
6026
|
-
|
|
6027
|
-
|
|
6028
|
-
|
|
6029
|
-
|
|
6030
|
-
|
|
6031
|
-
|
|
6032
|
-
|
|
6033
|
-
|
|
6034
|
-
|
|
6035
|
-
|
|
6036
|
-
|
|
6037
|
-
|
|
6038
|
-
|
|
6039
|
-
|
|
6040
|
-
|
|
5896
|
+
if (priorityToken.chainKey !== chainKey) {
|
|
5897
|
+
console.debug(
|
|
5898
|
+
`Skipping priority token ${priorityToken.symbol}: chain mismatch (expected ${chainKey}, got ${priorityToken.chainKey})`
|
|
5899
|
+
);
|
|
5900
|
+
} else {
|
|
5901
|
+
try {
|
|
5902
|
+
const isPriorityNative = isNativeAddress(priorityToken.address);
|
|
5903
|
+
if (isPriorityNative) {
|
|
5904
|
+
const ethBalance = await publicClient.getBalance({
|
|
5905
|
+
address
|
|
5906
|
+
});
|
|
5907
|
+
const balance = parseFloat(
|
|
5908
|
+
formatUnits(ethBalance, priorityToken.decimals)
|
|
5909
|
+
);
|
|
5910
|
+
if (balance > 0) {
|
|
5911
|
+
balances[priorityToken.symbol] = { balance, address };
|
|
5912
|
+
}
|
|
5913
|
+
} else if (isAddress(priorityToken.address)) {
|
|
5914
|
+
const tokenBalance = await publicClient.readContract({
|
|
5915
|
+
address: priorityToken.address,
|
|
5916
|
+
abi: [
|
|
5917
|
+
{
|
|
5918
|
+
name: "balanceOf",
|
|
5919
|
+
type: "function",
|
|
5920
|
+
stateMutability: "view",
|
|
5921
|
+
inputs: [{ name: "owner", type: "address" }],
|
|
5922
|
+
outputs: [{ name: "balance", type: "uint256" }]
|
|
5923
|
+
}
|
|
5924
|
+
],
|
|
5925
|
+
functionName: "balanceOf",
|
|
5926
|
+
args: [address]
|
|
5927
|
+
});
|
|
5928
|
+
const balance = parseFloat(
|
|
5929
|
+
formatUnits(tokenBalance, priorityToken.decimals)
|
|
5930
|
+
);
|
|
5931
|
+
if (balance > 0) {
|
|
5932
|
+
balances[priorityToken.symbol] = { balance, address };
|
|
5933
|
+
}
|
|
6041
5934
|
}
|
|
5935
|
+
} catch (error) {
|
|
5936
|
+
console.debug(
|
|
5937
|
+
`Failed to get priority token balance for ${priorityToken.symbol}:`,
|
|
5938
|
+
error
|
|
5939
|
+
);
|
|
6042
5940
|
}
|
|
6043
|
-
} catch (error) {
|
|
6044
|
-
console.debug(`Failed to get priority token balance for ${priorityToken.symbol}:`, error);
|
|
6045
5941
|
}
|
|
6046
5942
|
}
|
|
6047
5943
|
for (const token of nativeTokens) {
|
|
@@ -6054,7 +5950,10 @@ async function getEvmBalances(publicClient, address, tokens, priorityToken) {
|
|
|
6054
5950
|
balances[token.symbol] = { balance, address };
|
|
6055
5951
|
}
|
|
6056
5952
|
} catch (error) {
|
|
6057
|
-
console.debug(
|
|
5953
|
+
console.debug(
|
|
5954
|
+
`Failed to get native balance for ${token.symbol}:`,
|
|
5955
|
+
error
|
|
5956
|
+
);
|
|
6058
5957
|
}
|
|
6059
5958
|
}
|
|
6060
5959
|
if (erc20Tokens.length > 0) {
|
|
@@ -6082,17 +5981,25 @@ async function getEvmBalances(publicClient, address, tokens, priorityToken) {
|
|
|
6082
5981
|
if (!token) return;
|
|
6083
5982
|
if (result.status === "success" && result.result !== void 0) {
|
|
6084
5983
|
try {
|
|
6085
|
-
const balance = parseFloat(
|
|
5984
|
+
const balance = parseFloat(
|
|
5985
|
+
formatUnits(result.result, token.decimals)
|
|
5986
|
+
);
|
|
6086
5987
|
if (balance > 0) {
|
|
6087
5988
|
balances[token.symbol] = { balance, address };
|
|
6088
5989
|
}
|
|
6089
5990
|
} catch (error) {
|
|
6090
|
-
console.debug(
|
|
5991
|
+
console.debug(
|
|
5992
|
+
`Failed to parse balance for ${token.symbol}:`,
|
|
5993
|
+
error
|
|
5994
|
+
);
|
|
6091
5995
|
}
|
|
6092
5996
|
}
|
|
6093
5997
|
});
|
|
6094
5998
|
} catch (error) {
|
|
6095
|
-
console.warn(
|
|
5999
|
+
console.warn(
|
|
6000
|
+
"Multicall failed, falling back to individual calls:",
|
|
6001
|
+
error
|
|
6002
|
+
);
|
|
6096
6003
|
for (const token of erc20Tokens) {
|
|
6097
6004
|
try {
|
|
6098
6005
|
const tokenBalance = await publicClient.readContract({
|
|
@@ -6126,7 +6033,7 @@ async function getEvmBalances(publicClient, address, tokens, priorityToken) {
|
|
|
6126
6033
|
}
|
|
6127
6034
|
return balances;
|
|
6128
6035
|
}
|
|
6129
|
-
async function getTonBalances(address, tokens, customTonClient, tonApiKey) {
|
|
6036
|
+
async function getTonBalances(address, tokens, chainKey, customTonClient, tonApiKey) {
|
|
6130
6037
|
const balances = {};
|
|
6131
6038
|
try {
|
|
6132
6039
|
if (!isTonFriendlyAddress(address)) {
|
|
@@ -6285,13 +6192,18 @@ class EvmChainStrategy {
|
|
|
6285
6192
|
getConnectLabel(t2) {
|
|
6286
6193
|
return t2("wallets.connectEvmWallet");
|
|
6287
6194
|
}
|
|
6288
|
-
async getBalances(address, tokens, priorityToken) {
|
|
6195
|
+
async getBalances(address, tokens, chainKey, priorityToken) {
|
|
6289
6196
|
if (!this.publicClient) {
|
|
6290
6197
|
console.warn("No publicClient available for balance query");
|
|
6291
6198
|
return {};
|
|
6292
6199
|
}
|
|
6293
|
-
|
|
6294
|
-
|
|
6200
|
+
return await getEvmBalances(
|
|
6201
|
+
this.publicClient,
|
|
6202
|
+
address,
|
|
6203
|
+
tokens,
|
|
6204
|
+
chainKey,
|
|
6205
|
+
priorityToken
|
|
6206
|
+
);
|
|
6295
6207
|
}
|
|
6296
6208
|
isAddressValid(address) {
|
|
6297
6209
|
if (!address) return false;
|
|
@@ -6647,10 +6559,11 @@ class TonChainStrategy {
|
|
|
6647
6559
|
getConnectLabel(t2) {
|
|
6648
6560
|
return t2("wallets.connectTonWallet");
|
|
6649
6561
|
}
|
|
6650
|
-
async getBalances(address, tokens) {
|
|
6562
|
+
async getBalances(address, tokens, chainKey) {
|
|
6651
6563
|
return await getTonBalances(
|
|
6652
6564
|
address,
|
|
6653
6565
|
tokens,
|
|
6566
|
+
chainKey,
|
|
6654
6567
|
this.config.tonClient,
|
|
6655
6568
|
this.config.tonApiKey
|
|
6656
6569
|
);
|
|
@@ -6859,7 +6772,6 @@ class TronChainStrategy {
|
|
|
6859
6772
|
__publicField(this, "config");
|
|
6860
6773
|
this.config = config;
|
|
6861
6774
|
}
|
|
6862
|
-
// ========== Identity ==========
|
|
6863
6775
|
canHandle(chainKey) {
|
|
6864
6776
|
return chainKey.toLowerCase() === "tron";
|
|
6865
6777
|
}
|
|
@@ -6869,7 +6781,6 @@ class TronChainStrategy {
|
|
|
6869
6781
|
getName() {
|
|
6870
6782
|
return "TRON Chain Strategy";
|
|
6871
6783
|
}
|
|
6872
|
-
// ========== Wallet Management ==========
|
|
6873
6784
|
async connect() {
|
|
6874
6785
|
const tronWeb = this.getTronWeb();
|
|
6875
6786
|
if (!tronWeb && (typeof window === "undefined" || !window.tronLink)) {
|
|
@@ -6900,7 +6811,6 @@ class TronChainStrategy {
|
|
|
6900
6811
|
getConnectLabel(t2) {
|
|
6901
6812
|
return t2("wallets.connectTronWallet");
|
|
6902
6813
|
}
|
|
6903
|
-
// ========== Balance & Validation ==========
|
|
6904
6814
|
async getBalances(address, tokens) {
|
|
6905
6815
|
const tronWeb = this.getTronWeb();
|
|
6906
6816
|
if (!tronWeb) return {};
|
|
@@ -6910,7 +6820,6 @@ class TronChainStrategy {
|
|
|
6910
6820
|
if (!address) return false;
|
|
6911
6821
|
return /^T[1-9A-HJ-NP-Za-km-z]{33}$/.test(address);
|
|
6912
6822
|
}
|
|
6913
|
-
// ========== Gas Estimation ==========
|
|
6914
6823
|
async estimateGasRequirement(params) {
|
|
6915
6824
|
const {
|
|
6916
6825
|
selectedToken,
|
|
@@ -7593,7 +7502,6 @@ const EvaaBridgeContent = ({
|
|
|
7593
7502
|
const { t: t2 } = useBridgeTranslation();
|
|
7594
7503
|
useTokensRequest();
|
|
7595
7504
|
useChainsRequest();
|
|
7596
|
-
const [sendToAnother, setSendToAnother] = useState(false);
|
|
7597
7505
|
const swap = useSwapModel();
|
|
7598
7506
|
const { fromChain, toChain } = swap;
|
|
7599
7507
|
const { selectedAssetSymbol, assetMatrix } = useTokensStore();
|
|
@@ -7721,13 +7629,7 @@ const EvaaBridgeContent = ({
|
|
|
7721
7629
|
onSelect: handleToChainChange
|
|
7722
7630
|
}
|
|
7723
7631
|
),
|
|
7724
|
-
/* @__PURE__ */ jsx(
|
|
7725
|
-
ToggleRow,
|
|
7726
|
-
{
|
|
7727
|
-
enabled: sendToAnother,
|
|
7728
|
-
onToggle: () => setSendToAnother((v) => !v)
|
|
7729
|
-
}
|
|
7730
|
-
),
|
|
7632
|
+
/* @__PURE__ */ jsx(AnotherAddress, {}),
|
|
7731
7633
|
/* @__PURE__ */ jsx(SubmitButton, {})
|
|
7732
7634
|
] }),
|
|
7733
7635
|
/* @__PURE__ */ jsx(CardFooter, { children: /* @__PURE__ */ jsx(Details, {}) })
|
|
@@ -7803,7 +7705,6 @@ export {
|
|
|
7803
7705
|
buildAssetMatrix,
|
|
7804
7706
|
calculateMinReceived,
|
|
7805
7707
|
computeFeesUsdFromArray,
|
|
7806
|
-
dollarsFromNativeFees,
|
|
7807
7708
|
findNativeMeta,
|
|
7808
7709
|
formatBalance,
|
|
7809
7710
|
formatHash,
|
|
@@ -7822,10 +7723,7 @@ export {
|
|
|
7822
7723
|
getTokens,
|
|
7823
7724
|
getTonBalances,
|
|
7824
7725
|
getTronBalances,
|
|
7825
|
-
isAddressValidForChain,
|
|
7826
|
-
isEvmAddress,
|
|
7827
7726
|
isNativeAddrEqual,
|
|
7828
|
-
isTronAddress,
|
|
7829
7727
|
isZeroAddr,
|
|
7830
7728
|
listAssetsForSelect,
|
|
7831
7729
|
lookupTokenMeta,
|