@unifold/ui-react 0.1.41 → 0.1.43
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 +410 -37
- package/dist/index.d.ts +410 -37
- package/dist/index.js +3174 -107
- package/dist/index.mjs +3218 -123
- package/dist/styles-base.css +1 -1
- package/dist/styles.css +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -32,6 +32,7 @@ var index_exports = {};
|
|
|
32
32
|
__export(index_exports, {
|
|
33
33
|
Button: () => Button,
|
|
34
34
|
BuyWithCard: () => BuyWithCard,
|
|
35
|
+
CheckoutModal: () => CheckoutModal,
|
|
35
36
|
ConfirmingView: () => ConfirmingView,
|
|
36
37
|
CurrencyListItem: () => CurrencyListItem,
|
|
37
38
|
CurrencyListSection: () => CurrencyListSection,
|
|
@@ -55,6 +56,7 @@ __export(index_exports, {
|
|
|
55
56
|
DialogPortal: () => DialogPortal,
|
|
56
57
|
DialogTitle: () => DialogTitle,
|
|
57
58
|
DialogTrigger: () => DialogTrigger,
|
|
59
|
+
HYPERCORE_CHAIN_ID: () => HYPERCORE_CHAIN_ID,
|
|
58
60
|
Select: () => Select,
|
|
59
61
|
SelectContent: () => SelectContent,
|
|
60
62
|
SelectGroup: () => SelectGroup,
|
|
@@ -74,17 +76,35 @@ __export(index_exports, {
|
|
|
74
76
|
TransferCryptoButton: () => TransferCryptoButton,
|
|
75
77
|
TransferCryptoDoubleInput: () => TransferCryptoDoubleInput,
|
|
76
78
|
TransferCryptoSingleInput: () => TransferCryptoSingleInput,
|
|
79
|
+
WithdrawConfirmingView: () => WithdrawConfirmingView,
|
|
80
|
+
WithdrawDoubleInput: () => WithdrawDoubleInput,
|
|
81
|
+
WithdrawExecutionItem: () => WithdrawExecutionItem,
|
|
82
|
+
WithdrawForm: () => WithdrawForm,
|
|
83
|
+
WithdrawModal: () => WithdrawModal,
|
|
84
|
+
WithdrawTokenSelector: () => WithdrawTokenSelector,
|
|
77
85
|
buttonVariants: () => buttonVariants,
|
|
78
86
|
cn: () => cn,
|
|
79
87
|
colors: () => colors,
|
|
80
88
|
defaultColors: () => defaultColors,
|
|
89
|
+
detectBrowserWallet: () => detectBrowserWallet,
|
|
81
90
|
getColors: () => getColors,
|
|
91
|
+
isHypercoreChain: () => isHypercoreChain,
|
|
82
92
|
mergeColors: () => mergeColors,
|
|
83
93
|
resolveComponentTokens: () => resolveComponentTokens,
|
|
94
|
+
sendEvmWithdraw: () => sendEvmWithdraw,
|
|
95
|
+
sendHypercoreWithdraw: () => sendHypercoreWithdraw,
|
|
96
|
+
sendSolanaWithdraw: () => sendSolanaWithdraw,
|
|
84
97
|
truncateAddress: () => truncateAddress,
|
|
98
|
+
useAddressBalance: () => useAddressBalance,
|
|
85
99
|
useAllowedCountry: () => useAllowedCountry,
|
|
86
100
|
useDepositPolling: () => useDepositPolling,
|
|
87
|
-
|
|
101
|
+
useDepositQuote: () => useDepositQuote,
|
|
102
|
+
usePaymentIntent: () => usePaymentIntent,
|
|
103
|
+
useSourceTokenValidation: () => useSourceTokenValidation,
|
|
104
|
+
useSupportedDestinationTokens: () => useSupportedDestinationTokens,
|
|
105
|
+
useTheme: () => useTheme,
|
|
106
|
+
useVerifyRecipientAddress: () => useVerifyRecipientAddress,
|
|
107
|
+
useWithdrawPolling: () => useWithdrawPolling
|
|
88
108
|
});
|
|
89
109
|
module.exports = __toCommonJS(index_exports);
|
|
90
110
|
|
|
@@ -693,6 +713,7 @@ function useDepositAddress(params) {
|
|
|
693
713
|
destinationChainType,
|
|
694
714
|
destinationChainId,
|
|
695
715
|
destinationTokenAddress,
|
|
716
|
+
actionType,
|
|
696
717
|
enabled = true
|
|
697
718
|
} = params;
|
|
698
719
|
return (0, import_react_query.useQuery)({
|
|
@@ -704,6 +725,7 @@ function useDepositAddress(params) {
|
|
|
704
725
|
destinationChainType ?? null,
|
|
705
726
|
destinationChainId ?? null,
|
|
706
727
|
destinationTokenAddress ?? null,
|
|
728
|
+
actionType ?? null,
|
|
707
729
|
publishableKey
|
|
708
730
|
],
|
|
709
731
|
queryFn: () => (0, import_core.createDepositAddress)(
|
|
@@ -712,7 +734,8 @@ function useDepositAddress(params) {
|
|
|
712
734
|
recipient_address: recipientAddress,
|
|
713
735
|
destination_chain_type: destinationChainType,
|
|
714
736
|
destination_chain_id: destinationChainId,
|
|
715
|
-
destination_token_address: destinationTokenAddress
|
|
737
|
+
destination_token_address: destinationTokenAddress,
|
|
738
|
+
action_type: actionType
|
|
716
739
|
},
|
|
717
740
|
publishableKey
|
|
718
741
|
),
|
|
@@ -1426,6 +1449,30 @@ var en_default = {
|
|
|
1426
1449
|
youReceive: "You receive",
|
|
1427
1450
|
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."
|
|
1428
1451
|
}
|
|
1452
|
+
},
|
|
1453
|
+
withdrawModal: {
|
|
1454
|
+
title: "Withdraw",
|
|
1455
|
+
withdrawCrypto: {
|
|
1456
|
+
title: "Withdraw with Crypto",
|
|
1457
|
+
subtitle: "Send to any wallet address"
|
|
1458
|
+
},
|
|
1459
|
+
selectToken: "Select withdrawal token",
|
|
1460
|
+
receiveToken: "Receive token",
|
|
1461
|
+
receiveChain: "Receive chain",
|
|
1462
|
+
recipientAddress: "Recipient address",
|
|
1463
|
+
recipientAddressPlaceholder: "Enter wallet address",
|
|
1464
|
+
amount: "Amount",
|
|
1465
|
+
amountPlaceholder: "0.00",
|
|
1466
|
+
balance: "Balance",
|
|
1467
|
+
minimum: "min",
|
|
1468
|
+
withdraw: "Withdraw",
|
|
1469
|
+
invalidAddress: "Please enter a valid address",
|
|
1470
|
+
invalidAmount: "Please enter a valid amount",
|
|
1471
|
+
verifyingAddress: "Verifying address...",
|
|
1472
|
+
loading: "Loading...",
|
|
1473
|
+
noTokensAvailable: "No tokens available",
|
|
1474
|
+
review: "Review Withdrawal",
|
|
1475
|
+
back: "Back"
|
|
1429
1476
|
}
|
|
1430
1477
|
};
|
|
1431
1478
|
|
|
@@ -1449,6 +1496,7 @@ var CUTOFF_BUFFER_MS = 6e4;
|
|
|
1449
1496
|
function useDepositPolling({
|
|
1450
1497
|
userId,
|
|
1451
1498
|
publishableKey,
|
|
1499
|
+
clientSecret,
|
|
1452
1500
|
depositConfirmationMode = "auto_ui",
|
|
1453
1501
|
depositWalletId,
|
|
1454
1502
|
enabled = true,
|
|
@@ -1506,11 +1554,12 @@ function useDepositPolling({
|
|
|
1506
1554
|
depositWalletId
|
|
1507
1555
|
]);
|
|
1508
1556
|
(0, import_react3.useEffect)(() => {
|
|
1509
|
-
if (!
|
|
1557
|
+
if (!enabled) return;
|
|
1558
|
+
if (!clientSecret && !userId) return;
|
|
1510
1559
|
const modalOpenedAt = modalOpenedAtRef.current;
|
|
1511
1560
|
const poll = async () => {
|
|
1512
1561
|
try {
|
|
1513
|
-
const response = await (0, import_core6.queryExecutions)(userId, publishableKey);
|
|
1562
|
+
const response = clientSecret ? await (0, import_core6.listPaymentIntentExecutions)(clientSecret, publishableKey) : await (0, import_core6.queryExecutions)(userId, publishableKey, import_core6.ActionType.Deposit);
|
|
1514
1563
|
const cutoff = new Date(modalOpenedAt.getTime() - CUTOFF_BUFFER_MS);
|
|
1515
1564
|
const sortedExecutions = [...response.data].sort((a, b) => {
|
|
1516
1565
|
const timeA = a.created_at ? new Date(a.created_at).getTime() : 0;
|
|
@@ -1594,7 +1643,7 @@ function useDepositPolling({
|
|
|
1594
1643
|
clearInterval(pollInterval);
|
|
1595
1644
|
setIsPolling(false);
|
|
1596
1645
|
};
|
|
1597
|
-
}, [userId, publishableKey, enabled]);
|
|
1646
|
+
}, [userId, publishableKey, clientSecret, enabled]);
|
|
1598
1647
|
(0, import_react3.useEffect)(() => {
|
|
1599
1648
|
if (!pollingEnabled || !depositWalletId) return;
|
|
1600
1649
|
const triggerPoll = async () => {
|
|
@@ -1646,7 +1695,8 @@ function formatCurrency(currency) {
|
|
|
1646
1695
|
}
|
|
1647
1696
|
function DepositDetailContent({
|
|
1648
1697
|
execution,
|
|
1649
|
-
className
|
|
1698
|
+
className,
|
|
1699
|
+
variant = "deposit"
|
|
1650
1700
|
}) {
|
|
1651
1701
|
const { colors: colors2, fonts, components } = useTheme();
|
|
1652
1702
|
const [chains, setChains] = (0, import_react4.useState)([]);
|
|
@@ -2052,7 +2102,7 @@ function DepositDetailContent({
|
|
|
2052
2102
|
color: components.card.rowLeftLabel,
|
|
2053
2103
|
fontFamily: fonts.regular
|
|
2054
2104
|
},
|
|
2055
|
-
children: "Deposit Tx"
|
|
2105
|
+
children: variant === "withdraw" ? "Withdrawal Tx" : "Deposit Tx"
|
|
2056
2106
|
}
|
|
2057
2107
|
),
|
|
2058
2108
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
@@ -7338,7 +7388,7 @@ function DepositsModal({
|
|
|
7338
7388
|
if (!open || !userId) return;
|
|
7339
7389
|
const fetchExecutions = async () => {
|
|
7340
7390
|
try {
|
|
7341
|
-
const response = await (0, import_core19.queryExecutions)(userId, publishableKey);
|
|
7391
|
+
const response = await (0, import_core19.queryExecutions)(userId, publishableKey, import_core19.ActionType.Deposit);
|
|
7342
7392
|
const sorted = [...response.data].sort((a, b) => {
|
|
7343
7393
|
const timeA = a.created_at ? new Date(a.created_at).getTime() : 0;
|
|
7344
7394
|
const timeB = b.created_at ? new Date(b.created_at).getTime() : 0;
|
|
@@ -7460,7 +7510,7 @@ function saveRecentToken(token) {
|
|
|
7460
7510
|
try {
|
|
7461
7511
|
const recent = getRecentTokens();
|
|
7462
7512
|
const filtered = recent.filter(
|
|
7463
|
-
(
|
|
7513
|
+
(t11) => !(t11.symbol === token.symbol && t11.chainType === token.chainType && t11.chainId === token.chainId)
|
|
7464
7514
|
);
|
|
7465
7515
|
filtered.unshift(token);
|
|
7466
7516
|
const trimmed = filtered.slice(0, MAX_RECENT_TOKENS);
|
|
@@ -7473,7 +7523,7 @@ function removeRecentToken(token) {
|
|
|
7473
7523
|
try {
|
|
7474
7524
|
const recent = getRecentTokens();
|
|
7475
7525
|
const filtered = recent.filter(
|
|
7476
|
-
(
|
|
7526
|
+
(t11) => !(t11.symbol === token.symbol && t11.chainType === token.chainType && t11.chainId === token.chainId)
|
|
7477
7527
|
);
|
|
7478
7528
|
localStorage.setItem(STORAGE_KEY, JSON.stringify(filtered));
|
|
7479
7529
|
return filtered;
|
|
@@ -7512,7 +7562,7 @@ function TokenSelectorSheet({
|
|
|
7512
7562
|
const addOption = (symbol, chainType, chainId, isRecent) => {
|
|
7513
7563
|
const key = `${symbol}-${chainType}:${chainId}`;
|
|
7514
7564
|
if (seen.has(key)) return;
|
|
7515
|
-
const tokenData = tokens.find((
|
|
7565
|
+
const tokenData = tokens.find((t11) => t11.symbol === symbol);
|
|
7516
7566
|
if (!tokenData) return;
|
|
7517
7567
|
const chainData = tokenData.chains.find(
|
|
7518
7568
|
(c) => c.chain_type === chainType && c.chain_id === chainId
|
|
@@ -7983,35 +8033,35 @@ function resolveSourceToken(supportedTokens, defaultSourceChainType, defaultSour
|
|
|
7983
8033
|
let selectedChainData;
|
|
7984
8034
|
const hasChainDefaults = defaultSourceChainType && defaultSourceChainId;
|
|
7985
8035
|
if (defaultSourceTokenAddress && hasChainDefaults) {
|
|
7986
|
-
for (const
|
|
7987
|
-
const matchingChain =
|
|
8036
|
+
for (const t11 of supportedTokens) {
|
|
8037
|
+
const matchingChain = t11.chains.find(
|
|
7988
8038
|
(c) => c.token_address.toLowerCase() === defaultSourceTokenAddress.toLowerCase() && c.chain_type === defaultSourceChainType && c.chain_id === defaultSourceChainId
|
|
7989
8039
|
);
|
|
7990
8040
|
if (matchingChain) {
|
|
7991
|
-
selectedTokenData =
|
|
8041
|
+
selectedTokenData = t11;
|
|
7992
8042
|
selectedChainData = matchingChain;
|
|
7993
8043
|
break;
|
|
7994
8044
|
}
|
|
7995
8045
|
}
|
|
7996
8046
|
}
|
|
7997
8047
|
if (!selectedTokenData && defaultSourceSymbol && hasChainDefaults) {
|
|
7998
|
-
for (const
|
|
7999
|
-
if (
|
|
8000
|
-
const matchedChain =
|
|
8048
|
+
for (const t11 of supportedTokens) {
|
|
8049
|
+
if (t11.symbol !== defaultSourceSymbol) continue;
|
|
8050
|
+
const matchedChain = t11.chains.find(
|
|
8001
8051
|
(c) => c.chain_type === defaultSourceChainType && c.chain_id === defaultSourceChainId
|
|
8002
8052
|
);
|
|
8003
8053
|
if (matchedChain) {
|
|
8004
|
-
selectedTokenData =
|
|
8054
|
+
selectedTokenData = t11;
|
|
8005
8055
|
selectedChainData = matchedChain;
|
|
8006
8056
|
break;
|
|
8007
8057
|
}
|
|
8008
8058
|
}
|
|
8009
8059
|
}
|
|
8010
8060
|
if (!selectedTokenData) {
|
|
8011
|
-
for (const
|
|
8012
|
-
if (
|
|
8013
|
-
selectedTokenData =
|
|
8014
|
-
selectedChainData =
|
|
8061
|
+
for (const t11 of supportedTokens) {
|
|
8062
|
+
if (t11.chains.length > 0) {
|
|
8063
|
+
selectedTokenData = t11;
|
|
8064
|
+
selectedChainData = t11.chains[0];
|
|
8015
8065
|
break;
|
|
8016
8066
|
}
|
|
8017
8067
|
}
|
|
@@ -8060,7 +8110,7 @@ function useDefaultSourceToken({
|
|
|
8060
8110
|
]);
|
|
8061
8111
|
(0, import_react13.useEffect)(() => {
|
|
8062
8112
|
if (!supportedTokens.length || !token) return;
|
|
8063
|
-
const currentToken = supportedTokens.find((
|
|
8113
|
+
const currentToken = supportedTokens.find((t11) => t11.symbol === token);
|
|
8064
8114
|
if (!currentToken || currentToken.chains.length === 0) return;
|
|
8065
8115
|
const isChainAvailable = chain && currentToken.chains.some((c) => {
|
|
8066
8116
|
return getChainKey(c.chain_id, c.chain_type) === chain;
|
|
@@ -8330,6 +8380,7 @@ var parseChainKey = (chainKey) => {
|
|
|
8330
8380
|
function TransferCryptoSingleInput({
|
|
8331
8381
|
userId,
|
|
8332
8382
|
publishableKey,
|
|
8383
|
+
clientSecret,
|
|
8333
8384
|
recipientAddress,
|
|
8334
8385
|
destinationChainType,
|
|
8335
8386
|
destinationChainId,
|
|
@@ -8342,7 +8393,9 @@ function TransferCryptoSingleInput({
|
|
|
8342
8393
|
onExecutionsChange,
|
|
8343
8394
|
onDepositSuccess,
|
|
8344
8395
|
onDepositError,
|
|
8345
|
-
wallets: externalWallets
|
|
8396
|
+
wallets: externalWallets,
|
|
8397
|
+
onSourceTokenChange,
|
|
8398
|
+
checkoutQuote
|
|
8346
8399
|
}) {
|
|
8347
8400
|
const { themeClass, colors: colors2, fonts, components } = useTheme();
|
|
8348
8401
|
const isDarkMode = themeClass.includes("uf-dark");
|
|
@@ -8384,8 +8437,8 @@ function TransferCryptoSingleInput({
|
|
|
8384
8437
|
const error = walletsError?.message ?? null;
|
|
8385
8438
|
const allAvailableChains = (0, import_react15.useMemo)(() => {
|
|
8386
8439
|
const chainsMap = /* @__PURE__ */ new Map();
|
|
8387
|
-
supportedTokens.forEach((
|
|
8388
|
-
|
|
8440
|
+
supportedTokens.forEach((t11) => {
|
|
8441
|
+
t11.chains.forEach((c) => {
|
|
8389
8442
|
const comboKey = `${c.chain_type}:${c.chain_id}`;
|
|
8390
8443
|
if (!chainsMap.has(comboKey)) {
|
|
8391
8444
|
chainsMap.set(comboKey, c);
|
|
@@ -8409,18 +8462,34 @@ function TransferCryptoSingleInput({
|
|
|
8409
8462
|
} = useDepositPolling({
|
|
8410
8463
|
userId,
|
|
8411
8464
|
publishableKey,
|
|
8465
|
+
clientSecret,
|
|
8412
8466
|
depositConfirmationMode,
|
|
8413
8467
|
depositWalletId: currentWallet?.id,
|
|
8414
8468
|
enabled: true,
|
|
8415
8469
|
onDepositSuccess,
|
|
8416
8470
|
onDepositError
|
|
8417
8471
|
});
|
|
8472
|
+
(0, import_react15.useEffect)(() => {
|
|
8473
|
+
if (!onSourceTokenChange || !token || !chain || !initialSelectionDone) return;
|
|
8474
|
+
const { chainType, chainId } = parseChainKey(chain);
|
|
8475
|
+
const matchedToken = supportedTokens.find((t11) => t11.symbol === token);
|
|
8476
|
+
const matchedChain = matchedToken?.chains.find(
|
|
8477
|
+
(c) => c.chain_type === chainType && c.chain_id === chainId
|
|
8478
|
+
);
|
|
8479
|
+
onSourceTokenChange({
|
|
8480
|
+
symbol: token,
|
|
8481
|
+
chainType,
|
|
8482
|
+
chainId,
|
|
8483
|
+
tokenAddress: matchedChain?.token_address ?? "",
|
|
8484
|
+
minimumDepositAmountUsd: matchedChain?.minimum_deposit_amount_usd ?? 0
|
|
8485
|
+
});
|
|
8486
|
+
}, [token, chain, initialSelectionDone, onSourceTokenChange, supportedTokens]);
|
|
8418
8487
|
(0, import_react15.useEffect)(() => {
|
|
8419
8488
|
if (onExecutionsChange) {
|
|
8420
8489
|
onExecutionsChange(depositExecutions);
|
|
8421
8490
|
}
|
|
8422
8491
|
}, [depositExecutions, onExecutionsChange]);
|
|
8423
|
-
const selectedToken = token ? supportedTokens.find((
|
|
8492
|
+
const selectedToken = token ? supportedTokens.find((t11) => t11.symbol === token) : void 0;
|
|
8424
8493
|
const availableChainsForToken = selectedToken?.chains || [];
|
|
8425
8494
|
const currentChainFromBackend = chain ? availableChainsForToken.find((c) => {
|
|
8426
8495
|
const key = getChainKey2(c.chain_id, c.chain_type);
|
|
@@ -8434,7 +8503,7 @@ function TransferCryptoSingleInput({
|
|
|
8434
8503
|
setCopied(true);
|
|
8435
8504
|
setTimeout(() => setCopied(false), 2e3);
|
|
8436
8505
|
};
|
|
8437
|
-
const
|
|
8506
|
+
const formatProcessingTime3 = (seconds) => {
|
|
8438
8507
|
if (seconds === null) {
|
|
8439
8508
|
return t4.processingTime.lessThanMinutes.replace("{{minutes}}", "1");
|
|
8440
8509
|
}
|
|
@@ -8561,6 +8630,53 @@ function TransferCryptoSingleInput({
|
|
|
8561
8630
|
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { children: "Retrying automatically every 5 seconds..." })
|
|
8562
8631
|
] })
|
|
8563
8632
|
] }),
|
|
8633
|
+
checkoutQuote && /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(
|
|
8634
|
+
"div",
|
|
8635
|
+
{
|
|
8636
|
+
className: "uf-rounded-xl uf-px-3 uf-py-2 uf-flex uf-items-center uf-justify-between",
|
|
8637
|
+
style: {
|
|
8638
|
+
backgroundColor: components.card.backgroundColor,
|
|
8639
|
+
border: `${components.card.borderWidth}px solid ${components.card.borderColor}`,
|
|
8640
|
+
borderRadius: components.card.borderRadius
|
|
8641
|
+
},
|
|
8642
|
+
children: [
|
|
8643
|
+
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
|
|
8644
|
+
"span",
|
|
8645
|
+
{
|
|
8646
|
+
className: "uf-text-xs",
|
|
8647
|
+
style: { color: components.card.subtitleColor, fontFamily: fonts.regular },
|
|
8648
|
+
children: "You send"
|
|
8649
|
+
}
|
|
8650
|
+
),
|
|
8651
|
+
/* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(
|
|
8652
|
+
"span",
|
|
8653
|
+
{
|
|
8654
|
+
className: "uf-text-sm uf-font-semibold",
|
|
8655
|
+
style: { color: components.card.titleColor, fontFamily: fonts.semibold },
|
|
8656
|
+
children: [
|
|
8657
|
+
(Number(checkoutQuote.sourceAmount) / 10 ** checkoutQuote.sourceTokenDecimals).toFixed(
|
|
8658
|
+
Math.min(checkoutQuote.sourceTokenDecimals, 6)
|
|
8659
|
+
),
|
|
8660
|
+
" ",
|
|
8661
|
+
checkoutQuote.sourceTokenSymbol,
|
|
8662
|
+
checkoutQuote.sourceAmountUsd && /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(
|
|
8663
|
+
"span",
|
|
8664
|
+
{
|
|
8665
|
+
className: "uf-text-xs uf-font-normal uf-ml-1.5",
|
|
8666
|
+
style: { color: components.card.subtitleColor },
|
|
8667
|
+
children: [
|
|
8668
|
+
"($",
|
|
8669
|
+
checkoutQuote.sourceAmountUsd,
|
|
8670
|
+
")"
|
|
8671
|
+
]
|
|
8672
|
+
}
|
|
8673
|
+
)
|
|
8674
|
+
]
|
|
8675
|
+
}
|
|
8676
|
+
)
|
|
8677
|
+
]
|
|
8678
|
+
}
|
|
8679
|
+
),
|
|
8564
8680
|
/* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "uf-flex uf-flex-col uf-items-center uf-pt-2", children: [
|
|
8565
8681
|
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "uf-text-xs uf-mb-2 uf-flex uf-items-center uf-gap-1", style: { color: components.card.labelColor }, children: "Intent address" }),
|
|
8566
8682
|
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "uf-shadow-lg", style: { borderRadius: components.card.borderRadius, border: `${components.card.borderWidth}px solid ${components.card.borderColor}` }, children: loading || tokensLoading || !initialSelectionDone ? (
|
|
@@ -8643,7 +8759,7 @@ function TransferCryptoSingleInput({
|
|
|
8643
8759
|
t4.processingTime.label,
|
|
8644
8760
|
":",
|
|
8645
8761
|
" ",
|
|
8646
|
-
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { style: { color: components.card.titleColor, fontFamily: fonts.medium }, children:
|
|
8762
|
+
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { style: { color: components.card.titleColor, fontFamily: fonts.medium }, children: formatProcessingTime3(processingTime) })
|
|
8647
8763
|
] })
|
|
8648
8764
|
] }),
|
|
8649
8765
|
detailsExpanded ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_lucide_react16.ChevronUp, { className: "uf-w-4 uf-h-4", style: { color: components.card.actionColor } }) : /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_lucide_react16.ChevronDown, { className: "uf-w-4 uf-h-4", style: { color: components.card.actionColor } })
|
|
@@ -8957,8 +9073,8 @@ function TransferCryptoDoubleInput({
|
|
|
8957
9073
|
const error = walletsError?.message ?? null;
|
|
8958
9074
|
const allAvailableChains = (0, import_react16.useMemo)(() => {
|
|
8959
9075
|
const chainsMap = /* @__PURE__ */ new Map();
|
|
8960
|
-
supportedTokens.forEach((
|
|
8961
|
-
|
|
9076
|
+
supportedTokens.forEach((t11) => {
|
|
9077
|
+
t11.chains.forEach((c) => {
|
|
8962
9078
|
const comboKey = `${c.chain_type}:${c.chain_id}`;
|
|
8963
9079
|
if (!chainsMap.has(comboKey)) {
|
|
8964
9080
|
chainsMap.set(comboKey, c);
|
|
@@ -8993,7 +9109,7 @@ function TransferCryptoDoubleInput({
|
|
|
8993
9109
|
onExecutionsChange(depositExecutions);
|
|
8994
9110
|
}
|
|
8995
9111
|
}, [depositExecutions, onExecutionsChange]);
|
|
8996
|
-
const selectedToken = token ? supportedTokens.find((
|
|
9112
|
+
const selectedToken = token ? supportedTokens.find((t11) => t11.symbol === token) : void 0;
|
|
8997
9113
|
const availableChainsForToken = selectedToken?.chains || [];
|
|
8998
9114
|
const currentChainFromBackend = chain ? availableChainsForToken.find((c) => {
|
|
8999
9115
|
const key = getChainKey3(c.chain_id, c.chain_type);
|
|
@@ -9007,7 +9123,7 @@ function TransferCryptoDoubleInput({
|
|
|
9007
9123
|
setCopied(true);
|
|
9008
9124
|
setTimeout(() => setCopied(false), 2e3);
|
|
9009
9125
|
};
|
|
9010
|
-
const
|
|
9126
|
+
const formatProcessingTime3 = (seconds) => {
|
|
9011
9127
|
if (seconds === null) {
|
|
9012
9128
|
return t5.processingTime.lessThanMinutes.replace("{{minutes}}", "1");
|
|
9013
9129
|
}
|
|
@@ -9234,7 +9350,7 @@ function TransferCryptoDoubleInput({
|
|
|
9234
9350
|
t5.processingTime.label,
|
|
9235
9351
|
":",
|
|
9236
9352
|
" ",
|
|
9237
|
-
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { style: { color: components.card.titleColor, fontFamily: fonts.medium }, children:
|
|
9353
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { style: { color: components.card.titleColor, fontFamily: fonts.medium }, children: formatProcessingTime3(processingTime) })
|
|
9238
9354
|
] })
|
|
9239
9355
|
] }),
|
|
9240
9356
|
detailsExpanded ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_lucide_react18.ChevronUp, { className: "uf-w-4 uf-h-4", style: { color: components.card.actionColor } }) : /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_lucide_react18.ChevronDown, { className: "uf-w-4 uf-h-4", style: { color: components.card.actionColor } })
|
|
@@ -9412,9 +9528,16 @@ function SelectTokenView({
|
|
|
9412
9528
|
onBack,
|
|
9413
9529
|
onClose,
|
|
9414
9530
|
onDisconnectWallet,
|
|
9415
|
-
isDisconnectingWallet = false
|
|
9531
|
+
isDisconnectingWallet = false,
|
|
9532
|
+
checkoutAmountUsd,
|
|
9533
|
+
checkoutReceivedUsd
|
|
9416
9534
|
}) {
|
|
9417
9535
|
const { colors: colors2, fonts, components } = useTheme();
|
|
9536
|
+
const isCheckout = !!checkoutAmountUsd;
|
|
9537
|
+
const headerSubtitle = isCheckout ? parseFloat(checkoutReceivedUsd || "0") > 0 ? `$${checkoutReceivedUsd} / $${checkoutAmountUsd} received` : `Amount due: $${checkoutAmountUsd}` : formatBalanceDisplay(
|
|
9538
|
+
`$${totalBalanceUsd || "0.00"}`,
|
|
9539
|
+
projectName
|
|
9540
|
+
);
|
|
9418
9541
|
return /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(
|
|
9419
9542
|
"div",
|
|
9420
9543
|
{
|
|
@@ -9423,11 +9546,8 @@ function SelectTokenView({
|
|
|
9423
9546
|
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
9424
9547
|
DepositHeader,
|
|
9425
9548
|
{
|
|
9426
|
-
title: "Select Token",
|
|
9427
|
-
subtitle:
|
|
9428
|
-
`$${totalBalanceUsd || "0.00"}`,
|
|
9429
|
-
projectName
|
|
9430
|
-
),
|
|
9549
|
+
title: isCheckout ? "Select Token" : "Select Token",
|
|
9550
|
+
subtitle: headerSubtitle,
|
|
9431
9551
|
showBack: true,
|
|
9432
9552
|
onBack,
|
|
9433
9553
|
onClose
|
|
@@ -9658,10 +9778,19 @@ function EnterAmountView({
|
|
|
9658
9778
|
onReview,
|
|
9659
9779
|
onBack,
|
|
9660
9780
|
onClose,
|
|
9661
|
-
quickSelectMode
|
|
9781
|
+
quickSelectMode,
|
|
9782
|
+
checkoutAmountUsd,
|
|
9783
|
+
checkoutReceivedUsd
|
|
9662
9784
|
}) {
|
|
9663
9785
|
const { colors: colors2, fonts, components } = useTheme();
|
|
9786
|
+
const isCheckout = !!checkoutAmountUsd;
|
|
9664
9787
|
const balanceSubtitle = selectedBalance?.amount_usd ? `Balance: $${parseFloat(selectedBalance.amount_usd).toLocaleString(void 0, { minimumFractionDigits: 2, maximumFractionDigits: 2 })} (${formatTokenAmount(selectedBalance.amount, selectedToken.decimals, selectedToken.symbol)} ${selectedToken.symbol})` : `Balance: ${formatTokenAmount(selectedBalance.amount, selectedToken.decimals, selectedToken.symbol)} ${selectedToken.symbol}`;
|
|
9788
|
+
const checkoutRemainingUsd = isCheckout ? Math.max(
|
|
9789
|
+
parseFloat(checkoutAmountUsd) - parseFloat(checkoutReceivedUsd || "0"),
|
|
9790
|
+
0
|
|
9791
|
+
).toFixed(2) : null;
|
|
9792
|
+
const headerTitle = isCheckout ? `Pay $${checkoutRemainingUsd}` : "Enter Amount";
|
|
9793
|
+
const headerSubtitle = isCheckout ? parseFloat(checkoutReceivedUsd || "0") > 0 ? `$${checkoutReceivedUsd} / $${checkoutAmountUsd} received` : null : balanceSubtitle;
|
|
9665
9794
|
const usePercentageChips = quickSelectMode === "percentage" && maxUsdAmount > 0;
|
|
9666
9795
|
const chipButtonClass = "uf-flex-1 uf-min-w-0 uf-basis-0 uf-py-2 uf-px-1 uf-rounded-lg uf-text-sm uf-font-medium uf-transition-colors hover:uf-opacity-80 uf-whitespace-nowrap";
|
|
9667
9796
|
return /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(
|
|
@@ -9675,14 +9804,27 @@ function EnterAmountView({
|
|
|
9675
9804
|
/* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
|
|
9676
9805
|
DepositHeader,
|
|
9677
9806
|
{
|
|
9678
|
-
title:
|
|
9679
|
-
subtitle:
|
|
9807
|
+
title: headerTitle,
|
|
9808
|
+
subtitle: headerSubtitle ?? void 0,
|
|
9680
9809
|
showBack: true,
|
|
9681
9810
|
onBack,
|
|
9682
9811
|
onClose
|
|
9683
9812
|
}
|
|
9684
9813
|
),
|
|
9685
|
-
walletInfoProp ? /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("div", { className: "uf-flex uf-w-full uf-justify-center uf-mb-3", children: /* @__PURE__ */ (0, import_jsx_runtime46.
|
|
9814
|
+
walletInfoProp ? /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("div", { className: "uf-flex uf-w-full uf-justify-center uf-mb-3", children: /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "uf-flex uf-flex-col uf-items-center uf-gap-1", children: [
|
|
9815
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsx)(WalletWithNetworkBadge, { walletInfo: walletInfoProp }),
|
|
9816
|
+
isCheckout && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
|
|
9817
|
+
"span",
|
|
9818
|
+
{
|
|
9819
|
+
className: "uf-text-xs",
|
|
9820
|
+
style: {
|
|
9821
|
+
color: colors2.foregroundMuted,
|
|
9822
|
+
fontFamily: fonts.regular
|
|
9823
|
+
},
|
|
9824
|
+
children: balanceSubtitle
|
|
9825
|
+
}
|
|
9826
|
+
)
|
|
9827
|
+
] }) }) : null,
|
|
9686
9828
|
/* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "uf-flex uf-min-h-0 uf-flex-1 uf-flex-col", children: [
|
|
9687
9829
|
/* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "uf-min-h-0 uf-flex-1", children: [
|
|
9688
9830
|
/* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "uf-text-center uf-py-8", children: [
|
|
@@ -9705,7 +9847,9 @@ function EnterAmountView({
|
|
|
9705
9847
|
inputMode: "decimal",
|
|
9706
9848
|
placeholder: "0",
|
|
9707
9849
|
value: amountUsd,
|
|
9850
|
+
readOnly: isCheckout,
|
|
9708
9851
|
onChange: (e) => {
|
|
9852
|
+
if (isCheckout) return;
|
|
9709
9853
|
const value = e.target.value;
|
|
9710
9854
|
if (value === "" || /^\d*\.?\d*$/.test(value)) {
|
|
9711
9855
|
const decimalIndex = value.indexOf(".");
|
|
@@ -9716,7 +9860,7 @@ function EnterAmountView({
|
|
|
9716
9860
|
onAmountChange(value);
|
|
9717
9861
|
}
|
|
9718
9862
|
},
|
|
9719
|
-
className:
|
|
9863
|
+
className: `uf-bg-transparent uf-outline-none uf-text-center uf-font-normal uf-w-auto uf-min-w-[60px] ${isCheckout ? "uf-cursor-default" : ""}`,
|
|
9720
9864
|
style: {
|
|
9721
9865
|
fontSize: `${Math.max(3.75 - (amountUsd || "0").length * 0.15, 2)}rem`,
|
|
9722
9866
|
color: components.input.textColor,
|
|
@@ -9738,7 +9882,7 @@ function EnterAmountView({
|
|
|
9738
9882
|
}
|
|
9739
9883
|
)
|
|
9740
9884
|
] }),
|
|
9741
|
-
/* @__PURE__ */ (0, import_jsx_runtime46.jsx)("div", { className: "uf-mb-4 uf-flex uf-w-full uf-min-w-0 uf-flex-nowrap uf-gap-1.5 uf-overflow-x-auto [scrollbar-width:none] [&::-webkit-scrollbar]:uf-hidden", children: usePercentageChips ? /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(import_jsx_runtime46.Fragment, { children: [
|
|
9885
|
+
!isCheckout && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("div", { className: "uf-mb-4 uf-flex uf-w-full uf-min-w-0 uf-flex-nowrap uf-gap-1.5 uf-overflow-x-auto [scrollbar-width:none] [&::-webkit-scrollbar]:uf-hidden", children: usePercentageChips ? /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(import_jsx_runtime46.Fragment, { children: [
|
|
9742
9886
|
PERCENT_QUICK_AMOUNTS.map((pct) => /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(
|
|
9743
9887
|
"button",
|
|
9744
9888
|
{
|
|
@@ -9807,7 +9951,46 @@ function EnterAmountView({
|
|
|
9807
9951
|
}
|
|
9808
9952
|
)
|
|
9809
9953
|
] }) }),
|
|
9810
|
-
tokenChainDetails && tokenChainDetails.minimum_deposit_amount_usd > 0 && /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(
|
|
9954
|
+
tokenChainDetails && tokenChainDetails.minimum_deposit_amount_usd > 0 && (isCheckout && checkoutAmountUsd && inputUsdNum > parseFloat(checkoutAmountUsd) - parseFloat(checkoutReceivedUsd || "0") + 5e-3 ? /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(
|
|
9955
|
+
"div",
|
|
9956
|
+
{
|
|
9957
|
+
className: "uf-rounded-lg uf-px-3 uf-py-2 uf-mb-3 uf-text-center",
|
|
9958
|
+
style: {
|
|
9959
|
+
backgroundColor: colors2.warning + "15",
|
|
9960
|
+
border: `1px solid ${colors2.warning}30`,
|
|
9961
|
+
borderRadius: components.card.borderRadius,
|
|
9962
|
+
animation: "uf-fadeSlideIn 0.4s ease-out"
|
|
9963
|
+
},
|
|
9964
|
+
children: [
|
|
9965
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(
|
|
9966
|
+
"div",
|
|
9967
|
+
{
|
|
9968
|
+
className: "uf-text-xs uf-font-medium",
|
|
9969
|
+
style: { color: colors2.warning, fontFamily: fonts.medium },
|
|
9970
|
+
children: [
|
|
9971
|
+
"Minimum for ",
|
|
9972
|
+
selectedToken.symbol,
|
|
9973
|
+
" on ",
|
|
9974
|
+
selectedToken.chain_name,
|
|
9975
|
+
" is $",
|
|
9976
|
+
tokenChainDetails.minimum_deposit_amount_usd.toFixed(2)
|
|
9977
|
+
]
|
|
9978
|
+
}
|
|
9979
|
+
),
|
|
9980
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(
|
|
9981
|
+
"div",
|
|
9982
|
+
{
|
|
9983
|
+
className: "uf-text-xs uf-mt-0.5",
|
|
9984
|
+
style: { color: colors2.foregroundMuted, fontFamily: fonts.regular },
|
|
9985
|
+
children: [
|
|
9986
|
+
"Amount adjusted from remaining $",
|
|
9987
|
+
(parseFloat(checkoutAmountUsd) - parseFloat(checkoutReceivedUsd || "0")).toFixed(2)
|
|
9988
|
+
]
|
|
9989
|
+
}
|
|
9990
|
+
)
|
|
9991
|
+
]
|
|
9992
|
+
}
|
|
9993
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(
|
|
9811
9994
|
"div",
|
|
9812
9995
|
{
|
|
9813
9996
|
className: "uf-text-center uf-text-xs uf-mb-3",
|
|
@@ -9817,7 +10000,7 @@ function EnterAmountView({
|
|
|
9817
10000
|
tokenChainDetails.minimum_deposit_amount_usd.toFixed(2)
|
|
9818
10001
|
]
|
|
9819
10002
|
}
|
|
9820
|
-
),
|
|
10003
|
+
)),
|
|
9821
10004
|
inputUsdNum > 0 && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(import_jsx_runtime46.Fragment, { children: inputUsdNum > maxUsdAmount ? /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
|
|
9822
10005
|
"div",
|
|
9823
10006
|
{
|
|
@@ -9832,7 +10015,44 @@ function EnterAmountView({
|
|
|
9832
10015
|
style: { color: colors2.error },
|
|
9833
10016
|
children: error
|
|
9834
10017
|
}
|
|
9835
|
-
) })
|
|
10018
|
+
) }),
|
|
10019
|
+
isCheckout && selectedToken.icon_url && /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "uf-flex uf-items-center uf-justify-center uf-gap-2 uf-py-2", children: [
|
|
10020
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "uf-relative", children: [
|
|
10021
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
|
|
10022
|
+
"img",
|
|
10023
|
+
{
|
|
10024
|
+
src: selectedToken.icon_url,
|
|
10025
|
+
alt: selectedToken.symbol,
|
|
10026
|
+
width: 20,
|
|
10027
|
+
height: 20,
|
|
10028
|
+
className: "uf-w-5 uf-h-5 uf-rounded-full"
|
|
10029
|
+
}
|
|
10030
|
+
),
|
|
10031
|
+
selectedToken.chain_icon_url && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
|
|
10032
|
+
"img",
|
|
10033
|
+
{
|
|
10034
|
+
src: selectedToken.chain_icon_url,
|
|
10035
|
+
alt: selectedToken.chain_name,
|
|
10036
|
+
width: 10,
|
|
10037
|
+
height: 10,
|
|
10038
|
+
className: "uf-w-2.5 uf-h-2.5 uf-rounded-full uf-absolute -uf-bottom-0.5 -uf-right-0.5 uf-border",
|
|
10039
|
+
style: { borderColor: colors2.background }
|
|
10040
|
+
}
|
|
10041
|
+
)
|
|
10042
|
+
] }),
|
|
10043
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(
|
|
10044
|
+
"span",
|
|
10045
|
+
{
|
|
10046
|
+
className: "uf-text-xs",
|
|
10047
|
+
style: { color: colors2.foregroundMuted, fontFamily: fonts.regular },
|
|
10048
|
+
children: [
|
|
10049
|
+
selectedToken.symbol,
|
|
10050
|
+
" on ",
|
|
10051
|
+
selectedToken.chain_name
|
|
10052
|
+
]
|
|
10053
|
+
}
|
|
10054
|
+
)
|
|
10055
|
+
] })
|
|
9836
10056
|
] }),
|
|
9837
10057
|
/* @__PURE__ */ (0, import_jsx_runtime46.jsx)("div", { className: "uf-shrink-0 uf-pt-2", children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
|
|
9838
10058
|
"button",
|
|
@@ -9860,6 +10080,18 @@ function EnterAmountView({
|
|
|
9860
10080
|
// src/components/deposits/browser-wallets/ReviewView.tsx
|
|
9861
10081
|
var import_lucide_react20 = require("lucide-react");
|
|
9862
10082
|
var import_jsx_runtime47 = require("react/jsx-runtime");
|
|
10083
|
+
var WALLET_ICONS2 = {
|
|
10084
|
+
metamask: MetamaskIcon,
|
|
10085
|
+
phantom: PhantomIcon,
|
|
10086
|
+
coinbase: CoinbaseIcon,
|
|
10087
|
+
trust: TrustIcon,
|
|
10088
|
+
rainbow: RainbowIcon,
|
|
10089
|
+
rabby: RabbyIcon,
|
|
10090
|
+
okx: OkxIcon,
|
|
10091
|
+
solflare: SolflareIcon,
|
|
10092
|
+
backpack: BackpackIcon,
|
|
10093
|
+
glow: GlowIcon
|
|
10094
|
+
};
|
|
9863
10095
|
function ReviewView({
|
|
9864
10096
|
walletInfo,
|
|
9865
10097
|
recipientAddress,
|
|
@@ -9894,30 +10126,17 @@ function ReviewView({
|
|
|
9894
10126
|
),
|
|
9895
10127
|
/* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: "uf-flex uf-min-h-0 uf-flex-1 uf-flex-col", children: [
|
|
9896
10128
|
/* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: "uf-min-h-0 uf-flex-1 uf-overflow-y-auto [scrollbar-width:none] [&::-webkit-scrollbar]:uf-hidden", children: [
|
|
9897
|
-
/* @__PURE__ */ (0, import_jsx_runtime47.
|
|
9898
|
-
|
|
9899
|
-
|
|
9900
|
-
|
|
9901
|
-
|
|
9902
|
-
|
|
9903
|
-
|
|
9904
|
-
|
|
9905
|
-
|
|
9906
|
-
|
|
9907
|
-
|
|
9908
|
-
),
|
|
9909
|
-
formattedTokenAmount && /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(
|
|
9910
|
-
"div",
|
|
9911
|
-
{
|
|
9912
|
-
className: "uf-text-sm uf-mt-2",
|
|
9913
|
-
style: { color: colors2.foregroundMuted },
|
|
9914
|
-
children: [
|
|
9915
|
-
"\u2248 ",
|
|
9916
|
-
formattedTokenAmount
|
|
9917
|
-
]
|
|
9918
|
-
}
|
|
9919
|
-
)
|
|
9920
|
-
] }),
|
|
10129
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)("div", { className: "uf-text-center", children: /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(
|
|
10130
|
+
"div",
|
|
10131
|
+
{
|
|
10132
|
+
className: "uf-text-4xl uf-font-medium",
|
|
10133
|
+
style: { color: colors2.foreground, fontFamily: fonts.medium },
|
|
10134
|
+
children: [
|
|
10135
|
+
"$",
|
|
10136
|
+
amountUsd || "0"
|
|
10137
|
+
]
|
|
10138
|
+
}
|
|
10139
|
+
) }),
|
|
9921
10140
|
/* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(
|
|
9922
10141
|
"div",
|
|
9923
10142
|
{
|
|
@@ -9934,7 +10153,31 @@ function ReviewView({
|
|
|
9934
10153
|
{
|
|
9935
10154
|
className: "uf-text-sm",
|
|
9936
10155
|
style: { color: colors2.foregroundMuted, fontFamily: fonts.regular },
|
|
9937
|
-
children: "
|
|
10156
|
+
children: "From"
|
|
10157
|
+
}
|
|
10158
|
+
),
|
|
10159
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: "uf-flex uf-items-center uf-gap-2", children: [
|
|
10160
|
+
WALLET_ICONS2[walletInfo.icon] && (() => {
|
|
10161
|
+
const Icon2 = WALLET_ICONS2[walletInfo.icon];
|
|
10162
|
+
return /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("div", { className: "uf-w-5 uf-h-5 uf-rounded-full uf-overflow-hidden uf-flex-shrink-0", children: /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(Icon2, { size: 20, variant: "color" }) });
|
|
10163
|
+
})(),
|
|
10164
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
|
|
10165
|
+
"span",
|
|
10166
|
+
{
|
|
10167
|
+
className: "uf-text-sm uf-font-medium",
|
|
10168
|
+
style: { color: colors2.foreground, fontFamily: fonts.medium },
|
|
10169
|
+
children: walletInfo.name
|
|
10170
|
+
}
|
|
10171
|
+
)
|
|
10172
|
+
] })
|
|
10173
|
+
] }),
|
|
10174
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: "uf-flex uf-justify-between uf-items-center", children: [
|
|
10175
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
|
|
10176
|
+
"span",
|
|
10177
|
+
{
|
|
10178
|
+
className: "uf-text-sm",
|
|
10179
|
+
style: { color: colors2.foregroundMuted, fontFamily: fonts.regular },
|
|
10180
|
+
children: "You send"
|
|
9938
10181
|
}
|
|
9939
10182
|
),
|
|
9940
10183
|
/* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: "uf-flex uf-items-center uf-gap-2", children: [
|
|
@@ -9946,17 +10189,12 @@ function ReviewView({
|
|
|
9946
10189
|
className: "uf-w-5 uf-h-5 uf-rounded-full"
|
|
9947
10190
|
}
|
|
9948
10191
|
),
|
|
9949
|
-
/* @__PURE__ */ (0, import_jsx_runtime47.
|
|
10192
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
|
|
9950
10193
|
"span",
|
|
9951
10194
|
{
|
|
9952
10195
|
className: "uf-text-sm uf-font-medium",
|
|
9953
10196
|
style: { color: colors2.foreground, fontFamily: fonts.medium },
|
|
9954
|
-
children:
|
|
9955
|
-
walletInfo.name,
|
|
9956
|
-
" (",
|
|
9957
|
-
truncateAddress2(walletInfo.address),
|
|
9958
|
-
")"
|
|
9959
|
-
]
|
|
10197
|
+
children: formattedTokenAmount || `$${amountUsd}`
|
|
9960
10198
|
}
|
|
9961
10199
|
)
|
|
9962
10200
|
] })
|
|
@@ -10119,7 +10357,10 @@ function ReviewView({
|
|
|
10119
10357
|
borderRadius: components.button.borderRadius,
|
|
10120
10358
|
border: `${components.button.borderWidth}px solid ${components.button.borderColor}`
|
|
10121
10359
|
},
|
|
10122
|
-
children: isConfirming ? "
|
|
10360
|
+
children: isConfirming ? /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("span", { className: "uf-flex uf-items-center uf-justify-center uf-gap-2", children: [
|
|
10361
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)(import_lucide_react20.Loader2, { className: "uf-w-4 uf-h-4 uf-animate-spin" }),
|
|
10362
|
+
"Confirming..."
|
|
10363
|
+
] }) : "Confirm Order"
|
|
10123
10364
|
}
|
|
10124
10365
|
) })
|
|
10125
10366
|
] })
|
|
@@ -10133,17 +10374,35 @@ function ReviewView({
|
|
|
10133
10374
|
var import_react17 = require("react");
|
|
10134
10375
|
var import_lucide_react21 = require("lucide-react");
|
|
10135
10376
|
var import_jsx_runtime48 = require("react/jsx-runtime");
|
|
10377
|
+
var SETTLE_FALLBACK_MS = 15e3;
|
|
10136
10378
|
function ConfirmingView({
|
|
10137
10379
|
isConfirming,
|
|
10138
10380
|
onClose,
|
|
10139
10381
|
executions = [],
|
|
10140
|
-
isPolling = false
|
|
10382
|
+
isPolling = false,
|
|
10383
|
+
onNewDeposit,
|
|
10384
|
+
onDone,
|
|
10385
|
+
paymentIntentStatus,
|
|
10386
|
+
amountReceivedUsd,
|
|
10387
|
+
amountReceivedUsdAtSubmission
|
|
10141
10388
|
}) {
|
|
10142
|
-
const { colors: colors2, fonts } = useTheme();
|
|
10389
|
+
const { colors: colors2, fonts, components } = useTheme();
|
|
10143
10390
|
const [containerEl, setContainerEl] = (0, import_react17.useState)(null);
|
|
10144
10391
|
const containerCallbackRef = (0, import_react17.useCallback)((el) => {
|
|
10145
10392
|
setContainerEl(el);
|
|
10146
10393
|
}, []);
|
|
10394
|
+
const [fallbackSettled, setFallbackSettled] = (0, import_react17.useState)(false);
|
|
10395
|
+
const hasExecution = executions.length > 0;
|
|
10396
|
+
const isCheckoutMode = paymentIntentStatus != null;
|
|
10397
|
+
const isPaymentComplete = paymentIntentStatus === "succeeded";
|
|
10398
|
+
const amountChanged = amountReceivedUsdAtSubmission != null && amountReceivedUsd != null && amountReceivedUsd !== amountReceivedUsdAtSubmission;
|
|
10399
|
+
const piSettled = !isCheckoutMode || isPaymentComplete || amountChanged || fallbackSettled;
|
|
10400
|
+
(0, import_react17.useEffect)(() => {
|
|
10401
|
+
if (!hasExecution || piSettled) return;
|
|
10402
|
+
const timeout = setTimeout(() => setFallbackSettled(true), SETTLE_FALLBACK_MS);
|
|
10403
|
+
return () => clearTimeout(timeout);
|
|
10404
|
+
}, [hasExecution, piSettled]);
|
|
10405
|
+
const showButtons = hasExecution && piSettled;
|
|
10147
10406
|
return /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(PortalContainerProvider, { value: containerEl, children: /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(
|
|
10148
10407
|
"div",
|
|
10149
10408
|
{
|
|
@@ -10156,8 +10415,8 @@ function ConfirmingView({
|
|
|
10156
10415
|
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
10157
10416
|
DepositHeader,
|
|
10158
10417
|
{
|
|
10159
|
-
title: isConfirming ? "Confirming..." : "Processing",
|
|
10160
|
-
onClose
|
|
10418
|
+
title: isConfirming ? "Confirming..." : hasExecution && isPaymentComplete ? "Payment Complete" : hasExecution ? "Deposit Received" : "Processing",
|
|
10419
|
+
onClose: isPaymentComplete && onDone ? onDone : onClose
|
|
10161
10420
|
}
|
|
10162
10421
|
),
|
|
10163
10422
|
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { className: "uf-flex uf-flex-1 uf-flex-col uf-items-center uf-justify-center uf-py-8", children: isConfirming ? /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(import_jsx_runtime48.Fragment, { children: [
|
|
@@ -10184,11 +10443,70 @@ function ConfirmingView({
|
|
|
10184
10443
|
children: "Please confirm the transaction in your wallet"
|
|
10185
10444
|
}
|
|
10186
10445
|
)
|
|
10187
|
-
] }) : /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(import_jsx_runtime48.Fragment, { children: [
|
|
10446
|
+
] }) : hasExecution ? /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(import_jsx_runtime48.Fragment, { children: [
|
|
10188
10447
|
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
10189
10448
|
import_lucide_react21.CheckCircle2,
|
|
10190
10449
|
{
|
|
10191
10450
|
className: "uf-w-12 uf-h-12 uf-mb-4",
|
|
10451
|
+
style: { color: "rgb(34, 197, 94)" }
|
|
10452
|
+
}
|
|
10453
|
+
),
|
|
10454
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
10455
|
+
"div",
|
|
10456
|
+
{
|
|
10457
|
+
className: "uf-text-lg uf-font-medium",
|
|
10458
|
+
style: { color: colors2.foreground, fontFamily: fonts.medium },
|
|
10459
|
+
children: isPaymentComplete ? "Payment Complete" : "Deposit Received"
|
|
10460
|
+
}
|
|
10461
|
+
),
|
|
10462
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
10463
|
+
"div",
|
|
10464
|
+
{
|
|
10465
|
+
className: "uf-text-sm uf-mt-2 uf-text-center uf-px-6",
|
|
10466
|
+
style: { color: colors2.foregroundMuted },
|
|
10467
|
+
children: isPaymentComplete ? "Your payment has been fulfilled." : showButtons ? "Your deposit is being processed." : "Checking payment status..."
|
|
10468
|
+
}
|
|
10469
|
+
),
|
|
10470
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { className: "uf-mt-6 uf-flex uf-flex-col uf-items-center uf-gap-3", children: !showButtons ? /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
10471
|
+
import_lucide_react21.Loader2,
|
|
10472
|
+
{
|
|
10473
|
+
className: "uf-w-5 uf-h-5 uf-animate-spin",
|
|
10474
|
+
style: { color: colors2.foregroundMuted }
|
|
10475
|
+
}
|
|
10476
|
+
) : isPaymentComplete && onDone ? /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
10477
|
+
"button",
|
|
10478
|
+
{
|
|
10479
|
+
onClick: onDone,
|
|
10480
|
+
className: "uf-w-full uf-py-3 uf-px-8 uf-text-sm uf-font-medium uf-transition-opacity hover:uf-opacity-80",
|
|
10481
|
+
style: {
|
|
10482
|
+
backgroundColor: colors2.primary,
|
|
10483
|
+
color: colors2.primaryForeground,
|
|
10484
|
+
fontFamily: fonts.medium,
|
|
10485
|
+
borderRadius: components.button.borderRadius
|
|
10486
|
+
},
|
|
10487
|
+
children: "Done"
|
|
10488
|
+
}
|
|
10489
|
+
) : onNewDeposit ? /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(
|
|
10490
|
+
"button",
|
|
10491
|
+
{
|
|
10492
|
+
onClick: onNewDeposit,
|
|
10493
|
+
className: "uf-flex uf-items-center uf-gap-2 uf-px-5 uf-py-2.5 uf-rounded-lg uf-text-sm uf-font-medium uf-transition-opacity hover:uf-opacity-80",
|
|
10494
|
+
style: {
|
|
10495
|
+
backgroundColor: colors2.primary,
|
|
10496
|
+
color: colors2.primaryForeground,
|
|
10497
|
+
fontFamily: fonts.medium
|
|
10498
|
+
},
|
|
10499
|
+
children: [
|
|
10500
|
+
"Make another deposit",
|
|
10501
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_lucide_react21.ArrowRight, { className: "uf-w-4 uf-h-4" })
|
|
10502
|
+
]
|
|
10503
|
+
}
|
|
10504
|
+
) : null })
|
|
10505
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(import_jsx_runtime48.Fragment, { children: [
|
|
10506
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
10507
|
+
import_lucide_react21.Loader2,
|
|
10508
|
+
{
|
|
10509
|
+
className: "uf-w-12 uf-h-12 uf-animate-spin uf-mb-4",
|
|
10192
10510
|
style: { color: colors2.primary }
|
|
10193
10511
|
}
|
|
10194
10512
|
),
|
|
@@ -10205,7 +10523,7 @@ function ConfirmingView({
|
|
|
10205
10523
|
{
|
|
10206
10524
|
className: "uf-text-sm uf-mt-2 uf-text-center uf-px-6",
|
|
10207
10525
|
style: { color: colors2.foregroundMuted },
|
|
10208
|
-
children: "
|
|
10526
|
+
children: "Waiting for your deposit to be detected..."
|
|
10209
10527
|
}
|
|
10210
10528
|
)
|
|
10211
10529
|
] }) }),
|
|
@@ -10232,6 +10550,7 @@ function BrowserWalletModal({
|
|
|
10232
10550
|
depositWallet,
|
|
10233
10551
|
userId,
|
|
10234
10552
|
publishableKey,
|
|
10553
|
+
clientSecret,
|
|
10235
10554
|
assetCdnUrl,
|
|
10236
10555
|
projectName,
|
|
10237
10556
|
theme = "dark",
|
|
@@ -10240,7 +10559,13 @@ function BrowserWalletModal({
|
|
|
10240
10559
|
onDepositSuccess,
|
|
10241
10560
|
onDepositError,
|
|
10242
10561
|
amountQuickSelect = "percentage",
|
|
10243
|
-
onWalletDisconnect
|
|
10562
|
+
onWalletDisconnect,
|
|
10563
|
+
prefillAmountUsd,
|
|
10564
|
+
checkoutAmountUsd,
|
|
10565
|
+
checkoutReceivedUsd,
|
|
10566
|
+
onNewDeposit,
|
|
10567
|
+
onDone,
|
|
10568
|
+
paymentIntentStatus
|
|
10244
10569
|
}) {
|
|
10245
10570
|
const { colors: colors2, fonts, components } = useTheme();
|
|
10246
10571
|
const [step, setStep] = React26.useState("select-token");
|
|
@@ -10258,6 +10583,7 @@ function BrowserWalletModal({
|
|
|
10258
10583
|
const [tokenChainDetails, setTokenChainDetails] = React26.useState(null);
|
|
10259
10584
|
const [loadingTokenDetails, setLoadingTokenDetails] = React26.useState(false);
|
|
10260
10585
|
const [showTransactionDetails, setShowTransactionDetails] = React26.useState(false);
|
|
10586
|
+
const [receivedUsdAtSubmission, setReceivedUsdAtSubmission] = React26.useState(null);
|
|
10261
10587
|
const themeClass = theme === "dark" ? "uf-dark" : "";
|
|
10262
10588
|
const chainType = depositWallet.chain_type;
|
|
10263
10589
|
const recipientAddress = depositWallet.address;
|
|
@@ -10265,15 +10591,19 @@ function BrowserWalletModal({
|
|
|
10265
10591
|
const { executions: depositExecutions, isPolling } = useDepositPolling({
|
|
10266
10592
|
userId,
|
|
10267
10593
|
publishableKey,
|
|
10594
|
+
clientSecret,
|
|
10268
10595
|
enabled: open && hasSignedTransaction,
|
|
10269
10596
|
onDepositSuccess,
|
|
10270
10597
|
onDepositError
|
|
10271
10598
|
});
|
|
10599
|
+
const prevOpenRef = React26.useRef(false);
|
|
10272
10600
|
React26.useEffect(() => {
|
|
10273
|
-
|
|
10601
|
+
const wasOpen = prevOpenRef.current;
|
|
10602
|
+
prevOpenRef.current = open;
|
|
10603
|
+
if (open && !wasOpen) {
|
|
10274
10604
|
setStep("select-token");
|
|
10275
10605
|
setSelectedBalance(null);
|
|
10276
|
-
setAmountUsd("");
|
|
10606
|
+
setAmountUsd(prefillAmountUsd ?? "");
|
|
10277
10607
|
setError(null);
|
|
10278
10608
|
setIsConfirming(false);
|
|
10279
10609
|
setTokenChainDetails(null);
|
|
@@ -10281,7 +10611,15 @@ function BrowserWalletModal({
|
|
|
10281
10611
|
setHasSignedTransaction(false);
|
|
10282
10612
|
setIsDisconnectingWallet(false);
|
|
10283
10613
|
}
|
|
10284
|
-
}, [open]);
|
|
10614
|
+
}, [open, prefillAmountUsd]);
|
|
10615
|
+
React26.useEffect(() => {
|
|
10616
|
+
if (!prefillAmountUsd || !tokenChainDetails || step !== "input-amount") return;
|
|
10617
|
+
const minDeposit = tokenChainDetails.minimum_deposit_amount_usd || 0;
|
|
10618
|
+
const currentAmount = parseFloat(amountUsd) || 0;
|
|
10619
|
+
if (currentAmount > 0 && currentAmount < minDeposit) {
|
|
10620
|
+
setAmountUsd(minDeposit.toFixed(2));
|
|
10621
|
+
}
|
|
10622
|
+
}, [tokenChainDetails, step, prefillAmountUsd]);
|
|
10285
10623
|
React26.useEffect(() => {
|
|
10286
10624
|
if (step === "review") {
|
|
10287
10625
|
setShowTransactionDetails(false);
|
|
@@ -10308,7 +10646,7 @@ function BrowserWalletModal({
|
|
|
10308
10646
|
);
|
|
10309
10647
|
if (cancelled) return;
|
|
10310
10648
|
const supportedToken = response.data.find(
|
|
10311
|
-
(
|
|
10649
|
+
(t11) => t11.symbol.toLowerCase() === token.symbol.toLowerCase()
|
|
10312
10650
|
);
|
|
10313
10651
|
if (supportedToken) {
|
|
10314
10652
|
const chainDetail = supportedToken.chains.find(
|
|
@@ -10399,7 +10737,7 @@ function BrowserWalletModal({
|
|
|
10399
10737
|
setError(null);
|
|
10400
10738
|
if (step === "input-amount") {
|
|
10401
10739
|
setStep("select-token");
|
|
10402
|
-
setAmountUsd("");
|
|
10740
|
+
setAmountUsd(prefillAmountUsd ?? "");
|
|
10403
10741
|
setTokenChainDetails(null);
|
|
10404
10742
|
} else if (step === "review") {
|
|
10405
10743
|
setStep("input-amount");
|
|
@@ -10485,7 +10823,6 @@ function BrowserWalletModal({
|
|
|
10485
10823
|
}
|
|
10486
10824
|
}
|
|
10487
10825
|
setIsConfirming(true);
|
|
10488
|
-
setStep("confirming");
|
|
10489
10826
|
setError(null);
|
|
10490
10827
|
try {
|
|
10491
10828
|
let txHash;
|
|
@@ -10503,16 +10840,17 @@ function BrowserWalletModal({
|
|
|
10503
10840
|
} else {
|
|
10504
10841
|
txHash = await sendEthereumTransaction(token, tokenAmount.toString());
|
|
10505
10842
|
}
|
|
10843
|
+
setReceivedUsdAtSubmission(checkoutReceivedUsd ?? "0");
|
|
10506
10844
|
setHasSignedTransaction(true);
|
|
10507
|
-
onSuccess?.(txHash);
|
|
10508
10845
|
setIsConfirming(false);
|
|
10846
|
+
setStep("confirming");
|
|
10847
|
+
onSuccess?.(txHash);
|
|
10509
10848
|
} catch (err) {
|
|
10510
10849
|
console.error("[BrowserWalletModal] Transaction error:", err);
|
|
10511
10850
|
const errorMessage = err instanceof Error ? err.message : "Transaction failed";
|
|
10512
10851
|
setError(errorMessage);
|
|
10513
10852
|
onError?.(err instanceof Error ? err : new Error(errorMessage));
|
|
10514
10853
|
setIsConfirming(false);
|
|
10515
|
-
setStep("review");
|
|
10516
10854
|
}
|
|
10517
10855
|
};
|
|
10518
10856
|
const sendEthereumTransaction = async (token, amountStr) => {
|
|
@@ -10761,7 +11099,9 @@ function BrowserWalletModal({
|
|
|
10761
11099
|
onBack: handleClose,
|
|
10762
11100
|
onClose: handleFullClose,
|
|
10763
11101
|
onDisconnectWallet: onWalletDisconnect ? () => void handleDisconnectFromSelectToken() : void 0,
|
|
10764
|
-
isDisconnectingWallet
|
|
11102
|
+
isDisconnectingWallet,
|
|
11103
|
+
checkoutAmountUsd,
|
|
11104
|
+
checkoutReceivedUsd
|
|
10765
11105
|
}
|
|
10766
11106
|
),
|
|
10767
11107
|
step === "input-amount" && selectedToken && selectedBalance && /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
|
|
@@ -10782,7 +11122,9 @@ function BrowserWalletModal({
|
|
|
10782
11122
|
onReview: handleReview,
|
|
10783
11123
|
onBack: handleBack,
|
|
10784
11124
|
onClose: handleFullClose,
|
|
10785
|
-
quickSelectMode: amountQuickSelect
|
|
11125
|
+
quickSelectMode: amountQuickSelect,
|
|
11126
|
+
checkoutAmountUsd,
|
|
11127
|
+
checkoutReceivedUsd
|
|
10786
11128
|
}
|
|
10787
11129
|
),
|
|
10788
11130
|
step === "review" && selectedToken && /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
|
|
@@ -10811,7 +11153,12 @@ function BrowserWalletModal({
|
|
|
10811
11153
|
isConfirming,
|
|
10812
11154
|
onClose: handleFullClose,
|
|
10813
11155
|
executions: depositExecutions,
|
|
10814
|
-
isPolling
|
|
11156
|
+
isPolling,
|
|
11157
|
+
onNewDeposit,
|
|
11158
|
+
onDone,
|
|
11159
|
+
paymentIntentStatus,
|
|
11160
|
+
amountReceivedUsd: checkoutReceivedUsd,
|
|
11161
|
+
amountReceivedUsdAtSubmission: receivedUsdAtSubmission
|
|
10815
11162
|
}
|
|
10816
11163
|
)
|
|
10817
11164
|
] })
|
|
@@ -10825,7 +11172,7 @@ function BrowserWalletModal({
|
|
|
10825
11172
|
var React27 = __toESM(require("react"));
|
|
10826
11173
|
var import_lucide_react22 = require("lucide-react");
|
|
10827
11174
|
var import_jsx_runtime50 = require("react/jsx-runtime");
|
|
10828
|
-
var
|
|
11175
|
+
var WALLET_ICONS3 = {
|
|
10829
11176
|
metamask: MetamaskIcon,
|
|
10830
11177
|
phantom: PhantomIcon,
|
|
10831
11178
|
coinbase: CoinbaseIcon,
|
|
@@ -11264,10 +11611,10 @@ function WalletSelectionModal({
|
|
|
11264
11611
|
},
|
|
11265
11612
|
children: [
|
|
11266
11613
|
/* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("div", { className: "uf-flex uf-items-center uf-gap-3", children: [
|
|
11267
|
-
|
|
11614
|
+
WALLET_ICONS3[wallet.id] ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
|
|
11268
11615
|
WalletIconWithNetwork,
|
|
11269
11616
|
{
|
|
11270
|
-
WalletIcon:
|
|
11617
|
+
WalletIcon: WALLET_ICONS3[wallet.id],
|
|
11271
11618
|
networks: wallet.networks,
|
|
11272
11619
|
size: 40,
|
|
11273
11620
|
className: "uf-rounded-lg"
|
|
@@ -11338,10 +11685,10 @@ function WalletSelectionModal({
|
|
|
11338
11685
|
style: { minHeight: WALLET_STEP_BODY_MIN_HEIGHT },
|
|
11339
11686
|
children: [
|
|
11340
11687
|
/* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("div", { className: "uf-flex uf-flex-col uf-items-center uf-pb-4 uf-shrink-0", children: [
|
|
11341
|
-
/* @__PURE__ */ (0, import_jsx_runtime50.jsx)("div", { className: "uf-mb-2", children:
|
|
11688
|
+
/* @__PURE__ */ (0, import_jsx_runtime50.jsx)("div", { className: "uf-mb-2", children: WALLET_ICONS3[selectedWallet.id] ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
|
|
11342
11689
|
WalletIconWithNetwork,
|
|
11343
11690
|
{
|
|
11344
|
-
WalletIcon:
|
|
11691
|
+
WalletIcon: WALLET_ICONS3[selectedWallet.id],
|
|
11345
11692
|
networks: selectedWallet.networks,
|
|
11346
11693
|
size: 48,
|
|
11347
11694
|
className: "uf-rounded-lg"
|
|
@@ -11624,7 +11971,7 @@ function DepositModal({
|
|
|
11624
11971
|
if (view !== "tracker" || !userId) return;
|
|
11625
11972
|
const fetchExecutions = async () => {
|
|
11626
11973
|
try {
|
|
11627
|
-
const response = await (0, import_core23.queryExecutions)(userId, publishableKey);
|
|
11974
|
+
const response = await (0, import_core23.queryExecutions)(userId, publishableKey, import_core23.ActionType.Deposit);
|
|
11628
11975
|
const sorted = [...response.data].sort((a, b) => {
|
|
11629
11976
|
const timeA = a.created_at ? new Date(a.created_at).getTime() : 0;
|
|
11630
11977
|
const timeB = b.created_at ? new Date(b.created_at).getTime() : 0;
|
|
@@ -12143,10 +12490,2711 @@ function DepositModal({
|
|
|
12143
12490
|
}
|
|
12144
12491
|
) });
|
|
12145
12492
|
}
|
|
12493
|
+
|
|
12494
|
+
// src/components/checkout/CheckoutModal.tsx
|
|
12495
|
+
var import_react19 = require("react");
|
|
12496
|
+
var import_lucide_react24 = require("lucide-react");
|
|
12497
|
+
|
|
12498
|
+
// src/hooks/use-payment-intent.ts
|
|
12499
|
+
var import_react_query9 = require("@tanstack/react-query");
|
|
12500
|
+
var import_core24 = require("@unifold/core");
|
|
12501
|
+
function usePaymentIntent(params) {
|
|
12502
|
+
const {
|
|
12503
|
+
clientSecret,
|
|
12504
|
+
publishableKey,
|
|
12505
|
+
enabled = true,
|
|
12506
|
+
pollingInterval = 5e3
|
|
12507
|
+
} = params;
|
|
12508
|
+
return (0, import_react_query9.useQuery)({
|
|
12509
|
+
queryKey: ["unifold", "paymentIntent", clientSecret, publishableKey],
|
|
12510
|
+
queryFn: () => (0, import_core24.retrievePaymentIntent)(clientSecret, publishableKey),
|
|
12511
|
+
enabled: enabled && !!clientSecret && !!publishableKey,
|
|
12512
|
+
staleTime: 0,
|
|
12513
|
+
refetchInterval: pollingInterval || false,
|
|
12514
|
+
refetchOnWindowFocus: true,
|
|
12515
|
+
retry: 3,
|
|
12516
|
+
retryDelay: (attempt) => Math.min(1e3 * 2 ** attempt, 1e4)
|
|
12517
|
+
});
|
|
12518
|
+
}
|
|
12519
|
+
|
|
12520
|
+
// src/hooks/use-deposit-quote.ts
|
|
12521
|
+
var import_react_query10 = require("@tanstack/react-query");
|
|
12522
|
+
var import_core25 = require("@unifold/core");
|
|
12523
|
+
function useDepositQuote(params) {
|
|
12524
|
+
const {
|
|
12525
|
+
publishableKey,
|
|
12526
|
+
sourceChainType,
|
|
12527
|
+
sourceChainId,
|
|
12528
|
+
sourceTokenAddress,
|
|
12529
|
+
destinationAmount,
|
|
12530
|
+
destinationChainType,
|
|
12531
|
+
destinationChainId,
|
|
12532
|
+
destinationTokenAddress,
|
|
12533
|
+
enabled = true
|
|
12534
|
+
} = params;
|
|
12535
|
+
const request = {
|
|
12536
|
+
source_chain_type: sourceChainType,
|
|
12537
|
+
source_chain_id: sourceChainId,
|
|
12538
|
+
source_token_address: sourceTokenAddress,
|
|
12539
|
+
destination_amount: destinationAmount,
|
|
12540
|
+
destination_chain_type: destinationChainType,
|
|
12541
|
+
destination_chain_id: destinationChainId,
|
|
12542
|
+
destination_token_address: destinationTokenAddress
|
|
12543
|
+
};
|
|
12544
|
+
return (0, import_react_query10.useQuery)({
|
|
12545
|
+
queryKey: [
|
|
12546
|
+
"unifold",
|
|
12547
|
+
"depositQuote",
|
|
12548
|
+
sourceChainType,
|
|
12549
|
+
sourceChainId,
|
|
12550
|
+
sourceTokenAddress,
|
|
12551
|
+
destinationAmount,
|
|
12552
|
+
destinationChainType,
|
|
12553
|
+
destinationChainId,
|
|
12554
|
+
destinationTokenAddress,
|
|
12555
|
+
publishableKey
|
|
12556
|
+
],
|
|
12557
|
+
queryFn: () => (0, import_core25.getDepositQuote)(request, publishableKey),
|
|
12558
|
+
enabled: enabled && !!publishableKey && !!sourceChainType && !!sourceChainId && !!sourceTokenAddress && !!destinationAmount && destinationAmount !== "0" && !!destinationChainType && !!destinationChainId && !!destinationTokenAddress,
|
|
12559
|
+
staleTime: 6e4,
|
|
12560
|
+
gcTime: 5 * 6e4,
|
|
12561
|
+
refetchOnWindowFocus: false,
|
|
12562
|
+
retry: 2,
|
|
12563
|
+
retryDelay: (attempt) => Math.min(1e3 * 2 ** attempt, 5e3)
|
|
12564
|
+
});
|
|
12565
|
+
}
|
|
12566
|
+
|
|
12567
|
+
// src/components/checkout/CheckoutModal.tsx
|
|
12568
|
+
var import_jsx_runtime52 = require("react/jsx-runtime");
|
|
12569
|
+
function mapDepositAddressesToWallets(depositAddresses, pi) {
|
|
12570
|
+
return depositAddresses.map((da, idx) => ({
|
|
12571
|
+
id: da.id,
|
|
12572
|
+
chain_type: da.chain_type,
|
|
12573
|
+
address_type: da.address_type,
|
|
12574
|
+
address: da.address,
|
|
12575
|
+
destination_chain_type: pi.destination_chain_type,
|
|
12576
|
+
destination_chain_id: pi.destination_chain_id,
|
|
12577
|
+
destination_token_address: pi.destination_token_address,
|
|
12578
|
+
recipient_address: pi.recipient_address,
|
|
12579
|
+
is_primary: idx === 0
|
|
12580
|
+
}));
|
|
12581
|
+
}
|
|
12582
|
+
function SkeletonButton2() {
|
|
12583
|
+
return /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("div", { className: "uf-w-full uf-bg-secondary uf-rounded-xl uf-p-3 uf-flex uf-items-center uf-justify-between uf-animate-pulse", children: [
|
|
12584
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("div", { className: "uf-flex uf-items-center uf-gap-3", children: [
|
|
12585
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsx)("div", { className: "uf-bg-muted uf-rounded-lg uf-w-9 uf-h-9" }),
|
|
12586
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("div", { className: "uf-space-y-1.5", children: [
|
|
12587
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsx)("div", { className: "uf-h-3.5 uf-w-24 uf-bg-muted uf-rounded" }),
|
|
12588
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsx)("div", { className: "uf-h-3 uf-w-32 uf-bg-muted uf-rounded" })
|
|
12589
|
+
] })
|
|
12590
|
+
] }),
|
|
12591
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsx)("div", { className: "uf-flex uf-items-center uf-gap-2", children: /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(import_lucide_react24.ChevronRight, { className: "uf-w-4 uf-h-4 uf-text-muted" }) })
|
|
12592
|
+
] });
|
|
12593
|
+
}
|
|
12594
|
+
function CheckoutModal({
|
|
12595
|
+
open,
|
|
12596
|
+
onOpenChange,
|
|
12597
|
+
clientSecret,
|
|
12598
|
+
publishableKey,
|
|
12599
|
+
modalTitle,
|
|
12600
|
+
enableConnectWallet = false,
|
|
12601
|
+
theme = "dark",
|
|
12602
|
+
onCheckoutSuccess,
|
|
12603
|
+
onCheckoutError
|
|
12604
|
+
}) {
|
|
12605
|
+
const { colors: colors2, fonts, components } = useTheme();
|
|
12606
|
+
const [view, setView] = (0, import_react19.useState)("main");
|
|
12607
|
+
const resetViewTimeoutRef = (0, import_react19.useRef)(
|
|
12608
|
+
null
|
|
12609
|
+
);
|
|
12610
|
+
const [browserWalletModalOpen, setBrowserWalletModalOpen] = (0, import_react19.useState)(false);
|
|
12611
|
+
const [browserWalletInfo, setBrowserWalletInfo] = (0, import_react19.useState)(null);
|
|
12612
|
+
const [walletSelectionModalOpen, setWalletSelectionModalOpen] = (0, import_react19.useState)(false);
|
|
12613
|
+
const [browserWalletChainType, setBrowserWalletChainType] = (0, import_react19.useState)(() => getStoredWalletChainType());
|
|
12614
|
+
const isMobileView = useIsMobileViewport();
|
|
12615
|
+
const [resolvedTheme, setResolvedTheme] = (0, import_react19.useState)(
|
|
12616
|
+
theme === "auto" ? "dark" : theme
|
|
12617
|
+
);
|
|
12618
|
+
(0, import_react19.useEffect)(() => {
|
|
12619
|
+
if (theme === "auto") {
|
|
12620
|
+
const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
|
|
12621
|
+
setResolvedTheme(mediaQuery.matches ? "dark" : "light");
|
|
12622
|
+
const handler = (e) => {
|
|
12623
|
+
setResolvedTheme(e.matches ? "dark" : "light");
|
|
12624
|
+
};
|
|
12625
|
+
mediaQuery.addEventListener("change", handler);
|
|
12626
|
+
return () => mediaQuery.removeEventListener("change", handler);
|
|
12627
|
+
} else {
|
|
12628
|
+
setResolvedTheme(theme);
|
|
12629
|
+
}
|
|
12630
|
+
}, [theme]);
|
|
12631
|
+
const themeClass = resolvedTheme === "dark" ? "uf-dark" : "";
|
|
12632
|
+
const {
|
|
12633
|
+
data: paymentIntent,
|
|
12634
|
+
isLoading: piLoading,
|
|
12635
|
+
error: piError
|
|
12636
|
+
} = usePaymentIntent({
|
|
12637
|
+
clientSecret,
|
|
12638
|
+
publishableKey,
|
|
12639
|
+
enabled: open && !!clientSecret,
|
|
12640
|
+
pollingInterval: 5e3
|
|
12641
|
+
});
|
|
12642
|
+
const { projectConfig } = useProjectConfig({
|
|
12643
|
+
publishableKey,
|
|
12644
|
+
enabled: open
|
|
12645
|
+
});
|
|
12646
|
+
const prevStatusRef = (0, import_react19.useRef)(null);
|
|
12647
|
+
(0, import_react19.useEffect)(() => {
|
|
12648
|
+
if (!paymentIntent) return;
|
|
12649
|
+
const prev = prevStatusRef.current;
|
|
12650
|
+
prevStatusRef.current = paymentIntent.status;
|
|
12651
|
+
if (prev && prev !== paymentIntent.status && paymentIntent.status === "succeeded") {
|
|
12652
|
+
if (!browserWalletModalOpen) {
|
|
12653
|
+
setView("main");
|
|
12654
|
+
}
|
|
12655
|
+
onCheckoutSuccess?.({
|
|
12656
|
+
paymentIntentId: paymentIntent.id,
|
|
12657
|
+
status: paymentIntent.status
|
|
12658
|
+
});
|
|
12659
|
+
}
|
|
12660
|
+
}, [paymentIntent, onCheckoutSuccess, browserWalletModalOpen]);
|
|
12661
|
+
const wallets = (0, import_react19.useMemo)(() => {
|
|
12662
|
+
if (!paymentIntent) return [];
|
|
12663
|
+
return mapDepositAddressesToWallets(
|
|
12664
|
+
paymentIntent.deposit_addresses,
|
|
12665
|
+
paymentIntent
|
|
12666
|
+
);
|
|
12667
|
+
}, [paymentIntent]);
|
|
12668
|
+
const formatCryptoAmount = (0, import_react19.useMemo)(() => {
|
|
12669
|
+
if (!paymentIntent) return (_) => "";
|
|
12670
|
+
const decimals = paymentIntent.destination_token_decimals ?? 6;
|
|
12671
|
+
const symbol = paymentIntent.currency.toUpperCase();
|
|
12672
|
+
return (baseUnits) => {
|
|
12673
|
+
const num = Number(baseUnits) / 10 ** decimals;
|
|
12674
|
+
const formatted = num % 1 === 0 ? num.toFixed(0) : num.toFixed(2);
|
|
12675
|
+
return `${formatted} ${symbol}`;
|
|
12676
|
+
};
|
|
12677
|
+
}, [paymentIntent]);
|
|
12678
|
+
const remainingAmountUsd = (0, import_react19.useMemo)(() => {
|
|
12679
|
+
if (!paymentIntent) return void 0;
|
|
12680
|
+
const total = parseFloat(paymentIntent.amount_usd);
|
|
12681
|
+
const received = parseFloat(paymentIntent.amount_received_usd);
|
|
12682
|
+
if (isNaN(total) || isNaN(received)) return paymentIntent.amount_usd;
|
|
12683
|
+
const remaining = total - received;
|
|
12684
|
+
return remaining > 0 ? remaining.toFixed(2) : "0.00";
|
|
12685
|
+
}, [paymentIntent]);
|
|
12686
|
+
const remainingCrypto = (0, import_react19.useMemo)(() => {
|
|
12687
|
+
if (!paymentIntent) return void 0;
|
|
12688
|
+
const total = BigInt(paymentIntent.amount);
|
|
12689
|
+
const received = BigInt(paymentIntent.amount_received);
|
|
12690
|
+
const remaining = total - received;
|
|
12691
|
+
return remaining > 0n ? remaining.toString() : "0";
|
|
12692
|
+
}, [paymentIntent]);
|
|
12693
|
+
const [selectedSource, setSelectedSource] = (0, import_react19.useState)(null);
|
|
12694
|
+
const quoteDestinationAmount = (0, import_react19.useMemo)(() => {
|
|
12695
|
+
if (!paymentIntent || !selectedSource) return "0";
|
|
12696
|
+
const remaining = BigInt(paymentIntent.amount) - BigInt(paymentIntent.amount_received);
|
|
12697
|
+
const totalBaseUnits = Number(paymentIntent.amount);
|
|
12698
|
+
const totalUsd = parseFloat(paymentIntent.amount_usd);
|
|
12699
|
+
const baseUnitsPerUsd = totalUsd > 0 ? totalBaseUnits / totalUsd : 0;
|
|
12700
|
+
const minUsd = Math.max(selectedSource.minimumDepositAmountUsd, 3);
|
|
12701
|
+
const minDepositBaseUnits = BigInt(Math.ceil(minUsd * baseUnitsPerUsd));
|
|
12702
|
+
const effective = remaining > minDepositBaseUnits ? remaining : minDepositBaseUnits;
|
|
12703
|
+
return effective > 0n ? effective.toString() : "0";
|
|
12704
|
+
}, [paymentIntent, selectedSource]);
|
|
12705
|
+
const { data: sourceQuote } = useDepositQuote({
|
|
12706
|
+
publishableKey,
|
|
12707
|
+
sourceChainType: selectedSource?.chainType ?? "",
|
|
12708
|
+
sourceChainId: selectedSource?.chainId ?? "",
|
|
12709
|
+
sourceTokenAddress: selectedSource?.tokenAddress ?? "",
|
|
12710
|
+
destinationAmount: quoteDestinationAmount,
|
|
12711
|
+
destinationChainType: paymentIntent?.destination_chain_type ?? "",
|
|
12712
|
+
destinationChainId: paymentIntent?.destination_chain_id ?? "",
|
|
12713
|
+
destinationTokenAddress: paymentIntent?.destination_token_address ?? "",
|
|
12714
|
+
enabled: open && view === "transfer" && !!paymentIntent && !!selectedSource && quoteDestinationAmount !== "0"
|
|
12715
|
+
});
|
|
12716
|
+
const handleBrowserWalletClick = (0, import_react19.useCallback)(
|
|
12717
|
+
(walletInfo) => {
|
|
12718
|
+
const walletChainType = walletInfo.type === "phantom-solana" || walletInfo.type === "solflare" || walletInfo.type === "backpack" || walletInfo.type === "glow" ? "solana" : "ethereum";
|
|
12719
|
+
setStoredWalletChainType(walletChainType);
|
|
12720
|
+
setBrowserWalletChainType(walletChainType);
|
|
12721
|
+
const matchingDepositWallet = wallets.find(
|
|
12722
|
+
(w) => w.chain_type === walletChainType
|
|
12723
|
+
);
|
|
12724
|
+
if (!matchingDepositWallet) {
|
|
12725
|
+
onCheckoutError?.({
|
|
12726
|
+
message: `Unable to pay from ${walletChainType}. Please try a different wallet.`,
|
|
12727
|
+
code: "NO_DEPOSIT_ADDRESS"
|
|
12728
|
+
});
|
|
12729
|
+
return;
|
|
12730
|
+
}
|
|
12731
|
+
setBrowserWalletInfo({
|
|
12732
|
+
...walletInfo,
|
|
12733
|
+
depositWallet: matchingDepositWallet
|
|
12734
|
+
});
|
|
12735
|
+
setBrowserWalletModalOpen(true);
|
|
12736
|
+
},
|
|
12737
|
+
[wallets, onCheckoutError]
|
|
12738
|
+
);
|
|
12739
|
+
const handleWalletConnectClick = (0, import_react19.useCallback)(() => {
|
|
12740
|
+
setWalletSelectionModalOpen(true);
|
|
12741
|
+
}, []);
|
|
12742
|
+
const handleWalletConnected = (0, import_react19.useCallback)(
|
|
12743
|
+
(walletInfo) => {
|
|
12744
|
+
const walletChainType = walletInfo.type === "phantom-solana" || walletInfo.type === "solflare" || walletInfo.type === "backpack" || walletInfo.type === "glow" ? "solana" : "ethereum";
|
|
12745
|
+
setStoredWalletChainType(walletChainType);
|
|
12746
|
+
setBrowserWalletChainType(walletChainType);
|
|
12747
|
+
const matchingDepositWallet = wallets.find(
|
|
12748
|
+
(w) => w.chain_type === walletChainType
|
|
12749
|
+
);
|
|
12750
|
+
if (!matchingDepositWallet) {
|
|
12751
|
+
onCheckoutError?.({
|
|
12752
|
+
message: `Unable to pay from ${walletChainType}. Please try a different wallet.`,
|
|
12753
|
+
code: "NO_DEPOSIT_ADDRESS"
|
|
12754
|
+
});
|
|
12755
|
+
setWalletSelectionModalOpen(false);
|
|
12756
|
+
return;
|
|
12757
|
+
}
|
|
12758
|
+
setBrowserWalletInfo({
|
|
12759
|
+
...walletInfo,
|
|
12760
|
+
depositWallet: matchingDepositWallet
|
|
12761
|
+
});
|
|
12762
|
+
setWalletSelectionModalOpen(false);
|
|
12763
|
+
setBrowserWalletModalOpen(true);
|
|
12764
|
+
},
|
|
12765
|
+
[wallets, onCheckoutError]
|
|
12766
|
+
);
|
|
12767
|
+
const handleWalletDisconnect = (0, import_react19.useCallback)(() => {
|
|
12768
|
+
setUserDisconnectedWallet(true);
|
|
12769
|
+
clearStoredWalletChainType();
|
|
12770
|
+
setBrowserWalletChainType(void 0);
|
|
12771
|
+
setBrowserWalletInfo(null);
|
|
12772
|
+
setBrowserWalletModalOpen(false);
|
|
12773
|
+
}, []);
|
|
12774
|
+
const handleClose = (0, import_react19.useCallback)(() => {
|
|
12775
|
+
onOpenChange(false);
|
|
12776
|
+
if (resetViewTimeoutRef.current) {
|
|
12777
|
+
clearTimeout(resetViewTimeoutRef.current);
|
|
12778
|
+
}
|
|
12779
|
+
resetViewTimeoutRef.current = setTimeout(() => {
|
|
12780
|
+
setView("main");
|
|
12781
|
+
setBrowserWalletInfo(null);
|
|
12782
|
+
resetViewTimeoutRef.current = null;
|
|
12783
|
+
}, 200);
|
|
12784
|
+
}, [onOpenChange]);
|
|
12785
|
+
(0, import_react19.useLayoutEffect)(() => {
|
|
12786
|
+
if (!open) return;
|
|
12787
|
+
if (resetViewTimeoutRef.current) {
|
|
12788
|
+
clearTimeout(resetViewTimeoutRef.current);
|
|
12789
|
+
resetViewTimeoutRef.current = null;
|
|
12790
|
+
}
|
|
12791
|
+
setView("main");
|
|
12792
|
+
setBrowserWalletInfo(null);
|
|
12793
|
+
}, [open]);
|
|
12794
|
+
(0, import_react19.useEffect)(
|
|
12795
|
+
() => () => {
|
|
12796
|
+
if (resetViewTimeoutRef.current) {
|
|
12797
|
+
clearTimeout(resetViewTimeoutRef.current);
|
|
12798
|
+
}
|
|
12799
|
+
},
|
|
12800
|
+
[]
|
|
12801
|
+
);
|
|
12802
|
+
const handleBack = (0, import_react19.useCallback)(() => {
|
|
12803
|
+
setView("main");
|
|
12804
|
+
}, []);
|
|
12805
|
+
const poweredByFooter = /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("div", { className: "uf-pt-3", children: /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
|
|
12806
|
+
PoweredByUnifold,
|
|
12807
|
+
{
|
|
12808
|
+
color: colors2.foregroundMuted,
|
|
12809
|
+
className: "uf-flex uf-justify-center uf-shrink-0"
|
|
12810
|
+
}
|
|
12811
|
+
) });
|
|
12812
|
+
const progressSection = paymentIntent ? (() => {
|
|
12813
|
+
const received = parseFloat(paymentIntent.amount_received_usd);
|
|
12814
|
+
const total = parseFloat(paymentIntent.amount_usd);
|
|
12815
|
+
const remaining = Math.max(total - received, 0);
|
|
12816
|
+
const pct = total > 0 ? Math.min(received / total * 100, 100) : 0;
|
|
12817
|
+
const hasPartial = received > 0;
|
|
12818
|
+
const amountStr = paymentIntent.amount_usd;
|
|
12819
|
+
const dynamicFontSize = `${Math.max(3.75 - amountStr.length * 0.15, 2)}rem`;
|
|
12820
|
+
return /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("div", { className: "uf-text-center uf-py-2 uf-space-y-1", children: [
|
|
12821
|
+
paymentIntent.description && /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
|
|
12822
|
+
"div",
|
|
12823
|
+
{
|
|
12824
|
+
className: "uf-text-xs",
|
|
12825
|
+
style: {
|
|
12826
|
+
color: colors2.foregroundMuted,
|
|
12827
|
+
fontFamily: fonts.regular
|
|
12828
|
+
},
|
|
12829
|
+
children: paymentIntent.description
|
|
12830
|
+
}
|
|
12831
|
+
),
|
|
12832
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("div", { className: "uf-flex uf-items-center uf-justify-center", children: [
|
|
12833
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
|
|
12834
|
+
"span",
|
|
12835
|
+
{
|
|
12836
|
+
className: "uf-mr-1",
|
|
12837
|
+
style: {
|
|
12838
|
+
fontSize: `calc(${dynamicFontSize} * 0.6)`,
|
|
12839
|
+
color: colors2.foregroundMuted,
|
|
12840
|
+
fontFamily: fonts.regular
|
|
12841
|
+
},
|
|
12842
|
+
children: "$"
|
|
12843
|
+
}
|
|
12844
|
+
),
|
|
12845
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
|
|
12846
|
+
"span",
|
|
12847
|
+
{
|
|
12848
|
+
style: {
|
|
12849
|
+
fontSize: dynamicFontSize,
|
|
12850
|
+
color: colors2.foreground,
|
|
12851
|
+
fontFamily: fonts.regular,
|
|
12852
|
+
lineHeight: 1.1
|
|
12853
|
+
},
|
|
12854
|
+
children: amountStr
|
|
12855
|
+
}
|
|
12856
|
+
)
|
|
12857
|
+
] }),
|
|
12858
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
|
|
12859
|
+
"div",
|
|
12860
|
+
{
|
|
12861
|
+
className: "uf-text-xs",
|
|
12862
|
+
style: {
|
|
12863
|
+
color: colors2.foregroundMuted,
|
|
12864
|
+
fontFamily: fonts.regular
|
|
12865
|
+
},
|
|
12866
|
+
children: paymentIntent.currency.toUpperCase()
|
|
12867
|
+
}
|
|
12868
|
+
),
|
|
12869
|
+
hasPartial && /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("div", { className: "uf-pt-2 uf-space-y-1.5", children: [
|
|
12870
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
|
|
12871
|
+
"div",
|
|
12872
|
+
{
|
|
12873
|
+
className: "uf-w-full uf-h-1.5 uf-rounded-full uf-overflow-hidden",
|
|
12874
|
+
style: { backgroundColor: colors2.border },
|
|
12875
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
|
|
12876
|
+
"div",
|
|
12877
|
+
{
|
|
12878
|
+
className: "uf-h-full uf-rounded-full uf-transition-all uf-duration-500",
|
|
12879
|
+
style: {
|
|
12880
|
+
width: `${pct}%`,
|
|
12881
|
+
backgroundColor: paymentIntent.status === "succeeded" ? "rgb(34, 197, 94)" : colors2.primary
|
|
12882
|
+
}
|
|
12883
|
+
}
|
|
12884
|
+
)
|
|
12885
|
+
}
|
|
12886
|
+
),
|
|
12887
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsxs)(
|
|
12888
|
+
"div",
|
|
12889
|
+
{
|
|
12890
|
+
className: "uf-text-xs",
|
|
12891
|
+
style: {
|
|
12892
|
+
color: colors2.foregroundMuted,
|
|
12893
|
+
fontFamily: fonts.regular
|
|
12894
|
+
},
|
|
12895
|
+
children: [
|
|
12896
|
+
"$",
|
|
12897
|
+
paymentIntent.amount_received_usd,
|
|
12898
|
+
" / $",
|
|
12899
|
+
amountStr,
|
|
12900
|
+
" received",
|
|
12901
|
+
remaining > 0 && paymentIntent.status !== "succeeded" && /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("span", { style: { color: colors2.foreground, fontFamily: fonts.medium }, children: [
|
|
12902
|
+
" ",
|
|
12903
|
+
"\xB7 $",
|
|
12904
|
+
remaining.toFixed(2),
|
|
12905
|
+
" remaining"
|
|
12906
|
+
] })
|
|
12907
|
+
]
|
|
12908
|
+
}
|
|
12909
|
+
)
|
|
12910
|
+
] }),
|
|
12911
|
+
paymentIntent.status !== "requires_payment" && /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("div", { className: "uf-pt-1", children: /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
|
|
12912
|
+
"span",
|
|
12913
|
+
{
|
|
12914
|
+
className: "uf-text-xs uf-font-medium uf-px-2.5 uf-py-1 uf-rounded-full uf-inline-block",
|
|
12915
|
+
style: {
|
|
12916
|
+
backgroundColor: paymentIntent.status === "succeeded" ? "rgba(34, 197, 94, 0.15)" : paymentIntent.status === "processing" ? "rgba(59, 130, 246, 0.15)" : "rgba(239, 68, 68, 0.15)",
|
|
12917
|
+
color: paymentIntent.status === "succeeded" ? "rgb(34, 197, 94)" : paymentIntent.status === "processing" ? "rgb(59, 130, 246)" : "rgb(239, 68, 68)",
|
|
12918
|
+
fontFamily: fonts.medium
|
|
12919
|
+
},
|
|
12920
|
+
children: paymentIntent.status === "succeeded" ? "Payment Complete" : paymentIntent.status === "processing" ? "Partial Payment Received" : paymentIntent.status === "canceled" ? "Canceled" : paymentIntent.status === "expired" ? "Expired" : paymentIntent.status
|
|
12921
|
+
}
|
|
12922
|
+
) })
|
|
12923
|
+
] });
|
|
12924
|
+
})() : null;
|
|
12925
|
+
return /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(PortalContainerProvider, { value: null, children: /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)(Dialog, { open, onOpenChange: handleClose, modal: true, children: [
|
|
12926
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
|
|
12927
|
+
DialogContent,
|
|
12928
|
+
{
|
|
12929
|
+
className: `sm:uf-max-w-[400px] uf-border-secondary uf-text-foreground uf-gap-0 [&>button]:uf-hidden uf-p-0 uf-overflow-visible ${view === "main" ? "!uf-top-auto !uf-h-auto !uf-max-h-[60vh] sm:!uf-max-h-none sm:!uf-top-[50%]" : "!uf-top-0 !uf-h-full sm:!uf-h-auto sm:!uf-top-[50%]"} ${themeClass}`,
|
|
12930
|
+
style: { backgroundColor: colors2.background },
|
|
12931
|
+
onPointerDownOutside: (e) => e.preventDefault(),
|
|
12932
|
+
onInteractOutside: (e) => e.preventDefault(),
|
|
12933
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(ThemeStyleInjector, { children: view === "main" ? /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)(import_jsx_runtime52.Fragment, { children: [
|
|
12934
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
|
|
12935
|
+
DepositHeader,
|
|
12936
|
+
{
|
|
12937
|
+
title: modalTitle || "Checkout",
|
|
12938
|
+
showClose: true,
|
|
12939
|
+
onClose: handleClose
|
|
12940
|
+
}
|
|
12941
|
+
),
|
|
12942
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("div", { className: "uf-flex uf-flex-col uf-gap-1.5", children: [
|
|
12943
|
+
piLoading ? /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("div", { className: "uf-space-y-3", children: [
|
|
12944
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
|
|
12945
|
+
"div",
|
|
12946
|
+
{
|
|
12947
|
+
className: "uf-rounded-xl uf-p-4 uf-animate-pulse",
|
|
12948
|
+
style: {
|
|
12949
|
+
backgroundColor: components.card.backgroundColor,
|
|
12950
|
+
borderRadius: components.card.borderRadius,
|
|
12951
|
+
border: `${components.card.borderWidth}px solid ${components.card.borderColor}`
|
|
12952
|
+
},
|
|
12953
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("div", { className: "uf-flex uf-flex-col uf-items-center uf-gap-2", children: [
|
|
12954
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
|
|
12955
|
+
"div",
|
|
12956
|
+
{
|
|
12957
|
+
className: "uf-h-8 uf-w-24 uf-rounded",
|
|
12958
|
+
style: {
|
|
12959
|
+
backgroundColor: components.card.borderColor
|
|
12960
|
+
}
|
|
12961
|
+
}
|
|
12962
|
+
),
|
|
12963
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
|
|
12964
|
+
"div",
|
|
12965
|
+
{
|
|
12966
|
+
className: "uf-h-4 uf-w-16 uf-rounded",
|
|
12967
|
+
style: {
|
|
12968
|
+
backgroundColor: components.card.borderColor
|
|
12969
|
+
}
|
|
12970
|
+
}
|
|
12971
|
+
)
|
|
12972
|
+
] })
|
|
12973
|
+
}
|
|
12974
|
+
),
|
|
12975
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsx)(SkeletonButton2, {}),
|
|
12976
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsx)(SkeletonButton2, {})
|
|
12977
|
+
] }) : piError ? /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("div", { className: "uf-flex uf-flex-col uf-items-center uf-justify-center uf-py-8 uf-px-4 uf-text-center", children: [
|
|
12978
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsx)("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__ */ (0, import_jsx_runtime52.jsx)(import_lucide_react24.AlertTriangle, { className: "uf-w-8 uf-h-8 uf-text-muted-foreground" }) }),
|
|
12979
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
|
|
12980
|
+
"h3",
|
|
12981
|
+
{
|
|
12982
|
+
className: "uf-text-lg uf-font-semibold uf-mb-2",
|
|
12983
|
+
style: {
|
|
12984
|
+
color: colors2.foreground,
|
|
12985
|
+
fontFamily: fonts.semibold
|
|
12986
|
+
},
|
|
12987
|
+
children: "Unable to Load Checkout"
|
|
12988
|
+
}
|
|
12989
|
+
),
|
|
12990
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
|
|
12991
|
+
"p",
|
|
12992
|
+
{
|
|
12993
|
+
className: "uf-text-sm uf-max-w-[280px]",
|
|
12994
|
+
style: {
|
|
12995
|
+
color: colors2.foregroundMuted,
|
|
12996
|
+
fontFamily: fonts.regular
|
|
12997
|
+
},
|
|
12998
|
+
children: piError instanceof Error ? piError.message : "Something went wrong. Please try again."
|
|
12999
|
+
}
|
|
13000
|
+
)
|
|
13001
|
+
] }) : paymentIntent ? /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("div", { className: "uf-space-y-3", children: [
|
|
13002
|
+
progressSection,
|
|
13003
|
+
(paymentIntent.status === "requires_payment" || paymentIntent.status === "processing") && /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)(import_jsx_runtime52.Fragment, { children: [
|
|
13004
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
|
|
13005
|
+
TransferCryptoButton,
|
|
13006
|
+
{
|
|
13007
|
+
onClick: () => setView("transfer"),
|
|
13008
|
+
title: "Transfer Crypto",
|
|
13009
|
+
subtitle: "Send from any wallet or exchange",
|
|
13010
|
+
featuredTokens: projectConfig?.transfer_crypto.networks
|
|
13011
|
+
}
|
|
13012
|
+
),
|
|
13013
|
+
enableConnectWallet && !isMobileView && /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
|
|
13014
|
+
BrowserWalletButton,
|
|
13015
|
+
{
|
|
13016
|
+
onClick: handleBrowserWalletClick,
|
|
13017
|
+
onConnectClick: handleWalletConnectClick,
|
|
13018
|
+
onDisconnect: handleWalletDisconnect,
|
|
13019
|
+
chainType: browserWalletChainType,
|
|
13020
|
+
publishableKey
|
|
13021
|
+
}
|
|
13022
|
+
)
|
|
13023
|
+
] })
|
|
13024
|
+
] }) : null,
|
|
13025
|
+
poweredByFooter
|
|
13026
|
+
] })
|
|
13027
|
+
] }) : view === "transfer" ? /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)(import_jsx_runtime52.Fragment, { children: [
|
|
13028
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
|
|
13029
|
+
DepositHeader,
|
|
13030
|
+
{
|
|
13031
|
+
title: `Pay $${remainingAmountUsd ?? paymentIntent?.amount_usd ?? ""}`,
|
|
13032
|
+
showBack: true,
|
|
13033
|
+
onBack: handleBack,
|
|
13034
|
+
onClose: handleClose
|
|
13035
|
+
}
|
|
13036
|
+
),
|
|
13037
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("div", { className: "uf-flex uf-flex-col uf-gap-1.5", children: [
|
|
13038
|
+
paymentIntent ? /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)(import_jsx_runtime52.Fragment, { children: [
|
|
13039
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsxs)(
|
|
13040
|
+
"div",
|
|
13041
|
+
{
|
|
13042
|
+
className: "uf-rounded-lg uf-px-3 uf-py-2 uf-flex uf-items-center uf-justify-between",
|
|
13043
|
+
style: {
|
|
13044
|
+
backgroundColor: components.card.backgroundColor,
|
|
13045
|
+
border: `${components.card.borderWidth}px solid ${components.card.borderColor}`,
|
|
13046
|
+
borderRadius: components.card.borderRadius
|
|
13047
|
+
},
|
|
13048
|
+
children: [
|
|
13049
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
|
|
13050
|
+
"span",
|
|
13051
|
+
{
|
|
13052
|
+
className: "uf-text-xs",
|
|
13053
|
+
style: {
|
|
13054
|
+
color: colors2.foregroundMuted,
|
|
13055
|
+
fontFamily: fonts.regular
|
|
13056
|
+
},
|
|
13057
|
+
children: parseFloat(paymentIntent.amount_received_usd) > 0 ? `$${paymentIntent.amount_received_usd} / $${paymentIntent.amount_usd} received` : "Amount due"
|
|
13058
|
+
}
|
|
13059
|
+
),
|
|
13060
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsxs)(
|
|
13061
|
+
"span",
|
|
13062
|
+
{
|
|
13063
|
+
className: "uf-text-sm uf-font-semibold",
|
|
13064
|
+
style: {
|
|
13065
|
+
color: colors2.foreground,
|
|
13066
|
+
fontFamily: fonts.semibold
|
|
13067
|
+
},
|
|
13068
|
+
children: [
|
|
13069
|
+
formatCryptoAmount(remainingCrypto ?? paymentIntent.amount),
|
|
13070
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsxs)(
|
|
13071
|
+
"span",
|
|
13072
|
+
{
|
|
13073
|
+
className: "uf-text-xs uf-font-normal uf-ml-1",
|
|
13074
|
+
style: { color: colors2.foregroundMuted },
|
|
13075
|
+
children: [
|
|
13076
|
+
"($",
|
|
13077
|
+
remainingAmountUsd ?? paymentIntent.amount_usd,
|
|
13078
|
+
")"
|
|
13079
|
+
]
|
|
13080
|
+
}
|
|
13081
|
+
)
|
|
13082
|
+
]
|
|
13083
|
+
}
|
|
13084
|
+
)
|
|
13085
|
+
]
|
|
13086
|
+
}
|
|
13087
|
+
),
|
|
13088
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
|
|
13089
|
+
TransferCryptoSingleInput,
|
|
13090
|
+
{
|
|
13091
|
+
userId: paymentIntent.user_id || "",
|
|
13092
|
+
publishableKey,
|
|
13093
|
+
clientSecret,
|
|
13094
|
+
recipientAddress: paymentIntent.recipient_address,
|
|
13095
|
+
destinationChainType: paymentIntent.destination_chain_type,
|
|
13096
|
+
destinationChainId: paymentIntent.destination_chain_id,
|
|
13097
|
+
destinationTokenAddress: paymentIntent.destination_token_address,
|
|
13098
|
+
depositConfirmationMode: "auto_ui",
|
|
13099
|
+
wallets,
|
|
13100
|
+
onSourceTokenChange: setSelectedSource,
|
|
13101
|
+
checkoutQuote: sourceQuote ? {
|
|
13102
|
+
sourceAmount: sourceQuote.source_amount,
|
|
13103
|
+
sourceTokenDecimals: sourceQuote.source_token_decimals,
|
|
13104
|
+
sourceTokenSymbol: sourceQuote.source_token_symbol,
|
|
13105
|
+
sourceAmountUsd: sourceQuote.source_amount_usd
|
|
13106
|
+
} : null
|
|
13107
|
+
}
|
|
13108
|
+
)
|
|
13109
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(SkeletonButton2, {}),
|
|
13110
|
+
poweredByFooter
|
|
13111
|
+
] })
|
|
13112
|
+
] }) : null })
|
|
13113
|
+
}
|
|
13114
|
+
),
|
|
13115
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
|
|
13116
|
+
WalletSelectionModal,
|
|
13117
|
+
{
|
|
13118
|
+
open: walletSelectionModalOpen,
|
|
13119
|
+
onOpenChange: setWalletSelectionModalOpen,
|
|
13120
|
+
onWalletConnected: handleWalletConnected,
|
|
13121
|
+
onClose: () => setWalletSelectionModalOpen(false),
|
|
13122
|
+
theme: resolvedTheme
|
|
13123
|
+
}
|
|
13124
|
+
),
|
|
13125
|
+
browserWalletInfo && browserWalletInfo.depositWallet && /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
|
|
13126
|
+
BrowserWalletModal,
|
|
13127
|
+
{
|
|
13128
|
+
open: browserWalletModalOpen,
|
|
13129
|
+
onOpenChange: setBrowserWalletModalOpen,
|
|
13130
|
+
onFullClose: handleClose,
|
|
13131
|
+
walletInfo: browserWalletInfo,
|
|
13132
|
+
depositWallet: browserWalletInfo.depositWallet,
|
|
13133
|
+
userId: paymentIntent?.user_id || "",
|
|
13134
|
+
publishableKey,
|
|
13135
|
+
clientSecret,
|
|
13136
|
+
theme: resolvedTheme,
|
|
13137
|
+
prefillAmountUsd: remainingAmountUsd,
|
|
13138
|
+
checkoutAmountUsd: paymentIntent?.amount_usd,
|
|
13139
|
+
checkoutReceivedUsd: paymentIntent?.amount_received_usd,
|
|
13140
|
+
onSuccess: (txHash) => {
|
|
13141
|
+
onCheckoutSuccess?.({
|
|
13142
|
+
paymentIntentId: paymentIntent?.id || "",
|
|
13143
|
+
status: "processing"
|
|
13144
|
+
});
|
|
13145
|
+
},
|
|
13146
|
+
onError: (error) => {
|
|
13147
|
+
onCheckoutError?.({
|
|
13148
|
+
message: error.message,
|
|
13149
|
+
error
|
|
13150
|
+
});
|
|
13151
|
+
},
|
|
13152
|
+
onWalletDisconnect: handleWalletDisconnect,
|
|
13153
|
+
onNewDeposit: () => {
|
|
13154
|
+
setBrowserWalletModalOpen(false);
|
|
13155
|
+
setView("main");
|
|
13156
|
+
},
|
|
13157
|
+
onDone: () => {
|
|
13158
|
+
setBrowserWalletModalOpen(false);
|
|
13159
|
+
setView("main");
|
|
13160
|
+
},
|
|
13161
|
+
paymentIntentStatus: paymentIntent?.status
|
|
13162
|
+
}
|
|
13163
|
+
)
|
|
13164
|
+
] }) });
|
|
13165
|
+
}
|
|
13166
|
+
|
|
13167
|
+
// src/components/withdrawals/WithdrawModal.tsx
|
|
13168
|
+
var import_react23 = require("react");
|
|
13169
|
+
var import_lucide_react27 = require("lucide-react");
|
|
13170
|
+
|
|
13171
|
+
// src/hooks/use-supported-destination-tokens.ts
|
|
13172
|
+
var import_react_query11 = require("@tanstack/react-query");
|
|
13173
|
+
var import_core26 = require("@unifold/core");
|
|
13174
|
+
function useSupportedDestinationTokens(publishableKey, enabled = true) {
|
|
13175
|
+
return (0, import_react_query11.useQuery)({
|
|
13176
|
+
queryKey: ["unifold", "supportedDestinationTokens", publishableKey],
|
|
13177
|
+
queryFn: () => (0, import_core26.getSupportedDestinationTokens)(publishableKey),
|
|
13178
|
+
staleTime: 1e3 * 60 * 5,
|
|
13179
|
+
gcTime: 1e3 * 60 * 30,
|
|
13180
|
+
refetchOnMount: false,
|
|
13181
|
+
refetchOnWindowFocus: false,
|
|
13182
|
+
enabled
|
|
13183
|
+
});
|
|
13184
|
+
}
|
|
13185
|
+
|
|
13186
|
+
// src/hooks/use-source-token-validation.ts
|
|
13187
|
+
var import_react_query12 = require("@tanstack/react-query");
|
|
13188
|
+
var import_core27 = require("@unifold/core");
|
|
13189
|
+
function useSourceTokenValidation(params) {
|
|
13190
|
+
const {
|
|
13191
|
+
sourceChainType,
|
|
13192
|
+
sourceChainId,
|
|
13193
|
+
sourceTokenAddress,
|
|
13194
|
+
sourceTokenSymbol,
|
|
13195
|
+
publishableKey,
|
|
13196
|
+
enabled = true
|
|
13197
|
+
} = params;
|
|
13198
|
+
const hasParams = !!sourceChainType && !!sourceChainId && !!sourceTokenAddress;
|
|
13199
|
+
return (0, import_react_query12.useQuery)({
|
|
13200
|
+
queryKey: [
|
|
13201
|
+
"unifold",
|
|
13202
|
+
"sourceTokenValidation",
|
|
13203
|
+
sourceChainType ?? null,
|
|
13204
|
+
sourceChainId ?? null,
|
|
13205
|
+
sourceTokenAddress ?? null,
|
|
13206
|
+
publishableKey
|
|
13207
|
+
],
|
|
13208
|
+
queryFn: async () => {
|
|
13209
|
+
const res = await (0, import_core27.getSupportedDepositTokens)(publishableKey);
|
|
13210
|
+
let matchedMinUsd = null;
|
|
13211
|
+
let matchedProcessingTime = null;
|
|
13212
|
+
let matchedSlippage = null;
|
|
13213
|
+
let matchedPriceImpact = null;
|
|
13214
|
+
const found = res.data.some(
|
|
13215
|
+
(token) => token.chains.some((chain) => {
|
|
13216
|
+
const match = chain.chain_type === sourceChainType && chain.chain_id === sourceChainId && chain.token_address.toLowerCase() === sourceTokenAddress.toLowerCase();
|
|
13217
|
+
if (match) {
|
|
13218
|
+
matchedMinUsd = chain.minimum_deposit_amount_usd;
|
|
13219
|
+
matchedProcessingTime = chain.estimated_processing_time;
|
|
13220
|
+
matchedSlippage = chain.max_slippage_percent;
|
|
13221
|
+
matchedPriceImpact = chain.estimated_price_impact_percent;
|
|
13222
|
+
}
|
|
13223
|
+
return match;
|
|
13224
|
+
})
|
|
13225
|
+
);
|
|
13226
|
+
return {
|
|
13227
|
+
isSupported: found,
|
|
13228
|
+
minimumAmountUsd: matchedMinUsd,
|
|
13229
|
+
estimatedProcessingTime: matchedProcessingTime,
|
|
13230
|
+
maxSlippagePercent: matchedSlippage,
|
|
13231
|
+
priceImpactPercent: matchedPriceImpact,
|
|
13232
|
+
errorMessage: found ? null : `${sourceTokenSymbol || "Source token"} is not a supported withdrawal token. Supported tokens include USDC, USDT, and other stablecoins.`
|
|
13233
|
+
};
|
|
13234
|
+
},
|
|
13235
|
+
enabled: enabled && hasParams,
|
|
13236
|
+
staleTime: 1e3 * 60 * 5,
|
|
13237
|
+
gcTime: 1e3 * 60 * 30,
|
|
13238
|
+
refetchOnMount: false,
|
|
13239
|
+
refetchOnWindowFocus: false
|
|
13240
|
+
});
|
|
13241
|
+
}
|
|
13242
|
+
|
|
13243
|
+
// src/hooks/use-address-balance.ts
|
|
13244
|
+
var import_react_query13 = require("@tanstack/react-query");
|
|
13245
|
+
var import_core28 = require("@unifold/core");
|
|
13246
|
+
function useAddressBalance(params) {
|
|
13247
|
+
const {
|
|
13248
|
+
address,
|
|
13249
|
+
chainType,
|
|
13250
|
+
chainId,
|
|
13251
|
+
tokenAddress,
|
|
13252
|
+
publishableKey,
|
|
13253
|
+
enabled = true
|
|
13254
|
+
} = params;
|
|
13255
|
+
const hasParams = !!address && !!chainType && !!chainId && !!tokenAddress;
|
|
13256
|
+
return (0, import_react_query13.useQuery)({
|
|
13257
|
+
queryKey: [
|
|
13258
|
+
"unifold",
|
|
13259
|
+
"addressBalance",
|
|
13260
|
+
address ?? null,
|
|
13261
|
+
chainType ?? null,
|
|
13262
|
+
chainId ?? null,
|
|
13263
|
+
tokenAddress ?? null,
|
|
13264
|
+
publishableKey
|
|
13265
|
+
],
|
|
13266
|
+
queryFn: async () => {
|
|
13267
|
+
const res = await (0, import_core28.getAddressBalance)(
|
|
13268
|
+
address,
|
|
13269
|
+
chainType,
|
|
13270
|
+
chainId,
|
|
13271
|
+
tokenAddress,
|
|
13272
|
+
publishableKey
|
|
13273
|
+
);
|
|
13274
|
+
if (res.balance) {
|
|
13275
|
+
const decimals = res.balance.token?.decimals ?? 6;
|
|
13276
|
+
const symbol = res.balance.token?.symbol ?? "";
|
|
13277
|
+
const baseUnit = res.balance.amount;
|
|
13278
|
+
const raw = BigInt(baseUnit);
|
|
13279
|
+
const divisor = BigInt(10 ** decimals);
|
|
13280
|
+
const whole = raw / divisor;
|
|
13281
|
+
const frac = raw % divisor;
|
|
13282
|
+
const fracStr = frac.toString().padStart(decimals, "0").replace(/0+$/, "");
|
|
13283
|
+
const balanceHuman = fracStr ? `${whole}.${fracStr}` : whole.toString();
|
|
13284
|
+
return {
|
|
13285
|
+
balanceBaseUnit: baseUnit,
|
|
13286
|
+
balanceHuman,
|
|
13287
|
+
balanceUsd: res.balance.amount_usd,
|
|
13288
|
+
exchangeRate: res.balance.exchange_rate,
|
|
13289
|
+
decimals,
|
|
13290
|
+
symbol
|
|
13291
|
+
};
|
|
13292
|
+
}
|
|
13293
|
+
return { balanceBaseUnit: "0", balanceHuman: "0", balanceUsd: "0", exchangeRate: null, decimals: 6, symbol: "" };
|
|
13294
|
+
},
|
|
13295
|
+
enabled: enabled && hasParams,
|
|
13296
|
+
staleTime: 1e3 * 30,
|
|
13297
|
+
gcTime: 1e3 * 60 * 5,
|
|
13298
|
+
refetchInterval: 1e3 * 30,
|
|
13299
|
+
refetchOnMount: "always",
|
|
13300
|
+
refetchOnWindowFocus: false
|
|
13301
|
+
});
|
|
13302
|
+
}
|
|
13303
|
+
|
|
13304
|
+
// src/hooks/use-executions.ts
|
|
13305
|
+
var import_react_query14 = require("@tanstack/react-query");
|
|
13306
|
+
var import_core29 = require("@unifold/core");
|
|
13307
|
+
function useExecutions(userId, publishableKey, options) {
|
|
13308
|
+
const actionType = options?.actionType ?? import_core29.ActionType.Deposit;
|
|
13309
|
+
return (0, import_react_query14.useQuery)({
|
|
13310
|
+
queryKey: ["unifold", "executions", actionType, userId, publishableKey],
|
|
13311
|
+
queryFn: () => (0, import_core29.queryExecutions)(userId, publishableKey, actionType),
|
|
13312
|
+
enabled: (options?.enabled ?? true) && !!userId,
|
|
13313
|
+
refetchInterval: options?.refetchInterval ?? 3e3,
|
|
13314
|
+
staleTime: 0,
|
|
13315
|
+
gcTime: 1e3 * 60 * 5,
|
|
13316
|
+
refetchOnWindowFocus: false
|
|
13317
|
+
});
|
|
13318
|
+
}
|
|
13319
|
+
|
|
13320
|
+
// src/hooks/use-withdraw-polling.ts
|
|
13321
|
+
var import_react20 = require("react");
|
|
13322
|
+
var import_core30 = require("@unifold/core");
|
|
13323
|
+
var POLL_INTERVAL_MS2 = 2500;
|
|
13324
|
+
var POLL_ENDPOINT_INTERVAL_MS2 = 3e3;
|
|
13325
|
+
var CUTOFF_BUFFER_MS2 = 6e4;
|
|
13326
|
+
function useWithdrawPolling({
|
|
13327
|
+
userId,
|
|
13328
|
+
publishableKey,
|
|
13329
|
+
depositWalletId,
|
|
13330
|
+
enabled = false,
|
|
13331
|
+
onWithdrawSuccess,
|
|
13332
|
+
onWithdrawError
|
|
13333
|
+
}) {
|
|
13334
|
+
const [executions, setExecutions] = (0, import_react20.useState)([]);
|
|
13335
|
+
const [isPolling, setIsPolling] = (0, import_react20.useState)(false);
|
|
13336
|
+
const enabledAtRef = (0, import_react20.useRef)(/* @__PURE__ */ new Date());
|
|
13337
|
+
const trackedRef = (0, import_react20.useRef)(/* @__PURE__ */ new Map());
|
|
13338
|
+
const prevEnabledRef = (0, import_react20.useRef)(false);
|
|
13339
|
+
const onSuccessRef = (0, import_react20.useRef)(onWithdrawSuccess);
|
|
13340
|
+
const onErrorRef = (0, import_react20.useRef)(onWithdrawError);
|
|
13341
|
+
(0, import_react20.useEffect)(() => {
|
|
13342
|
+
onSuccessRef.current = onWithdrawSuccess;
|
|
13343
|
+
}, [onWithdrawSuccess]);
|
|
13344
|
+
(0, import_react20.useEffect)(() => {
|
|
13345
|
+
onErrorRef.current = onWithdrawError;
|
|
13346
|
+
}, [onWithdrawError]);
|
|
13347
|
+
(0, import_react20.useEffect)(() => {
|
|
13348
|
+
if (enabled && !prevEnabledRef.current) {
|
|
13349
|
+
enabledAtRef.current = /* @__PURE__ */ new Date();
|
|
13350
|
+
trackedRef.current.clear();
|
|
13351
|
+
}
|
|
13352
|
+
if (!enabled) {
|
|
13353
|
+
trackedRef.current.clear();
|
|
13354
|
+
}
|
|
13355
|
+
prevEnabledRef.current = enabled;
|
|
13356
|
+
}, [enabled]);
|
|
13357
|
+
(0, import_react20.useEffect)(() => {
|
|
13358
|
+
if (!userId || !enabled) return;
|
|
13359
|
+
const enabledAt = enabledAtRef.current;
|
|
13360
|
+
const poll = async () => {
|
|
13361
|
+
try {
|
|
13362
|
+
const response = await (0, import_core30.queryExecutions)(userId, publishableKey, import_core30.ActionType.Withdraw);
|
|
13363
|
+
const cutoff = new Date(enabledAt.getTime() - CUTOFF_BUFFER_MS2);
|
|
13364
|
+
const sorted = [...response.data].sort((a, b) => {
|
|
13365
|
+
const tA = a.created_at ? new Date(a.created_at).getTime() : 0;
|
|
13366
|
+
const tB = b.created_at ? new Date(b.created_at).getTime() : 0;
|
|
13367
|
+
return tB - tA;
|
|
13368
|
+
});
|
|
13369
|
+
const inProgress = [import_core30.ExecutionStatus.PENDING, import_core30.ExecutionStatus.WAITING, import_core30.ExecutionStatus.DELAYED];
|
|
13370
|
+
const terminal = [import_core30.ExecutionStatus.SUCCEEDED, import_core30.ExecutionStatus.FAILED];
|
|
13371
|
+
let target = null;
|
|
13372
|
+
for (const ex of sorted) {
|
|
13373
|
+
const t11 = ex.created_at ? new Date(ex.created_at) : null;
|
|
13374
|
+
if (!t11 || t11 < cutoff) continue;
|
|
13375
|
+
const prev = trackedRef.current.get(ex.id);
|
|
13376
|
+
if (!prev) {
|
|
13377
|
+
target = ex;
|
|
13378
|
+
break;
|
|
13379
|
+
}
|
|
13380
|
+
if (inProgress.includes(prev) && terminal.includes(ex.status)) {
|
|
13381
|
+
target = ex;
|
|
13382
|
+
break;
|
|
13383
|
+
}
|
|
13384
|
+
}
|
|
13385
|
+
if (target) {
|
|
13386
|
+
const ex = target;
|
|
13387
|
+
const exTime = ex.created_at ? new Date(ex.created_at) : null;
|
|
13388
|
+
if (!exTime || exTime < enabledAtRef.current) return;
|
|
13389
|
+
const prev = trackedRef.current.get(ex.id);
|
|
13390
|
+
trackedRef.current.set(ex.id, ex.status);
|
|
13391
|
+
setExecutions((list) => {
|
|
13392
|
+
const idx = list.findIndex((e) => e.id === ex.id);
|
|
13393
|
+
if (idx >= 0) {
|
|
13394
|
+
const u = [...list];
|
|
13395
|
+
u[idx] = ex;
|
|
13396
|
+
return u;
|
|
13397
|
+
}
|
|
13398
|
+
return [...list, ex];
|
|
13399
|
+
});
|
|
13400
|
+
if (ex.status === import_core30.ExecutionStatus.SUCCEEDED && (!prev || inProgress.includes(prev))) {
|
|
13401
|
+
onSuccessRef.current?.({ message: "Withdrawal completed successfully", executionId: ex.id, transaction: ex });
|
|
13402
|
+
} else if (ex.status === import_core30.ExecutionStatus.FAILED && prev !== import_core30.ExecutionStatus.FAILED) {
|
|
13403
|
+
onErrorRef.current?.({ message: "Withdrawal failed", code: "WITHDRAW_FAILED", error: ex });
|
|
13404
|
+
}
|
|
13405
|
+
}
|
|
13406
|
+
} catch (error) {
|
|
13407
|
+
console.error("Failed to fetch withdraw executions:", error);
|
|
13408
|
+
onErrorRef.current?.({ message: "Failed to fetch withdrawal status", code: "POLLING_ERROR", error });
|
|
13409
|
+
}
|
|
13410
|
+
};
|
|
13411
|
+
void poll();
|
|
13412
|
+
const interval = setInterval(poll, POLL_INTERVAL_MS2);
|
|
13413
|
+
setIsPolling(true);
|
|
13414
|
+
return () => {
|
|
13415
|
+
clearInterval(interval);
|
|
13416
|
+
setIsPolling(false);
|
|
13417
|
+
};
|
|
13418
|
+
}, [userId, publishableKey, enabled]);
|
|
13419
|
+
(0, import_react20.useEffect)(() => {
|
|
13420
|
+
if (!enabled || !depositWalletId) return;
|
|
13421
|
+
const trigger = async () => {
|
|
13422
|
+
try {
|
|
13423
|
+
await (0, import_core30.pollDirectExecutions)({ deposit_wallet_id: depositWalletId }, publishableKey);
|
|
13424
|
+
} catch {
|
|
13425
|
+
}
|
|
13426
|
+
};
|
|
13427
|
+
trigger();
|
|
13428
|
+
const interval = setInterval(trigger, POLL_ENDPOINT_INTERVAL_MS2);
|
|
13429
|
+
return () => clearInterval(interval);
|
|
13430
|
+
}, [enabled, depositWalletId, publishableKey]);
|
|
13431
|
+
return { executions, isPolling };
|
|
13432
|
+
}
|
|
13433
|
+
|
|
13434
|
+
// src/components/withdrawals/WithdrawDoubleInput.tsx
|
|
13435
|
+
var import_jsx_runtime53 = require("react/jsx-runtime");
|
|
13436
|
+
var t7 = i18n.withdrawModal;
|
|
13437
|
+
var getChainKey4 = (chainId, chainType) => `${chainType}:${chainId}`;
|
|
13438
|
+
function WithdrawDoubleInput({
|
|
13439
|
+
tokens,
|
|
13440
|
+
selectedTokenSymbol,
|
|
13441
|
+
selectedChainKey,
|
|
13442
|
+
onTokenChange,
|
|
13443
|
+
onChainChange,
|
|
13444
|
+
isLoading = false
|
|
13445
|
+
}) {
|
|
13446
|
+
const { fonts, components } = useTheme();
|
|
13447
|
+
const isDarkMode = useTheme().themeClass.includes("uf-dark");
|
|
13448
|
+
const selectedToken = selectedTokenSymbol ? tokens.find((t11) => t11.symbol === selectedTokenSymbol) : void 0;
|
|
13449
|
+
const availableChainsForToken = selectedToken?.chains || [];
|
|
13450
|
+
const renderTokenItem = (tokenData) => /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", { className: "uf-flex uf-items-center uf-gap-2", children: [
|
|
13451
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
|
|
13452
|
+
"img",
|
|
13453
|
+
{
|
|
13454
|
+
src: tokenData.icon_url,
|
|
13455
|
+
alt: tokenData.symbol,
|
|
13456
|
+
width: 20,
|
|
13457
|
+
height: 20,
|
|
13458
|
+
loading: "lazy",
|
|
13459
|
+
className: "uf-rounded-full uf-flex-shrink-0"
|
|
13460
|
+
}
|
|
13461
|
+
),
|
|
13462
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)("span", { className: "uf-text-xs uf-font-normal", children: tokenData.symbol })
|
|
13463
|
+
] });
|
|
13464
|
+
const renderChainItem = (chainData) => /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", { className: "uf-flex uf-items-center uf-gap-2", children: [
|
|
13465
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
|
|
13466
|
+
"img",
|
|
13467
|
+
{
|
|
13468
|
+
src: chainData.icon_url,
|
|
13469
|
+
alt: chainData.chain_name,
|
|
13470
|
+
width: 20,
|
|
13471
|
+
height: 20,
|
|
13472
|
+
loading: "lazy",
|
|
13473
|
+
className: "uf-rounded-full uf-flex-shrink-0"
|
|
13474
|
+
}
|
|
13475
|
+
),
|
|
13476
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)("span", { className: "uf-text-xs uf-font-normal", children: chainData.chain_name })
|
|
13477
|
+
] });
|
|
13478
|
+
const currentChainData = selectedChainKey ? availableChainsForToken.find(
|
|
13479
|
+
(c) => getChainKey4(c.chain_id, c.chain_type) === selectedChainKey
|
|
13480
|
+
) : void 0;
|
|
13481
|
+
return /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", { className: "uf-grid uf-grid-cols-2 uf-gap-2.5", children: [
|
|
13482
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", { children: [
|
|
13483
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
|
|
13484
|
+
"div",
|
|
13485
|
+
{
|
|
13486
|
+
className: "uf-text-xs uf-mb-2 uf-flex uf-items-center uf-gap-1",
|
|
13487
|
+
style: { color: components.card.labelColor },
|
|
13488
|
+
children: t7.receiveToken
|
|
13489
|
+
}
|
|
13490
|
+
),
|
|
13491
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(
|
|
13492
|
+
Select,
|
|
13493
|
+
{
|
|
13494
|
+
value: selectedTokenSymbol ?? "",
|
|
13495
|
+
onValueChange: onTokenChange,
|
|
13496
|
+
disabled: isLoading || tokens.length === 0,
|
|
13497
|
+
children: [
|
|
13498
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
|
|
13499
|
+
SelectTrigger,
|
|
13500
|
+
{
|
|
13501
|
+
className: "uf-h-10 hover:uf-opacity-90 uf-text-foreground disabled:uf-opacity-50",
|
|
13502
|
+
style: {
|
|
13503
|
+
backgroundColor: components.card.backgroundColor,
|
|
13504
|
+
border: `${components.card.borderWidth}px solid ${components.card.borderColor}`
|
|
13505
|
+
},
|
|
13506
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(SelectValue, { children: isLoading || !selectedTokenSymbol ? /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("span", { className: "uf-text-xs uf-font-light uf-text-muted-foreground", children: t7.loading }) : selectedToken ? renderTokenItem(selectedToken) : /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("span", { className: "uf-text-xs uf-font-normal", children: selectedTokenSymbol }) })
|
|
13507
|
+
}
|
|
13508
|
+
),
|
|
13509
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
|
|
13510
|
+
SelectContent,
|
|
13511
|
+
{
|
|
13512
|
+
className: "uf-bg-secondary uf-border uf-text-foreground uf-max-h-[300px]",
|
|
13513
|
+
style: {
|
|
13514
|
+
border: `1px solid ${isDarkMode ? "rgba(255,255,255,0.15)" : "rgba(0,0,0,0.15)"}`,
|
|
13515
|
+
...fonts.regular ? { "--uf-font-family": fonts.regular } : {}
|
|
13516
|
+
},
|
|
13517
|
+
children: tokens.map((tokenData) => /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
|
|
13518
|
+
SelectItem,
|
|
13519
|
+
{
|
|
13520
|
+
value: tokenData.symbol,
|
|
13521
|
+
className: "focus:uf-bg-accent focus:uf-text-foreground",
|
|
13522
|
+
children: renderTokenItem(tokenData)
|
|
13523
|
+
},
|
|
13524
|
+
tokenData.symbol
|
|
13525
|
+
))
|
|
13526
|
+
}
|
|
13527
|
+
)
|
|
13528
|
+
]
|
|
13529
|
+
}
|
|
13530
|
+
)
|
|
13531
|
+
] }),
|
|
13532
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", { children: [
|
|
13533
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
|
|
13534
|
+
"div",
|
|
13535
|
+
{
|
|
13536
|
+
className: "uf-text-xs uf-mb-2 uf-flex uf-items-center uf-gap-1",
|
|
13537
|
+
style: { color: components.card.labelColor },
|
|
13538
|
+
children: t7.receiveChain
|
|
13539
|
+
}
|
|
13540
|
+
),
|
|
13541
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(
|
|
13542
|
+
Select,
|
|
13543
|
+
{
|
|
13544
|
+
value: selectedChainKey ?? "",
|
|
13545
|
+
onValueChange: onChainChange,
|
|
13546
|
+
disabled: isLoading || availableChainsForToken.length === 0,
|
|
13547
|
+
children: [
|
|
13548
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
|
|
13549
|
+
SelectTrigger,
|
|
13550
|
+
{
|
|
13551
|
+
className: "uf-h-10 hover:uf-opacity-90 uf-text-foreground disabled:uf-opacity-50",
|
|
13552
|
+
style: {
|
|
13553
|
+
backgroundColor: components.card.backgroundColor,
|
|
13554
|
+
border: `${components.card.borderWidth}px solid ${components.card.borderColor}`
|
|
13555
|
+
},
|
|
13556
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(SelectValue, { children: isLoading || !selectedChainKey ? /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("span", { className: "uf-text-xs uf-font-light uf-text-muted-foreground", children: t7.loading }) : currentChainData ? renderChainItem(currentChainData) : /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("span", { className: "uf-text-xs uf-font-normal", children: selectedChainKey }) })
|
|
13557
|
+
}
|
|
13558
|
+
),
|
|
13559
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
|
|
13560
|
+
SelectContent,
|
|
13561
|
+
{
|
|
13562
|
+
align: "end",
|
|
13563
|
+
className: "uf-bg-secondary uf-border uf-text-foreground uf-max-h-[300px] uf-min-w-[200px]",
|
|
13564
|
+
style: {
|
|
13565
|
+
border: `1px solid ${isDarkMode ? "rgba(255,255,255,0.15)" : "rgba(0,0,0,0.15)"}`,
|
|
13566
|
+
...fonts.regular ? { "--uf-font-family": fonts.regular } : {}
|
|
13567
|
+
},
|
|
13568
|
+
children: availableChainsForToken.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("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) => {
|
|
13569
|
+
const chainKey = getChainKey4(chainData.chain_id, chainData.chain_type);
|
|
13570
|
+
return /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
|
|
13571
|
+
SelectItem,
|
|
13572
|
+
{
|
|
13573
|
+
value: chainKey,
|
|
13574
|
+
className: "focus:uf-bg-accent focus:uf-text-foreground",
|
|
13575
|
+
children: renderChainItem(chainData)
|
|
13576
|
+
},
|
|
13577
|
+
chainKey
|
|
13578
|
+
);
|
|
13579
|
+
})
|
|
13580
|
+
}
|
|
13581
|
+
)
|
|
13582
|
+
]
|
|
13583
|
+
}
|
|
13584
|
+
)
|
|
13585
|
+
] })
|
|
13586
|
+
] });
|
|
13587
|
+
}
|
|
13588
|
+
|
|
13589
|
+
// src/components/withdrawals/WithdrawForm.tsx
|
|
13590
|
+
var import_react21 = require("react");
|
|
13591
|
+
var import_lucide_react25 = require("lucide-react");
|
|
13592
|
+
|
|
13593
|
+
// src/hooks/use-verify-recipient-address.ts
|
|
13594
|
+
var import_react_query15 = require("@tanstack/react-query");
|
|
13595
|
+
var import_core31 = require("@unifold/core");
|
|
13596
|
+
function useVerifyRecipientAddress(params) {
|
|
13597
|
+
const {
|
|
13598
|
+
chainType,
|
|
13599
|
+
chainId,
|
|
13600
|
+
tokenAddress,
|
|
13601
|
+
recipientAddress,
|
|
13602
|
+
publishableKey,
|
|
13603
|
+
enabled = true
|
|
13604
|
+
} = params;
|
|
13605
|
+
const trimmedAddress = recipientAddress?.trim() || "";
|
|
13606
|
+
const hasAllParams = !!chainType && !!chainId && !!tokenAddress && trimmedAddress.length > 0;
|
|
13607
|
+
return (0, import_react_query15.useQuery)({
|
|
13608
|
+
queryKey: [
|
|
13609
|
+
"unifold",
|
|
13610
|
+
"verifyRecipientAddress",
|
|
13611
|
+
chainType ?? null,
|
|
13612
|
+
chainId ?? null,
|
|
13613
|
+
tokenAddress ?? null,
|
|
13614
|
+
trimmedAddress,
|
|
13615
|
+
publishableKey
|
|
13616
|
+
],
|
|
13617
|
+
queryFn: () => (0, import_core31.verifyRecipientAddress)(
|
|
13618
|
+
{
|
|
13619
|
+
chain_type: chainType,
|
|
13620
|
+
chain_id: chainId,
|
|
13621
|
+
token_address: tokenAddress,
|
|
13622
|
+
recipient_address: trimmedAddress
|
|
13623
|
+
},
|
|
13624
|
+
publishableKey
|
|
13625
|
+
),
|
|
13626
|
+
enabled: enabled && hasAllParams,
|
|
13627
|
+
staleTime: 1e3 * 60 * 5,
|
|
13628
|
+
gcTime: 1e3 * 60 * 30,
|
|
13629
|
+
retry: 1,
|
|
13630
|
+
refetchOnMount: false,
|
|
13631
|
+
refetchOnWindowFocus: false
|
|
13632
|
+
});
|
|
13633
|
+
}
|
|
13634
|
+
|
|
13635
|
+
// src/components/withdrawals/send-withdraw.ts
|
|
13636
|
+
var import_core32 = require("@unifold/core");
|
|
13637
|
+
async function sendEvmWithdraw(params) {
|
|
13638
|
+
const {
|
|
13639
|
+
provider,
|
|
13640
|
+
fromAddress,
|
|
13641
|
+
depositWalletAddress,
|
|
13642
|
+
sourceTokenAddress,
|
|
13643
|
+
sourceChainId,
|
|
13644
|
+
amountBaseUnit
|
|
13645
|
+
} = params;
|
|
13646
|
+
const currentChainIdHex = await provider.request({
|
|
13647
|
+
method: "eth_chainId",
|
|
13648
|
+
params: []
|
|
13649
|
+
});
|
|
13650
|
+
const currentChainId = parseInt(currentChainIdHex, 16).toString();
|
|
13651
|
+
if (currentChainId !== sourceChainId) {
|
|
13652
|
+
const requiredHex = "0x" + parseInt(sourceChainId).toString(16);
|
|
13653
|
+
try {
|
|
13654
|
+
await provider.request({
|
|
13655
|
+
method: "wallet_switchEthereumChain",
|
|
13656
|
+
params: [{ chainId: requiredHex }]
|
|
13657
|
+
});
|
|
13658
|
+
const newHex = await provider.request({ method: "eth_chainId", params: [] });
|
|
13659
|
+
if (parseInt(newHex, 16).toString() !== sourceChainId) {
|
|
13660
|
+
throw new Error(`Failed to switch to chain ${sourceChainId}. Please switch manually.`);
|
|
13661
|
+
}
|
|
13662
|
+
} catch (err) {
|
|
13663
|
+
if (err && typeof err === "object" && "code" in err) {
|
|
13664
|
+
const e = err;
|
|
13665
|
+
if (e.code === 4902) throw new Error(`Chain ${sourceChainId} is not configured in your wallet.`);
|
|
13666
|
+
if (e.code === 4001) throw new Error("You must approve the network switch to withdraw.");
|
|
13667
|
+
}
|
|
13668
|
+
throw err;
|
|
13669
|
+
}
|
|
13670
|
+
}
|
|
13671
|
+
const isNative = sourceTokenAddress === "native" || sourceTokenAddress === "0x0000000000000000000000000000000000000000" || sourceTokenAddress === "";
|
|
13672
|
+
const amountBig = BigInt(amountBaseUnit);
|
|
13673
|
+
const txParams = isNative ? { from: fromAddress, to: depositWalletAddress, value: "0x" + amountBig.toString(16) } : {
|
|
13674
|
+
from: fromAddress,
|
|
13675
|
+
to: sourceTokenAddress,
|
|
13676
|
+
data: "0xa9059cbb" + depositWalletAddress.slice(2).padStart(64, "0") + amountBig.toString(16).padStart(64, "0")
|
|
13677
|
+
};
|
|
13678
|
+
let gasEstimate;
|
|
13679
|
+
try {
|
|
13680
|
+
const hex = await provider.request({ method: "eth_estimateGas", params: [txParams] });
|
|
13681
|
+
gasEstimate = BigInt(hex);
|
|
13682
|
+
} catch {
|
|
13683
|
+
gasEstimate = isNative ? BigInt(21e3) : BigInt(65e3);
|
|
13684
|
+
}
|
|
13685
|
+
const gasPrice = BigInt(await provider.request({ method: "eth_gasPrice", params: [] }));
|
|
13686
|
+
const gasWithBuffer = gasEstimate * BigInt(120) / BigInt(100);
|
|
13687
|
+
const gasCost = gasWithBuffer * gasPrice;
|
|
13688
|
+
const ethBalance = BigInt(
|
|
13689
|
+
await provider.request({ method: "eth_getBalance", params: [fromAddress, "latest"] })
|
|
13690
|
+
);
|
|
13691
|
+
const totalRequired = isNative ? gasCost + amountBig : gasCost;
|
|
13692
|
+
if (ethBalance < totalRequired) {
|
|
13693
|
+
const gasFmt = (Number(gasCost) / 1e18).toFixed(6);
|
|
13694
|
+
if (isNative) {
|
|
13695
|
+
throw new Error(`Insufficient balance. Need ${(Number(totalRequired) / 1e18).toFixed(6)} ETH (amount + ~${gasFmt} gas).`);
|
|
13696
|
+
}
|
|
13697
|
+
throw new Error(`Insufficient ETH for gas. Need ~${gasFmt} ETH for fees.`);
|
|
13698
|
+
}
|
|
13699
|
+
const txHash = await provider.request({ method: "eth_sendTransaction", params: [txParams] });
|
|
13700
|
+
return txHash;
|
|
13701
|
+
}
|
|
13702
|
+
async function sendSolanaWithdraw(params) {
|
|
13703
|
+
const {
|
|
13704
|
+
provider,
|
|
13705
|
+
fromAddress,
|
|
13706
|
+
depositWalletAddress,
|
|
13707
|
+
sourceTokenAddress,
|
|
13708
|
+
amountBaseUnit,
|
|
13709
|
+
publishableKey
|
|
13710
|
+
} = params;
|
|
13711
|
+
if (!provider.publicKey) {
|
|
13712
|
+
await provider.connect();
|
|
13713
|
+
}
|
|
13714
|
+
const buildResponse = await (0, import_core32.buildSolanaTransaction)(
|
|
13715
|
+
{
|
|
13716
|
+
chain_id: "mainnet",
|
|
13717
|
+
token_address: sourceTokenAddress === "" ? "native" : sourceTokenAddress,
|
|
13718
|
+
source_address: fromAddress,
|
|
13719
|
+
destination_address: depositWalletAddress,
|
|
13720
|
+
amount: amountBaseUnit
|
|
13721
|
+
},
|
|
13722
|
+
publishableKey
|
|
13723
|
+
);
|
|
13724
|
+
const { VersionedTransaction } = await import(
|
|
13725
|
+
/* @vite-ignore */
|
|
13726
|
+
"@solana/web3.js"
|
|
13727
|
+
);
|
|
13728
|
+
const binaryString = atob(buildResponse.transaction);
|
|
13729
|
+
const bytes = new Uint8Array(binaryString.length);
|
|
13730
|
+
for (let i = 0; i < binaryString.length; i++) {
|
|
13731
|
+
bytes[i] = binaryString.charCodeAt(i);
|
|
13732
|
+
}
|
|
13733
|
+
const transaction = VersionedTransaction.deserialize(bytes);
|
|
13734
|
+
const signedTransaction = await provider.signTransaction(transaction);
|
|
13735
|
+
const serialized = signedTransaction.serialize();
|
|
13736
|
+
let binaryStr = "";
|
|
13737
|
+
for (let i = 0; i < serialized.length; i++) {
|
|
13738
|
+
binaryStr += String.fromCharCode(serialized[i]);
|
|
13739
|
+
}
|
|
13740
|
+
const sendResponse = await (0, import_core32.sendSolanaTransaction)(
|
|
13741
|
+
{ chain_id: "mainnet", signed_transaction: btoa(binaryStr) },
|
|
13742
|
+
publishableKey
|
|
13743
|
+
);
|
|
13744
|
+
return sendResponse.signature;
|
|
13745
|
+
}
|
|
13746
|
+
var HYPERCORE_CHAIN_ID = "1337";
|
|
13747
|
+
var HYPERCORE_SPOT_USDC_ADDRESS = "0x6d1e7cde53ba9467b783cb7c530ce054";
|
|
13748
|
+
function isHypercoreChain(chainId) {
|
|
13749
|
+
return chainId === HYPERCORE_CHAIN_ID;
|
|
13750
|
+
}
|
|
13751
|
+
async function sendHypercoreWithdraw(params) {
|
|
13752
|
+
const {
|
|
13753
|
+
provider,
|
|
13754
|
+
fromAddress,
|
|
13755
|
+
depositWalletAddress,
|
|
13756
|
+
sourceTokenAddress,
|
|
13757
|
+
amount,
|
|
13758
|
+
tokenSymbol,
|
|
13759
|
+
publishableKey
|
|
13760
|
+
} = params;
|
|
13761
|
+
const isSpot = sourceTokenAddress.toLowerCase() === HYPERCORE_SPOT_USDC_ADDRESS;
|
|
13762
|
+
const currentChainHex = await provider.request({
|
|
13763
|
+
method: "eth_chainId",
|
|
13764
|
+
params: []
|
|
13765
|
+
});
|
|
13766
|
+
const activeChainId = String(parseInt(currentChainHex, 16));
|
|
13767
|
+
const buildResult = await (0, import_core32.buildHypercoreTransaction)(
|
|
13768
|
+
{
|
|
13769
|
+
action_type: isSpot ? "spot_send" : "usd_send",
|
|
13770
|
+
signature_chain_type: "ethereum",
|
|
13771
|
+
signature_chain_id: activeChainId,
|
|
13772
|
+
recipient_address: depositWalletAddress,
|
|
13773
|
+
token_address: sourceTokenAddress,
|
|
13774
|
+
token_symbol: tokenSymbol || void 0,
|
|
13775
|
+
amount
|
|
13776
|
+
},
|
|
13777
|
+
publishableKey
|
|
13778
|
+
);
|
|
13779
|
+
const signature = await provider.request({
|
|
13780
|
+
method: "eth_signTypedData_v4",
|
|
13781
|
+
params: [fromAddress, JSON.stringify(buildResult.typed_data)]
|
|
13782
|
+
});
|
|
13783
|
+
await (0, import_core32.sendHypercoreTransaction)(
|
|
13784
|
+
{
|
|
13785
|
+
action_payload: buildResult.action_payload,
|
|
13786
|
+
signature,
|
|
13787
|
+
nonce: buildResult.nonce
|
|
13788
|
+
},
|
|
13789
|
+
publishableKey
|
|
13790
|
+
);
|
|
13791
|
+
}
|
|
13792
|
+
async function detectBrowserWallet(chainType, senderAddress) {
|
|
13793
|
+
const win = typeof window !== "undefined" ? window : null;
|
|
13794
|
+
if (!win || !senderAddress) return null;
|
|
13795
|
+
const anyWin = win;
|
|
13796
|
+
if (chainType === "solana") {
|
|
13797
|
+
const solProviders = [];
|
|
13798
|
+
if (win.phantom?.solana) solProviders.push({ provider: win.phantom.solana, name: "Phantom" });
|
|
13799
|
+
if (anyWin.solflare) solProviders.push({ provider: anyWin.solflare, name: "Solflare" });
|
|
13800
|
+
if (anyWin.backpack) solProviders.push({ provider: anyWin.backpack, name: "Backpack" });
|
|
13801
|
+
if (anyWin.trustwallet?.solana) solProviders.push({ provider: anyWin.trustwallet.solana, name: "Trust Wallet" });
|
|
13802
|
+
for (const { provider, name } of solProviders) {
|
|
13803
|
+
if (!provider) continue;
|
|
13804
|
+
try {
|
|
13805
|
+
let addr;
|
|
13806
|
+
if (provider.isConnected && provider.publicKey) {
|
|
13807
|
+
addr = provider.publicKey.toString();
|
|
13808
|
+
} else {
|
|
13809
|
+
const resp = await provider.connect({ onlyIfTrusted: true });
|
|
13810
|
+
if (resp?.publicKey) addr = resp.publicKey.toString();
|
|
13811
|
+
}
|
|
13812
|
+
if (addr && addr === senderAddress) {
|
|
13813
|
+
return { chainFamily: "solana", provider, name, address: addr };
|
|
13814
|
+
}
|
|
13815
|
+
} catch {
|
|
13816
|
+
}
|
|
13817
|
+
}
|
|
13818
|
+
}
|
|
13819
|
+
if (chainType === "ethereum") {
|
|
13820
|
+
const evmProviders = [];
|
|
13821
|
+
const seen = /* @__PURE__ */ new Set();
|
|
13822
|
+
const add = (p, name) => {
|
|
13823
|
+
if (p && typeof p.request === "function" && !seen.has(p)) {
|
|
13824
|
+
seen.add(p);
|
|
13825
|
+
evmProviders.push({ provider: p, name });
|
|
13826
|
+
}
|
|
13827
|
+
};
|
|
13828
|
+
add(anyWin.phantom?.ethereum, "Phantom");
|
|
13829
|
+
add(anyWin.coinbaseWalletExtension, "Coinbase");
|
|
13830
|
+
add(anyWin.trustwallet?.ethereum, "Trust Wallet");
|
|
13831
|
+
add(anyWin.okxwallet, "OKX Wallet");
|
|
13832
|
+
if (anyWin.__eip6963Providers) {
|
|
13833
|
+
for (const detail of anyWin.__eip6963Providers) {
|
|
13834
|
+
const rdns = detail.info?.rdns || "";
|
|
13835
|
+
let name = detail.info?.name || "Wallet";
|
|
13836
|
+
if (rdns.includes("metamask")) name = "MetaMask";
|
|
13837
|
+
else if (rdns.includes("rabby")) name = "Rabby";
|
|
13838
|
+
else if (rdns.includes("rainbow")) name = "Rainbow";
|
|
13839
|
+
add(detail.provider, name);
|
|
13840
|
+
}
|
|
13841
|
+
}
|
|
13842
|
+
if (win.ethereum) {
|
|
13843
|
+
const eth = win.ethereum;
|
|
13844
|
+
let name = "Wallet";
|
|
13845
|
+
if (eth.isMetaMask && !eth.isPhantom && !eth.isRabby) name = "MetaMask";
|
|
13846
|
+
else if (eth.isRabby) name = "Rabby";
|
|
13847
|
+
else if (eth.isRainbow) name = "Rainbow";
|
|
13848
|
+
else if (eth.isCoinbaseWallet) name = "Coinbase";
|
|
13849
|
+
add(eth, name);
|
|
13850
|
+
}
|
|
13851
|
+
for (const { provider, name } of evmProviders) {
|
|
13852
|
+
try {
|
|
13853
|
+
const accounts = await provider.request({ method: "eth_accounts" });
|
|
13854
|
+
if (accounts?.length > 0 && accounts[0].toLowerCase() === senderAddress.toLowerCase()) {
|
|
13855
|
+
return { chainFamily: "evm", provider, name, address: accounts[0] };
|
|
13856
|
+
}
|
|
13857
|
+
} catch {
|
|
13858
|
+
}
|
|
13859
|
+
}
|
|
13860
|
+
}
|
|
13861
|
+
return null;
|
|
13862
|
+
}
|
|
13863
|
+
|
|
13864
|
+
// src/components/withdrawals/WithdrawForm.tsx
|
|
13865
|
+
var import_jsx_runtime54 = require("react/jsx-runtime");
|
|
13866
|
+
var t8 = i18n.withdrawModal;
|
|
13867
|
+
var tCrypto = i18n.transferCrypto;
|
|
13868
|
+
function formatProcessingTime2(seconds) {
|
|
13869
|
+
if (seconds === null) {
|
|
13870
|
+
return tCrypto.processingTime.lessThanMinutes.replace("{{minutes}}", "1");
|
|
13871
|
+
}
|
|
13872
|
+
const minutes = Math.ceil(seconds / 60);
|
|
13873
|
+
if (minutes < 60) {
|
|
13874
|
+
return tCrypto.processingTime.lessThanMinutes.replace("{{minutes}}", String(minutes));
|
|
13875
|
+
}
|
|
13876
|
+
const hours = Math.ceil(minutes / 60);
|
|
13877
|
+
return tCrypto.processingTime.lessThanHours.replace("{{hours}}", String(hours));
|
|
13878
|
+
}
|
|
13879
|
+
function computeBaseUnit(balanceBaseUnit, inputAmount, balanceAmount) {
|
|
13880
|
+
if (balanceAmount <= 0 || inputAmount <= 0) return "0";
|
|
13881
|
+
if (inputAmount >= balanceAmount) return balanceBaseUnit;
|
|
13882
|
+
const PRECISION = 10n ** 18n;
|
|
13883
|
+
const ratioScaled = BigInt(Math.round(inputAmount / balanceAmount * Number(PRECISION)));
|
|
13884
|
+
const result = BigInt(balanceBaseUnit) * ratioScaled / PRECISION;
|
|
13885
|
+
return result.toString();
|
|
13886
|
+
}
|
|
13887
|
+
function toSafeDecimalString(n, maxDecimals) {
|
|
13888
|
+
if (n === 0) return "0";
|
|
13889
|
+
return n.toFixed(maxDecimals).replace(/\.?0+$/, "");
|
|
13890
|
+
}
|
|
13891
|
+
function WithdrawForm({
|
|
13892
|
+
publishableKey,
|
|
13893
|
+
externalUserId,
|
|
13894
|
+
sourceChainType,
|
|
13895
|
+
selectedToken,
|
|
13896
|
+
selectedChain,
|
|
13897
|
+
sourceTokenSymbol,
|
|
13898
|
+
recipientAddressProp,
|
|
13899
|
+
balanceData,
|
|
13900
|
+
isLoadingBalance,
|
|
13901
|
+
minimumWithdrawAmountUsd,
|
|
13902
|
+
estimatedProcessingTime,
|
|
13903
|
+
maxSlippagePercent,
|
|
13904
|
+
priceImpactPercent,
|
|
13905
|
+
detectedWallet,
|
|
13906
|
+
sourceChainId,
|
|
13907
|
+
sourceTokenAddress,
|
|
13908
|
+
isWalletMatch,
|
|
13909
|
+
connectedWalletName,
|
|
13910
|
+
canWithdraw,
|
|
13911
|
+
onWithdraw,
|
|
13912
|
+
onWithdrawError,
|
|
13913
|
+
onDepositWalletCreation,
|
|
13914
|
+
onWithdrawSubmitted,
|
|
13915
|
+
footerLeft
|
|
13916
|
+
}) {
|
|
13917
|
+
const { colors: colors2, fonts, components } = useTheme();
|
|
13918
|
+
const [recipientAddress, setRecipientAddress] = (0, import_react21.useState)(recipientAddressProp || "");
|
|
13919
|
+
const [amount, setAmount] = (0, import_react21.useState)("");
|
|
13920
|
+
const [inputUnit, setInputUnit] = (0, import_react21.useState)("crypto");
|
|
13921
|
+
const [isSubmitting, setIsSubmitting] = (0, import_react21.useState)(false);
|
|
13922
|
+
const [submitError, setSubmitError] = (0, import_react21.useState)(null);
|
|
13923
|
+
const [detailsExpanded, setDetailsExpanded] = (0, import_react21.useState)(false);
|
|
13924
|
+
const [glossaryOpen, setGlossaryOpen] = (0, import_react21.useState)(false);
|
|
13925
|
+
(0, import_react21.useEffect)(() => {
|
|
13926
|
+
setRecipientAddress(recipientAddressProp || "");
|
|
13927
|
+
setAmount("");
|
|
13928
|
+
setInputUnit("crypto");
|
|
13929
|
+
setSubmitError(null);
|
|
13930
|
+
}, [recipientAddressProp]);
|
|
13931
|
+
const trimmedAddress = recipientAddress.trim();
|
|
13932
|
+
const [debouncedAddress, setDebouncedAddress] = (0, import_react21.useState)(trimmedAddress);
|
|
13933
|
+
(0, import_react21.useEffect)(() => {
|
|
13934
|
+
const id = setTimeout(() => setDebouncedAddress(trimmedAddress), 500);
|
|
13935
|
+
return () => clearTimeout(id);
|
|
13936
|
+
}, [trimmedAddress]);
|
|
13937
|
+
const {
|
|
13938
|
+
data: addressVerification,
|
|
13939
|
+
isLoading: isVerifyingAddress,
|
|
13940
|
+
error: verifyError
|
|
13941
|
+
} = useVerifyRecipientAddress({
|
|
13942
|
+
chainType: selectedChain?.chain_type,
|
|
13943
|
+
chainId: selectedChain?.chain_id,
|
|
13944
|
+
tokenAddress: selectedChain?.token_address,
|
|
13945
|
+
recipientAddress: debouncedAddress,
|
|
13946
|
+
publishableKey,
|
|
13947
|
+
enabled: debouncedAddress.length > 5 && !!selectedChain
|
|
13948
|
+
});
|
|
13949
|
+
const isDebouncing = trimmedAddress !== debouncedAddress;
|
|
13950
|
+
const addressError = (0, import_react21.useMemo)(() => {
|
|
13951
|
+
if (!trimmedAddress || trimmedAddress.length <= 5) return null;
|
|
13952
|
+
if (isDebouncing || isVerifyingAddress) return null;
|
|
13953
|
+
if (verifyError) return t8.invalidAddress;
|
|
13954
|
+
if (addressVerification && !addressVerification.valid) {
|
|
13955
|
+
if (addressVerification.failure_code === "account_not_found")
|
|
13956
|
+
return `Account not found on ${selectedChain?.chain_name}`;
|
|
13957
|
+
if (addressVerification.failure_code === "not_opted_in")
|
|
13958
|
+
return `Recipient has not opted in to ${selectedToken?.symbol} on ${selectedChain?.chain_name}`;
|
|
13959
|
+
return t8.invalidAddress;
|
|
13960
|
+
}
|
|
13961
|
+
return null;
|
|
13962
|
+
}, [trimmedAddress, isDebouncing, isVerifyingAddress, verifyError, addressVerification, selectedChain, selectedToken]);
|
|
13963
|
+
const isAddressValid = !isDebouncing && !!addressVerification?.valid && !addressError;
|
|
13964
|
+
const exchangeRate = (0, import_react21.useMemo)(() => {
|
|
13965
|
+
if (!balanceData?.exchangeRate) return 0;
|
|
13966
|
+
return parseFloat(balanceData.exchangeRate);
|
|
13967
|
+
}, [balanceData]);
|
|
13968
|
+
const balanceCrypto = (0, import_react21.useMemo)(() => {
|
|
13969
|
+
if (!balanceData?.balanceHuman) return 0;
|
|
13970
|
+
return parseFloat(balanceData.balanceHuman);
|
|
13971
|
+
}, [balanceData]);
|
|
13972
|
+
const balanceUsdNum = (0, import_react21.useMemo)(() => {
|
|
13973
|
+
if (!balanceData?.balanceUsd) return 0;
|
|
13974
|
+
return parseFloat(balanceData.balanceUsd);
|
|
13975
|
+
}, [balanceData]);
|
|
13976
|
+
const tokenSymbol = sourceTokenSymbol || balanceData?.symbol || "TOKEN";
|
|
13977
|
+
const sourceDecimals = balanceData?.decimals ?? 6;
|
|
13978
|
+
const cryptoAmountFromInput = (0, import_react21.useMemo)(() => {
|
|
13979
|
+
const val = parseFloat(amount);
|
|
13980
|
+
if (!val || val <= 0) return 0;
|
|
13981
|
+
if (inputUnit === "crypto") return val;
|
|
13982
|
+
return exchangeRate > 0 ? val / exchangeRate : 0;
|
|
13983
|
+
}, [amount, inputUnit, exchangeRate]);
|
|
13984
|
+
const fiatAmountFromInput = (0, import_react21.useMemo)(() => {
|
|
13985
|
+
const val = parseFloat(amount);
|
|
13986
|
+
if (!val || val <= 0) return 0;
|
|
13987
|
+
if (inputUnit === "fiat") return val;
|
|
13988
|
+
return val * exchangeRate;
|
|
13989
|
+
}, [amount, inputUnit, exchangeRate]);
|
|
13990
|
+
const convertedDisplay = (0, import_react21.useMemo)(() => {
|
|
13991
|
+
if (!amount || parseFloat(amount) <= 0) return null;
|
|
13992
|
+
if (inputUnit === "crypto") {
|
|
13993
|
+
return `$${fiatAmountFromInput.toLocaleString(void 0, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;
|
|
13994
|
+
}
|
|
13995
|
+
return `${cryptoAmountFromInput.toLocaleString(void 0, { minimumFractionDigits: 2, maximumFractionDigits: 6 })} ${tokenSymbol}`;
|
|
13996
|
+
}, [amount, inputUnit, fiatAmountFromInput, cryptoAmountFromInput, tokenSymbol]);
|
|
13997
|
+
const balanceDisplay = (0, import_react21.useMemo)(() => {
|
|
13998
|
+
if (isLoadingBalance || !balanceData) return null;
|
|
13999
|
+
if (inputUnit === "crypto") {
|
|
14000
|
+
return `${balanceCrypto.toLocaleString(void 0, { minimumFractionDigits: 2, maximumFractionDigits: 2 })} ${tokenSymbol}`;
|
|
14001
|
+
}
|
|
14002
|
+
return `$${balanceUsdNum.toLocaleString(void 0, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;
|
|
14003
|
+
}, [isLoadingBalance, balanceData, inputUnit, balanceCrypto, balanceUsdNum, tokenSymbol]);
|
|
14004
|
+
const handleSwitchUnit = (0, import_react21.useCallback)(() => {
|
|
14005
|
+
const val = parseFloat(amount);
|
|
14006
|
+
if (!val || val <= 0 || exchangeRate <= 0) {
|
|
14007
|
+
setInputUnit((u) => u === "crypto" ? "fiat" : "crypto");
|
|
14008
|
+
setAmount("");
|
|
14009
|
+
return;
|
|
14010
|
+
}
|
|
14011
|
+
if (inputUnit === "crypto") {
|
|
14012
|
+
const fiat = val * exchangeRate;
|
|
14013
|
+
setAmount(fiat.toFixed(2));
|
|
14014
|
+
setInputUnit("fiat");
|
|
14015
|
+
} else {
|
|
14016
|
+
const crypto = val / exchangeRate;
|
|
14017
|
+
setAmount(crypto.toFixed(sourceDecimals > 6 ? 6 : sourceDecimals));
|
|
14018
|
+
setInputUnit("crypto");
|
|
14019
|
+
}
|
|
14020
|
+
}, [amount, inputUnit, exchangeRate, sourceDecimals]);
|
|
14021
|
+
const handleMaxClick = (0, import_react21.useCallback)(() => {
|
|
14022
|
+
if (inputUnit === "crypto") {
|
|
14023
|
+
if (balanceCrypto <= 0) return;
|
|
14024
|
+
setAmount(balanceData?.balanceHuman ?? "0");
|
|
14025
|
+
} else {
|
|
14026
|
+
if (balanceUsdNum <= 0) return;
|
|
14027
|
+
setAmount((Math.floor(balanceUsdNum * 100) / 100).toFixed(2));
|
|
14028
|
+
}
|
|
14029
|
+
}, [inputUnit, balanceCrypto, balanceUsdNum, balanceData]);
|
|
14030
|
+
const isBelowMinimum = minimumWithdrawAmountUsd !== null && fiatAmountFromInput > 0 && fiatAmountFromInput < minimumWithdrawAmountUsd;
|
|
14031
|
+
const isOverBalance = inputUnit === "crypto" ? cryptoAmountFromInput > 0 && balanceCrypto > 0 && cryptoAmountFromInput > balanceCrypto : fiatAmountFromInput > 0 && balanceUsdNum > 0 && fiatAmountFromInput > balanceUsdNum;
|
|
14032
|
+
const isFormValid = trimmedAddress.length > 0 && amount.trim().length > 0 && cryptoAmountFromInput > 0 && isAddressValid && !isBelowMinimum && !isOverBalance && !!balanceData;
|
|
14033
|
+
const handleWithdraw = (0, import_react21.useCallback)(async () => {
|
|
14034
|
+
if (!selectedToken || !selectedChain) return;
|
|
14035
|
+
if (!isFormValid) return;
|
|
14036
|
+
setIsSubmitting(true);
|
|
14037
|
+
setSubmitError(null);
|
|
14038
|
+
try {
|
|
14039
|
+
const depositWallet = await onDepositWalletCreation({
|
|
14040
|
+
destinationChainType: selectedChain.chain_type,
|
|
14041
|
+
destinationChainId: selectedChain.chain_id,
|
|
14042
|
+
destinationTokenAddress: selectedChain.token_address,
|
|
14043
|
+
recipientAddress: trimmedAddress
|
|
14044
|
+
});
|
|
14045
|
+
const amountBaseUnit = computeBaseUnit(
|
|
14046
|
+
balanceData.balanceBaseUnit,
|
|
14047
|
+
parseFloat(amount),
|
|
14048
|
+
inputUnit === "crypto" ? balanceCrypto : balanceUsdNum
|
|
14049
|
+
);
|
|
14050
|
+
const humanAmount = toSafeDecimalString(cryptoAmountFromInput, sourceDecimals);
|
|
14051
|
+
const txInfo = {
|
|
14052
|
+
sourceChainType,
|
|
14053
|
+
sourceChainId,
|
|
14054
|
+
sourceTokenAddress,
|
|
14055
|
+
sourceTokenSymbol: tokenSymbol,
|
|
14056
|
+
destinationChainType: selectedChain.chain_type,
|
|
14057
|
+
destinationChainId: selectedChain.chain_id,
|
|
14058
|
+
destinationTokenAddress: selectedChain.token_address,
|
|
14059
|
+
destinationTokenSymbol: selectedToken.symbol,
|
|
14060
|
+
amount: humanAmount,
|
|
14061
|
+
amountBaseUnit,
|
|
14062
|
+
withdrawIntentAddress: depositWallet.address,
|
|
14063
|
+
recipientAddress: trimmedAddress
|
|
14064
|
+
};
|
|
14065
|
+
if (detectedWallet) {
|
|
14066
|
+
if (detectedWallet.chainFamily === "evm" && isHypercoreChain(sourceChainId)) {
|
|
14067
|
+
await sendHypercoreWithdraw({
|
|
14068
|
+
provider: detectedWallet.provider,
|
|
14069
|
+
fromAddress: detectedWallet.address,
|
|
14070
|
+
depositWalletAddress: depositWallet.address,
|
|
14071
|
+
sourceTokenAddress,
|
|
14072
|
+
amount: humanAmount,
|
|
14073
|
+
tokenSymbol,
|
|
14074
|
+
publishableKey
|
|
14075
|
+
});
|
|
14076
|
+
} else if (detectedWallet.chainFamily === "evm") {
|
|
14077
|
+
await sendEvmWithdraw({
|
|
14078
|
+
provider: detectedWallet.provider,
|
|
14079
|
+
fromAddress: detectedWallet.address,
|
|
14080
|
+
depositWalletAddress: depositWallet.address,
|
|
14081
|
+
sourceTokenAddress,
|
|
14082
|
+
sourceChainId,
|
|
14083
|
+
amountBaseUnit
|
|
14084
|
+
});
|
|
14085
|
+
} else if (detectedWallet.chainFamily === "solana") {
|
|
14086
|
+
await sendSolanaWithdraw({
|
|
14087
|
+
provider: detectedWallet.provider,
|
|
14088
|
+
fromAddress: detectedWallet.address,
|
|
14089
|
+
depositWalletAddress: depositWallet.address,
|
|
14090
|
+
sourceTokenAddress,
|
|
14091
|
+
amountBaseUnit,
|
|
14092
|
+
publishableKey
|
|
14093
|
+
});
|
|
14094
|
+
}
|
|
14095
|
+
} else if (onWithdraw) {
|
|
14096
|
+
await onWithdraw(txInfo);
|
|
14097
|
+
} else {
|
|
14098
|
+
throw new Error("No withdrawal method available. Please connect a wallet.");
|
|
14099
|
+
}
|
|
14100
|
+
onWithdrawSubmitted?.(txInfo);
|
|
14101
|
+
} catch (err) {
|
|
14102
|
+
const raw = err instanceof Error ? err.message : "Withdrawal failed. Please try again.";
|
|
14103
|
+
setSubmitError(raw.length > 120 ? "Withdrawal failed. Please try again." : raw);
|
|
14104
|
+
onWithdrawError?.({
|
|
14105
|
+
message: raw,
|
|
14106
|
+
error: err,
|
|
14107
|
+
code: "WITHDRAW_FAILED"
|
|
14108
|
+
});
|
|
14109
|
+
} finally {
|
|
14110
|
+
setIsSubmitting(false);
|
|
14111
|
+
}
|
|
14112
|
+
}, [selectedToken, selectedChain, isFormValid, cryptoAmountFromInput, sourceDecimals, trimmedAddress, publishableKey, onWithdraw, detectedWallet, sourceTokenAddress, sourceChainId, onWithdrawError, onDepositWalletCreation, onWithdrawSubmitted, amount, inputUnit, balanceCrypto, balanceUsdNum, balanceData]);
|
|
14113
|
+
return /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)(import_jsx_runtime54.Fragment, { children: [
|
|
14114
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("div", { children: [
|
|
14115
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
|
|
14116
|
+
"div",
|
|
14117
|
+
{
|
|
14118
|
+
className: "uf-text-xs uf-mb-1.5",
|
|
14119
|
+
style: { color: components.card.labelColor, fontFamily: fonts.medium },
|
|
14120
|
+
children: t8.recipientAddress
|
|
14121
|
+
}
|
|
14122
|
+
),
|
|
14123
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
|
|
14124
|
+
"style",
|
|
14125
|
+
{
|
|
14126
|
+
dangerouslySetInnerHTML: {
|
|
14127
|
+
__html: `.uf-withdraw-addr::placeholder { color: ${components.search.placeholderColor}; }`
|
|
14128
|
+
}
|
|
14129
|
+
}
|
|
14130
|
+
),
|
|
14131
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsxs)(
|
|
14132
|
+
"div",
|
|
14133
|
+
{
|
|
14134
|
+
className: "uf-flex uf-items-center uf-gap-1 uf-pr-2",
|
|
14135
|
+
style: {
|
|
14136
|
+
backgroundColor: components.search.backgroundColor,
|
|
14137
|
+
borderRadius: components.input.borderRadius,
|
|
14138
|
+
border: `${components.input.borderWidth}px solid ${addressError ? colors2.error : components.input.borderColor}`
|
|
14139
|
+
},
|
|
14140
|
+
children: [
|
|
14141
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
|
|
14142
|
+
"input",
|
|
14143
|
+
{
|
|
14144
|
+
type: "text",
|
|
14145
|
+
placeholder: t8.recipientAddressPlaceholder,
|
|
14146
|
+
value: recipientAddress,
|
|
14147
|
+
onChange: (e) => {
|
|
14148
|
+
setRecipientAddress(e.target.value);
|
|
14149
|
+
setSubmitError(null);
|
|
14150
|
+
},
|
|
14151
|
+
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",
|
|
14152
|
+
style: {
|
|
14153
|
+
color: components.search.inputColor,
|
|
14154
|
+
fontFamily: fonts.regular
|
|
14155
|
+
}
|
|
14156
|
+
}
|
|
14157
|
+
),
|
|
14158
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
|
|
14159
|
+
"button",
|
|
14160
|
+
{
|
|
14161
|
+
type: "button",
|
|
14162
|
+
onClick: async () => {
|
|
14163
|
+
try {
|
|
14164
|
+
const text = await navigator.clipboard.readText();
|
|
14165
|
+
if (text) {
|
|
14166
|
+
setRecipientAddress(text.trim());
|
|
14167
|
+
setSubmitError(null);
|
|
14168
|
+
}
|
|
14169
|
+
} catch {
|
|
14170
|
+
}
|
|
14171
|
+
},
|
|
14172
|
+
className: "uf-flex-shrink-0 uf-p-1 uf-rounded uf-transition-colors hover:uf-opacity-70",
|
|
14173
|
+
style: { color: colors2.foregroundMuted },
|
|
14174
|
+
title: "Paste from clipboard",
|
|
14175
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(import_lucide_react25.ClipboardPaste, { className: "uf-w-4 uf-h-4" })
|
|
14176
|
+
}
|
|
14177
|
+
)
|
|
14178
|
+
]
|
|
14179
|
+
}
|
|
14180
|
+
),
|
|
14181
|
+
(isDebouncing || isVerifyingAddress) && trimmedAddress.length > 5 && /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("div", { className: "uf-flex uf-items-center uf-gap-1.5 uf-mt-1.5", children: [
|
|
14182
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)(import_lucide_react25.Loader2, { className: "uf-w-3 uf-h-3 uf-animate-spin", style: { color: colors2.foregroundMuted } }),
|
|
14183
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)("span", { className: "uf-text-xs", style: { color: colors2.foregroundMuted, fontFamily: fonts.regular }, children: t8.verifyingAddress })
|
|
14184
|
+
] }),
|
|
14185
|
+
addressError && /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("div", { className: "uf-flex uf-items-center uf-gap-1.5 uf-mt-1.5", children: [
|
|
14186
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)(import_lucide_react25.AlertTriangle, { className: "uf-w-3 uf-h-3", style: { color: colors2.error } }),
|
|
14187
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)("span", { className: "uf-text-xs", style: { color: colors2.error, fontFamily: fonts.regular }, children: addressError })
|
|
14188
|
+
] })
|
|
14189
|
+
] }),
|
|
14190
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("div", { children: [
|
|
14191
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("div", { className: "uf-text-xs uf-mb-1.5", style: { color: components.card.labelColor, fontFamily: fonts.medium }, children: [
|
|
14192
|
+
t8.amount,
|
|
14193
|
+
minimumWithdrawAmountUsd != null && minimumWithdrawAmountUsd > 0 && /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("span", { style: { color: colors2.warning, fontFamily: fonts.regular }, children: ` ($${minimumWithdrawAmountUsd.toFixed(2)} min)` })
|
|
14194
|
+
] }),
|
|
14195
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
|
|
14196
|
+
"style",
|
|
14197
|
+
{
|
|
14198
|
+
dangerouslySetInnerHTML: {
|
|
14199
|
+
__html: `.uf-withdraw-amt::placeholder { color: ${components.search.placeholderColor}; }`
|
|
14200
|
+
}
|
|
14201
|
+
}
|
|
14202
|
+
),
|
|
14203
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsxs)(
|
|
14204
|
+
"div",
|
|
14205
|
+
{
|
|
14206
|
+
className: "uf-flex uf-items-center uf-gap-2 uf-px-3 uf-py-2.5",
|
|
14207
|
+
style: {
|
|
14208
|
+
backgroundColor: components.search.backgroundColor,
|
|
14209
|
+
borderRadius: components.input.borderRadius,
|
|
14210
|
+
border: `${components.input.borderWidth}px solid ${components.input.borderColor}`
|
|
14211
|
+
},
|
|
14212
|
+
children: [
|
|
14213
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
|
|
14214
|
+
"input",
|
|
14215
|
+
{
|
|
14216
|
+
type: "text",
|
|
14217
|
+
inputMode: "decimal",
|
|
14218
|
+
placeholder: "0.00",
|
|
14219
|
+
value: amount,
|
|
14220
|
+
onChange: (e) => {
|
|
14221
|
+
const val = e.target.value;
|
|
14222
|
+
if (val === "" || /^\d*\.?\d*$/.test(val)) {
|
|
14223
|
+
setAmount(val);
|
|
14224
|
+
setSubmitError(null);
|
|
14225
|
+
}
|
|
14226
|
+
},
|
|
14227
|
+
className: "uf-withdraw-amt uf-flex-1 uf-min-w-0 uf-bg-transparent uf-text-sm uf-outline-none",
|
|
14228
|
+
style: {
|
|
14229
|
+
color: components.search.inputColor,
|
|
14230
|
+
fontFamily: fonts.regular
|
|
14231
|
+
}
|
|
14232
|
+
}
|
|
14233
|
+
),
|
|
14234
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)("span", { className: "uf-text-sm uf-shrink-0", style: { color: colors2.foregroundMuted, fontFamily: fonts.medium }, children: inputUnit === "crypto" ? tokenSymbol : "USD" }),
|
|
14235
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
|
|
14236
|
+
"button",
|
|
14237
|
+
{
|
|
14238
|
+
type: "button",
|
|
14239
|
+
onClick: handleMaxClick,
|
|
14240
|
+
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",
|
|
14241
|
+
style: { backgroundColor: colors2.primary + "20", color: colors2.primary, fontFamily: fonts.medium },
|
|
14242
|
+
children: "Max"
|
|
14243
|
+
}
|
|
14244
|
+
)
|
|
14245
|
+
]
|
|
14246
|
+
}
|
|
14247
|
+
),
|
|
14248
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("div", { className: "uf-flex uf-items-center uf-justify-between uf-mt-1.5 uf-px-3", children: [
|
|
14249
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("div", { className: "uf-flex uf-items-center uf-gap-1", children: [
|
|
14250
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)("span", { className: "uf-text-xs", style: { color: colors2.foregroundMuted, fontFamily: fonts.regular }, children: convertedDisplay || (inputUnit === "crypto" ? "$0.00" : `0.00 ${tokenSymbol}`) }),
|
|
14251
|
+
exchangeRate > 0 && /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
|
|
14252
|
+
"button",
|
|
14253
|
+
{
|
|
14254
|
+
type: "button",
|
|
14255
|
+
onClick: handleSwitchUnit,
|
|
14256
|
+
className: "uf-p-0.5 uf-rounded uf-transition-colors hover:uf-opacity-70",
|
|
14257
|
+
style: { color: colors2.foregroundMuted },
|
|
14258
|
+
title: "Switch unit",
|
|
14259
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(import_lucide_react25.ArrowUpDown, { className: "uf-w-3 uf-h-3" })
|
|
14260
|
+
}
|
|
14261
|
+
)
|
|
14262
|
+
] }),
|
|
14263
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("div", { children: [
|
|
14264
|
+
balanceDisplay && /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("span", { className: "uf-text-xs", style: { color: colors2.foregroundMuted, fontFamily: fonts.regular }, children: [
|
|
14265
|
+
t8.balance,
|
|
14266
|
+
": ",
|
|
14267
|
+
balanceDisplay
|
|
14268
|
+
] }),
|
|
14269
|
+
isLoadingBalance && /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("div", { className: "uf-h-3 uf-w-16 uf-bg-muted uf-rounded uf-animate-pulse" })
|
|
14270
|
+
] })
|
|
14271
|
+
] })
|
|
14272
|
+
] }),
|
|
14273
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("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: [
|
|
14274
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsxs)(
|
|
14275
|
+
"button",
|
|
14276
|
+
{
|
|
14277
|
+
type: "button",
|
|
14278
|
+
onClick: () => setDetailsExpanded(!detailsExpanded),
|
|
14279
|
+
className: "uf-w-full uf-flex uf-items-center uf-justify-between uf-py-2.5",
|
|
14280
|
+
children: [
|
|
14281
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("div", { className: "uf-flex uf-items-center uf-gap-2", children: [
|
|
14282
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)("div", { className: "uf-rounded-full uf-p-1", style: { backgroundColor: components.card.iconBackgroundColor }, children: /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(import_lucide_react25.Clock, { className: "uf-w-3 uf-h-3", style: { color: components.card.iconColor } }) }),
|
|
14283
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("span", { className: "uf-text-xs", style: { color: components.card.labelColor, fontFamily: fonts.regular }, children: [
|
|
14284
|
+
tCrypto.processingTime.label,
|
|
14285
|
+
":",
|
|
14286
|
+
" ",
|
|
14287
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)("span", { style: { color: components.card.titleColor, fontFamily: fonts.medium }, children: formatProcessingTime2(estimatedProcessingTime) })
|
|
14288
|
+
] })
|
|
14289
|
+
] }),
|
|
14290
|
+
detailsExpanded ? /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(import_lucide_react25.ChevronUp, { className: "uf-w-4 uf-h-4", style: { color: components.card.actionColor } }) : /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(import_lucide_react25.ChevronDown, { className: "uf-w-4 uf-h-4", style: { color: components.card.actionColor } })
|
|
14291
|
+
]
|
|
14292
|
+
}
|
|
14293
|
+
),
|
|
14294
|
+
detailsExpanded && /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("div", { className: "uf-pb-3 uf-space-y-2.5", children: [
|
|
14295
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("div", { className: "uf-flex uf-items-center uf-gap-2", children: [
|
|
14296
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)("div", { className: "uf-rounded-full uf-p-1", style: { backgroundColor: components.card.iconBackgroundColor }, children: /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(import_lucide_react25.ShieldCheck, { className: "uf-w-3 uf-h-3", style: { color: components.card.iconColor } }) }),
|
|
14297
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("span", { className: "uf-text-xs", style: { color: components.card.labelColor, fontFamily: fonts.regular }, children: [
|
|
14298
|
+
tCrypto.slippage.label,
|
|
14299
|
+
":",
|
|
14300
|
+
" ",
|
|
14301
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("span", { style: { color: components.card.titleColor, fontFamily: fonts.medium }, children: [
|
|
14302
|
+
tCrypto.slippage.auto,
|
|
14303
|
+
" \u2022 ",
|
|
14304
|
+
(maxSlippagePercent ?? 0.25).toFixed(2),
|
|
14305
|
+
"%"
|
|
14306
|
+
] })
|
|
14307
|
+
] })
|
|
14308
|
+
] }),
|
|
14309
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("div", { className: "uf-flex uf-items-center uf-gap-2", children: [
|
|
14310
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)("div", { className: "uf-rounded-full uf-p-1", style: { backgroundColor: components.card.iconBackgroundColor }, children: /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(import_lucide_react25.DollarSign, { className: "uf-w-3 uf-h-3", style: { color: components.card.iconColor } }) }),
|
|
14311
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("span", { className: "uf-text-xs", style: { color: components.card.labelColor, fontFamily: fonts.regular }, children: [
|
|
14312
|
+
tCrypto.priceImpact.label,
|
|
14313
|
+
":",
|
|
14314
|
+
" ",
|
|
14315
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("span", { style: { color: components.card.titleColor, fontFamily: fonts.medium }, children: [
|
|
14316
|
+
(priceImpactPercent ?? 0).toFixed(2),
|
|
14317
|
+
"%"
|
|
14318
|
+
] })
|
|
14319
|
+
] })
|
|
14320
|
+
] })
|
|
14321
|
+
] })
|
|
14322
|
+
] }),
|
|
14323
|
+
!canWithdraw && !submitError && /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)(
|
|
14324
|
+
"div",
|
|
14325
|
+
{
|
|
14326
|
+
className: "uf-flex uf-items-start uf-gap-2.5 uf-p-3 uf-rounded-xl",
|
|
14327
|
+
style: { backgroundColor: colors2.card, border: `1px solid ${colors2.border}` },
|
|
14328
|
+
children: [
|
|
14329
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)(import_lucide_react25.Wallet, { className: "uf-w-4 uf-h-4 uf-flex-shrink-0 uf-mt-0.5", style: { color: colors2.warning } }),
|
|
14330
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)("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." })
|
|
14331
|
+
]
|
|
14332
|
+
}
|
|
14333
|
+
),
|
|
14334
|
+
isWalletMatch && connectedWalletName ? /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
|
|
14335
|
+
"button",
|
|
14336
|
+
{
|
|
14337
|
+
type: "button",
|
|
14338
|
+
onClick: handleWithdraw,
|
|
14339
|
+
disabled: !isFormValid || !canWithdraw || isSubmitting || !selectedToken || !selectedChain,
|
|
14340
|
+
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",
|
|
14341
|
+
style: {
|
|
14342
|
+
backgroundColor: colors2.primary,
|
|
14343
|
+
color: colors2.primaryForeground,
|
|
14344
|
+
fontFamily: fonts.medium,
|
|
14345
|
+
borderRadius: components.button.borderRadius,
|
|
14346
|
+
border: `${components.button.borderWidth}px solid ${components.button.borderColor}`
|
|
14347
|
+
},
|
|
14348
|
+
children: isSubmitting ? /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)(import_jsx_runtime54.Fragment, { children: [
|
|
14349
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)(import_lucide_react25.Loader2, { className: "uf-w-4 uf-h-4 uf-animate-spin" }),
|
|
14350
|
+
"Processing..."
|
|
14351
|
+
] }) : isOverBalance ? /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(import_jsx_runtime54.Fragment, { children: "Insufficient balance" }) : isBelowMinimum ? /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(import_jsx_runtime54.Fragment, { children: "Minimum amount not met" }) : submitError ? /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(import_jsx_runtime54.Fragment, { children: "Withdrawal failed. Try again" }) : /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)(import_jsx_runtime54.Fragment, { children: [
|
|
14352
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)(import_lucide_react25.Wallet, { className: "uf-w-4 uf-h-4" }),
|
|
14353
|
+
"Withdraw from ",
|
|
14354
|
+
connectedWalletName
|
|
14355
|
+
] })
|
|
14356
|
+
}
|
|
14357
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
|
|
14358
|
+
"button",
|
|
14359
|
+
{
|
|
14360
|
+
type: "button",
|
|
14361
|
+
onClick: handleWithdraw,
|
|
14362
|
+
disabled: !isFormValid || !canWithdraw || isSubmitting || !selectedToken || !selectedChain,
|
|
14363
|
+
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",
|
|
14364
|
+
style: {
|
|
14365
|
+
backgroundColor: colors2.primary,
|
|
14366
|
+
color: colors2.primaryForeground,
|
|
14367
|
+
fontFamily: fonts.medium,
|
|
14368
|
+
borderRadius: components.button.borderRadius,
|
|
14369
|
+
border: `${components.button.borderWidth}px solid ${components.button.borderColor}`
|
|
14370
|
+
},
|
|
14371
|
+
children: isSubmitting ? /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("span", { className: "uf-flex uf-items-center uf-justify-center uf-gap-2", children: [
|
|
14372
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)(import_lucide_react25.Loader2, { className: "uf-w-4 uf-h-4 uf-animate-spin" }),
|
|
14373
|
+
"Processing..."
|
|
14374
|
+
] }) : isOverBalance ? "Insufficient balance" : isBelowMinimum ? "Minimum amount not met" : submitError ? "Withdrawal failed. Try again" : t8.withdraw
|
|
14375
|
+
}
|
|
14376
|
+
),
|
|
14377
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("div", { className: "uf-flex uf-items-center uf-justify-between uf-text-xs uf-pt-1", children: [
|
|
14378
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)("div", { children: footerLeft }),
|
|
14379
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)(DepositFooterLinks, { onGlossaryClick: () => setGlossaryOpen(true) })
|
|
14380
|
+
] }),
|
|
14381
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
|
|
14382
|
+
GlossaryModal,
|
|
14383
|
+
{
|
|
14384
|
+
open: glossaryOpen,
|
|
14385
|
+
onOpenChange: setGlossaryOpen
|
|
14386
|
+
}
|
|
14387
|
+
)
|
|
14388
|
+
] });
|
|
14389
|
+
}
|
|
14390
|
+
|
|
14391
|
+
// src/components/withdrawals/WithdrawExecutionItem.tsx
|
|
14392
|
+
var import_lucide_react26 = require("lucide-react");
|
|
14393
|
+
var import_core33 = require("@unifold/core");
|
|
14394
|
+
var import_jsx_runtime55 = require("react/jsx-runtime");
|
|
14395
|
+
function WithdrawExecutionItem({
|
|
14396
|
+
execution,
|
|
14397
|
+
onClick
|
|
14398
|
+
}) {
|
|
14399
|
+
const { colors: colors2, fonts, components } = useTheme();
|
|
14400
|
+
const isPending = execution.status === import_core33.ExecutionStatus.PENDING || execution.status === import_core33.ExecutionStatus.WAITING || execution.status === import_core33.ExecutionStatus.DELAYED;
|
|
14401
|
+
const formatDateTime = (timestamp) => {
|
|
14402
|
+
try {
|
|
14403
|
+
const date = new Date(timestamp);
|
|
14404
|
+
const monthDay = date.toLocaleDateString("en-US", {
|
|
14405
|
+
month: "short",
|
|
14406
|
+
day: "numeric",
|
|
14407
|
+
year: "numeric"
|
|
14408
|
+
});
|
|
14409
|
+
const time = date.toLocaleTimeString("en-US", {
|
|
14410
|
+
hour: "numeric",
|
|
14411
|
+
minute: "2-digit",
|
|
14412
|
+
hour12: true
|
|
14413
|
+
}).toLowerCase();
|
|
14414
|
+
return `${monthDay} at ${time}`;
|
|
14415
|
+
} catch {
|
|
14416
|
+
return timestamp;
|
|
14417
|
+
}
|
|
14418
|
+
};
|
|
14419
|
+
const formatUsdAmount2 = (sourceAmountUsd) => {
|
|
14420
|
+
try {
|
|
14421
|
+
const amount = Number(sourceAmountUsd);
|
|
14422
|
+
return new Intl.NumberFormat("en-US", {
|
|
14423
|
+
style: "currency",
|
|
14424
|
+
currency: "USD",
|
|
14425
|
+
minimumFractionDigits: 2,
|
|
14426
|
+
maximumFractionDigits: 2
|
|
14427
|
+
}).format(amount);
|
|
14428
|
+
} catch {
|
|
14429
|
+
return "$0.00";
|
|
14430
|
+
}
|
|
14431
|
+
};
|
|
14432
|
+
return /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)(
|
|
14433
|
+
"button",
|
|
14434
|
+
{
|
|
14435
|
+
onClick,
|
|
14436
|
+
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",
|
|
14437
|
+
style: {
|
|
14438
|
+
backgroundColor: components.card.backgroundColor,
|
|
14439
|
+
borderRadius: components.list.rowBorderRadius,
|
|
14440
|
+
border: `${components.card.borderWidth}px solid ${components.card.borderColor}`
|
|
14441
|
+
},
|
|
14442
|
+
children: [
|
|
14443
|
+
/* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { className: "uf-relative uf-flex-shrink-0 uf-w-9 uf-h-9", children: [
|
|
14444
|
+
/* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
|
|
14445
|
+
"img",
|
|
14446
|
+
{
|
|
14447
|
+
src: execution.destination_token_metadata?.icon_url || (0, import_core33.getIconUrl)("/icons/tokens/svg/usdc.svg"),
|
|
14448
|
+
alt: "Token",
|
|
14449
|
+
width: 36,
|
|
14450
|
+
height: 36,
|
|
14451
|
+
loading: "lazy",
|
|
14452
|
+
className: "uf-rounded-full uf-w-9 uf-h-9"
|
|
14453
|
+
}
|
|
14454
|
+
),
|
|
14455
|
+
isPending ? /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
|
|
14456
|
+
"div",
|
|
14457
|
+
{
|
|
14458
|
+
className: "uf-absolute -uf-bottom-0.5 -uf-right-0.5 uf-rounded-full uf-p-0.5",
|
|
14459
|
+
style: { backgroundColor: colors2.warning },
|
|
14460
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
|
|
14461
|
+
"svg",
|
|
14462
|
+
{
|
|
14463
|
+
width: "10",
|
|
14464
|
+
height: "10",
|
|
14465
|
+
viewBox: "0 0 12 12",
|
|
14466
|
+
fill: "none",
|
|
14467
|
+
className: "uf-animate-spin uf-block",
|
|
14468
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
|
|
14469
|
+
"path",
|
|
14470
|
+
{
|
|
14471
|
+
d: "M6 1V3M6 9V11M1 6H3M9 6H11M2.5 2.5L4 4M8 8L9.5 9.5M2.5 9.5L4 8M8 4L9.5 2.5",
|
|
14472
|
+
stroke: "white",
|
|
14473
|
+
strokeWidth: "2",
|
|
14474
|
+
strokeLinecap: "round"
|
|
14475
|
+
}
|
|
14476
|
+
)
|
|
14477
|
+
}
|
|
14478
|
+
)
|
|
14479
|
+
}
|
|
14480
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
|
|
14481
|
+
"div",
|
|
14482
|
+
{
|
|
14483
|
+
className: "uf-absolute -uf-bottom-0.5 -uf-right-0.5 uf-rounded-full uf-p-0.5",
|
|
14484
|
+
style: { backgroundColor: colors2.success },
|
|
14485
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
|
|
14486
|
+
"svg",
|
|
14487
|
+
{
|
|
14488
|
+
width: "10",
|
|
14489
|
+
height: "10",
|
|
14490
|
+
viewBox: "0 0 12 12",
|
|
14491
|
+
fill: "none",
|
|
14492
|
+
className: "uf-block",
|
|
14493
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
|
|
14494
|
+
"path",
|
|
14495
|
+
{
|
|
14496
|
+
d: "M10 3L4.5 8.5L2 6",
|
|
14497
|
+
stroke: "white",
|
|
14498
|
+
strokeWidth: "2",
|
|
14499
|
+
strokeLinecap: "round",
|
|
14500
|
+
strokeLinejoin: "round"
|
|
14501
|
+
}
|
|
14502
|
+
)
|
|
14503
|
+
}
|
|
14504
|
+
)
|
|
14505
|
+
}
|
|
14506
|
+
)
|
|
14507
|
+
] }),
|
|
14508
|
+
/* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { className: "uf-flex-1 uf-min-w-0", children: [
|
|
14509
|
+
/* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
|
|
14510
|
+
"h3",
|
|
14511
|
+
{
|
|
14512
|
+
className: "uf-font-medium uf-text-sm uf-leading-tight",
|
|
14513
|
+
style: {
|
|
14514
|
+
color: components.card.titleColor,
|
|
14515
|
+
fontFamily: fonts.medium
|
|
14516
|
+
},
|
|
14517
|
+
children: isPending ? "Withdrawal processing" : "Withdrawal completed"
|
|
14518
|
+
}
|
|
14519
|
+
),
|
|
14520
|
+
/* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
|
|
14521
|
+
"p",
|
|
14522
|
+
{
|
|
14523
|
+
className: "uf-text-xs uf-leading-tight",
|
|
14524
|
+
style: {
|
|
14525
|
+
color: components.card.subtitleColor,
|
|
14526
|
+
fontFamily: fonts.regular
|
|
14527
|
+
},
|
|
14528
|
+
children: formatDateTime(execution.created_at || (/* @__PURE__ */ new Date()).toISOString())
|
|
14529
|
+
}
|
|
14530
|
+
)
|
|
14531
|
+
] }),
|
|
14532
|
+
/* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
|
|
14533
|
+
"span",
|
|
14534
|
+
{
|
|
14535
|
+
className: "uf-font-medium uf-text-sm uf-flex-shrink-0",
|
|
14536
|
+
style: {
|
|
14537
|
+
color: components.card.textRightColor,
|
|
14538
|
+
fontFamily: fonts.medium
|
|
14539
|
+
},
|
|
14540
|
+
children: formatUsdAmount2(execution.source_amount_usd || "0")
|
|
14541
|
+
}
|
|
14542
|
+
),
|
|
14543
|
+
/* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
|
|
14544
|
+
import_lucide_react26.ChevronRight,
|
|
14545
|
+
{
|
|
14546
|
+
className: "uf-w-4 uf-h-4 uf-flex-shrink-0",
|
|
14547
|
+
style: { color: components.card.actionColor }
|
|
14548
|
+
}
|
|
14549
|
+
)
|
|
14550
|
+
]
|
|
14551
|
+
}
|
|
14552
|
+
);
|
|
14553
|
+
}
|
|
14554
|
+
|
|
14555
|
+
// src/components/withdrawals/WithdrawConfirmingView.tsx
|
|
14556
|
+
var import_react22 = require("react");
|
|
14557
|
+
var import_jsx_runtime56 = require("react/jsx-runtime");
|
|
14558
|
+
function truncateAddress4(addr) {
|
|
14559
|
+
if (addr.length <= 12) return addr;
|
|
14560
|
+
return `${addr.slice(0, 6)}...${addr.slice(-4)}`;
|
|
14561
|
+
}
|
|
14562
|
+
var SHOW_BUTTON_DELAY_MS = 5e3;
|
|
14563
|
+
function WithdrawConfirmingView({
|
|
14564
|
+
txInfo,
|
|
14565
|
+
executions,
|
|
14566
|
+
onClose,
|
|
14567
|
+
onViewTracker
|
|
14568
|
+
}) {
|
|
14569
|
+
const { colors: colors2, fonts, components } = useTheme();
|
|
14570
|
+
const [showButton, setShowButton] = (0, import_react22.useState)(false);
|
|
14571
|
+
const latestExecution = executions.length > 0 ? executions[executions.length - 1] : null;
|
|
14572
|
+
(0, import_react22.useEffect)(() => {
|
|
14573
|
+
if (latestExecution) return;
|
|
14574
|
+
const timer = setTimeout(() => setShowButton(true), SHOW_BUTTON_DELAY_MS);
|
|
14575
|
+
return () => clearTimeout(timer);
|
|
14576
|
+
}, [latestExecution]);
|
|
14577
|
+
const btnRadius = components.button.borderRadius;
|
|
14578
|
+
const btnBorder = `${components.button.borderWidth}px solid ${components.button.borderColor}`;
|
|
14579
|
+
if (latestExecution) {
|
|
14580
|
+
return /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(import_jsx_runtime56.Fragment, { children: [
|
|
14581
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(DepositHeader, { title: "Withdrawal Details", showClose: true, onClose }),
|
|
14582
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(DepositDetailContent, { execution: latestExecution, variant: "withdraw" }),
|
|
14583
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: "uf-flex uf-gap-2 uf-px-2 uf-pt-2", children: [
|
|
14584
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
|
|
14585
|
+
"button",
|
|
14586
|
+
{
|
|
14587
|
+
type: "button",
|
|
14588
|
+
onClick: onViewTracker,
|
|
14589
|
+
className: "uf-flex-1 uf-py-2.5 uf-text-sm uf-transition-colors hover:uf-opacity-90",
|
|
14590
|
+
style: {
|
|
14591
|
+
backgroundColor: components.button.secondaryBackground,
|
|
14592
|
+
color: components.button.secondaryText,
|
|
14593
|
+
fontFamily: fonts.medium,
|
|
14594
|
+
borderRadius: btnRadius,
|
|
14595
|
+
border: btnBorder
|
|
14596
|
+
},
|
|
14597
|
+
children: "Withdrawal History"
|
|
14598
|
+
}
|
|
14599
|
+
),
|
|
14600
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
|
|
14601
|
+
"button",
|
|
14602
|
+
{
|
|
14603
|
+
type: "button",
|
|
14604
|
+
onClick: onClose,
|
|
14605
|
+
className: "uf-flex-1 uf-py-2.5 uf-text-sm uf-transition-colors hover:uf-opacity-90",
|
|
14606
|
+
style: {
|
|
14607
|
+
backgroundColor: components.button.primaryBackground,
|
|
14608
|
+
color: components.button.primaryText,
|
|
14609
|
+
fontFamily: fonts.medium,
|
|
14610
|
+
borderRadius: btnRadius,
|
|
14611
|
+
border: btnBorder
|
|
14612
|
+
},
|
|
14613
|
+
children: "Close"
|
|
14614
|
+
}
|
|
14615
|
+
)
|
|
14616
|
+
] }),
|
|
14617
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)("div", { className: "uf-pt-3", children: /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
|
|
14618
|
+
PoweredByUnifold,
|
|
14619
|
+
{
|
|
14620
|
+
color: colors2.foregroundMuted,
|
|
14621
|
+
className: "uf-flex uf-justify-center uf-shrink-0"
|
|
14622
|
+
}
|
|
14623
|
+
) })
|
|
14624
|
+
] });
|
|
14625
|
+
}
|
|
14626
|
+
return /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(import_jsx_runtime56.Fragment, { children: [
|
|
14627
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(DepositHeader, { title: "Withdrawal Status", showClose: true, onClose }),
|
|
14628
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: "uf-flex uf-flex-col uf-items-center uf-justify-center uf-py-16 uf-px-4", children: [
|
|
14629
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
|
|
14630
|
+
"div",
|
|
14631
|
+
{
|
|
14632
|
+
className: "uf-w-20 uf-h-20 uf-rounded-full uf-flex uf-items-center uf-justify-center uf-mb-6",
|
|
14633
|
+
style: { backgroundColor: `${colors2.primary}20` },
|
|
14634
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
|
|
14635
|
+
"svg",
|
|
14636
|
+
{
|
|
14637
|
+
width: "40",
|
|
14638
|
+
height: "40",
|
|
14639
|
+
viewBox: "0 0 24 24",
|
|
14640
|
+
fill: "none",
|
|
14641
|
+
className: "uf-animate-spin",
|
|
14642
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
|
|
14643
|
+
"path",
|
|
14644
|
+
{
|
|
14645
|
+
d: "M21 12a9 9 0 1 1-6.22-8.56",
|
|
14646
|
+
stroke: colors2.primary,
|
|
14647
|
+
strokeWidth: "2.5",
|
|
14648
|
+
strokeLinecap: "round"
|
|
14649
|
+
}
|
|
14650
|
+
)
|
|
14651
|
+
}
|
|
14652
|
+
)
|
|
14653
|
+
}
|
|
14654
|
+
),
|
|
14655
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
|
|
14656
|
+
"h3",
|
|
14657
|
+
{
|
|
14658
|
+
className: "uf-text-xl uf-mb-2",
|
|
14659
|
+
style: { color: colors2.foreground, fontFamily: fonts.medium },
|
|
14660
|
+
children: "Checking Withdrawal"
|
|
14661
|
+
}
|
|
14662
|
+
),
|
|
14663
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(
|
|
14664
|
+
"p",
|
|
14665
|
+
{
|
|
14666
|
+
className: "uf-text-sm uf-text-center",
|
|
14667
|
+
style: { color: colors2.foregroundMuted, fontFamily: fonts.regular },
|
|
14668
|
+
children: [
|
|
14669
|
+
txInfo.amount,
|
|
14670
|
+
" ",
|
|
14671
|
+
txInfo.sourceTokenSymbol,
|
|
14672
|
+
" to",
|
|
14673
|
+
" ",
|
|
14674
|
+
truncateAddress4(txInfo.recipientAddress)
|
|
14675
|
+
]
|
|
14676
|
+
}
|
|
14677
|
+
)
|
|
14678
|
+
] }),
|
|
14679
|
+
showButton && /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("div", { className: "uf-px-1 uf-pb-1", children: /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
|
|
14680
|
+
"button",
|
|
14681
|
+
{
|
|
14682
|
+
type: "button",
|
|
14683
|
+
onClick: onViewTracker,
|
|
14684
|
+
className: "uf-w-full uf-py-2.5 uf-text-sm uf-transition-colors hover:uf-opacity-90",
|
|
14685
|
+
style: {
|
|
14686
|
+
backgroundColor: components.button.secondaryBackground,
|
|
14687
|
+
color: components.button.secondaryText,
|
|
14688
|
+
fontFamily: fonts.medium,
|
|
14689
|
+
borderRadius: btnRadius,
|
|
14690
|
+
border: btnBorder
|
|
14691
|
+
},
|
|
14692
|
+
children: "Withdrawal History"
|
|
14693
|
+
}
|
|
14694
|
+
) }),
|
|
14695
|
+
/* @__PURE__ */ (0, import_jsx_runtime56.jsx)("div", { className: "uf-pt-3", children: /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
|
|
14696
|
+
PoweredByUnifold,
|
|
14697
|
+
{
|
|
14698
|
+
color: colors2.foregroundMuted,
|
|
14699
|
+
className: "uf-flex uf-justify-center uf-shrink-0"
|
|
14700
|
+
}
|
|
14701
|
+
) })
|
|
14702
|
+
] });
|
|
14703
|
+
}
|
|
14704
|
+
|
|
14705
|
+
// src/components/withdrawals/WithdrawModal.tsx
|
|
14706
|
+
var import_core34 = require("@unifold/core");
|
|
14707
|
+
var import_jsx_runtime57 = require("react/jsx-runtime");
|
|
14708
|
+
var t9 = i18n.withdrawModal;
|
|
14709
|
+
var getChainKey5 = (chainId, chainType) => `${chainType}:${chainId}`;
|
|
14710
|
+
function WithdrawModal({
|
|
14711
|
+
open,
|
|
14712
|
+
onOpenChange,
|
|
14713
|
+
publishableKey,
|
|
14714
|
+
modalTitle,
|
|
14715
|
+
externalUserId,
|
|
14716
|
+
sourceChainType,
|
|
14717
|
+
sourceChainId,
|
|
14718
|
+
sourceTokenAddress,
|
|
14719
|
+
sourceTokenSymbol,
|
|
14720
|
+
recipientAddress: recipientAddressProp,
|
|
14721
|
+
senderAddress,
|
|
14722
|
+
onWithdraw,
|
|
14723
|
+
onWithdrawSuccess,
|
|
14724
|
+
onWithdrawError,
|
|
14725
|
+
theme = "dark",
|
|
14726
|
+
hideOverlay = false
|
|
14727
|
+
}) {
|
|
14728
|
+
const { colors: colors2, fonts, components } = useTheme();
|
|
14729
|
+
const [containerEl, setContainerEl] = (0, import_react23.useState)(null);
|
|
14730
|
+
const containerCallbackRef = (0, import_react23.useCallback)((el) => {
|
|
14731
|
+
setContainerEl(el);
|
|
14732
|
+
}, []);
|
|
14733
|
+
const [resolvedTheme, setResolvedTheme] = (0, import_react23.useState)(
|
|
14734
|
+
theme === "auto" ? "dark" : theme
|
|
14735
|
+
);
|
|
14736
|
+
(0, import_react23.useEffect)(() => {
|
|
14737
|
+
if (theme === "auto") {
|
|
14738
|
+
const mq = window.matchMedia("(prefers-color-scheme: dark)");
|
|
14739
|
+
setResolvedTheme(mq.matches ? "dark" : "light");
|
|
14740
|
+
const h = (e) => setResolvedTheme(e.matches ? "dark" : "light");
|
|
14741
|
+
mq.addEventListener("change", h);
|
|
14742
|
+
return () => mq.removeEventListener("change", h);
|
|
14743
|
+
}
|
|
14744
|
+
setResolvedTheme(theme);
|
|
14745
|
+
}, [theme]);
|
|
14746
|
+
const themeClass = resolvedTheme === "dark" ? "uf-dark" : "";
|
|
14747
|
+
const { data: tokensResponse, isLoading: tokensLoading } = useSupportedDestinationTokens(publishableKey, open);
|
|
14748
|
+
const destinationTokens = tokensResponse?.data ?? [];
|
|
14749
|
+
const { data: sourceValidation, isLoading: isCheckingSourceToken } = useSourceTokenValidation({
|
|
14750
|
+
sourceChainType,
|
|
14751
|
+
sourceChainId,
|
|
14752
|
+
sourceTokenAddress,
|
|
14753
|
+
sourceTokenSymbol,
|
|
14754
|
+
publishableKey,
|
|
14755
|
+
enabled: open
|
|
14756
|
+
});
|
|
14757
|
+
const { data: balanceData, isLoading: isLoadingBalance } = useAddressBalance({
|
|
14758
|
+
address: senderAddress,
|
|
14759
|
+
chainType: sourceChainType,
|
|
14760
|
+
chainId: sourceChainId,
|
|
14761
|
+
tokenAddress: sourceTokenAddress,
|
|
14762
|
+
publishableKey,
|
|
14763
|
+
enabled: open
|
|
14764
|
+
});
|
|
14765
|
+
const [selectedToken, setSelectedToken] = (0, import_react23.useState)(null);
|
|
14766
|
+
const [selectedChain, setSelectedChain] = (0, import_react23.useState)(null);
|
|
14767
|
+
const [detectedWallet, setDetectedWallet] = (0, import_react23.useState)(null);
|
|
14768
|
+
const connectedWalletName = detectedWallet?.name ?? null;
|
|
14769
|
+
const isWalletMatch = !!detectedWallet;
|
|
14770
|
+
(0, import_react23.useEffect)(() => {
|
|
14771
|
+
if (!senderAddress || !open) {
|
|
14772
|
+
setDetectedWallet(null);
|
|
14773
|
+
return;
|
|
14774
|
+
}
|
|
14775
|
+
let cancelled = false;
|
|
14776
|
+
detectBrowserWallet(sourceChainType, senderAddress).then((wallet) => {
|
|
14777
|
+
if (!cancelled) setDetectedWallet(wallet);
|
|
14778
|
+
});
|
|
14779
|
+
return () => {
|
|
14780
|
+
cancelled = true;
|
|
14781
|
+
};
|
|
14782
|
+
}, [senderAddress, sourceChainType, open]);
|
|
14783
|
+
const [view, setView] = (0, import_react23.useState)("form");
|
|
14784
|
+
const [withdrawDepositWalletId, setWithdrawDepositWalletId] = (0, import_react23.useState)();
|
|
14785
|
+
const [selectedExecution, setSelectedExecution] = (0, import_react23.useState)(null);
|
|
14786
|
+
const [submittedTxInfo, setSubmittedTxInfo] = (0, import_react23.useState)(null);
|
|
14787
|
+
const { executions: realtimeExecutions } = useWithdrawPolling({
|
|
14788
|
+
userId: externalUserId,
|
|
14789
|
+
publishableKey,
|
|
14790
|
+
depositWalletId: withdrawDepositWalletId,
|
|
14791
|
+
enabled: !!withdrawDepositWalletId && open,
|
|
14792
|
+
onWithdrawSuccess: onWithdrawSuccess ? (d) => onWithdrawSuccess({ message: d.message, transaction: d.transaction }) : void 0,
|
|
14793
|
+
onWithdrawError
|
|
14794
|
+
});
|
|
14795
|
+
const { data: allWithdrawalsData } = useExecutions(externalUserId, publishableKey, {
|
|
14796
|
+
actionType: import_core34.ActionType.Withdraw,
|
|
14797
|
+
enabled: open,
|
|
14798
|
+
refetchInterval: view === "tracker" || view === "detail" ? 5e3 : 15e3
|
|
14799
|
+
});
|
|
14800
|
+
const allWithdrawals = allWithdrawalsData?.data ?? [];
|
|
14801
|
+
const handleDepositWalletCreation = (0, import_react23.useCallback)(async (params) => {
|
|
14802
|
+
const { data: wallets } = await (0, import_core34.createDepositAddress)(
|
|
14803
|
+
{
|
|
14804
|
+
external_user_id: externalUserId,
|
|
14805
|
+
destination_chain_type: params.destinationChainType,
|
|
14806
|
+
destination_chain_id: params.destinationChainId,
|
|
14807
|
+
destination_token_address: params.destinationTokenAddress,
|
|
14808
|
+
recipient_address: params.recipientAddress,
|
|
14809
|
+
action_type: import_core34.ActionType.Withdraw
|
|
14810
|
+
},
|
|
14811
|
+
publishableKey
|
|
14812
|
+
);
|
|
14813
|
+
const depositWallet = (0, import_core34.getWalletByChainType)(wallets, sourceChainType);
|
|
14814
|
+
if (!depositWallet) {
|
|
14815
|
+
throw new Error(`No deposit wallet available for ${sourceChainType}`);
|
|
14816
|
+
}
|
|
14817
|
+
setWithdrawDepositWalletId(depositWallet.id);
|
|
14818
|
+
return depositWallet;
|
|
14819
|
+
}, [externalUserId, publishableKey, sourceChainType]);
|
|
14820
|
+
const handleWithdrawSubmitted = (0, import_react23.useCallback)((txInfo) => {
|
|
14821
|
+
setSubmittedTxInfo(txInfo);
|
|
14822
|
+
setView("confirming");
|
|
14823
|
+
}, []);
|
|
14824
|
+
(0, import_react23.useEffect)(() => {
|
|
14825
|
+
if (!destinationTokens.length || selectedToken) return;
|
|
14826
|
+
const first = destinationTokens[0];
|
|
14827
|
+
if (first?.chains.length > 0) {
|
|
14828
|
+
setSelectedToken(first);
|
|
14829
|
+
setSelectedChain(first.chains[0]);
|
|
14830
|
+
}
|
|
14831
|
+
}, [destinationTokens, selectedToken]);
|
|
14832
|
+
const resetViewTimeoutRef = (0, import_react23.useRef)(null);
|
|
14833
|
+
const handleClose = (0, import_react23.useCallback)(() => {
|
|
14834
|
+
onOpenChange(false);
|
|
14835
|
+
if (resetViewTimeoutRef.current) clearTimeout(resetViewTimeoutRef.current);
|
|
14836
|
+
resetViewTimeoutRef.current = setTimeout(() => {
|
|
14837
|
+
setSelectedToken(null);
|
|
14838
|
+
setSelectedChain(null);
|
|
14839
|
+
setView("form");
|
|
14840
|
+
setSelectedExecution(null);
|
|
14841
|
+
setSubmittedTxInfo(null);
|
|
14842
|
+
setWithdrawDepositWalletId(void 0);
|
|
14843
|
+
resetViewTimeoutRef.current = null;
|
|
14844
|
+
}, 200);
|
|
14845
|
+
}, [onOpenChange]);
|
|
14846
|
+
(0, import_react23.useLayoutEffect)(() => {
|
|
14847
|
+
if (!open) return;
|
|
14848
|
+
if (resetViewTimeoutRef.current) {
|
|
14849
|
+
clearTimeout(resetViewTimeoutRef.current);
|
|
14850
|
+
resetViewTimeoutRef.current = null;
|
|
14851
|
+
}
|
|
14852
|
+
setSelectedToken(null);
|
|
14853
|
+
setSelectedChain(null);
|
|
14854
|
+
setView("form");
|
|
14855
|
+
setSelectedExecution(null);
|
|
14856
|
+
setSubmittedTxInfo(null);
|
|
14857
|
+
setWithdrawDepositWalletId(void 0);
|
|
14858
|
+
}, [open]);
|
|
14859
|
+
(0, import_react23.useEffect)(() => () => {
|
|
14860
|
+
if (resetViewTimeoutRef.current) clearTimeout(resetViewTimeoutRef.current);
|
|
14861
|
+
}, []);
|
|
14862
|
+
const handleTokenSymbolChange = (0, import_react23.useCallback)((symbol) => {
|
|
14863
|
+
const tok = destinationTokens.find((t11) => t11.symbol === symbol);
|
|
14864
|
+
if (tok) {
|
|
14865
|
+
setSelectedToken(tok);
|
|
14866
|
+
if (tok.chains.length > 0) setSelectedChain(tok.chains[0]);
|
|
14867
|
+
}
|
|
14868
|
+
}, [destinationTokens]);
|
|
14869
|
+
const handleChainKeyChange = (0, import_react23.useCallback)((chainKey) => {
|
|
14870
|
+
if (!selectedToken) return;
|
|
14871
|
+
const chain = selectedToken.chains.find((c) => getChainKey5(c.chain_id, c.chain_type) === chainKey);
|
|
14872
|
+
if (chain) setSelectedChain(chain);
|
|
14873
|
+
}, [selectedToken]);
|
|
14874
|
+
const isSourceSupported = sourceValidation?.isSupported ?? null;
|
|
14875
|
+
const canWithdraw = !!onWithdraw || isWalletMatch;
|
|
14876
|
+
const isAnyLoading = tokensLoading || isCheckingSourceToken;
|
|
14877
|
+
const withdrawPoweredByFooter = /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("div", { className: "uf-pt-3", children: /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(PoweredByUnifold, { color: colors2.foregroundMuted, className: "uf-flex uf-justify-center uf-shrink-0" }) });
|
|
14878
|
+
return /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(PortalContainerProvider, { value: hideOverlay ? containerEl : null, children: /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(Dialog, { open: hideOverlay || open, onOpenChange: hideOverlay ? void 0 : handleClose, modal: !hideOverlay, children: /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
|
|
14879
|
+
DialogContent,
|
|
14880
|
+
{
|
|
14881
|
+
ref: hideOverlay ? containerCallbackRef : void 0,
|
|
14882
|
+
hideOverlay,
|
|
14883
|
+
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}`}`,
|
|
14884
|
+
style: { backgroundColor: colors2.background },
|
|
14885
|
+
onPointerDownOutside: (e) => e.preventDefault(),
|
|
14886
|
+
onInteractOutside: (e) => e.preventDefault(),
|
|
14887
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(ThemeStyleInjector, { children: view === "confirming" && submittedTxInfo ? /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
|
|
14888
|
+
WithdrawConfirmingView,
|
|
14889
|
+
{
|
|
14890
|
+
txInfo: submittedTxInfo,
|
|
14891
|
+
executions: realtimeExecutions,
|
|
14892
|
+
onClose: handleClose,
|
|
14893
|
+
onViewTracker: () => setView("tracker")
|
|
14894
|
+
}
|
|
14895
|
+
) : view === "detail" && selectedExecution ? /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)(import_jsx_runtime57.Fragment, { children: [
|
|
14896
|
+
/* @__PURE__ */ (0, import_jsx_runtime57.jsx)(DepositHeader, { title: "Withdrawal Details", showBack: true, showClose: !hideOverlay, onBack: () => {
|
|
14897
|
+
setSelectedExecution(null);
|
|
14898
|
+
setView("tracker");
|
|
14899
|
+
}, onClose: handleClose }),
|
|
14900
|
+
/* @__PURE__ */ (0, import_jsx_runtime57.jsx)(DepositDetailContent, { execution: selectedExecution, variant: "withdraw" }),
|
|
14901
|
+
withdrawPoweredByFooter
|
|
14902
|
+
] }) : view === "tracker" ? (
|
|
14903
|
+
/* ---------- Tracker view: execution list ---------- */
|
|
14904
|
+
/* @__PURE__ */ (0, import_jsx_runtime57.jsxs)(import_jsx_runtime57.Fragment, { children: [
|
|
14905
|
+
/* @__PURE__ */ (0, import_jsx_runtime57.jsx)(DepositHeader, { title: "Withdrawal History", showBack: true, showClose: !hideOverlay, onBack: () => setView("form"), onClose: handleClose }),
|
|
14906
|
+
/* @__PURE__ */ (0, import_jsx_runtime57.jsx)("div", { className: "uf-flex uf-flex-col uf-gap-2", style: { minHeight: 200 }, children: allWithdrawals.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("div", { className: "uf-flex uf-items-center uf-justify-center uf-py-8", children: /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("p", { className: "uf-text-sm", style: { color: colors2.foregroundMuted, fontFamily: fonts.regular }, children: "No withdrawals to track yet" }) }) : allWithdrawals.map((ex) => /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
|
|
14907
|
+
WithdrawExecutionItem,
|
|
14908
|
+
{
|
|
14909
|
+
execution: ex,
|
|
14910
|
+
onClick: () => {
|
|
14911
|
+
setSelectedExecution(ex);
|
|
14912
|
+
setView("detail");
|
|
14913
|
+
}
|
|
14914
|
+
},
|
|
14915
|
+
ex.id
|
|
14916
|
+
)) }),
|
|
14917
|
+
withdrawPoweredByFooter
|
|
14918
|
+
] })
|
|
14919
|
+
) : (
|
|
14920
|
+
/* ---------- Form view (default) ---------- */
|
|
14921
|
+
/* @__PURE__ */ (0, import_jsx_runtime57.jsxs)(import_jsx_runtime57.Fragment, { children: [
|
|
14922
|
+
/* @__PURE__ */ (0, import_jsx_runtime57.jsx)(DepositHeader, { title: modalTitle || t9.title, showClose: !hideOverlay, onClose: handleClose }),
|
|
14923
|
+
/* @__PURE__ */ (0, import_jsx_runtime57.jsxs)("div", { className: "uf-flex uf-flex-col uf-gap-3", children: [
|
|
14924
|
+
isAnyLoading ? /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("div", { className: "uf-space-y-3", children: [1, 2, 3].map((i) => /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("div", { className: "uf-w-full uf-bg-secondary uf-rounded-xl uf-p-3 uf-flex uf-items-center uf-animate-pulse", children: /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("div", { className: "uf-bg-muted uf-rounded-lg uf-w-full uf-h-10" }) }, i)) }) : isSourceSupported === false ? /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)("div", { className: "uf-flex uf-flex-col uf-items-center uf-justify-center uf-py-8 uf-px-4 uf-text-center", children: [
|
|
14925
|
+
/* @__PURE__ */ (0, import_jsx_runtime57.jsx)("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__ */ (0, import_jsx_runtime57.jsx)(import_lucide_react27.AlertTriangle, { className: "uf-w-8 uf-h-8 uf-text-muted-foreground" }) }),
|
|
14926
|
+
/* @__PURE__ */ (0, import_jsx_runtime57.jsx)("h3", { className: "uf-text-lg uf-font-semibold uf-mb-2", style: { color: colors2.foreground, fontFamily: fonts.medium }, children: "Unsupported Source Token" }),
|
|
14927
|
+
/* @__PURE__ */ (0, import_jsx_runtime57.jsx)("p", { className: "uf-text-sm uf-max-w-[280px]", style: { color: colors2.foregroundMuted, fontFamily: fonts.regular }, children: sourceValidation?.errorMessage })
|
|
14928
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)(import_jsx_runtime57.Fragment, { children: [
|
|
14929
|
+
/* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
|
|
14930
|
+
WithdrawDoubleInput,
|
|
14931
|
+
{
|
|
14932
|
+
tokens: destinationTokens,
|
|
14933
|
+
selectedTokenSymbol: selectedToken?.symbol ?? null,
|
|
14934
|
+
selectedChainKey: selectedChain ? getChainKey5(selectedChain.chain_id, selectedChain.chain_type) : null,
|
|
14935
|
+
onTokenChange: handleTokenSymbolChange,
|
|
14936
|
+
onChainChange: handleChainKeyChange,
|
|
14937
|
+
isLoading: tokensLoading
|
|
14938
|
+
}
|
|
14939
|
+
),
|
|
14940
|
+
/* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
|
|
14941
|
+
WithdrawForm,
|
|
14942
|
+
{
|
|
14943
|
+
publishableKey,
|
|
14944
|
+
externalUserId,
|
|
14945
|
+
sourceChainType,
|
|
14946
|
+
selectedToken,
|
|
14947
|
+
selectedChain,
|
|
14948
|
+
sourceTokenSymbol,
|
|
14949
|
+
recipientAddressProp,
|
|
14950
|
+
balanceData: balanceData ?? null,
|
|
14951
|
+
isLoadingBalance,
|
|
14952
|
+
minimumWithdrawAmountUsd: sourceValidation?.minimumAmountUsd ?? null,
|
|
14953
|
+
estimatedProcessingTime: sourceValidation?.estimatedProcessingTime ?? null,
|
|
14954
|
+
maxSlippagePercent: sourceValidation?.maxSlippagePercent ?? null,
|
|
14955
|
+
priceImpactPercent: sourceValidation?.priceImpactPercent ?? null,
|
|
14956
|
+
detectedWallet,
|
|
14957
|
+
sourceChainId,
|
|
14958
|
+
sourceTokenAddress,
|
|
14959
|
+
isWalletMatch,
|
|
14960
|
+
connectedWalletName,
|
|
14961
|
+
canWithdraw,
|
|
14962
|
+
onWithdraw,
|
|
14963
|
+
onWithdrawError,
|
|
14964
|
+
onDepositWalletCreation: handleDepositWalletCreation,
|
|
14965
|
+
onWithdrawSubmitted: handleWithdrawSubmitted,
|
|
14966
|
+
footerLeft: /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)(
|
|
14967
|
+
"button",
|
|
14968
|
+
{
|
|
14969
|
+
onClick: () => setView("tracker"),
|
|
14970
|
+
className: "uf-flex uf-items-center uf-gap-1 uf-transition-colors hover:uf-opacity-70",
|
|
14971
|
+
style: { color: colors2.foregroundMuted },
|
|
14972
|
+
children: [
|
|
14973
|
+
/* @__PURE__ */ (0, import_jsx_runtime57.jsx)(import_lucide_react27.Clock, { className: "uf-w-3.5 uf-h-3.5" }),
|
|
14974
|
+
"Withdrawal History",
|
|
14975
|
+
/* @__PURE__ */ (0, import_jsx_runtime57.jsx)(import_lucide_react27.ChevronRight, { className: "uf-w-3 uf-h-3" })
|
|
14976
|
+
]
|
|
14977
|
+
}
|
|
14978
|
+
)
|
|
14979
|
+
}
|
|
14980
|
+
)
|
|
14981
|
+
] }),
|
|
14982
|
+
withdrawPoweredByFooter
|
|
14983
|
+
] })
|
|
14984
|
+
] })
|
|
14985
|
+
) })
|
|
14986
|
+
}
|
|
14987
|
+
) }) });
|
|
14988
|
+
}
|
|
14989
|
+
|
|
14990
|
+
// src/components/withdrawals/WithdrawTokenSelector.tsx
|
|
14991
|
+
var import_react24 = require("react");
|
|
14992
|
+
var import_lucide_react28 = require("lucide-react");
|
|
14993
|
+
var import_jsx_runtime58 = require("react/jsx-runtime");
|
|
14994
|
+
var t10 = i18n.withdrawModal;
|
|
14995
|
+
function WithdrawTokenSelector({
|
|
14996
|
+
tokens,
|
|
14997
|
+
onSelect,
|
|
14998
|
+
onBack
|
|
14999
|
+
}) {
|
|
15000
|
+
const { themeClass, colors: colors2, fonts, components } = useTheme();
|
|
15001
|
+
const [searchQuery, setSearchQuery] = (0, import_react24.useState)("");
|
|
15002
|
+
const [hoveredKey, setHoveredKey] = (0, import_react24.useState)(null);
|
|
15003
|
+
const allOptions = (0, import_react24.useMemo)(() => {
|
|
15004
|
+
const options = [];
|
|
15005
|
+
tokens.forEach((token) => {
|
|
15006
|
+
token.chains.forEach((chain) => {
|
|
15007
|
+
options.push({ token, chain });
|
|
15008
|
+
});
|
|
15009
|
+
});
|
|
15010
|
+
return options;
|
|
15011
|
+
}, [tokens]);
|
|
15012
|
+
const filteredOptions = (0, import_react24.useMemo)(() => {
|
|
15013
|
+
if (!searchQuery.trim()) return allOptions;
|
|
15014
|
+
const query = searchQuery.toLowerCase();
|
|
15015
|
+
return allOptions.filter(
|
|
15016
|
+
({ token, chain }) => token.symbol.toLowerCase().includes(query) || token.name.toLowerCase().includes(query) || chain.chain_name.toLowerCase().includes(query)
|
|
15017
|
+
);
|
|
15018
|
+
}, [allOptions, searchQuery]);
|
|
15019
|
+
return /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)(
|
|
15020
|
+
"div",
|
|
15021
|
+
{
|
|
15022
|
+
className: "uf-flex uf-flex-col",
|
|
15023
|
+
style: { minHeight: 0, flex: 1 },
|
|
15024
|
+
children: [
|
|
15025
|
+
/* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("div", { className: "uf-pb-3", children: [
|
|
15026
|
+
/* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
|
|
15027
|
+
"style",
|
|
15028
|
+
{
|
|
15029
|
+
dangerouslySetInnerHTML: {
|
|
15030
|
+
__html: `.uf-withdraw-token-search::placeholder { color: ${components.search.placeholderColor}; }`
|
|
15031
|
+
}
|
|
15032
|
+
}
|
|
15033
|
+
),
|
|
15034
|
+
/* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("div", { style: { position: "relative" }, children: [
|
|
15035
|
+
/* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
|
|
15036
|
+
import_lucide_react28.Search,
|
|
15037
|
+
{
|
|
15038
|
+
className: "uf-absolute uf-left-3 uf-top-1/2 uf--translate-y-1/2 uf-w-4 uf-h-4",
|
|
15039
|
+
style: { color: components.search.placeholderColor }
|
|
15040
|
+
}
|
|
15041
|
+
),
|
|
15042
|
+
/* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
|
|
15043
|
+
"input",
|
|
15044
|
+
{
|
|
15045
|
+
type: "text",
|
|
15046
|
+
placeholder: "Search token or network",
|
|
15047
|
+
value: searchQuery,
|
|
15048
|
+
onChange: (e) => setSearchQuery(e.target.value),
|
|
15049
|
+
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",
|
|
15050
|
+
style: {
|
|
15051
|
+
backgroundColor: components.search.backgroundColor,
|
|
15052
|
+
color: components.search.inputColor,
|
|
15053
|
+
fontFamily: fonts.regular,
|
|
15054
|
+
borderRadius: components.input.borderRadius,
|
|
15055
|
+
border: `${components.input.borderWidth}px solid ${components.input.borderColor}`
|
|
15056
|
+
}
|
|
15057
|
+
}
|
|
15058
|
+
)
|
|
15059
|
+
] })
|
|
15060
|
+
] }),
|
|
15061
|
+
/* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
|
|
15062
|
+
"div",
|
|
15063
|
+
{
|
|
15064
|
+
className: "uf-text-xs uf-mb-2",
|
|
15065
|
+
style: {
|
|
15066
|
+
color: components.list.titleSectionColor,
|
|
15067
|
+
fontFamily: fonts.medium
|
|
15068
|
+
},
|
|
15069
|
+
children: t10.selectToken
|
|
15070
|
+
}
|
|
15071
|
+
),
|
|
15072
|
+
/* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
|
|
15073
|
+
"div",
|
|
15074
|
+
{
|
|
15075
|
+
className: "uf-flex-1 uf-overflow-y-auto uf-min-h-0 uf--mx-6 uf-px-6 uf-pb-3",
|
|
15076
|
+
style: { scrollbarWidth: "none" },
|
|
15077
|
+
children: filteredOptions.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
|
|
15078
|
+
"div",
|
|
15079
|
+
{
|
|
15080
|
+
style: {
|
|
15081
|
+
textAlign: "center",
|
|
15082
|
+
padding: "2rem 0",
|
|
15083
|
+
fontSize: 14,
|
|
15084
|
+
color: components.container.subtitleColor,
|
|
15085
|
+
fontFamily: fonts.regular
|
|
15086
|
+
},
|
|
15087
|
+
children: t10.noTokensAvailable
|
|
15088
|
+
}
|
|
15089
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("div", { style: { display: "flex", flexDirection: "column", gap: 4 }, children: filteredOptions.map(({ token, chain }) => {
|
|
15090
|
+
const key = `${token.symbol}-${chain.chain_type}:${chain.chain_id}`;
|
|
15091
|
+
return /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)(
|
|
15092
|
+
"button",
|
|
15093
|
+
{
|
|
15094
|
+
type: "button",
|
|
15095
|
+
onClick: () => onSelect(token, chain),
|
|
15096
|
+
onMouseEnter: () => setHoveredKey(key),
|
|
15097
|
+
onMouseLeave: () => setHoveredKey(null),
|
|
15098
|
+
className: "uf-transition-colors",
|
|
15099
|
+
style: {
|
|
15100
|
+
width: "100%",
|
|
15101
|
+
display: "flex",
|
|
15102
|
+
alignItems: "center",
|
|
15103
|
+
gap: 12,
|
|
15104
|
+
padding: 12,
|
|
15105
|
+
borderRadius: 12,
|
|
15106
|
+
border: "none",
|
|
15107
|
+
cursor: "pointer",
|
|
15108
|
+
textAlign: "left",
|
|
15109
|
+
backgroundColor: hoveredKey === key ? colors2.cardHover : "transparent"
|
|
15110
|
+
},
|
|
15111
|
+
children: [
|
|
15112
|
+
/* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("div", { style: { position: "relative", flexShrink: 0 }, children: [
|
|
15113
|
+
/* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
|
|
15114
|
+
"img",
|
|
15115
|
+
{
|
|
15116
|
+
src: token.icon_url,
|
|
15117
|
+
alt: token.symbol,
|
|
15118
|
+
width: 40,
|
|
15119
|
+
height: 40,
|
|
15120
|
+
loading: "lazy",
|
|
15121
|
+
className: "uf-rounded-full"
|
|
15122
|
+
}
|
|
15123
|
+
),
|
|
15124
|
+
/* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
|
|
15125
|
+
"div",
|
|
15126
|
+
{
|
|
15127
|
+
style: {
|
|
15128
|
+
position: "absolute",
|
|
15129
|
+
bottom: -4,
|
|
15130
|
+
right: -4
|
|
15131
|
+
},
|
|
15132
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
|
|
15133
|
+
"img",
|
|
15134
|
+
{
|
|
15135
|
+
src: chain.icon_url,
|
|
15136
|
+
alt: chain.chain_name,
|
|
15137
|
+
width: 20,
|
|
15138
|
+
height: 20,
|
|
15139
|
+
loading: "lazy",
|
|
15140
|
+
className: "uf-rounded-full uf-border-2"
|
|
15141
|
+
}
|
|
15142
|
+
)
|
|
15143
|
+
}
|
|
15144
|
+
)
|
|
15145
|
+
] }),
|
|
15146
|
+
/* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("div", { style: { flex: 1, minWidth: 0 }, children: [
|
|
15147
|
+
/* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
|
|
15148
|
+
"div",
|
|
15149
|
+
{
|
|
15150
|
+
style: {
|
|
15151
|
+
fontSize: 14,
|
|
15152
|
+
fontWeight: 500,
|
|
15153
|
+
color: components.card.titleColor,
|
|
15154
|
+
fontFamily: fonts.medium
|
|
15155
|
+
},
|
|
15156
|
+
children: token.symbol
|
|
15157
|
+
}
|
|
15158
|
+
),
|
|
15159
|
+
/* @__PURE__ */ (0, import_jsx_runtime58.jsxs)(
|
|
15160
|
+
"div",
|
|
15161
|
+
{
|
|
15162
|
+
style: {
|
|
15163
|
+
fontSize: 12,
|
|
15164
|
+
color: components.card.subtitleColor,
|
|
15165
|
+
fontFamily: fonts.regular
|
|
15166
|
+
},
|
|
15167
|
+
children: [
|
|
15168
|
+
token.name,
|
|
15169
|
+
" \u2022 ",
|
|
15170
|
+
chain.chain_name
|
|
15171
|
+
]
|
|
15172
|
+
}
|
|
15173
|
+
)
|
|
15174
|
+
] })
|
|
15175
|
+
]
|
|
15176
|
+
},
|
|
15177
|
+
key
|
|
15178
|
+
);
|
|
15179
|
+
}) })
|
|
15180
|
+
}
|
|
15181
|
+
),
|
|
15182
|
+
/* @__PURE__ */ (0, import_jsx_runtime58.jsx)("div", { className: "uf-pt-3 uf-pb-2 uf-shrink-0", children: /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
|
|
15183
|
+
PoweredByUnifold,
|
|
15184
|
+
{
|
|
15185
|
+
color: colors2.foregroundMuted,
|
|
15186
|
+
className: "uf-flex uf-justify-center uf-shrink-0"
|
|
15187
|
+
}
|
|
15188
|
+
) })
|
|
15189
|
+
]
|
|
15190
|
+
}
|
|
15191
|
+
);
|
|
15192
|
+
}
|
|
12146
15193
|
// Annotate the CommonJS export names for ESM import in node:
|
|
12147
15194
|
0 && (module.exports = {
|
|
12148
15195
|
Button,
|
|
12149
15196
|
BuyWithCard,
|
|
15197
|
+
CheckoutModal,
|
|
12150
15198
|
ConfirmingView,
|
|
12151
15199
|
CurrencyListItem,
|
|
12152
15200
|
CurrencyListSection,
|
|
@@ -12170,6 +15218,7 @@ function DepositModal({
|
|
|
12170
15218
|
DialogPortal,
|
|
12171
15219
|
DialogTitle,
|
|
12172
15220
|
DialogTrigger,
|
|
15221
|
+
HYPERCORE_CHAIN_ID,
|
|
12173
15222
|
Select,
|
|
12174
15223
|
SelectContent,
|
|
12175
15224
|
SelectGroup,
|
|
@@ -12189,15 +15238,33 @@ function DepositModal({
|
|
|
12189
15238
|
TransferCryptoButton,
|
|
12190
15239
|
TransferCryptoDoubleInput,
|
|
12191
15240
|
TransferCryptoSingleInput,
|
|
15241
|
+
WithdrawConfirmingView,
|
|
15242
|
+
WithdrawDoubleInput,
|
|
15243
|
+
WithdrawExecutionItem,
|
|
15244
|
+
WithdrawForm,
|
|
15245
|
+
WithdrawModal,
|
|
15246
|
+
WithdrawTokenSelector,
|
|
12192
15247
|
buttonVariants,
|
|
12193
15248
|
cn,
|
|
12194
15249
|
colors,
|
|
12195
15250
|
defaultColors,
|
|
15251
|
+
detectBrowserWallet,
|
|
12196
15252
|
getColors,
|
|
15253
|
+
isHypercoreChain,
|
|
12197
15254
|
mergeColors,
|
|
12198
15255
|
resolveComponentTokens,
|
|
15256
|
+
sendEvmWithdraw,
|
|
15257
|
+
sendHypercoreWithdraw,
|
|
15258
|
+
sendSolanaWithdraw,
|
|
12199
15259
|
truncateAddress,
|
|
15260
|
+
useAddressBalance,
|
|
12200
15261
|
useAllowedCountry,
|
|
12201
15262
|
useDepositPolling,
|
|
12202
|
-
|
|
15263
|
+
useDepositQuote,
|
|
15264
|
+
usePaymentIntent,
|
|
15265
|
+
useSourceTokenValidation,
|
|
15266
|
+
useSupportedDestinationTokens,
|
|
15267
|
+
useTheme,
|
|
15268
|
+
useVerifyRecipientAddress,
|
|
15269
|
+
useWithdrawPolling
|
|
12203
15270
|
});
|