@rash2x/bridge-widget 0.1.13 → 0.1.15

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.
@@ -31,16 +31,16 @@ const i18n = require("i18next");
31
31
  const zustand = require("zustand");
32
32
  const button = require("@/components/ui/button");
33
33
  const dialog = require("@/components/ui/dialog");
34
+ const badge = require("@/components/ui/badge");
34
35
  const tooltip = require("@/components/ui/tooltip");
35
36
  const utils = require("@/lib/utils");
36
- const input = require("@/components/ui/input");
37
+ const skeleton = require("@/components/ui/skeleton");
37
38
  const wagmi = require("wagmi");
38
39
  const tronwalletAdapterReactHooks = require("@tronweb3/tronwallet-adapter-react-hooks");
39
40
  const uiReact = require("@tonconnect/ui-react");
40
41
  const reactQuery = require("@tanstack/react-query");
41
42
  const core = require("@ton/core");
42
- const reactWindow = require("react-window");
43
- const skeleton = require("@/components/ui/skeleton");
43
+ const input = require("@/components/ui/input");
44
44
  const card = require("@/components/ui/card");
45
45
  const _switch = require("@/components/ui/switch");
46
46
  const lucideReact = require("lucide-react");
@@ -53,7 +53,7 @@ const ton = require("@ton/ton");
53
53
  const tronwalletAdapters = require("@tronweb3/tronwallet-adapters");
54
54
  const common$1 = { "connecting": "Connecting…", "initializing": "Initializing...", "loading": "Loading...", "paste": "paste", "close": "Close", "zeroPlaceholder": "0", "nativeToken": "Native Token" };
55
55
  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" };
56
- 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", "tonAddressPlaceholder": "TON address", "evmAddressPlaceholder": "0x… EVM address", "addressDoesntMatch": "Address doesn't match the {{network}} network", "checkBeforeTransfer": "Check correctness before transfer" };
56
+ 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" };
57
57
  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" };
58
58
  const app$1 = { "stargateWidgetName": "Stargate Bridge Widget", "liveWidget": "Live Widget", "getStarted": "Get Started" };
59
59
  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" } };
@@ -67,7 +67,7 @@ const en = {
67
67
  };
68
68
  const common = { "connecting": "Подключение…", "initializing": "Инициализация...", "loading": "Загрузка...", "paste": "вставить", "close": "Закрыть", "zeroPlaceholder": "0", "nativeToken": "Нативный токен" };
69
69
  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": "Подключить кошелёк" };
70
- const bridge = { "sourceNetwork": "Исходная сеть", "destinationNetwork": "Целевая сеть", "selectToken": "Выбрать токен", "selectNetwork": "Выбрать сеть", "searchToken": "Поиск токена", "searchDestinationChain": "Поиск целевой сети", "myTokens": "Мои токены", "allTokens": "Все токены", "willChangeSourceChain": "Сменит исходную сеть", "noBalancesFound": "Балансы не найдены.", "noResults": "Нет результатов", "sendToAnotherAddress": "Отправить на другой адрес", "youWillReceive": "Вы получите", "tonAddressPlaceholder": "TON адрес", "evmAddressPlaceholder": "0x… EVM адрес", "addressDoesntMatch": "Адрес не соответствует сети {{network}}", "checkBeforeTransfer": "Проверьте корректность перед переводом" };
70
+ const bridge = { "sourceNetwork": "Исходная сеть", "destinationNetwork": "Целевая сеть", "selectToken": "Выбрать токен", "selectNetwork": "Выбрать сеть", "searchToken": "Поиск токена", "searchDestinationChain": "Поиск целевой сети", "myTokens": "Мои токены", "allTokens": "Все токены", "willChangeSourceChain": "Сменит исходную сеть", "noBalancesFound": "Балансы не найдены.", "noResults": "Нет результатов", "sendToAnotherAddress": "Отправить на другой адрес", "youWillReceive": "Вы получите", "anotherAddressPlaceholder": "Адрес", "addressDoesntMatch": "Адрес не соответствует сети {{network}}", "checkBeforeTransfer": "Проверьте корректность перед переводом" };
71
71
  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": "Ошибка котировки" };
72
72
  const app = { "stargateWidgetName": "Виджет Stargate Bridge", "liveWidget": "Живой виджет", "getStarted": "Начало работы" };
73
73
  const settings = { "title": "Настройки", "gasOnDestination": "Газ на назначении", "slippageTolerance": "Толерантность к проскальзыванию", "routePriority": "Приоритет маршрута", "highSlippageWarning": "Высокое проскальзывание", "gasPresets": { "auto": "Авто", "none": "Нет", "medium": "Средний", "max": "Макс" }, "routePresets": { "fastest": "Быстрейший", "cheapest": "Дешевейший", "recommended": "Рекомендуемый" } };
@@ -926,16 +926,16 @@ const SettingModal = ({ isOpen, onClose }) => {
926
926
  toChain?.chainKey,
927
927
  dstNativeToken?.decimals || 18
928
928
  );
929
- const activeBtn = "bg-settings-active hover:bg-settings-active/80 text-settings-active-foreground";
930
- const notActiveBtn = "bg-settings-button hover:bg-settings-button/80 text-settings-button-foreground";
929
+ const activeBtn = "bg-primary hover:bg-primary/80 text-primary-foreground transition-colors";
930
+ const notActiveBtn = "bg-accent hover:bg-accent/80 text-accent-foreground transition-colors";
931
931
  return /* @__PURE__ */ jsxRuntime.jsx(dialog.Dialog, { open: isOpen, onOpenChange: (open) => !open && onClose(), children: /* @__PURE__ */ jsxRuntime.jsxs(dialog.DialogContent, { children: [
932
- /* @__PURE__ */ jsxRuntime.jsx(dialog.DialogHeader, { children: /* @__PURE__ */ jsxRuntime.jsx(dialog.DialogTitle, { children: t("settings.title", { defaultValue: "Settings" }) }) }),
932
+ /* @__PURE__ */ jsxRuntime.jsx(dialog.DialogHeader, { children: /* @__PURE__ */ jsxRuntime.jsx(dialog.DialogTitle, { children: t("settings.title") }) }),
933
933
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-5", children: [
934
934
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-5", children: [
935
935
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-between items-center", children: [
936
936
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
937
937
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-muted-foreground text-sm font-medium leading-3.5", children: t("settings.gasOnDestination") }),
938
- /* @__PURE__ */ jsxRuntime.jsx(Tip, { text: t("settings.gasOnDestination"), children: /* @__PURE__ */ jsxRuntime.jsx(TipIcon, { className: "size-4 text-muted-foreground" }) })
938
+ /* @__PURE__ */ jsxRuntime.jsx(Tip, { text: t("settings.gasOnDestinationTip"), children: /* @__PURE__ */ jsxRuntime.jsx(TipIcon, { className: "size-4 text-muted-foreground" }) })
939
939
  ] }),
940
940
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-foreground text-sm font-medium leading-3.5", children: formatUsd(gasUsdValue) })
941
941
  ] }),
@@ -954,12 +954,11 @@ const SettingModal = ({ isOpen, onClose }) => {
954
954
  ) }) })
955
955
  ] }),
956
956
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-1.5", children: gasPresets.map((g) => /* @__PURE__ */ jsxRuntime.jsx(
957
- button.Button,
957
+ badge.Badge,
958
958
  {
959
- type: "button",
960
959
  onClick: () => setGasPreset(g),
961
960
  className: utils.cn(
962
- `cursor-pointer rounded-6 px-2 py-2.5 h-7 text-xs font-semibold leading-2 transition`,
961
+ "cursor-pointer",
963
962
  gasPreset === g ? activeBtn : notActiveBtn
964
963
  ),
965
964
  children: t(`settings.gasPresets.${g}`)
@@ -975,22 +974,21 @@ const SettingModal = ({ isOpen, onClose }) => {
975
974
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-muted-foreground text-sm font-medium leading-3.5", children: t("settings.slippageTolerance") }),
976
975
  /* @__PURE__ */ jsxRuntime.jsx(Tip, { text: t("settings.slippageTolerance"), children: /* @__PURE__ */ jsxRuntime.jsx(TipIcon, { className: "size-4 text-muted-foreground" }) })
977
976
  ] }),
978
- slippageBps >= 500 && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-orange-500 text-xs font-medium", children: t("settings.highSlippageWarning", {
977
+ slippageBps >= 500 && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-destructive text-xs font-medium", children: t("settings.highSlippageWarning", {
979
978
  defaultValue: "High slippage warning"
980
979
  }) })
981
980
  ] }),
982
981
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-6", children: [
983
982
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-2", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-lg text-foreground leading-4.5 font-semibold h-4.5", children: slippagePercent }) }),
984
983
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-2", children: slippagePresets.map((p) => /* @__PURE__ */ jsxRuntime.jsx(
985
- button.Button,
984
+ badge.Badge,
986
985
  {
987
- type: "button",
988
986
  onClick: () => {
989
987
  const bps = parseFloat(p.replace("%", "")) * 100;
990
988
  setSlippageBps(bps);
991
989
  },
992
990
  className: utils.cn(
993
- `cursor-pointer rounded-6 px-2 py-2.5 h-7 text-xs font-semibold leading-2 transition`,
991
+ "cursor-pointer",
994
992
  activeSlippagePreset === p ? activeBtn : notActiveBtn
995
993
  ),
996
994
  children: p
@@ -1006,12 +1004,11 @@ const SettingModal = ({ isOpen, onClose }) => {
1006
1004
  /* @__PURE__ */ jsxRuntime.jsx(Tip, { text: t("settings.routePriority"), children: /* @__PURE__ */ jsxRuntime.jsx(TipIcon, { className: "size-4 text-muted-foreground" }) })
1007
1005
  ] }) }),
