@oasisprotocol/privana-sdk 0.5.7 → 0.5.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +88 -7
- package/dist/{chunk-FFYLKZ7J.cjs → chunk-KCXYYUUG.cjs} +1228 -105
- package/dist/chunk-KCXYYUUG.cjs.map +1 -0
- package/dist/{chunk-4VOTSHNC.js → chunk-RDYNQUMV.js} +1220 -107
- package/dist/chunk-RDYNQUMV.js.map +1 -0
- package/dist/index.cjs +797 -317
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +1 -1
- package/dist/index.css.map +1 -1
- package/dist/index.d.cts +13 -5
- package/dist/index.d.ts +13 -5
- package/dist/index.js +560 -80
- package/dist/index.js.map +1 -1
- package/dist/on-ramp.cjs +11 -3
- package/dist/on-ramp.d.cts +61 -7
- package/dist/on-ramp.d.ts +61 -7
- package/dist/on-ramp.js +1 -1
- package/dist/{pending-lock-BIMYw4gd.d.cts → pending-lock-DIL2jCaT.d.cts} +33 -1
- package/dist/{pending-lock-BIMYw4gd.d.ts → pending-lock-DIL2jCaT.d.ts} +33 -1
- package/package.json +1 -1
- package/dist/chunk-4VOTSHNC.js.map +0 -1
- package/dist/chunk-FFYLKZ7J.cjs.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { usePrivanaContext, createHostedAuthPendingStorageKey, clearHostedAuthPendingTransaction, HostedAuthRequiredError, HostedAuthError, createPkceVerifier, createPkceChallenge, createHostedAuthState, persistHostedAuthPendingTransaction, parseHostedAuthCallback, readHostedAuthPendingTransaction, HostedAuthStateMismatchError, buildHostedAuthSession, useSafePrivanaContext, usePrivateReadRequest, formatTokenAmount, submitPendingLock, PostDepositLockError, useDepositVerification, useEnsureCorrectChain, getTransactionReceipt, getBlockNumber, waitForTransactionReceipt, canUseBrowserStorage, clampLockAmount, requireDepositLockOwner, getWalletClient, createSignedLockRequest, requireServiceAddress, signWithdrawMessage, signLockMessage, signTransferMessage, signTransferLockedMessage, signModifyLockMessage, cn, stripHostedAuthCallbackParams, AccountingApiError, getBrowserStorageItem, removeBrowserStorageItem, isSignedLockUsable, setBrowserStorageItem, canUseSharedBrowserStorage, DEFAULT_LOCK_DURATION_SECONDS, parseTokenAmount, Skeleton, shortenAddress, formatCountdown,
|
|
3
|
-
export { AccountingApiError, Button, DEFAULT_LOCK_DURATION_SECONDS, DEFAULT_ONRAMP_LOCK_BUFFER, HOSTED_AUTH_CLOCK_SKEW_MS, HostedAuthError, HostedAuthRequiredError, HostedAuthStateMismatchError, HttpClient, LOCK_TYPES, MODIFY_LOCK_TYPES, NETWORK_CONFIG, NetworkError, PostDepositLockError, PrivanaClient, PrivanaProvider, SUPPORTED_CHAINS, SiweAuthProvider, Skeleton, TRANSFER_LOCKED_TYPES, TRANSFER_TYPES, ValidationError, WITHDRAW_FROM_LOCK_TYPES, WITHDRAW_TYPES, applyLockBuffer, applyRefreshResponse, buildHostedAuthSession, buildSiweStatement, buttonVariants, clampLockAmount, clearHostedAuthPendingTransaction, clearPendingLock, createDomain, createHostedAuthPendingStorageKey, createHostedAuthState, createHostedAuthStorageKey, createLockExpiry, createPkceChallenge, createPkceVerifier, createSignedLockRequest, getAccountingContract, getApiUrl, getChainById, getChainId, getExplorerAddressUrl, getExplorerLabel, isHostedAuthRefreshActive, isHostedAuthSessionActive, isSignedLockUsable, loadPendingLock, normalizeAddress, normalizeHex, parseHostedAuthCallback, persistHostedAuthPendingTransaction, readHostedAuthPendingTransaction, readStoredHostedAuthSession, requireDepositLockOwner, requireServiceAddress, savePendingLock, signLockMessage, signModifyLockMessage, signTransferLockedMessage, signTransferMessage, signWithdrawFromLockMessage, signWithdrawMessage, stripHostedAuthCallbackParams, submitPendingLock, syncHostedAuthSessionToClient, useDepositVerification, usePrivanaContext, useSafeAccount, useSafePrivanaContext, useSiweAuth } from './chunk-
|
|
2
|
+
import { usePrivanaContext, createHostedAuthPendingStorageKey, clearHostedAuthPendingTransaction, HostedAuthRequiredError, HostedAuthError, createPkceVerifier, createPkceChallenge, createHostedAuthState, persistHostedAuthPendingTransaction, parseHostedAuthCallback, readHostedAuthPendingTransaction, HostedAuthStateMismatchError, buildHostedAuthSession, useSafePrivanaContext, usePrivateReadRequest, formatTokenAmount, submitPendingLock, PostDepositLockError, useDepositVerification, useEnsureCorrectChain, getTransactionReceipt, getBlockNumber, waitForTransactionReceipt, canUseBrowserStorage, clampLockAmount, requireDepositLockOwner, getWalletClient, createSignedLockRequest, requireServiceAddress, signWithdrawMessage, signLockMessage, signTransferMessage, signTransferLockedMessage, signModifyLockMessage, cn, stripHostedAuthCallbackParams, AccountingApiError, getBrowserStorageItem, removeBrowserStorageItem, isSignedLockUsable, setBrowserStorageItem, resolveProductOnRamp, matchesProductOnRampScope, createProductOnRampOutcomeCallbacks, canUseSharedBrowserStorage, DEFAULT_LOCK_DURATION_SECONDS, isMoonPayProductOnRamp, parseTokenAmount, Skeleton, createProductOnRampFlowSnapshot, shortenAddress, formatCountdown, getExplorerAddressUrl, getExplorerLabel, formatTimeRemaining, getSharedBrowserStorageItem, removeSharedBrowserStorageItem, setSharedBrowserStorageItem, matchesOnRampTransaction, useTransakOnRamp, getTransakMinimumTargetBaseUnits, matchesFrozenOnRampToken, Button, canRetryOnRampVerification, FiatOnRampForm } from './chunk-RDYNQUMV.js';
|
|
3
|
+
export { AccountingApiError, Button, DEFAULT_LOCK_DURATION_SECONDS, DEFAULT_ONRAMP_LOCK_BUFFER, HOSTED_AUTH_CLOCK_SKEW_MS, HostedAuthError, HostedAuthRequiredError, HostedAuthStateMismatchError, HttpClient, LOCK_TYPES, MODIFY_LOCK_TYPES, NETWORK_CONFIG, NetworkError, PostDepositLockError, PrivanaClient, PrivanaProvider, SUPPORTED_CHAINS, SiweAuthProvider, Skeleton, TRANSFER_LOCKED_TYPES, TRANSFER_TYPES, ValidationError, WITHDRAW_FROM_LOCK_TYPES, WITHDRAW_TYPES, applyLockBuffer, applyRefreshResponse, buildHostedAuthSession, buildSiweStatement, buttonVariants, clampLockAmount, clearHostedAuthPendingTransaction, clearPendingLock, createDomain, createHostedAuthPendingStorageKey, createHostedAuthState, createHostedAuthStorageKey, createLockExpiry, createPkceChallenge, createPkceVerifier, createSignedLockRequest, getAccountingContract, getApiUrl, getChainById, getChainId, getExplorerAddressUrl, getExplorerLabel, isHostedAuthRefreshActive, isHostedAuthSessionActive, isSignedLockUsable, loadPendingLock, normalizeAddress, normalizeHex, parseHostedAuthCallback, persistHostedAuthPendingTransaction, readHostedAuthPendingTransaction, readStoredHostedAuthSession, requireDepositLockOwner, requireServiceAddress, savePendingLock, signLockMessage, signModifyLockMessage, signTransferLockedMessage, signTransferMessage, signWithdrawFromLockMessage, signWithdrawMessage, stripHostedAuthCallbackParams, submitPendingLock, syncHostedAuthSessionToClient, useDepositVerification, usePrivanaContext, useSafeAccount, useSafePrivanaContext, useSiweAuth } from './chunk-RDYNQUMV.js';
|
|
4
4
|
import { useState, useRef, useMemo, useCallback, useContext, useEffect, useId } from 'react';
|
|
5
5
|
import { QueryClientContext, useQuery, useQueryClient, useMutation, keepPreviousData } from '@tanstack/react-query';
|
|
6
6
|
import { useAccount, useWalletClient, useConfig, useWriteContract, useSendTransaction, useBalance as useBalance$1, useReadContract } from 'wagmi';
|
|
7
|
-
import { zeroAddress, erc20Abi, formatUnits } from 'viem';
|
|
7
|
+
import { zeroAddress, erc20Abi, formatUnits, parseUnits } from 'viem';
|
|
8
8
|
import { MoonPayProvider, MoonPayContext } from '@moonpay/moonpay-react';
|
|
9
9
|
import * as DialogPrimitive from '@radix-ui/react-dialog';
|
|
10
|
-
import { XIcon } from 'lucide-react';
|
|
10
|
+
import { XIcon, CircleCheckIcon, Loader2 } from 'lucide-react';
|
|
11
11
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
12
12
|
import { toast } from 'sonner';
|
|
13
13
|
import { QRCodeSVG } from 'qrcode.react';
|
|
@@ -788,6 +788,7 @@ function useWithdraw(options = {}) {
|
|
|
788
788
|
const isStale = () => generation !== generationRef.current;
|
|
789
789
|
try {
|
|
790
790
|
if (!address || !walletClient) throw new Error("Wallet not connected");
|
|
791
|
+
setCurrentStep("preparing");
|
|
791
792
|
const pendingResponse = await client.getPendingWithdrawals(address);
|
|
792
793
|
if (isStale()) return void 0;
|
|
793
794
|
const knownIndices = new Set(pendingResponse.pending_withdrawals.map((w) => w.index));
|
|
@@ -2455,15 +2456,356 @@ function TokenSelectorView({ selectedTokenId, onSelect }) {
|
|
|
2455
2456
|
enabledTokens.length === 0 && /* @__PURE__ */ jsx("p", { className: "text-muted-foreground px-3 py-6 text-center text-sm", children: "No tokens available" })
|
|
2456
2457
|
] }) });
|
|
2457
2458
|
}
|
|
2459
|
+
function assertTransakCheckoutPreconditions({
|
|
2460
|
+
activeIntentId,
|
|
2461
|
+
canOpen,
|
|
2462
|
+
canRecreateSession
|
|
2463
|
+
}) {
|
|
2464
|
+
if (activeIntentId && !canRecreateSession) {
|
|
2465
|
+
throw new Error("Continue signed-intent recovery instead of reopening this checkout");
|
|
2466
|
+
}
|
|
2467
|
+
if (!canOpen) {
|
|
2468
|
+
throw new Error("Card checkout is unavailable; close this purchase and start again");
|
|
2469
|
+
}
|
|
2470
|
+
}
|
|
2471
|
+
function TransakCardWidgetView({
|
|
2472
|
+
token,
|
|
2473
|
+
providerAssetCode,
|
|
2474
|
+
amount,
|
|
2475
|
+
allowance,
|
|
2476
|
+
lockServiceAddress,
|
|
2477
|
+
onCredited,
|
|
2478
|
+
onLockSubmitted,
|
|
2479
|
+
onLockFailed,
|
|
2480
|
+
onLeave,
|
|
2481
|
+
onUnsafeToCloseChange,
|
|
2482
|
+
onActiveFlowChange,
|
|
2483
|
+
useOnRamp = useTransakOnRamp
|
|
2484
|
+
}) {
|
|
2485
|
+
const [actionError, setActionError] = useState(null);
|
|
2486
|
+
const [rowError, setRowError] = useState(null);
|
|
2487
|
+
const [lockSettled, setLockSettled] = useState(false);
|
|
2488
|
+
const [lockError, setLockError] = useState(null);
|
|
2489
|
+
const [ownedTerminal, setOwnedTerminal] = useState(false);
|
|
2490
|
+
const ownedIntentIdRef = useRef(null);
|
|
2491
|
+
const postDepositLock = useMemo(
|
|
2492
|
+
() => allowance ? {
|
|
2493
|
+
serviceAddress: lockServiceAddress,
|
|
2494
|
+
maxAmount: BigInt(allowance.value),
|
|
2495
|
+
lockDuration: allowance.lockDuration
|
|
2496
|
+
} : void 0,
|
|
2497
|
+
[allowance, lockServiceAddress]
|
|
2498
|
+
);
|
|
2499
|
+
const ownsRecord = useCallback(
|
|
2500
|
+
(record) => Boolean(
|
|
2501
|
+
ownedIntentIdRef.current && matchesOnRampTransaction(record, ownedIntentIdRef.current)
|
|
2502
|
+
),
|
|
2503
|
+
[]
|
|
2504
|
+
);
|
|
2505
|
+
const {
|
|
2506
|
+
status,
|
|
2507
|
+
activeIntentId,
|
|
2508
|
+
pending,
|
|
2509
|
+
activeVerificationId,
|
|
2510
|
+
error,
|
|
2511
|
+
finalityProgress,
|
|
2512
|
+
depositAddress,
|
|
2513
|
+
minDepositBaseUnits,
|
|
2514
|
+
selectedToken,
|
|
2515
|
+
isLaunching,
|
|
2516
|
+
isWidgetOpen,
|
|
2517
|
+
canRecreateSession,
|
|
2518
|
+
widget,
|
|
2519
|
+
launch,
|
|
2520
|
+
recreateSession,
|
|
2521
|
+
closeWidget,
|
|
2522
|
+
finishPendingVerification,
|
|
2523
|
+
refreshPending
|
|
2524
|
+
} = useOnRamp({
|
|
2525
|
+
tokenId: token.id,
|
|
2526
|
+
postDepositLock,
|
|
2527
|
+
iframeTitle: "Card checkout",
|
|
2528
|
+
iframeClassName: "h-[680px] w-full border-0",
|
|
2529
|
+
onCredited: (_depositTxHash, record) => {
|
|
2530
|
+
if (!ownsRecord(record)) return;
|
|
2531
|
+
onCredited?.();
|
|
2532
|
+
if (!postDepositLock) {
|
|
2533
|
+
setOwnedTerminal(true);
|
|
2534
|
+
onActiveFlowChange?.(false);
|
|
2535
|
+
}
|
|
2536
|
+
},
|
|
2537
|
+
onLockSubmitted: (_response, record) => {
|
|
2538
|
+
if (!ownsRecord(record)) return;
|
|
2539
|
+
setLockError(null);
|
|
2540
|
+
setLockSettled(true);
|
|
2541
|
+
setOwnedTerminal(true);
|
|
2542
|
+
onActiveFlowChange?.(false);
|
|
2543
|
+
onLockSubmitted?.();
|
|
2544
|
+
},
|
|
2545
|
+
onLockFailed: (nextError, record) => {
|
|
2546
|
+
if (!ownsRecord(record)) return;
|
|
2547
|
+
setLockError(nextError);
|
|
2548
|
+
setOwnedTerminal(true);
|
|
2549
|
+
onActiveFlowChange?.(false);
|
|
2550
|
+
onLockFailed?.(nextError);
|
|
2551
|
+
}
|
|
2552
|
+
});
|
|
2553
|
+
const ownedIntentId = ownedIntentIdRef.current ?? activeIntentId;
|
|
2554
|
+
useEffect(() => {
|
|
2555
|
+
if (activeIntentId && !ownedIntentIdRef.current) {
|
|
2556
|
+
ownedIntentIdRef.current = activeIntentId;
|
|
2557
|
+
}
|
|
2558
|
+
}, [activeIntentId]);
|
|
2559
|
+
let amountBaseUnits;
|
|
2560
|
+
try {
|
|
2561
|
+
amountBaseUnits = parseUnits(amount, token.decimals);
|
|
2562
|
+
} catch {
|
|
2563
|
+
}
|
|
2564
|
+
const minimumTargetBaseUnits = minDepositBaseUnits === void 0 ? void 0 : getTransakMinimumTargetBaseUnits(minDepositBaseUnits);
|
|
2565
|
+
const belowMinimum = amountBaseUnits !== void 0 && minimumTargetBaseUnits !== void 0 && amountBaseUnits < minimumTargetBaseUnits;
|
|
2566
|
+
const minimumUnknown = minimumTargetBaseUnits === void 0;
|
|
2567
|
+
const tokenMismatch = !matchesFrozenOnRampToken(token, selectedToken);
|
|
2568
|
+
const isSettling = status === "awaiting-delivery" || status === "verifying";
|
|
2569
|
+
const lockPending = !!allowance && status === "credited" && !lockSettled && !lockError;
|
|
2570
|
+
const ownedPending = ownedIntentId ? pending.filter((record) => matchesOnRampTransaction(record, ownedIntentId)) : [];
|
|
2571
|
+
const ownedFlowActive = !ownedTerminal && (Boolean(activeIntentId && activeIntentId === ownedIntentId) || ownedPending.length > 0 || lockPending);
|
|
2572
|
+
const canOpen = Boolean(selectedToken && depositAddress && amountBaseUnits && amountBaseUnits > 0n) && !tokenMismatch && !minimumUnknown && !belowMinimum && !isLaunching && !isWidgetOpen && !isSettling && status !== "credited" && (!activeIntentId || canRecreateSession);
|
|
2573
|
+
useEffect(() => {
|
|
2574
|
+
onActiveFlowChange?.(ownedFlowActive);
|
|
2575
|
+
}, [onActiveFlowChange, ownedFlowActive]);
|
|
2576
|
+
const unsafeToClose = isLaunching || lockPending;
|
|
2577
|
+
useEffect(() => {
|
|
2578
|
+
onUnsafeToCloseChange?.(unsafeToClose);
|
|
2579
|
+
return () => onUnsafeToCloseChange?.(false);
|
|
2580
|
+
}, [onUnsafeToCloseChange, unsafeToClose]);
|
|
2581
|
+
const runCheckout = useCallback(async () => {
|
|
2582
|
+
setActionError(null);
|
|
2583
|
+
try {
|
|
2584
|
+
assertTransakCheckoutPreconditions({ activeIntentId, canOpen, canRecreateSession });
|
|
2585
|
+
setLockError(null);
|
|
2586
|
+
setLockSettled(false);
|
|
2587
|
+
setOwnedTerminal(false);
|
|
2588
|
+
if (!activeIntentId) ownedIntentIdRef.current = null;
|
|
2589
|
+
if (activeIntentId) await recreateSession();
|
|
2590
|
+
else await launch({ providerAssetCode, quoteCurrencyAmount: amount });
|
|
2591
|
+
} catch (nextError) {
|
|
2592
|
+
setActionError(
|
|
2593
|
+
nextError instanceof Error ? nextError : new Error("Failed to open card checkout")
|
|
2594
|
+
);
|
|
2595
|
+
}
|
|
2596
|
+
}, [
|
|
2597
|
+
activeIntentId,
|
|
2598
|
+
amount,
|
|
2599
|
+
canOpen,
|
|
2600
|
+
canRecreateSession,
|
|
2601
|
+
launch,
|
|
2602
|
+
providerAssetCode,
|
|
2603
|
+
recreateSession
|
|
2604
|
+
]);
|
|
2605
|
+
const handleClose = useCallback(async () => {
|
|
2606
|
+
setActionError(null);
|
|
2607
|
+
try {
|
|
2608
|
+
await closeWidget();
|
|
2609
|
+
} catch (nextError) {
|
|
2610
|
+
setActionError(
|
|
2611
|
+
nextError instanceof Error ? nextError : new Error("Failed to close card checkout")
|
|
2612
|
+
);
|
|
2613
|
+
}
|
|
2614
|
+
}, [closeWidget]);
|
|
2615
|
+
const handleLeave = useCallback(() => {
|
|
2616
|
+
setActionError(null);
|
|
2617
|
+
onActiveFlowChange?.(false);
|
|
2618
|
+
onLeave?.();
|
|
2619
|
+
}, [onActiveFlowChange, onLeave]);
|
|
2620
|
+
return /* @__PURE__ */ jsxs("div", { className: "bg-muted flex flex-col gap-4 rounded-[10px] p-5", children: [
|
|
2621
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
2622
|
+
/* @__PURE__ */ jsx("h2", { className: "text-foreground text-[28px] leading-8 font-medium", children: "Complete your purchase" }),
|
|
2623
|
+
/* @__PURE__ */ jsxs("p", { className: "text-muted-foreground mt-1 text-sm", children: [
|
|
2624
|
+
"Buy ",
|
|
2625
|
+
token.symbol,
|
|
2626
|
+
" and deposit it directly into your Privana balance."
|
|
2627
|
+
] })
|
|
2628
|
+
] }),
|
|
2629
|
+
/* @__PURE__ */ jsxs("div", { className: "border-border bg-card rounded-lg border p-3 text-sm", children: [
|
|
2630
|
+
/* @__PURE__ */ jsxs("p", { className: "text-foreground font-medium", children: [
|
|
2631
|
+
"Target receipt: at least ",
|
|
2632
|
+
amount,
|
|
2633
|
+
" ",
|
|
2634
|
+
token.symbol
|
|
2635
|
+
] }),
|
|
2636
|
+
/* @__PURE__ */ jsx("p", { className: "text-muted-foreground mt-1", children: "In Transak, adjust the fiat amount until \u201CYou receive\u201D is at least this target." }),
|
|
2637
|
+
allowance && /* @__PURE__ */ jsx("p", { className: "text-muted-foreground mt-1", children: "The pre-signed lock is 98% of the target, capped by the service allowance." })
|
|
2638
|
+
] }),
|
|
2639
|
+
widget ? /* @__PURE__ */ jsxs("div", { className: "border-border bg-card overflow-hidden rounded-xl border", children: [
|
|
2640
|
+
/* @__PURE__ */ jsxs("div", { className: "border-border flex items-center justify-between border-b px-4 py-2 text-sm", children: [
|
|
2641
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium", children: "Card checkout" }),
|
|
2642
|
+
/* @__PURE__ */ jsx(Button, { type: "button", variant: "outline", size: "sm", onClick: () => void handleClose(), children: "Close" })
|
|
2643
|
+
] }),
|
|
2644
|
+
widget
|
|
2645
|
+
] }) : status === "credited" && !lockPending && !lockError ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-2 py-8 text-center", children: [
|
|
2646
|
+
/* @__PURE__ */ jsx(CircleCheckIcon, { className: "text-primary size-8", "aria-hidden": true }),
|
|
2647
|
+
/* @__PURE__ */ jsx("p", { className: "text-foreground text-sm font-medium", children: "Purchase credited" }),
|
|
2648
|
+
/* @__PURE__ */ jsxs("p", { className: "text-muted-foreground text-sm", children: [
|
|
2649
|
+
"Your ",
|
|
2650
|
+
token.symbol,
|
|
2651
|
+
" deposit is now available in your balance."
|
|
2652
|
+
] })
|
|
2653
|
+
] }) : !activeIntentId || canRecreateSession ? /* @__PURE__ */ jsxs(Button, { type: "button", disabled: !canOpen, onClick: () => void runCheckout(), children: [
|
|
2654
|
+
isLaunching && /* @__PURE__ */ jsx(Loader2, { className: "animate-spin", "aria-hidden": true }),
|
|
2655
|
+
isLaunching ? "Opening checkout\u2026" : activeIntentId ? "Reopen card checkout" : allowance ? "Sign policy and open checkout" : "Open card checkout"
|
|
2656
|
+
] }) : /* @__PURE__ */ jsx("p", { className: "text-muted-foreground text-sm", children: "This signed purchase is in recovery. Do not open another checkout for it." }),
|
|
2657
|
+
!depositAddress && !error && !actionError && /* @__PURE__ */ jsx("p", { className: "text-muted-foreground text-sm", children: "Preparing your secure deposit address\u2026" }),
|
|
2658
|
+
tokenMismatch && /* @__PURE__ */ jsx("p", { className: "text-destructive text-sm", role: "alert", children: "The token configuration changed. Close this purchase and start again." }),
|
|
2659
|
+
!tokenMismatch && depositAddress && minimumUnknown && !error && !actionError && /* @__PURE__ */ jsx("p", { className: "text-destructive text-sm", role: "alert", children: "The minimum purchase amount is unavailable. Close this purchase and try again." }),
|
|
2660
|
+
belowMinimum && minimumTargetBaseUnits !== void 0 && /* @__PURE__ */ jsxs("p", { className: "text-destructive text-sm", role: "alert", children: [
|
|
2661
|
+
"Minimum target is ",
|
|
2662
|
+
formatUnits(minimumTargetBaseUnits, token.decimals),
|
|
2663
|
+
" ",
|
|
2664
|
+
token.symbol,
|
|
2665
|
+
", including a 5% delivery buffer."
|
|
2666
|
+
] }),
|
|
2667
|
+
isSettling && pending.length === 0 && /* @__PURE__ */ jsxs("p", { className: "text-muted-foreground flex items-center gap-2 text-sm", children: [
|
|
2668
|
+
/* @__PURE__ */ jsx(Loader2, { className: "size-4 animate-spin", "aria-hidden": true }),
|
|
2669
|
+
"Verifying your purchase\u2026"
|
|
2670
|
+
] }),
|
|
2671
|
+
lockPending && /* @__PURE__ */ jsxs("p", { className: "text-muted-foreground flex items-center gap-2 text-sm", children: [
|
|
2672
|
+
/* @__PURE__ */ jsx(Loader2, { className: "size-4 animate-spin", "aria-hidden": true }),
|
|
2673
|
+
"Purchase credited. Locking your funds\u2026"
|
|
2674
|
+
] }),
|
|
2675
|
+
pending.length > 0 && /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
|
|
2676
|
+
/* @__PURE__ */ jsx("p", { className: "text-foreground text-sm font-medium", children: "Validating purchases" }),
|
|
2677
|
+
pending.map((record) => {
|
|
2678
|
+
const isActivelyVerifying = record.transaction_id === activeVerificationId;
|
|
2679
|
+
const progress = parseFinalityProgress(finalityProgress[record.transaction_id]);
|
|
2680
|
+
const showRetry = canRetryOnRampVerification(record, activeVerificationId);
|
|
2681
|
+
return /* @__PURE__ */ jsxs(
|
|
2682
|
+
"div",
|
|
2683
|
+
{
|
|
2684
|
+
className: "border-border flex flex-col gap-2 rounded-md border p-2",
|
|
2685
|
+
children: [
|
|
2686
|
+
/* @__PURE__ */ jsxs("p", { className: "text-muted-foreground flex items-center gap-1 text-xs", children: [
|
|
2687
|
+
/* @__PURE__ */ jsx(Loader2, { className: "size-3 animate-spin", "aria-hidden": true }),
|
|
2688
|
+
record.on_chain_tx_hash ? progress ?? (isActivelyVerifying ? "Verifying\u2026" : "Ready to verify") : "Waiting for provider delivery\u2026"
|
|
2689
|
+
] }),
|
|
2690
|
+
rowError?.id === record.transaction_id && /* @__PURE__ */ jsx("p", { className: "text-destructive text-xs", children: rowError.message }),
|
|
2691
|
+
showRetry && /* @__PURE__ */ jsx(
|
|
2692
|
+
Button,
|
|
2693
|
+
{
|
|
2694
|
+
type: "button",
|
|
2695
|
+
variant: "outline",
|
|
2696
|
+
size: "sm",
|
|
2697
|
+
onClick: async () => {
|
|
2698
|
+
setRowError(null);
|
|
2699
|
+
try {
|
|
2700
|
+
await finishPendingVerification(record);
|
|
2701
|
+
} catch (nextError) {
|
|
2702
|
+
setRowError({
|
|
2703
|
+
id: record.transaction_id,
|
|
2704
|
+
message: nextError instanceof Error ? nextError.message : "Verification failed"
|
|
2705
|
+
});
|
|
2706
|
+
}
|
|
2707
|
+
},
|
|
2708
|
+
children: "Retry verification"
|
|
2709
|
+
}
|
|
2710
|
+
),
|
|
2711
|
+
!record.on_chain_tx_hash && /* @__PURE__ */ jsx(
|
|
2712
|
+
Button,
|
|
2713
|
+
{
|
|
2714
|
+
type: "button",
|
|
2715
|
+
variant: "outline",
|
|
2716
|
+
size: "sm",
|
|
2717
|
+
onClick: () => void refreshPending(),
|
|
2718
|
+
children: "Refresh delivery"
|
|
2719
|
+
}
|
|
2720
|
+
)
|
|
2721
|
+
]
|
|
2722
|
+
},
|
|
2723
|
+
record.transaction_id
|
|
2724
|
+
);
|
|
2725
|
+
})
|
|
2726
|
+
] }),
|
|
2727
|
+
onLeave && ownedFlowActive && !unsafeToClose && /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
2728
|
+
/* @__PURE__ */ jsx(Button, { type: "button", variant: "outline", onClick: handleLeave, children: "Leave checkout" }),
|
|
2729
|
+
/* @__PURE__ */ jsx("p", { className: "text-muted-foreground text-xs", children: "Privana will keep this signed purchase available for exact recovery." })
|
|
2730
|
+
] }),
|
|
2731
|
+
(actionError ?? error) && /* @__PURE__ */ jsx("p", { className: "text-destructive text-sm", role: "alert", children: (actionError ?? error)?.message }),
|
|
2732
|
+
lockError && /* @__PURE__ */ jsxs("p", { className: "text-destructive text-sm", role: "alert", children: [
|
|
2733
|
+
"Purchase credited, but locking the funds failed: ",
|
|
2734
|
+
lockError.message
|
|
2735
|
+
] })
|
|
2736
|
+
] });
|
|
2737
|
+
}
|
|
2738
|
+
function parseFinalityProgress(message) {
|
|
2739
|
+
if (!message) return null;
|
|
2740
|
+
const match = message.match(/(\d+\/\d+)\s+confirmations/i);
|
|
2741
|
+
return match ? `${match[1]} confirmations` : null;
|
|
2742
|
+
}
|
|
2458
2743
|
function CreditCardWidgetView({
|
|
2459
2744
|
token,
|
|
2745
|
+
onRamp,
|
|
2460
2746
|
amount,
|
|
2461
2747
|
allowance,
|
|
2748
|
+
lockServiceAddress,
|
|
2462
2749
|
onCredited,
|
|
2463
2750
|
onLockSubmitted,
|
|
2464
|
-
onLockFailed
|
|
2751
|
+
onLockFailed,
|
|
2752
|
+
onLeave,
|
|
2753
|
+
onUnsafeToCloseChange,
|
|
2754
|
+
onActiveFlowChange
|
|
2755
|
+
}) {
|
|
2756
|
+
if (onRamp.unavailableReason || !token || !onRamp.provider || !onRamp.providerAssetCode) {
|
|
2757
|
+
return /* @__PURE__ */ jsxs("div", { className: "bg-muted flex flex-col gap-2 rounded-[10px] p-5", children: [
|
|
2758
|
+
/* @__PURE__ */ jsx("h2", { className: "text-foreground text-[28px] leading-8 font-medium", children: "Card purchases unavailable" }),
|
|
2759
|
+
/* @__PURE__ */ jsx("p", { className: "text-destructive text-sm", children: onRamp.unavailableReason ?? "The card on-ramp is not configured for this token." })
|
|
2760
|
+
] });
|
|
2761
|
+
}
|
|
2762
|
+
if (onRamp.provider === "transak") {
|
|
2763
|
+
return /* @__PURE__ */ jsx(
|
|
2764
|
+
TransakCardWidgetView,
|
|
2765
|
+
{
|
|
2766
|
+
token,
|
|
2767
|
+
providerAssetCode: onRamp.providerAssetCode,
|
|
2768
|
+
amount,
|
|
2769
|
+
allowance,
|
|
2770
|
+
lockServiceAddress,
|
|
2771
|
+
onCredited,
|
|
2772
|
+
onLockSubmitted,
|
|
2773
|
+
onLockFailed,
|
|
2774
|
+
onLeave,
|
|
2775
|
+
onUnsafeToCloseChange,
|
|
2776
|
+
onActiveFlowChange
|
|
2777
|
+
}
|
|
2778
|
+
);
|
|
2779
|
+
}
|
|
2780
|
+
return /* @__PURE__ */ jsx(
|
|
2781
|
+
MoonPayCardWidgetView,
|
|
2782
|
+
{
|
|
2783
|
+
token,
|
|
2784
|
+
amount,
|
|
2785
|
+
allowance,
|
|
2786
|
+
lockServiceAddress,
|
|
2787
|
+
onCredited,
|
|
2788
|
+
onLockSubmitted,
|
|
2789
|
+
onLockFailed,
|
|
2790
|
+
onLeaveFlow: onLeave,
|
|
2791
|
+
onUnsafeToCloseChange,
|
|
2792
|
+
onActiveFlowChange
|
|
2793
|
+
}
|
|
2794
|
+
);
|
|
2795
|
+
}
|
|
2796
|
+
function MoonPayCardWidgetView({
|
|
2797
|
+
token,
|
|
2798
|
+
amount,
|
|
2799
|
+
allowance,
|
|
2800
|
+
lockServiceAddress,
|
|
2801
|
+
onCredited,
|
|
2802
|
+
onLockSubmitted,
|
|
2803
|
+
onLockFailed,
|
|
2804
|
+
onLeaveFlow,
|
|
2805
|
+
onUnsafeToCloseChange,
|
|
2806
|
+
onActiveFlowChange
|
|
2465
2807
|
}) {
|
|
2466
|
-
const moonpayCurrencyCode = token
|
|
2808
|
+
const moonpayCurrencyCode = token.moonpayCurrencyCode;
|
|
2467
2809
|
const containerRef = useRef(null);
|
|
2468
2810
|
const [widgetTheme, setWidgetTheme] = useState();
|
|
2469
2811
|
useEffect(() => {
|
|
@@ -2471,26 +2813,32 @@ function CreditCardWidgetView({
|
|
|
2471
2813
|
}, []);
|
|
2472
2814
|
return /* @__PURE__ */ jsxs("div", { ref: containerRef, className: "bg-muted flex flex-col gap-6 rounded-[10px] p-5", children: [
|
|
2473
2815
|
/* @__PURE__ */ jsx("h2", { className: "text-foreground text-[28px] leading-8 font-medium", children: "Complete your purchase" }),
|
|
2474
|
-
|
|
2816
|
+
moonpayCurrencyCode ? /* @__PURE__ */ jsx(
|
|
2475
2817
|
FiatOnRampForm,
|
|
2476
2818
|
{
|
|
2477
2819
|
tokenId: token.id,
|
|
2820
|
+
frozenToken: token,
|
|
2478
2821
|
currencyCode: moonpayCurrencyCode,
|
|
2479
2822
|
quoteCurrencyAmount: amount || void 0,
|
|
2480
2823
|
lockAmount: true,
|
|
2481
2824
|
variant: "embedded",
|
|
2482
2825
|
autoStart: true,
|
|
2483
2826
|
theme: widgetTheme,
|
|
2827
|
+
onlyRouteActiveIntentCallbacks: true,
|
|
2828
|
+
onUnsafeToCloseChange,
|
|
2829
|
+
onActiveFlowChange,
|
|
2484
2830
|
postDepositLock: allowance ? {
|
|
2831
|
+
serviceAddress: lockServiceAddress,
|
|
2485
2832
|
maxAmount: BigInt(allowance.value),
|
|
2486
2833
|
lockDuration: allowance.lockDuration
|
|
2487
2834
|
} : void 0,
|
|
2488
2835
|
onCredited,
|
|
2489
2836
|
onLockSubmitted,
|
|
2490
|
-
onLockFailed
|
|
2837
|
+
onLockFailed,
|
|
2838
|
+
onLeaveFlow
|
|
2491
2839
|
}
|
|
2492
2840
|
) : /* @__PURE__ */ jsxs("p", { className: "text-muted-foreground text-sm", children: [
|
|
2493
|
-
token
|
|
2841
|
+
token.symbol,
|
|
2494
2842
|
" isn\u2019t available for card purchases yet."
|
|
2495
2843
|
] })
|
|
2496
2844
|
] });
|
|
@@ -2799,7 +3147,7 @@ function CopyIcon() {
|
|
|
2799
3147
|
}
|
|
2800
3148
|
);
|
|
2801
3149
|
}
|
|
2802
|
-
function
|
|
3150
|
+
function CircleCheckIcon2() {
|
|
2803
3151
|
return /* @__PURE__ */ jsxs("svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", children: [
|
|
2804
3152
|
/* @__PURE__ */ jsx("circle", { cx: "10", cy: "10", r: "9", stroke: "currentColor", strokeWidth: "1.5" }),
|
|
2805
3153
|
/* @__PURE__ */ jsx(
|
|
@@ -2918,7 +3266,7 @@ function PolicyTermRow({
|
|
|
2918
3266
|
"mt-0.5 shrink-0",
|
|
2919
3267
|
kind === "permission" ? "text-emerald-500" : "text-orange-500"
|
|
2920
3268
|
),
|
|
2921
|
-
children: kind === "permission" ? /* @__PURE__ */ jsx(
|
|
3269
|
+
children: kind === "permission" ? /* @__PURE__ */ jsx(CircleCheckIcon2, {}) : /* @__PURE__ */ jsx(CircleXIcon, {})
|
|
2922
3270
|
}
|
|
2923
3271
|
),
|
|
2924
3272
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
@@ -2978,6 +3326,7 @@ function AllowancePolicySection({
|
|
|
2978
3326
|
function DepositView({
|
|
2979
3327
|
source,
|
|
2980
3328
|
selectedToken,
|
|
3329
|
+
onRamp,
|
|
2981
3330
|
amount,
|
|
2982
3331
|
allowance,
|
|
2983
3332
|
externalMinimum,
|
|
@@ -2996,13 +3345,15 @@ function DepositView({
|
|
|
2996
3345
|
const isConnectedSource = source === "connected";
|
|
2997
3346
|
const isExternal = source === "external";
|
|
2998
3347
|
const isCreditCard = source === "credit-card";
|
|
3348
|
+
const isMoonPayCard = isCreditCard && isMoonPayProductOnRamp(onRamp);
|
|
3349
|
+
const isTransakCard = isCreditCard && onRamp.provider === "transak";
|
|
2999
3350
|
const isNative = selectedToken?.contract === zeroAddress;
|
|
3000
|
-
const { data: nativeBalanceData } = useBalance$1({
|
|
3351
|
+
const { data: nativeBalanceData, isLoading: isNativeBalanceLoading } = useBalance$1({
|
|
3001
3352
|
address,
|
|
3002
3353
|
chainId: targetChain?.id,
|
|
3003
3354
|
query: { enabled: isConnectedSource && !!address && !!selectedToken && isNative }
|
|
3004
3355
|
});
|
|
3005
|
-
const { data: erc20Balance } = useReadContract({
|
|
3356
|
+
const { data: erc20Balance, isLoading: isErc20BalanceLoading } = useReadContract({
|
|
3006
3357
|
address: selectedToken?.contract,
|
|
3007
3358
|
abi: erc20Abi,
|
|
3008
3359
|
functionName: "balanceOf",
|
|
@@ -3011,6 +3362,7 @@ function DepositView({
|
|
|
3011
3362
|
query: { enabled: isConnectedSource && !!address && !!selectedToken && !isNative }
|
|
3012
3363
|
});
|
|
3013
3364
|
const walletBalance = isNative ? nativeBalanceData?.value : erc20Balance;
|
|
3365
|
+
const isWalletBalanceLoading = isNative ? isNativeBalanceLoading : isErc20BalanceLoading;
|
|
3014
3366
|
const formattedWalletBalance = walletBalance != null && selectedToken ? formatTokenAmount(walletBalance.toString(), selectedToken.decimals) : "0.00";
|
|
3015
3367
|
const {
|
|
3016
3368
|
minBuyAmount: moonpayMinBuy,
|
|
@@ -3019,15 +3371,15 @@ function DepositView({
|
|
|
3019
3371
|
} = useMoonpayLimits({
|
|
3020
3372
|
currencyCode: selectedToken?.moonpayCurrencyCode,
|
|
3021
3373
|
apiBaseUrl: networkConfig.moonpayApiUrl,
|
|
3022
|
-
enabled:
|
|
3374
|
+
enabled: isMoonPayCard
|
|
3023
3375
|
});
|
|
3024
3376
|
const hasValidAmount = !!amount && parseFloat(amount) > 0;
|
|
3025
|
-
const maxAmountDecimals =
|
|
3377
|
+
const maxAmountDecimals = isMoonPayCard ? 2 : selectedToken?.decimals;
|
|
3026
3378
|
const tooManyDecimals = hasValidAmount && maxAmountDecimals != null && amount.includes(".") && amount.split(".")[1].length > maxAmountDecimals;
|
|
3027
3379
|
const exceedsBalance = isConnectedSource && hasValidAmount && !tooManyDecimals && !!selectedToken && walletBalance != null && parseTokenAmount(amount, selectedToken.decimals) > walletBalance;
|
|
3028
|
-
const belowMoonpayMin =
|
|
3029
|
-
const moonpayLimitsUnready =
|
|
3030
|
-
const creditCardUnavailable = isCreditCard && !!
|
|
3380
|
+
const belowMoonpayMin = isMoonPayCard && hasValidAmount && moonpayMinBuy != null && parseFloat(amount) < moonpayMinBuy;
|
|
3381
|
+
const moonpayLimitsUnready = isMoonPayCard && !!onRamp.providerAssetCode && moonpayMinBuy == null;
|
|
3382
|
+
const creditCardUnavailable = isCreditCard && !!onRamp.unavailableReason;
|
|
3031
3383
|
const externalTokenUnavailable = isExternal && !!selectedToken && isNative;
|
|
3032
3384
|
const externalMinimumRequired = isExternal && !!allowance && !!selectedToken;
|
|
3033
3385
|
const externalMinimumLoading = externalMinimumRequired && externalMinimum === void 0;
|
|
@@ -3037,13 +3389,13 @@ function DepositView({
|
|
|
3037
3389
|
const needsConnect = (isConnectedSource || externalNeedsWallet) && !isConnected;
|
|
3038
3390
|
const canDeposit = hasValidAmount && !!selectedToken && !tooManyDecimals && !exceedsBalance && !belowMoonpayMin && !moonpayLimitsUnready && !creditCardUnavailable && !externalTokenUnavailable && !externalMinimumLoading && !externalMinimumUnavailable && !belowExternalMinimum && !needsConnect;
|
|
3039
3391
|
const handleMax = () => {
|
|
3040
|
-
|
|
3041
|
-
|
|
3392
|
+
if (selectedToken && walletBalance != null && walletBalance > 0n)
|
|
3393
|
+
onAmountChange(formatUnits(walletBalance, selectedToken.decimals));
|
|
3042
3394
|
};
|
|
3043
3395
|
return /* @__PURE__ */ jsxs("div", { className: "bg-muted flex flex-col gap-6 rounded-[10px] p-5", children: [
|
|
3044
3396
|
isCreditCard ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
|
|
3045
|
-
/* @__PURE__ */ jsx("h2", { className: "text-foreground text-[28px] leading-8 font-medium", children: "Buy with
|
|
3046
|
-
/* @__PURE__ */ jsx("p", { className: "text-muted-foreground text-sm", children: "Enter your deposit amount and proceed to sign a policy." })
|
|
3397
|
+
/* @__PURE__ */ jsx("h2", { className: "text-foreground text-[28px] leading-8 font-medium", children: "Buy with card and deposit" }),
|
|
3398
|
+
/* @__PURE__ */ jsx("p", { className: "text-muted-foreground text-sm", children: isTransakCard ? "Enter your target deposit amount and continue." : "Enter your deposit amount and proceed to sign a policy." })
|
|
3047
3399
|
] }) : /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
|
|
3048
3400
|
/* @__PURE__ */ jsxs("h2", { className: "text-foreground text-[28px] leading-8 font-medium", children: [
|
|
3049
3401
|
"Deposit from ",
|
|
@@ -3058,7 +3410,7 @@ function DepositView({
|
|
|
3058
3410
|
{
|
|
3059
3411
|
type: "button",
|
|
3060
3412
|
onClick: onSelectToken,
|
|
3061
|
-
disabled: isSubmitting,
|
|
3413
|
+
disabled: isSubmitting || isCreditCard && onRamp.tokenSelectionLocked,
|
|
3062
3414
|
className: "border-border bg-input flex w-full cursor-pointer items-center gap-3 rounded-lg border p-3 text-left disabled:cursor-not-allowed disabled:opacity-50",
|
|
3063
3415
|
children: [
|
|
3064
3416
|
selectedToken ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
@@ -3071,7 +3423,7 @@ function DepositView({
|
|
|
3071
3423
|
] })
|
|
3072
3424
|
] })
|
|
3073
3425
|
] }) : /* @__PURE__ */ jsx("span", { className: "text-muted-foreground flex-1 text-sm", children: "Select token" }),
|
|
3074
|
-
/* @__PURE__ */ jsx("div", { className: "text-muted-foreground flex h-5 w-5 items-center justify-center", children: /* @__PURE__ */ jsx(ChevronRightIcon, {}) })
|
|
3426
|
+
(!isCreditCard || !onRamp.tokenSelectionLocked) && /* @__PURE__ */ jsx("div", { className: "text-muted-foreground flex h-5 w-5 items-center justify-center", children: /* @__PURE__ */ jsx(ChevronRightIcon, {}) })
|
|
3075
3427
|
]
|
|
3076
3428
|
}
|
|
3077
3429
|
)
|
|
@@ -3079,11 +3431,10 @@ function DepositView({
|
|
|
3079
3431
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
|
|
3080
3432
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
|
|
3081
3433
|
/* @__PURE__ */ jsx("label", { className: "text-muted-foreground text-sm", children: "Amount" }),
|
|
3082
|
-
isConnectedSource && /* @__PURE__ */ jsxs("span", { className: "text-muted-foreground text-sm", children: [
|
|
3083
|
-
"Available
|
|
3084
|
-
formattedWalletBalance,
|
|
3434
|
+
isConnectedSource && /* @__PURE__ */ jsxs("span", { className: "text-muted-foreground flex items-center gap-1 text-sm", children: [
|
|
3435
|
+
"Available",
|
|
3085
3436
|
" ",
|
|
3086
|
-
selectedToken?.symbol
|
|
3437
|
+
isWalletBalanceLoading ? /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-16" }) : `${formattedWalletBalance} ${selectedToken?.symbol ?? ""}`
|
|
3087
3438
|
] })
|
|
3088
3439
|
] }),
|
|
3089
3440
|
/* @__PURE__ */ jsxs(
|
|
@@ -3114,7 +3465,8 @@ function DepositView({
|
|
|
3114
3465
|
{
|
|
3115
3466
|
type: "button",
|
|
3116
3467
|
onClick: handleMax,
|
|
3117
|
-
|
|
3468
|
+
disabled: isWalletBalanceLoading,
|
|
3469
|
+
className: "bg-secondary text-foreground hover:bg-secondary/80 cursor-pointer rounded px-3 py-2.5 text-xs font-semibold transition-colors disabled:cursor-default disabled:opacity-50",
|
|
3118
3470
|
children: "MAX"
|
|
3119
3471
|
}
|
|
3120
3472
|
) : isCreditCard ? /* @__PURE__ */ jsx("span", { className: "text-muted-foreground text-sm", children: selectedToken?.symbol ?? "USD" }) : selectedToken && /* @__PURE__ */ jsx("span", { className: "text-muted-foreground text-sm", children: selectedToken.symbol })
|
|
@@ -3141,12 +3493,9 @@ function DepositView({
|
|
|
3141
3493
|
] }),
|
|
3142
3494
|
externalMinimumLoading && /* @__PURE__ */ jsx("p", { className: "text-muted-foreground text-sm", children: "Checking minimum deposit\u2026" }),
|
|
3143
3495
|
externalMinimumUnavailable && /* @__PURE__ */ jsx("p", { className: "text-destructive text-sm", children: "Couldn\u2019t load the minimum deposit. Please try again." }),
|
|
3144
|
-
|
|
3145
|
-
|
|
3146
|
-
creditCardUnavailable && /* @__PURE__ */
|
|
3147
|
-
selectedToken?.symbol ?? "This token",
|
|
3148
|
-
" isn\u2019t available for card purchases yet."
|
|
3149
|
-
] }),
|
|
3496
|
+
isMoonPayCard && moonpayLimitsError && /* @__PURE__ */ jsx("p", { className: "text-destructive text-sm", children: "Couldn\u2019t load purchase limits. Please try again." }),
|
|
3497
|
+
isMoonPayCard && moonpayLimitsLoading && /* @__PURE__ */ jsx("p", { className: "text-muted-foreground text-sm", children: "Checking purchase limits\u2026" }),
|
|
3498
|
+
creditCardUnavailable && /* @__PURE__ */ jsx("p", { className: "text-destructive text-sm", children: onRamp.unavailableReason }),
|
|
3150
3499
|
externalTokenUnavailable && /* @__PURE__ */ jsxs("p", { className: "text-destructive text-sm", children: [
|
|
3151
3500
|
selectedToken?.symbol ?? "This token",
|
|
3152
3501
|
" can\u2019t be used for external deposits. Choose an ERC20 token."
|
|
@@ -3173,7 +3522,7 @@ function DepositView({
|
|
|
3173
3522
|
if (selectedToken) onSubmit({ source, tokenId: selectedToken.id, amount });
|
|
3174
3523
|
},
|
|
3175
3524
|
className: "bg-primary text-primary-foreground hover:bg-primary/90 flex h-10 w-full cursor-pointer items-center justify-center rounded-[10px] px-3 py-2 text-sm font-medium transition-colors disabled:cursor-not-allowed disabled:opacity-50",
|
|
3176
|
-
children: needsConnect ? "Connect Wallet" : allowance ? "Sign Policy and Deposit" : "Deposit"
|
|
3525
|
+
children: needsConnect ? "Connect Wallet" : isTransakCard ? "Continue" : allowance ? "Sign Policy and Deposit" : "Deposit"
|
|
3177
3526
|
}
|
|
3178
3527
|
)
|
|
3179
3528
|
] });
|
|
@@ -3485,9 +3834,11 @@ function ExternalDepositView({
|
|
|
3485
3834
|
] })
|
|
3486
3835
|
] });
|
|
3487
3836
|
}
|
|
3488
|
-
function MoonPayGate({
|
|
3489
|
-
|
|
3490
|
-
|
|
3837
|
+
function MoonPayGate({
|
|
3838
|
+
enabled,
|
|
3839
|
+
apiKey,
|
|
3840
|
+
children
|
|
3841
|
+
}) {
|
|
3491
3842
|
if (!enabled || !apiKey) return /* @__PURE__ */ jsx(Fragment, { children });
|
|
3492
3843
|
return /* @__PURE__ */ jsx(MoonPayProvider, { apiKey, children });
|
|
3493
3844
|
}
|
|
@@ -3574,15 +3925,52 @@ function DepositModalContent({
|
|
|
3574
3925
|
onCloseBlockedChange,
|
|
3575
3926
|
onExit
|
|
3576
3927
|
}) {
|
|
3577
|
-
const {
|
|
3928
|
+
const {
|
|
3929
|
+
serviceName,
|
|
3930
|
+
enabledTokens,
|
|
3931
|
+
defaultToken,
|
|
3932
|
+
hostedAuthConfig,
|
|
3933
|
+
serviceAddress,
|
|
3934
|
+
getChainById: getChainById2,
|
|
3935
|
+
getTokenById,
|
|
3936
|
+
networkConfig,
|
|
3937
|
+
onRamp
|
|
3938
|
+
} = usePrivanaContext();
|
|
3578
3939
|
const { address } = useAccount();
|
|
3940
|
+
const { privateReadQueryScope } = usePrivateReadRequest();
|
|
3941
|
+
const [privateReadApiUrl, accountingChainId, beneficiaryAddress] = privateReadQueryScope;
|
|
3579
3942
|
const appName = serviceName ?? "Privana";
|
|
3580
3943
|
const [activeTab, setActiveTab] = useState(defaultTab);
|
|
3581
3944
|
const [view, setView] = useState("method");
|
|
3582
3945
|
const [source, setSource] = useState("connected");
|
|
3583
3946
|
const [selectedTokenId, setSelectedTokenId] = useState(defaultToken?.id ?? "");
|
|
3584
3947
|
const [amount, setAmount] = useState("");
|
|
3585
|
-
const
|
|
3948
|
+
const [cardFlow, setCardFlow] = useState(null);
|
|
3949
|
+
const [cardFlowActive, setCardFlowActive] = useState(false);
|
|
3950
|
+
const [cardUnsafeToClose, setCardUnsafeToClose] = useState(false);
|
|
3951
|
+
const nextCardFlowId = useRef(0);
|
|
3952
|
+
const stateSelectedToken = enabledTokens.find((t) => t.id === selectedTokenId) ?? defaultToken;
|
|
3953
|
+
const cardOnRamp = useMemo(
|
|
3954
|
+
() => resolveProductOnRamp({
|
|
3955
|
+
config: onRamp,
|
|
3956
|
+
enabledTokens,
|
|
3957
|
+
legacyToken: stateSelectedToken,
|
|
3958
|
+
moonpayApiKey: networkConfig.moonpayApiKey
|
|
3959
|
+
}),
|
|
3960
|
+
[enabledTokens, networkConfig.moonpayApiKey, onRamp, stateSelectedToken]
|
|
3961
|
+
);
|
|
3962
|
+
const cardOnRampScope = useMemo(
|
|
3963
|
+
() => ({
|
|
3964
|
+
apiUrl: privateReadApiUrl,
|
|
3965
|
+
accountingChainId,
|
|
3966
|
+
accountingContract: networkConfig.accountingContract,
|
|
3967
|
+
beneficiaryAddress
|
|
3968
|
+
}),
|
|
3969
|
+
[accountingChainId, beneficiaryAddress, networkConfig.accountingContract, privateReadApiUrl]
|
|
3970
|
+
);
|
|
3971
|
+
const mountedCardFlow = cardFlow && matchesProductOnRampScope(cardFlow.scope, cardOnRampScope) ? cardFlow : null;
|
|
3972
|
+
const displayedCardOnRamp = view === "credit-card-widget" && mountedCardFlow ? mountedCardFlow.selection : cardOnRamp;
|
|
3973
|
+
const selectedToken = source === "credit-card" ? displayedCardOnRamp.token : stateSelectedToken;
|
|
3586
3974
|
const externalDepositAddress = useDepositAddress({
|
|
3587
3975
|
enabled: source === "external" && (view === "deposit" || view === "external-deposit")
|
|
3588
3976
|
});
|
|
@@ -3596,6 +3984,9 @@ function DepositModalContent({
|
|
|
3596
3984
|
setView("method");
|
|
3597
3985
|
setAmount("");
|
|
3598
3986
|
setSelectedTokenId("");
|
|
3987
|
+
setCardFlow(null);
|
|
3988
|
+
setCardFlowActive(false);
|
|
3989
|
+
setCardUnsafeToClose(false);
|
|
3599
3990
|
}
|
|
3600
3991
|
}, [address, hostedAuthConfig]);
|
|
3601
3992
|
const openDeposit = (next) => {
|
|
@@ -3618,9 +4009,33 @@ function DepositModalContent({
|
|
|
3618
4009
|
}
|
|
3619
4010
|
};
|
|
3620
4011
|
const finishCardPurchase = () => {
|
|
4012
|
+
setCardFlowActive(false);
|
|
4013
|
+
setCardUnsafeToClose(false);
|
|
3621
4014
|
setAmount("");
|
|
3622
4015
|
onDepositSuccess?.();
|
|
3623
4016
|
};
|
|
4017
|
+
const leaveCardPurchase = useCallback(() => {
|
|
4018
|
+
setCardFlow(null);
|
|
4019
|
+
setCardFlowActive(false);
|
|
4020
|
+
setCardUnsafeToClose(false);
|
|
4021
|
+
setAmount("");
|
|
4022
|
+
setView("deposit");
|
|
4023
|
+
}, []);
|
|
4024
|
+
useEffect(() => {
|
|
4025
|
+
if (cardFlow && !matchesProductOnRampScope(cardFlow.scope, cardOnRampScope)) {
|
|
4026
|
+
leaveCardPurchase();
|
|
4027
|
+
}
|
|
4028
|
+
}, [cardFlow, cardOnRampScope, leaveCardPurchase]);
|
|
4029
|
+
const cardOutcomeCallbacks = mountedCardFlow ? createProductOnRampOutcomeCallbacks({
|
|
4030
|
+
requiresLock: mountedCardFlow.requiresLock,
|
|
4031
|
+
onComplete: finishCardPurchase,
|
|
4032
|
+
onLockFailed: (err) => {
|
|
4033
|
+
setCardFlowActive(false);
|
|
4034
|
+
setCardUnsafeToClose(false);
|
|
4035
|
+
setLockFailure(err);
|
|
4036
|
+
onLockFailed?.(err);
|
|
4037
|
+
}
|
|
4038
|
+
}) : null;
|
|
3624
4039
|
const {
|
|
3625
4040
|
txHash,
|
|
3626
4041
|
isGettingAddress,
|
|
@@ -3690,7 +4105,7 @@ function DepositModalContent({
|
|
|
3690
4105
|
setView("deposit");
|
|
3691
4106
|
}
|
|
3692
4107
|
}, [allowance, externalLock.session, view]);
|
|
3693
|
-
const isUnsafeToClose = (isGettingAddress || isSendingTransaction) && !cancelled || externalLock.isSigning || externalLock.isSubmittingLock;
|
|
4108
|
+
const isUnsafeToClose = (isGettingAddress || isSendingTransaction) && !cancelled || externalLock.isSigning || externalLock.isSubmittingLock || cardUnsafeToClose;
|
|
3694
4109
|
useEffect(() => {
|
|
3695
4110
|
onCloseBlockedChange?.(isUnsafeToClose);
|
|
3696
4111
|
}, [isUnsafeToClose, onCloseBlockedChange]);
|
|
@@ -3733,6 +4148,28 @@ function DepositModalContent({
|
|
|
3733
4148
|
return;
|
|
3734
4149
|
}
|
|
3735
4150
|
if (args.source === "credit-card") {
|
|
4151
|
+
if (cardFlow && cardFlowActive) {
|
|
4152
|
+
setView("credit-card-widget");
|
|
4153
|
+
return;
|
|
4154
|
+
}
|
|
4155
|
+
try {
|
|
4156
|
+
setCardFlow(
|
|
4157
|
+
createProductOnRampFlowSnapshot({
|
|
4158
|
+
id: ++nextCardFlowId.current,
|
|
4159
|
+
selection: cardOnRamp,
|
|
4160
|
+
amount: args.amount,
|
|
4161
|
+
allowance,
|
|
4162
|
+
lockServiceAddress: serviceAddress,
|
|
4163
|
+
moonpayApiKey: networkConfig.moonpayApiKey,
|
|
4164
|
+
scope: cardOnRampScope
|
|
4165
|
+
})
|
|
4166
|
+
);
|
|
4167
|
+
} catch (error) {
|
|
4168
|
+
toast.error(error instanceof Error ? error.message : "Card purchase is unavailable");
|
|
4169
|
+
return;
|
|
4170
|
+
}
|
|
4171
|
+
setCardFlowActive(false);
|
|
4172
|
+
setCardUnsafeToClose(false);
|
|
3736
4173
|
setView("credit-card-widget");
|
|
3737
4174
|
return;
|
|
3738
4175
|
}
|
|
@@ -3810,6 +4247,12 @@ function DepositModalContent({
|
|
|
3810
4247
|
setCancelled(false);
|
|
3811
4248
|
resetDeposit();
|
|
3812
4249
|
if (view === "external-deposit") setView("deposit");
|
|
4250
|
+
if (view === "credit-card-widget") {
|
|
4251
|
+
setCardFlow(null);
|
|
4252
|
+
setCardFlowActive(false);
|
|
4253
|
+
setCardUnsafeToClose(false);
|
|
4254
|
+
setView("deposit");
|
|
4255
|
+
}
|
|
3813
4256
|
};
|
|
3814
4257
|
const handleExternalLockRetry = () => {
|
|
3815
4258
|
externalLock.retryAfterCredit().catch((err) => {
|
|
@@ -3833,12 +4276,20 @@ function DepositModalContent({
|
|
|
3833
4276
|
retryVerification().catch(() => {
|
|
3834
4277
|
});
|
|
3835
4278
|
};
|
|
3836
|
-
const back = view === "external-deposit" ? { to: "deposit", label: "Deposit from External Wallet" } : view === "credit-card-widget" ? { to: "deposit", label: "Buy with
|
|
4279
|
+
const back = view === "external-deposit" ? { to: "deposit", label: "Deposit from External Wallet" } : view === "credit-card-widget" ? { to: "deposit", label: "Buy with card and deposit" } : view === "select-token" ? { to: "deposit", label: "Deposit" } : { to: "method", label: "Deposit Method" };
|
|
3837
4280
|
const goBack = () => {
|
|
3838
4281
|
if (view === "external-deposit" && externalLock.session) {
|
|
3839
4282
|
toast.error("Cancel the active deposit from the address screen before going back");
|
|
3840
4283
|
return;
|
|
3841
4284
|
}
|
|
4285
|
+
if (view === "credit-card-widget" && (cardUnsafeToClose || cardFlowActive)) {
|
|
4286
|
+
toast.error("Finish or recover the active card purchase before going back");
|
|
4287
|
+
return;
|
|
4288
|
+
}
|
|
4289
|
+
if (view === "credit-card-widget") {
|
|
4290
|
+
setCardFlow(null);
|
|
4291
|
+
setCardUnsafeToClose(false);
|
|
4292
|
+
}
|
|
3842
4293
|
if (back.to === "method") {
|
|
3843
4294
|
setAmount("");
|
|
3844
4295
|
setSelectedTokenId("");
|
|
@@ -3924,8 +4375,8 @@ function DepositModalContent({
|
|
|
3924
4375
|
] }),
|
|
3925
4376
|
activeView === "method" && /* @__PURE__ */ jsxs("div", { className: "bg-muted flex flex-col gap-6 rounded-[10px] p-5", children: [
|
|
3926
4377
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
|
|
3927
|
-
/* @__PURE__ */ jsx("h2", { className: "text-foreground text-[28px] leading-8 font-medium", children: activeTab === "crypto" ? "Choose the deposit method" : "Buy with
|
|
3928
|
-
/* @__PURE__ */ jsx("p", { className: "text-muted-foreground text-sm", children: activeTab === "crypto" ? "Choose the deposit method." : "
|
|
4378
|
+
/* @__PURE__ */ jsx("h2", { className: "text-foreground text-[28px] leading-8 font-medium", children: activeTab === "crypto" ? "Choose the deposit method" : "Buy with card and deposit" }),
|
|
4379
|
+
/* @__PURE__ */ jsx("p", { className: "text-muted-foreground text-sm", children: activeTab === "crypto" ? "Choose the deposit method." : "Buy crypto by card and deposit it into your account." })
|
|
3929
4380
|
] }),
|
|
3930
4381
|
/* @__PURE__ */ jsx(MethodTabs, { activeTab, onTabChange: setActiveTab }),
|
|
3931
4382
|
activeTab === "crypto" ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
|
|
@@ -3954,8 +4405,8 @@ function DepositModalContent({
|
|
|
3954
4405
|
] }) : /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-3", children: /* @__PURE__ */ jsx(
|
|
3955
4406
|
MethodOption,
|
|
3956
4407
|
{
|
|
3957
|
-
title: "
|
|
3958
|
-
description: "
|
|
4408
|
+
title: "Buy with card",
|
|
4409
|
+
description: "Purchase and deposit directly into your account.",
|
|
3959
4410
|
onClick: () => {
|
|
3960
4411
|
onSelectCreditCard?.();
|
|
3961
4412
|
openDeposit("credit-card");
|
|
@@ -3963,26 +4414,35 @@ function DepositModalContent({
|
|
|
3963
4414
|
}
|
|
3964
4415
|
) })
|
|
3965
4416
|
] }),
|
|
3966
|
-
activeView === "deposit" && /* @__PURE__ */ jsx(
|
|
3967
|
-
|
|
4417
|
+
activeView === "deposit" && /* @__PURE__ */ jsx(
|
|
4418
|
+
MoonPayGate,
|
|
3968
4419
|
{
|
|
3969
|
-
source,
|
|
3970
|
-
|
|
3971
|
-
|
|
3972
|
-
|
|
3973
|
-
|
|
3974
|
-
|
|
3975
|
-
|
|
3976
|
-
|
|
3977
|
-
|
|
3978
|
-
|
|
4420
|
+
enabled: source === "credit-card" && cardOnRamp.provider === "moonpay" && !cardOnRamp.unavailableReason,
|
|
4421
|
+
apiKey: networkConfig.moonpayApiKey,
|
|
4422
|
+
children: /* @__PURE__ */ jsx(
|
|
4423
|
+
DepositView,
|
|
4424
|
+
{
|
|
4425
|
+
source,
|
|
4426
|
+
selectedToken,
|
|
4427
|
+
onRamp: cardOnRamp,
|
|
4428
|
+
amount,
|
|
4429
|
+
allowance,
|
|
4430
|
+
externalMinimum,
|
|
4431
|
+
onAmountChange: setAmount,
|
|
4432
|
+
onSelectToken: () => setView("select-token"),
|
|
4433
|
+
onConnectWallet,
|
|
4434
|
+
onSubmit: handleSubmit,
|
|
4435
|
+
isSubmitting: isPending || externalLock.isSigning || externalLock.isSubmittingLock
|
|
4436
|
+
}
|
|
4437
|
+
)
|
|
3979
4438
|
}
|
|
3980
|
-
)
|
|
4439
|
+
),
|
|
3981
4440
|
activeView === "select-token" && /* @__PURE__ */ jsx(
|
|
3982
4441
|
TokenSelectorView,
|
|
3983
4442
|
{
|
|
3984
4443
|
selectedTokenId: selectedToken?.id,
|
|
3985
4444
|
onSelect: (id) => {
|
|
4445
|
+
if (id !== selectedTokenId) setAmount("");
|
|
3986
4446
|
setSelectedTokenId(id);
|
|
3987
4447
|
setView("deposit");
|
|
3988
4448
|
}
|
|
@@ -3999,20 +4459,30 @@ function DepositModalContent({
|
|
|
3999
4459
|
lock: externalLock.session ? externalLock : void 0
|
|
4000
4460
|
}
|
|
4001
4461
|
),
|
|
4002
|
-
activeView === "credit-card-widget" &&
|
|
4003
|
-
|
|
4462
|
+
activeView === "credit-card-widget" && mountedCardFlow && /* @__PURE__ */ jsx(
|
|
4463
|
+
MoonPayGate,
|
|
4004
4464
|
{
|
|
4005
|
-
|
|
4006
|
-
|
|
4007
|
-
|
|
4008
|
-
|
|
4009
|
-
|
|
4010
|
-
|
|
4011
|
-
|
|
4012
|
-
|
|
4013
|
-
|
|
4465
|
+
enabled: mountedCardFlow.selection.provider === "moonpay",
|
|
4466
|
+
apiKey: mountedCardFlow.moonpayApiKey,
|
|
4467
|
+
children: /* @__PURE__ */ jsx(
|
|
4468
|
+
CreditCardWidgetView,
|
|
4469
|
+
{
|
|
4470
|
+
token: mountedCardFlow.selection.token,
|
|
4471
|
+
onRamp: mountedCardFlow.selection,
|
|
4472
|
+
amount: mountedCardFlow.amount,
|
|
4473
|
+
allowance: mountedCardFlow.allowance,
|
|
4474
|
+
lockServiceAddress: mountedCardFlow.lockServiceAddress,
|
|
4475
|
+
onUnsafeToCloseChange: setCardUnsafeToClose,
|
|
4476
|
+
onActiveFlowChange: setCardFlowActive,
|
|
4477
|
+
onCredited: cardOutcomeCallbacks?.onCredited,
|
|
4478
|
+
onLockSubmitted: cardOutcomeCallbacks?.onLockSubmitted,
|
|
4479
|
+
onLockFailed: cardOutcomeCallbacks?.onLockFailed,
|
|
4480
|
+
onLeave: leaveCardPurchase
|
|
4481
|
+
},
|
|
4482
|
+
mountedCardFlow.id
|
|
4483
|
+
)
|
|
4014
4484
|
}
|
|
4015
|
-
)
|
|
4485
|
+
)
|
|
4016
4486
|
] });
|
|
4017
4487
|
}
|
|
4018
4488
|
function DepositModal({ open, onClose, ...handlers }) {
|
|
@@ -4114,6 +4584,15 @@ function WithdrawView({
|
|
|
4114
4584
|
return "pending";
|
|
4115
4585
|
};
|
|
4116
4586
|
const withdrawSteps = [
|
|
4587
|
+
{
|
|
4588
|
+
label: "Preparing withdrawal",
|
|
4589
|
+
status: getStepStatus("preparing", [
|
|
4590
|
+
"switching-chain",
|
|
4591
|
+
"signing",
|
|
4592
|
+
"submitting",
|
|
4593
|
+
"processing"
|
|
4594
|
+
])
|
|
4595
|
+
},
|
|
4117
4596
|
{
|
|
4118
4597
|
label: "Switching to signing chain",
|
|
4119
4598
|
status: getStepStatus("switching-chain", ["signing", "submitting", "processing"])
|
|
@@ -4136,8 +4615,8 @@ function WithdrawView({
|
|
|
4136
4615
|
const canWithdraw = isConnected && hasValidAmount && !!selectedToken && !tooManyDecimals && !exceedsBalance;
|
|
4137
4616
|
const handleMax = () => {
|
|
4138
4617
|
if (!selectedToken) return;
|
|
4139
|
-
const
|
|
4140
|
-
if (
|
|
4618
|
+
const wei = BigInt(balanceWei);
|
|
4619
|
+
if (wei > 0n) onAmountChange(formatUnits(wei, selectedToken.decimals));
|
|
4141
4620
|
};
|
|
4142
4621
|
const handleWithdraw = async () => {
|
|
4143
4622
|
if (!selectedToken || !canWithdraw) return;
|
|
@@ -4180,7 +4659,7 @@ function WithdrawView({
|
|
|
4180
4659
|
) });
|
|
4181
4660
|
}
|
|
4182
4661
|
if (isPending && !cancelled) {
|
|
4183
|
-
const canCancel = currentStep === "idle" || currentStep === "switching-chain" || currentStep === "signing";
|
|
4662
|
+
const canCancel = currentStep === "idle" || currentStep === "preparing" || currentStep === "switching-chain" || currentStep === "signing";
|
|
4184
4663
|
return /* @__PURE__ */ jsx("div", { className: "bg-muted flex flex-col gap-6 rounded-[10px] p-5", children: /* @__PURE__ */ jsx(
|
|
4185
4664
|
TransactionProgressView,
|
|
4186
4665
|
{
|
|
@@ -4219,11 +4698,10 @@ function WithdrawView({
|
|
|
4219
4698
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
|
|
4220
4699
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
|
|
4221
4700
|
/* @__PURE__ */ jsx("label", { className: "text-muted-foreground text-sm", children: "Amount" }),
|
|
4222
|
-
/* @__PURE__ */ jsxs("span", { className: "text-muted-foreground text-sm", children: [
|
|
4223
|
-
"Available
|
|
4224
|
-
formattedBalance,
|
|
4701
|
+
/* @__PURE__ */ jsxs("span", { className: "text-muted-foreground flex items-center gap-1 text-sm", children: [
|
|
4702
|
+
"Available",
|
|
4225
4703
|
" ",
|
|
4226
|
-
selectedToken?.symbol
|
|
4704
|
+
isBalanceLoading ? /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-16" }) : `${formattedBalance} ${selectedToken?.symbol ?? ""}`
|
|
4227
4705
|
] })
|
|
4228
4706
|
] }),
|
|
4229
4707
|
/* @__PURE__ */ jsxs("div", { className: "border-border bg-input flex items-center gap-2 rounded-[10px] border py-1 pr-1 pl-3", children: [
|
|
@@ -4246,7 +4724,8 @@ function WithdrawView({
|
|
|
4246
4724
|
{
|
|
4247
4725
|
type: "button",
|
|
4248
4726
|
onClick: handleMax,
|
|
4249
|
-
|
|
4727
|
+
disabled: isBalanceLoading,
|
|
4728
|
+
className: "bg-secondary text-foreground hover:bg-secondary/80 cursor-pointer rounded px-3 py-2.5 text-xs font-semibold transition-colors disabled:cursor-default disabled:opacity-50",
|
|
4250
4729
|
children: "MAX"
|
|
4251
4730
|
}
|
|
4252
4731
|
)
|
|
@@ -4349,6 +4828,7 @@ function WithdrawModalContent({
|
|
|
4349
4828
|
{
|
|
4350
4829
|
selectedTokenId: selectedToken?.id,
|
|
4351
4830
|
onSelect: (id) => {
|
|
4831
|
+
if (id !== selectedTokenId) setAmount("");
|
|
4352
4832
|
setSelectedTokenId(id);
|
|
4353
4833
|
setView("form");
|
|
4354
4834
|
}
|