@unifold/ui-react 0.1.41 → 0.1.42
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +309 -34
- package/dist/index.d.ts +309 -34
- package/dist/index.js +2061 -34
- package/dist/index.mjs +2085 -36
- package/dist/styles-base.css +1 -1
- package/dist/styles.css +1 -1
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -621,6 +621,7 @@ function useDepositAddress(params) {
|
|
|
621
621
|
destinationChainType,
|
|
622
622
|
destinationChainId,
|
|
623
623
|
destinationTokenAddress,
|
|
624
|
+
actionType,
|
|
624
625
|
enabled = true
|
|
625
626
|
} = params;
|
|
626
627
|
return useQuery({
|
|
@@ -632,6 +633,7 @@ function useDepositAddress(params) {
|
|
|
632
633
|
destinationChainType ?? null,
|
|
633
634
|
destinationChainId ?? null,
|
|
634
635
|
destinationTokenAddress ?? null,
|
|
636
|
+
actionType ?? null,
|
|
635
637
|
publishableKey
|
|
636
638
|
],
|
|
637
639
|
queryFn: () => createDepositAddress(
|
|
@@ -640,7 +642,8 @@ function useDepositAddress(params) {
|
|
|
640
642
|
recipient_address: recipientAddress,
|
|
641
643
|
destination_chain_type: destinationChainType,
|
|
642
644
|
destination_chain_id: destinationChainId,
|
|
643
|
-
destination_token_address: destinationTokenAddress
|
|
645
|
+
destination_token_address: destinationTokenAddress,
|
|
646
|
+
action_type: actionType
|
|
644
647
|
},
|
|
645
648
|
publishableKey
|
|
646
649
|
),
|
|
@@ -1354,6 +1357,30 @@ var en_default = {
|
|
|
1354
1357
|
youReceive: "You receive",
|
|
1355
1358
|
intentAddressNote: "The wallet address displayed in the payment provider is a temporary deposit address. Your funds will be automatically converted and deposited into your account."
|
|
1356
1359
|
}
|
|
1360
|
+
},
|
|
1361
|
+
withdrawModal: {
|
|
1362
|
+
title: "Withdraw",
|
|
1363
|
+
withdrawCrypto: {
|
|
1364
|
+
title: "Withdraw with Crypto",
|
|
1365
|
+
subtitle: "Send to any wallet address"
|
|
1366
|
+
},
|
|
1367
|
+
selectToken: "Select withdrawal token",
|
|
1368
|
+
receiveToken: "Receive token",
|
|
1369
|
+
receiveChain: "Receive chain",
|
|
1370
|
+
recipientAddress: "Recipient address",
|
|
1371
|
+
recipientAddressPlaceholder: "Enter wallet address",
|
|
1372
|
+
amount: "Amount",
|
|
1373
|
+
amountPlaceholder: "0.00",
|
|
1374
|
+
balance: "Balance",
|
|
1375
|
+
minimum: "min",
|
|
1376
|
+
withdraw: "Withdraw",
|
|
1377
|
+
invalidAddress: "Please enter a valid address",
|
|
1378
|
+
invalidAmount: "Please enter a valid amount",
|
|
1379
|
+
verifyingAddress: "Verifying address...",
|
|
1380
|
+
loading: "Loading...",
|
|
1381
|
+
noTokensAvailable: "No tokens available",
|
|
1382
|
+
review: "Review Withdrawal",
|
|
1383
|
+
back: "Back"
|
|
1357
1384
|
}
|
|
1358
1385
|
};
|
|
1359
1386
|
|
|
@@ -1372,7 +1399,8 @@ import { useState as useState5, useEffect as useEffect3, useRef } from "react";
|
|
|
1372
1399
|
import {
|
|
1373
1400
|
queryExecutions,
|
|
1374
1401
|
pollDirectExecutions,
|
|
1375
|
-
ExecutionStatus
|
|
1402
|
+
ExecutionStatus,
|
|
1403
|
+
ActionType
|
|
1376
1404
|
} from "@unifold/core";
|
|
1377
1405
|
var DEPOSIT_CONFIRM_DELAY_MS = 1e4;
|
|
1378
1406
|
var POLL_INTERVAL_MS = 2500;
|
|
@@ -1442,7 +1470,7 @@ function useDepositPolling({
|
|
|
1442
1470
|
const modalOpenedAt = modalOpenedAtRef.current;
|
|
1443
1471
|
const poll = async () => {
|
|
1444
1472
|
try {
|
|
1445
|
-
const response = await queryExecutions(userId, publishableKey);
|
|
1473
|
+
const response = await queryExecutions(userId, publishableKey, ActionType.Deposit);
|
|
1446
1474
|
const cutoff = new Date(modalOpenedAt.getTime() - CUTOFF_BUFFER_MS);
|
|
1447
1475
|
const sortedExecutions = [...response.data].sort((a, b) => {
|
|
1448
1476
|
const timeA = a.created_at ? new Date(a.created_at).getTime() : 0;
|
|
@@ -1586,7 +1614,8 @@ function formatCurrency(currency) {
|
|
|
1586
1614
|
}
|
|
1587
1615
|
function DepositDetailContent({
|
|
1588
1616
|
execution,
|
|
1589
|
-
className
|
|
1617
|
+
className,
|
|
1618
|
+
variant = "deposit"
|
|
1590
1619
|
}) {
|
|
1591
1620
|
const { colors: colors2, fonts, components } = useTheme();
|
|
1592
1621
|
const [chains, setChains] = useState6([]);
|
|
@@ -1992,7 +2021,7 @@ function DepositDetailContent({
|
|
|
1992
2021
|
color: components.card.rowLeftLabel,
|
|
1993
2022
|
fontFamily: fonts.regular
|
|
1994
2023
|
},
|
|
1995
|
-
children: "Deposit Tx"
|
|
2024
|
+
children: variant === "withdraw" ? "Withdrawal Tx" : "Deposit Tx"
|
|
1996
2025
|
}
|
|
1997
2026
|
),
|
|
1998
2027
|
/* @__PURE__ */ jsx7(
|
|
@@ -6900,7 +6929,8 @@ function useProjectConfig({
|
|
|
6900
6929
|
|
|
6901
6930
|
// src/components/deposits/DepositModal.tsx
|
|
6902
6931
|
import {
|
|
6903
|
-
queryExecutions as queryExecutions3
|
|
6932
|
+
queryExecutions as queryExecutions3,
|
|
6933
|
+
ActionType as ActionType3
|
|
6904
6934
|
} from "@unifold/core";
|
|
6905
6935
|
|
|
6906
6936
|
// src/hooks/use-allowed-country.ts
|
|
@@ -7287,7 +7317,7 @@ function PoweredByUnifold({
|
|
|
7287
7317
|
}
|
|
7288
7318
|
|
|
7289
7319
|
// src/components/deposits/DepositsModal.tsx
|
|
7290
|
-
import { queryExecutions as queryExecutions2 } from "@unifold/core";
|
|
7320
|
+
import { queryExecutions as queryExecutions2, ActionType as ActionType2 } from "@unifold/core";
|
|
7291
7321
|
import { Fragment as Fragment3, jsx as jsx35, jsxs as jsxs30 } from "react/jsx-runtime";
|
|
7292
7322
|
function DepositsModal({
|
|
7293
7323
|
open,
|
|
@@ -7305,7 +7335,7 @@ function DepositsModal({
|
|
|
7305
7335
|
if (!open || !userId) return;
|
|
7306
7336
|
const fetchExecutions = async () => {
|
|
7307
7337
|
try {
|
|
7308
|
-
const response = await queryExecutions2(userId, publishableKey);
|
|
7338
|
+
const response = await queryExecutions2(userId, publishableKey, ActionType2.Deposit);
|
|
7309
7339
|
const sorted = [...response.data].sort((a, b) => {
|
|
7310
7340
|
const timeA = a.created_at ? new Date(a.created_at).getTime() : 0;
|
|
7311
7341
|
const timeB = b.created_at ? new Date(b.created_at).getTime() : 0;
|
|
@@ -7427,7 +7457,7 @@ function saveRecentToken(token) {
|
|
|
7427
7457
|
try {
|
|
7428
7458
|
const recent = getRecentTokens();
|
|
7429
7459
|
const filtered = recent.filter(
|
|
7430
|
-
(
|
|
7460
|
+
(t11) => !(t11.symbol === token.symbol && t11.chainType === token.chainType && t11.chainId === token.chainId)
|
|
7431
7461
|
);
|
|
7432
7462
|
filtered.unshift(token);
|
|
7433
7463
|
const trimmed = filtered.slice(0, MAX_RECENT_TOKENS);
|
|
@@ -7440,7 +7470,7 @@ function removeRecentToken(token) {
|
|
|
7440
7470
|
try {
|
|
7441
7471
|
const recent = getRecentTokens();
|
|
7442
7472
|
const filtered = recent.filter(
|
|
7443
|
-
(
|
|
7473
|
+
(t11) => !(t11.symbol === token.symbol && t11.chainType === token.chainType && t11.chainId === token.chainId)
|
|
7444
7474
|
);
|
|
7445
7475
|
localStorage.setItem(STORAGE_KEY, JSON.stringify(filtered));
|
|
7446
7476
|
return filtered;
|
|
@@ -7479,7 +7509,7 @@ function TokenSelectorSheet({
|
|
|
7479
7509
|
const addOption = (symbol, chainType, chainId, isRecent) => {
|
|
7480
7510
|
const key = `${symbol}-${chainType}:${chainId}`;
|
|
7481
7511
|
if (seen.has(key)) return;
|
|
7482
|
-
const tokenData = tokens.find((
|
|
7512
|
+
const tokenData = tokens.find((t11) => t11.symbol === symbol);
|
|
7483
7513
|
if (!tokenData) return;
|
|
7484
7514
|
const chainData = tokenData.chains.find(
|
|
7485
7515
|
(c) => c.chain_type === chainType && c.chain_id === chainId
|
|
@@ -7950,35 +7980,35 @@ function resolveSourceToken(supportedTokens, defaultSourceChainType, defaultSour
|
|
|
7950
7980
|
let selectedChainData;
|
|
7951
7981
|
const hasChainDefaults = defaultSourceChainType && defaultSourceChainId;
|
|
7952
7982
|
if (defaultSourceTokenAddress && hasChainDefaults) {
|
|
7953
|
-
for (const
|
|
7954
|
-
const matchingChain =
|
|
7983
|
+
for (const t11 of supportedTokens) {
|
|
7984
|
+
const matchingChain = t11.chains.find(
|
|
7955
7985
|
(c) => c.token_address.toLowerCase() === defaultSourceTokenAddress.toLowerCase() && c.chain_type === defaultSourceChainType && c.chain_id === defaultSourceChainId
|
|
7956
7986
|
);
|
|
7957
7987
|
if (matchingChain) {
|
|
7958
|
-
selectedTokenData =
|
|
7988
|
+
selectedTokenData = t11;
|
|
7959
7989
|
selectedChainData = matchingChain;
|
|
7960
7990
|
break;
|
|
7961
7991
|
}
|
|
7962
7992
|
}
|
|
7963
7993
|
}
|
|
7964
7994
|
if (!selectedTokenData && defaultSourceSymbol && hasChainDefaults) {
|
|
7965
|
-
for (const
|
|
7966
|
-
if (
|
|
7967
|
-
const matchedChain =
|
|
7995
|
+
for (const t11 of supportedTokens) {
|
|
7996
|
+
if (t11.symbol !== defaultSourceSymbol) continue;
|
|
7997
|
+
const matchedChain = t11.chains.find(
|
|
7968
7998
|
(c) => c.chain_type === defaultSourceChainType && c.chain_id === defaultSourceChainId
|
|
7969
7999
|
);
|
|
7970
8000
|
if (matchedChain) {
|
|
7971
|
-
selectedTokenData =
|
|
8001
|
+
selectedTokenData = t11;
|
|
7972
8002
|
selectedChainData = matchedChain;
|
|
7973
8003
|
break;
|
|
7974
8004
|
}
|
|
7975
8005
|
}
|
|
7976
8006
|
}
|
|
7977
8007
|
if (!selectedTokenData) {
|
|
7978
|
-
for (const
|
|
7979
|
-
if (
|
|
7980
|
-
selectedTokenData =
|
|
7981
|
-
selectedChainData =
|
|
8008
|
+
for (const t11 of supportedTokens) {
|
|
8009
|
+
if (t11.chains.length > 0) {
|
|
8010
|
+
selectedTokenData = t11;
|
|
8011
|
+
selectedChainData = t11.chains[0];
|
|
7982
8012
|
break;
|
|
7983
8013
|
}
|
|
7984
8014
|
}
|
|
@@ -8027,7 +8057,7 @@ function useDefaultSourceToken({
|
|
|
8027
8057
|
]);
|
|
8028
8058
|
useEffect16(() => {
|
|
8029
8059
|
if (!supportedTokens.length || !token) return;
|
|
8030
|
-
const currentToken = supportedTokens.find((
|
|
8060
|
+
const currentToken = supportedTokens.find((t11) => t11.symbol === token);
|
|
8031
8061
|
if (!currentToken || currentToken.chains.length === 0) return;
|
|
8032
8062
|
const isChainAvailable = chain && currentToken.chains.some((c) => {
|
|
8033
8063
|
return getChainKey(c.chain_id, c.chain_type) === chain;
|
|
@@ -8353,8 +8383,8 @@ function TransferCryptoSingleInput({
|
|
|
8353
8383
|
const error = walletsError?.message ?? null;
|
|
8354
8384
|
const allAvailableChains = useMemo5(() => {
|
|
8355
8385
|
const chainsMap = /* @__PURE__ */ new Map();
|
|
8356
|
-
supportedTokens.forEach((
|
|
8357
|
-
|
|
8386
|
+
supportedTokens.forEach((t11) => {
|
|
8387
|
+
t11.chains.forEach((c) => {
|
|
8358
8388
|
const comboKey = `${c.chain_type}:${c.chain_id}`;
|
|
8359
8389
|
if (!chainsMap.has(comboKey)) {
|
|
8360
8390
|
chainsMap.set(comboKey, c);
|
|
@@ -8389,7 +8419,7 @@ function TransferCryptoSingleInput({
|
|
|
8389
8419
|
onExecutionsChange(depositExecutions);
|
|
8390
8420
|
}
|
|
8391
8421
|
}, [depositExecutions, onExecutionsChange]);
|
|
8392
|
-
const selectedToken = token ? supportedTokens.find((
|
|
8422
|
+
const selectedToken = token ? supportedTokens.find((t11) => t11.symbol === token) : void 0;
|
|
8393
8423
|
const availableChainsForToken = selectedToken?.chains || [];
|
|
8394
8424
|
const currentChainFromBackend = chain ? availableChainsForToken.find((c) => {
|
|
8395
8425
|
const key = getChainKey2(c.chain_id, c.chain_type);
|
|
@@ -8403,7 +8433,7 @@ function TransferCryptoSingleInput({
|
|
|
8403
8433
|
setCopied(true);
|
|
8404
8434
|
setTimeout(() => setCopied(false), 2e3);
|
|
8405
8435
|
};
|
|
8406
|
-
const
|
|
8436
|
+
const formatProcessingTime3 = (seconds) => {
|
|
8407
8437
|
if (seconds === null) {
|
|
8408
8438
|
return t4.processingTime.lessThanMinutes.replace("{{minutes}}", "1");
|
|
8409
8439
|
}
|
|
@@ -8612,7 +8642,7 @@ function TransferCryptoSingleInput({
|
|
|
8612
8642
|
t4.processingTime.label,
|
|
8613
8643
|
":",
|
|
8614
8644
|
" ",
|
|
8615
|
-
/* @__PURE__ */ jsx41("span", { style: { color: components.card.titleColor, fontFamily: fonts.medium }, children:
|
|
8645
|
+
/* @__PURE__ */ jsx41("span", { style: { color: components.card.titleColor, fontFamily: fonts.medium }, children: formatProcessingTime3(processingTime) })
|
|
8616
8646
|
] })
|
|
8617
8647
|
] }),
|
|
8618
8648
|
detailsExpanded ? /* @__PURE__ */ jsx41(ChevronUp2, { className: "uf-w-4 uf-h-4", style: { color: components.card.actionColor } }) : /* @__PURE__ */ jsx41(ChevronDown3, { className: "uf-w-4 uf-h-4", style: { color: components.card.actionColor } })
|
|
@@ -8939,8 +8969,8 @@ function TransferCryptoDoubleInput({
|
|
|
8939
8969
|
const error = walletsError?.message ?? null;
|
|
8940
8970
|
const allAvailableChains = useMemo6(() => {
|
|
8941
8971
|
const chainsMap = /* @__PURE__ */ new Map();
|
|
8942
|
-
supportedTokens.forEach((
|
|
8943
|
-
|
|
8972
|
+
supportedTokens.forEach((t11) => {
|
|
8973
|
+
t11.chains.forEach((c) => {
|
|
8944
8974
|
const comboKey = `${c.chain_type}:${c.chain_id}`;
|
|
8945
8975
|
if (!chainsMap.has(comboKey)) {
|
|
8946
8976
|
chainsMap.set(comboKey, c);
|
|
@@ -8975,7 +9005,7 @@ function TransferCryptoDoubleInput({
|
|
|
8975
9005
|
onExecutionsChange(depositExecutions);
|
|
8976
9006
|
}
|
|
8977
9007
|
}, [depositExecutions, onExecutionsChange]);
|
|
8978
|
-
const selectedToken = token ? supportedTokens.find((
|
|
9008
|
+
const selectedToken = token ? supportedTokens.find((t11) => t11.symbol === token) : void 0;
|
|
8979
9009
|
const availableChainsForToken = selectedToken?.chains || [];
|
|
8980
9010
|
const currentChainFromBackend = chain ? availableChainsForToken.find((c) => {
|
|
8981
9011
|
const key = getChainKey3(c.chain_id, c.chain_type);
|
|
@@ -8989,7 +9019,7 @@ function TransferCryptoDoubleInput({
|
|
|
8989
9019
|
setCopied(true);
|
|
8990
9020
|
setTimeout(() => setCopied(false), 2e3);
|
|
8991
9021
|
};
|
|
8992
|
-
const
|
|
9022
|
+
const formatProcessingTime3 = (seconds) => {
|
|
8993
9023
|
if (seconds === null) {
|
|
8994
9024
|
return t5.processingTime.lessThanMinutes.replace("{{minutes}}", "1");
|
|
8995
9025
|
}
|
|
@@ -9216,7 +9246,7 @@ function TransferCryptoDoubleInput({
|
|
|
9216
9246
|
t5.processingTime.label,
|
|
9217
9247
|
":",
|
|
9218
9248
|
" ",
|
|
9219
|
-
/* @__PURE__ */ jsx43("span", { style: { color: components.card.titleColor, fontFamily: fonts.medium }, children:
|
|
9249
|
+
/* @__PURE__ */ jsx43("span", { style: { color: components.card.titleColor, fontFamily: fonts.medium }, children: formatProcessingTime3(processingTime) })
|
|
9220
9250
|
] })
|
|
9221
9251
|
] }),
|
|
9222
9252
|
detailsExpanded ? /* @__PURE__ */ jsx43(ChevronUp4, { className: "uf-w-4 uf-h-4", style: { color: components.card.actionColor } }) : /* @__PURE__ */ jsx43(ChevronDown5, { className: "uf-w-4 uf-h-4", style: { color: components.card.actionColor } })
|
|
@@ -10295,7 +10325,7 @@ function BrowserWalletModal({
|
|
|
10295
10325
|
);
|
|
10296
10326
|
if (cancelled) return;
|
|
10297
10327
|
const supportedToken = response.data.find(
|
|
10298
|
-
(
|
|
10328
|
+
(t11) => t11.symbol.toLowerCase() === token.symbol.toLowerCase()
|
|
10299
10329
|
);
|
|
10300
10330
|
if (supportedToken) {
|
|
10301
10331
|
const chainDetail = supportedToken.chains.find(
|
|
@@ -11611,7 +11641,7 @@ function DepositModal({
|
|
|
11611
11641
|
if (view !== "tracker" || !userId) return;
|
|
11612
11642
|
const fetchExecutions = async () => {
|
|
11613
11643
|
try {
|
|
11614
|
-
const response = await queryExecutions3(userId, publishableKey);
|
|
11644
|
+
const response = await queryExecutions3(userId, publishableKey, ActionType3.Deposit);
|
|
11615
11645
|
const sorted = [...response.data].sort((a, b) => {
|
|
11616
11646
|
const timeA = a.created_at ? new Date(a.created_at).getTime() : 0;
|
|
11617
11647
|
const timeB = b.created_at ? new Date(b.created_at).getTime() : 0;
|
|
@@ -12130,6 +12160,2011 @@ function DepositModal({
|
|
|
12130
12160
|
}
|
|
12131
12161
|
) });
|
|
12132
12162
|
}
|
|
12163
|
+
|
|
12164
|
+
// src/components/withdrawals/WithdrawModal.tsx
|
|
12165
|
+
import {
|
|
12166
|
+
useState as useState31,
|
|
12167
|
+
useEffect as useEffect25,
|
|
12168
|
+
useLayoutEffect as useLayoutEffect3,
|
|
12169
|
+
useCallback as useCallback6,
|
|
12170
|
+
useRef as useRef8
|
|
12171
|
+
} from "react";
|
|
12172
|
+
import { AlertTriangle as AlertTriangle3, ChevronRight as ChevronRight13, Clock as Clock5 } from "lucide-react";
|
|
12173
|
+
|
|
12174
|
+
// src/hooks/use-supported-destination-tokens.ts
|
|
12175
|
+
import { useQuery as useQuery9 } from "@tanstack/react-query";
|
|
12176
|
+
import {
|
|
12177
|
+
getSupportedDestinationTokens
|
|
12178
|
+
} from "@unifold/core";
|
|
12179
|
+
function useSupportedDestinationTokens(publishableKey, enabled = true) {
|
|
12180
|
+
return useQuery9({
|
|
12181
|
+
queryKey: ["unifold", "supportedDestinationTokens", publishableKey],
|
|
12182
|
+
queryFn: () => getSupportedDestinationTokens(publishableKey),
|
|
12183
|
+
staleTime: 1e3 * 60 * 5,
|
|
12184
|
+
gcTime: 1e3 * 60 * 30,
|
|
12185
|
+
refetchOnMount: false,
|
|
12186
|
+
refetchOnWindowFocus: false,
|
|
12187
|
+
enabled
|
|
12188
|
+
});
|
|
12189
|
+
}
|
|
12190
|
+
|
|
12191
|
+
// src/hooks/use-source-token-validation.ts
|
|
12192
|
+
import { useQuery as useQuery10 } from "@tanstack/react-query";
|
|
12193
|
+
import { getSupportedDepositTokens as getSupportedDepositTokens3 } from "@unifold/core";
|
|
12194
|
+
function useSourceTokenValidation(params) {
|
|
12195
|
+
const {
|
|
12196
|
+
sourceChainType,
|
|
12197
|
+
sourceChainId,
|
|
12198
|
+
sourceTokenAddress,
|
|
12199
|
+
sourceTokenSymbol,
|
|
12200
|
+
publishableKey,
|
|
12201
|
+
enabled = true
|
|
12202
|
+
} = params;
|
|
12203
|
+
const hasParams = !!sourceChainType && !!sourceChainId && !!sourceTokenAddress;
|
|
12204
|
+
return useQuery10({
|
|
12205
|
+
queryKey: [
|
|
12206
|
+
"unifold",
|
|
12207
|
+
"sourceTokenValidation",
|
|
12208
|
+
sourceChainType ?? null,
|
|
12209
|
+
sourceChainId ?? null,
|
|
12210
|
+
sourceTokenAddress ?? null,
|
|
12211
|
+
publishableKey
|
|
12212
|
+
],
|
|
12213
|
+
queryFn: async () => {
|
|
12214
|
+
const res = await getSupportedDepositTokens3(publishableKey);
|
|
12215
|
+
let matchedMinUsd = null;
|
|
12216
|
+
let matchedProcessingTime = null;
|
|
12217
|
+
let matchedSlippage = null;
|
|
12218
|
+
let matchedPriceImpact = null;
|
|
12219
|
+
const found = res.data.some(
|
|
12220
|
+
(token) => token.chains.some((chain) => {
|
|
12221
|
+
const match = chain.chain_type === sourceChainType && chain.chain_id === sourceChainId && chain.token_address.toLowerCase() === sourceTokenAddress.toLowerCase();
|
|
12222
|
+
if (match) {
|
|
12223
|
+
matchedMinUsd = chain.minimum_deposit_amount_usd;
|
|
12224
|
+
matchedProcessingTime = chain.estimated_processing_time;
|
|
12225
|
+
matchedSlippage = chain.max_slippage_percent;
|
|
12226
|
+
matchedPriceImpact = chain.estimated_price_impact_percent;
|
|
12227
|
+
}
|
|
12228
|
+
return match;
|
|
12229
|
+
})
|
|
12230
|
+
);
|
|
12231
|
+
return {
|
|
12232
|
+
isSupported: found,
|
|
12233
|
+
minimumAmountUsd: matchedMinUsd,
|
|
12234
|
+
estimatedProcessingTime: matchedProcessingTime,
|
|
12235
|
+
maxSlippagePercent: matchedSlippage,
|
|
12236
|
+
priceImpactPercent: matchedPriceImpact,
|
|
12237
|
+
errorMessage: found ? null : `${sourceTokenSymbol || "Source token"} is not a supported withdrawal token. Supported tokens include USDC, USDT, and other stablecoins.`
|
|
12238
|
+
};
|
|
12239
|
+
},
|
|
12240
|
+
enabled: enabled && hasParams,
|
|
12241
|
+
staleTime: 1e3 * 60 * 5,
|
|
12242
|
+
gcTime: 1e3 * 60 * 30,
|
|
12243
|
+
refetchOnMount: false,
|
|
12244
|
+
refetchOnWindowFocus: false
|
|
12245
|
+
});
|
|
12246
|
+
}
|
|
12247
|
+
|
|
12248
|
+
// src/hooks/use-address-balance.ts
|
|
12249
|
+
import { useQuery as useQuery11 } from "@tanstack/react-query";
|
|
12250
|
+
import { getAddressBalance as getAddressBalance2 } from "@unifold/core";
|
|
12251
|
+
function useAddressBalance(params) {
|
|
12252
|
+
const {
|
|
12253
|
+
address,
|
|
12254
|
+
chainType,
|
|
12255
|
+
chainId,
|
|
12256
|
+
tokenAddress,
|
|
12257
|
+
publishableKey,
|
|
12258
|
+
enabled = true
|
|
12259
|
+
} = params;
|
|
12260
|
+
const hasParams = !!address && !!chainType && !!chainId && !!tokenAddress;
|
|
12261
|
+
return useQuery11({
|
|
12262
|
+
queryKey: [
|
|
12263
|
+
"unifold",
|
|
12264
|
+
"addressBalance",
|
|
12265
|
+
address ?? null,
|
|
12266
|
+
chainType ?? null,
|
|
12267
|
+
chainId ?? null,
|
|
12268
|
+
tokenAddress ?? null,
|
|
12269
|
+
publishableKey
|
|
12270
|
+
],
|
|
12271
|
+
queryFn: async () => {
|
|
12272
|
+
const res = await getAddressBalance2(
|
|
12273
|
+
address,
|
|
12274
|
+
chainType,
|
|
12275
|
+
chainId,
|
|
12276
|
+
tokenAddress,
|
|
12277
|
+
publishableKey
|
|
12278
|
+
);
|
|
12279
|
+
if (res.balance) {
|
|
12280
|
+
const decimals = res.balance.token?.decimals ?? 6;
|
|
12281
|
+
const symbol = res.balance.token?.symbol ?? "";
|
|
12282
|
+
const baseUnit = res.balance.amount;
|
|
12283
|
+
const raw = BigInt(baseUnit);
|
|
12284
|
+
const divisor = BigInt(10 ** decimals);
|
|
12285
|
+
const whole = raw / divisor;
|
|
12286
|
+
const frac = raw % divisor;
|
|
12287
|
+
const fracStr = frac.toString().padStart(decimals, "0").replace(/0+$/, "");
|
|
12288
|
+
const balanceHuman = fracStr ? `${whole}.${fracStr}` : whole.toString();
|
|
12289
|
+
return {
|
|
12290
|
+
balanceBaseUnit: baseUnit,
|
|
12291
|
+
balanceHuman,
|
|
12292
|
+
balanceUsd: res.balance.amount_usd,
|
|
12293
|
+
exchangeRate: res.balance.exchange_rate,
|
|
12294
|
+
decimals,
|
|
12295
|
+
symbol
|
|
12296
|
+
};
|
|
12297
|
+
}
|
|
12298
|
+
return { balanceBaseUnit: "0", balanceHuman: "0", balanceUsd: "0", exchangeRate: null, decimals: 6, symbol: "" };
|
|
12299
|
+
},
|
|
12300
|
+
enabled: enabled && hasParams,
|
|
12301
|
+
staleTime: 1e3 * 30,
|
|
12302
|
+
gcTime: 1e3 * 60 * 5,
|
|
12303
|
+
refetchInterval: 1e3 * 30,
|
|
12304
|
+
refetchOnMount: "always",
|
|
12305
|
+
refetchOnWindowFocus: false
|
|
12306
|
+
});
|
|
12307
|
+
}
|
|
12308
|
+
|
|
12309
|
+
// src/hooks/use-executions.ts
|
|
12310
|
+
import { useQuery as useQuery12 } from "@tanstack/react-query";
|
|
12311
|
+
import { queryExecutions as queryExecutions4, ActionType as ActionType4 } from "@unifold/core";
|
|
12312
|
+
function useExecutions(userId, publishableKey, options) {
|
|
12313
|
+
const actionType = options?.actionType ?? ActionType4.Deposit;
|
|
12314
|
+
return useQuery12({
|
|
12315
|
+
queryKey: ["unifold", "executions", actionType, userId, publishableKey],
|
|
12316
|
+
queryFn: () => queryExecutions4(userId, publishableKey, actionType),
|
|
12317
|
+
enabled: (options?.enabled ?? true) && !!userId,
|
|
12318
|
+
refetchInterval: options?.refetchInterval ?? 3e3,
|
|
12319
|
+
staleTime: 0,
|
|
12320
|
+
gcTime: 1e3 * 60 * 5,
|
|
12321
|
+
refetchOnWindowFocus: false
|
|
12322
|
+
});
|
|
12323
|
+
}
|
|
12324
|
+
|
|
12325
|
+
// src/hooks/use-withdraw-polling.ts
|
|
12326
|
+
import { useState as useState28, useEffect as useEffect22, useRef as useRef7 } from "react";
|
|
12327
|
+
import {
|
|
12328
|
+
queryExecutions as queryExecutions5,
|
|
12329
|
+
pollDirectExecutions as pollDirectExecutions2,
|
|
12330
|
+
ExecutionStatus as ExecutionStatus5,
|
|
12331
|
+
ActionType as ActionType5
|
|
12332
|
+
} from "@unifold/core";
|
|
12333
|
+
var POLL_INTERVAL_MS2 = 2500;
|
|
12334
|
+
var POLL_ENDPOINT_INTERVAL_MS2 = 3e3;
|
|
12335
|
+
var CUTOFF_BUFFER_MS2 = 6e4;
|
|
12336
|
+
function useWithdrawPolling({
|
|
12337
|
+
userId,
|
|
12338
|
+
publishableKey,
|
|
12339
|
+
depositWalletId,
|
|
12340
|
+
enabled = false,
|
|
12341
|
+
onWithdrawSuccess,
|
|
12342
|
+
onWithdrawError
|
|
12343
|
+
}) {
|
|
12344
|
+
const [executions, setExecutions] = useState28([]);
|
|
12345
|
+
const [isPolling, setIsPolling] = useState28(false);
|
|
12346
|
+
const enabledAtRef = useRef7(/* @__PURE__ */ new Date());
|
|
12347
|
+
const trackedRef = useRef7(/* @__PURE__ */ new Map());
|
|
12348
|
+
const prevEnabledRef = useRef7(false);
|
|
12349
|
+
const onSuccessRef = useRef7(onWithdrawSuccess);
|
|
12350
|
+
const onErrorRef = useRef7(onWithdrawError);
|
|
12351
|
+
useEffect22(() => {
|
|
12352
|
+
onSuccessRef.current = onWithdrawSuccess;
|
|
12353
|
+
}, [onWithdrawSuccess]);
|
|
12354
|
+
useEffect22(() => {
|
|
12355
|
+
onErrorRef.current = onWithdrawError;
|
|
12356
|
+
}, [onWithdrawError]);
|
|
12357
|
+
useEffect22(() => {
|
|
12358
|
+
if (enabled && !prevEnabledRef.current) {
|
|
12359
|
+
enabledAtRef.current = /* @__PURE__ */ new Date();
|
|
12360
|
+
trackedRef.current.clear();
|
|
12361
|
+
}
|
|
12362
|
+
if (!enabled) {
|
|
12363
|
+
trackedRef.current.clear();
|
|
12364
|
+
}
|
|
12365
|
+
prevEnabledRef.current = enabled;
|
|
12366
|
+
}, [enabled]);
|
|
12367
|
+
useEffect22(() => {
|
|
12368
|
+
if (!userId || !enabled) return;
|
|
12369
|
+
const enabledAt = enabledAtRef.current;
|
|
12370
|
+
const poll = async () => {
|
|
12371
|
+
try {
|
|
12372
|
+
const response = await queryExecutions5(userId, publishableKey, ActionType5.Withdraw);
|
|
12373
|
+
const cutoff = new Date(enabledAt.getTime() - CUTOFF_BUFFER_MS2);
|
|
12374
|
+
const sorted = [...response.data].sort((a, b) => {
|
|
12375
|
+
const tA = a.created_at ? new Date(a.created_at).getTime() : 0;
|
|
12376
|
+
const tB = b.created_at ? new Date(b.created_at).getTime() : 0;
|
|
12377
|
+
return tB - tA;
|
|
12378
|
+
});
|
|
12379
|
+
const inProgress = [ExecutionStatus5.PENDING, ExecutionStatus5.WAITING, ExecutionStatus5.DELAYED];
|
|
12380
|
+
const terminal = [ExecutionStatus5.SUCCEEDED, ExecutionStatus5.FAILED];
|
|
12381
|
+
let target = null;
|
|
12382
|
+
for (const ex of sorted) {
|
|
12383
|
+
const t11 = ex.created_at ? new Date(ex.created_at) : null;
|
|
12384
|
+
if (!t11 || t11 < cutoff) continue;
|
|
12385
|
+
const prev = trackedRef.current.get(ex.id);
|
|
12386
|
+
if (!prev) {
|
|
12387
|
+
target = ex;
|
|
12388
|
+
break;
|
|
12389
|
+
}
|
|
12390
|
+
if (inProgress.includes(prev) && terminal.includes(ex.status)) {
|
|
12391
|
+
target = ex;
|
|
12392
|
+
break;
|
|
12393
|
+
}
|
|
12394
|
+
}
|
|
12395
|
+
if (target) {
|
|
12396
|
+
const ex = target;
|
|
12397
|
+
const exTime = ex.created_at ? new Date(ex.created_at) : null;
|
|
12398
|
+
if (!exTime || exTime < enabledAtRef.current) return;
|
|
12399
|
+
const prev = trackedRef.current.get(ex.id);
|
|
12400
|
+
trackedRef.current.set(ex.id, ex.status);
|
|
12401
|
+
setExecutions((list) => {
|
|
12402
|
+
const idx = list.findIndex((e) => e.id === ex.id);
|
|
12403
|
+
if (idx >= 0) {
|
|
12404
|
+
const u = [...list];
|
|
12405
|
+
u[idx] = ex;
|
|
12406
|
+
return u;
|
|
12407
|
+
}
|
|
12408
|
+
return [...list, ex];
|
|
12409
|
+
});
|
|
12410
|
+
if (ex.status === ExecutionStatus5.SUCCEEDED && (!prev || inProgress.includes(prev))) {
|
|
12411
|
+
onSuccessRef.current?.({ message: "Withdrawal completed successfully", executionId: ex.id, transaction: ex });
|
|
12412
|
+
} else if (ex.status === ExecutionStatus5.FAILED && prev !== ExecutionStatus5.FAILED) {
|
|
12413
|
+
onErrorRef.current?.({ message: "Withdrawal failed", code: "WITHDRAW_FAILED", error: ex });
|
|
12414
|
+
}
|
|
12415
|
+
}
|
|
12416
|
+
} catch (error) {
|
|
12417
|
+
console.error("Failed to fetch withdraw executions:", error);
|
|
12418
|
+
onErrorRef.current?.({ message: "Failed to fetch withdrawal status", code: "POLLING_ERROR", error });
|
|
12419
|
+
}
|
|
12420
|
+
};
|
|
12421
|
+
void poll();
|
|
12422
|
+
const interval = setInterval(poll, POLL_INTERVAL_MS2);
|
|
12423
|
+
setIsPolling(true);
|
|
12424
|
+
return () => {
|
|
12425
|
+
clearInterval(interval);
|
|
12426
|
+
setIsPolling(false);
|
|
12427
|
+
};
|
|
12428
|
+
}, [userId, publishableKey, enabled]);
|
|
12429
|
+
useEffect22(() => {
|
|
12430
|
+
if (!enabled || !depositWalletId) return;
|
|
12431
|
+
const trigger = async () => {
|
|
12432
|
+
try {
|
|
12433
|
+
await pollDirectExecutions2({ deposit_wallet_id: depositWalletId }, publishableKey);
|
|
12434
|
+
} catch {
|
|
12435
|
+
}
|
|
12436
|
+
};
|
|
12437
|
+
trigger();
|
|
12438
|
+
const interval = setInterval(trigger, POLL_ENDPOINT_INTERVAL_MS2);
|
|
12439
|
+
return () => clearInterval(interval);
|
|
12440
|
+
}, [enabled, depositWalletId, publishableKey]);
|
|
12441
|
+
return { executions, isPolling };
|
|
12442
|
+
}
|
|
12443
|
+
|
|
12444
|
+
// src/components/withdrawals/WithdrawDoubleInput.tsx
|
|
12445
|
+
import { jsx as jsx52, jsxs as jsxs45 } from "react/jsx-runtime";
|
|
12446
|
+
var t7 = i18n.withdrawModal;
|
|
12447
|
+
var getChainKey4 = (chainId, chainType) => `${chainType}:${chainId}`;
|
|
12448
|
+
function WithdrawDoubleInput({
|
|
12449
|
+
tokens,
|
|
12450
|
+
selectedTokenSymbol,
|
|
12451
|
+
selectedChainKey,
|
|
12452
|
+
onTokenChange,
|
|
12453
|
+
onChainChange,
|
|
12454
|
+
isLoading = false
|
|
12455
|
+
}) {
|
|
12456
|
+
const { fonts, components } = useTheme();
|
|
12457
|
+
const isDarkMode = useTheme().themeClass.includes("uf-dark");
|
|
12458
|
+
const selectedToken = selectedTokenSymbol ? tokens.find((t11) => t11.symbol === selectedTokenSymbol) : void 0;
|
|
12459
|
+
const availableChainsForToken = selectedToken?.chains || [];
|
|
12460
|
+
const renderTokenItem = (tokenData) => /* @__PURE__ */ jsxs45("div", { className: "uf-flex uf-items-center uf-gap-2", children: [
|
|
12461
|
+
/* @__PURE__ */ jsx52(
|
|
12462
|
+
"img",
|
|
12463
|
+
{
|
|
12464
|
+
src: tokenData.icon_url,
|
|
12465
|
+
alt: tokenData.symbol,
|
|
12466
|
+
width: 20,
|
|
12467
|
+
height: 20,
|
|
12468
|
+
loading: "lazy",
|
|
12469
|
+
className: "uf-rounded-full uf-flex-shrink-0"
|
|
12470
|
+
}
|
|
12471
|
+
),
|
|
12472
|
+
/* @__PURE__ */ jsx52("span", { className: "uf-text-xs uf-font-normal", children: tokenData.symbol })
|
|
12473
|
+
] });
|
|
12474
|
+
const renderChainItem = (chainData) => /* @__PURE__ */ jsxs45("div", { className: "uf-flex uf-items-center uf-gap-2", children: [
|
|
12475
|
+
/* @__PURE__ */ jsx52(
|
|
12476
|
+
"img",
|
|
12477
|
+
{
|
|
12478
|
+
src: chainData.icon_url,
|
|
12479
|
+
alt: chainData.chain_name,
|
|
12480
|
+
width: 20,
|
|
12481
|
+
height: 20,
|
|
12482
|
+
loading: "lazy",
|
|
12483
|
+
className: "uf-rounded-full uf-flex-shrink-0"
|
|
12484
|
+
}
|
|
12485
|
+
),
|
|
12486
|
+
/* @__PURE__ */ jsx52("span", { className: "uf-text-xs uf-font-normal", children: chainData.chain_name })
|
|
12487
|
+
] });
|
|
12488
|
+
const currentChainData = selectedChainKey ? availableChainsForToken.find(
|
|
12489
|
+
(c) => getChainKey4(c.chain_id, c.chain_type) === selectedChainKey
|
|
12490
|
+
) : void 0;
|
|
12491
|
+
return /* @__PURE__ */ jsxs45("div", { className: "uf-grid uf-grid-cols-2 uf-gap-2.5", children: [
|
|
12492
|
+
/* @__PURE__ */ jsxs45("div", { children: [
|
|
12493
|
+
/* @__PURE__ */ jsx52(
|
|
12494
|
+
"div",
|
|
12495
|
+
{
|
|
12496
|
+
className: "uf-text-xs uf-mb-2 uf-flex uf-items-center uf-gap-1",
|
|
12497
|
+
style: { color: components.card.labelColor },
|
|
12498
|
+
children: t7.receiveToken
|
|
12499
|
+
}
|
|
12500
|
+
),
|
|
12501
|
+
/* @__PURE__ */ jsxs45(
|
|
12502
|
+
Select,
|
|
12503
|
+
{
|
|
12504
|
+
value: selectedTokenSymbol ?? "",
|
|
12505
|
+
onValueChange: onTokenChange,
|
|
12506
|
+
disabled: isLoading || tokens.length === 0,
|
|
12507
|
+
children: [
|
|
12508
|
+
/* @__PURE__ */ jsx52(
|
|
12509
|
+
SelectTrigger,
|
|
12510
|
+
{
|
|
12511
|
+
className: "uf-h-10 hover:uf-opacity-90 uf-text-foreground disabled:uf-opacity-50",
|
|
12512
|
+
style: {
|
|
12513
|
+
backgroundColor: components.card.backgroundColor,
|
|
12514
|
+
border: `${components.card.borderWidth}px solid ${components.card.borderColor}`
|
|
12515
|
+
},
|
|
12516
|
+
children: /* @__PURE__ */ jsx52(SelectValue, { children: isLoading || !selectedTokenSymbol ? /* @__PURE__ */ jsx52("span", { className: "uf-text-xs uf-font-light uf-text-muted-foreground", children: t7.loading }) : selectedToken ? renderTokenItem(selectedToken) : /* @__PURE__ */ jsx52("span", { className: "uf-text-xs uf-font-normal", children: selectedTokenSymbol }) })
|
|
12517
|
+
}
|
|
12518
|
+
),
|
|
12519
|
+
/* @__PURE__ */ jsx52(
|
|
12520
|
+
SelectContent,
|
|
12521
|
+
{
|
|
12522
|
+
className: "uf-bg-secondary uf-border uf-text-foreground uf-max-h-[300px]",
|
|
12523
|
+
style: {
|
|
12524
|
+
border: `1px solid ${isDarkMode ? "rgba(255,255,255,0.15)" : "rgba(0,0,0,0.15)"}`,
|
|
12525
|
+
...fonts.regular ? { "--uf-font-family": fonts.regular } : {}
|
|
12526
|
+
},
|
|
12527
|
+
children: tokens.map((tokenData) => /* @__PURE__ */ jsx52(
|
|
12528
|
+
SelectItem,
|
|
12529
|
+
{
|
|
12530
|
+
value: tokenData.symbol,
|
|
12531
|
+
className: "focus:uf-bg-accent focus:uf-text-foreground",
|
|
12532
|
+
children: renderTokenItem(tokenData)
|
|
12533
|
+
},
|
|
12534
|
+
tokenData.symbol
|
|
12535
|
+
))
|
|
12536
|
+
}
|
|
12537
|
+
)
|
|
12538
|
+
]
|
|
12539
|
+
}
|
|
12540
|
+
)
|
|
12541
|
+
] }),
|
|
12542
|
+
/* @__PURE__ */ jsxs45("div", { children: [
|
|
12543
|
+
/* @__PURE__ */ jsx52(
|
|
12544
|
+
"div",
|
|
12545
|
+
{
|
|
12546
|
+
className: "uf-text-xs uf-mb-2 uf-flex uf-items-center uf-gap-1",
|
|
12547
|
+
style: { color: components.card.labelColor },
|
|
12548
|
+
children: t7.receiveChain
|
|
12549
|
+
}
|
|
12550
|
+
),
|
|
12551
|
+
/* @__PURE__ */ jsxs45(
|
|
12552
|
+
Select,
|
|
12553
|
+
{
|
|
12554
|
+
value: selectedChainKey ?? "",
|
|
12555
|
+
onValueChange: onChainChange,
|
|
12556
|
+
disabled: isLoading || availableChainsForToken.length === 0,
|
|
12557
|
+
children: [
|
|
12558
|
+
/* @__PURE__ */ jsx52(
|
|
12559
|
+
SelectTrigger,
|
|
12560
|
+
{
|
|
12561
|
+
className: "uf-h-10 hover:uf-opacity-90 uf-text-foreground disabled:uf-opacity-50",
|
|
12562
|
+
style: {
|
|
12563
|
+
backgroundColor: components.card.backgroundColor,
|
|
12564
|
+
border: `${components.card.borderWidth}px solid ${components.card.borderColor}`
|
|
12565
|
+
},
|
|
12566
|
+
children: /* @__PURE__ */ jsx52(SelectValue, { children: isLoading || !selectedChainKey ? /* @__PURE__ */ jsx52("span", { className: "uf-text-xs uf-font-light uf-text-muted-foreground", children: t7.loading }) : currentChainData ? renderChainItem(currentChainData) : /* @__PURE__ */ jsx52("span", { className: "uf-text-xs uf-font-normal", children: selectedChainKey }) })
|
|
12567
|
+
}
|
|
12568
|
+
),
|
|
12569
|
+
/* @__PURE__ */ jsx52(
|
|
12570
|
+
SelectContent,
|
|
12571
|
+
{
|
|
12572
|
+
align: "end",
|
|
12573
|
+
className: "uf-bg-secondary uf-border uf-text-foreground uf-max-h-[300px] uf-min-w-[200px]",
|
|
12574
|
+
style: {
|
|
12575
|
+
border: `1px solid ${isDarkMode ? "rgba(255,255,255,0.15)" : "rgba(0,0,0,0.15)"}`,
|
|
12576
|
+
...fonts.regular ? { "--uf-font-family": fonts.regular } : {}
|
|
12577
|
+
},
|
|
12578
|
+
children: availableChainsForToken.length === 0 ? /* @__PURE__ */ jsx52("div", { className: "uf-px-2 uf-py-3 uf-text-xs uf-text-muted-foreground uf-text-center", children: "No chains available" }) : availableChainsForToken.map((chainData) => {
|
|
12579
|
+
const chainKey = getChainKey4(chainData.chain_id, chainData.chain_type);
|
|
12580
|
+
return /* @__PURE__ */ jsx52(
|
|
12581
|
+
SelectItem,
|
|
12582
|
+
{
|
|
12583
|
+
value: chainKey,
|
|
12584
|
+
className: "focus:uf-bg-accent focus:uf-text-foreground",
|
|
12585
|
+
children: renderChainItem(chainData)
|
|
12586
|
+
},
|
|
12587
|
+
chainKey
|
|
12588
|
+
);
|
|
12589
|
+
})
|
|
12590
|
+
}
|
|
12591
|
+
)
|
|
12592
|
+
]
|
|
12593
|
+
}
|
|
12594
|
+
)
|
|
12595
|
+
] })
|
|
12596
|
+
] });
|
|
12597
|
+
}
|
|
12598
|
+
|
|
12599
|
+
// src/components/withdrawals/WithdrawForm.tsx
|
|
12600
|
+
import { useState as useState29, useCallback as useCallback5, useMemo as useMemo10, useEffect as useEffect23 } from "react";
|
|
12601
|
+
import {
|
|
12602
|
+
AlertTriangle as AlertTriangle2,
|
|
12603
|
+
ArrowUpDown,
|
|
12604
|
+
ChevronDown as ChevronDown7,
|
|
12605
|
+
ChevronUp as ChevronUp6,
|
|
12606
|
+
Clock as Clock4,
|
|
12607
|
+
ClipboardPaste,
|
|
12608
|
+
DollarSign as DollarSign3,
|
|
12609
|
+
Loader2 as Loader25,
|
|
12610
|
+
ShieldCheck as ShieldCheck3,
|
|
12611
|
+
Wallet as Wallet3
|
|
12612
|
+
} from "lucide-react";
|
|
12613
|
+
|
|
12614
|
+
// src/hooks/use-verify-recipient-address.ts
|
|
12615
|
+
import { useQuery as useQuery13 } from "@tanstack/react-query";
|
|
12616
|
+
import { verifyRecipientAddress as verifyRecipientAddress2 } from "@unifold/core";
|
|
12617
|
+
function useVerifyRecipientAddress(params) {
|
|
12618
|
+
const {
|
|
12619
|
+
chainType,
|
|
12620
|
+
chainId,
|
|
12621
|
+
tokenAddress,
|
|
12622
|
+
recipientAddress,
|
|
12623
|
+
publishableKey,
|
|
12624
|
+
enabled = true
|
|
12625
|
+
} = params;
|
|
12626
|
+
const trimmedAddress = recipientAddress?.trim() || "";
|
|
12627
|
+
const hasAllParams = !!chainType && !!chainId && !!tokenAddress && trimmedAddress.length > 0;
|
|
12628
|
+
return useQuery13({
|
|
12629
|
+
queryKey: [
|
|
12630
|
+
"unifold",
|
|
12631
|
+
"verifyRecipientAddress",
|
|
12632
|
+
chainType ?? null,
|
|
12633
|
+
chainId ?? null,
|
|
12634
|
+
tokenAddress ?? null,
|
|
12635
|
+
trimmedAddress,
|
|
12636
|
+
publishableKey
|
|
12637
|
+
],
|
|
12638
|
+
queryFn: () => verifyRecipientAddress2(
|
|
12639
|
+
{
|
|
12640
|
+
chain_type: chainType,
|
|
12641
|
+
chain_id: chainId,
|
|
12642
|
+
token_address: tokenAddress,
|
|
12643
|
+
recipient_address: trimmedAddress
|
|
12644
|
+
},
|
|
12645
|
+
publishableKey
|
|
12646
|
+
),
|
|
12647
|
+
enabled: enabled && hasAllParams,
|
|
12648
|
+
staleTime: 1e3 * 60 * 5,
|
|
12649
|
+
gcTime: 1e3 * 60 * 30,
|
|
12650
|
+
retry: 1,
|
|
12651
|
+
refetchOnMount: false,
|
|
12652
|
+
refetchOnWindowFocus: false
|
|
12653
|
+
});
|
|
12654
|
+
}
|
|
12655
|
+
|
|
12656
|
+
// src/components/withdrawals/send-withdraw.ts
|
|
12657
|
+
import {
|
|
12658
|
+
buildSolanaTransaction as buildSolanaTransaction2,
|
|
12659
|
+
sendSolanaTransaction as sendSolanaTransactionToBackend2
|
|
12660
|
+
} from "@unifold/core";
|
|
12661
|
+
async function sendEvmWithdraw(params) {
|
|
12662
|
+
const {
|
|
12663
|
+
provider,
|
|
12664
|
+
fromAddress,
|
|
12665
|
+
depositWalletAddress,
|
|
12666
|
+
sourceTokenAddress,
|
|
12667
|
+
sourceChainId,
|
|
12668
|
+
amountBaseUnit
|
|
12669
|
+
} = params;
|
|
12670
|
+
const currentChainIdHex = await provider.request({
|
|
12671
|
+
method: "eth_chainId",
|
|
12672
|
+
params: []
|
|
12673
|
+
});
|
|
12674
|
+
const currentChainId = parseInt(currentChainIdHex, 16).toString();
|
|
12675
|
+
if (currentChainId !== sourceChainId) {
|
|
12676
|
+
const requiredHex = "0x" + parseInt(sourceChainId).toString(16);
|
|
12677
|
+
try {
|
|
12678
|
+
await provider.request({
|
|
12679
|
+
method: "wallet_switchEthereumChain",
|
|
12680
|
+
params: [{ chainId: requiredHex }]
|
|
12681
|
+
});
|
|
12682
|
+
const newHex = await provider.request({ method: "eth_chainId", params: [] });
|
|
12683
|
+
if (parseInt(newHex, 16).toString() !== sourceChainId) {
|
|
12684
|
+
throw new Error(`Failed to switch to chain ${sourceChainId}. Please switch manually.`);
|
|
12685
|
+
}
|
|
12686
|
+
} catch (err) {
|
|
12687
|
+
if (err && typeof err === "object" && "code" in err) {
|
|
12688
|
+
const e = err;
|
|
12689
|
+
if (e.code === 4902) throw new Error(`Chain ${sourceChainId} is not configured in your wallet.`);
|
|
12690
|
+
if (e.code === 4001) throw new Error("You must approve the network switch to withdraw.");
|
|
12691
|
+
}
|
|
12692
|
+
throw err;
|
|
12693
|
+
}
|
|
12694
|
+
}
|
|
12695
|
+
const isNative = sourceTokenAddress === "native" || sourceTokenAddress === "0x0000000000000000000000000000000000000000" || sourceTokenAddress === "";
|
|
12696
|
+
const amountBig = BigInt(amountBaseUnit);
|
|
12697
|
+
const txParams = isNative ? { from: fromAddress, to: depositWalletAddress, value: "0x" + amountBig.toString(16) } : {
|
|
12698
|
+
from: fromAddress,
|
|
12699
|
+
to: sourceTokenAddress,
|
|
12700
|
+
data: "0xa9059cbb" + depositWalletAddress.slice(2).padStart(64, "0") + amountBig.toString(16).padStart(64, "0")
|
|
12701
|
+
};
|
|
12702
|
+
let gasEstimate;
|
|
12703
|
+
try {
|
|
12704
|
+
const hex = await provider.request({ method: "eth_estimateGas", params: [txParams] });
|
|
12705
|
+
gasEstimate = BigInt(hex);
|
|
12706
|
+
} catch {
|
|
12707
|
+
gasEstimate = isNative ? BigInt(21e3) : BigInt(65e3);
|
|
12708
|
+
}
|
|
12709
|
+
const gasPrice = BigInt(await provider.request({ method: "eth_gasPrice", params: [] }));
|
|
12710
|
+
const gasWithBuffer = gasEstimate * BigInt(120) / BigInt(100);
|
|
12711
|
+
const gasCost = gasWithBuffer * gasPrice;
|
|
12712
|
+
const ethBalance = BigInt(
|
|
12713
|
+
await provider.request({ method: "eth_getBalance", params: [fromAddress, "latest"] })
|
|
12714
|
+
);
|
|
12715
|
+
const totalRequired = isNative ? gasCost + amountBig : gasCost;
|
|
12716
|
+
if (ethBalance < totalRequired) {
|
|
12717
|
+
const gasFmt = (Number(gasCost) / 1e18).toFixed(6);
|
|
12718
|
+
if (isNative) {
|
|
12719
|
+
throw new Error(`Insufficient balance. Need ${(Number(totalRequired) / 1e18).toFixed(6)} ETH (amount + ~${gasFmt} gas).`);
|
|
12720
|
+
}
|
|
12721
|
+
throw new Error(`Insufficient ETH for gas. Need ~${gasFmt} ETH for fees.`);
|
|
12722
|
+
}
|
|
12723
|
+
const txHash = await provider.request({ method: "eth_sendTransaction", params: [txParams] });
|
|
12724
|
+
return txHash;
|
|
12725
|
+
}
|
|
12726
|
+
async function sendSolanaWithdraw(params) {
|
|
12727
|
+
const {
|
|
12728
|
+
provider,
|
|
12729
|
+
fromAddress,
|
|
12730
|
+
depositWalletAddress,
|
|
12731
|
+
sourceTokenAddress,
|
|
12732
|
+
amountBaseUnit,
|
|
12733
|
+
publishableKey
|
|
12734
|
+
} = params;
|
|
12735
|
+
if (!provider.publicKey) {
|
|
12736
|
+
await provider.connect();
|
|
12737
|
+
}
|
|
12738
|
+
const buildResponse = await buildSolanaTransaction2(
|
|
12739
|
+
{
|
|
12740
|
+
chain_id: "mainnet",
|
|
12741
|
+
token_address: sourceTokenAddress === "" ? "native" : sourceTokenAddress,
|
|
12742
|
+
source_address: fromAddress,
|
|
12743
|
+
destination_address: depositWalletAddress,
|
|
12744
|
+
amount: amountBaseUnit
|
|
12745
|
+
},
|
|
12746
|
+
publishableKey
|
|
12747
|
+
);
|
|
12748
|
+
const { VersionedTransaction } = await import(
|
|
12749
|
+
/* @vite-ignore */
|
|
12750
|
+
"@solana/web3.js"
|
|
12751
|
+
);
|
|
12752
|
+
const binaryString = atob(buildResponse.transaction);
|
|
12753
|
+
const bytes = new Uint8Array(binaryString.length);
|
|
12754
|
+
for (let i = 0; i < binaryString.length; i++) {
|
|
12755
|
+
bytes[i] = binaryString.charCodeAt(i);
|
|
12756
|
+
}
|
|
12757
|
+
const transaction = VersionedTransaction.deserialize(bytes);
|
|
12758
|
+
const signedTransaction = await provider.signTransaction(transaction);
|
|
12759
|
+
const serialized = signedTransaction.serialize();
|
|
12760
|
+
let binaryStr = "";
|
|
12761
|
+
for (let i = 0; i < serialized.length; i++) {
|
|
12762
|
+
binaryStr += String.fromCharCode(serialized[i]);
|
|
12763
|
+
}
|
|
12764
|
+
const sendResponse = await sendSolanaTransactionToBackend2(
|
|
12765
|
+
{ chain_id: "mainnet", signed_transaction: btoa(binaryStr) },
|
|
12766
|
+
publishableKey
|
|
12767
|
+
);
|
|
12768
|
+
return sendResponse.signature;
|
|
12769
|
+
}
|
|
12770
|
+
async function detectBrowserWallet(chainType, senderAddress) {
|
|
12771
|
+
const win = typeof window !== "undefined" ? window : null;
|
|
12772
|
+
if (!win || !senderAddress) return null;
|
|
12773
|
+
const anyWin = win;
|
|
12774
|
+
if (chainType === "solana") {
|
|
12775
|
+
const solProviders = [];
|
|
12776
|
+
if (win.phantom?.solana) solProviders.push({ provider: win.phantom.solana, name: "Phantom" });
|
|
12777
|
+
if (anyWin.solflare) solProviders.push({ provider: anyWin.solflare, name: "Solflare" });
|
|
12778
|
+
if (anyWin.backpack) solProviders.push({ provider: anyWin.backpack, name: "Backpack" });
|
|
12779
|
+
if (anyWin.trustwallet?.solana) solProviders.push({ provider: anyWin.trustwallet.solana, name: "Trust Wallet" });
|
|
12780
|
+
for (const { provider, name } of solProviders) {
|
|
12781
|
+
if (!provider) continue;
|
|
12782
|
+
try {
|
|
12783
|
+
let addr;
|
|
12784
|
+
if (provider.isConnected && provider.publicKey) {
|
|
12785
|
+
addr = provider.publicKey.toString();
|
|
12786
|
+
} else {
|
|
12787
|
+
const resp = await provider.connect({ onlyIfTrusted: true });
|
|
12788
|
+
if (resp?.publicKey) addr = resp.publicKey.toString();
|
|
12789
|
+
}
|
|
12790
|
+
if (addr && addr === senderAddress) {
|
|
12791
|
+
return { chainFamily: "solana", provider, name, address: addr };
|
|
12792
|
+
}
|
|
12793
|
+
} catch {
|
|
12794
|
+
}
|
|
12795
|
+
}
|
|
12796
|
+
}
|
|
12797
|
+
if (chainType === "ethereum") {
|
|
12798
|
+
const evmProviders = [];
|
|
12799
|
+
const seen = /* @__PURE__ */ new Set();
|
|
12800
|
+
const add = (p, name) => {
|
|
12801
|
+
if (p && typeof p.request === "function" && !seen.has(p)) {
|
|
12802
|
+
seen.add(p);
|
|
12803
|
+
evmProviders.push({ provider: p, name });
|
|
12804
|
+
}
|
|
12805
|
+
};
|
|
12806
|
+
add(anyWin.phantom?.ethereum, "Phantom");
|
|
12807
|
+
add(anyWin.coinbaseWalletExtension, "Coinbase");
|
|
12808
|
+
add(anyWin.trustwallet?.ethereum, "Trust Wallet");
|
|
12809
|
+
add(anyWin.okxwallet, "OKX Wallet");
|
|
12810
|
+
if (anyWin.__eip6963Providers) {
|
|
12811
|
+
for (const detail of anyWin.__eip6963Providers) {
|
|
12812
|
+
const rdns = detail.info?.rdns || "";
|
|
12813
|
+
let name = detail.info?.name || "Wallet";
|
|
12814
|
+
if (rdns.includes("metamask")) name = "MetaMask";
|
|
12815
|
+
else if (rdns.includes("rabby")) name = "Rabby";
|
|
12816
|
+
else if (rdns.includes("rainbow")) name = "Rainbow";
|
|
12817
|
+
add(detail.provider, name);
|
|
12818
|
+
}
|
|
12819
|
+
}
|
|
12820
|
+
if (win.ethereum) {
|
|
12821
|
+
const eth = win.ethereum;
|
|
12822
|
+
let name = "Wallet";
|
|
12823
|
+
if (eth.isMetaMask && !eth.isPhantom && !eth.isRabby) name = "MetaMask";
|
|
12824
|
+
else if (eth.isRabby) name = "Rabby";
|
|
12825
|
+
else if (eth.isRainbow) name = "Rainbow";
|
|
12826
|
+
else if (eth.isCoinbaseWallet) name = "Coinbase";
|
|
12827
|
+
add(eth, name);
|
|
12828
|
+
}
|
|
12829
|
+
for (const { provider, name } of evmProviders) {
|
|
12830
|
+
try {
|
|
12831
|
+
const accounts = await provider.request({ method: "eth_accounts" });
|
|
12832
|
+
if (accounts?.length > 0 && accounts[0].toLowerCase() === senderAddress.toLowerCase()) {
|
|
12833
|
+
return { chainFamily: "evm", provider, name, address: accounts[0] };
|
|
12834
|
+
}
|
|
12835
|
+
} catch {
|
|
12836
|
+
}
|
|
12837
|
+
}
|
|
12838
|
+
}
|
|
12839
|
+
return null;
|
|
12840
|
+
}
|
|
12841
|
+
|
|
12842
|
+
// src/components/withdrawals/WithdrawForm.tsx
|
|
12843
|
+
import { Fragment as Fragment10, jsx as jsx53, jsxs as jsxs46 } from "react/jsx-runtime";
|
|
12844
|
+
var t8 = i18n.withdrawModal;
|
|
12845
|
+
var tCrypto = i18n.transferCrypto;
|
|
12846
|
+
function formatProcessingTime2(seconds) {
|
|
12847
|
+
if (seconds === null) {
|
|
12848
|
+
return tCrypto.processingTime.lessThanMinutes.replace("{{minutes}}", "1");
|
|
12849
|
+
}
|
|
12850
|
+
const minutes = Math.ceil(seconds / 60);
|
|
12851
|
+
if (minutes < 60) {
|
|
12852
|
+
return tCrypto.processingTime.lessThanMinutes.replace("{{minutes}}", String(minutes));
|
|
12853
|
+
}
|
|
12854
|
+
const hours = Math.ceil(minutes / 60);
|
|
12855
|
+
return tCrypto.processingTime.lessThanHours.replace("{{hours}}", String(hours));
|
|
12856
|
+
}
|
|
12857
|
+
function computeBaseUnit(balanceBaseUnit, inputAmount, balanceAmount) {
|
|
12858
|
+
if (balanceAmount <= 0 || inputAmount <= 0) return "0";
|
|
12859
|
+
if (inputAmount >= balanceAmount) return balanceBaseUnit;
|
|
12860
|
+
const PRECISION = 10n ** 18n;
|
|
12861
|
+
const ratioScaled = BigInt(Math.round(inputAmount / balanceAmount * Number(PRECISION)));
|
|
12862
|
+
const result = BigInt(balanceBaseUnit) * ratioScaled / PRECISION;
|
|
12863
|
+
return result.toString();
|
|
12864
|
+
}
|
|
12865
|
+
function toSafeDecimalString(n, maxDecimals) {
|
|
12866
|
+
if (n === 0) return "0";
|
|
12867
|
+
return n.toFixed(maxDecimals).replace(/\.?0+$/, "");
|
|
12868
|
+
}
|
|
12869
|
+
function WithdrawForm({
|
|
12870
|
+
publishableKey,
|
|
12871
|
+
externalUserId,
|
|
12872
|
+
sourceChainType,
|
|
12873
|
+
selectedToken,
|
|
12874
|
+
selectedChain,
|
|
12875
|
+
sourceTokenSymbol,
|
|
12876
|
+
recipientAddressProp,
|
|
12877
|
+
balanceData,
|
|
12878
|
+
isLoadingBalance,
|
|
12879
|
+
minimumWithdrawAmountUsd,
|
|
12880
|
+
estimatedProcessingTime,
|
|
12881
|
+
maxSlippagePercent,
|
|
12882
|
+
priceImpactPercent,
|
|
12883
|
+
detectedWallet,
|
|
12884
|
+
sourceChainId,
|
|
12885
|
+
sourceTokenAddress,
|
|
12886
|
+
isWalletMatch,
|
|
12887
|
+
connectedWalletName,
|
|
12888
|
+
canWithdraw,
|
|
12889
|
+
onWithdraw,
|
|
12890
|
+
onWithdrawError,
|
|
12891
|
+
onDepositWalletCreation,
|
|
12892
|
+
onWithdrawSubmitted,
|
|
12893
|
+
footerLeft
|
|
12894
|
+
}) {
|
|
12895
|
+
const { colors: colors2, fonts, components } = useTheme();
|
|
12896
|
+
const [recipientAddress, setRecipientAddress] = useState29(recipientAddressProp || "");
|
|
12897
|
+
const [amount, setAmount] = useState29("");
|
|
12898
|
+
const [inputUnit, setInputUnit] = useState29("crypto");
|
|
12899
|
+
const [isSubmitting, setIsSubmitting] = useState29(false);
|
|
12900
|
+
const [submitError, setSubmitError] = useState29(null);
|
|
12901
|
+
const [detailsExpanded, setDetailsExpanded] = useState29(false);
|
|
12902
|
+
const [glossaryOpen, setGlossaryOpen] = useState29(false);
|
|
12903
|
+
useEffect23(() => {
|
|
12904
|
+
setRecipientAddress(recipientAddressProp || "");
|
|
12905
|
+
setAmount("");
|
|
12906
|
+
setInputUnit("crypto");
|
|
12907
|
+
setSubmitError(null);
|
|
12908
|
+
}, [recipientAddressProp]);
|
|
12909
|
+
const trimmedAddress = recipientAddress.trim();
|
|
12910
|
+
const [debouncedAddress, setDebouncedAddress] = useState29(trimmedAddress);
|
|
12911
|
+
useEffect23(() => {
|
|
12912
|
+
const id = setTimeout(() => setDebouncedAddress(trimmedAddress), 500);
|
|
12913
|
+
return () => clearTimeout(id);
|
|
12914
|
+
}, [trimmedAddress]);
|
|
12915
|
+
const {
|
|
12916
|
+
data: addressVerification,
|
|
12917
|
+
isLoading: isVerifyingAddress,
|
|
12918
|
+
error: verifyError
|
|
12919
|
+
} = useVerifyRecipientAddress({
|
|
12920
|
+
chainType: selectedChain?.chain_type,
|
|
12921
|
+
chainId: selectedChain?.chain_id,
|
|
12922
|
+
tokenAddress: selectedChain?.token_address,
|
|
12923
|
+
recipientAddress: debouncedAddress,
|
|
12924
|
+
publishableKey,
|
|
12925
|
+
enabled: debouncedAddress.length > 5 && !!selectedChain
|
|
12926
|
+
});
|
|
12927
|
+
const isDebouncing = trimmedAddress !== debouncedAddress;
|
|
12928
|
+
const addressError = useMemo10(() => {
|
|
12929
|
+
if (!trimmedAddress || trimmedAddress.length <= 5) return null;
|
|
12930
|
+
if (isDebouncing || isVerifyingAddress) return null;
|
|
12931
|
+
if (verifyError) return t8.invalidAddress;
|
|
12932
|
+
if (addressVerification && !addressVerification.valid) {
|
|
12933
|
+
if (addressVerification.failure_code === "account_not_found")
|
|
12934
|
+
return `Account not found on ${selectedChain?.chain_name}`;
|
|
12935
|
+
if (addressVerification.failure_code === "not_opted_in")
|
|
12936
|
+
return `Recipient has not opted in to ${selectedToken?.symbol} on ${selectedChain?.chain_name}`;
|
|
12937
|
+
return t8.invalidAddress;
|
|
12938
|
+
}
|
|
12939
|
+
return null;
|
|
12940
|
+
}, [trimmedAddress, isDebouncing, isVerifyingAddress, verifyError, addressVerification, selectedChain, selectedToken]);
|
|
12941
|
+
const isAddressValid = !isDebouncing && !!addressVerification?.valid && !addressError;
|
|
12942
|
+
const exchangeRate = useMemo10(() => {
|
|
12943
|
+
if (!balanceData?.exchangeRate) return 0;
|
|
12944
|
+
return parseFloat(balanceData.exchangeRate);
|
|
12945
|
+
}, [balanceData]);
|
|
12946
|
+
const balanceCrypto = useMemo10(() => {
|
|
12947
|
+
if (!balanceData?.balanceHuman) return 0;
|
|
12948
|
+
return parseFloat(balanceData.balanceHuman);
|
|
12949
|
+
}, [balanceData]);
|
|
12950
|
+
const balanceUsdNum = useMemo10(() => {
|
|
12951
|
+
if (!balanceData?.balanceUsd) return 0;
|
|
12952
|
+
return parseFloat(balanceData.balanceUsd);
|
|
12953
|
+
}, [balanceData]);
|
|
12954
|
+
const tokenSymbol = sourceTokenSymbol || balanceData?.symbol || "TOKEN";
|
|
12955
|
+
const sourceDecimals = balanceData?.decimals ?? 6;
|
|
12956
|
+
const cryptoAmountFromInput = useMemo10(() => {
|
|
12957
|
+
const val = parseFloat(amount);
|
|
12958
|
+
if (!val || val <= 0) return 0;
|
|
12959
|
+
if (inputUnit === "crypto") return val;
|
|
12960
|
+
return exchangeRate > 0 ? val / exchangeRate : 0;
|
|
12961
|
+
}, [amount, inputUnit, exchangeRate]);
|
|
12962
|
+
const fiatAmountFromInput = useMemo10(() => {
|
|
12963
|
+
const val = parseFloat(amount);
|
|
12964
|
+
if (!val || val <= 0) return 0;
|
|
12965
|
+
if (inputUnit === "fiat") return val;
|
|
12966
|
+
return val * exchangeRate;
|
|
12967
|
+
}, [amount, inputUnit, exchangeRate]);
|
|
12968
|
+
const convertedDisplay = useMemo10(() => {
|
|
12969
|
+
if (!amount || parseFloat(amount) <= 0) return null;
|
|
12970
|
+
if (inputUnit === "crypto") {
|
|
12971
|
+
return `$${fiatAmountFromInput.toLocaleString(void 0, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;
|
|
12972
|
+
}
|
|
12973
|
+
return `${cryptoAmountFromInput.toLocaleString(void 0, { minimumFractionDigits: 2, maximumFractionDigits: 6 })} ${tokenSymbol}`;
|
|
12974
|
+
}, [amount, inputUnit, fiatAmountFromInput, cryptoAmountFromInput, tokenSymbol]);
|
|
12975
|
+
const balanceDisplay = useMemo10(() => {
|
|
12976
|
+
if (isLoadingBalance || !balanceData) return null;
|
|
12977
|
+
if (inputUnit === "crypto") {
|
|
12978
|
+
return `${balanceCrypto.toLocaleString(void 0, { minimumFractionDigits: 2, maximumFractionDigits: 2 })} ${tokenSymbol}`;
|
|
12979
|
+
}
|
|
12980
|
+
return `$${balanceUsdNum.toLocaleString(void 0, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;
|
|
12981
|
+
}, [isLoadingBalance, balanceData, inputUnit, balanceCrypto, balanceUsdNum, tokenSymbol]);
|
|
12982
|
+
const handleSwitchUnit = useCallback5(() => {
|
|
12983
|
+
const val = parseFloat(amount);
|
|
12984
|
+
if (!val || val <= 0 || exchangeRate <= 0) {
|
|
12985
|
+
setInputUnit((u) => u === "crypto" ? "fiat" : "crypto");
|
|
12986
|
+
setAmount("");
|
|
12987
|
+
return;
|
|
12988
|
+
}
|
|
12989
|
+
if (inputUnit === "crypto") {
|
|
12990
|
+
const fiat = val * exchangeRate;
|
|
12991
|
+
setAmount(fiat.toFixed(2));
|
|
12992
|
+
setInputUnit("fiat");
|
|
12993
|
+
} else {
|
|
12994
|
+
const crypto = val / exchangeRate;
|
|
12995
|
+
setAmount(crypto.toFixed(sourceDecimals > 6 ? 6 : sourceDecimals));
|
|
12996
|
+
setInputUnit("crypto");
|
|
12997
|
+
}
|
|
12998
|
+
}, [amount, inputUnit, exchangeRate, sourceDecimals]);
|
|
12999
|
+
const handleMaxClick = useCallback5(() => {
|
|
13000
|
+
if (inputUnit === "crypto") {
|
|
13001
|
+
if (balanceCrypto <= 0) return;
|
|
13002
|
+
setAmount(balanceData?.balanceHuman ?? "0");
|
|
13003
|
+
} else {
|
|
13004
|
+
if (balanceUsdNum <= 0) return;
|
|
13005
|
+
setAmount((Math.floor(balanceUsdNum * 100) / 100).toFixed(2));
|
|
13006
|
+
}
|
|
13007
|
+
}, [inputUnit, balanceCrypto, balanceUsdNum, balanceData]);
|
|
13008
|
+
const isBelowMinimum = minimumWithdrawAmountUsd !== null && fiatAmountFromInput > 0 && fiatAmountFromInput < minimumWithdrawAmountUsd;
|
|
13009
|
+
const isOverBalance = inputUnit === "crypto" ? cryptoAmountFromInput > 0 && balanceCrypto > 0 && cryptoAmountFromInput > balanceCrypto : fiatAmountFromInput > 0 && balanceUsdNum > 0 && fiatAmountFromInput > balanceUsdNum;
|
|
13010
|
+
const isFormValid = trimmedAddress.length > 0 && amount.trim().length > 0 && cryptoAmountFromInput > 0 && isAddressValid && !isBelowMinimum && !isOverBalance && !!balanceData;
|
|
13011
|
+
const handleWithdraw = useCallback5(async () => {
|
|
13012
|
+
if (!selectedToken || !selectedChain) return;
|
|
13013
|
+
if (!isFormValid) return;
|
|
13014
|
+
setIsSubmitting(true);
|
|
13015
|
+
setSubmitError(null);
|
|
13016
|
+
try {
|
|
13017
|
+
const depositWallet = await onDepositWalletCreation({
|
|
13018
|
+
destinationChainType: selectedChain.chain_type,
|
|
13019
|
+
destinationChainId: selectedChain.chain_id,
|
|
13020
|
+
destinationTokenAddress: selectedChain.token_address,
|
|
13021
|
+
recipientAddress: trimmedAddress
|
|
13022
|
+
});
|
|
13023
|
+
const amountBaseUnit = computeBaseUnit(
|
|
13024
|
+
balanceData.balanceBaseUnit,
|
|
13025
|
+
parseFloat(amount),
|
|
13026
|
+
inputUnit === "crypto" ? balanceCrypto : balanceUsdNum
|
|
13027
|
+
);
|
|
13028
|
+
const humanAmount = toSafeDecimalString(cryptoAmountFromInput, sourceDecimals);
|
|
13029
|
+
const txInfo = {
|
|
13030
|
+
sourceChainType,
|
|
13031
|
+
sourceChainId,
|
|
13032
|
+
sourceTokenAddress,
|
|
13033
|
+
sourceTokenSymbol: tokenSymbol,
|
|
13034
|
+
destinationChainType: selectedChain.chain_type,
|
|
13035
|
+
destinationChainId: selectedChain.chain_id,
|
|
13036
|
+
destinationTokenAddress: selectedChain.token_address,
|
|
13037
|
+
destinationTokenSymbol: selectedToken.symbol,
|
|
13038
|
+
amount: humanAmount,
|
|
13039
|
+
amountBaseUnit,
|
|
13040
|
+
withdrawIntentAddress: depositWallet.address,
|
|
13041
|
+
recipientAddress: trimmedAddress
|
|
13042
|
+
};
|
|
13043
|
+
if (detectedWallet) {
|
|
13044
|
+
if (detectedWallet.chainFamily === "evm") {
|
|
13045
|
+
await sendEvmWithdraw({
|
|
13046
|
+
provider: detectedWallet.provider,
|
|
13047
|
+
fromAddress: detectedWallet.address,
|
|
13048
|
+
depositWalletAddress: depositWallet.address,
|
|
13049
|
+
sourceTokenAddress,
|
|
13050
|
+
sourceChainId,
|
|
13051
|
+
amountBaseUnit
|
|
13052
|
+
});
|
|
13053
|
+
} else if (detectedWallet.chainFamily === "solana") {
|
|
13054
|
+
await sendSolanaWithdraw({
|
|
13055
|
+
provider: detectedWallet.provider,
|
|
13056
|
+
fromAddress: detectedWallet.address,
|
|
13057
|
+
depositWalletAddress: depositWallet.address,
|
|
13058
|
+
sourceTokenAddress,
|
|
13059
|
+
amountBaseUnit,
|
|
13060
|
+
publishableKey
|
|
13061
|
+
});
|
|
13062
|
+
}
|
|
13063
|
+
} else if (onWithdraw) {
|
|
13064
|
+
await onWithdraw(txInfo);
|
|
13065
|
+
} else {
|
|
13066
|
+
throw new Error("No withdrawal method available. Please connect a wallet.");
|
|
13067
|
+
}
|
|
13068
|
+
onWithdrawSubmitted?.(txInfo);
|
|
13069
|
+
} catch (err) {
|
|
13070
|
+
const raw = err instanceof Error ? err.message : "Withdrawal failed. Please try again.";
|
|
13071
|
+
setSubmitError(raw.length > 120 ? "Withdrawal failed. Please try again." : raw);
|
|
13072
|
+
onWithdrawError?.({
|
|
13073
|
+
message: raw,
|
|
13074
|
+
error: err,
|
|
13075
|
+
code: "WITHDRAW_FAILED"
|
|
13076
|
+
});
|
|
13077
|
+
} finally {
|
|
13078
|
+
setIsSubmitting(false);
|
|
13079
|
+
}
|
|
13080
|
+
}, [selectedToken, selectedChain, isFormValid, cryptoAmountFromInput, sourceDecimals, trimmedAddress, publishableKey, onWithdraw, detectedWallet, sourceTokenAddress, sourceChainId, onWithdrawError, onDepositWalletCreation, onWithdrawSubmitted, amount, inputUnit, balanceCrypto, balanceUsdNum, balanceData]);
|
|
13081
|
+
return /* @__PURE__ */ jsxs46(Fragment10, { children: [
|
|
13082
|
+
/* @__PURE__ */ jsxs46("div", { children: [
|
|
13083
|
+
/* @__PURE__ */ jsx53(
|
|
13084
|
+
"div",
|
|
13085
|
+
{
|
|
13086
|
+
className: "uf-text-xs uf-mb-1.5",
|
|
13087
|
+
style: { color: components.card.labelColor, fontFamily: fonts.medium },
|
|
13088
|
+
children: t8.recipientAddress
|
|
13089
|
+
}
|
|
13090
|
+
),
|
|
13091
|
+
/* @__PURE__ */ jsx53(
|
|
13092
|
+
"style",
|
|
13093
|
+
{
|
|
13094
|
+
dangerouslySetInnerHTML: {
|
|
13095
|
+
__html: `.uf-withdraw-addr::placeholder { color: ${components.search.placeholderColor}; }`
|
|
13096
|
+
}
|
|
13097
|
+
}
|
|
13098
|
+
),
|
|
13099
|
+
/* @__PURE__ */ jsxs46(
|
|
13100
|
+
"div",
|
|
13101
|
+
{
|
|
13102
|
+
className: "uf-flex uf-items-center uf-gap-1 uf-pr-2",
|
|
13103
|
+
style: {
|
|
13104
|
+
backgroundColor: components.search.backgroundColor,
|
|
13105
|
+
borderRadius: components.input.borderRadius,
|
|
13106
|
+
border: `${components.input.borderWidth}px solid ${addressError ? colors2.error : components.input.borderColor}`
|
|
13107
|
+
},
|
|
13108
|
+
children: [
|
|
13109
|
+
/* @__PURE__ */ jsx53(
|
|
13110
|
+
"input",
|
|
13111
|
+
{
|
|
13112
|
+
type: "text",
|
|
13113
|
+
placeholder: t8.recipientAddressPlaceholder,
|
|
13114
|
+
value: recipientAddress,
|
|
13115
|
+
onChange: (e) => {
|
|
13116
|
+
setRecipientAddress(e.target.value);
|
|
13117
|
+
setSubmitError(null);
|
|
13118
|
+
},
|
|
13119
|
+
className: "uf-withdraw-addr uf-flex-1 uf-min-w-0 uf-px-3 uf-py-2.5 uf-text-sm uf-bg-transparent uf-outline-none",
|
|
13120
|
+
style: {
|
|
13121
|
+
color: components.search.inputColor,
|
|
13122
|
+
fontFamily: fonts.regular
|
|
13123
|
+
}
|
|
13124
|
+
}
|
|
13125
|
+
),
|
|
13126
|
+
/* @__PURE__ */ jsx53(
|
|
13127
|
+
"button",
|
|
13128
|
+
{
|
|
13129
|
+
type: "button",
|
|
13130
|
+
onClick: async () => {
|
|
13131
|
+
try {
|
|
13132
|
+
const text = await navigator.clipboard.readText();
|
|
13133
|
+
if (text) {
|
|
13134
|
+
setRecipientAddress(text.trim());
|
|
13135
|
+
setSubmitError(null);
|
|
13136
|
+
}
|
|
13137
|
+
} catch {
|
|
13138
|
+
}
|
|
13139
|
+
},
|
|
13140
|
+
className: "uf-flex-shrink-0 uf-p-1 uf-rounded uf-transition-colors hover:uf-opacity-70",
|
|
13141
|
+
style: { color: colors2.foregroundMuted },
|
|
13142
|
+
title: "Paste from clipboard",
|
|
13143
|
+
children: /* @__PURE__ */ jsx53(ClipboardPaste, { className: "uf-w-4 uf-h-4" })
|
|
13144
|
+
}
|
|
13145
|
+
)
|
|
13146
|
+
]
|
|
13147
|
+
}
|
|
13148
|
+
),
|
|
13149
|
+
(isDebouncing || isVerifyingAddress) && trimmedAddress.length > 5 && /* @__PURE__ */ jsxs46("div", { className: "uf-flex uf-items-center uf-gap-1.5 uf-mt-1.5", children: [
|
|
13150
|
+
/* @__PURE__ */ jsx53(Loader25, { className: "uf-w-3 uf-h-3 uf-animate-spin", style: { color: colors2.foregroundMuted } }),
|
|
13151
|
+
/* @__PURE__ */ jsx53("span", { className: "uf-text-xs", style: { color: colors2.foregroundMuted, fontFamily: fonts.regular }, children: t8.verifyingAddress })
|
|
13152
|
+
] }),
|
|
13153
|
+
addressError && /* @__PURE__ */ jsxs46("div", { className: "uf-flex uf-items-center uf-gap-1.5 uf-mt-1.5", children: [
|
|
13154
|
+
/* @__PURE__ */ jsx53(AlertTriangle2, { className: "uf-w-3 uf-h-3", style: { color: colors2.error } }),
|
|
13155
|
+
/* @__PURE__ */ jsx53("span", { className: "uf-text-xs", style: { color: colors2.error, fontFamily: fonts.regular }, children: addressError })
|
|
13156
|
+
] })
|
|
13157
|
+
] }),
|
|
13158
|
+
/* @__PURE__ */ jsxs46("div", { children: [
|
|
13159
|
+
/* @__PURE__ */ jsxs46("div", { className: "uf-text-xs uf-mb-1.5", style: { color: components.card.labelColor, fontFamily: fonts.medium }, children: [
|
|
13160
|
+
t8.amount,
|
|
13161
|
+
minimumWithdrawAmountUsd != null && minimumWithdrawAmountUsd > 0 && /* @__PURE__ */ jsx53("span", { style: { color: colors2.warning, fontFamily: fonts.regular }, children: ` ($${minimumWithdrawAmountUsd.toFixed(2)} min)` })
|
|
13162
|
+
] }),
|
|
13163
|
+
/* @__PURE__ */ jsx53(
|
|
13164
|
+
"style",
|
|
13165
|
+
{
|
|
13166
|
+
dangerouslySetInnerHTML: {
|
|
13167
|
+
__html: `.uf-withdraw-amt::placeholder { color: ${components.search.placeholderColor}; }`
|
|
13168
|
+
}
|
|
13169
|
+
}
|
|
13170
|
+
),
|
|
13171
|
+
/* @__PURE__ */ jsxs46(
|
|
13172
|
+
"div",
|
|
13173
|
+
{
|
|
13174
|
+
className: "uf-flex uf-items-center uf-gap-2 uf-px-3 uf-py-2.5",
|
|
13175
|
+
style: {
|
|
13176
|
+
backgroundColor: components.search.backgroundColor,
|
|
13177
|
+
borderRadius: components.input.borderRadius,
|
|
13178
|
+
border: `${components.input.borderWidth}px solid ${components.input.borderColor}`
|
|
13179
|
+
},
|
|
13180
|
+
children: [
|
|
13181
|
+
/* @__PURE__ */ jsx53(
|
|
13182
|
+
"input",
|
|
13183
|
+
{
|
|
13184
|
+
type: "text",
|
|
13185
|
+
inputMode: "decimal",
|
|
13186
|
+
placeholder: "0.00",
|
|
13187
|
+
value: amount,
|
|
13188
|
+
onChange: (e) => {
|
|
13189
|
+
const val = e.target.value;
|
|
13190
|
+
if (val === "" || /^\d*\.?\d*$/.test(val)) {
|
|
13191
|
+
setAmount(val);
|
|
13192
|
+
setSubmitError(null);
|
|
13193
|
+
}
|
|
13194
|
+
},
|
|
13195
|
+
className: "uf-withdraw-amt uf-flex-1 uf-min-w-0 uf-bg-transparent uf-text-sm uf-outline-none",
|
|
13196
|
+
style: {
|
|
13197
|
+
color: components.search.inputColor,
|
|
13198
|
+
fontFamily: fonts.regular
|
|
13199
|
+
}
|
|
13200
|
+
}
|
|
13201
|
+
),
|
|
13202
|
+
/* @__PURE__ */ jsx53("span", { className: "uf-text-sm uf-shrink-0", style: { color: colors2.foregroundMuted, fontFamily: fonts.medium }, children: inputUnit === "crypto" ? tokenSymbol : "USD" }),
|
|
13203
|
+
/* @__PURE__ */ jsx53(
|
|
13204
|
+
"button",
|
|
13205
|
+
{
|
|
13206
|
+
type: "button",
|
|
13207
|
+
onClick: handleMaxClick,
|
|
13208
|
+
className: "uf-shrink-0 uf-px-2 uf-py-0.5 uf-rounded-md uf-text-xs uf-font-medium uf-transition-colors hover:uf-opacity-80",
|
|
13209
|
+
style: { backgroundColor: colors2.primary + "20", color: colors2.primary, fontFamily: fonts.medium },
|
|
13210
|
+
children: "Max"
|
|
13211
|
+
}
|
|
13212
|
+
)
|
|
13213
|
+
]
|
|
13214
|
+
}
|
|
13215
|
+
),
|
|
13216
|
+
/* @__PURE__ */ jsxs46("div", { className: "uf-flex uf-items-center uf-justify-between uf-mt-1.5 uf-px-3", children: [
|
|
13217
|
+
/* @__PURE__ */ jsxs46("div", { className: "uf-flex uf-items-center uf-gap-1", children: [
|
|
13218
|
+
/* @__PURE__ */ jsx53("span", { className: "uf-text-xs", style: { color: colors2.foregroundMuted, fontFamily: fonts.regular }, children: convertedDisplay || (inputUnit === "crypto" ? "$0.00" : `0.00 ${tokenSymbol}`) }),
|
|
13219
|
+
exchangeRate > 0 && /* @__PURE__ */ jsx53(
|
|
13220
|
+
"button",
|
|
13221
|
+
{
|
|
13222
|
+
type: "button",
|
|
13223
|
+
onClick: handleSwitchUnit,
|
|
13224
|
+
className: "uf-p-0.5 uf-rounded uf-transition-colors hover:uf-opacity-70",
|
|
13225
|
+
style: { color: colors2.foregroundMuted },
|
|
13226
|
+
title: "Switch unit",
|
|
13227
|
+
children: /* @__PURE__ */ jsx53(ArrowUpDown, { className: "uf-w-3 uf-h-3" })
|
|
13228
|
+
}
|
|
13229
|
+
)
|
|
13230
|
+
] }),
|
|
13231
|
+
/* @__PURE__ */ jsxs46("div", { children: [
|
|
13232
|
+
balanceDisplay && /* @__PURE__ */ jsxs46("span", { className: "uf-text-xs", style: { color: colors2.foregroundMuted, fontFamily: fonts.regular }, children: [
|
|
13233
|
+
t8.balance,
|
|
13234
|
+
": ",
|
|
13235
|
+
balanceDisplay
|
|
13236
|
+
] }),
|
|
13237
|
+
isLoadingBalance && /* @__PURE__ */ jsx53("div", { className: "uf-h-3 uf-w-16 uf-bg-muted uf-rounded uf-animate-pulse" })
|
|
13238
|
+
] })
|
|
13239
|
+
] })
|
|
13240
|
+
] }),
|
|
13241
|
+
/* @__PURE__ */ jsxs46("div", { className: "uf-px-2.5", style: { backgroundColor: components.card.backgroundColor, borderRadius: components.card.borderRadius, border: `${components.card.borderWidth}px solid ${components.card.borderColor}` }, children: [
|
|
13242
|
+
/* @__PURE__ */ jsxs46(
|
|
13243
|
+
"button",
|
|
13244
|
+
{
|
|
13245
|
+
type: "button",
|
|
13246
|
+
onClick: () => setDetailsExpanded(!detailsExpanded),
|
|
13247
|
+
className: "uf-w-full uf-flex uf-items-center uf-justify-between uf-py-2.5",
|
|
13248
|
+
children: [
|
|
13249
|
+
/* @__PURE__ */ jsxs46("div", { className: "uf-flex uf-items-center uf-gap-2", children: [
|
|
13250
|
+
/* @__PURE__ */ jsx53("div", { className: "uf-rounded-full uf-p-1", style: { backgroundColor: components.card.iconBackgroundColor }, children: /* @__PURE__ */ jsx53(Clock4, { className: "uf-w-3 uf-h-3", style: { color: components.card.iconColor } }) }),
|
|
13251
|
+
/* @__PURE__ */ jsxs46("span", { className: "uf-text-xs", style: { color: components.card.labelColor, fontFamily: fonts.regular }, children: [
|
|
13252
|
+
tCrypto.processingTime.label,
|
|
13253
|
+
":",
|
|
13254
|
+
" ",
|
|
13255
|
+
/* @__PURE__ */ jsx53("span", { style: { color: components.card.titleColor, fontFamily: fonts.medium }, children: formatProcessingTime2(estimatedProcessingTime) })
|
|
13256
|
+
] })
|
|
13257
|
+
] }),
|
|
13258
|
+
detailsExpanded ? /* @__PURE__ */ jsx53(ChevronUp6, { className: "uf-w-4 uf-h-4", style: { color: components.card.actionColor } }) : /* @__PURE__ */ jsx53(ChevronDown7, { className: "uf-w-4 uf-h-4", style: { color: components.card.actionColor } })
|
|
13259
|
+
]
|
|
13260
|
+
}
|
|
13261
|
+
),
|
|
13262
|
+
detailsExpanded && /* @__PURE__ */ jsxs46("div", { className: "uf-pb-3 uf-space-y-2.5", children: [
|
|
13263
|
+
/* @__PURE__ */ jsxs46("div", { className: "uf-flex uf-items-center uf-gap-2", children: [
|
|
13264
|
+
/* @__PURE__ */ jsx53("div", { className: "uf-rounded-full uf-p-1", style: { backgroundColor: components.card.iconBackgroundColor }, children: /* @__PURE__ */ jsx53(ShieldCheck3, { className: "uf-w-3 uf-h-3", style: { color: components.card.iconColor } }) }),
|
|
13265
|
+
/* @__PURE__ */ jsxs46("span", { className: "uf-text-xs", style: { color: components.card.labelColor, fontFamily: fonts.regular }, children: [
|
|
13266
|
+
tCrypto.slippage.label,
|
|
13267
|
+
":",
|
|
13268
|
+
" ",
|
|
13269
|
+
/* @__PURE__ */ jsxs46("span", { style: { color: components.card.titleColor, fontFamily: fonts.medium }, children: [
|
|
13270
|
+
tCrypto.slippage.auto,
|
|
13271
|
+
" \u2022 ",
|
|
13272
|
+
(maxSlippagePercent ?? 0.25).toFixed(2),
|
|
13273
|
+
"%"
|
|
13274
|
+
] })
|
|
13275
|
+
] })
|
|
13276
|
+
] }),
|
|
13277
|
+
/* @__PURE__ */ jsxs46("div", { className: "uf-flex uf-items-center uf-gap-2", children: [
|
|
13278
|
+
/* @__PURE__ */ jsx53("div", { className: "uf-rounded-full uf-p-1", style: { backgroundColor: components.card.iconBackgroundColor }, children: /* @__PURE__ */ jsx53(DollarSign3, { className: "uf-w-3 uf-h-3", style: { color: components.card.iconColor } }) }),
|
|
13279
|
+
/* @__PURE__ */ jsxs46("span", { className: "uf-text-xs", style: { color: components.card.labelColor, fontFamily: fonts.regular }, children: [
|
|
13280
|
+
tCrypto.priceImpact.label,
|
|
13281
|
+
":",
|
|
13282
|
+
" ",
|
|
13283
|
+
/* @__PURE__ */ jsxs46("span", { style: { color: components.card.titleColor, fontFamily: fonts.medium }, children: [
|
|
13284
|
+
(priceImpactPercent ?? 0).toFixed(2),
|
|
13285
|
+
"%"
|
|
13286
|
+
] })
|
|
13287
|
+
] })
|
|
13288
|
+
] })
|
|
13289
|
+
] })
|
|
13290
|
+
] }),
|
|
13291
|
+
!canWithdraw && !submitError && /* @__PURE__ */ jsxs46(
|
|
13292
|
+
"div",
|
|
13293
|
+
{
|
|
13294
|
+
className: "uf-flex uf-items-start uf-gap-2.5 uf-p-3 uf-rounded-xl",
|
|
13295
|
+
style: { backgroundColor: colors2.card, border: `1px solid ${colors2.border}` },
|
|
13296
|
+
children: [
|
|
13297
|
+
/* @__PURE__ */ jsx53(Wallet3, { className: "uf-w-4 uf-h-4 uf-flex-shrink-0 uf-mt-0.5", style: { color: colors2.warning } }),
|
|
13298
|
+
/* @__PURE__ */ jsx53("div", { className: "uf-text-xs", style: { color: colors2.foregroundMuted, fontFamily: fonts.regular }, children: "No connected wallet detected. Please connect a wallet that matches your account to withdraw." })
|
|
13299
|
+
]
|
|
13300
|
+
}
|
|
13301
|
+
),
|
|
13302
|
+
isWalletMatch && connectedWalletName ? /* @__PURE__ */ jsx53(
|
|
13303
|
+
"button",
|
|
13304
|
+
{
|
|
13305
|
+
type: "button",
|
|
13306
|
+
onClick: handleWithdraw,
|
|
13307
|
+
disabled: !isFormValid || !canWithdraw || isSubmitting || !selectedToken || !selectedChain,
|
|
13308
|
+
className: "uf-w-full uf-py-3 uf-text-sm uf-font-medium uf-transition-colors disabled:uf-opacity-50 disabled:uf-cursor-not-allowed uf-flex uf-items-center uf-justify-center uf-gap-2",
|
|
13309
|
+
style: {
|
|
13310
|
+
backgroundColor: colors2.primary,
|
|
13311
|
+
color: colors2.primaryForeground,
|
|
13312
|
+
fontFamily: fonts.medium,
|
|
13313
|
+
borderRadius: components.button.borderRadius,
|
|
13314
|
+
border: `${components.button.borderWidth}px solid ${components.button.borderColor}`
|
|
13315
|
+
},
|
|
13316
|
+
children: isSubmitting ? /* @__PURE__ */ jsxs46(Fragment10, { children: [
|
|
13317
|
+
/* @__PURE__ */ jsx53(Loader25, { className: "uf-w-4 uf-h-4 uf-animate-spin" }),
|
|
13318
|
+
"Processing..."
|
|
13319
|
+
] }) : isOverBalance ? /* @__PURE__ */ jsx53(Fragment10, { children: "Insufficient balance" }) : isBelowMinimum ? /* @__PURE__ */ jsx53(Fragment10, { children: "Minimum amount not met" }) : submitError ? /* @__PURE__ */ jsx53(Fragment10, { children: "Withdrawal failed. Try again" }) : /* @__PURE__ */ jsxs46(Fragment10, { children: [
|
|
13320
|
+
/* @__PURE__ */ jsx53(Wallet3, { className: "uf-w-4 uf-h-4" }),
|
|
13321
|
+
"Withdraw from ",
|
|
13322
|
+
connectedWalletName
|
|
13323
|
+
] })
|
|
13324
|
+
}
|
|
13325
|
+
) : /* @__PURE__ */ jsx53(
|
|
13326
|
+
"button",
|
|
13327
|
+
{
|
|
13328
|
+
type: "button",
|
|
13329
|
+
onClick: handleWithdraw,
|
|
13330
|
+
disabled: !isFormValid || !canWithdraw || isSubmitting || !selectedToken || !selectedChain,
|
|
13331
|
+
className: "uf-w-full uf-py-3 uf-text-sm uf-font-medium uf-transition-colors disabled:uf-opacity-50 disabled:uf-cursor-not-allowed",
|
|
13332
|
+
style: {
|
|
13333
|
+
backgroundColor: colors2.primary,
|
|
13334
|
+
color: colors2.primaryForeground,
|
|
13335
|
+
fontFamily: fonts.medium,
|
|
13336
|
+
borderRadius: components.button.borderRadius,
|
|
13337
|
+
border: `${components.button.borderWidth}px solid ${components.button.borderColor}`
|
|
13338
|
+
},
|
|
13339
|
+
children: isSubmitting ? /* @__PURE__ */ jsxs46("span", { className: "uf-flex uf-items-center uf-justify-center uf-gap-2", children: [
|
|
13340
|
+
/* @__PURE__ */ jsx53(Loader25, { className: "uf-w-4 uf-h-4 uf-animate-spin" }),
|
|
13341
|
+
"Processing..."
|
|
13342
|
+
] }) : isOverBalance ? "Insufficient balance" : isBelowMinimum ? "Minimum amount not met" : submitError ? "Withdrawal failed. Try again" : t8.withdraw
|
|
13343
|
+
}
|
|
13344
|
+
),
|
|
13345
|
+
/* @__PURE__ */ jsxs46("div", { className: "uf-flex uf-items-center uf-justify-between uf-text-xs uf-pt-1", children: [
|
|
13346
|
+
/* @__PURE__ */ jsx53("div", { children: footerLeft }),
|
|
13347
|
+
/* @__PURE__ */ jsx53(DepositFooterLinks, { onGlossaryClick: () => setGlossaryOpen(true) })
|
|
13348
|
+
] }),
|
|
13349
|
+
/* @__PURE__ */ jsx53(
|
|
13350
|
+
GlossaryModal,
|
|
13351
|
+
{
|
|
13352
|
+
open: glossaryOpen,
|
|
13353
|
+
onOpenChange: setGlossaryOpen
|
|
13354
|
+
}
|
|
13355
|
+
)
|
|
13356
|
+
] });
|
|
13357
|
+
}
|
|
13358
|
+
|
|
13359
|
+
// src/components/withdrawals/WithdrawExecutionItem.tsx
|
|
13360
|
+
import { ChevronRight as ChevronRight12 } from "lucide-react";
|
|
13361
|
+
import {
|
|
13362
|
+
ExecutionStatus as ExecutionStatus6,
|
|
13363
|
+
getIconUrl as getIconUrl5
|
|
13364
|
+
} from "@unifold/core";
|
|
13365
|
+
import { jsx as jsx54, jsxs as jsxs47 } from "react/jsx-runtime";
|
|
13366
|
+
function WithdrawExecutionItem({
|
|
13367
|
+
execution,
|
|
13368
|
+
onClick
|
|
13369
|
+
}) {
|
|
13370
|
+
const { colors: colors2, fonts, components } = useTheme();
|
|
13371
|
+
const isPending = execution.status === ExecutionStatus6.PENDING || execution.status === ExecutionStatus6.WAITING || execution.status === ExecutionStatus6.DELAYED;
|
|
13372
|
+
const formatDateTime = (timestamp) => {
|
|
13373
|
+
try {
|
|
13374
|
+
const date = new Date(timestamp);
|
|
13375
|
+
const monthDay = date.toLocaleDateString("en-US", {
|
|
13376
|
+
month: "short",
|
|
13377
|
+
day: "numeric",
|
|
13378
|
+
year: "numeric"
|
|
13379
|
+
});
|
|
13380
|
+
const time = date.toLocaleTimeString("en-US", {
|
|
13381
|
+
hour: "numeric",
|
|
13382
|
+
minute: "2-digit",
|
|
13383
|
+
hour12: true
|
|
13384
|
+
}).toLowerCase();
|
|
13385
|
+
return `${monthDay} at ${time}`;
|
|
13386
|
+
} catch {
|
|
13387
|
+
return timestamp;
|
|
13388
|
+
}
|
|
13389
|
+
};
|
|
13390
|
+
const formatUsdAmount2 = (sourceAmountUsd) => {
|
|
13391
|
+
try {
|
|
13392
|
+
const amount = Number(sourceAmountUsd);
|
|
13393
|
+
return new Intl.NumberFormat("en-US", {
|
|
13394
|
+
style: "currency",
|
|
13395
|
+
currency: "USD",
|
|
13396
|
+
minimumFractionDigits: 2,
|
|
13397
|
+
maximumFractionDigits: 2
|
|
13398
|
+
}).format(amount);
|
|
13399
|
+
} catch {
|
|
13400
|
+
return "$0.00";
|
|
13401
|
+
}
|
|
13402
|
+
};
|
|
13403
|
+
return /* @__PURE__ */ jsxs47(
|
|
13404
|
+
"button",
|
|
13405
|
+
{
|
|
13406
|
+
onClick,
|
|
13407
|
+
className: "uf-w-full uf-p-3 uf-flex uf-items-center uf-gap-3 hover:uf-bg-secondary/80 uf-transition-colors uf-text-left",
|
|
13408
|
+
style: {
|
|
13409
|
+
backgroundColor: components.card.backgroundColor,
|
|
13410
|
+
borderRadius: components.list.rowBorderRadius,
|
|
13411
|
+
border: `${components.card.borderWidth}px solid ${components.card.borderColor}`
|
|
13412
|
+
},
|
|
13413
|
+
children: [
|
|
13414
|
+
/* @__PURE__ */ jsxs47("div", { className: "uf-relative uf-flex-shrink-0 uf-w-9 uf-h-9", children: [
|
|
13415
|
+
/* @__PURE__ */ jsx54(
|
|
13416
|
+
"img",
|
|
13417
|
+
{
|
|
13418
|
+
src: execution.destination_token_metadata?.icon_url || getIconUrl5("/icons/tokens/svg/usdc.svg"),
|
|
13419
|
+
alt: "Token",
|
|
13420
|
+
width: 36,
|
|
13421
|
+
height: 36,
|
|
13422
|
+
loading: "lazy",
|
|
13423
|
+
className: "uf-rounded-full uf-w-9 uf-h-9"
|
|
13424
|
+
}
|
|
13425
|
+
),
|
|
13426
|
+
isPending ? /* @__PURE__ */ jsx54(
|
|
13427
|
+
"div",
|
|
13428
|
+
{
|
|
13429
|
+
className: "uf-absolute -uf-bottom-0.5 -uf-right-0.5 uf-rounded-full uf-p-0.5",
|
|
13430
|
+
style: { backgroundColor: colors2.warning },
|
|
13431
|
+
children: /* @__PURE__ */ jsx54(
|
|
13432
|
+
"svg",
|
|
13433
|
+
{
|
|
13434
|
+
width: "10",
|
|
13435
|
+
height: "10",
|
|
13436
|
+
viewBox: "0 0 12 12",
|
|
13437
|
+
fill: "none",
|
|
13438
|
+
className: "uf-animate-spin uf-block",
|
|
13439
|
+
children: /* @__PURE__ */ jsx54(
|
|
13440
|
+
"path",
|
|
13441
|
+
{
|
|
13442
|
+
d: "M6 1V3M6 9V11M1 6H3M9 6H11M2.5 2.5L4 4M8 8L9.5 9.5M2.5 9.5L4 8M8 4L9.5 2.5",
|
|
13443
|
+
stroke: "white",
|
|
13444
|
+
strokeWidth: "2",
|
|
13445
|
+
strokeLinecap: "round"
|
|
13446
|
+
}
|
|
13447
|
+
)
|
|
13448
|
+
}
|
|
13449
|
+
)
|
|
13450
|
+
}
|
|
13451
|
+
) : /* @__PURE__ */ jsx54(
|
|
13452
|
+
"div",
|
|
13453
|
+
{
|
|
13454
|
+
className: "uf-absolute -uf-bottom-0.5 -uf-right-0.5 uf-rounded-full uf-p-0.5",
|
|
13455
|
+
style: { backgroundColor: colors2.success },
|
|
13456
|
+
children: /* @__PURE__ */ jsx54(
|
|
13457
|
+
"svg",
|
|
13458
|
+
{
|
|
13459
|
+
width: "10",
|
|
13460
|
+
height: "10",
|
|
13461
|
+
viewBox: "0 0 12 12",
|
|
13462
|
+
fill: "none",
|
|
13463
|
+
className: "uf-block",
|
|
13464
|
+
children: /* @__PURE__ */ jsx54(
|
|
13465
|
+
"path",
|
|
13466
|
+
{
|
|
13467
|
+
d: "M10 3L4.5 8.5L2 6",
|
|
13468
|
+
stroke: "white",
|
|
13469
|
+
strokeWidth: "2",
|
|
13470
|
+
strokeLinecap: "round",
|
|
13471
|
+
strokeLinejoin: "round"
|
|
13472
|
+
}
|
|
13473
|
+
)
|
|
13474
|
+
}
|
|
13475
|
+
)
|
|
13476
|
+
}
|
|
13477
|
+
)
|
|
13478
|
+
] }),
|
|
13479
|
+
/* @__PURE__ */ jsxs47("div", { className: "uf-flex-1 uf-min-w-0", children: [
|
|
13480
|
+
/* @__PURE__ */ jsx54(
|
|
13481
|
+
"h3",
|
|
13482
|
+
{
|
|
13483
|
+
className: "uf-font-medium uf-text-sm uf-leading-tight",
|
|
13484
|
+
style: {
|
|
13485
|
+
color: components.card.titleColor,
|
|
13486
|
+
fontFamily: fonts.medium
|
|
13487
|
+
},
|
|
13488
|
+
children: isPending ? "Withdrawal processing" : "Withdrawal completed"
|
|
13489
|
+
}
|
|
13490
|
+
),
|
|
13491
|
+
/* @__PURE__ */ jsx54(
|
|
13492
|
+
"p",
|
|
13493
|
+
{
|
|
13494
|
+
className: "uf-text-xs uf-leading-tight",
|
|
13495
|
+
style: {
|
|
13496
|
+
color: components.card.subtitleColor,
|
|
13497
|
+
fontFamily: fonts.regular
|
|
13498
|
+
},
|
|
13499
|
+
children: formatDateTime(execution.created_at || (/* @__PURE__ */ new Date()).toISOString())
|
|
13500
|
+
}
|
|
13501
|
+
)
|
|
13502
|
+
] }),
|
|
13503
|
+
/* @__PURE__ */ jsx54(
|
|
13504
|
+
"span",
|
|
13505
|
+
{
|
|
13506
|
+
className: "uf-font-medium uf-text-sm uf-flex-shrink-0",
|
|
13507
|
+
style: {
|
|
13508
|
+
color: components.card.textRightColor,
|
|
13509
|
+
fontFamily: fonts.medium
|
|
13510
|
+
},
|
|
13511
|
+
children: formatUsdAmount2(execution.source_amount_usd || "0")
|
|
13512
|
+
}
|
|
13513
|
+
),
|
|
13514
|
+
/* @__PURE__ */ jsx54(
|
|
13515
|
+
ChevronRight12,
|
|
13516
|
+
{
|
|
13517
|
+
className: "uf-w-4 uf-h-4 uf-flex-shrink-0",
|
|
13518
|
+
style: { color: components.card.actionColor }
|
|
13519
|
+
}
|
|
13520
|
+
)
|
|
13521
|
+
]
|
|
13522
|
+
}
|
|
13523
|
+
);
|
|
13524
|
+
}
|
|
13525
|
+
|
|
13526
|
+
// src/components/withdrawals/WithdrawConfirmingView.tsx
|
|
13527
|
+
import { useState as useState30, useEffect as useEffect24 } from "react";
|
|
13528
|
+
import { Fragment as Fragment11, jsx as jsx55, jsxs as jsxs48 } from "react/jsx-runtime";
|
|
13529
|
+
function truncateAddress4(addr) {
|
|
13530
|
+
if (addr.length <= 12) return addr;
|
|
13531
|
+
return `${addr.slice(0, 6)}...${addr.slice(-4)}`;
|
|
13532
|
+
}
|
|
13533
|
+
var SHOW_BUTTON_DELAY_MS = 5e3;
|
|
13534
|
+
function WithdrawConfirmingView({
|
|
13535
|
+
txInfo,
|
|
13536
|
+
executions,
|
|
13537
|
+
onClose,
|
|
13538
|
+
onViewTracker
|
|
13539
|
+
}) {
|
|
13540
|
+
const { colors: colors2, fonts, components } = useTheme();
|
|
13541
|
+
const [showButton, setShowButton] = useState30(false);
|
|
13542
|
+
const latestExecution = executions.length > 0 ? executions[executions.length - 1] : null;
|
|
13543
|
+
useEffect24(() => {
|
|
13544
|
+
if (latestExecution) return;
|
|
13545
|
+
const timer = setTimeout(() => setShowButton(true), SHOW_BUTTON_DELAY_MS);
|
|
13546
|
+
return () => clearTimeout(timer);
|
|
13547
|
+
}, [latestExecution]);
|
|
13548
|
+
const btnRadius = components.button.borderRadius;
|
|
13549
|
+
const btnBorder = `${components.button.borderWidth}px solid ${components.button.borderColor}`;
|
|
13550
|
+
if (latestExecution) {
|
|
13551
|
+
return /* @__PURE__ */ jsxs48(Fragment11, { children: [
|
|
13552
|
+
/* @__PURE__ */ jsx55(DepositHeader, { title: "Withdrawal Details", showClose: true, onClose }),
|
|
13553
|
+
/* @__PURE__ */ jsx55(DepositDetailContent, { execution: latestExecution, variant: "withdraw" }),
|
|
13554
|
+
/* @__PURE__ */ jsxs48("div", { className: "uf-flex uf-gap-2 uf-px-2 uf-pt-2", children: [
|
|
13555
|
+
/* @__PURE__ */ jsx55(
|
|
13556
|
+
"button",
|
|
13557
|
+
{
|
|
13558
|
+
type: "button",
|
|
13559
|
+
onClick: onViewTracker,
|
|
13560
|
+
className: "uf-flex-1 uf-py-2.5 uf-text-sm uf-transition-colors hover:uf-opacity-90",
|
|
13561
|
+
style: {
|
|
13562
|
+
backgroundColor: components.button.secondaryBackground,
|
|
13563
|
+
color: components.button.secondaryText,
|
|
13564
|
+
fontFamily: fonts.medium,
|
|
13565
|
+
borderRadius: btnRadius,
|
|
13566
|
+
border: btnBorder
|
|
13567
|
+
},
|
|
13568
|
+
children: "Withdrawal History"
|
|
13569
|
+
}
|
|
13570
|
+
),
|
|
13571
|
+
/* @__PURE__ */ jsx55(
|
|
13572
|
+
"button",
|
|
13573
|
+
{
|
|
13574
|
+
type: "button",
|
|
13575
|
+
onClick: onClose,
|
|
13576
|
+
className: "uf-flex-1 uf-py-2.5 uf-text-sm uf-transition-colors hover:uf-opacity-90",
|
|
13577
|
+
style: {
|
|
13578
|
+
backgroundColor: components.button.primaryBackground,
|
|
13579
|
+
color: components.button.primaryText,
|
|
13580
|
+
fontFamily: fonts.medium,
|
|
13581
|
+
borderRadius: btnRadius,
|
|
13582
|
+
border: btnBorder
|
|
13583
|
+
},
|
|
13584
|
+
children: "Close"
|
|
13585
|
+
}
|
|
13586
|
+
)
|
|
13587
|
+
] }),
|
|
13588
|
+
/* @__PURE__ */ jsx55("div", { className: "uf-pt-3", children: /* @__PURE__ */ jsx55(
|
|
13589
|
+
PoweredByUnifold,
|
|
13590
|
+
{
|
|
13591
|
+
color: colors2.foregroundMuted,
|
|
13592
|
+
className: "uf-flex uf-justify-center uf-shrink-0"
|
|
13593
|
+
}
|
|
13594
|
+
) })
|
|
13595
|
+
] });
|
|
13596
|
+
}
|
|
13597
|
+
return /* @__PURE__ */ jsxs48(Fragment11, { children: [
|
|
13598
|
+
/* @__PURE__ */ jsx55(DepositHeader, { title: "Withdrawal Status", showClose: true, onClose }),
|
|
13599
|
+
/* @__PURE__ */ jsxs48("div", { className: "uf-flex uf-flex-col uf-items-center uf-justify-center uf-py-16 uf-px-4", children: [
|
|
13600
|
+
/* @__PURE__ */ jsx55(
|
|
13601
|
+
"div",
|
|
13602
|
+
{
|
|
13603
|
+
className: "uf-w-20 uf-h-20 uf-rounded-full uf-flex uf-items-center uf-justify-center uf-mb-6",
|
|
13604
|
+
style: { backgroundColor: `${colors2.primary}20` },
|
|
13605
|
+
children: /* @__PURE__ */ jsx55(
|
|
13606
|
+
"svg",
|
|
13607
|
+
{
|
|
13608
|
+
width: "40",
|
|
13609
|
+
height: "40",
|
|
13610
|
+
viewBox: "0 0 24 24",
|
|
13611
|
+
fill: "none",
|
|
13612
|
+
className: "uf-animate-spin",
|
|
13613
|
+
children: /* @__PURE__ */ jsx55(
|
|
13614
|
+
"path",
|
|
13615
|
+
{
|
|
13616
|
+
d: "M21 12a9 9 0 1 1-6.22-8.56",
|
|
13617
|
+
stroke: colors2.primary,
|
|
13618
|
+
strokeWidth: "2.5",
|
|
13619
|
+
strokeLinecap: "round"
|
|
13620
|
+
}
|
|
13621
|
+
)
|
|
13622
|
+
}
|
|
13623
|
+
)
|
|
13624
|
+
}
|
|
13625
|
+
),
|
|
13626
|
+
/* @__PURE__ */ jsx55(
|
|
13627
|
+
"h3",
|
|
13628
|
+
{
|
|
13629
|
+
className: "uf-text-xl uf-mb-2",
|
|
13630
|
+
style: { color: colors2.foreground, fontFamily: fonts.medium },
|
|
13631
|
+
children: "Checking Withdrawal"
|
|
13632
|
+
}
|
|
13633
|
+
),
|
|
13634
|
+
/* @__PURE__ */ jsxs48(
|
|
13635
|
+
"p",
|
|
13636
|
+
{
|
|
13637
|
+
className: "uf-text-sm uf-text-center",
|
|
13638
|
+
style: { color: colors2.foregroundMuted, fontFamily: fonts.regular },
|
|
13639
|
+
children: [
|
|
13640
|
+
txInfo.amount,
|
|
13641
|
+
" ",
|
|
13642
|
+
txInfo.sourceTokenSymbol,
|
|
13643
|
+
" to",
|
|
13644
|
+
" ",
|
|
13645
|
+
truncateAddress4(txInfo.recipientAddress)
|
|
13646
|
+
]
|
|
13647
|
+
}
|
|
13648
|
+
)
|
|
13649
|
+
] }),
|
|
13650
|
+
showButton && /* @__PURE__ */ jsx55("div", { className: "uf-px-1 uf-pb-1", children: /* @__PURE__ */ jsx55(
|
|
13651
|
+
"button",
|
|
13652
|
+
{
|
|
13653
|
+
type: "button",
|
|
13654
|
+
onClick: onViewTracker,
|
|
13655
|
+
className: "uf-w-full uf-py-2.5 uf-text-sm uf-transition-colors hover:uf-opacity-90",
|
|
13656
|
+
style: {
|
|
13657
|
+
backgroundColor: components.button.secondaryBackground,
|
|
13658
|
+
color: components.button.secondaryText,
|
|
13659
|
+
fontFamily: fonts.medium,
|
|
13660
|
+
borderRadius: btnRadius,
|
|
13661
|
+
border: btnBorder
|
|
13662
|
+
},
|
|
13663
|
+
children: "Withdrawal History"
|
|
13664
|
+
}
|
|
13665
|
+
) }),
|
|
13666
|
+
/* @__PURE__ */ jsx55("div", { className: "uf-pt-3", children: /* @__PURE__ */ jsx55(
|
|
13667
|
+
PoweredByUnifold,
|
|
13668
|
+
{
|
|
13669
|
+
color: colors2.foregroundMuted,
|
|
13670
|
+
className: "uf-flex uf-justify-center uf-shrink-0"
|
|
13671
|
+
}
|
|
13672
|
+
) })
|
|
13673
|
+
] });
|
|
13674
|
+
}
|
|
13675
|
+
|
|
13676
|
+
// src/components/withdrawals/WithdrawModal.tsx
|
|
13677
|
+
import {
|
|
13678
|
+
createDepositAddress as createDepositAddress2,
|
|
13679
|
+
getWalletByChainType as getWalletByChainType4,
|
|
13680
|
+
ActionType as ActionType6
|
|
13681
|
+
} from "@unifold/core";
|
|
13682
|
+
import { Fragment as Fragment12, jsx as jsx56, jsxs as jsxs49 } from "react/jsx-runtime";
|
|
13683
|
+
var t9 = i18n.withdrawModal;
|
|
13684
|
+
var getChainKey5 = (chainId, chainType) => `${chainType}:${chainId}`;
|
|
13685
|
+
function WithdrawModal({
|
|
13686
|
+
open,
|
|
13687
|
+
onOpenChange,
|
|
13688
|
+
publishableKey,
|
|
13689
|
+
modalTitle,
|
|
13690
|
+
externalUserId,
|
|
13691
|
+
sourceChainType,
|
|
13692
|
+
sourceChainId,
|
|
13693
|
+
sourceTokenAddress,
|
|
13694
|
+
sourceTokenSymbol,
|
|
13695
|
+
recipientAddress: recipientAddressProp,
|
|
13696
|
+
senderAddress,
|
|
13697
|
+
onWithdraw,
|
|
13698
|
+
onWithdrawSuccess,
|
|
13699
|
+
onWithdrawError,
|
|
13700
|
+
theme = "dark",
|
|
13701
|
+
hideOverlay = false
|
|
13702
|
+
}) {
|
|
13703
|
+
const { colors: colors2, fonts, components } = useTheme();
|
|
13704
|
+
const [containerEl, setContainerEl] = useState31(null);
|
|
13705
|
+
const containerCallbackRef = useCallback6((el) => {
|
|
13706
|
+
setContainerEl(el);
|
|
13707
|
+
}, []);
|
|
13708
|
+
const [resolvedTheme, setResolvedTheme] = useState31(
|
|
13709
|
+
theme === "auto" ? "dark" : theme
|
|
13710
|
+
);
|
|
13711
|
+
useEffect25(() => {
|
|
13712
|
+
if (theme === "auto") {
|
|
13713
|
+
const mq = window.matchMedia("(prefers-color-scheme: dark)");
|
|
13714
|
+
setResolvedTheme(mq.matches ? "dark" : "light");
|
|
13715
|
+
const h = (e) => setResolvedTheme(e.matches ? "dark" : "light");
|
|
13716
|
+
mq.addEventListener("change", h);
|
|
13717
|
+
return () => mq.removeEventListener("change", h);
|
|
13718
|
+
}
|
|
13719
|
+
setResolvedTheme(theme);
|
|
13720
|
+
}, [theme]);
|
|
13721
|
+
const themeClass = resolvedTheme === "dark" ? "uf-dark" : "";
|
|
13722
|
+
const { data: tokensResponse, isLoading: tokensLoading } = useSupportedDestinationTokens(publishableKey, open);
|
|
13723
|
+
const destinationTokens = tokensResponse?.data ?? [];
|
|
13724
|
+
const { data: sourceValidation, isLoading: isCheckingSourceToken } = useSourceTokenValidation({
|
|
13725
|
+
sourceChainType,
|
|
13726
|
+
sourceChainId,
|
|
13727
|
+
sourceTokenAddress,
|
|
13728
|
+
sourceTokenSymbol,
|
|
13729
|
+
publishableKey,
|
|
13730
|
+
enabled: open
|
|
13731
|
+
});
|
|
13732
|
+
const { data: balanceData, isLoading: isLoadingBalance } = useAddressBalance({
|
|
13733
|
+
address: senderAddress,
|
|
13734
|
+
chainType: sourceChainType,
|
|
13735
|
+
chainId: sourceChainId,
|
|
13736
|
+
tokenAddress: sourceTokenAddress,
|
|
13737
|
+
publishableKey,
|
|
13738
|
+
enabled: open
|
|
13739
|
+
});
|
|
13740
|
+
const [selectedToken, setSelectedToken] = useState31(null);
|
|
13741
|
+
const [selectedChain, setSelectedChain] = useState31(null);
|
|
13742
|
+
const [detectedWallet, setDetectedWallet] = useState31(null);
|
|
13743
|
+
const connectedWalletName = detectedWallet?.name ?? null;
|
|
13744
|
+
const isWalletMatch = !!detectedWallet;
|
|
13745
|
+
useEffect25(() => {
|
|
13746
|
+
if (!senderAddress || !open) {
|
|
13747
|
+
setDetectedWallet(null);
|
|
13748
|
+
return;
|
|
13749
|
+
}
|
|
13750
|
+
let cancelled = false;
|
|
13751
|
+
detectBrowserWallet(sourceChainType, senderAddress).then((wallet) => {
|
|
13752
|
+
if (!cancelled) setDetectedWallet(wallet);
|
|
13753
|
+
});
|
|
13754
|
+
return () => {
|
|
13755
|
+
cancelled = true;
|
|
13756
|
+
};
|
|
13757
|
+
}, [senderAddress, sourceChainType, open]);
|
|
13758
|
+
const [view, setView] = useState31("form");
|
|
13759
|
+
const [withdrawDepositWalletId, setWithdrawDepositWalletId] = useState31();
|
|
13760
|
+
const [selectedExecution, setSelectedExecution] = useState31(null);
|
|
13761
|
+
const [submittedTxInfo, setSubmittedTxInfo] = useState31(null);
|
|
13762
|
+
const { executions: realtimeExecutions } = useWithdrawPolling({
|
|
13763
|
+
userId: externalUserId,
|
|
13764
|
+
publishableKey,
|
|
13765
|
+
depositWalletId: withdrawDepositWalletId,
|
|
13766
|
+
enabled: !!withdrawDepositWalletId && open,
|
|
13767
|
+
onWithdrawSuccess: onWithdrawSuccess ? (d) => onWithdrawSuccess({ message: d.message, transaction: d.transaction }) : void 0,
|
|
13768
|
+
onWithdrawError
|
|
13769
|
+
});
|
|
13770
|
+
const { data: allWithdrawalsData } = useExecutions(externalUserId, publishableKey, {
|
|
13771
|
+
actionType: ActionType6.Withdraw,
|
|
13772
|
+
enabled: open,
|
|
13773
|
+
refetchInterval: view === "tracker" || view === "detail" ? 5e3 : 15e3
|
|
13774
|
+
});
|
|
13775
|
+
const allWithdrawals = allWithdrawalsData?.data ?? [];
|
|
13776
|
+
const handleDepositWalletCreation = useCallback6(async (params) => {
|
|
13777
|
+
const { data: wallets } = await createDepositAddress2(
|
|
13778
|
+
{
|
|
13779
|
+
external_user_id: externalUserId,
|
|
13780
|
+
destination_chain_type: params.destinationChainType,
|
|
13781
|
+
destination_chain_id: params.destinationChainId,
|
|
13782
|
+
destination_token_address: params.destinationTokenAddress,
|
|
13783
|
+
recipient_address: params.recipientAddress,
|
|
13784
|
+
action_type: ActionType6.Withdraw
|
|
13785
|
+
},
|
|
13786
|
+
publishableKey
|
|
13787
|
+
);
|
|
13788
|
+
const depositWallet = getWalletByChainType4(wallets, sourceChainType);
|
|
13789
|
+
if (!depositWallet) {
|
|
13790
|
+
throw new Error(`No deposit wallet available for ${sourceChainType}`);
|
|
13791
|
+
}
|
|
13792
|
+
setWithdrawDepositWalletId(depositWallet.id);
|
|
13793
|
+
return depositWallet;
|
|
13794
|
+
}, [externalUserId, publishableKey, sourceChainType]);
|
|
13795
|
+
const handleWithdrawSubmitted = useCallback6((txInfo) => {
|
|
13796
|
+
setSubmittedTxInfo(txInfo);
|
|
13797
|
+
setView("confirming");
|
|
13798
|
+
}, []);
|
|
13799
|
+
useEffect25(() => {
|
|
13800
|
+
if (!destinationTokens.length || selectedToken) return;
|
|
13801
|
+
const first = destinationTokens[0];
|
|
13802
|
+
if (first?.chains.length > 0) {
|
|
13803
|
+
setSelectedToken(first);
|
|
13804
|
+
setSelectedChain(first.chains[0]);
|
|
13805
|
+
}
|
|
13806
|
+
}, [destinationTokens, selectedToken]);
|
|
13807
|
+
const resetViewTimeoutRef = useRef8(null);
|
|
13808
|
+
const handleClose = useCallback6(() => {
|
|
13809
|
+
onOpenChange(false);
|
|
13810
|
+
if (resetViewTimeoutRef.current) clearTimeout(resetViewTimeoutRef.current);
|
|
13811
|
+
resetViewTimeoutRef.current = setTimeout(() => {
|
|
13812
|
+
setSelectedToken(null);
|
|
13813
|
+
setSelectedChain(null);
|
|
13814
|
+
setView("form");
|
|
13815
|
+
setSelectedExecution(null);
|
|
13816
|
+
setSubmittedTxInfo(null);
|
|
13817
|
+
setWithdrawDepositWalletId(void 0);
|
|
13818
|
+
resetViewTimeoutRef.current = null;
|
|
13819
|
+
}, 200);
|
|
13820
|
+
}, [onOpenChange]);
|
|
13821
|
+
useLayoutEffect3(() => {
|
|
13822
|
+
if (!open) return;
|
|
13823
|
+
if (resetViewTimeoutRef.current) {
|
|
13824
|
+
clearTimeout(resetViewTimeoutRef.current);
|
|
13825
|
+
resetViewTimeoutRef.current = null;
|
|
13826
|
+
}
|
|
13827
|
+
setSelectedToken(null);
|
|
13828
|
+
setSelectedChain(null);
|
|
13829
|
+
setView("form");
|
|
13830
|
+
setSelectedExecution(null);
|
|
13831
|
+
setSubmittedTxInfo(null);
|
|
13832
|
+
setWithdrawDepositWalletId(void 0);
|
|
13833
|
+
}, [open]);
|
|
13834
|
+
useEffect25(() => () => {
|
|
13835
|
+
if (resetViewTimeoutRef.current) clearTimeout(resetViewTimeoutRef.current);
|
|
13836
|
+
}, []);
|
|
13837
|
+
const handleTokenSymbolChange = useCallback6((symbol) => {
|
|
13838
|
+
const tok = destinationTokens.find((t11) => t11.symbol === symbol);
|
|
13839
|
+
if (tok) {
|
|
13840
|
+
setSelectedToken(tok);
|
|
13841
|
+
if (tok.chains.length > 0) setSelectedChain(tok.chains[0]);
|
|
13842
|
+
}
|
|
13843
|
+
}, [destinationTokens]);
|
|
13844
|
+
const handleChainKeyChange = useCallback6((chainKey) => {
|
|
13845
|
+
if (!selectedToken) return;
|
|
13846
|
+
const chain = selectedToken.chains.find((c) => getChainKey5(c.chain_id, c.chain_type) === chainKey);
|
|
13847
|
+
if (chain) setSelectedChain(chain);
|
|
13848
|
+
}, [selectedToken]);
|
|
13849
|
+
const isSourceSupported = sourceValidation?.isSupported ?? null;
|
|
13850
|
+
const canWithdraw = !!onWithdraw || isWalletMatch;
|
|
13851
|
+
const isAnyLoading = tokensLoading || isCheckingSourceToken;
|
|
13852
|
+
const withdrawPoweredByFooter = /* @__PURE__ */ jsx56("div", { className: "uf-pt-3", children: /* @__PURE__ */ jsx56(PoweredByUnifold, { color: colors2.foregroundMuted, className: "uf-flex uf-justify-center uf-shrink-0" }) });
|
|
13853
|
+
return /* @__PURE__ */ jsx56(PortalContainerProvider, { value: hideOverlay ? containerEl : null, children: /* @__PURE__ */ jsx56(Dialog, { open: hideOverlay || open, onOpenChange: hideOverlay ? void 0 : handleClose, modal: !hideOverlay, children: /* @__PURE__ */ jsx56(
|
|
13854
|
+
DialogContent,
|
|
13855
|
+
{
|
|
13856
|
+
ref: hideOverlay ? containerCallbackRef : void 0,
|
|
13857
|
+
hideOverlay,
|
|
13858
|
+
className: `sm:uf-max-w-[400px] uf-border-secondary uf-text-foreground uf-gap-0 [&>button]:uf-hidden ${hideOverlay ? `uf-p-6 uf-overflow-hidden ${themeClass}` : `uf-p-0 uf-overflow-visible !uf-top-auto !uf-h-auto !uf-max-h-[90vh] sm:!uf-max-h-none sm:!uf-top-[50%] ${themeClass}`}`,
|
|
13859
|
+
style: { backgroundColor: colors2.background },
|
|
13860
|
+
onPointerDownOutside: (e) => e.preventDefault(),
|
|
13861
|
+
onInteractOutside: (e) => e.preventDefault(),
|
|
13862
|
+
children: /* @__PURE__ */ jsx56(ThemeStyleInjector, { children: view === "confirming" && submittedTxInfo ? /* @__PURE__ */ jsx56(
|
|
13863
|
+
WithdrawConfirmingView,
|
|
13864
|
+
{
|
|
13865
|
+
txInfo: submittedTxInfo,
|
|
13866
|
+
executions: realtimeExecutions,
|
|
13867
|
+
onClose: handleClose,
|
|
13868
|
+
onViewTracker: () => setView("tracker")
|
|
13869
|
+
}
|
|
13870
|
+
) : view === "detail" && selectedExecution ? /* @__PURE__ */ jsxs49(Fragment12, { children: [
|
|
13871
|
+
/* @__PURE__ */ jsx56(DepositHeader, { title: "Withdrawal Details", showBack: true, showClose: !hideOverlay, onBack: () => {
|
|
13872
|
+
setSelectedExecution(null);
|
|
13873
|
+
setView("tracker");
|
|
13874
|
+
}, onClose: handleClose }),
|
|
13875
|
+
/* @__PURE__ */ jsx56(DepositDetailContent, { execution: selectedExecution, variant: "withdraw" }),
|
|
13876
|
+
withdrawPoweredByFooter
|
|
13877
|
+
] }) : view === "tracker" ? (
|
|
13878
|
+
/* ---------- Tracker view: execution list ---------- */
|
|
13879
|
+
/* @__PURE__ */ jsxs49(Fragment12, { children: [
|
|
13880
|
+
/* @__PURE__ */ jsx56(DepositHeader, { title: "Withdrawal History", showBack: true, showClose: !hideOverlay, onBack: () => setView("form"), onClose: handleClose }),
|
|
13881
|
+
/* @__PURE__ */ jsx56("div", { className: "uf-flex uf-flex-col uf-gap-2", style: { minHeight: 200 }, children: allWithdrawals.length === 0 ? /* @__PURE__ */ jsx56("div", { className: "uf-flex uf-items-center uf-justify-center uf-py-8", children: /* @__PURE__ */ jsx56("p", { className: "uf-text-sm", style: { color: colors2.foregroundMuted, fontFamily: fonts.regular }, children: "No withdrawals to track yet" }) }) : allWithdrawals.map((ex) => /* @__PURE__ */ jsx56(
|
|
13882
|
+
WithdrawExecutionItem,
|
|
13883
|
+
{
|
|
13884
|
+
execution: ex,
|
|
13885
|
+
onClick: () => {
|
|
13886
|
+
setSelectedExecution(ex);
|
|
13887
|
+
setView("detail");
|
|
13888
|
+
}
|
|
13889
|
+
},
|
|
13890
|
+
ex.id
|
|
13891
|
+
)) }),
|
|
13892
|
+
withdrawPoweredByFooter
|
|
13893
|
+
] })
|
|
13894
|
+
) : (
|
|
13895
|
+
/* ---------- Form view (default) ---------- */
|
|
13896
|
+
/* @__PURE__ */ jsxs49(Fragment12, { children: [
|
|
13897
|
+
/* @__PURE__ */ jsx56(DepositHeader, { title: modalTitle || t9.title, showClose: !hideOverlay, onClose: handleClose }),
|
|
13898
|
+
/* @__PURE__ */ jsxs49("div", { className: "uf-flex uf-flex-col uf-gap-3", children: [
|
|
13899
|
+
isAnyLoading ? /* @__PURE__ */ jsx56("div", { className: "uf-space-y-3", children: [1, 2, 3].map((i) => /* @__PURE__ */ jsx56("div", { className: "uf-w-full uf-bg-secondary uf-rounded-xl uf-p-3 uf-flex uf-items-center uf-animate-pulse", children: /* @__PURE__ */ jsx56("div", { className: "uf-bg-muted uf-rounded-lg uf-w-full uf-h-10" }) }, i)) }) : isSourceSupported === false ? /* @__PURE__ */ jsxs49("div", { className: "uf-flex uf-flex-col uf-items-center uf-justify-center uf-py-8 uf-px-4 uf-text-center", children: [
|
|
13900
|
+
/* @__PURE__ */ jsx56("div", { className: "uf-w-16 uf-h-16 uf-rounded-full uf-bg-muted uf-flex uf-items-center uf-justify-center uf-mb-4", children: /* @__PURE__ */ jsx56(AlertTriangle3, { className: "uf-w-8 uf-h-8 uf-text-muted-foreground" }) }),
|
|
13901
|
+
/* @__PURE__ */ jsx56("h3", { className: "uf-text-lg uf-font-semibold uf-mb-2", style: { color: colors2.foreground, fontFamily: fonts.medium }, children: "Unsupported Source Token" }),
|
|
13902
|
+
/* @__PURE__ */ jsx56("p", { className: "uf-text-sm uf-max-w-[280px]", style: { color: colors2.foregroundMuted, fontFamily: fonts.regular }, children: sourceValidation?.errorMessage })
|
|
13903
|
+
] }) : /* @__PURE__ */ jsxs49(Fragment12, { children: [
|
|
13904
|
+
/* @__PURE__ */ jsx56(
|
|
13905
|
+
WithdrawDoubleInput,
|
|
13906
|
+
{
|
|
13907
|
+
tokens: destinationTokens,
|
|
13908
|
+
selectedTokenSymbol: selectedToken?.symbol ?? null,
|
|
13909
|
+
selectedChainKey: selectedChain ? getChainKey5(selectedChain.chain_id, selectedChain.chain_type) : null,
|
|
13910
|
+
onTokenChange: handleTokenSymbolChange,
|
|
13911
|
+
onChainChange: handleChainKeyChange,
|
|
13912
|
+
isLoading: tokensLoading
|
|
13913
|
+
}
|
|
13914
|
+
),
|
|
13915
|
+
/* @__PURE__ */ jsx56(
|
|
13916
|
+
WithdrawForm,
|
|
13917
|
+
{
|
|
13918
|
+
publishableKey,
|
|
13919
|
+
externalUserId,
|
|
13920
|
+
sourceChainType,
|
|
13921
|
+
selectedToken,
|
|
13922
|
+
selectedChain,
|
|
13923
|
+
sourceTokenSymbol,
|
|
13924
|
+
recipientAddressProp,
|
|
13925
|
+
balanceData: balanceData ?? null,
|
|
13926
|
+
isLoadingBalance,
|
|
13927
|
+
minimumWithdrawAmountUsd: sourceValidation?.minimumAmountUsd ?? null,
|
|
13928
|
+
estimatedProcessingTime: sourceValidation?.estimatedProcessingTime ?? null,
|
|
13929
|
+
maxSlippagePercent: sourceValidation?.maxSlippagePercent ?? null,
|
|
13930
|
+
priceImpactPercent: sourceValidation?.priceImpactPercent ?? null,
|
|
13931
|
+
detectedWallet,
|
|
13932
|
+
sourceChainId,
|
|
13933
|
+
sourceTokenAddress,
|
|
13934
|
+
isWalletMatch,
|
|
13935
|
+
connectedWalletName,
|
|
13936
|
+
canWithdraw,
|
|
13937
|
+
onWithdraw,
|
|
13938
|
+
onWithdrawError,
|
|
13939
|
+
onDepositWalletCreation: handleDepositWalletCreation,
|
|
13940
|
+
onWithdrawSubmitted: handleWithdrawSubmitted,
|
|
13941
|
+
footerLeft: /* @__PURE__ */ jsxs49(
|
|
13942
|
+
"button",
|
|
13943
|
+
{
|
|
13944
|
+
onClick: () => setView("tracker"),
|
|
13945
|
+
className: "uf-flex uf-items-center uf-gap-1 uf-transition-colors hover:uf-opacity-70",
|
|
13946
|
+
style: { color: colors2.foregroundMuted },
|
|
13947
|
+
children: [
|
|
13948
|
+
/* @__PURE__ */ jsx56(Clock5, { className: "uf-w-3.5 uf-h-3.5" }),
|
|
13949
|
+
"Withdrawal History",
|
|
13950
|
+
/* @__PURE__ */ jsx56(ChevronRight13, { className: "uf-w-3 uf-h-3" })
|
|
13951
|
+
]
|
|
13952
|
+
}
|
|
13953
|
+
)
|
|
13954
|
+
}
|
|
13955
|
+
)
|
|
13956
|
+
] }),
|
|
13957
|
+
withdrawPoweredByFooter
|
|
13958
|
+
] })
|
|
13959
|
+
] })
|
|
13960
|
+
) })
|
|
13961
|
+
}
|
|
13962
|
+
) }) });
|
|
13963
|
+
}
|
|
13964
|
+
|
|
13965
|
+
// src/components/withdrawals/WithdrawTokenSelector.tsx
|
|
13966
|
+
import { useState as useState32, useMemo as useMemo11 } from "react";
|
|
13967
|
+
import { Search } from "lucide-react";
|
|
13968
|
+
import { jsx as jsx57, jsxs as jsxs50 } from "react/jsx-runtime";
|
|
13969
|
+
var t10 = i18n.withdrawModal;
|
|
13970
|
+
function WithdrawTokenSelector({
|
|
13971
|
+
tokens,
|
|
13972
|
+
onSelect,
|
|
13973
|
+
onBack
|
|
13974
|
+
}) {
|
|
13975
|
+
const { themeClass, colors: colors2, fonts, components } = useTheme();
|
|
13976
|
+
const [searchQuery, setSearchQuery] = useState32("");
|
|
13977
|
+
const [hoveredKey, setHoveredKey] = useState32(null);
|
|
13978
|
+
const allOptions = useMemo11(() => {
|
|
13979
|
+
const options = [];
|
|
13980
|
+
tokens.forEach((token) => {
|
|
13981
|
+
token.chains.forEach((chain) => {
|
|
13982
|
+
options.push({ token, chain });
|
|
13983
|
+
});
|
|
13984
|
+
});
|
|
13985
|
+
return options;
|
|
13986
|
+
}, [tokens]);
|
|
13987
|
+
const filteredOptions = useMemo11(() => {
|
|
13988
|
+
if (!searchQuery.trim()) return allOptions;
|
|
13989
|
+
const query = searchQuery.toLowerCase();
|
|
13990
|
+
return allOptions.filter(
|
|
13991
|
+
({ token, chain }) => token.symbol.toLowerCase().includes(query) || token.name.toLowerCase().includes(query) || chain.chain_name.toLowerCase().includes(query)
|
|
13992
|
+
);
|
|
13993
|
+
}, [allOptions, searchQuery]);
|
|
13994
|
+
return /* @__PURE__ */ jsxs50(
|
|
13995
|
+
"div",
|
|
13996
|
+
{
|
|
13997
|
+
className: "uf-flex uf-flex-col",
|
|
13998
|
+
style: { minHeight: 0, flex: 1 },
|
|
13999
|
+
children: [
|
|
14000
|
+
/* @__PURE__ */ jsxs50("div", { className: "uf-pb-3", children: [
|
|
14001
|
+
/* @__PURE__ */ jsx57(
|
|
14002
|
+
"style",
|
|
14003
|
+
{
|
|
14004
|
+
dangerouslySetInnerHTML: {
|
|
14005
|
+
__html: `.uf-withdraw-token-search::placeholder { color: ${components.search.placeholderColor}; }`
|
|
14006
|
+
}
|
|
14007
|
+
}
|
|
14008
|
+
),
|
|
14009
|
+
/* @__PURE__ */ jsxs50("div", { style: { position: "relative" }, children: [
|
|
14010
|
+
/* @__PURE__ */ jsx57(
|
|
14011
|
+
Search,
|
|
14012
|
+
{
|
|
14013
|
+
className: "uf-absolute uf-left-3 uf-top-1/2 uf--translate-y-1/2 uf-w-4 uf-h-4",
|
|
14014
|
+
style: { color: components.search.placeholderColor }
|
|
14015
|
+
}
|
|
14016
|
+
),
|
|
14017
|
+
/* @__PURE__ */ jsx57(
|
|
14018
|
+
"input",
|
|
14019
|
+
{
|
|
14020
|
+
type: "text",
|
|
14021
|
+
placeholder: "Search token or network",
|
|
14022
|
+
value: searchQuery,
|
|
14023
|
+
onChange: (e) => setSearchQuery(e.target.value),
|
|
14024
|
+
className: "uf-withdraw-token-search uf-w-full uf-pl-10 uf-pr-4 uf-py-2.5 uf-text-sm uf-outline-none focus:uf-ring-2 focus:uf-ring-ring/30",
|
|
14025
|
+
style: {
|
|
14026
|
+
backgroundColor: components.search.backgroundColor,
|
|
14027
|
+
color: components.search.inputColor,
|
|
14028
|
+
fontFamily: fonts.regular,
|
|
14029
|
+
borderRadius: components.input.borderRadius,
|
|
14030
|
+
border: `${components.input.borderWidth}px solid ${components.input.borderColor}`
|
|
14031
|
+
}
|
|
14032
|
+
}
|
|
14033
|
+
)
|
|
14034
|
+
] })
|
|
14035
|
+
] }),
|
|
14036
|
+
/* @__PURE__ */ jsx57(
|
|
14037
|
+
"div",
|
|
14038
|
+
{
|
|
14039
|
+
className: "uf-text-xs uf-mb-2",
|
|
14040
|
+
style: {
|
|
14041
|
+
color: components.list.titleSectionColor,
|
|
14042
|
+
fontFamily: fonts.medium
|
|
14043
|
+
},
|
|
14044
|
+
children: t10.selectToken
|
|
14045
|
+
}
|
|
14046
|
+
),
|
|
14047
|
+
/* @__PURE__ */ jsx57(
|
|
14048
|
+
"div",
|
|
14049
|
+
{
|
|
14050
|
+
className: "uf-flex-1 uf-overflow-y-auto uf-min-h-0 uf--mx-6 uf-px-6 uf-pb-3",
|
|
14051
|
+
style: { scrollbarWidth: "none" },
|
|
14052
|
+
children: filteredOptions.length === 0 ? /* @__PURE__ */ jsx57(
|
|
14053
|
+
"div",
|
|
14054
|
+
{
|
|
14055
|
+
style: {
|
|
14056
|
+
textAlign: "center",
|
|
14057
|
+
padding: "2rem 0",
|
|
14058
|
+
fontSize: 14,
|
|
14059
|
+
color: components.container.subtitleColor,
|
|
14060
|
+
fontFamily: fonts.regular
|
|
14061
|
+
},
|
|
14062
|
+
children: t10.noTokensAvailable
|
|
14063
|
+
}
|
|
14064
|
+
) : /* @__PURE__ */ jsx57("div", { style: { display: "flex", flexDirection: "column", gap: 4 }, children: filteredOptions.map(({ token, chain }) => {
|
|
14065
|
+
const key = `${token.symbol}-${chain.chain_type}:${chain.chain_id}`;
|
|
14066
|
+
return /* @__PURE__ */ jsxs50(
|
|
14067
|
+
"button",
|
|
14068
|
+
{
|
|
14069
|
+
type: "button",
|
|
14070
|
+
onClick: () => onSelect(token, chain),
|
|
14071
|
+
onMouseEnter: () => setHoveredKey(key),
|
|
14072
|
+
onMouseLeave: () => setHoveredKey(null),
|
|
14073
|
+
className: "uf-transition-colors",
|
|
14074
|
+
style: {
|
|
14075
|
+
width: "100%",
|
|
14076
|
+
display: "flex",
|
|
14077
|
+
alignItems: "center",
|
|
14078
|
+
gap: 12,
|
|
14079
|
+
padding: 12,
|
|
14080
|
+
borderRadius: 12,
|
|
14081
|
+
border: "none",
|
|
14082
|
+
cursor: "pointer",
|
|
14083
|
+
textAlign: "left",
|
|
14084
|
+
backgroundColor: hoveredKey === key ? colors2.cardHover : "transparent"
|
|
14085
|
+
},
|
|
14086
|
+
children: [
|
|
14087
|
+
/* @__PURE__ */ jsxs50("div", { style: { position: "relative", flexShrink: 0 }, children: [
|
|
14088
|
+
/* @__PURE__ */ jsx57(
|
|
14089
|
+
"img",
|
|
14090
|
+
{
|
|
14091
|
+
src: token.icon_url,
|
|
14092
|
+
alt: token.symbol,
|
|
14093
|
+
width: 40,
|
|
14094
|
+
height: 40,
|
|
14095
|
+
loading: "lazy",
|
|
14096
|
+
className: "uf-rounded-full"
|
|
14097
|
+
}
|
|
14098
|
+
),
|
|
14099
|
+
/* @__PURE__ */ jsx57(
|
|
14100
|
+
"div",
|
|
14101
|
+
{
|
|
14102
|
+
style: {
|
|
14103
|
+
position: "absolute",
|
|
14104
|
+
bottom: -4,
|
|
14105
|
+
right: -4
|
|
14106
|
+
},
|
|
14107
|
+
children: /* @__PURE__ */ jsx57(
|
|
14108
|
+
"img",
|
|
14109
|
+
{
|
|
14110
|
+
src: chain.icon_url,
|
|
14111
|
+
alt: chain.chain_name,
|
|
14112
|
+
width: 20,
|
|
14113
|
+
height: 20,
|
|
14114
|
+
loading: "lazy",
|
|
14115
|
+
className: "uf-rounded-full uf-border-2"
|
|
14116
|
+
}
|
|
14117
|
+
)
|
|
14118
|
+
}
|
|
14119
|
+
)
|
|
14120
|
+
] }),
|
|
14121
|
+
/* @__PURE__ */ jsxs50("div", { style: { flex: 1, minWidth: 0 }, children: [
|
|
14122
|
+
/* @__PURE__ */ jsx57(
|
|
14123
|
+
"div",
|
|
14124
|
+
{
|
|
14125
|
+
style: {
|
|
14126
|
+
fontSize: 14,
|
|
14127
|
+
fontWeight: 500,
|
|
14128
|
+
color: components.card.titleColor,
|
|
14129
|
+
fontFamily: fonts.medium
|
|
14130
|
+
},
|
|
14131
|
+
children: token.symbol
|
|
14132
|
+
}
|
|
14133
|
+
),
|
|
14134
|
+
/* @__PURE__ */ jsxs50(
|
|
14135
|
+
"div",
|
|
14136
|
+
{
|
|
14137
|
+
style: {
|
|
14138
|
+
fontSize: 12,
|
|
14139
|
+
color: components.card.subtitleColor,
|
|
14140
|
+
fontFamily: fonts.regular
|
|
14141
|
+
},
|
|
14142
|
+
children: [
|
|
14143
|
+
token.name,
|
|
14144
|
+
" \u2022 ",
|
|
14145
|
+
chain.chain_name
|
|
14146
|
+
]
|
|
14147
|
+
}
|
|
14148
|
+
)
|
|
14149
|
+
] })
|
|
14150
|
+
]
|
|
14151
|
+
},
|
|
14152
|
+
key
|
|
14153
|
+
);
|
|
14154
|
+
}) })
|
|
14155
|
+
}
|
|
14156
|
+
),
|
|
14157
|
+
/* @__PURE__ */ jsx57("div", { className: "uf-pt-3 uf-pb-2 uf-shrink-0", children: /* @__PURE__ */ jsx57(
|
|
14158
|
+
PoweredByUnifold,
|
|
14159
|
+
{
|
|
14160
|
+
color: colors2.foregroundMuted,
|
|
14161
|
+
className: "uf-flex uf-justify-center uf-shrink-0"
|
|
14162
|
+
}
|
|
14163
|
+
) })
|
|
14164
|
+
]
|
|
14165
|
+
}
|
|
14166
|
+
);
|
|
14167
|
+
}
|
|
12133
14168
|
export {
|
|
12134
14169
|
Button,
|
|
12135
14170
|
BuyWithCard,
|
|
@@ -12175,15 +14210,29 @@ export {
|
|
|
12175
14210
|
TransferCryptoButton,
|
|
12176
14211
|
TransferCryptoDoubleInput,
|
|
12177
14212
|
TransferCryptoSingleInput,
|
|
14213
|
+
WithdrawConfirmingView,
|
|
14214
|
+
WithdrawDoubleInput,
|
|
14215
|
+
WithdrawExecutionItem,
|
|
14216
|
+
WithdrawForm,
|
|
14217
|
+
WithdrawModal,
|
|
14218
|
+
WithdrawTokenSelector,
|
|
12178
14219
|
buttonVariants,
|
|
12179
14220
|
cn,
|
|
12180
14221
|
colors,
|
|
12181
14222
|
defaultColors,
|
|
14223
|
+
detectBrowserWallet,
|
|
12182
14224
|
getColors,
|
|
12183
14225
|
mergeColors,
|
|
12184
14226
|
resolveComponentTokens,
|
|
14227
|
+
sendEvmWithdraw,
|
|
14228
|
+
sendSolanaWithdraw,
|
|
12185
14229
|
truncateAddress,
|
|
14230
|
+
useAddressBalance,
|
|
12186
14231
|
useAllowedCountry,
|
|
12187
14232
|
useDepositPolling,
|
|
12188
|
-
|
|
14233
|
+
useSourceTokenValidation,
|
|
14234
|
+
useSupportedDestinationTokens,
|
|
14235
|
+
useTheme,
|
|
14236
|
+
useVerifyRecipientAddress,
|
|
14237
|
+
useWithdrawPolling
|
|
12189
14238
|
};
|