1008
1006
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-end gap-2", children: routePresets.map((r) => /* @__PURE__ */ jsxRuntime.jsx(
1009
- button.Button,
1007
+ badge.Badge,
1010
1008
  {
1011
- type: "button",
1012
1009
  onClick: () => setRoutePriority(r),
1013
1010
  className: utils.cn(
1014
- `cursor-pointer rounded-6 px-2 py-2.5 h-7 text-xs font-semibold leading-2 transition`,
1011
+ "cursor-pointer",
1015
1012
  routePriority === r ? activeBtn : notActiveBtn
1016
1013
  ),
1017
1014
  children: t(`settings.routePresets.${r}`)
@@ -1079,168 +1076,31 @@ function useChainStrategies() {
1079
1076
  }
1080
1077
  return context;
1081
1078
  }
1082
- function toLD(human, decimals) {
1083
- const [i = "0", f = ""] = human.replace(",", ".").split(".");
1084
- const frac = (f + "0".repeat(decimals)).slice(0, decimals);
1085
- return BigInt(i + frac).toString();
1086
- }
1087
- function fromLD(ld, decimals) {
1088
- const bi = BigInt(ld || "0");
1089
- if (decimals === 0) return Number(bi);
1090
- const base = BigInt(10) ** BigInt(decimals);
1091
- const int = bi / base;
1092
- const frac = Number(bi % base) / Number(base);
1093
- return Number(int) + frac;
1094
- }
1095
- function resolveTokenOnChainFromMatrix$2(assetMatrix, assetSymbol, chainKey) {
1096
- if (!assetMatrix || !assetSymbol || !chainKey) return void 0;
1097
- const byChain = assetMatrix[assetSymbol.toUpperCase()];
1098
- return byChain?.[chainKey];
1099
- }
1100
- const DEFAULT_SLIPPAGE_BPS = 50;
1101
- const lower = (s) => (s ?? "").toLowerCase();
1102
- const normSym = (s) => (s ?? "").toUpperCase().replace(/₮/g, "T").replace(/[^A-Z0-9]/g, "");
1103
- function tonNorm(addr) {
1104
- if (!addr) return null;
1079
+ const isEvmAddress = (addr) => {
1080
+ return /^0x[0-9a-fA-F]{40}$/.test(addr ?? "");
1081
+ };
1082
+ const isTronAddress = (addr) => {
1083
+ return /^T[1-9A-HJ-NP-Za-km-z]{33}$/.test(addr ?? "");
1084
+ };
1085
+ const isTonAddress = (addr) => {
1086
+ if (!addr) return false;
1105
1087
  try {
1106
1088
  if (addr.includes(":")) {
1107
- return core.Address.parseRaw(addr).toString({
1108
- bounceable: false,
1109
- urlSafe: true
1110
- });
1089
+ core.Address.parseRaw(addr);
1090
+ return true;
1111
1091
  }
1112
- return core.Address.parse(addr).toString({ bounceable: false, urlSafe: true });
1092
+ core.Address.parse(addr);
1093
+ return true;
1113
1094
  } catch {
1114
- return null;
1095
+ return false;
1115
1096
  }
1116
- }
1117
- const isEvmAddress = (a) => /^0x[0-9a-fA-F]{40}$/.test(a ?? "");
1118
- const isTronAddress = (a) => /^T[1-9A-HJ-NP-Za-km-z]{33}$/.test(a ?? "");
1119
- const isZeroAddr = (a) => (
1120
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1121
- !!a && /^0x0{40}$/i.test(a) || /^0x[eE]{4}e{36}$/i.test(a)
1122
- );
1097
+ };
1123
1098
  function isAddressValidForChain(chainKey, addr) {
1124
1099
  if (!chainKey || !addr) return false;
1125
- if (chainKey === "ton") return tonNorm(addr) !== null;
1100
+ if (chainKey === "ton") return isTonAddress(addr);
1126
1101
  if (chainKey === "tron") return isTronAddress(addr);
1127
1102
  return isEvmAddress(addr);
1128
1103
  }
1129
- function addrForApi(chainKey, addr) {
1130
- if (chainKey === "ton") return tonNorm(addr);
1131
- return addr;
1132
- }
1133
- function isNativeAddrEqual(chain, tokenAddr) {
1134
- if (!chain) return false;
1135
- if (!tokenAddr) return false;
1136
- if (isZeroAddr(tokenAddr)) return true;
1137
- const nativeAddr = chain.nativeCurrency?.address;
1138
- if (!nativeAddr) return false;
1139
- if (chain.chainKey === "ton") {
1140
- const a = tonNorm(tokenAddr);
1141
- const b = tonNorm(nativeAddr);
1142
- return !!a && !!b && a === b;
1143
- }
1144
- return lower(nativeAddr) === lower(tokenAddr);
1145
- }
1146
- function findNativeMeta(tokens, chain) {
1147
- if (!chain) return { decimals: 18, priceUsd: void 0 };
1148
- const sym = normSym(chain.nativeCurrency?.symbol);
1149
- if (!sym) {
1150
- return { decimals: chain.chainKey === "ton" ? 9 : 18, priceUsd: void 0 };
1151
- }
1152
- const sameChain = tokens?.find(
1153
- (t) => t.chainKey === chain.chainKey && normSym(t.symbol) === sym
1154
- ) ?? void 0;
1155
- if (sameChain)
1156
- return { decimals: sameChain.decimals, priceUsd: sameChain.price?.usd };
1157
- const anyChain = tokens?.find((t) => normSym(t.symbol) === sym);
1158
- if (anyChain)
1159
- return { decimals: anyChain.decimals, priceUsd: anyChain.price?.usd };
1160
- return { decimals: chain.chainKey === "ton" ? 9 : 18, priceUsd: void 0 };
1161
- }
1162
- function lookupTokenMeta(tokens, chains, chainKey, tokenAddr) {
1163
- if (!chainKey) return { decimals: 18, priceUsd: void 0 };
1164
- const chain = chains?.find((c) => c.chainKey === chainKey);
1165
- const hit = tokens?.find((t) => {
1166
- if (t.chainKey !== chainKey) return false;
1167
- if (chainKey === "ton") {
1168
- const a = tonNorm(t.address);
1169
- const b = tonNorm(tokenAddr);
1170
- return !!a && !!b && a === b;
1171
- }
1172
- return lower(t.address) === lower(tokenAddr);
1173
- }) ?? void 0;
1174
- if (hit) return { decimals: hit.decimals, priceUsd: hit.price?.usd };
1175
- if (isNativeAddrEqual(chain, tokenAddr)) {
1176
- return findNativeMeta(tokens, chain);
1177
- }
1178
- return { decimals: chainKey === "ton" ? 9 : 18, priceUsd: void 0 };
1179
- }
1180
- function computeFeesUsdFromArray(fees, tokens, chains) {
1181
- if (!fees?.length) return { totalUsd: 0 };
1182
- let total = 0;
1183
- let protocolFeeUsd = 0;
1184
- let messageFeeUsd = 0;
1185
- const byType = /* @__PURE__ */ new Map();
1186
- for (const f of fees) {
1187
- let usd = Number(f.usd ?? 0);
1188
- if (!usd) {
1189
- const { decimals, priceUsd } = lookupTokenMeta(
1190
- tokens,
1191
- chains,
1192
- f.chainKey,
1193
- f.token
1194
- );
1195
- const human = fromLD(String(f.amount ?? "0"), decimals);
1196
- usd = (priceUsd ?? 0) * human;
1197
- }
1198
- total += usd;
1199
- const type = (f.type ?? "other").toLowerCase();
1200
- byType.set(type, (byType.get(type) ?? 0) + usd);
1201
- if (type === "protocol" || type === "service") {
1202
- protocolFeeUsd += usd;
1203
- } else if (type === "message" || type === "gas" || type === "network") {
1204
- messageFeeUsd += usd;
1205
- }
1206
- }
1207
- const serviceUsd = byType.get("protocol") ?? byType.get("service") ?? void 0;
1208
- const blockchainUsd = byType.get("gas") ?? byType.get("network") ?? byType.get("message") ?? void 0;
1209
- return {
1210
- totalUsd: total,
1211
- protocolFeeUsd: protocolFeeUsd > 0 ? protocolFeeUsd : void 0,
1212
- messageFeeUsd: messageFeeUsd > 0 ? messageFeeUsd : void 0,
1213
- serviceUsd,
1214
- blockchainUsd
1215
- };
1216
- }
1217
- function dollarsFromNativeFees(feeNative, feeLzToken, chain, tokens) {
1218
- let total = 0;
1219
- if (feeNative && chain) {
1220
- const { decimals, priceUsd } = findNativeMeta(tokens, chain);
1221
- const human = fromLD(String(feeNative), decimals);
1222
- total += (priceUsd ?? 0) * human;
1223
- }
1224
- if (feeLzToken) {
1225
- const lz = tokens?.find((t) => normSym(t.symbol) === "LZ");
1226
- if (lz?.price?.usd && lz.decimals != null) {
1227
- const human = fromLD(String(feeLzToken), lz.decimals);
1228
- total += lz.price.usd * human;
1229
- }
1230
- }
1231
- return total;
1232
- }
1233
- function sumFeeByTokenLD(fees, dstTokenAddr, dstChainKey) {
1234
- if (!fees?.length || !dstTokenAddr || !dstChainKey) return "0";
1235
- let acc = 0n;
1236
- for (const f of fees) {
1237
- if (f.chainKey !== dstChainKey) continue;
1238
- const same = dstChainKey === "ton" ? tonNorm(f.token) === tonNorm(dstTokenAddr) : lower(f.token) === lower(dstTokenAddr);
1239
- if (!same) continue;
1240
- acc += BigInt(f.amount ?? "0");
1241
- }
1242
- return acc.toString();
1243
- }
1244
1104
  function useBalances(chainKey, address, priorityTokenSymbol) {
1245
1105
  const { chainRegistry } = useChainStrategies();
1246
1106
  const { assetMatrix } = useTokensStore();
@@ -1302,10 +1162,92 @@ function useBalances(chainKey, address, priorityTokenSymbol) {
1302
1162
  query
1303
1163
  };
1304
1164
  }
