@rash2x/bridge-widget 0.1.12 → 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.
- package/README.md +5 -2
- package/dist/evaa-bridge.cjs +541 -563
- package/dist/evaa-bridge.cjs.map +1 -1
- package/dist/evaa-bridge.mjs +539 -561
- package/dist/evaa-bridge.mjs.map +1 -1
- package/dist/index.d.ts +3 -10
- package/package.json +1 -1
package/dist/evaa-bridge.mjs
CHANGED
|
@@ -2,32 +2,97 @@ 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 {
|
|
6
|
-
import
|
|
5
|
+
import require$$0, { useEffect, useState, useCallback, useMemo, createContext, useContext, memo, forwardRef } from "react";
|
|
6
|
+
import { initReactI18next, useTranslation, I18nextProvider } from "react-i18next";
|
|
7
|
+
import i18n, { t } from "i18next";
|
|
7
8
|
import { create as create$1 } from "zustand";
|
|
8
9
|
import { Button } from "@/components/ui/button";
|
|
9
10
|
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription } from "@/components/ui/dialog";
|
|
11
|
+
import { Badge } from "@/components/ui/badge";
|
|
10
12
|
import { Tooltip, TooltipTrigger, TooltipContent } from "@/components/ui/tooltip";
|
|
11
13
|
import { cn } from "@/lib/utils";
|
|
12
|
-
import {
|
|
14
|
+
import { Skeleton } from "@/components/ui/skeleton";
|
|
13
15
|
import { useAccount, useConnect, useDisconnect, useWalletClient, usePublicClient } from "wagmi";
|
|
14
16
|
import { useWallet } from "@tronweb3/tronwallet-adapter-react-hooks";
|
|
15
17
|
import { useTonAddress, useTonConnectUI } from "@tonconnect/ui-react";
|
|
16
18
|
import { useQuery, useQueryClient } from "@tanstack/react-query";
|
|
17
19
|
import { Address, beginCell as beginCell$1, storeMessage, loadMessage, Cell } from "@ton/core";
|
|
18
|
-
import {
|
|
19
|
-
import { Skeleton } from "@/components/ui/skeleton";
|
|
20
|
+
import { Input } from "@/components/ui/input";
|
|
20
21
|
import { CardHeader, CardTitle, CardAction, Card, CardContent, CardFooter } from "@/components/ui/card";
|
|
21
22
|
import { Switch } from "@/components/ui/switch";
|
|
22
23
|
import { X } from "lucide-react";
|
|
23
24
|
import { AnimatePresence, motion } from "framer-motion";
|
|
24
25
|
import { Accordion, AccordionItem, AccordionTrigger, AccordionContent } from "@/components/ui/accordion";
|
|
25
|
-
import { t } from "i18next";
|
|
26
26
|
import { toast, Toaster } from "sonner";
|
|
27
27
|
import { BrowserProvider, Contract, parseUnits } from "ethers";
|
|
28
28
|
import { isAddress, formatUnits } from "viem";
|
|
29
29
|
import { TonClient, Address as Address$1, beginCell } from "@ton/ton";
|
|
30
30
|
import { TronLinkAdapterName } from "@tronweb3/tronwallet-adapters";
|
|
31
|
+
const common$1 = { "connecting": "Connecting…", "initializing": "Initializing...", "loading": "Loading...", "paste": "paste", "close": "Close", "zeroPlaceholder": "0", "nativeToken": "Native Token" };
|
|
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", "anotherAddressPlaceholder": "Address", "addressDoesntMatch": "Address doesn't match the {{network}} network", "checkBeforeTransfer": "Check correctness before transfer" };
|
|
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
|
+
const app$1 = { "stargateWidgetName": "Stargate Bridge Widget", "liveWidget": "Live Widget", "getStarted": "Get Started" };
|
|
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" } };
|
|
37
|
+
const en = {
|
|
38
|
+
common: common$1,
|
|
39
|
+
wallets: wallets$1,
|
|
40
|
+
bridge: bridge$1,
|
|
41
|
+
transaction: transaction$1,
|
|
42
|
+
app: app$1,
|
|
43
|
+
settings: settings$1
|
|
44
|
+
};
|
|
45
|
+
const common = { "connecting": "Подключение…", "initializing": "Инициализация...", "loading": "Загрузка...", "paste": "вставить", "close": "Закрыть", "zeroPlaceholder": "0", "nativeToken": "Нативный токен" };
|
|
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": "Вы получите", "anotherAddressPlaceholder": "Адрес", "addressDoesntMatch": "Адрес не соответствует сети {{network}}", "checkBeforeTransfer": "Проверьте корректность перед переводом" };
|
|
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
|
+
const app = { "stargateWidgetName": "Виджет Stargate Bridge", "liveWidget": "Живой виджет", "getStarted": "Начало работы" };
|
|
50
|
+
const settings = { "title": "Настройки", "gasOnDestination": "Газ на назначении", "slippageTolerance": "Толерантность к проскальзыванию", "routePriority": "Приоритет маршрута", "highSlippageWarning": "Высокое проскальзывание", "gasPresets": { "auto": "Авто", "none": "Нет", "medium": "Средний", "max": "Макс" }, "routePresets": { "fastest": "Быстрейший", "cheapest": "Дешевейший", "recommended": "Рекомендуемый" } };
|
|
51
|
+
const ru = {
|
|
52
|
+
common,
|
|
53
|
+
wallets,
|
|
54
|
+
bridge,
|
|
55
|
+
transaction,
|
|
56
|
+
app,
|
|
57
|
+
settings
|
|
58
|
+
};
|
|
59
|
+
const bridgeI18n = i18n.createInstance();
|
|
60
|
+
const resources = {
|
|
61
|
+
en: {
|
|
62
|
+
"evaa-bridge": en
|
|
63
|
+
},
|
|
64
|
+
ru: {
|
|
65
|
+
"evaa-bridge": ru
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
bridgeI18n.use(initReactI18next).init({
|
|
69
|
+
resources,
|
|
70
|
+
lng: "en",
|
|
71
|
+
// Will be overridden by defaultLanguage prop
|
|
72
|
+
fallbackLng: "en",
|
|
73
|
+
debug: false,
|
|
74
|
+
// Use a dedicated namespace to avoid conflicts
|
|
75
|
+
defaultNS: "evaa-bridge",
|
|
76
|
+
ns: ["evaa-bridge"],
|
|
77
|
+
interpolation: {
|
|
78
|
+
escapeValue: false
|
|
79
|
+
// react already does escaping
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
function BridgeI18nProvider({
|
|
83
|
+
children,
|
|
84
|
+
defaultLanguage = "en"
|
|
85
|
+
}) {
|
|
86
|
+
useEffect(() => {
|
|
87
|
+
if (bridgeI18n.language !== defaultLanguage) {
|
|
88
|
+
bridgeI18n.changeLanguage(defaultLanguage);
|
|
89
|
+
}
|
|
90
|
+
}, [defaultLanguage]);
|
|
91
|
+
return /* @__PURE__ */ jsx(I18nextProvider, { i18n: bridgeI18n, children });
|
|
92
|
+
}
|
|
93
|
+
function useBridgeTranslation() {
|
|
94
|
+
return useTranslation("evaa-bridge", { i18n: bridgeI18n });
|
|
95
|
+
}
|
|
31
96
|
const norm = (s) => (s ?? "").toUpperCase().replace(/₮/g, "T").replace(/[^A-Z0-9]/g, "");
|
|
32
97
|
const POPULAR_ORDER = [
|
|
33
98
|
"USDT",
|
|
@@ -808,7 +873,7 @@ const routePresets = [
|
|
|
808
873
|
RoutePriority.RECOMMENDED
|
|
809
874
|
];
|
|
810
875
|
const SettingModal = ({ isOpen, onClose }) => {
|
|
811
|
-
const { t: t2 } =
|
|
876
|
+
const { t: t2 } = useBridgeTranslation();
|
|
812
877
|
const { toChain } = useChainsStore();
|
|
813
878
|
const { tokens } = useTokensStore();
|
|
814
879
|
const {
|
|
@@ -838,16 +903,16 @@ const SettingModal = ({ isOpen, onClose }) => {
|
|
|
838
903
|
toChain?.chainKey,
|
|
839
904
|
dstNativeToken?.decimals || 18
|
|
840
905
|
);
|
|
841
|
-
const activeBtn = "bg-
|
|
842
|
-
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";
|
|
843
908
|
return /* @__PURE__ */ jsx(Dialog, { open: isOpen, onOpenChange: (open) => !open && onClose(), children: /* @__PURE__ */ jsxs(DialogContent, { children: [
|
|
844
|
-
/* @__PURE__ */ jsx(DialogHeader, { children: /* @__PURE__ */ jsx(DialogTitle, { children: t2("settings.title"
|
|
909
|
+
/* @__PURE__ */ jsx(DialogHeader, { children: /* @__PURE__ */ jsx(DialogTitle, { children: t2("settings.title") }) }),
|
|
845
910
|
/* @__PURE__ */ jsxs("div", { className: "space-y-5", children: [
|
|
846
911
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-5", children: [
|
|
847
912
|
/* @__PURE__ */ jsxs("div", { className: "flex justify-between items-center", children: [
|
|
848
913
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
|
|
849
914
|
/* @__PURE__ */ jsx("p", { className: "text-muted-foreground text-sm font-medium leading-3.5", children: t2("settings.gasOnDestination") }),
|
|
850
|
-
/* @__PURE__ */ jsx(Tip, { text: t2("settings.
|
|
915
|
+
/* @__PURE__ */ jsx(Tip, { text: t2("settings.gasOnDestinationTip"), children: /* @__PURE__ */ jsx(TipIcon, { className: "size-4 text-muted-foreground" }) })
|
|
851
916
|
] }),
|
|
852
917
|
/* @__PURE__ */ jsx("p", { className: "text-foreground text-sm font-medium leading-3.5", children: formatUsd(gasUsdValue) })
|
|
853
918
|
] }),
|
|
@@ -866,12 +931,11 @@ const SettingModal = ({ isOpen, onClose }) => {
|
|
|
866
931
|
) }) })
|
|
867
932
|
] }),
|
|
868
933
|
/* @__PURE__ */ jsx("div", { className: "flex items-center gap-1.5", children: gasPresets.map((g) => /* @__PURE__ */ jsx(
|
|
869
|
-
|
|
934
|
+
Badge,
|
|
870
935
|
{
|
|
871
|
-
type: "button",
|
|
872
936
|
onClick: () => setGasPreset(g),
|
|
873
937
|
className: cn(
|
|
874
|
-
|
|
938
|
+
"cursor-pointer",
|
|
875
939
|
gasPreset === g ? activeBtn : notActiveBtn
|
|
876
940
|
),
|
|
877
941
|
children: t2(`settings.gasPresets.${g}`)
|
|
@@ -887,22 +951,21 @@ const SettingModal = ({ isOpen, onClose }) => {
|
|
|
887
951
|
/* @__PURE__ */ jsx("p", { className: "text-muted-foreground text-sm font-medium leading-3.5", children: t2("settings.slippageTolerance") }),
|
|
888
952
|
/* @__PURE__ */ jsx(Tip, { text: t2("settings.slippageTolerance"), children: /* @__PURE__ */ jsx(TipIcon, { className: "size-4 text-muted-foreground" }) })
|
|
889
953
|
] }),
|
|
890
|
-
slippageBps >= 500 && /* @__PURE__ */ jsx("p", { className: "text-
|
|
954
|
+
slippageBps >= 500 && /* @__PURE__ */ jsx("p", { className: "text-destructive text-xs font-medium", children: t2("settings.highSlippageWarning", {
|
|
891
955
|
defaultValue: "High slippage warning"
|
|
892
956
|
}) })
|
|
893
957
|
] }),
|
|
894
958
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-6", children: [
|
|
895
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 }) }),
|
|
896
960
|
/* @__PURE__ */ jsx("div", { className: "flex items-center gap-2", children: slippagePresets.map((p) => /* @__PURE__ */ jsx(
|
|
897
|
-
|
|
961
|
+
Badge,
|
|
898
962
|
{
|
|
899
|
-
type: "button",
|
|
900
963
|
onClick: () => {
|
|
901
964
|
const bps = parseFloat(p.replace("%", "")) * 100;
|
|
902
965
|
setSlippageBps(bps);
|
|
903
966
|
},
|
|
904
967
|
className: cn(
|
|
905
|
-
|
|
968
|
+
"cursor-pointer",
|
|
906
969
|
activeSlippagePreset === p ? activeBtn : notActiveBtn
|
|
907
970
|
),
|
|
908
971
|
children: p
|
|
@@ -918,12 +981,11 @@ const SettingModal = ({ isOpen, onClose }) => {
|
|
|
918
981
|
/* @__PURE__ */ jsx(Tip, { text: t2("settings.routePriority"), children: /* @__PURE__ */ jsx(TipIcon, { className: "size-4 text-muted-foreground" }) })
|
|
919
982
|
] }) }),
|
|
920
983
|
/* @__PURE__ */ jsx("div", { className: "flex items-center justify-end gap-2", children: routePresets.map((r) => /* @__PURE__ */ jsx(
|
|
921
|
-
|
|
984
|
+
Badge,
|
|
922
985
|
{
|
|
923
|
-
type: "button",
|
|
924
986
|
onClick: () => setRoutePriority(r),
|
|
925
987
|
className: cn(
|
|
926
|
-
|
|
988
|
+
"cursor-pointer",
|
|
927
989
|
routePriority === r ? activeBtn : notActiveBtn
|
|
928
990
|
),
|
|
929
991
|
children: t2(`settings.routePresets.${r}`)
|
|
@@ -991,168 +1053,31 @@ function useChainStrategies() {
|
|
|
991
1053
|
}
|
|
992
1054
|
return context;
|
|
993
1055
|
}
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
}
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
if (
|
|
1002
|
-
const base = BigInt(10) ** BigInt(decimals);
|
|
1003
|
-
const int = bi / base;
|
|
1004
|
-
const frac = Number(bi % base) / Number(base);
|
|
1005
|
-
return Number(int) + frac;
|
|
1006
|
-
}
|
|
1007
|
-
function resolveTokenOnChainFromMatrix$2(assetMatrix, assetSymbol, chainKey) {
|
|
1008
|
-
if (!assetMatrix || !assetSymbol || !chainKey) return void 0;
|
|
1009
|
-
const byChain = assetMatrix[assetSymbol.toUpperCase()];
|
|
1010
|
-
return byChain?.[chainKey];
|
|
1011
|
-
}
|
|
1012
|
-
const DEFAULT_SLIPPAGE_BPS = 50;
|
|
1013
|
-
const lower = (s) => (s ?? "").toLowerCase();
|
|
1014
|
-
const normSym = (s) => (s ?? "").toUpperCase().replace(/₮/g, "T").replace(/[^A-Z0-9]/g, "");
|
|
1015
|
-
function tonNorm(addr) {
|
|
1016
|
-
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;
|
|
1017
1064
|
try {
|
|
1018
1065
|
if (addr.includes(":")) {
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
urlSafe: true
|
|
1022
|
-
});
|
|
1066
|
+
Address.parseRaw(addr);
|
|
1067
|
+
return true;
|
|
1023
1068
|
}
|
|
1024
|
-
|
|
1069
|
+
Address.parse(addr);
|
|
1070
|
+
return true;
|
|
1025
1071
|
} catch {
|
|
1026
|
-
return
|
|
1072
|
+
return false;
|
|
1027
1073
|
}
|
|
1028
|
-
}
|
|
1029
|
-
const isEvmAddress = (a) => /^0x[0-9a-fA-F]{40}$/.test(a ?? "");
|
|
1030
|
-
const isTronAddress = (a) => /^T[1-9A-HJ-NP-Za-km-z]{33}$/.test(a ?? "");
|
|
1031
|
-
const isZeroAddr = (a) => (
|
|
1032
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1033
|
-
!!a && /^0x0{40}$/i.test(a) || /^0x[eE]{4}e{36}$/i.test(a)
|
|
1034
|
-
);
|
|
1074
|
+
};
|
|
1035
1075
|
function isAddressValidForChain(chainKey, addr) {
|
|
1036
1076
|
if (!chainKey || !addr) return false;
|
|
1037
|
-
if (chainKey === "ton") return
|
|
1077
|
+
if (chainKey === "ton") return isTonAddress(addr);
|
|
1038
1078
|
if (chainKey === "tron") return isTronAddress(addr);
|
|
1039
1079
|
return isEvmAddress(addr);
|
|
1040
1080
|
}
|
|
1041
|
-
function addrForApi(chainKey, addr) {
|
|
1042
|
-
if (chainKey === "ton") return tonNorm(addr);
|
|
1043
|
-
return addr;
|
|
1044
|
-
}
|
|
1045
|
-
function isNativeAddrEqual(chain, tokenAddr) {
|
|
1046
|
-
if (!chain) return false;
|
|
1047
|
-
if (!tokenAddr) return false;
|
|
1048
|
-
if (isZeroAddr(tokenAddr)) return true;
|
|
1049
|
-
const nativeAddr = chain.nativeCurrency?.address;
|
|
1050
|
-
if (!nativeAddr) return false;
|
|
1051
|
-
if (chain.chainKey === "ton") {
|
|
1052
|
-
const a = tonNorm(tokenAddr);
|
|
1053
|
-
const b = tonNorm(nativeAddr);
|
|
1054
|
-
return !!a && !!b && a === b;
|
|
1055
|
-
}
|
|
1056
|
-
return lower(nativeAddr) === lower(tokenAddr);
|
|
1057
|
-
}
|
|
1058
|
-
function findNativeMeta(tokens, chain) {
|
|
1059
|
-
if (!chain) return { decimals: 18, priceUsd: void 0 };
|
|
1060
|
-
const sym = normSym(chain.nativeCurrency?.symbol);
|
|
1061
|
-
if (!sym) {
|
|
1062
|
-
return { decimals: chain.chainKey === "ton" ? 9 : 18, priceUsd: void 0 };
|
|
1063
|
-
}
|
|
1064
|
-
const sameChain = tokens?.find(
|
|
1065
|
-
(t2) => t2.chainKey === chain.chainKey && normSym(t2.symbol) === sym
|
|
1066
|
-
) ?? void 0;
|
|
1067
|
-
if (sameChain)
|
|
1068
|
-
return { decimals: sameChain.decimals, priceUsd: sameChain.price?.usd };
|
|
1069
|
-
const anyChain = tokens?.find((t2) => normSym(t2.symbol) === sym);
|
|
1070
|
-
if (anyChain)
|
|
1071
|
-
return { decimals: anyChain.decimals, priceUsd: anyChain.price?.usd };
|
|
1072
|
-
return { decimals: chain.chainKey === "ton" ? 9 : 18, priceUsd: void 0 };
|
|
1073
|
-
}
|
|
1074
|
-
function lookupTokenMeta(tokens, chains, chainKey, tokenAddr) {
|
|
1075
|
-
if (!chainKey) return { decimals: 18, priceUsd: void 0 };
|
|
1076
|
-
const chain = chains?.find((c) => c.chainKey === chainKey);
|
|
1077
|
-
const hit = tokens?.find((t2) => {
|
|
1078
|
-
if (t2.chainKey !== chainKey) return false;
|
|
1079
|
-
if (chainKey === "ton") {
|
|
1080
|
-
const a = tonNorm(t2.address);
|
|
1081
|
-
const b = tonNorm(tokenAddr);
|
|
1082
|
-
return !!a && !!b && a === b;
|
|
1083
|
-
}
|
|
1084
|
-
return lower(t2.address) === lower(tokenAddr);
|
|
1085
|
-
}) ?? void 0;
|
|
1086
|
-
if (hit) return { decimals: hit.decimals, priceUsd: hit.price?.usd };
|
|
1087
|
-
if (isNativeAddrEqual(chain, tokenAddr)) {
|
|
1088
|
-
return findNativeMeta(tokens, chain);
|
|
1089
|
-
}
|
|
1090
|
-
return { decimals: chainKey === "ton" ? 9 : 18, priceUsd: void 0 };
|
|
1091
|
-
}
|
|
1092
|
-
function computeFeesUsdFromArray(fees, tokens, chains) {
|
|
1093
|
-
if (!fees?.length) return { totalUsd: 0 };
|
|
1094
|
-
let total = 0;
|
|
1095
|
-
let protocolFeeUsd = 0;
|
|
1096
|
-
let messageFeeUsd = 0;
|
|
1097
|
-
const byType = /* @__PURE__ */ new Map();
|
|
1098
|
-
for (const f of fees) {
|
|
1099
|
-
let usd = Number(f.usd ?? 0);
|
|
1100
|
-
if (!usd) {
|
|
1101
|
-
const { decimals, priceUsd } = lookupTokenMeta(
|
|
1102
|
-
tokens,
|
|
1103
|
-
chains,
|
|
1104
|
-
f.chainKey,
|
|
1105
|
-
f.token
|
|
1106
|
-
);
|
|
1107
|
-
const human = fromLD(String(f.amount ?? "0"), decimals);
|
|
1108
|
-
usd = (priceUsd ?? 0) * human;
|
|
1109
|
-
}
|
|
1110
|
-
total += usd;
|
|
1111
|
-
const type = (f.type ?? "other").toLowerCase();
|
|
1112
|
-
byType.set(type, (byType.get(type) ?? 0) + usd);
|
|
1113
|
-
if (type === "protocol" || type === "service") {
|
|
1114
|
-
protocolFeeUsd += usd;
|
|
1115
|
-
} else if (type === "message" || type === "gas" || type === "network") {
|
|
1116
|
-
messageFeeUsd += usd;
|
|
1117
|
-
}
|
|
1118
|
-
}
|
|
1119
|
-
const serviceUsd = byType.get("protocol") ?? byType.get("service") ?? void 0;
|
|
1120
|
-
const blockchainUsd = byType.get("gas") ?? byType.get("network") ?? byType.get("message") ?? void 0;
|
|
1121
|
-
return {
|
|
1122
|
-
totalUsd: total,
|
|
1123
|
-
protocolFeeUsd: protocolFeeUsd > 0 ? protocolFeeUsd : void 0,
|
|
1124
|
-
messageFeeUsd: messageFeeUsd > 0 ? messageFeeUsd : void 0,
|
|
1125
|
-
serviceUsd,
|
|
1126
|
-
blockchainUsd
|
|
1127
|
-
};
|
|
1128
|
-
}
|
|
1129
|
-
function dollarsFromNativeFees(feeNative, feeLzToken, chain, tokens) {
|
|
1130
|
-
let total = 0;
|
|
1131
|
-
if (feeNative && chain) {
|
|
1132
|
-
const { decimals, priceUsd } = findNativeMeta(tokens, chain);
|
|
1133
|
-
const human = fromLD(String(feeNative), decimals);
|
|
1134
|
-
total += (priceUsd ?? 0) * human;
|
|
1135
|
-
}
|
|
1136
|
-
if (feeLzToken) {
|
|
1137
|
-
const lz = tokens?.find((t2) => normSym(t2.symbol) === "LZ");
|
|
1138
|
-
if (lz?.price?.usd && lz.decimals != null) {
|
|
1139
|
-
const human = fromLD(String(feeLzToken), lz.decimals);
|
|
1140
|
-
total += lz.price.usd * human;
|
|
1141
|
-
}
|
|
1142
|
-
}
|
|
1143
|
-
return total;
|
|
1144
|
-
}
|
|
1145
|
-
function sumFeeByTokenLD(fees, dstTokenAddr, dstChainKey) {
|
|
1146
|
-
if (!fees?.length || !dstTokenAddr || !dstChainKey) return "0";
|
|
1147
|
-
let acc = 0n;
|
|
1148
|
-
for (const f of fees) {
|
|
1149
|
-
if (f.chainKey !== dstChainKey) continue;
|
|
1150
|
-
const same = dstChainKey === "ton" ? tonNorm(f.token) === tonNorm(dstTokenAddr) : lower(f.token) === lower(dstTokenAddr);
|
|
1151
|
-
if (!same) continue;
|
|
1152
|
-
acc += BigInt(f.amount ?? "0");
|
|
1153
|
-
}
|
|
1154
|
-
return acc.toString();
|
|
1155
|
-
}
|
|
1156
1081
|
function useBalances(chainKey, address, priorityTokenSymbol) {
|
|
1157
1082
|
const { chainRegistry } = useChainStrategies();
|
|
1158
1083
|
const { assetMatrix } = useTokensStore();
|
|
@@ -1214,10 +1139,92 @@ function useBalances(chainKey, address, priorityTokenSymbol) {
|
|
|
1214
1139
|
query
|
|
1215
1140
|
};
|
|
1216
1141
|
}
|
|
1217
|
-
|
|
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-2.5 px-5 py-3.5 bg-input rounded-md h-12.5 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-2.5 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-7.5 max-w-7.5 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();
|
|
1218
1226
|
const [query, setQuery] = useState("");
|
|
1219
1227
|
const [tab, setTab] = useState("my");
|
|
1220
|
-
const [isFocused, setIsFocused] = useState(false);
|
|
1221
1228
|
const { srcAddress } = useAddresses();
|
|
1222
1229
|
const { fromChain, setFromChain, chains } = useChainsStore();
|
|
1223
1230
|
const { assetMatrix, selectedAssetSymbol } = useTokensStore();
|
|
@@ -1302,159 +1309,7 @@ function useTokenSelectData(items) {
|
|
|
1302
1309
|
const resetState = useCallback(() => {
|
|
1303
1310
|
setQuery("");
|
|
1304
1311
|
setTab("my");
|
|
1305
|
-
setIsFocused(false);
|
|
1306
1312
|
}, []);
|
|
1307
|
-
return {
|
|
1308
|
-
query,
|
|
1309
|
-
setQuery,
|
|
1310
|
-
tab,
|
|
1311
|
-
setTab,
|
|
1312
|
-
isFocused,
|
|
1313
|
-
setIsFocused,
|
|
1314
|
-
effectiveTab,
|
|
1315
|
-
resetState,
|
|
1316
|
-
fromChain,
|
|
1317
|
-
setFromChain,
|
|
1318
|
-
selectedAssetSymbol,
|
|
1319
|
-
balancesQuery,
|
|
1320
|
-
groupedTokens,
|
|
1321
|
-
myTokens,
|
|
1322
|
-
getBalance,
|
|
1323
|
-
getTokenUsdValue,
|
|
1324
|
-
findFirstAvailableChain,
|
|
1325
|
-
hasAnyWallet
|
|
1326
|
-
};
|
|
1327
|
-
}
|
|
1328
|
-
const TokenRow = ({
|
|
1329
|
-
symbol,
|
|
1330
|
-
name,
|
|
1331
|
-
isSelected,
|
|
1332
|
-
hasAnyWallet,
|
|
1333
|
-
balance,
|
|
1334
|
-
usdValue,
|
|
1335
|
-
isBalanceLoading,
|
|
1336
|
-
onPick
|
|
1337
|
-
}) => {
|
|
1338
|
-
return /* @__PURE__ */ jsxs(
|
|
1339
|
-
Button,
|
|
1340
|
-
{
|
|
1341
|
-
onClick: onPick,
|
|
1342
|
-
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" : ""}`,
|
|
1343
|
-
children: [
|
|
1344
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
|
|
1345
|
-
/* @__PURE__ */ jsx(
|
|
1346
|
-
TokenSymbol,
|
|
1347
|
-
{
|
|
1348
|
-
symbol,
|
|
1349
|
-
className: "size-7.5 max-w-7.5 rounded-full",
|
|
1350
|
-
alt: symbol
|
|
1351
|
-
}
|
|
1352
|
-
),
|
|
1353
|
-
/* @__PURE__ */ jsxs("div", { className: "flex flex-col items-start gap-1", children: [
|
|
1354
|
-
/* @__PURE__ */ jsx("p", { className: "font-extrabold text-foreground text-lg leading-4 truncate flex items-center gap-1", children: symbol }),
|
|
1355
|
-
/* @__PURE__ */ jsx("div", { className: "text-xs leading-3 font-semibold text-muted-foreground truncate", children: name })
|
|
1356
|
-
] })
|
|
1357
|
-
] }),
|
|
1358
|
-
/* @__PURE__ */ jsx("div", { className: "text-right space-y-1", children: isBalanceLoading && hasAnyWallet ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-end gap-1", children: [
|
|
1359
|
-
/* @__PURE__ */ jsx(Skeleton, { className: "h-5 w-16 rounded-md" }),
|
|
1360
|
-
/* @__PURE__ */ jsx(Skeleton, { className: "h-3 w-12 rounded-md" })
|
|
1361
|
-
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1362
|
-
/* @__PURE__ */ jsx("div", { className: "font-extrabold text-foreground text-lg leading-4 truncate", children: hasAnyWallet ? formatBalance(balance) : "—" }),
|
|
1363
|
-
/* @__PURE__ */ jsx("div", { className: "text-xs leading-3 text-muted-foreground", children: hasAnyWallet && balance > 0 && usdValue > 0 ? formatUsd(usdValue) : "—" })
|
|
1364
|
-
] }) })
|
|
1365
|
-
]
|
|
1366
|
-
}
|
|
1367
|
-
);
|
|
1368
|
-
};
|
|
1369
|
-
const HEADER_H = 30;
|
|
1370
|
-
const ROW_H = 50;
|
|
1371
|
-
const HEADER_TOP_GAP = 30;
|
|
1372
|
-
const VirtualizedTokenList = ({
|
|
1373
|
-
nodes,
|
|
1374
|
-
balancesLoading,
|
|
1375
|
-
hasAnyWallet,
|
|
1376
|
-
selectedAssetSymbol,
|
|
1377
|
-
getBalance,
|
|
1378
|
-
getTokenUsdValue,
|
|
1379
|
-
onPick
|
|
1380
|
-
}) => {
|
|
1381
|
-
const Row = ({ index, style }) => {
|
|
1382
|
-
const node = nodes[index];
|
|
1383
|
-
if (node.kind === "header") {
|
|
1384
|
-
const gap = index === 0 ? 0 : HEADER_TOP_GAP;
|
|
1385
|
-
return /* @__PURE__ */ jsx(
|
|
1386
|
-
"div",
|
|
1387
|
-
{
|
|
1388
|
-
style: { ...style, paddingTop: gap },
|
|
1389
|
-
className: "px-5 flex leading-4 text-base py-1.5 font-semibold text-muted-foreground uppercase",
|
|
1390
|
-
children: /* @__PURE__ */ jsx("p", { children: node.title })
|
|
1391
|
-
}
|
|
1392
|
-
);
|
|
1393
|
-
}
|
|
1394
|
-
const bal = getBalance(node.token.symbol);
|
|
1395
|
-
const usd = getTokenUsdValue(node.token.symbol, node.token.price?.usd);
|
|
1396
|
-
const isSelected = selectedAssetSymbol?.toUpperCase() === node.token.symbol.toUpperCase();
|
|
1397
|
-
return /* @__PURE__ */ jsx(
|
|
1398
|
-
TokenRow,
|
|
1399
|
-
{
|
|
1400
|
-
symbol: node.token.symbol,
|
|
1401
|
-
name: node.token.name,
|
|
1402
|
-
isSelected: !!isSelected,
|
|
1403
|
-
hasAnyWallet,
|
|
1404
|
-
balance: bal,
|
|
1405
|
-
usdValue: usd,
|
|
1406
|
-
isBalanceLoading: balancesLoading,
|
|
1407
|
-
onPick: () => onPick(node.token.symbol, node.willChangeSrc)
|
|
1408
|
-
}
|
|
1409
|
-
);
|
|
1410
|
-
};
|
|
1411
|
-
const getItemSize = (index) => {
|
|
1412
|
-
const node = nodes[index];
|
|
1413
|
-
if (node.kind === "header") {
|
|
1414
|
-
const gap = index === 0 ? 0 : HEADER_TOP_GAP;
|
|
1415
|
-
return HEADER_H + gap;
|
|
1416
|
-
}
|
|
1417
|
-
return ROW_H;
|
|
1418
|
-
};
|
|
1419
|
-
return /* @__PURE__ */ jsx(
|
|
1420
|
-
VariableSizeList,
|
|
1421
|
-
{
|
|
1422
|
-
height: 480,
|
|
1423
|
-
width: "100%",
|
|
1424
|
-
itemCount: nodes.length,
|
|
1425
|
-
itemSize: getItemSize,
|
|
1426
|
-
overscanCount: 8,
|
|
1427
|
-
style: { willChange: "transform", paddingBottom: "40px" },
|
|
1428
|
-
children: Row
|
|
1429
|
-
}
|
|
1430
|
-
);
|
|
1431
|
-
};
|
|
1432
|
-
const TokenSelectModal = ({
|
|
1433
|
-
isOpen,
|
|
1434
|
-
onClose,
|
|
1435
|
-
items,
|
|
1436
|
-
onChangeAsset
|
|
1437
|
-
}) => {
|
|
1438
|
-
const { t: t2 } = useTranslation();
|
|
1439
|
-
const {
|
|
1440
|
-
query,
|
|
1441
|
-
setQuery,
|
|
1442
|
-
tab,
|
|
1443
|
-
setTab,
|
|
1444
|
-
isFocused,
|
|
1445
|
-
setIsFocused,
|
|
1446
|
-
effectiveTab,
|
|
1447
|
-
resetState,
|
|
1448
|
-
setFromChain,
|
|
1449
|
-
selectedAssetSymbol,
|
|
1450
|
-
balancesQuery,
|
|
1451
|
-
groupedTokens,
|
|
1452
|
-
myTokens,
|
|
1453
|
-
getBalance,
|
|
1454
|
-
getTokenUsdValue,
|
|
1455
|
-
findFirstAvailableChain,
|
|
1456
|
-
hasAnyWallet
|
|
1457
|
-
} = useTokenSelectData(items);
|
|
1458
1313
|
const handleClose = useCallback(() => {
|
|
1459
1314
|
resetState();
|
|
1460
1315
|
onClose();
|
|
@@ -1471,68 +1326,41 @@ const TokenSelectModal = ({
|
|
|
1471
1326
|
onChangeAsset(sym);
|
|
1472
1327
|
handleClose();
|
|
1473
1328
|
};
|
|
1474
|
-
const
|
|
1475
|
-
const out = [];
|
|
1329
|
+
const tokensToRender = useMemo(() => {
|
|
1476
1330
|
if (effectiveTab === "my") {
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
token,
|
|
1482
|
-
willChangeSrc: false
|
|
1483
|
-
});
|
|
1484
|
-
}
|
|
1485
|
-
return out;
|
|
1331
|
+
return myTokens.map((token) => ({
|
|
1332
|
+
token,
|
|
1333
|
+
willChangeSrc: false
|
|
1334
|
+
}));
|
|
1486
1335
|
}
|
|
1487
1336
|
const mainTokens = [
|
|
1488
|
-
...groupedTokens.withBalance
|
|
1489
|
-
...groupedTokens.onSrcChain
|
|
1490
|
-
];
|
|
1491
|
-
for (const token of mainTokens) {
|
|
1492
|
-
out.push({
|
|
1493
|
-
kind: "token",
|
|
1494
|
-
key: `main:${token.symbol}`,
|
|
1337
|
+
...groupedTokens.withBalance.map((token) => ({
|
|
1495
1338
|
token,
|
|
1496
1339
|
willChangeSrc: false
|
|
1497
|
-
})
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
return out;
|
|
1515
|
-
}, [effectiveTab, myTokens, groupedTokens, t2]);
|
|
1516
|
-
return /* @__PURE__ */ jsx(Dialog, { open: isOpen, onOpenChange: (open) => !open && handleClose(), children: /* @__PURE__ */ jsxs(DialogContent, { className: "!max-h-[80dvh] overflow-auto", children: [
|
|
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: [
|
|
1517
1357
|
/* @__PURE__ */ jsx(DialogHeader, { children: /* @__PURE__ */ jsx(DialogTitle, { children: t2("bridge.selectToken") }) }),
|
|
1518
|
-
/* @__PURE__ */
|
|
1519
|
-
|
|
1358
|
+
/* @__PURE__ */ jsx(
|
|
1359
|
+
SearchInput,
|
|
1520
1360
|
{
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
/* @__PURE__ */ jsx(
|
|
1525
|
-
Input,
|
|
1526
|
-
{
|
|
1527
|
-
placeholder: t2("bridge.searchToken"),
|
|
1528
|
-
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",
|
|
1529
|
-
value: query,
|
|
1530
|
-
onChange: (e) => setQuery(e.target.value),
|
|
1531
|
-
onFocus: () => setIsFocused(true),
|
|
1532
|
-
onBlur: () => setIsFocused(false)
|
|
1533
|
-
}
|
|
1534
|
-
)
|
|
1535
|
-
]
|
|
1361
|
+
placeholder: t2("bridge.searchToken"),
|
|
1362
|
+
value: query,
|
|
1363
|
+
onChange: setQuery
|
|
1536
1364
|
}
|
|
1537
1365
|
),
|
|
1538
1366
|
hasAnyWallet() && /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
|
|
@@ -1555,20 +1383,52 @@ const TokenSelectModal = ({
|
|
|
1555
1383
|
}
|
|
1556
1384
|
)
|
|
1557
1385
|
] }),
|
|
1558
|
-
/* @__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-3.5", children: t2("bridge.noResults") }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1559
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") }),
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
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-1.5 font-semibold text-muted-foreground uppercase mt-7.5", 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
|
+
] })
|
|
1572
1432
|
] }) })
|
|
1573
1433
|
] }) });
|
|
1574
1434
|
};
|
|
@@ -1669,7 +1529,7 @@ const SelectTokenButton = ({
|
|
|
1669
1529
|
onClick,
|
|
1670
1530
|
token
|
|
1671
1531
|
}) => {
|
|
1672
|
-
const { t: t2 } =
|
|
1532
|
+
const { t: t2 } = useBridgeTranslation();
|
|
1673
1533
|
const label = useMemo(() => {
|
|
1674
1534
|
return token?.symbol ?? t2("bridge.selectToken");
|
|
1675
1535
|
}, [token, t2]);
|
|
@@ -1699,7 +1559,7 @@ const SelectTokenButton = ({
|
|
|
1699
1559
|
);
|
|
1700
1560
|
};
|
|
1701
1561
|
const FormHeaderComponent = () => {
|
|
1702
|
-
const { t: t2 } =
|
|
1562
|
+
const { t: t2 } = useBridgeTranslation();
|
|
1703
1563
|
const { isOpen, onClose, onOpen } = useModal();
|
|
1704
1564
|
const {
|
|
1705
1565
|
isOpen: isOpenSettings,
|
|
@@ -1714,7 +1574,7 @@ const FormHeaderComponent = () => {
|
|
|
1714
1574
|
const sum = selectedAssetSymbol.toUpperCase();
|
|
1715
1575
|
return assets.find((a) => a.symbol.toUpperCase() === sum) ?? assets[0];
|
|
1716
1576
|
}, [assets, selectedAssetSymbol]);
|
|
1717
|
-
return /* @__PURE__ */ jsxs(CardHeader, { className: "gap-y-0 flex justify-between items-center", children: [
|
|
1577
|
+
return /* @__PURE__ */ jsxs(CardHeader, { className: "gap-y-0 flex flex-row justify-between items-center", children: [
|
|
1718
1578
|
/* @__PURE__ */ jsxs(CardTitle, { className: "flex items-center gap-2.5", children: [
|
|
1719
1579
|
/* @__PURE__ */ jsx("span", { className: "text-sm font-normal leading-3.5 text-muted-foreground", children: t2("bridge.selectToken") }),
|
|
1720
1580
|
/* @__PURE__ */ jsx(SelectTokenButton, { token: current, onClick: onOpen })
|
|
@@ -1745,6 +1605,19 @@ const FormHeaderComponent = () => {
|
|
|
1745
1605
|
] });
|
|
1746
1606
|
};
|
|
1747
1607
|
const FormHeader = memo(FormHeaderComponent);
|
|
1608
|
+
function toLD(human, decimals) {
|
|
1609
|
+
const [i = "0", f = ""] = human.replace(",", ".").split(".");
|
|
1610
|
+
const frac = (f + "0".repeat(decimals)).slice(0, decimals);
|
|
1611
|
+
return BigInt(i + frac).toString();
|
|
1612
|
+
}
|
|
1613
|
+
function fromLD(ld, decimals) {
|
|
1614
|
+
const bi = BigInt(ld || "0");
|
|
1615
|
+
if (decimals === 0) return Number(bi);
|
|
1616
|
+
const base = BigInt(10) ** BigInt(decimals);
|
|
1617
|
+
const int = bi / base;
|
|
1618
|
+
const frac = Number(bi % base) / Number(base);
|
|
1619
|
+
return Number(int) + frac;
|
|
1620
|
+
}
|
|
1748
1621
|
async function fetchQuotes(req) {
|
|
1749
1622
|
const params = {
|
|
1750
1623
|
srcChainKey: req.srcChainKey,
|
|
@@ -1803,6 +1676,131 @@ async function getQuotesByPriority(req) {
|
|
|
1803
1676
|
const priority = req.routePriority || RoutePriority.RECOMMENDED;
|
|
1804
1677
|
return selectQuoteByPriority(routes, priority);
|
|
1805
1678
|
}
|
|
1679
|
+
function resolveTokenOnChainFromMatrix$2(assetMatrix, assetSymbol, chainKey) {
|
|
1680
|
+
if (!assetMatrix || !assetSymbol || !chainKey) return void 0;
|
|
1681
|
+
const byChain = assetMatrix[assetSymbol.toUpperCase()];
|
|
1682
|
+
return byChain?.[chainKey];
|
|
1683
|
+
}
|
|
1684
|
+
const DEFAULT_SLIPPAGE_BPS = 50;
|
|
1685
|
+
const lower = (s) => (s ?? "").toLowerCase();
|
|
1686
|
+
const normSym = (s) => (s ?? "").toUpperCase().replace(/₮/g, "T").replace(/[^A-Z0-9]/g, "");
|
|
1687
|
+
function tonNorm(addr) {
|
|
1688
|
+
if (!addr) return null;
|
|
1689
|
+
try {
|
|
1690
|
+
if (addr.includes(":")) {
|
|
1691
|
+
return Address.parseRaw(addr).toString({
|
|
1692
|
+
bounceable: false,
|
|
1693
|
+
urlSafe: true
|
|
1694
|
+
});
|
|
1695
|
+
}
|
|
1696
|
+
return Address.parse(addr).toString({ bounceable: false, urlSafe: true });
|
|
1697
|
+
} catch {
|
|
1698
|
+
return null;
|
|
1699
|
+
}
|
|
1700
|
+
}
|
|
1701
|
+
const isZeroAddr = (a) => (
|
|
1702
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1703
|
+
!!a && /^0x0{40}$/i.test(a) || /^0x[eE]{4}e{36}$/i.test(a)
|
|
1704
|
+
);
|
|
1705
|
+
function addrForApi(chainKey, addr) {
|
|
1706
|
+
if (chainKey === "ton") return tonNorm(addr);
|
|
1707
|
+
return addr;
|
|
1708
|
+
}
|
|
1709
|
+
function isNativeAddrEqual(chain, tokenAddr) {
|
|
1710
|
+
if (!chain) return false;
|
|
1711
|
+
if (!tokenAddr) return false;
|
|
1712
|
+
if (isZeroAddr(tokenAddr)) return true;
|
|
1713
|
+
const nativeAddr = chain.nativeCurrency?.address;
|
|
1714
|
+
if (!nativeAddr) return false;
|
|
1715
|
+
if (chain.chainKey === "ton") {
|
|
1716
|
+
const a = tonNorm(tokenAddr);
|
|
1717
|
+
const b = tonNorm(nativeAddr);
|
|
1718
|
+
return !!a && !!b && a === b;
|
|
1719
|
+
}
|
|
1720
|
+
return lower(nativeAddr) === lower(tokenAddr);
|
|
1721
|
+
}
|
|
1722
|
+
function findNativeMeta(tokens, chain) {
|
|
1723
|
+
if (!chain) return { decimals: 18, priceUsd: void 0 };
|
|
1724
|
+
const sym = normSym(chain.nativeCurrency?.symbol);
|
|
1725
|
+
if (!sym) {
|
|
1726
|
+
return { decimals: chain.chainKey === "ton" ? 9 : 18, priceUsd: void 0 };
|
|
1727
|
+
}
|
|
1728
|
+
const sameChain = tokens?.find(
|
|
1729
|
+
(t2) => t2.chainKey === chain.chainKey && normSym(t2.symbol) === sym
|
|
1730
|
+
) ?? void 0;
|
|
1731
|
+
if (sameChain)
|
|
1732
|
+
return { decimals: sameChain.decimals, priceUsd: sameChain.price?.usd };
|
|
1733
|
+
const anyChain = tokens?.find((t2) => normSym(t2.symbol) === sym);
|
|
1734
|
+
if (anyChain)
|
|
1735
|
+
return { decimals: anyChain.decimals, priceUsd: anyChain.price?.usd };
|
|
1736
|
+
return { decimals: chain.chainKey === "ton" ? 9 : 18, priceUsd: void 0 };
|
|
1737
|
+
}
|
|
1738
|
+
function lookupTokenMeta(tokens, chains, chainKey, tokenAddr) {
|
|
1739
|
+
if (!chainKey) return { decimals: 18, priceUsd: void 0 };
|
|
1740
|
+
const chain = chains?.find((c) => c.chainKey === chainKey);
|
|
1741
|
+
const hit = tokens?.find((t2) => {
|
|
1742
|
+
if (t2.chainKey !== chainKey) return false;
|
|
1743
|
+
if (chainKey === "ton") {
|
|
1744
|
+
const a = tonNorm(t2.address);
|
|
1745
|
+
const b = tonNorm(tokenAddr);
|
|
1746
|
+
return !!a && !!b && a === b;
|
|
1747
|
+
}
|
|
1748
|
+
return lower(t2.address) === lower(tokenAddr);
|
|
1749
|
+
}) ?? void 0;
|
|
1750
|
+
if (hit) return { decimals: hit.decimals, priceUsd: hit.price?.usd };
|
|
1751
|
+
if (isNativeAddrEqual(chain, tokenAddr)) {
|
|
1752
|
+
return findNativeMeta(tokens, chain);
|
|
1753
|
+
}
|
|
1754
|
+
return { decimals: chainKey === "ton" ? 9 : 18, priceUsd: void 0 };
|
|
1755
|
+
}
|
|
1756
|
+
function computeFeesUsdFromArray(fees, tokens, chains) {
|
|
1757
|
+
if (!fees?.length) return { totalUsd: 0 };
|
|
1758
|
+
let total = 0;
|
|
1759
|
+
let protocolFeeUsd = 0;
|
|
1760
|
+
let messageFeeUsd = 0;
|
|
1761
|
+
const byType = /* @__PURE__ */ new Map();
|
|
1762
|
+
for (const f of fees) {
|
|
1763
|
+
let usd = Number(f.usd ?? 0);
|
|
1764
|
+
if (!usd) {
|
|
1765
|
+
const { decimals, priceUsd } = lookupTokenMeta(
|
|
1766
|
+
tokens,
|
|
1767
|
+
chains,
|
|
1768
|
+
f.chainKey,
|
|
1769
|
+
f.token
|
|
1770
|
+
);
|
|
1771
|
+
const human = fromLD(String(f.amount ?? "0"), decimals);
|
|
1772
|
+
usd = (priceUsd ?? 0) * human;
|
|
1773
|
+
}
|
|
1774
|
+
total += usd;
|
|
1775
|
+
const type = (f.type ?? "other").toLowerCase();
|
|
1776
|
+
byType.set(type, (byType.get(type) ?? 0) + usd);
|
|
1777
|
+
if (type === "protocol" || type === "service") {
|
|
1778
|
+
protocolFeeUsd += usd;
|
|
1779
|
+
} else if (type === "message" || type === "gas" || type === "network") {
|
|
1780
|
+
messageFeeUsd += usd;
|
|
1781
|
+
}
|
|
1782
|
+
}
|
|
1783
|
+
const serviceUsd = byType.get("protocol") ?? byType.get("service") ?? void 0;
|
|
1784
|
+
const blockchainUsd = byType.get("gas") ?? byType.get("network") ?? byType.get("message") ?? void 0;
|
|
1785
|
+
return {
|
|
1786
|
+
totalUsd: total,
|
|
1787
|
+
protocolFeeUsd: protocolFeeUsd > 0 ? protocolFeeUsd : void 0,
|
|
1788
|
+
messageFeeUsd: messageFeeUsd > 0 ? messageFeeUsd : void 0,
|
|
1789
|
+
serviceUsd,
|
|
1790
|
+
blockchainUsd
|
|
1791
|
+
};
|
|
1792
|
+
}
|
|
1793
|
+
function sumFeeByTokenLD(fees, dstTokenAddr, dstChainKey) {
|
|
1794
|
+
if (!fees?.length || !dstTokenAddr || !dstChainKey) return "0";
|
|
1795
|
+
let acc = 0n;
|
|
1796
|
+
for (const f of fees) {
|
|
1797
|
+
if (f.chainKey !== dstChainKey) continue;
|
|
1798
|
+
const same = dstChainKey === "ton" ? tonNorm(f.token) === tonNorm(dstTokenAddr) : lower(f.token) === lower(dstTokenAddr);
|
|
1799
|
+
if (!same) continue;
|
|
1800
|
+
acc += BigInt(f.amount ?? "0");
|
|
1801
|
+
}
|
|
1802
|
+
return acc.toString();
|
|
1803
|
+
}
|
|
1806
1804
|
function useBridgeQuote() {
|
|
1807
1805
|
const { assetMatrix, selectedAssetSymbol } = useTokensStore();
|
|
1808
1806
|
const { fromChain, toChain } = useChainsStore();
|
|
@@ -2204,7 +2202,7 @@ const SelectNetworkButton = ({
|
|
|
2204
2202
|
onClick,
|
|
2205
2203
|
network
|
|
2206
2204
|
}) => {
|
|
2207
|
-
const { t: t2 } =
|
|
2205
|
+
const { t: t2 } = useBridgeTranslation();
|
|
2208
2206
|
const label = useMemo(() => {
|
|
2209
2207
|
return network?.name ?? t2("bridge.selectNetwork");
|
|
2210
2208
|
}, [network, t2]);
|
|
@@ -2301,14 +2299,12 @@ const ChainSelectModal = ({
|
|
|
2301
2299
|
allowedItems,
|
|
2302
2300
|
onChangeChain
|
|
2303
2301
|
}) => {
|
|
2304
|
-
const { t: t2 } =
|
|
2302
|
+
const { t: t2 } = useBridgeTranslation();
|
|
2305
2303
|
const [query, setQuery] = useState("");
|
|
2306
|
-
const [isFocused, setIsFocused] = useState(false);
|
|
2307
2304
|
const { setFromChain, chains, fromChain, toChain } = useChainsStore();
|
|
2308
2305
|
const { assetMatrix, selectedAssetSymbol } = useTokensStore();
|
|
2309
2306
|
const handleClose = useCallback(() => {
|
|
2310
2307
|
setQuery("");
|
|
2311
|
-
setIsFocused(false);
|
|
2312
2308
|
onClose();
|
|
2313
2309
|
}, [onClose]);
|
|
2314
2310
|
const findCompatibleSrcChain = useCallback(
|
|
@@ -2368,7 +2364,7 @@ const ChainSelectModal = ({
|
|
|
2368
2364
|
Button,
|
|
2369
2365
|
{
|
|
2370
2366
|
onClick: () => onChainPick(chain, willChangeSrc),
|
|
2371
|
-
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-
|
|
2367
|
+
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" : ""}`,
|
|
2372
2368
|
children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2.5", children: [
|
|
2373
2369
|
/* @__PURE__ */ jsx(
|
|
2374
2370
|
NetworkSymbol,
|
|
@@ -2384,26 +2380,16 @@ const ChainSelectModal = ({
|
|
|
2384
2380
|
chain.chainKey
|
|
2385
2381
|
);
|
|
2386
2382
|
};
|
|
2387
|
-
return /* @__PURE__ */ jsx(Dialog, { open: isOpen, onOpenChange: (open) => !open && handleClose(), children: /* @__PURE__ */ jsxs(DialogContent, { className: "!
|
|
2383
|
+
return /* @__PURE__ */ jsx(Dialog, { open: isOpen, onOpenChange: (open) => !open && handleClose(), children: /* @__PURE__ */ jsxs(DialogContent, { className: "!h-[90dvh] flex flex-col", children: [
|
|
2388
2384
|
/* @__PURE__ */ jsx(DialogHeader, { children: /* @__PURE__ */ jsx(DialogTitle, { children: t2("bridge.selectNetwork") }) }),
|
|
2389
|
-
/* @__PURE__ */
|
|
2390
|
-
|
|
2385
|
+
/* @__PURE__ */ jsx(
|
|
2386
|
+
SearchInput,
|
|
2391
2387
|
{
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
{
|
|
2398
|
-
placeholder: t2("bridge.searchDestinationChain"),
|
|
2399
|
-
className: "w-full outline-none leading-0 p-0 h-6 text-base text-foreground placeholder:text-muted-foreground bg-none dark:bg-transparent",
|
|
2400
|
-
value: query,
|
|
2401
|
-
onChange: (e) => setQuery(e.target.value),
|
|
2402
|
-
onFocus: () => setIsFocused(true),
|
|
2403
|
-
onBlur: () => setIsFocused(false)
|
|
2404
|
-
}
|
|
2405
|
-
)
|
|
2406
|
-
]
|
|
2388
|
+
placeholder: t2("bridge.searchDestinationChain"),
|
|
2389
|
+
value: query,
|
|
2390
|
+
onChange: setQuery,
|
|
2391
|
+
containerClassName: "rounded-md",
|
|
2392
|
+
className: "text-foreground placeholder:text-muted-foreground"
|
|
2407
2393
|
}
|
|
2408
2394
|
),
|
|
2409
2395
|
/* @__PURE__ */ jsxs("div", { className: "flex-1 overflow-y-auto", children: [
|
|
@@ -2446,7 +2432,7 @@ const WalletButton = ({
|
|
|
2446
2432
|
wallet,
|
|
2447
2433
|
addressType
|
|
2448
2434
|
}) => {
|
|
2449
|
-
const { t: t2 } =
|
|
2435
|
+
const { t: t2 } = useBridgeTranslation();
|
|
2450
2436
|
const { onOpen } = useWalletSelectModal();
|
|
2451
2437
|
const { chainRegistry } = useChainStrategies();
|
|
2452
2438
|
const walletType = mapWalletToType(wallet);
|
|
@@ -2618,63 +2604,30 @@ const useCustomAddressStore = create$1((set) => ({
|
|
|
2618
2604
|
setCustomDstAddress: (address) => set({ customDstAddress: address }),
|
|
2619
2605
|
clearCustomDstAddress: () => set({ customDstAddress: void 0 })
|
|
2620
2606
|
}));
|
|
2621
|
-
const
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
|
|
2626
|
-
bounceable: false,
|
|
2627
|
-
urlSafe: true
|
|
2628
|
-
});
|
|
2629
|
-
}
|
|
2630
|
-
return Address.parse(addr).toString({ bounceable: false, urlSafe: true });
|
|
2631
|
-
} catch {
|
|
2632
|
-
return null;
|
|
2633
|
-
}
|
|
2607
|
+
const useIsAddressValid = (address, chainKey) => {
|
|
2608
|
+
const isValid = useMemo(() => {
|
|
2609
|
+
return isAddressValidForChain(chainKey, address);
|
|
2610
|
+
}, [address, chainKey]);
|
|
2611
|
+
return { isValid };
|
|
2634
2612
|
};
|
|
2635
|
-
const
|
|
2636
|
-
const
|
|
2613
|
+
const AnotherAddress = () => {
|
|
2614
|
+
const [enabled, setEnabled] = useState(false);
|
|
2615
|
+
const [isFocused, setIsFocused] = useState(false);
|
|
2616
|
+
const { t: t2 } = useBridgeTranslation();
|
|
2637
2617
|
const { toChain } = useChainsStore();
|
|
2638
|
-
const {
|
|
2639
|
-
const { setCustomDstAddress, clearCustomDstAddress } = useCustomAddressStore();
|
|
2618
|
+
const { setCustomDstAddress } = useCustomAddressStore();
|
|
2640
2619
|
const [value, setValue] = useState("");
|
|
2641
|
-
const
|
|
2642
|
-
const
|
|
2643
|
-
const prevEnabledRef = useRef(enabled);
|
|
2644
|
-
useEffect(() => {
|
|
2645
|
-
const wasEnabled = prevEnabledRef.current;
|
|
2646
|
-
if (enabled && !wasEnabled) {
|
|
2647
|
-
prevDstRef.current = dstAddress;
|
|
2648
|
-
setValue(dstAddress ?? "");
|
|
2649
|
-
setInvalid(false);
|
|
2650
|
-
}
|
|
2651
|
-
if (!enabled && wasEnabled) {
|
|
2652
|
-
clearCustomDstAddress();
|
|
2653
|
-
setInvalid(false);
|
|
2654
|
-
}
|
|
2655
|
-
prevEnabledRef.current = enabled;
|
|
2656
|
-
}, [enabled]);
|
|
2620
|
+
const { isValid } = useIsAddressValid(value.trim(), toChain?.chainKey);
|
|
2621
|
+
const invalid = value.trim() && !isValid;
|
|
2657
2622
|
const pushToStoreIfValid = (raw) => {
|
|
2658
2623
|
if (!enabled) return;
|
|
2659
2624
|
const v = raw.trim();
|
|
2660
2625
|
if (!v) {
|
|
2661
2626
|
setCustomDstAddress(void 0);
|
|
2662
|
-
setInvalid(false);
|
|
2663
|
-
return;
|
|
2664
|
-
}
|
|
2665
|
-
const ck = toChain?.chainKey;
|
|
2666
|
-
if (!ck) {
|
|
2667
|
-
setInvalid(true);
|
|
2668
2627
|
return;
|
|
2669
2628
|
}
|
|
2670
|
-
|
|
2671
|
-
|
|
2672
|
-
if (valid && valueForStore) {
|
|
2673
|
-
setInvalid(false);
|
|
2674
|
-
setCustomDstAddress(valueForStore);
|
|
2675
|
-
if (ck === "ton") setValue(valueForStore);
|
|
2676
|
-
} else {
|
|
2677
|
-
setInvalid(true);
|
|
2629
|
+
if (isValid) {
|
|
2630
|
+
setCustomDstAddress(v);
|
|
2678
2631
|
}
|
|
2679
2632
|
};
|
|
2680
2633
|
const onChange = (text) => {
|
|
@@ -2689,7 +2642,7 @@ const ToggleRow = ({ enabled, onToggle }) => {
|
|
|
2689
2642
|
} catch {
|
|
2690
2643
|
}
|
|
2691
2644
|
};
|
|
2692
|
-
return /* @__PURE__ */ jsxs("div", { className: "p-4 flex flex-col rounded-b-lg
|
|
2645
|
+
return /* @__PURE__ */ jsxs("div", { className: "p-4 flex flex-col rounded-b-lg bg-muted", children: [
|
|
2693
2646
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
|
|
2694
2647
|
/* @__PURE__ */ jsx("p", { className: "text-sm leading-4.5 font-medium text-muted-foreground", children: t2("bridge.sendToAnotherAddress") }),
|
|
2695
2648
|
/* @__PURE__ */ jsx(
|
|
@@ -2698,7 +2651,7 @@ const ToggleRow = ({ enabled, onToggle }) => {
|
|
|
2698
2651
|
className: "data-[state=unchecked]:bg-switch-inactive data-[state=checked]:bg-switch-active",
|
|
2699
2652
|
"aria-pressed": enabled,
|
|
2700
2653
|
checked: enabled,
|
|
2701
|
-
onClick:
|
|
2654
|
+
onClick: () => setEnabled((v) => !v)
|
|
2702
2655
|
}
|
|
2703
2656
|
)
|
|
2704
2657
|
] }),
|
|
@@ -2713,16 +2666,27 @@ const ToggleRow = ({ enabled, onToggle }) => {
|
|
|
2713
2666
|
children: /* @__PURE__ */ jsxs(
|
|
2714
2667
|
"div",
|
|
2715
2668
|
{
|
|
2716
|
-
className:
|
|
2669
|
+
className: cn(
|
|
2670
|
+
"bg-input py-2 px-4 mt-2 w-full flex items-center gap-4 rounded-md justify-between border border-transparent transition-all",
|
|
2671
|
+
{
|
|
2672
|
+
"py-4": value,
|
|
2673
|
+
"border border-ring": isFocused,
|
|
2674
|
+
"border-destructive": invalid
|
|
2675
|
+
}
|
|
2676
|
+
),
|
|
2717
2677
|
children: [
|
|
2718
2678
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5 w-full", children: [
|
|
2719
2679
|
/* @__PURE__ */ jsx(
|
|
2720
2680
|
Input,
|
|
2721
2681
|
{
|
|
2722
|
-
className:
|
|
2723
|
-
|
|
2682
|
+
className: cn(
|
|
2683
|
+
"p-0 h-auto text-base leading-5 font-semibold w-full bg-transparent dark:bg-transparent placeholder:text-muted-foreground/50 border-none"
|
|
2684
|
+
),
|
|
2685
|
+
placeholder: t2("bridge.anotherAddressPlaceholder"),
|
|
2724
2686
|
type: "text",
|
|
2725
2687
|
value,
|
|
2688
|
+
onFocus: () => setIsFocused(true),
|
|
2689
|
+
onBlur: () => setIsFocused(false),
|
|
2726
2690
|
onChange: (e) => onChange(e.target.value)
|
|
2727
2691
|
}
|
|
2728
2692
|
),
|
|
@@ -2732,21 +2696,14 @@ const ToggleRow = ({ enabled, onToggle }) => {
|
|
|
2732
2696
|
defaultValue: "Check correctness before transfer"
|
|
2733
2697
|
}) }) })
|
|
2734
2698
|
] }),
|
|
2735
|
-
!value ? /* @__PURE__ */ jsx(
|
|
2736
|
-
Button,
|
|
2737
|
-
{
|
|
2738
|
-
variant: "default",
|
|
2739
|
-
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",
|
|
2740
|
-
onClick: onPaste,
|
|
2741
|
-
children: t2("common.paste")
|
|
2742
|
-
}
|
|
2743
|
-
) : /* @__PURE__ */ jsx(
|
|
2699
|
+
!value ? /* @__PURE__ */ jsx(Button, { variant: "secondary", size: "sm", onClick: onPaste, children: t2("common.paste") }) : /* @__PURE__ */ jsx(
|
|
2744
2700
|
Button,
|
|
2745
2701
|
{
|
|
2746
2702
|
variant: "ghost",
|
|
2747
|
-
|
|
2703
|
+
size: "sm",
|
|
2704
|
+
className: "rounded-full p-0 size-5 self-start",
|
|
2748
2705
|
onClick: () => setValue(""),
|
|
2749
|
-
children: /* @__PURE__ */ jsx(X, { className: "size-
|
|
2706
|
+
children: /* @__PURE__ */ jsx(X, { className: "size-4" })
|
|
2750
2707
|
}
|
|
2751
2708
|
)
|
|
2752
2709
|
]
|
|
@@ -2859,7 +2816,7 @@ function getRouteDisplayName(route) {
|
|
|
2859
2816
|
return route.split(/[/\-_]/).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(" ");
|
|
2860
2817
|
}
|
|
2861
2818
|
const Details = () => {
|
|
2862
|
-
const { t: t2 } =
|
|
2819
|
+
const { t: t2 } = useBridgeTranslation();
|
|
2863
2820
|
const { selectedAssetSymbol, assetMatrix, tokens } = useTokensStore();
|
|
2864
2821
|
const { toChain, fromChain, chains } = useChainsStore();
|
|
2865
2822
|
const { quote, status } = useBridgeQuoteStore();
|
|
@@ -3505,7 +3462,7 @@ function useSilentValidations(amountString) {
|
|
|
3505
3462
|
return validationResult;
|
|
3506
3463
|
}
|
|
3507
3464
|
const SubmitButton = () => {
|
|
3508
|
-
const { t: t2 } =
|
|
3465
|
+
const { t: t2 } = useBridgeTranslation();
|
|
3509
3466
|
const { chainRegistry } = useChainStrategies();
|
|
3510
3467
|
const { srcAddress, dstAddress } = useAddresses();
|
|
3511
3468
|
const { quote, status, inputAmount, noRoute } = useBridgeQuoteStore();
|
|
@@ -3600,13 +3557,22 @@ const SubmitButton = () => {
|
|
|
3600
3557
|
}
|
|
3601
3558
|
};
|
|
3602
3559
|
const disabled = isBusy || amountNum <= 0 || status === "loading" || isBalanceLoading || hasInsufficientBalance || hasAmountTooLarge || !gas.hasEnoughGas || noRoute || !isValidForTransfer;
|
|
3603
|
-
return /* @__PURE__ */ jsx(
|
|
3560
|
+
return /* @__PURE__ */ jsx(
|
|
3561
|
+
Button,
|
|
3562
|
+
{
|
|
3563
|
+
onClick: handleClick,
|
|
3564
|
+
disabled,
|
|
3565
|
+
size: "lg",
|
|
3566
|
+
className: "w-full mt-4",
|
|
3567
|
+
children: label
|
|
3568
|
+
}
|
|
3569
|
+
);
|
|
3604
3570
|
};
|
|
3605
3571
|
function short(addr) {
|
|
3606
3572
|
return addr.slice(0, 4) + "…" + addr.slice(-4);
|
|
3607
3573
|
}
|
|
3608
3574
|
const WalletSelectModal = () => {
|
|
3609
|
-
const { t: t2 } =
|
|
3575
|
+
const { t: t2 } = useBridgeTranslation();
|
|
3610
3576
|
const { isOpen, onClose } = useWalletSelectModal();
|
|
3611
3577
|
const { connect, connectors, isPending } = useConnect();
|
|
3612
3578
|
const { chainRegistry } = useChainStrategies();
|
|
@@ -3715,7 +3681,7 @@ const WalletSelectModal = () => {
|
|
|
3715
3681
|
/* @__PURE__ */ jsx("div", { className: "py-2 font-semibold text-muted-foreground uppercase", children: t2("wallets.connected") }),
|
|
3716
3682
|
/* @__PURE__ */ jsx("div", { className: "", children: connectedWallets.map((wallet) => {
|
|
3717
3683
|
const IconComponent = wallet.icon;
|
|
3718
|
-
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-2.5 px-5 py-2.5 hover:bg-muted h-auto rounded-
|
|
3684
|
+
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-2.5 px-5 py-2.5 hover:bg-muted h-auto rounded-md transition-[300]", children: [
|
|
3719
3685
|
/* @__PURE__ */ jsx("div", { className: "flex items-center gap-3 min-w-0", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2.5", children: [
|
|
3720
3686
|
/* @__PURE__ */ jsx("div", { className: "w-7.5 h-7.5 flex items-center justify-center", children: /* @__PURE__ */ jsx(IconComponent, { className: "size-7.5" }) }),
|
|
3721
3687
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-col items-start min-w-0", children: [
|
|
@@ -3756,7 +3722,7 @@ const WalletSelectModal = () => {
|
|
|
3756
3722
|
}
|
|
3757
3723
|
},
|
|
3758
3724
|
disabled: isEvmConnector ? isPending : !wallet.enabled,
|
|
3759
|
-
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-
|
|
3725
|
+
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",
|
|
3760
3726
|
children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 min-w-0", children: [
|
|
3761
3727
|
/* @__PURE__ */ jsx("div", { className: "w-7.5 h-7.5 flex items-center justify-center", children: /* @__PURE__ */ jsx(IconComponent, { className: "size-7.5" }) }),
|
|
3762
3728
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-col items-start min-w-0", children: [
|
|
@@ -5465,7 +5431,7 @@ var fireworksExports = requireFireworks();
|
|
|
5465
5431
|
const Fireworks = /* @__PURE__ */ getDefaultExportFromCjs(fireworksExports);
|
|
5466
5432
|
const SuccessStep = () => {
|
|
5467
5433
|
const { current, reset } = useTransactionStore();
|
|
5468
|
-
const { t: t2 } =
|
|
5434
|
+
const { t: t2 } = useBridgeTranslation();
|
|
5469
5435
|
const metadata = current?.metadata;
|
|
5470
5436
|
const srcTxHash = current?.srcTxHash;
|
|
5471
5437
|
const handleCopyHash = () => {
|
|
@@ -5684,7 +5650,7 @@ const useCountdown = (initialSeconds) => {
|
|
|
5684
5650
|
};
|
|
5685
5651
|
};
|
|
5686
5652
|
const ConfirmStep = () => {
|
|
5687
|
-
const { t: t2 } =
|
|
5653
|
+
const { t: t2 } = useBridgeTranslation();
|
|
5688
5654
|
const { formatTime } = useCountdown(90);
|
|
5689
5655
|
return /* @__PURE__ */ jsx(Card, { className: "flex flex-col border-none h-full bg-background overflow-hidden rounded-none md:rounded-lg", children: /* @__PURE__ */ jsxs(CardContent, { className: "flex flex-col relative gap-4 py-10 px-8 flex-1 items-center justify-start text-center noise", children: [
|
|
5690
5656
|
/* @__PURE__ */ jsx(TransactionConfirmVector, {}),
|
|
@@ -5807,7 +5773,7 @@ class ChainStrategyRegistry {
|
|
|
5807
5773
|
async getBalances(chainKey, address, tokens, priorityToken) {
|
|
5808
5774
|
const strategy = this.getStrategy(chainKey);
|
|
5809
5775
|
if (!strategy) return {};
|
|
5810
|
-
return await strategy.getBalances(address, tokens, priorityToken);
|
|
5776
|
+
return await strategy.getBalances(address, tokens, chainKey, priorityToken);
|
|
5811
5777
|
}
|
|
5812
5778
|
isAddressValid(chainKey, address) {
|
|
5813
5779
|
const strategy = this.getStrategy(chainKey);
|
|
@@ -5918,14 +5884,9 @@ function parseTonAddress(address) {
|
|
|
5918
5884
|
}
|
|
5919
5885
|
return Address$1.parse(address);
|
|
5920
5886
|
}
|
|
5921
|
-
async function getEvmBalances(publicClient, address, tokens, priorityToken) {
|
|
5887
|
+
async function getEvmBalances(publicClient, address, tokens, chainKey, priorityToken) {
|
|
5922
5888
|
const balances = {};
|
|
5923
5889
|
try {
|
|
5924
|
-
console.log("start getEvmBalances");
|
|
5925
|
-
console.log("publicClient:", publicClient);
|
|
5926
|
-
console.log("isAddress:", isAddress(address));
|
|
5927
|
-
console.log("tokens:", tokens);
|
|
5928
|
-
console.log("priorityToken:", priorityToken);
|
|
5929
5890
|
if (!address || !isAddress(address)) {
|
|
5930
5891
|
console.warn(`Invalid EVM address provided: ${address}`);
|
|
5931
5892
|
return balances;
|
|
@@ -5934,40 +5895,55 @@ async function getEvmBalances(publicClient, address, tokens, priorityToken) {
|
|
|
5934
5895
|
throw new Error("No public client provided");
|
|
5935
5896
|
}
|
|
5936
5897
|
const nativeTokens = tokens.filter((t2) => isNativeAddress(t2.address));
|
|
5937
|
-
const erc20Tokens = tokens.filter(
|
|
5898
|
+
const erc20Tokens = tokens.filter(
|
|
5899
|
+
(t2) => !isNativeAddress(t2.address) && isAddress(t2.address)
|
|
5900
|
+
);
|
|
5938
5901
|
if (priorityToken) {
|
|
5939
|
-
|
|
5940
|
-
|
|
5941
|
-
|
|
5942
|
-
|
|
5943
|
-
|
|
5944
|
-
|
|
5945
|
-
const
|
|
5946
|
-
if (
|
|
5947
|
-
|
|
5948
|
-
|
|
5949
|
-
|
|
5950
|
-
|
|
5951
|
-
|
|
5952
|
-
|
|
5953
|
-
|
|
5954
|
-
|
|
5955
|
-
|
|
5956
|
-
|
|
5957
|
-
|
|
5958
|
-
|
|
5959
|
-
|
|
5960
|
-
|
|
5961
|
-
|
|
5962
|
-
|
|
5963
|
-
|
|
5964
|
-
|
|
5965
|
-
|
|
5966
|
-
|
|
5902
|
+
if (priorityToken.chainKey !== chainKey) {
|
|
5903
|
+
console.debug(
|
|
5904
|
+
`Skipping priority token ${priorityToken.symbol}: chain mismatch (expected ${chainKey}, got ${priorityToken.chainKey})`
|
|
5905
|
+
);
|
|
5906
|
+
} else {
|
|
5907
|
+
try {
|
|
5908
|
+
const isPriorityNative = isNativeAddress(priorityToken.address);
|
|
5909
|
+
if (isPriorityNative) {
|
|
5910
|
+
const ethBalance = await publicClient.getBalance({
|
|
5911
|
+
address
|
|
5912
|
+
});
|
|
5913
|
+
const balance = parseFloat(
|
|
5914
|
+
formatUnits(ethBalance, priorityToken.decimals)
|
|
5915
|
+
);
|
|
5916
|
+
if (balance > 0) {
|
|
5917
|
+
balances[priorityToken.symbol] = { balance, address };
|
|
5918
|
+
}
|
|
5919
|
+
} else if (isAddress(priorityToken.address)) {
|
|
5920
|
+
const tokenBalance = await publicClient.readContract({
|
|
5921
|
+
address: priorityToken.address,
|
|
5922
|
+
abi: [
|
|
5923
|
+
{
|
|
5924
|
+
name: "balanceOf",
|
|
5925
|
+
type: "function",
|
|
5926
|
+
stateMutability: "view",
|
|
5927
|
+
inputs: [{ name: "owner", type: "address" }],
|
|
5928
|
+
outputs: [{ name: "balance", type: "uint256" }]
|
|
5929
|
+
}
|
|
5930
|
+
],
|
|
5931
|
+
functionName: "balanceOf",
|
|
5932
|
+
args: [address]
|
|
5933
|
+
});
|
|
5934
|
+
const balance = parseFloat(
|
|
5935
|
+
formatUnits(tokenBalance, priorityToken.decimals)
|
|
5936
|
+
);
|
|
5937
|
+
if (balance > 0) {
|
|
5938
|
+
balances[priorityToken.symbol] = { balance, address };
|
|
5939
|
+
}
|
|
5967
5940
|
}
|
|
5941
|
+
} catch (error) {
|
|
5942
|
+
console.debug(
|
|
5943
|
+
`Failed to get priority token balance for ${priorityToken.symbol}:`,
|
|
5944
|
+
error
|
|
5945
|
+
);
|
|
5968
5946
|
}
|
|
5969
|
-
} catch (error) {
|
|
5970
|
-
console.debug(`Failed to get priority token balance for ${priorityToken.symbol}:`, error);
|
|
5971
5947
|
}
|
|
5972
5948
|
}
|
|
5973
5949
|
for (const token of nativeTokens) {
|
|
@@ -5980,7 +5956,10 @@ async function getEvmBalances(publicClient, address, tokens, priorityToken) {
|
|
|
5980
5956
|
balances[token.symbol] = { balance, address };
|
|
5981
5957
|
}
|
|
5982
5958
|
} catch (error) {
|
|
5983
|
-
console.debug(
|
|
5959
|
+
console.debug(
|
|
5960
|
+
`Failed to get native balance for ${token.symbol}:`,
|
|
5961
|
+
error
|
|
5962
|
+
);
|
|
5984
5963
|
}
|
|
5985
5964
|
}
|
|
5986
5965
|
if (erc20Tokens.length > 0) {
|
|
@@ -6008,17 +5987,25 @@ async function getEvmBalances(publicClient, address, tokens, priorityToken) {
|
|
|
6008
5987
|
if (!token) return;
|
|
6009
5988
|
if (result.status === "success" && result.result !== void 0) {
|
|
6010
5989
|
try {
|
|
6011
|
-
const balance = parseFloat(
|
|
5990
|
+
const balance = parseFloat(
|
|
5991
|
+
formatUnits(result.result, token.decimals)
|
|
5992
|
+
);
|
|
6012
5993
|
if (balance > 0) {
|
|
6013
5994
|
balances[token.symbol] = { balance, address };
|
|
6014
5995
|
}
|
|
6015
5996
|
} catch (error) {
|
|
6016
|
-
console.debug(
|
|
5997
|
+
console.debug(
|
|
5998
|
+
`Failed to parse balance for ${token.symbol}:`,
|
|
5999
|
+
error
|
|
6000
|
+
);
|
|
6017
6001
|
}
|
|
6018
6002
|
}
|
|
6019
6003
|
});
|
|
6020
6004
|
} catch (error) {
|
|
6021
|
-
console.warn(
|
|
6005
|
+
console.warn(
|
|
6006
|
+
"Multicall failed, falling back to individual calls:",
|
|
6007
|
+
error
|
|
6008
|
+
);
|
|
6022
6009
|
for (const token of erc20Tokens) {
|
|
6023
6010
|
try {
|
|
6024
6011
|
const tokenBalance = await publicClient.readContract({
|
|
@@ -6052,7 +6039,7 @@ async function getEvmBalances(publicClient, address, tokens, priorityToken) {
|
|
|
6052
6039
|
}
|
|
6053
6040
|
return balances;
|
|
6054
6041
|
}
|
|
6055
|
-
async function getTonBalances(address, tokens, customTonClient, tonApiKey) {
|
|
6042
|
+
async function getTonBalances(address, tokens, chainKey, customTonClient, tonApiKey) {
|
|
6056
6043
|
const balances = {};
|
|
6057
6044
|
try {
|
|
6058
6045
|
if (!isTonFriendlyAddress(address)) {
|
|
@@ -6211,13 +6198,18 @@ class EvmChainStrategy {
|
|
|
6211
6198
|
getConnectLabel(t2) {
|
|
6212
6199
|
return t2("wallets.connectEvmWallet");
|
|
6213
6200
|
}
|
|
6214
|
-
async getBalances(address, tokens, priorityToken) {
|
|
6201
|
+
async getBalances(address, tokens, chainKey, priorityToken) {
|
|
6215
6202
|
if (!this.publicClient) {
|
|
6216
6203
|
console.warn("No publicClient available for balance query");
|
|
6217
6204
|
return {};
|
|
6218
6205
|
}
|
|
6219
|
-
|
|
6220
|
-
|
|
6206
|
+
return await getEvmBalances(
|
|
6207
|
+
this.publicClient,
|
|
6208
|
+
address,
|
|
6209
|
+
tokens,
|
|
6210
|
+
chainKey,
|
|
6211
|
+
priorityToken
|
|
6212
|
+
);
|
|
6221
6213
|
}
|
|
6222
6214
|
isAddressValid(address) {
|
|
6223
6215
|
if (!address) return false;
|
|
@@ -6573,10 +6565,11 @@ class TonChainStrategy {
|
|
|
6573
6565
|
getConnectLabel(t2) {
|
|
6574
6566
|
return t2("wallets.connectTonWallet");
|
|
6575
6567
|
}
|
|
6576
|
-
async getBalances(address, tokens) {
|
|
6568
|
+
async getBalances(address, tokens, chainKey) {
|
|
6577
6569
|
return await getTonBalances(
|
|
6578
6570
|
address,
|
|
6579
6571
|
tokens,
|
|
6572
|
+
chainKey,
|
|
6580
6573
|
this.config.tonClient,
|
|
6581
6574
|
this.config.tonApiKey
|
|
6582
6575
|
);
|
|
@@ -6659,12 +6652,12 @@ class TonChainStrategy {
|
|
|
6659
6652
|
payload: msg.payload
|
|
6660
6653
|
})
|
|
6661
6654
|
);
|
|
6662
|
-
const
|
|
6655
|
+
const transaction2 = {
|
|
6663
6656
|
validUntil: Math.floor(Date.now() / 1e3) + TON_CONFIG.validUntil,
|
|
6664
6657
|
messages: tonMessages
|
|
6665
6658
|
};
|
|
6666
6659
|
const result = await this.config.tonConnectUI.sendTransaction(
|
|
6667
|
-
|
|
6660
|
+
transaction2
|
|
6668
6661
|
);
|
|
6669
6662
|
return {
|
|
6670
6663
|
chainKey: "ton",
|
|
@@ -6785,7 +6778,6 @@ class TronChainStrategy {
|
|
|
6785
6778
|
__publicField(this, "config");
|
|
6786
6779
|
this.config = config;
|
|
6787
6780
|
}
|
|
6788
|
-
// ========== Identity ==========
|
|
6789
6781
|
canHandle(chainKey) {
|
|
6790
6782
|
return chainKey.toLowerCase() === "tron";
|
|
6791
6783
|
}
|
|
@@ -6795,7 +6787,6 @@ class TronChainStrategy {
|
|
|
6795
6787
|
getName() {
|
|
6796
6788
|
return "TRON Chain Strategy";
|
|
6797
6789
|
}
|
|
6798
|
-
// ========== Wallet Management ==========
|
|
6799
6790
|
async connect() {
|
|
6800
6791
|
const tronWeb = this.getTronWeb();
|
|
6801
6792
|
if (!tronWeb && (typeof window === "undefined" || !window.tronLink)) {
|
|
@@ -6826,7 +6817,6 @@ class TronChainStrategy {
|
|
|
6826
6817
|
getConnectLabel(t2) {
|
|
6827
6818
|
return t2("wallets.connectTronWallet");
|
|
6828
6819
|
}
|
|
6829
|
-
// ========== Balance & Validation ==========
|
|
6830
6820
|
async getBalances(address, tokens) {
|
|
6831
6821
|
const tronWeb = this.getTronWeb();
|
|
6832
6822
|
if (!tronWeb) return {};
|
|
@@ -6836,7 +6826,6 @@ class TronChainStrategy {
|
|
|
6836
6826
|
if (!address) return false;
|
|
6837
6827
|
return /^T[1-9A-HJ-NP-Za-km-z]{33}$/.test(address);
|
|
6838
6828
|
}
|
|
6839
|
-
// ========== Gas Estimation ==========
|
|
6840
6829
|
async estimateGasRequirement(params) {
|
|
6841
6830
|
const {
|
|
6842
6831
|
selectedToken,
|
|
@@ -7483,7 +7472,7 @@ const EvaaBridgeWithProviders = (props) => {
|
|
|
7483
7472
|
useEffect(() => {
|
|
7484
7473
|
setTronConnected(!!tronConnected);
|
|
7485
7474
|
}, [tronConnected, setTronConnected]);
|
|
7486
|
-
return /* @__PURE__ */ jsx(
|
|
7475
|
+
return /* @__PURE__ */ jsx(BridgeI18nProvider, { defaultLanguage: props.defaultLanguage, children: /* @__PURE__ */ jsx(
|
|
7487
7476
|
ChainStrategyProvider,
|
|
7488
7477
|
{
|
|
7489
7478
|
evmWallet: {
|
|
@@ -7508,7 +7497,7 @@ const EvaaBridgeWithProviders = (props) => {
|
|
|
7508
7497
|
tonApiKey: props.tonApiKey,
|
|
7509
7498
|
children: /* @__PURE__ */ jsx(EvaaBridgeContent, { ...props })
|
|
7510
7499
|
}
|
|
7511
|
-
);
|
|
7500
|
+
) });
|
|
7512
7501
|
};
|
|
7513
7502
|
const EvaaBridgeContent = ({
|
|
7514
7503
|
className,
|
|
@@ -7516,10 +7505,9 @@ const EvaaBridgeContent = ({
|
|
|
7516
7505
|
onAmountChange,
|
|
7517
7506
|
onChainChange
|
|
7518
7507
|
} = {}) => {
|
|
7519
|
-
const { t: t2 } =
|
|
7508
|
+
const { t: t2 } = useBridgeTranslation();
|
|
7520
7509
|
useTokensRequest();
|
|
7521
7510
|
useChainsRequest();
|
|
7522
|
-
const [sendToAnother, setSendToAnother] = useState(false);
|
|
7523
7511
|
const swap = useSwapModel();
|
|
7524
7512
|
const { fromChain, toChain } = swap;
|
|
7525
7513
|
const { selectedAssetSymbol, assetMatrix } = useTokensStore();
|
|
@@ -7647,13 +7635,7 @@ const EvaaBridgeContent = ({
|
|
|
7647
7635
|
onSelect: handleToChainChange
|
|
7648
7636
|
}
|
|
7649
7637
|
),
|
|
7650
|
-
/* @__PURE__ */ jsx(
|
|
7651
|
-
ToggleRow,
|
|
7652
|
-
{
|
|
7653
|
-
enabled: sendToAnother,
|
|
7654
|
-
onToggle: () => setSendToAnother((v) => !v)
|
|
7655
|
-
}
|
|
7656
|
-
),
|
|
7638
|
+
/* @__PURE__ */ jsx(AnotherAddress, {}),
|
|
7657
7639
|
/* @__PURE__ */ jsx(SubmitButton, {})
|
|
7658
7640
|
] }),
|
|
7659
7641
|
/* @__PURE__ */ jsx(CardFooter, { children: /* @__PURE__ */ jsx(Details, {}) })
|
|
@@ -7729,7 +7711,6 @@ export {
|
|
|
7729
7711
|
buildAssetMatrix,
|
|
7730
7712
|
calculateMinReceived,
|
|
7731
7713
|
computeFeesUsdFromArray,
|
|
7732
|
-
dollarsFromNativeFees,
|
|
7733
7714
|
findNativeMeta,
|
|
7734
7715
|
formatBalance,
|
|
7735
7716
|
formatHash,
|
|
@@ -7748,10 +7729,7 @@ export {
|
|
|
7748
7729
|
getTokens,
|
|
7749
7730
|
getTonBalances,
|
|
7750
7731
|
getTronBalances,
|
|
7751
|
-
isAddressValidForChain,
|
|
7752
|
-
isEvmAddress,
|
|
7753
7732
|
isNativeAddrEqual,
|
|
7754
|
-
isTronAddress,
|
|
7755
7733
|
isZeroAddr,
|
|
7756
7734
|
listAssetsForSelect,
|
|
7757
7735
|
lookupTokenMeta,
|