@unifold/ui-react 0.1.40 → 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 +332 -37
- package/dist/index.d.ts +332 -37
- package/dist/index.js +2253 -186
- package/dist/index.mjs +2273 -184
- package/dist/styles-base.css +1 -1
- package/dist/styles.css +1 -1
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
// src/components/deposits/DepositModal.tsx
|
|
2
2
|
import {
|
|
3
|
-
useState as
|
|
4
|
-
useEffect as
|
|
3
|
+
useState as useState27,
|
|
4
|
+
useEffect as useEffect21,
|
|
5
5
|
useLayoutEffect as useLayoutEffect2,
|
|
6
6
|
useCallback as useCallback4,
|
|
7
|
-
useRef as
|
|
7
|
+
useRef as useRef6,
|
|
8
8
|
useMemo as useMemo9
|
|
9
9
|
} from "react";
|
|
10
10
|
import { ChevronRight as ChevronRight11, MapPinOff, AlertTriangle } from "lucide-react";
|
|
@@ -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
|
|
@@ -7051,7 +7081,7 @@ function useSupportedDepositTokens(publishableKey, options) {
|
|
|
7051
7081
|
}
|
|
7052
7082
|
|
|
7053
7083
|
// src/components/deposits/TransferCryptoSingleInput.tsx
|
|
7054
|
-
import { useState as
|
|
7084
|
+
import { useState as useState22, useEffect as useEffect17, useMemo as useMemo5 } from "react";
|
|
7055
7085
|
import {
|
|
7056
7086
|
ChevronDown as ChevronDown3,
|
|
7057
7087
|
ChevronUp as ChevronUp2,
|
|
@@ -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
|
|
@@ -7939,6 +7969,107 @@ function DepositPollingUi({
|
|
|
7939
7969
|
return null;
|
|
7940
7970
|
}
|
|
7941
7971
|
|
|
7972
|
+
// src/hooks/use-default-source-token.ts
|
|
7973
|
+
import { useState as useState19, useEffect as useEffect16, useRef as useRef5 } from "react";
|
|
7974
|
+
var getChainKey = (chainId, chainType) => {
|
|
7975
|
+
return `${chainType}:${chainId}`;
|
|
7976
|
+
};
|
|
7977
|
+
function resolveSourceToken(supportedTokens, defaultSourceChainType, defaultSourceChainId, defaultSourceTokenAddress, defaultSourceSymbol) {
|
|
7978
|
+
if (!supportedTokens.length) return null;
|
|
7979
|
+
let selectedTokenData;
|
|
7980
|
+
let selectedChainData;
|
|
7981
|
+
const hasChainDefaults = defaultSourceChainType && defaultSourceChainId;
|
|
7982
|
+
if (defaultSourceTokenAddress && hasChainDefaults) {
|
|
7983
|
+
for (const t11 of supportedTokens) {
|
|
7984
|
+
const matchingChain = t11.chains.find(
|
|
7985
|
+
(c) => c.token_address.toLowerCase() === defaultSourceTokenAddress.toLowerCase() && c.chain_type === defaultSourceChainType && c.chain_id === defaultSourceChainId
|
|
7986
|
+
);
|
|
7987
|
+
if (matchingChain) {
|
|
7988
|
+
selectedTokenData = t11;
|
|
7989
|
+
selectedChainData = matchingChain;
|
|
7990
|
+
break;
|
|
7991
|
+
}
|
|
7992
|
+
}
|
|
7993
|
+
}
|
|
7994
|
+
if (!selectedTokenData && defaultSourceSymbol && hasChainDefaults) {
|
|
7995
|
+
for (const t11 of supportedTokens) {
|
|
7996
|
+
if (t11.symbol !== defaultSourceSymbol) continue;
|
|
7997
|
+
const matchedChain = t11.chains.find(
|
|
7998
|
+
(c) => c.chain_type === defaultSourceChainType && c.chain_id === defaultSourceChainId
|
|
7999
|
+
);
|
|
8000
|
+
if (matchedChain) {
|
|
8001
|
+
selectedTokenData = t11;
|
|
8002
|
+
selectedChainData = matchedChain;
|
|
8003
|
+
break;
|
|
8004
|
+
}
|
|
8005
|
+
}
|
|
8006
|
+
}
|
|
8007
|
+
if (!selectedTokenData) {
|
|
8008
|
+
for (const t11 of supportedTokens) {
|
|
8009
|
+
if (t11.chains.length > 0) {
|
|
8010
|
+
selectedTokenData = t11;
|
|
8011
|
+
selectedChainData = t11.chains[0];
|
|
8012
|
+
break;
|
|
8013
|
+
}
|
|
8014
|
+
}
|
|
8015
|
+
}
|
|
8016
|
+
if (selectedTokenData && selectedChainData) {
|
|
8017
|
+
return { token: selectedTokenData, chain: selectedChainData };
|
|
8018
|
+
}
|
|
8019
|
+
return null;
|
|
8020
|
+
}
|
|
8021
|
+
function useDefaultSourceToken({
|
|
8022
|
+
supportedTokens,
|
|
8023
|
+
defaultSourceChainType,
|
|
8024
|
+
defaultSourceChainId,
|
|
8025
|
+
defaultSourceTokenAddress,
|
|
8026
|
+
defaultSourceSymbol
|
|
8027
|
+
}) {
|
|
8028
|
+
const [token, setToken] = useState19(null);
|
|
8029
|
+
const [chain, setChain] = useState19(null);
|
|
8030
|
+
const [initialSelectionDone, setInitialSelectionDone] = useState19(false);
|
|
8031
|
+
const appliedDefaultsRef = useRef5("");
|
|
8032
|
+
useEffect16(() => {
|
|
8033
|
+
if (!supportedTokens.length) return;
|
|
8034
|
+
const defaultsKey = `${defaultSourceTokenAddress ?? ""}|${defaultSourceSymbol ?? ""}|${defaultSourceChainType ?? ""}|${defaultSourceChainId ?? ""}`;
|
|
8035
|
+
const defaultsChanged = appliedDefaultsRef.current !== defaultsKey;
|
|
8036
|
+
if (initialSelectionDone && !defaultsChanged) return;
|
|
8037
|
+
const result = resolveSourceToken(
|
|
8038
|
+
supportedTokens,
|
|
8039
|
+
defaultSourceChainType,
|
|
8040
|
+
defaultSourceChainId,
|
|
8041
|
+
defaultSourceTokenAddress,
|
|
8042
|
+
defaultSourceSymbol
|
|
8043
|
+
);
|
|
8044
|
+
if (result) {
|
|
8045
|
+
setToken(result.token.symbol);
|
|
8046
|
+
setChain(getChainKey(result.chain.chain_id, result.chain.chain_type));
|
|
8047
|
+
appliedDefaultsRef.current = defaultsKey;
|
|
8048
|
+
setInitialSelectionDone(true);
|
|
8049
|
+
}
|
|
8050
|
+
}, [
|
|
8051
|
+
supportedTokens,
|
|
8052
|
+
defaultSourceTokenAddress,
|
|
8053
|
+
defaultSourceSymbol,
|
|
8054
|
+
defaultSourceChainType,
|
|
8055
|
+
defaultSourceChainId,
|
|
8056
|
+
initialSelectionDone
|
|
8057
|
+
]);
|
|
8058
|
+
useEffect16(() => {
|
|
8059
|
+
if (!supportedTokens.length || !token) return;
|
|
8060
|
+
const currentToken = supportedTokens.find((t11) => t11.symbol === token);
|
|
8061
|
+
if (!currentToken || currentToken.chains.length === 0) return;
|
|
8062
|
+
const isChainAvailable = chain && currentToken.chains.some((c) => {
|
|
8063
|
+
return getChainKey(c.chain_id, c.chain_type) === chain;
|
|
8064
|
+
});
|
|
8065
|
+
if (!isChainAvailable) {
|
|
8066
|
+
const firstChain = currentToken.chains[0];
|
|
8067
|
+
setChain(getChainKey(firstChain.chain_id, firstChain.chain_type));
|
|
8068
|
+
}
|
|
8069
|
+
}, [token, supportedTokens, chain]);
|
|
8070
|
+
return { token, chain, setToken, setChain, initialSelectionDone };
|
|
8071
|
+
}
|
|
8072
|
+
|
|
7942
8073
|
// src/components/deposits/shared/DepositFooterLinks.tsx
|
|
7943
8074
|
import { jsx as jsx38, jsxs as jsxs33 } from "react/jsx-runtime";
|
|
7944
8075
|
function DepositFooterLinks({
|
|
@@ -8105,9 +8236,9 @@ function GlossaryModal({
|
|
|
8105
8236
|
}
|
|
8106
8237
|
|
|
8107
8238
|
// src/components/deposits/shared/useCopyAddress.ts
|
|
8108
|
-
import { useState as
|
|
8239
|
+
import { useState as useState20 } from "react";
|
|
8109
8240
|
function useCopyAddress() {
|
|
8110
|
-
const [copied, setCopied] =
|
|
8241
|
+
const [copied, setCopied] = useState20(false);
|
|
8111
8242
|
const handleCopy = (address) => {
|
|
8112
8243
|
if (!address) return;
|
|
8113
8244
|
navigator.clipboard.writeText(address);
|
|
@@ -8188,7 +8319,7 @@ import {
|
|
|
8188
8319
|
} from "@unifold/core";
|
|
8189
8320
|
import { Fragment as Fragment4, jsx as jsx41, jsxs as jsxs35 } from "react/jsx-runtime";
|
|
8190
8321
|
var t4 = i18n.transferCrypto;
|
|
8191
|
-
var
|
|
8322
|
+
var getChainKey2 = (chainId, chainType) => {
|
|
8192
8323
|
return `${chainType}:${chainId}`;
|
|
8193
8324
|
};
|
|
8194
8325
|
var parseChainKey = (chainKey) => {
|
|
@@ -8202,6 +8333,10 @@ function TransferCryptoSingleInput({
|
|
|
8202
8333
|
destinationChainType,
|
|
8203
8334
|
destinationChainId,
|
|
8204
8335
|
destinationTokenAddress,
|
|
8336
|
+
defaultSourceChainType,
|
|
8337
|
+
defaultSourceChainId,
|
|
8338
|
+
defaultSourceTokenAddress,
|
|
8339
|
+
defaultSourceSymbol,
|
|
8205
8340
|
depositConfirmationMode = "auto_ui",
|
|
8206
8341
|
onExecutionsChange,
|
|
8207
8342
|
onDepositSuccess,
|
|
@@ -8210,21 +8345,25 @@ function TransferCryptoSingleInput({
|
|
|
8210
8345
|
}) {
|
|
8211
8346
|
const { themeClass, colors: colors2, fonts, components } = useTheme();
|
|
8212
8347
|
const isDarkMode = themeClass.includes("uf-dark");
|
|
8213
|
-
const [
|
|
8214
|
-
const [chain, setChain] = useState21("solana:mainnet");
|
|
8215
|
-
const [copied, setCopied] = useState21(false);
|
|
8348
|
+
const [copied, setCopied] = useState22(false);
|
|
8216
8349
|
const { copied: copiedRecipient, handleCopy: handleCopyRecipientAddress } = useCopyAddress();
|
|
8217
|
-
const [glossaryOpen, setGlossaryOpen] =
|
|
8218
|
-
const [detailsExpanded, setDetailsExpanded] =
|
|
8219
|
-
const [depositsModalOpen, setDepositsModalOpen] =
|
|
8220
|
-
const [tokenSelectorOpen, setTokenSelectorOpen] =
|
|
8221
|
-
const [initialSelectionDone, setInitialSelectionDone] = useState21(false);
|
|
8350
|
+
const [glossaryOpen, setGlossaryOpen] = useState22(false);
|
|
8351
|
+
const [detailsExpanded, setDetailsExpanded] = useState22(false);
|
|
8352
|
+
const [depositsModalOpen, setDepositsModalOpen] = useState22(false);
|
|
8353
|
+
const [tokenSelectorOpen, setTokenSelectorOpen] = useState22(false);
|
|
8222
8354
|
const { data: tokensResponse, isLoading: tokensLoading } = useSupportedDepositTokens(publishableKey, {
|
|
8223
8355
|
destination_token_address: destinationTokenAddress,
|
|
8224
8356
|
destination_chain_id: destinationChainId,
|
|
8225
8357
|
destination_chain_type: destinationChainType
|
|
8226
8358
|
});
|
|
8227
8359
|
const supportedTokens = tokensResponse?.data ?? [];
|
|
8360
|
+
const { token, chain, setToken, setChain, initialSelectionDone } = useDefaultSourceToken({
|
|
8361
|
+
supportedTokens,
|
|
8362
|
+
defaultSourceChainType,
|
|
8363
|
+
defaultSourceChainId,
|
|
8364
|
+
defaultSourceTokenAddress,
|
|
8365
|
+
defaultSourceSymbol
|
|
8366
|
+
});
|
|
8228
8367
|
const {
|
|
8229
8368
|
data: depositAddressResponse,
|
|
8230
8369
|
isLoading: walletsLoading,
|
|
@@ -8244,8 +8383,8 @@ function TransferCryptoSingleInput({
|
|
|
8244
8383
|
const error = walletsError?.message ?? null;
|
|
8245
8384
|
const allAvailableChains = useMemo5(() => {
|
|
8246
8385
|
const chainsMap = /* @__PURE__ */ new Map();
|
|
8247
|
-
supportedTokens.forEach((
|
|
8248
|
-
|
|
8386
|
+
supportedTokens.forEach((t11) => {
|
|
8387
|
+
t11.chains.forEach((c) => {
|
|
8249
8388
|
const comboKey = `${c.chain_type}:${c.chain_id}`;
|
|
8250
8389
|
if (!chainsMap.has(comboKey)) {
|
|
8251
8390
|
chainsMap.set(comboKey, c);
|
|
@@ -8254,10 +8393,10 @@ function TransferCryptoSingleInput({
|
|
|
8254
8393
|
});
|
|
8255
8394
|
return Array.from(chainsMap.values());
|
|
8256
8395
|
}, [supportedTokens]);
|
|
8257
|
-
const currentChainCombo = parseChainKey(chain);
|
|
8258
|
-
const currentChainData = allAvailableChains.find(
|
|
8396
|
+
const currentChainCombo = chain ? parseChainKey(chain) : null;
|
|
8397
|
+
const currentChainData = currentChainCombo ? allAvailableChains.find(
|
|
8259
8398
|
(c) => c.chain_type === currentChainCombo.chainType && c.chain_id === currentChainCombo.chainId
|
|
8260
|
-
);
|
|
8399
|
+
) : void 0;
|
|
8261
8400
|
const currentChainType = currentChainData?.chain_type || "ethereum";
|
|
8262
8401
|
const currentWallet = getWalletByChainType2(wallets, currentChainType);
|
|
8263
8402
|
const depositAddress = currentWallet?.address || "";
|
|
@@ -8275,84 +8414,26 @@ function TransferCryptoSingleInput({
|
|
|
8275
8414
|
onDepositSuccess,
|
|
8276
8415
|
onDepositError
|
|
8277
8416
|
});
|
|
8278
|
-
|
|
8279
|
-
if (!supportedTokens.length || initialSelectionDone) return;
|
|
8280
|
-
let selectedTokenData;
|
|
8281
|
-
let selectedChainData;
|
|
8282
|
-
if (destinationTokenAddress) {
|
|
8283
|
-
for (const t7 of supportedTokens) {
|
|
8284
|
-
const matchingChain = t7.chains.find(
|
|
8285
|
-
(c) => c.token_address.toLowerCase() === destinationTokenAddress.toLowerCase()
|
|
8286
|
-
);
|
|
8287
|
-
if (matchingChain) {
|
|
8288
|
-
selectedTokenData = t7;
|
|
8289
|
-
selectedChainData = matchingChain;
|
|
8290
|
-
break;
|
|
8291
|
-
}
|
|
8292
|
-
}
|
|
8293
|
-
}
|
|
8294
|
-
if (!selectedTokenData) {
|
|
8295
|
-
selectedTokenData = supportedTokens.find((t7) => t7.symbol === "USDC");
|
|
8296
|
-
if (selectedTokenData && selectedTokenData.chains.length > 0) {
|
|
8297
|
-
selectedChainData = selectedTokenData.chains[0];
|
|
8298
|
-
}
|
|
8299
|
-
}
|
|
8300
|
-
if (!selectedTokenData) {
|
|
8301
|
-
selectedTokenData = supportedTokens.find((t7) => t7.symbol === "USDT");
|
|
8302
|
-
if (selectedTokenData && selectedTokenData.chains.length > 0) {
|
|
8303
|
-
selectedChainData = selectedTokenData.chains[0];
|
|
8304
|
-
}
|
|
8305
|
-
}
|
|
8306
|
-
if (!selectedTokenData) {
|
|
8307
|
-
selectedTokenData = supportedTokens[0];
|
|
8308
|
-
if (selectedTokenData.chains.length > 0) {
|
|
8309
|
-
selectedChainData = selectedTokenData.chains[0];
|
|
8310
|
-
}
|
|
8311
|
-
}
|
|
8312
|
-
if (selectedTokenData) {
|
|
8313
|
-
setToken(selectedTokenData.symbol);
|
|
8314
|
-
}
|
|
8315
|
-
if (selectedChainData) {
|
|
8316
|
-
setChain(
|
|
8317
|
-
getChainKey(selectedChainData.chain_id, selectedChainData.chain_type)
|
|
8318
|
-
);
|
|
8319
|
-
}
|
|
8320
|
-
setInitialSelectionDone(true);
|
|
8321
|
-
}, [supportedTokens, destinationTokenAddress, initialSelectionDone]);
|
|
8322
|
-
useEffect16(() => {
|
|
8417
|
+
useEffect17(() => {
|
|
8323
8418
|
if (onExecutionsChange) {
|
|
8324
8419
|
onExecutionsChange(depositExecutions);
|
|
8325
8420
|
}
|
|
8326
8421
|
}, [depositExecutions, onExecutionsChange]);
|
|
8327
|
-
|
|
8328
|
-
if (!supportedTokens.length) return;
|
|
8329
|
-
const currentToken = supportedTokens.find((t7) => t7.symbol === token);
|
|
8330
|
-
if (!currentToken || currentToken.chains.length === 0) return;
|
|
8331
|
-
const isChainAvailable = currentToken.chains.some((c) => {
|
|
8332
|
-
const key = getChainKey(c.chain_id, c.chain_type);
|
|
8333
|
-
return key === chain;
|
|
8334
|
-
});
|
|
8335
|
-
if (!isChainAvailable) {
|
|
8336
|
-
const firstChain = currentToken.chains[0];
|
|
8337
|
-
const newChain = getChainKey(firstChain.chain_id, firstChain.chain_type);
|
|
8338
|
-
setChain(newChain);
|
|
8339
|
-
}
|
|
8340
|
-
}, [token, supportedTokens, chain]);
|
|
8341
|
-
const selectedToken = supportedTokens.find((t7) => t7.symbol === token);
|
|
8422
|
+
const selectedToken = token ? supportedTokens.find((t11) => t11.symbol === token) : void 0;
|
|
8342
8423
|
const availableChainsForToken = selectedToken?.chains || [];
|
|
8343
|
-
const currentChainFromBackend = availableChainsForToken.find((c) => {
|
|
8344
|
-
const key =
|
|
8424
|
+
const currentChainFromBackend = chain ? availableChainsForToken.find((c) => {
|
|
8425
|
+
const key = getChainKey2(c.chain_id, c.chain_type);
|
|
8345
8426
|
return key === chain;
|
|
8346
8427
|
}) || allAvailableChains.find((c) => {
|
|
8347
|
-
const key =
|
|
8428
|
+
const key = getChainKey2(c.chain_id, c.chain_type);
|
|
8348
8429
|
return key === chain;
|
|
8349
|
-
});
|
|
8430
|
+
}) : void 0;
|
|
8350
8431
|
const handleCopyAddress = () => {
|
|
8351
8432
|
navigator.clipboard.writeText(depositAddress);
|
|
8352
8433
|
setCopied(true);
|
|
8353
8434
|
setTimeout(() => setCopied(false), 2e3);
|
|
8354
8435
|
};
|
|
8355
|
-
const
|
|
8436
|
+
const formatProcessingTime3 = (seconds) => {
|
|
8356
8437
|
if (seconds === null) {
|
|
8357
8438
|
return t4.processingTime.lessThanMinutes.replace("{{minutes}}", "1");
|
|
8358
8439
|
}
|
|
@@ -8381,10 +8462,10 @@ function TransferCryptoSingleInput({
|
|
|
8381
8462
|
"button",
|
|
8382
8463
|
{
|
|
8383
8464
|
onClick: () => setTokenSelectorOpen(true),
|
|
8384
|
-
disabled: tokensLoading || supportedTokens.length === 0,
|
|
8465
|
+
disabled: tokensLoading || !token || supportedTokens.length === 0,
|
|
8385
8466
|
className: "uf-w-full hover:uf-bg-accent uf-p-3 uf-flex uf-items-center uf-gap-3 uf-transition-colors disabled:uf-opacity-50 disabled:uf-cursor-not-allowed",
|
|
8386
8467
|
style: { backgroundColor: components.card.backgroundColor, borderRadius: components.card.borderRadius, border: `${components.card.borderWidth}px solid ${components.card.borderColor}` },
|
|
8387
|
-
children: tokensLoading ? /* @__PURE__ */ jsxs35("div", { className: "uf-flex uf-items-center uf-gap-3 uf-animate-pulse", children: [
|
|
8468
|
+
children: tokensLoading || !token ? /* @__PURE__ */ jsxs35("div", { className: "uf-flex uf-items-center uf-gap-3 uf-animate-pulse", children: [
|
|
8388
8469
|
/* @__PURE__ */ jsx41("div", { className: "uf-w-10 uf-h-10 uf-rounded-full uf-bg-muted" }),
|
|
8389
8470
|
/* @__PURE__ */ jsxs35("div", { className: "uf-flex-1", children: [
|
|
8390
8471
|
/* @__PURE__ */ jsx41("div", { className: "uf-h-4 uf-w-16 uf-bg-muted uf-rounded uf-mb-1" }),
|
|
@@ -8458,8 +8539,8 @@ function TransferCryptoSingleInput({
|
|
|
8458
8539
|
open: tokenSelectorOpen,
|
|
8459
8540
|
onOpenChange: setTokenSelectorOpen,
|
|
8460
8541
|
tokens: supportedTokens,
|
|
8461
|
-
selectedToken: token,
|
|
8462
|
-
selectedChainKey: chain,
|
|
8542
|
+
selectedToken: token ?? "",
|
|
8543
|
+
selectedChainKey: chain ?? "",
|
|
8463
8544
|
onSelect: (newToken, newChain) => {
|
|
8464
8545
|
setToken(newToken);
|
|
8465
8546
|
setChain(newChain);
|
|
@@ -8561,7 +8642,7 @@ function TransferCryptoSingleInput({
|
|
|
8561
8642
|
t4.processingTime.label,
|
|
8562
8643
|
":",
|
|
8563
8644
|
" ",
|
|
8564
|
-
/* @__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) })
|
|
8565
8646
|
] })
|
|
8566
8647
|
] }),
|
|
8567
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 } })
|
|
@@ -8671,7 +8752,7 @@ function TransferCryptoSingleInput({
|
|
|
8671
8752
|
}
|
|
8672
8753
|
|
|
8673
8754
|
// src/components/deposits/TransferCryptoDoubleInput.tsx
|
|
8674
|
-
import { useState as
|
|
8755
|
+
import { useState as useState23, useEffect as useEffect18, useMemo as useMemo6 } from "react";
|
|
8675
8756
|
import {
|
|
8676
8757
|
ChevronDown as ChevronDown5,
|
|
8677
8758
|
ChevronUp as ChevronUp4,
|
|
@@ -8825,7 +8906,7 @@ import {
|
|
|
8825
8906
|
} from "@unifold/core";
|
|
8826
8907
|
import { jsx as jsx43, jsxs as jsxs37 } from "react/jsx-runtime";
|
|
8827
8908
|
var t5 = i18n.transferCrypto;
|
|
8828
|
-
var
|
|
8909
|
+
var getChainKey3 = (chainId, chainType) => {
|
|
8829
8910
|
return `${chainType}:${chainId}`;
|
|
8830
8911
|
};
|
|
8831
8912
|
var parseChainKey2 = (chainKey) => {
|
|
@@ -8839,6 +8920,10 @@ function TransferCryptoDoubleInput({
|
|
|
8839
8920
|
destinationChainType,
|
|
8840
8921
|
destinationChainId,
|
|
8841
8922
|
destinationTokenAddress,
|
|
8923
|
+
defaultSourceChainType,
|
|
8924
|
+
defaultSourceChainId,
|
|
8925
|
+
defaultSourceTokenAddress,
|
|
8926
|
+
defaultSourceSymbol,
|
|
8842
8927
|
depositConfirmationMode = "auto_ui",
|
|
8843
8928
|
onExecutionsChange,
|
|
8844
8929
|
onDepositSuccess,
|
|
@@ -8847,20 +8932,24 @@ function TransferCryptoDoubleInput({
|
|
|
8847
8932
|
}) {
|
|
8848
8933
|
const { themeClass, colors: colors2, fonts, components } = useTheme();
|
|
8849
8934
|
const isDarkMode = themeClass.includes("uf-dark");
|
|
8850
|
-
const [
|
|
8851
|
-
const [chain, setChain] = useState22("solana:mainnet");
|
|
8852
|
-
const [copied, setCopied] = useState22(false);
|
|
8935
|
+
const [copied, setCopied] = useState23(false);
|
|
8853
8936
|
const { copied: copiedRecipient, handleCopy: handleCopyRecipientAddress } = useCopyAddress();
|
|
8854
|
-
const [glossaryOpen, setGlossaryOpen] =
|
|
8855
|
-
const [detailsExpanded, setDetailsExpanded] =
|
|
8856
|
-
const [depositsModalOpen, setDepositsModalOpen] =
|
|
8857
|
-
const [initialSelectionDone, setInitialSelectionDone] = useState22(false);
|
|
8937
|
+
const [glossaryOpen, setGlossaryOpen] = useState23(false);
|
|
8938
|
+
const [detailsExpanded, setDetailsExpanded] = useState23(false);
|
|
8939
|
+
const [depositsModalOpen, setDepositsModalOpen] = useState23(false);
|
|
8858
8940
|
const { data: tokensResponse, isLoading: tokensLoading } = useSupportedDepositTokens(publishableKey, {
|
|
8859
8941
|
destination_token_address: destinationTokenAddress,
|
|
8860
8942
|
destination_chain_id: destinationChainId,
|
|
8861
8943
|
destination_chain_type: destinationChainType
|
|
8862
8944
|
});
|
|
8863
8945
|
const supportedTokens = tokensResponse?.data ?? [];
|
|
8946
|
+
const { token, chain, setToken, setChain, initialSelectionDone } = useDefaultSourceToken({
|
|
8947
|
+
supportedTokens,
|
|
8948
|
+
defaultSourceChainType,
|
|
8949
|
+
defaultSourceChainId,
|
|
8950
|
+
defaultSourceTokenAddress,
|
|
8951
|
+
defaultSourceSymbol
|
|
8952
|
+
});
|
|
8864
8953
|
const {
|
|
8865
8954
|
data: depositAddressResponse,
|
|
8866
8955
|
isLoading: walletsLoading,
|
|
@@ -8880,8 +8969,8 @@ function TransferCryptoDoubleInput({
|
|
|
8880
8969
|
const error = walletsError?.message ?? null;
|
|
8881
8970
|
const allAvailableChains = useMemo6(() => {
|
|
8882
8971
|
const chainsMap = /* @__PURE__ */ new Map();
|
|
8883
|
-
supportedTokens.forEach((
|
|
8884
|
-
|
|
8972
|
+
supportedTokens.forEach((t11) => {
|
|
8973
|
+
t11.chains.forEach((c) => {
|
|
8885
8974
|
const comboKey = `${c.chain_type}:${c.chain_id}`;
|
|
8886
8975
|
if (!chainsMap.has(comboKey)) {
|
|
8887
8976
|
chainsMap.set(comboKey, c);
|
|
@@ -8890,10 +8979,10 @@ function TransferCryptoDoubleInput({
|
|
|
8890
8979
|
});
|
|
8891
8980
|
return Array.from(chainsMap.values());
|
|
8892
8981
|
}, [supportedTokens]);
|
|
8893
|
-
const currentChainCombo = parseChainKey2(chain);
|
|
8894
|
-
const currentChainData = allAvailableChains.find(
|
|
8982
|
+
const currentChainCombo = chain ? parseChainKey2(chain) : null;
|
|
8983
|
+
const currentChainData = currentChainCombo ? allAvailableChains.find(
|
|
8895
8984
|
(c) => c.chain_type === currentChainCombo.chainType && c.chain_id === currentChainCombo.chainId
|
|
8896
|
-
);
|
|
8985
|
+
) : void 0;
|
|
8897
8986
|
const currentChainType = currentChainData?.chain_type || "ethereum";
|
|
8898
8987
|
const currentWallet = getWalletByChainType3(wallets, currentChainType);
|
|
8899
8988
|
const depositAddress = currentWallet?.address || "";
|
|
@@ -8911,57 +9000,26 @@ function TransferCryptoDoubleInput({
|
|
|
8911
9000
|
onDepositSuccess,
|
|
8912
9001
|
onDepositError
|
|
8913
9002
|
});
|
|
8914
|
-
|
|
8915
|
-
if (!supportedTokens.length || initialSelectionDone) return;
|
|
8916
|
-
const allChains = /* @__PURE__ */ new Set();
|
|
8917
|
-
supportedTokens.forEach((t7) => {
|
|
8918
|
-
t7.chains.forEach((c) => {
|
|
8919
|
-
allChains.add(getChainKey2(c.chain_id, c.chain_type));
|
|
8920
|
-
});
|
|
8921
|
-
});
|
|
8922
|
-
if (!allChains.has(chain)) {
|
|
8923
|
-
const firstToken = supportedTokens[0];
|
|
8924
|
-
if (firstToken.chains.length > 0) {
|
|
8925
|
-
const firstChain = firstToken.chains[0];
|
|
8926
|
-
setChain(getChainKey2(firstChain.chain_id, firstChain.chain_type));
|
|
8927
|
-
}
|
|
8928
|
-
}
|
|
8929
|
-
setInitialSelectionDone(true);
|
|
8930
|
-
}, [supportedTokens, chain, initialSelectionDone]);
|
|
8931
|
-
useEffect17(() => {
|
|
9003
|
+
useEffect18(() => {
|
|
8932
9004
|
if (onExecutionsChange) {
|
|
8933
9005
|
onExecutionsChange(depositExecutions);
|
|
8934
9006
|
}
|
|
8935
9007
|
}, [depositExecutions, onExecutionsChange]);
|
|
8936
|
-
|
|
8937
|
-
if (!supportedTokens.length) return;
|
|
8938
|
-
const currentToken = supportedTokens.find((t7) => t7.symbol === token);
|
|
8939
|
-
if (!currentToken || currentToken.chains.length === 0) return;
|
|
8940
|
-
const isChainAvailable = currentToken.chains.some((c) => {
|
|
8941
|
-
const key = getChainKey2(c.chain_id, c.chain_type);
|
|
8942
|
-
return key === chain;
|
|
8943
|
-
});
|
|
8944
|
-
if (!isChainAvailable) {
|
|
8945
|
-
const firstChain = currentToken.chains[0];
|
|
8946
|
-
const newChain = getChainKey2(firstChain.chain_id, firstChain.chain_type);
|
|
8947
|
-
setChain(newChain);
|
|
8948
|
-
}
|
|
8949
|
-
}, [token, supportedTokens, chain]);
|
|
8950
|
-
const selectedToken = supportedTokens.find((t7) => t7.symbol === token);
|
|
9008
|
+
const selectedToken = token ? supportedTokens.find((t11) => t11.symbol === token) : void 0;
|
|
8951
9009
|
const availableChainsForToken = selectedToken?.chains || [];
|
|
8952
|
-
const currentChainFromBackend = availableChainsForToken.find((c) => {
|
|
8953
|
-
const key =
|
|
9010
|
+
const currentChainFromBackend = chain ? availableChainsForToken.find((c) => {
|
|
9011
|
+
const key = getChainKey3(c.chain_id, c.chain_type);
|
|
8954
9012
|
return key === chain;
|
|
8955
9013
|
}) || allAvailableChains.find((c) => {
|
|
8956
|
-
const key =
|
|
9014
|
+
const key = getChainKey3(c.chain_id, c.chain_type);
|
|
8957
9015
|
return key === chain;
|
|
8958
|
-
});
|
|
9016
|
+
}) : void 0;
|
|
8959
9017
|
const handleCopyAddress = () => {
|
|
8960
9018
|
navigator.clipboard.writeText(depositAddress);
|
|
8961
9019
|
setCopied(true);
|
|
8962
9020
|
setTimeout(() => setCopied(false), 2e3);
|
|
8963
9021
|
};
|
|
8964
|
-
const
|
|
9022
|
+
const formatProcessingTime3 = (seconds) => {
|
|
8965
9023
|
if (seconds === null) {
|
|
8966
9024
|
return t5.processingTime.lessThanMinutes.replace("{{minutes}}", "1");
|
|
8967
9025
|
}
|
|
@@ -9029,11 +9087,11 @@ function TransferCryptoDoubleInput({
|
|
|
9029
9087
|
/* @__PURE__ */ jsxs37(
|
|
9030
9088
|
Select,
|
|
9031
9089
|
{
|
|
9032
|
-
value: token,
|
|
9090
|
+
value: token ?? "",
|
|
9033
9091
|
onValueChange: setToken,
|
|
9034
|
-
disabled: tokensLoading || supportedTokens.length === 0,
|
|
9092
|
+
disabled: tokensLoading || !token || supportedTokens.length === 0,
|
|
9035
9093
|
children: [
|
|
9036
|
-
/* @__PURE__ */ jsx43(SelectTrigger, { className: "uf-h-10 hover:uf-opacity-90 uf-text-foreground disabled:uf-opacity-50", style: { backgroundColor: components.card.backgroundColor, border: `${components.card.borderWidth}px solid ${components.card.borderColor}` }, children: /* @__PURE__ */ jsx43(SelectValue, { children: tokensLoading ? /* @__PURE__ */ jsx43("div", { className: "uf-flex uf-items-center uf-gap-2", children: /* @__PURE__ */ jsx43("span", { className: "uf-text-xs uf-font-light uf-text-muted-foreground", children: t5.loading }) }) : selectedToken ? renderTokenItem(selectedToken) : /* @__PURE__ */ jsx43("div", { className: "uf-flex uf-items-center uf-gap-2", children: /* @__PURE__ */ jsx43("span", { className: "uf-text-xs uf-font-normal", children: token }) }) }) }),
|
|
9094
|
+
/* @__PURE__ */ jsx43(SelectTrigger, { className: "uf-h-10 hover:uf-opacity-90 uf-text-foreground disabled:uf-opacity-50", style: { backgroundColor: components.card.backgroundColor, border: `${components.card.borderWidth}px solid ${components.card.borderColor}` }, children: /* @__PURE__ */ jsx43(SelectValue, { children: tokensLoading || !token ? /* @__PURE__ */ jsx43("div", { className: "uf-flex uf-items-center uf-gap-2", children: /* @__PURE__ */ jsx43("span", { className: "uf-text-xs uf-font-light uf-text-muted-foreground", children: t5.loading }) }) : selectedToken ? renderTokenItem(selectedToken) : /* @__PURE__ */ jsx43("div", { className: "uf-flex uf-items-center uf-gap-2", children: /* @__PURE__ */ jsx43("span", { className: "uf-text-xs uf-font-normal", children: token }) }) }) }),
|
|
9037
9095
|
/* @__PURE__ */ jsx43(SelectContent, { className: "uf-bg-secondary uf-border uf-text-foreground uf-max-h-[300px]", style: { border: `1px solid ${isDarkMode ? "rgba(255,255,255,0.15)" : "rgba(0,0,0,0.15)"}`, ...fonts.regular ? { "--uf-font-family": fonts.regular } : {} }, children: supportedTokens.map((tokenData) => /* @__PURE__ */ jsx43(
|
|
9038
9096
|
SelectItem,
|
|
9039
9097
|
{
|
|
@@ -9060,11 +9118,11 @@ function TransferCryptoDoubleInput({
|
|
|
9060
9118
|
/* @__PURE__ */ jsxs37(
|
|
9061
9119
|
Select,
|
|
9062
9120
|
{
|
|
9063
|
-
value: chain,
|
|
9121
|
+
value: chain ?? "",
|
|
9064
9122
|
onValueChange: setChain,
|
|
9065
|
-
disabled: tokensLoading || availableChainsForToken.length === 0,
|
|
9123
|
+
disabled: tokensLoading || !chain || availableChainsForToken.length === 0,
|
|
9066
9124
|
children: [
|
|
9067
|
-
/* @__PURE__ */ jsx43(SelectTrigger, { className: "uf-h-10 hover:uf-opacity-90 uf-text-foreground disabled:uf-opacity-50", style: { backgroundColor: components.card.backgroundColor, border: `${components.card.borderWidth}px solid ${components.card.borderColor}` }, children: /* @__PURE__ */ jsx43(SelectValue, { children: tokensLoading ? /* @__PURE__ */ jsx43("div", { className: "uf-flex uf-items-center uf-gap-2", children: /* @__PURE__ */ jsx43("span", { className: "uf-text-xs uf-font-light uf-text-muted-foreground", children: t5.loading }) }) : currentChainFromBackend ? renderChainItem(currentChainFromBackend) : currentChainData ? renderChainItem(currentChainData) : /* @__PURE__ */ jsx43("div", { className: "uf-flex uf-items-center uf-gap-2", children: /* @__PURE__ */ jsx43("span", { className: "uf-text-xs uf-font-normal", children: chain }) }) }) }),
|
|
9125
|
+
/* @__PURE__ */ jsx43(SelectTrigger, { className: "uf-h-10 hover:uf-opacity-90 uf-text-foreground disabled:uf-opacity-50", style: { backgroundColor: components.card.backgroundColor, border: `${components.card.borderWidth}px solid ${components.card.borderColor}` }, children: /* @__PURE__ */ jsx43(SelectValue, { children: tokensLoading || !chain ? /* @__PURE__ */ jsx43("div", { className: "uf-flex uf-items-center uf-gap-2", children: /* @__PURE__ */ jsx43("span", { className: "uf-text-xs uf-font-light uf-text-muted-foreground", children: t5.loading }) }) : currentChainFromBackend ? renderChainItem(currentChainFromBackend) : currentChainData ? renderChainItem(currentChainData) : /* @__PURE__ */ jsx43("div", { className: "uf-flex uf-items-center uf-gap-2", children: /* @__PURE__ */ jsx43("span", { className: "uf-text-xs uf-font-normal", children: chain }) }) }) }),
|
|
9068
9126
|
/* @__PURE__ */ jsx43(
|
|
9069
9127
|
SelectContent,
|
|
9070
9128
|
{
|
|
@@ -9072,7 +9130,7 @@ function TransferCryptoDoubleInput({
|
|
|
9072
9130
|
className: "uf-bg-secondary uf-border uf-text-foreground uf-max-h-[300px] uf-min-w-[200px]",
|
|
9073
9131
|
style: { border: `1px solid ${isDarkMode ? "rgba(255,255,255,0.15)" : "rgba(0,0,0,0.15)"}`, ...fonts.regular ? { "--uf-font-family": fonts.regular } : {} },
|
|
9074
9132
|
children: availableChainsForToken.length === 0 ? /* @__PURE__ */ jsx43("div", { className: "uf-px-2 uf-py-3 uf-text-xs uf-text-muted-foreground uf-text-center", children: t5.noChainsAvailable }) : availableChainsForToken.map((chainData) => {
|
|
9075
|
-
const chainKey =
|
|
9133
|
+
const chainKey = getChainKey3(
|
|
9076
9134
|
chainData.chain_id,
|
|
9077
9135
|
chainData.chain_type
|
|
9078
9136
|
);
|
|
@@ -9188,7 +9246,7 @@ function TransferCryptoDoubleInput({
|
|
|
9188
9246
|
t5.processingTime.label,
|
|
9189
9247
|
":",
|
|
9190
9248
|
" ",
|
|
9191
|
-
/* @__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) })
|
|
9192
9250
|
] })
|
|
9193
9251
|
] }),
|
|
9194
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 } })
|
|
@@ -10089,7 +10147,7 @@ function ReviewView({
|
|
|
10089
10147
|
}
|
|
10090
10148
|
|
|
10091
10149
|
// src/components/deposits/browser-wallets/ConfirmingView.tsx
|
|
10092
|
-
import { useCallback as useCallback2, useState as
|
|
10150
|
+
import { useCallback as useCallback2, useState as useState24 } from "react";
|
|
10093
10151
|
import { Loader2 as Loader23, CheckCircle2 } from "lucide-react";
|
|
10094
10152
|
import { Fragment as Fragment7, jsx as jsx48, jsxs as jsxs41 } from "react/jsx-runtime";
|
|
10095
10153
|
function ConfirmingView({
|
|
@@ -10099,7 +10157,7 @@ function ConfirmingView({
|
|
|
10099
10157
|
isPolling = false
|
|
10100
10158
|
}) {
|
|
10101
10159
|
const { colors: colors2, fonts } = useTheme();
|
|
10102
|
-
const [containerEl, setContainerEl] =
|
|
10160
|
+
const [containerEl, setContainerEl] = useState24(null);
|
|
10103
10161
|
const containerCallbackRef = useCallback2((el) => {
|
|
10104
10162
|
setContainerEl(el);
|
|
10105
10163
|
}, []);
|
|
@@ -10267,7 +10325,7 @@ function BrowserWalletModal({
|
|
|
10267
10325
|
);
|
|
10268
10326
|
if (cancelled) return;
|
|
10269
10327
|
const supportedToken = response.data.find(
|
|
10270
|
-
(
|
|
10328
|
+
(t11) => t11.symbol.toLowerCase() === token.symbol.toLowerCase()
|
|
10271
10329
|
);
|
|
10272
10330
|
if (supportedToken) {
|
|
10273
10331
|
const chainDetail = supportedToken.chains.find(
|
|
@@ -11483,6 +11541,10 @@ function DepositModal({
|
|
|
11483
11541
|
destinationChainType,
|
|
11484
11542
|
destinationChainId,
|
|
11485
11543
|
destinationTokenAddress,
|
|
11544
|
+
defaultSourceChainType,
|
|
11545
|
+
defaultSourceChainId,
|
|
11546
|
+
defaultSourceTokenAddress,
|
|
11547
|
+
defaultSourceSymbol,
|
|
11486
11548
|
hideDepositTracker = false,
|
|
11487
11549
|
showBalanceHeader = false,
|
|
11488
11550
|
transferInputVariant = "double_input",
|
|
@@ -11509,28 +11571,28 @@ function DepositModal({
|
|
|
11509
11571
|
if (s === "tracker" && hideDepositTracker) return "main";
|
|
11510
11572
|
return s;
|
|
11511
11573
|
}, [initialScreen, hideDepositTracker]);
|
|
11512
|
-
const [containerEl, setContainerEl] =
|
|
11574
|
+
const [containerEl, setContainerEl] = useState27(null);
|
|
11513
11575
|
const containerCallbackRef = useCallback4((el) => {
|
|
11514
11576
|
setContainerEl(el);
|
|
11515
11577
|
}, []);
|
|
11516
|
-
const [view, setView] =
|
|
11578
|
+
const [view, setView] = useState27(
|
|
11517
11579
|
effectiveInitialScreen
|
|
11518
11580
|
);
|
|
11519
|
-
const resetViewTimeoutRef =
|
|
11520
|
-
const [cardView, setCardView] =
|
|
11581
|
+
const resetViewTimeoutRef = useRef6(null);
|
|
11582
|
+
const [cardView, setCardView] = useState27(
|
|
11521
11583
|
"amount"
|
|
11522
11584
|
);
|
|
11523
|
-
const [exchangeView, setExchangeView] =
|
|
11585
|
+
const [exchangeView, setExchangeView] = useState27(
|
|
11524
11586
|
"providers"
|
|
11525
11587
|
);
|
|
11526
|
-
const [browserWalletModalOpen, setBrowserWalletModalOpen] =
|
|
11527
|
-
const [browserWalletInfo, setBrowserWalletInfo] =
|
|
11528
|
-
const [walletSelectionModalOpen, setWalletSelectionModalOpen] =
|
|
11529
|
-
const [browserWalletChainType, setBrowserWalletChainType] =
|
|
11530
|
-
const [quotesCount, setQuotesCount] =
|
|
11531
|
-
const [allExecutions, setAllExecutions] =
|
|
11532
|
-
const [selectedExecution, setSelectedExecution] =
|
|
11533
|
-
const [depositExecutions, setDepositExecutions] =
|
|
11588
|
+
const [browserWalletModalOpen, setBrowserWalletModalOpen] = useState27(false);
|
|
11589
|
+
const [browserWalletInfo, setBrowserWalletInfo] = useState27(null);
|
|
11590
|
+
const [walletSelectionModalOpen, setWalletSelectionModalOpen] = useState27(false);
|
|
11591
|
+
const [browserWalletChainType, setBrowserWalletChainType] = useState27(() => getStoredWalletChainType());
|
|
11592
|
+
const [quotesCount, setQuotesCount] = useState27(0);
|
|
11593
|
+
const [allExecutions, setAllExecutions] = useState27([]);
|
|
11594
|
+
const [selectedExecution, setSelectedExecution] = useState27(null);
|
|
11595
|
+
const [depositExecutions, setDepositExecutions] = useState27([]);
|
|
11534
11596
|
const isMobileView = useIsMobileViewport();
|
|
11535
11597
|
const { data: depositAddressResponse, isLoading: walletsLoading } = useDepositAddress({
|
|
11536
11598
|
userId,
|
|
@@ -11543,10 +11605,10 @@ function DepositModal({
|
|
|
11543
11605
|
// Only fetch when modal is open
|
|
11544
11606
|
});
|
|
11545
11607
|
const wallets = depositAddressResponse?.data ?? [];
|
|
11546
|
-
const [resolvedTheme, setResolvedTheme] =
|
|
11608
|
+
const [resolvedTheme, setResolvedTheme] = useState27(
|
|
11547
11609
|
theme === "auto" ? "dark" : theme
|
|
11548
11610
|
);
|
|
11549
|
-
|
|
11611
|
+
useEffect21(() => {
|
|
11550
11612
|
if (theme === "auto") {
|
|
11551
11613
|
const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
|
|
11552
11614
|
setResolvedTheme(mediaQuery.matches ? "dark" : "light");
|
|
@@ -11575,11 +11637,11 @@ function DepositModal({
|
|
|
11575
11637
|
chainType: destinationChainType,
|
|
11576
11638
|
enabled: open
|
|
11577
11639
|
});
|
|
11578
|
-
|
|
11640
|
+
useEffect21(() => {
|
|
11579
11641
|
if (view !== "tracker" || !userId) return;
|
|
11580
11642
|
const fetchExecutions = async () => {
|
|
11581
11643
|
try {
|
|
11582
|
-
const response = await queryExecutions3(userId, publishableKey);
|
|
11644
|
+
const response = await queryExecutions3(userId, publishableKey, ActionType3.Deposit);
|
|
11583
11645
|
const sorted = [...response.data].sort((a, b) => {
|
|
11584
11646
|
const timeA = a.created_at ? new Date(a.created_at).getTime() : 0;
|
|
11585
11647
|
const timeB = b.created_at ? new Date(b.created_at).getTime() : 0;
|
|
@@ -11596,7 +11658,7 @@ function DepositModal({
|
|
|
11596
11658
|
clearInterval(pollInterval);
|
|
11597
11659
|
};
|
|
11598
11660
|
}, [view, userId, publishableKey]);
|
|
11599
|
-
|
|
11661
|
+
useEffect21(() => {
|
|
11600
11662
|
if (view !== "tracker") {
|
|
11601
11663
|
setSelectedExecution(null);
|
|
11602
11664
|
}
|
|
@@ -11706,7 +11768,7 @@ function DepositModal({
|
|
|
11706
11768
|
setBrowserWalletInfo(null);
|
|
11707
11769
|
setSelectedExecution(null);
|
|
11708
11770
|
}, [open, effectiveInitialScreen]);
|
|
11709
|
-
|
|
11771
|
+
useEffect21(
|
|
11710
11772
|
() => () => {
|
|
11711
11773
|
if (resetViewTimeoutRef.current) {
|
|
11712
11774
|
clearTimeout(resetViewTimeoutRef.current);
|
|
@@ -11915,6 +11977,10 @@ function DepositModal({
|
|
|
11915
11977
|
destinationChainType,
|
|
11916
11978
|
destinationChainId,
|
|
11917
11979
|
destinationTokenAddress,
|
|
11980
|
+
defaultSourceChainType,
|
|
11981
|
+
defaultSourceChainId,
|
|
11982
|
+
defaultSourceTokenAddress,
|
|
11983
|
+
defaultSourceSymbol,
|
|
11918
11984
|
depositConfirmationMode,
|
|
11919
11985
|
onExecutionsChange: setDepositExecutions,
|
|
11920
11986
|
onDepositSuccess,
|
|
@@ -11930,6 +11996,10 @@ function DepositModal({
|
|
|
11930
11996
|
destinationChainType,
|
|
11931
11997
|
destinationChainId,
|
|
11932
11998
|
destinationTokenAddress,
|
|
11999
|
+
defaultSourceChainType,
|
|
12000
|
+
defaultSourceChainId,
|
|
12001
|
+
defaultSourceTokenAddress,
|
|
12002
|
+
defaultSourceSymbol,
|
|
11933
12003
|
depositConfirmationMode,
|
|
11934
12004
|
onExecutionsChange: setDepositExecutions,
|
|
11935
12005
|
onDepositSuccess,
|
|
@@ -12090,6 +12160,2011 @@ function DepositModal({
|
|
|
12090
12160
|
}
|
|
12091
12161
|
) });
|
|
12092
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
|
+
}
|
|
12093
14168
|
export {
|
|
12094
14169
|
Button,
|
|
12095
14170
|
BuyWithCard,
|
|
@@ -12135,15 +14210,29 @@ export {
|
|
|
12135
14210
|
TransferCryptoButton,
|
|
12136
14211
|
TransferCryptoDoubleInput,
|
|
12137
14212
|
TransferCryptoSingleInput,
|
|
14213
|
+
WithdrawConfirmingView,
|
|
14214
|
+
WithdrawDoubleInput,
|
|
14215
|
+
WithdrawExecutionItem,
|
|
14216
|
+
WithdrawForm,
|
|
14217
|
+
WithdrawModal,
|
|
14218
|
+
WithdrawTokenSelector,
|
|
12138
14219
|
buttonVariants,
|
|
12139
14220
|
cn,
|
|
12140
14221
|
colors,
|
|
12141
14222
|
defaultColors,
|
|
14223
|
+
detectBrowserWallet,
|
|
12142
14224
|
getColors,
|
|
12143
14225
|
mergeColors,
|
|
12144
14226
|
resolveComponentTokens,
|
|
14227
|
+
sendEvmWithdraw,
|
|
14228
|
+
sendSolanaWithdraw,
|
|
12145
14229
|
truncateAddress,
|
|
14230
|
+
useAddressBalance,
|
|
12146
14231
|
useAllowedCountry,
|
|
12147
14232
|
useDepositPolling,
|
|
12148
|
-
|
|
14233
|
+
useSourceTokenValidation,
|
|
14234
|
+
useSupportedDestinationTokens,
|
|
14235
|
+
useTheme,
|
|
14236
|
+
useVerifyRecipientAddress,
|
|
14237
|
+
useWithdrawPolling
|
|
12149
14238
|
};
|