1305
- function useTokenSelectData(items) {
1165
+ const SearchInput = ({
1166
+ placeholder,
1167
+ value,
1168
+ onChange,
1169
+ className,
1170
+ containerClassName
1171
+ }) => {
1172
+ const [isFocused, setIsFocused] = require$$0.useState(false);
1173
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1174
+ "div",
1175
+ {
1176
+ className: utils.cn(
1177
+ "flex items-center gap-2.5 px-5 py-3.5 bg-input rounded-md h-12.5 transition-all duration-200",
1178
+ isFocused ? "border border-ring" : "border border-transparent",
1179
+ containerClassName
1180
+ ),
1181
+ children: [
1182
+ /* @__PURE__ */ jsxRuntime.jsx(SearchIcon, { className: "size-6 text-input-icon" }),
1183
+ /* @__PURE__ */ jsxRuntime.jsx(
1184
+ input.Input,
1185
+ {
1186
+ placeholder,
1187
+ className: utils.cn(
1188
+ "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",
1189
+ className
1190
+ ),
1191
+ value,
1192
+ onChange: (e) => onChange(e.target.value),
1193
+ onFocus: () => setIsFocused(true),
1194
+ onBlur: () => setIsFocused(false)
1195
+ }
1196
+ )
1197
+ ]
1198
+ }
1199
+ );
1200
+ };
1201
+ const TokenRow = ({
1202
+ symbol,
1203
+ name,
1204
+ isSelected,
1205
+ hasAnyWallet,
1206
+ balance,
1207
+ usdValue,
1208
+ isBalanceLoading,
1209
+ onPick
1210
+ }) => {
1211
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1212
+ button.Button,
1213
+ {
1214
+ onClick: onPick,
1215
+ className: `w-full bg-transparent flex items-center justify-between gap-2.5 px-5 hover:bg-accent hover:scale-100 ${isSelected ? "border border-ring" : ""}`,
1216
+ children: [
1217
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
1218
+ /* @__PURE__ */ jsxRuntime.jsx(
1219
+ TokenSymbol,
1220
+ {
1221
+ symbol,
1222
+ className: "size-7.5 max-w-7.5 rounded-full",
1223
+ alt: symbol
1224
+ }
1225
+ ),
1226
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-start gap-1", children: [
1227
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-extrabold text-foreground text-lg leading-4 truncate flex items-center gap-1", children: symbol }),
1228
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs leading-3 font-semibold text-muted-foreground truncate", children: name })
1229
+ ] })
1230
+ ] }),
1231
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-right space-y-1", children: isBalanceLoading && hasAnyWallet ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-end gap-1", children: [
1232
+ /* @__PURE__ */ jsxRuntime.jsx(skeleton.Skeleton, { className: "h-5 w-16 rounded-md" }),
1233
+ /* @__PURE__ */ jsxRuntime.jsx(skeleton.Skeleton, { className: "h-3 w-12 rounded-md" })
1234
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1235
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "font-extrabold text-foreground text-lg leading-4 truncate", children: hasAnyWallet ? formatBalance(balance) : "—" }),
1236
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs leading-3 text-muted-foreground", children: hasAnyWallet && balance > 0 && usdValue > 0 ? formatUsd(usdValue) : "—" })
1237
+ ] }) })
1238
+ ]
1239
+ }
1240
+ );
1241
+ };
1242
+ const TokenSelectModal = ({
1243
+ isOpen,
1244
+ onClose,
1245
+ items,
1246
+ onChangeAsset
1247
+ }) => {
1248
+ const { t } = useBridgeTranslation();
1306
1249
  const [query, setQuery] = require$$0.useState("");
1307
1250
  const [tab, setTab] = require$$0.useState("my");
1308
- const [isFocused, setIsFocused] = require$$0.useState(false);
1309
1251
  const { srcAddress } = useAddresses();
1310
1252
  const { fromChain, setFromChain, chains } = useChainsStore();
1311
1253
  const { assetMatrix, selectedAssetSymbol } = useTokensStore();
@@ -1390,159 +1332,7 @@ function useTokenSelectData(items) {
1390
1332
  const resetState = require$$0.useCallback(() => {
1391
1333
  setQuery("");
1392
1334
  setTab("my");
1393
- setIsFocused(false);
1394
1335
  }, []);
1395
- return {
1396
- query,
1397
- setQuery,
1398
- tab,
1399
- setTab,
1400
- isFocused,
1401
- setIsFocused,
1402
- effectiveTab,
1403
- resetState,
1404
- fromChain,
1405
- setFromChain,
1406
- selectedAssetSymbol,
1407
- balancesQuery,
1408
- groupedTokens,
1409
- myTokens,
1410
- getBalance,
1411
- getTokenUsdValue,
1412
- findFirstAvailableChain,
1413
- hasAnyWallet
1414
- };
1415
- }
1416
- const TokenRow = ({
1417
- symbol,
1418
- name,
1419
- isSelected,
1420
- hasAnyWallet,
1421
- balance,
1422
- usdValue,
1423
- isBalanceLoading,
1424
- onPick
1425
- }) => {
1426
- return /* @__PURE__ */ jsxRuntime.jsxs(
1427
- button.Button,
1428
- {
1429
- onClick: onPick,
1430
- 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" : ""}`,
1431
- children: [
1432
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
1433
- /* @__PURE__ */ jsxRuntime.jsx(
1434
- TokenSymbol,
1435
- {
1436
- symbol,
1437
- className: "size-7.5 max-w-7.5 rounded-full",
1438
- alt: symbol
1439
- }
1440
- ),
1441
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-start gap-1", children: [
1442
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-extrabold text-foreground text-lg leading-4 truncate flex items-center gap-1", children: symbol }),
1443
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs leading-3 font-semibold text-muted-foreground truncate", children: name })
1444
- ] })
1445
- ] }),
1446
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-right space-y-1", children: isBalanceLoading && hasAnyWallet ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-end gap-1", children: [
1447
- /* @__PURE__ */ jsxRuntime.jsx(skeleton.Skeleton, { className: "h-5 w-16 rounded-md" }),
1448
- /* @__PURE__ */ jsxRuntime.jsx(skeleton.Skeleton, { className: "h-3 w-12 rounded-md" })
1449
- ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1450
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "font-extrabold text-foreground text-lg leading-4 truncate", children: hasAnyWallet ? formatBalance(balance) : "—" }),
1451
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs leading-3 text-muted-foreground", children: hasAnyWallet && balance > 0 && usdValue > 0 ? formatUsd(usdValue) : "—" })
1452
- ] }) })
1453
- ]
1454
- }
1455
- );
1456
- };
1457
- const HEADER_H = 30;
1458
- const ROW_H = 50;
1459
- const HEADER_TOP_GAP = 30;
1460
- const VirtualizedTokenList = ({
1461
- nodes,
1462
- balancesLoading,
1463
- hasAnyWallet,
1464
- selectedAssetSymbol,
1465
- getBalance,
1466
- getTokenUsdValue,
1467
- onPick
1468
- }) => {
1469
- const Row = ({ index, style }) => {
1470
- const node = nodes[index];
1471
- if (node.kind === "header") {
1472
- const gap = index === 0 ? 0 : HEADER_TOP_GAP;
1473
- return /* @__PURE__ */ jsxRuntime.jsx(
1474
- "div",
1475
- {
1476
- style: { ...style, paddingTop: gap },
1477
- className: "px-5 flex leading-4 text-base py-1.5 font-semibold text-muted-foreground uppercase",
1478
- children: /* @__PURE__ */ jsxRuntime.jsx("p", { children: node.title })
1479
- }
1480
- );
1481
- }
1482
- const bal = getBalance(node.token.symbol);
1483
- const usd = getTokenUsdValue(node.token.symbol, node.token.price?.usd);
1484
- const isSelected = selectedAssetSymbol?.toUpperCase() === node.token.symbol.toUpperCase();
1485
- return /* @__PURE__ */ jsxRuntime.jsx(
1486
- TokenRow,
1487
- {
1488
- symbol: node.token.symbol,
1489
- name: node.token.name,
1490
- isSelected: !!isSelected,
1491
- hasAnyWallet,
1492
- balance: bal,
1493
- usdValue: usd,
1494
- isBalanceLoading: balancesLoading,
1495
- onPick: () => onPick(node.token.symbol, node.willChangeSrc)
1496
- }
1497
- );
1498
- };
1499
- const getItemSize = (index) => {
1500
- const node = nodes[index];
1501
- if (node.kind === "header") {
1502
- const gap = index === 0 ? 0 : HEADER_TOP_GAP;
1503
- return HEADER_H + gap;
1504
- }
1505
- return ROW_H;
1506
- };
1507
- return /* @__PURE__ */ jsxRuntime.jsx(
1508
- reactWindow.VariableSizeList,
1509
- {
1510
- height: 480,
1511
- width: "100%",
1512
- itemCount: nodes.length,
1513
- itemSize: getItemSize,
1514
- overscanCount: 8,
1515
- style: { willChange: "transform", paddingBottom: "40px" },
1516
- children: Row
1517
- }
1518
- );
1519
- };
1520
- const TokenSelectModal = ({
1521
- isOpen,
1522
- onClose,
1523
- items,
1524
- onChangeAsset
1525
- }) => {
1526
- const { t } = useBridgeTranslation();
1527
- const {
1528
- query,
1529
- setQuery,
1530
- tab,
1531
- setTab,
1532
- isFocused,
1533
- setIsFocused,
1534
- effectiveTab,
1535
- resetState,
1536
- setFromChain,
1537
- selectedAssetSymbol,
1538
- balancesQuery,
1539
- groupedTokens,
1540
- myTokens,
1541
- getBalance,
1542
- getTokenUsdValue,
1543
- findFirstAvailableChain,
1544
- hasAnyWallet
1545
- } = useTokenSelectData(items);
1546
1336
  const handleClose = require$$0.useCallback(() => {
1547
1337
  resetState();
1548
1338
  onClose();
@@ -1559,68 +1349,41 @@ const TokenSelectModal = ({
1559
1349
  onChangeAsset(sym);
1560
1350
  handleClose();
1561
1351
  };
1562
- const virtualNodes = require$$0.useMemo(() => {
1563
- const out = [];
1352
+ const tokensToRender = require$$0.useMemo(() => {
1564
1353
  if (effectiveTab === "my") {
1565
- for (const token of myTokens) {
1566
- out.push({
1567
- kind: "token",
1568
- key: `my:${token.symbol}`,
1569
- token,
1570
- willChangeSrc: false
1571
- });
1572
- }
1573
- return out;
1354
+ return myTokens.map((token) => ({
1355
+ token,
1356
+ willChangeSrc: false
1357
+ }));
1574
1358
  }
1575
1359
  const mainTokens = [
1576
- ...groupedTokens.withBalance,
1577
- ...groupedTokens.onSrcChain
1578
- ];
1579
- for (const token of mainTokens) {
1580
- out.push({
1581
- kind: "token",
1582
- key: `main:${token.symbol}`,
1360
+ ...groupedTokens.withBalance.map((token) => ({
1583
1361
  token,
1584
1362
  willChangeSrc: false
1585
- });
1586
- }
1587
- if (groupedTokens.willChangeSrcChain.length > 0) {
1588
- out.push({
1589
- kind: "header",
1590
- key: "hdr:willChange",
1591
- title: t("bridge.willChangeSourceChain")
1592
- });
1593
- for (const token of groupedTokens.willChangeSrcChain) {
1594
- out.push({
1595
- kind: "token",
1596
- key: `will:${token.symbol}`,
1597
- token,
1598
- willChangeSrc: true
1599
- });
1600
- }
1601
- }
1602
- return out;
1603
- }, [effectiveTab, myTokens, groupedTokens, t]);
1604
- return /* @__PURE__ */ jsxRuntime.jsx(dialog.Dialog, { open: isOpen, onOpenChange: (open) => !open && handleClose(), children: /* @__PURE__ */ jsxRuntime.jsxs(dialog.DialogContent, { className: "!max-h-[80dvh] overflow-auto", children: [
1363
+ })),
1364
+ ...groupedTokens.onSrcChain.map((token) => ({
1365
+ token,
1366
+ willChangeSrc: false
1367
+ }))
1368
+ ];
1369
+ return mainTokens;
1370
+ }, [effectiveTab, myTokens, groupedTokens]);
1371
+ const willChangeSrcTokens = require$$0.useMemo(
1372
+ () => groupedTokens.willChangeSrcChain.map((token) => ({
1373
+ token,
1374
+ willChangeSrc: true
1375
+ })),
1376
+ [groupedTokens.willChangeSrcChain]
1377
+ );
1378
+ const hasNoResults = tokensToRender.length === 0 && willChangeSrcTokens.length === 0;
1379
+ return /* @__PURE__ */ jsxRuntime.jsx(dialog.Dialog, { open: isOpen, onOpenChange: (open) => !open && handleClose(), children: /* @__PURE__ */ jsxRuntime.jsxs(dialog.DialogContent, { className: "!h-[90dvh] overflow-hidden flex flex-col", children: [
1605
1380
  /* @__PURE__ */ jsxRuntime.jsx(dialog.DialogHeader, { children: /* @__PURE__ */ jsxRuntime.jsx(dialog.DialogTitle, { children: t("bridge.selectToken") }) }),
1606
- /* @__PURE__ */ jsxRuntime.jsxs(
1607
- "div",
1381
+ /* @__PURE__ */ jsxRuntime.jsx(
1382
+ SearchInput,
1608
1383
  {
1609
- className: `flex items-center gap-2.5 px-5 py-3.5 bg-input rounded-12 h-12.5 transition-all duration-200 ${isFocused ? "border border-ring" : "border border-transparent"}`,
1610
- children: [
1611
- /* @__PURE__ */ jsxRuntime.jsx(SearchIcon, { className: "size-6 text-input-icon" }),
1612
- /* @__PURE__ */ jsxRuntime.jsx(
1613
- input.Input,
1614
- {
1615
- placeholder: t("bridge.searchToken"),
1616
- 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",
1617
- value: query,
1618
- onChange: (e) => setQuery(e.target.value),
1619
- onFocus: () => setIsFocused(true),
1620
- onBlur: () => setIsFocused(false)
1621
- }
1622
- )
1623
- ]
1384
+ placeholder: t("bridge.searchToken"),
1385
+ value: query,
1386
+ onChange: setQuery
1624
1387
  }
1625
1388
  ),
1626
1389
  hasAnyWallet() && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-2", children: [
@@ -1643,20 +1406,52 @@ const TokenSelectModal = ({
1643
1406
  }
1644
1407
  )
1645
1408
  ] }),
1646
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 overflow-hidden -mx-5", children: virtualNodes.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground px-5 py-3.5", children: t("bridge.noResults") }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1409
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 overflow-auto -mx-5", children: hasNoResults ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground px-5 py-3.5", children: t("bridge.noResults") }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1647
1410
  effectiveTab === "my" && myTokens.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "leading-4 text-base font-semibold text-muted-foreground uppercase px-5 py-2", children: t("bridge.noBalancesFound") }),
1648
- /* @__PURE__ */ jsxRuntime.jsx(
1649
- VirtualizedTokenList,
1650
- {
1651
- nodes: virtualNodes,
1652
- balancesLoading: balancesQuery.isLoading || balancesQuery.isFetching,
1653
- hasAnyWallet: hasAnyWallet(),
1654
- selectedAssetSymbol,
1655
- getBalance,
1656
- getTokenUsdValue,
1657
- onPick
1658
- }
1659
- )
1411
+ tokensToRender.map(({ token, willChangeSrc }) => {
1412
+ const bal = getBalance(token.symbol);
1413
+ const usd = getTokenUsdValue(token.symbol, token.price?.usd);
1414
+ const isSelected = selectedAssetSymbol?.toUpperCase() === token.symbol.toUpperCase();
1415
+ return /* @__PURE__ */ jsxRuntime.jsx(
1416
+ TokenRow,
1417
+ {
1418
+ symbol: token.symbol,
1419
+ name: token.name,
1420
+ isSelected: !!isSelected,
1421
+ hasAnyWallet: hasAnyWallet(),
1422
+ balance: bal,
1423
+ usdValue: usd,
1424
+ isBalanceLoading: balancesQuery.isLoading || balancesQuery.isFetching,
1425
+ onPick: () => onPick(token.symbol, willChangeSrc)
1426
+ },
1427
+ `${effectiveTab}:${token.symbol}`
1428
+ );
1429
+ }),
1430
+ effectiveTab === "all" && willChangeSrcTokens.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1431
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-5 flex leading-4 text-base py-1.5 font-semibold text-muted-foreground uppercase mt-7.5", children: /* @__PURE__ */ jsxRuntime.jsx("p", { children: t("bridge.willChangeSourceChain") }) }),
1432
+ willChangeSrcTokens.map(({ token, willChangeSrc }) => {
1433
+ const bal = getBalance(token.symbol);
1434
+ const usd = getTokenUsdValue(
1435
+ token.symbol,
1436
+ token.price?.usd
1437
+ );
1438
+ const isSelected = selectedAssetSymbol?.toUpperCase() === token.symbol.toUpperCase();
1439
+ return /* @__PURE__ */ jsxRuntime.jsx(
1440
+ TokenRow,
1441
+ {
1442
+ symbol: token.symbol,
1443
+ name: token.name,
1444
+ isSelected: !!isSelected,
1445
+ hasAnyWallet: hasAnyWallet(),
1446
+ balance: bal,
1447
+ usdValue: usd,
1448
+ isBalanceLoading: balancesQuery.isLoading || balancesQuery.isFetching,
1449
+ onPick: () => onPick(token.symbol, willChangeSrc)
1450
+ },
1451
+ `will:${token.symbol}`
1452
+ );
1453
+ })
1454
+ ] })
1660
1455
  ] }) })
1661
1456
  ] }) });
1662
1457
  };
@@ -1802,7 +1597,7 @@ const FormHeaderComponent = () => {
1802
1597
  const sum = selectedAssetSymbol.toUpperCase();
1803
1598
  return assets.find((a) => a.symbol.toUpperCase() === sum) ?? assets[0];
1804
1599
  }, [assets, selectedAssetSymbol]);
1805
- return /* @__PURE__ */ jsxRuntime.jsxs(card.CardHeader, { className: "gap-y-0 flex justify-between items-center", children: [
1600
+ return /* @__PURE__ */ jsxRuntime.jsxs(card.CardHeader, { className: "gap-y-0 flex flex-row justify-between items-center", children: [
1806
1601
  /* @__PURE__ */ jsxRuntime.jsxs(card.CardTitle, { className: "flex items-center gap-2.5", children: [
1807
1602
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-normal leading-3.5 text-muted-foreground", children: t("bridge.selectToken") }),
1808
1603
  /* @__PURE__ */ jsxRuntime.jsx(SelectTokenButton, { token: current, onClick: onOpen })
@@ -1833,6 +1628,19 @@ const FormHeaderComponent = () => {
1833
1628
  ] });
1834
1629
  };
1835
1630
  const FormHeader = require$$0.memo(FormHeaderComponent);
1631
+ function toLD(human, decimals) {
1632
+ const [i = "0", f = ""] = human.replace(",", ".").split(".");
1633
+ const frac = (f + "0".repeat(decimals)).slice(0, decimals);
1634
+ return BigInt(i + frac).toString();
1635
+ }
1636
+ function fromLD(ld, decimals) {
1637
+ const bi = BigInt(ld || "0");
1638
+ if (decimals === 0) return Number(bi);
1639
+ const base = BigInt(10) ** BigInt(decimals);
1640
+ const int = bi / base;
1641
+ const frac = Number(bi % base) / Number(base);
1642
+ return Number(int) + frac;
1643
+ }
1836
1644
  async function fetchQuotes(req) {
1837
1645
  const params = {
1838
1646
  srcChainKey: req.srcChainKey,
@@ -1891,6 +1699,131 @@ async function getQuotesByPriority(req) {
1891
1699
  const priority = req.routePriority || RoutePriority.RECOMMENDED;
1892
1700
  return selectQuoteByPriority(routes, priority);
1893
1701
  }
1702
+ function resolveTokenOnChainFromMatrix$2(assetMatrix, assetSymbol, chainKey) {
1703
+ if (!assetMatrix || !assetSymbol || !chainKey) return void 0;
1704
+ const byChain = assetMatrix[assetSymbol.toUpperCase()];
1705
+ return byChain?.[chainKey];
1706
+ }
1707
+ const DEFAULT_SLIPPAGE_BPS = 50;
1708
+ const lower = (s) => (s ?? "").toLowerCase();
1709
+ const normSym = (s) => (s ?? "").toUpperCase().replace(/₮/g, "T").replace(/[^A-Z0-9]/g, "");
1710
+ function tonNorm(addr) {
1711
+ if (!addr) return null;
1712
+ try {
1713
+ if (addr.includes(":")) {
1714
+ return core.Address.parseRaw(addr).toString({
1715
+ bounceable: false,
1716
+ urlSafe: true
1717
+ });
1718
+ }
1719
+ return core.Address.parse(addr).toString({ bounceable: false, urlSafe: true });
1720
+ } catch {
1721
+ return null;
1722
+ }
1723
+ }
1724
+ const isZeroAddr = (a) => (
1725
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1726
+ !!a && /^0x0{40}$/i.test(a) || /^0x[eE]{4}e{36}$/i.test(a)
1727
+ );
1728
+ function addrForApi(chainKey, addr) {
1729
+ if (chainKey === "ton") return tonNorm(addr);
1730
+ return addr;
1731
+ }
1732
+ function isNativeAddrEqual(chain, tokenAddr) {
1733
+ if (!chain) return false;
1734
+ if (!tokenAddr) return false;
1735
+ if (isZeroAddr(tokenAddr)) return true;
1736
+ const nativeAddr = chain.nativeCurrency?.address;
1737
+ if (!nativeAddr) return false;
1738
+ if (chain.chainKey === "ton") {
1739
+ const a = tonNorm(tokenAddr);
1740
+ const b = tonNorm(nativeAddr);
1741
+ return !!a && !!b && a === b;
1742
+ }
1743
+ return lower(nativeAddr) === lower(tokenAddr);
1744
+ }
1745
+ function findNativeMeta(tokens, chain) {
1746
+ if (!chain) return { decimals: 18, priceUsd: void 0 };
1747
+ const sym = normSym(chain.nativeCurrency?.symbol);
1748
+ if (!sym) {
1749
+ return { decimals: chain.chainKey === "ton" ? 9 : 18, priceUsd: void 0 };
1750
+ }
1751
+ const sameChain = tokens?.find(
1752
+ (t) => t.chainKey === chain.chainKey && normSym(t.symbol) === sym
1753
+ ) ?? void 0;
1754
+ if (sameChain)
1755
+ return { decimals: sameChain.decimals, priceUsd: sameChain.price?.usd };
1756
+ const anyChain = tokens?.find((t) => normSym(t.symbol) === sym);
1757
+ if (anyChain)
1758
+ return { decimals: anyChain.decimals, priceUsd: anyChain.price?.usd };
1759
+ return { decimals: chain.chainKey === "ton" ? 9 : 18, priceUsd: void 0 };
1760
+ }
1761
+ function lookupTokenMeta(tokens, chains, chainKey, tokenAddr) {
1762
+ if (!chainKey) return { decimals: 18, priceUsd: void 0 };
1763
+ const chain = chains?.find((c) => c.chainKey === chainKey);
1764
+ const hit = tokens?.find((t) => {
1765
+ if (t.chainKey !== chainKey) return false;
1766
+ if (chainKey === "ton") {
1767
+ const a = tonNorm(t.address);
1768
+ const b = tonNorm(tokenAddr);
1769
+ return !!a && !!b && a === b;
1770
+ }
1771
+ return lower(t.address) === lower(tokenAddr);
1772
+ }) ?? void 0;
1773
+ if (hit) return { decimals: hit.decimals, priceUsd: hit.price?.usd };
1774
+ if (isNativeAddrEqual(chain, tokenAddr)) {
1775
+ return findNativeMeta(tokens, chain);
1776
+ }
1777
+ return { decimals: chainKey === "ton" ? 9 : 18, priceUsd: void 0 };
1778
+ }
1779
+ function computeFeesUsdFromArray(fees, tokens, chains) {
1780
+ if (!fees?.length) return { totalUsd: 0 };
1781
+ let total = 0;
1782
+ let protocolFeeUsd = 0;
1783
+ let messageFeeUsd = 0;
1784
+ const byType = /* @__PURE__ */ new Map();
1785
+ for (const f of fees) {
1786
+ let usd = Number(f.usd ?? 0);
1787
+ if (!usd) {
1788
+ const { decimals, priceUsd } = lookupTokenMeta(
1789
+ tokens,
1790
+ chains,
1791
+ f.chainKey,
1792
+ f.token
1793
+ );
1794
+ const human = fromLD(String(f.amount ?? "0"), decimals);
1795
+ usd = (priceUsd ?? 0) * human;
1796
+ }
1797
+ total += usd;
1798
+ const type = (f.type ?? "other").toLowerCase();
1799
+ byType.set(type, (byType.get(type) ?? 0) + usd);
1800
+ if (type === "protocol" || type === "service") {
1801
+ protocolFeeUsd += usd;
1802
+ } else if (type === "message" || type === "gas" || type === "network") {
1803
+ messageFeeUsd += usd;
1804
+ }
1805
+ }
1806
+ const serviceUsd = byType.get("protocol") ?? byType.get("service") ?? void 0;
1807
+ const blockchainUsd = byType.get("gas") ?? byType.get("network") ?? byType.get("message") ?? void 0;
1808
+ return {
1809
+ totalUsd: total,
1810
+ protocolFeeUsd: protocolFeeUsd > 0 ? protocolFeeUsd : void 0,
1811
+ messageFeeUsd: messageFeeUsd > 0 ? messageFeeUsd : void 0,
1812
+ serviceUsd,
1813
+ blockchainUsd
1814
+ };
1815
+ }
1816
+ function sumFeeByTokenLD(fees, dstTokenAddr, dstChainKey) {
1817
+ if (!fees?.length || !dstTokenAddr || !dstChainKey) return "0";
1818
+ let acc = 0n;
1819
+ for (const f of fees) {
1820
+ if (f.chainKey !== dstChainKey) continue;
1821
+ const same = dstChainKey === "ton" ? tonNorm(f.token) === tonNorm(dstTokenAddr) : lower(f.token) === lower(dstTokenAddr);
1822
+ if (!same) continue;
1823
+ acc += BigInt(f.amount ?? "0");
1824
+ }
1825
+ return acc.toString();
1826
+ }
1894
1827
  function useBridgeQuote() {
1895
1828
  const { assetMatrix, selectedAssetSymbol } = useTokensStore();
1896
1829
  const { fromChain, toChain } = useChainsStore();
@@ -2391,12 +2324,10 @@ const ChainSelectModal = ({
2391
2324
  }) => {
2392
2325
  const { t } = useBridgeTranslation();
2393
2326
  const [query, setQuery] = require$$0.useState("");
2394
- const [isFocused, setIsFocused] = require$$0.useState(false);
2395
2327
  const { setFromChain, chains, fromChain, toChain } = useChainsStore();
2396
2328
  const { assetMatrix, selectedAssetSymbol } = useTokensStore();
2397
2329
  const handleClose = require$$0.useCallback(() => {
2398
2330
  setQuery("");
2399
- setIsFocused(false);
2400
2331
  onClose();
2401
2332
  }, [onClose]);
2402
2333
  const findCompatibleSrcChain = require$$0.useCallback(
@@ -2456,7 +2387,7 @@ const ChainSelectModal = ({
2456
2387
  button.Button,
2457
2388
  {
2458
2389
  onClick: () => onChainPick(chain, willChangeSrc),
2459
- className: `w-full cursor-pointer flex shadow-none items-center justify-between gap-2.5 px-5 py-3.5 h-12.5 font-extrabold capitalize hover:bg-muted bg-transparent rounded-12 transition-[300] ${isSelected ? "border border-ring" : ""}`,
2390
+ className: `w-full cursor-pointer flex shadow-none items-center justify-between gap-2.5 px-5 py-3.5 h-12.5 font-extrabold capitalize hover:bg-muted bg-transparent rounded-md transition-[300] ${isSelected ? "border border-ring" : ""}`,
2460
2391
  children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2.5", children: [
2461
2392
  /* @__PURE__ */ jsxRuntime.jsx(
2462
2393
  NetworkSymbol,
@@ -2472,26 +2403,16 @@ const ChainSelectModal = ({
2472
2403
  chain.chainKey
2473
2404
  );
2474
2405
  };
2475
- return /* @__PURE__ */ jsxRuntime.jsx(dialog.Dialog, { open: isOpen, onOpenChange: (open) => !open && handleClose(), children: /* @__PURE__ */ jsxRuntime.jsxs(dialog.DialogContent, { className: "!max-h-[80dvh] overflow-hidden", children: [
2406
+ return /* @__PURE__ */ jsxRuntime.jsx(dialog.Dialog, { open: isOpen, onOpenChange: (open) => !open && handleClose(), children: /* @__PURE__ */ jsxRuntime.jsxs(dialog.DialogContent, { className: "!h-[90dvh] flex flex-col", children: [
2476
2407
  /* @__PURE__ */ jsxRuntime.jsx(dialog.DialogHeader, { children: /* @__PURE__ */ jsxRuntime.jsx(dialog.DialogTitle, { children: t("bridge.selectNetwork") }) }),
2477
- /* @__PURE__ */ jsxRuntime.jsxs(
2478
- "div",
2408
+ /* @__PURE__ */ jsxRuntime.jsx(
2409
+ SearchInput,
2479
2410
  {
2480
- className: `flex items-center gap-2.5 px-5 py-3.5 bg-input rounded-md h-12.5 transition-all duration-200 ${isFocused ? "border border-ring" : "border border-transparent"}`,
2481
- children: [
2482
- /* @__PURE__ */ jsxRuntime.jsx(SearchIcon, { className: "size-6 text-muted-foreground" }),
2483
- /* @__PURE__ */ jsxRuntime.jsx(
2484
- input.Input,
2485
- {
2486
- placeholder: t("bridge.searchDestinationChain"),
2487
- className: "w-full outline-none leading-0 p-0 h-6 text-base text-foreground placeholder:text-muted-foreground bg-none dark:bg-transparent",
2488
- value: query,
2489
- onChange: (e) => setQuery(e.target.value),
2490
- onFocus: () => setIsFocused(true),
2491
- onBlur: () => setIsFocused(false)
2492
- }
2493
- )
2494
- ]
2411
+ placeholder: t("bridge.searchDestinationChain"),
2412
+ value: query,
2413
+ onChange: setQuery,
2414
+ containerClassName: "rounded-md",
2415
+ className: "text-foreground placeholder:text-muted-foreground"
2495
2416
  }
2496
2417
  ),
2497
2418
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 overflow-y-auto", children: [
@@ -2706,63 +2627,30 @@ const useCustomAddressStore = zustand.create((set) => ({
2706
2627
  setCustomDstAddress: (address) => set({ customDstAddress: address }),
2707
2628
  clearCustomDstAddress: () => set({ customDstAddress: void 0 })
2708
2629
  }));
2709
- const tonNormalize = (addr) => {
2710
- if (!addr) return null;
2711
- try {
2712
- if (addr.includes(":")) {
2713
- return core.Address.parseRaw(addr).toString({
2714
- bounceable: false,
2715
- urlSafe: true
2716
- });
2717
- }
2718
- return core.Address.parse(addr).toString({ bounceable: false, urlSafe: true });
2719
- } catch {
2720
- return null;
2721
- }
2630
+ const useIsAddressValid = (address, chainKey) => {
2631
+ const isValid = require$$0.useMemo(() => {
2632
+ return isAddressValidForChain(chainKey, address);
2633
+ }, [address, chainKey]);
2634
+ return { isValid };
2722
2635
  };
2723
- const ToggleRow = ({ enabled, onToggle }) => {
2636
+ const AnotherAddress = () => {
2637
+ const [enabled, setEnabled] = require$$0.useState(false);
2638
+ const [isFocused, setIsFocused] = require$$0.useState(false);
2724
2639
  const { t } = useBridgeTranslation();
2725
2640
  const { toChain } = useChainsStore();
2726
- const { dstAddress } = useAddresses();
2727
- const { setCustomDstAddress, clearCustomDstAddress } = useCustomAddressStore();
2641
+ const { setCustomDstAddress } = useCustomAddressStore();
2728
2642
  const [value, setValue] = require$$0.useState("");
2729
- const [invalid, setInvalid] = require$$0.useState(false);
2730
- const prevDstRef = require$$0.useRef(void 0);
2731
- const prevEnabledRef = require$$0.useRef(enabled);
2732
- require$$0.useEffect(() => {
2733
- const wasEnabled = prevEnabledRef.current;
2734
- if (enabled && !wasEnabled) {
2735
- prevDstRef.current = dstAddress;
2736
- setValue(dstAddress ?? "");
2737
- setInvalid(false);
2738
- }
2739
- if (!enabled && wasEnabled) {
2740
- clearCustomDstAddress();
2741
- setInvalid(false);
2742
- }
2743
- prevEnabledRef.current = enabled;
2744
- }, [enabled]);
2643
+ const { isValid } = useIsAddressValid(value.trim(), toChain?.chainKey);
2644
+ const invalid = value.trim() && !isValid;
2745
2645
  const pushToStoreIfValid = (raw) => {
2746
2646
  if (!enabled) return;
2747
2647
  const v = raw.trim();
2748
2648
  if (!v) {
2749
2649
  setCustomDstAddress(void 0);
2750
- setInvalid(false);
2751
- return;
2752
- }
2753
- const ck = toChain?.chainKey;
2754
- if (!ck) {
2755
- setInvalid(true);
2756
2650
  return;
2757
2651
  }
2758
- const valueForStore = ck === "ton" ? tonNormalize(v) ?? void 0 : v;
2759
- const valid = isAddressValidForChain(ck, valueForStore ?? "");
2760
- if (valid && valueForStore) {
2761
- setInvalid(false);
2762
- setCustomDstAddress(valueForStore);
2763
- if (ck === "ton") setValue(valueForStore);
2764
- } else {
2765
- setInvalid(true);
2652
+ if (isValid) {
2653
+ setCustomDstAddress(v);
2766
2654
  }
2767
2655
  };
2768
2656
  const onChange = (text) => {
@@ -2777,7 +2665,7 @@ const ToggleRow = ({ enabled, onToggle }) => {
2777
2665
  } catch {
2778
2666
  }
2779
2667
  };
2780
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-4 flex flex-col rounded-b-lg gap-2 bg-muted", children: [
2668
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-4 flex flex-col rounded-b-lg bg-muted", children: [
2781
2669
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
2782
2670
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm leading-4.5 font-medium text-muted-foreground", children: t("bridge.sendToAnotherAddress") }),
2783
2671
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -2786,7 +2674,7 @@ const ToggleRow = ({ enabled, onToggle }) => {
2786
2674
  className: "data-[state=unchecked]:bg-switch-inactive data-[state=checked]:bg-switch-active",
2787
2675
  "aria-pressed": enabled,
2788
2676
  checked: enabled,
2789
- onClick: onToggle
2677
+ onClick: () => setEnabled((v) => !v)
2790
2678
  }
2791
2679
  )
2792
2680
  ] }),
@@ -2801,16 +2689,27 @@ const ToggleRow = ({ enabled, onToggle }) => {
2801
2689
  children: /* @__PURE__ */ jsxRuntime.jsxs(
2802
2690
  "div",
2803
2691
  {
2804
- className: `bg-input py-2 px-4 w-full flex items-center gap-4 rounded-12 justify-between border ${invalid ? "border-destructive" : "border-transparent"}`,
2692
+ className: utils.cn(
2693
+ "bg-input py-2 px-4 mt-2 w-full flex items-center gap-4 rounded-md justify-between border border-transparent transition-all",
2694
+ {
2695
+ "py-4": value,
2696
+ "border border-ring": isFocused,
2697
+ "border-destructive": invalid
2698
+ }
2699
+ ),
2805
2700
  children: [
2806
2701
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1.5 w-full", children: [
2807
2702
  /* @__PURE__ */ jsxRuntime.jsx(
2808
2703
  input.Input,
2809
2704
  {
2810
- className: "p-0 h-auto text-base leading-5 font-semibold w-full bg-transparent dark:bg-transparent placeholder:text-input-placeholder text-input-text border-none",
2811
- placeholder: toChain?.chainKey === "ton" ? t("bridge.tonAddressPlaceholder") : t("bridge.evmAddressPlaceholder"),
2705
+ className: utils.cn(
2706
+ "p-0 h-auto text-base leading-5 font-semibold w-full bg-transparent dark:bg-transparent placeholder:text-muted-foreground/50 border-none"
2707
+ ),
2708
+ placeholder: t("bridge.anotherAddressPlaceholder"),
2812
2709
  type: "text",
2813
2710
  value,
2711
+ onFocus: () => setIsFocused(true),
2712
+ onBlur: () => setIsFocused(false),
2814
2713
  onChange: (e) => onChange(e.target.value)
2815
2714
  }
2816
2715
  ),
@@ -2820,21 +2719,14 @@ const ToggleRow = ({ enabled, onToggle }) => {
2820
2719
  defaultValue: "Check correctness before transfer"
2821
2720
  }) }) })
2822
2721
  ] }),
2823
- !value ? /* @__PURE__ */ jsxRuntime.jsx(
2824
- button.Button,
2825
- {
2826
- variant: "default",
2827
- 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",
2828
- onClick: onPaste,
2829
- children: t("common.paste")
2830
- }
2831
- ) : /* @__PURE__ */ jsxRuntime.jsx(
2722
+ !value ? /* @__PURE__ */ jsxRuntime.jsx(button.Button, { variant: "secondary", size: "sm", onClick: onPaste, children: t("common.paste") }) : /* @__PURE__ */ jsxRuntime.jsx(
2832
2723
  button.Button,
2833
2724
  {
2834
2725
  variant: "ghost",
2835
- className: "h-5 w-5 self-start\n bg-input-x-bg hover:bg-input-x-bg \n p-0.5 m-0 rounded-full\n border-0 shadow-none\n focus:outline-none focus:ring-0 has-[>svg]:px-0",
2726
+ size: "sm",
2727
+ className: "rounded-full p-0 size-5 self-start",
2836
2728
  onClick: () => setValue(""),
2837
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "size-3 text-input-x" })
2729
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "size-4" })
2838
2730
  }
2839
2731
  )
2840
2732
  ]
@@ -3812,7 +3704,7 @@ const WalletSelectModal = () => {
3812
3704
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "py-2 font-semibold text-muted-foreground uppercase", children: t("wallets.connected") }),
3813
3705
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "", children: connectedWallets.map((wallet) => {
3814
3706
  const IconComponent = wallet.icon;
3815
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "-mx-5", children: /* @__PURE__ */ jsxRuntime.jsxs(button.Button, { className: "w-full cursor-pointer bg-transparent flex shadow-none items-center justify-between gap-2.5 px-5 py-2.5 hover:bg-muted h-auto rounded-12 transition-[300]", children: [
3707
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "-mx-5", children: /* @__PURE__ */ jsxRuntime.jsxs(button.Button, { className: "w-full cursor-pointer bg-transparent flex shadow-none items-center justify-between gap-2.5 px-5 py-2.5 hover:bg-muted h-auto rounded-md transition-[300]", children: [
3816
3708
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-3 min-w-0", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2.5", children: [
3817
3709
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-7.5 h-7.5 flex items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(IconComponent, { className: "size-7.5" }) }),
3818
3710
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-start min-w-0", children: [
@@ -3853,7 +3745,7 @@ const WalletSelectModal = () => {
3853
3745
  }
3854
3746
  },
3855
3747
  disabled: isEvmConnector ? isPending : !wallet.enabled,
3856
- className: "w-full cursor-pointer bg-transparent flex shadow-none items-center justify-between gap-2.5 px-5 py-2.5 hover:bg-muted h-auto rounded-12 transition-[300] disabled:opacity-50 disabled:cursor-not-allowed",
3748
+ className: "w-full cursor-pointer bg-transparent flex shadow-none items-center justify-between gap-2.5 px-5 py-2.5 hover:bg-muted h-auto rounded-md transition-[300] disabled:opacity-50 disabled:cursor-not-allowed",
3857
3749
  children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 min-w-0", children: [
3858
3750
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-7.5 h-7.5 flex items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(IconComponent, { className: "size-7.5" }) }),
3859
3751
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-start min-w-0", children: [
@@ -5904,7 +5796,7 @@ class ChainStrategyRegistry {
5904
5796
  async getBalances(chainKey, address, tokens, priorityToken) {
5905
5797
  const strategy = this.getStrategy(chainKey);
5906
5798
  if (!strategy) return {};
5907
- return await strategy.getBalances(address, tokens, priorityToken);
5799
+ return await strategy.getBalances(address, tokens, chainKey, priorityToken);
5908
5800
  }
5909
5801
  isAddressValid(chainKey, address) {
5910
5802
  const strategy = this.getStrategy(chainKey);
@@ -6015,14 +5907,9 @@ function parseTonAddress(address) {
6015
5907
  }
6016
5908
  return ton.Address.parse(address);
6017
5909
  }
6018
- async function getEvmBalances(publicClient, address, tokens, priorityToken) {
5910
+ async function getEvmBalances(publicClient, address, tokens, chainKey, priorityToken) {
6019
5911
  const balances = {};
6020
5912
  try {
6021
- console.log("start getEvmBalances");
6022
- console.log("publicClient:", publicClient);
6023
- console.log("isAddress:", viem.isAddress(address));
6024
- console.log("tokens:", tokens);
6025
- console.log("priorityToken:", priorityToken);
6026
5913
  if (!address || !viem.isAddress(address)) {
6027
5914
  console.warn(`Invalid EVM address provided: ${address}`);
6028
5915
  return balances;
@@ -6031,40 +5918,55 @@ async function getEvmBalances(publicClient, address, tokens, priorityToken) {
6031
5918
  throw new Error("No public client provided");
6032
5919
  }
6033
5920
  const nativeTokens = tokens.filter((t) => isNativeAddress(t.address));
6034
- const erc20Tokens = tokens.filter((t) => !isNativeAddress(t.address) && viem.isAddress(t.address));
5921
+ const erc20Tokens = tokens.filter(
5922
+ (t) => !isNativeAddress(t.address) && viem.isAddress(t.address)
5923
+ );
6035
5924
  if (priorityToken) {
6036
- try {
6037
- const isPriorityNative = isNativeAddress(priorityToken.address);
6038
- if (isPriorityNative) {
6039
- const ethBalance = await publicClient.getBalance({
6040
- address
6041
- });
6042
- const balance = parseFloat(viem.formatUnits(ethBalance, priorityToken.decimals));
6043
- if (balance > 0) {
6044
- balances[priorityToken.symbol] = { balance, address };
6045
- }
6046
- } else if (viem.isAddress(priorityToken.address)) {
6047
- const tokenBalance = await publicClient.readContract({
6048
- address: priorityToken.address,
6049
- abi: [
6050
- {
6051
- name: "balanceOf",
6052
- type: "function",
6053
- stateMutability: "view",
6054
- inputs: [{ name: "owner", type: "address" }],
6055
- outputs: [{ name: "balance", type: "uint256" }]
6056
- }
6057
- ],
6058
- functionName: "balanceOf",
6059
- args: [address]
6060
- });
6061
- const balance = parseFloat(viem.formatUnits(tokenBalance, priorityToken.decimals));
6062
- if (balance > 0) {
6063
- balances[priorityToken.symbol] = { balance, address };
5925
+ if (priorityToken.chainKey !== chainKey) {
5926
+ console.debug(
5927
+ `Skipping priority token ${priorityToken.symbol}: chain mismatch (expected ${chainKey}, got ${priorityToken.chainKey})`
5928
+ );
5929
+ } else {
5930
+ try {
5931
+ const isPriorityNative = isNativeAddress(priorityToken.address);
5932
+ if (isPriorityNative) {
5933
+ const ethBalance = await publicClient.getBalance({
5934
+ address
5935
+ });
5936
+ const balance = parseFloat(
5937
+ viem.formatUnits(ethBalance, priorityToken.decimals)
5938
+ );
5939
+ if (balance > 0) {
5940
+ balances[priorityToken.symbol] = { balance, address };
5941
+ }
5942
+ } else if (viem.isAddress(priorityToken.address)) {
5943
+ const tokenBalance = await publicClient.readContract({
5944
+ address: priorityToken.address,
5945
+ abi: [
5946
+ {
5947
+ name: "balanceOf",
5948
+ type: "function",
5949
+ stateMutability: "view",
5950
+ inputs: [{ name: "owner", type: "address" }],
5951
+ outputs: [{ name: "balance", type: "uint256" }]
5952
+ }
5953
+ ],
5954
+ functionName: "balanceOf",
5955
+ args: [address]
5956
+ });
5957
+ const balance = parseFloat(
5958
+ viem.formatUnits(tokenBalance, priorityToken.decimals)
5959
+ );
5960
+ if (balance > 0) {
5961
+ balances[priorityToken.symbol] = { balance, address };
5962
+ }
6064
5963
  }
5964
+ } catch (error) {
5965
+ console.debug(
5966
+ `Failed to get priority token balance for ${priorityToken.symbol}:`,
5967
+ error
5968
+ );
6065
5969
  }
6066
- } catch (error) {
6067
- console.debug(`Failed to get priority token balance for ${priorityToken.symbol}:`, error);
6068
5970
  }
6069
5971
  }
6070
5972
  for (const token of nativeTokens) {
@@ -6077,7 +5979,10 @@ async function getEvmBalances(publicClient, address, tokens, priorityToken) {
6077
5979
  balances[token.symbol] = { balance, address };
6078
5980
  }
6079
5981
  } catch (error) {
6080
- console.debug(`Failed to get native balance for ${token.symbol}:`, error);
5982
+ console.debug(
5983
+ `Failed to get native balance for ${token.symbol}:`,
5984
+ error
5985
+ );
6081
5986
  }
6082
5987
  }
6083
5988
  if (erc20Tokens.length > 0) {
@@ -6105,17 +6010,25 @@ async function getEvmBalances(publicClient, address, tokens, priorityToken) {
6105
6010
  if (!token) return;
6106
6011
  if (result.status === "success" && result.result !== void 0) {
6107
6012
  try {
6108
- const balance = parseFloat(viem.formatUnits(result.result, token.decimals));
6013
+ const balance = parseFloat(
6014
+ viem.formatUnits(result.result, token.decimals)
6015
+ );
6109
6016
  if (balance > 0) {
6110
6017
  balances[token.symbol] = { balance, address };
6111
6018
  }
6112
6019
  } catch (error) {
6113
- console.debug(`Failed to parse balance for ${token.symbol}:`, error);
6020
+ console.debug(
6021
+ `Failed to parse balance for ${token.symbol}:`,
6022
+ error
6023
+ );
6114
6024
  }
6115
6025
  }
6116
6026
  });
6117
6027
  } catch (error) {
6118
- console.warn("Multicall failed, falling back to individual calls:", error);
6028
+ console.warn(
6029
+ "Multicall failed, falling back to individual calls:",
6030
+ error
6031
+ );
6119
6032
  for (const token of erc20Tokens) {
6120
6033
  try {
6121
6034
  const tokenBalance = await publicClient.readContract({
@@ -6149,7 +6062,7 @@ async function getEvmBalances(publicClient, address, tokens, priorityToken) {
6149
6062
  }
6150
6063
  return balances;
6151
6064
  }
6152
- async function getTonBalances(address, tokens, customTonClient, tonApiKey) {
6065
+ async function getTonBalances(address, tokens, chainKey, customTonClient, tonApiKey) {
6153
6066
  const balances = {};
6154
6067
  try {
6155
6068
  if (!isTonFriendlyAddress(address)) {
@@ -6308,13 +6221,18 @@ class EvmChainStrategy {
6308
6221
  getConnectLabel(t) {
6309
6222
  return t("wallets.connectEvmWallet");
6310
6223
  }
6311
- async getBalances(address, tokens, priorityToken) {
6224
+ async getBalances(address, tokens, chainKey, priorityToken) {
6312
6225
  if (!this.publicClient) {
6313
6226
  console.warn("No publicClient available for balance query");
6314
6227
  return {};
6315
6228
  }
6316
- console.log("publicClient", this.publicClient);
6317
- return await getEvmBalances(this.publicClient, address, tokens, priorityToken);
6229
+ return await getEvmBalances(
6230
+ this.publicClient,
6231
+ address,
6232
+ tokens,
6233
+ chainKey,
6234
+ priorityToken
6235
+ );
6318
6236
  }
6319
6237
  isAddressValid(address) {
6320
6238
  if (!address) return false;
@@ -6670,10 +6588,11 @@ class TonChainStrategy {
6670
6588
  getConnectLabel(t) {
6671
6589
  return t("wallets.connectTonWallet");
6672
6590
  }
6673
- async getBalances(address, tokens) {
6591
+ async getBalances(address, tokens, chainKey) {
6674
6592
  return await getTonBalances(
6675
6593
  address,
6676
6594
  tokens,
6595
+ chainKey,
6677
6596
  this.config.tonClient,
6678
6597
  this.config.tonApiKey
6679
6598
  );
@@ -6882,7 +6801,6 @@ class TronChainStrategy {
6882
6801
  __publicField(this, "config");
6883
6802
  this.config = config;
6884
6803
  }
6885
- // ========== Identity ==========
6886
6804
  canHandle(chainKey) {
6887
6805
  return chainKey.toLowerCase() === "tron";
6888
6806
  }
@@ -6892,7 +6810,6 @@ class TronChainStrategy {
6892
6810
  getName() {
6893
6811
  return "TRON Chain Strategy";
6894
6812
  }
6895
- // ========== Wallet Management ==========
6896
6813
  async connect() {
6897
6814
  const tronWeb = this.getTronWeb();
6898
6815
  if (!tronWeb && (typeof window === "undefined" || !window.tronLink)) {
@@ -6923,7 +6840,6 @@ class TronChainStrategy {
6923
6840
  getConnectLabel(t) {
6924
6841
  return t("wallets.connectTronWallet");
6925
6842
  }
6926
- // ========== Balance & Validation ==========
6927
6843
  async getBalances(address, tokens) {
6928
6844
  const tronWeb = this.getTronWeb();
6929
6845
  if (!tronWeb) return {};
@@ -6933,7 +6849,6 @@ class TronChainStrategy {
6933
6849
  if (!address) return false;
6934
6850
  return /^T[1-9A-HJ-NP-Za-km-z]{33}$/.test(address);
6935
6851
  }
6936
- // ========== Gas Estimation ==========
6937
6852
  async estimateGasRequirement(params) {
6938
6853
  const {
6939
6854
  selectedToken,
@@ -7616,7 +7531,6 @@ const EvaaBridgeContent = ({
7616
7531
  const { t } = useBridgeTranslation();
7617
7532
  useTokensRequest();
7618
7533
  useChainsRequest();
7619
- const [sendToAnother, setSendToAnother] = require$$0.useState(false);
7620
7534
  const swap = useSwapModel();
7621
7535
  const { fromChain, toChain } = swap;
7622
7536
  const { selectedAssetSymbol, assetMatrix } = useTokensStore();
@@ -7744,13 +7658,7 @@ const EvaaBridgeContent = ({
7744
7658
  onSelect: handleToChainChange
7745
7659
  }
7746
7660
  ),
7747
- /* @__PURE__ */ jsxRuntime.jsx(
7748
- ToggleRow,
7749
- {
7750
- enabled: sendToAnother,
7751
- onToggle: () => setSendToAnother((v) => !v)
7752
- }
7753
- ),
7661
+ /* @__PURE__ */ jsxRuntime.jsx(AnotherAddress, {}),
7754
7662
  /* @__PURE__ */ jsxRuntime.jsx(SubmitButton, {})
7755
7663
  ] }),
7756
7664
  /* @__PURE__ */ jsxRuntime.jsx(card.CardFooter, { children: /* @__PURE__ */ jsxRuntime.jsx(Details, {}) })
@@ -7825,7 +7733,6 @@ exports.addrForApi = addrForApi;
7825
7733
  exports.buildAssetMatrix = buildAssetMatrix;
7826
7734
  exports.calculateMinReceived = calculateMinReceived;
7827
7735
  exports.computeFeesUsdFromArray = computeFeesUsdFromArray;
7828
- exports.dollarsFromNativeFees = dollarsFromNativeFees;
7829
7736
  exports.findNativeMeta = findNativeMeta;
7830
7737
  exports.formatBalance = formatBalance;
7831
7738
  exports.formatHash = formatHash;
@@ -7844,10 +7751,7 @@ exports.getQuotesByPriority = getQuotesByPriority;
7844
7751
  exports.getTokens = getTokens;
7845
7752
  exports.getTonBalances = getTonBalances;
7846
7753
  exports.getTronBalances = getTronBalances;
7847
- exports.isAddressValidForChain = isAddressValidForChain;
7848
- exports.isEvmAddress = isEvmAddress;
7849
7754
  exports.isNativeAddrEqual = isNativeAddrEqual;
7850
- exports.isTronAddress = isTronAddress;
7851
7755
  exports.isZeroAddr = isZeroAddr;
7852
7756
  exports.listAssetsForSelect = listAssetsForSelect;
7853
7757
  exports.lookupTokenMeta = lookupTokenMeta;