@oasisprotocol/privana-sdk 0.5.6 → 0.5.8
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-TNR7AA52.cjs → chunk-EXFISDHQ.cjs} +1241 -101
- package/dist/chunk-EXFISDHQ.cjs.map +1 -0
- package/dist/{chunk-DLGIPF4N.js → chunk-ONXJGUOH.js} +1233 -103
- package/dist/chunk-ONXJGUOH.js.map +1 -0
- package/dist/index.cjs +781 -305
- 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 +545 -69
- 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-DLGIPF4N.js.map +0 -1
- package/dist/chunk-TNR7AA52.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, createProductOnRampFlowSnapshot, Skeleton, shortenAddress, formatCountdown, getExplorerAddressUrl, getExplorerLabel, formatTimeRemaining, getSharedBrowserStorageItem, removeSharedBrowserStorageItem, setSharedBrowserStorageItem, matchesOnRampTransaction, useTransakOnRamp, getTransakMinimumTargetBaseUnits, matchesFrozenOnRampToken, Button, canRetryOnRampVerification, FiatOnRampForm } from './chunk-ONXJGUOH.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-ONXJGUOH.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';
|
|
@@ -2315,7 +2315,7 @@ function BaseIcon({ className, size = 24 }) {
|
|
|
2315
2315
|
}
|
|
2316
2316
|
);
|
|
2317
2317
|
}
|
|
2318
|
-
function
|
|
2318
|
+
function EthereumIcon({ className, size = 24 }) {
|
|
2319
2319
|
return /* @__PURE__ */ jsxs(
|
|
2320
2320
|
"svg",
|
|
2321
2321
|
{
|
|
@@ -2366,18 +2366,19 @@ function WETHIcon({ className, size = 24 }) {
|
|
|
2366
2366
|
}
|
|
2367
2367
|
function getTokenIcon(symbol, size) {
|
|
2368
2368
|
const iconSize = size ?? 24;
|
|
2369
|
-
switch (symbol.toUpperCase()) {
|
|
2369
|
+
switch ((symbol ?? "").toUpperCase()) {
|
|
2370
2370
|
case "USDC":
|
|
2371
2371
|
return /* @__PURE__ */ jsx(USDCIcon, { size: iconSize });
|
|
2372
|
+
case "ETH":
|
|
2372
2373
|
case "WETH":
|
|
2373
|
-
return /* @__PURE__ */ jsx(
|
|
2374
|
+
return /* @__PURE__ */ jsx(EthereumIcon, { size: iconSize });
|
|
2374
2375
|
default:
|
|
2375
2376
|
return /* @__PURE__ */ jsx(
|
|
2376
2377
|
"div",
|
|
2377
2378
|
{
|
|
2378
2379
|
className: "bg-muted flex items-center justify-center rounded-full text-xs font-bold",
|
|
2379
2380
|
style: { width: iconSize, height: iconSize },
|
|
2380
|
-
children: symbol.slice(0, 2)
|
|
2381
|
+
children: (symbol ?? "?").slice(0, 2)
|
|
2381
2382
|
}
|
|
2382
2383
|
);
|
|
2383
2384
|
}
|
|
@@ -2385,8 +2386,12 @@ function getTokenIcon(symbol, size) {
|
|
|
2385
2386
|
function getChainIcon(chainId, size) {
|
|
2386
2387
|
const iconSize = size ?? 24;
|
|
2387
2388
|
switch (chainId) {
|
|
2389
|
+
case 8453:
|
|
2388
2390
|
case 84532:
|
|
2389
2391
|
return /* @__PURE__ */ jsx(BaseIcon, { size: iconSize });
|
|
2392
|
+
case 1:
|
|
2393
|
+
case 11155111:
|
|
2394
|
+
return /* @__PURE__ */ jsx(EthereumIcon, { size: iconSize });
|
|
2390
2395
|
default:
|
|
2391
2396
|
return /* @__PURE__ */ jsx(
|
|
2392
2397
|
"div",
|
|
@@ -2399,10 +2404,11 @@ function getChainIcon(chainId, size) {
|
|
|
2399
2404
|
}
|
|
2400
2405
|
}
|
|
2401
2406
|
function TokenSelectorView({ selectedTokenId, onSelect }) {
|
|
2402
|
-
const { enabledTokens } = usePrivanaContext();
|
|
2407
|
+
const { enabledTokens, getChainById: getChainById2 } = usePrivanaContext();
|
|
2403
2408
|
return /* @__PURE__ */ jsx("div", { className: "bg-muted flex flex-col rounded-[10px] p-3", children: /* @__PURE__ */ jsxs("div", { className: "flex max-h-72 flex-col gap-1 overflow-y-auto", children: [
|
|
2404
2409
|
enabledTokens.map((token) => {
|
|
2405
2410
|
const isSelected = selectedTokenId === token.id;
|
|
2411
|
+
const chainName = getChainById2(token.chainId)?.name;
|
|
2406
2412
|
return /* @__PURE__ */ jsxs(
|
|
2407
2413
|
"button",
|
|
2408
2414
|
{
|
|
@@ -2416,7 +2422,10 @@ function TokenSelectorView({ selectedTokenId, onSelect }) {
|
|
|
2416
2422
|
/* @__PURE__ */ jsx("div", { className: "h-6 w-6 shrink-0 overflow-hidden rounded-full", children: getTokenIcon(token.symbol, 24) }),
|
|
2417
2423
|
/* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
2418
2424
|
/* @__PURE__ */ jsx("div", { className: "text-foreground text-sm font-medium", children: token.symbol }),
|
|
2419
|
-
/* @__PURE__ */
|
|
2425
|
+
/* @__PURE__ */ jsxs("div", { className: "text-muted-foreground text-[11px]", children: [
|
|
2426
|
+
"on ",
|
|
2427
|
+
chainName ?? "\u2014"
|
|
2428
|
+
] })
|
|
2420
2429
|
] }),
|
|
2421
2430
|
isSelected && /* @__PURE__ */ jsx("div", { className: "bg-primary flex h-4 w-4 shrink-0 items-center justify-center rounded-full", children: /* @__PURE__ */ jsx(
|
|
2422
2431
|
"svg",
|
|
@@ -2446,15 +2455,356 @@ function TokenSelectorView({ selectedTokenId, onSelect }) {
|
|
|
2446
2455
|
enabledTokens.length === 0 && /* @__PURE__ */ jsx("p", { className: "text-muted-foreground px-3 py-6 text-center text-sm", children: "No tokens available" })
|
|
2447
2456
|
] }) });
|
|
2448
2457
|
}
|
|
2458
|
+
function assertTransakCheckoutPreconditions({
|
|
2459
|
+
activeIntentId,
|
|
2460
|
+
canOpen,
|
|
2461
|
+
canRecreateSession
|
|
2462
|
+
}) {
|
|
2463
|
+
if (activeIntentId && !canRecreateSession) {
|
|
2464
|
+
throw new Error("Continue signed-intent recovery instead of reopening this checkout");
|
|
2465
|
+
}
|
|
2466
|
+
if (!canOpen) {
|
|
2467
|
+
throw new Error("Card checkout is unavailable; close this purchase and start again");
|
|
2468
|
+
}
|
|
2469
|
+
}
|
|
2470
|
+
function TransakCardWidgetView({
|
|
2471
|
+
token,
|
|
2472
|
+
providerAssetCode,
|
|
2473
|
+
amount,
|
|
2474
|
+
allowance,
|
|
2475
|
+
lockServiceAddress,
|
|
2476
|
+
onCredited,
|
|
2477
|
+
onLockSubmitted,
|
|
2478
|
+
onLockFailed,
|
|
2479
|
+
onLeave,
|
|
2480
|
+
onUnsafeToCloseChange,
|
|
2481
|
+
onActiveFlowChange,
|
|
2482
|
+
useOnRamp = useTransakOnRamp
|
|
2483
|
+
}) {
|
|
2484
|
+
const [actionError, setActionError] = useState(null);
|
|
2485
|
+
const [rowError, setRowError] = useState(null);
|
|
2486
|
+
const [lockSettled, setLockSettled] = useState(false);
|
|
2487
|
+
const [lockError, setLockError] = useState(null);
|
|
2488
|
+
const [ownedTerminal, setOwnedTerminal] = useState(false);
|
|
2489
|
+
const ownedIntentIdRef = useRef(null);
|
|
2490
|
+
const postDepositLock = useMemo(
|
|
2491
|
+
() => allowance ? {
|
|
2492
|
+
serviceAddress: lockServiceAddress,
|
|
2493
|
+
maxAmount: BigInt(allowance.value),
|
|
2494
|
+
lockDuration: allowance.lockDuration
|
|
2495
|
+
} : void 0,
|
|
2496
|
+
[allowance, lockServiceAddress]
|
|
2497
|
+
);
|
|
2498
|
+
const ownsRecord = useCallback(
|
|
2499
|
+
(record) => Boolean(
|
|
2500
|
+
ownedIntentIdRef.current && matchesOnRampTransaction(record, ownedIntentIdRef.current)
|
|
2501
|
+
),
|
|
2502
|
+
[]
|
|
2503
|
+
);
|
|
2504
|
+
const {
|
|
2505
|
+
status,
|
|
2506
|
+
activeIntentId,
|
|
2507
|
+
pending,
|
|
2508
|
+
activeVerificationId,
|
|
2509
|
+
error,
|
|
2510
|
+
finalityProgress,
|
|
2511
|
+
depositAddress,
|
|
2512
|
+
minDepositBaseUnits,
|
|
2513
|
+
selectedToken,
|
|
2514
|
+
isLaunching,
|
|
2515
|
+
isWidgetOpen,
|
|
2516
|
+
canRecreateSession,
|
|
2517
|
+
widget,
|
|
2518
|
+
launch,
|
|
2519
|
+
recreateSession,
|
|
2520
|
+
closeWidget,
|
|
2521
|
+
finishPendingVerification,
|
|
2522
|
+
refreshPending
|
|
2523
|
+
} = useOnRamp({
|
|
2524
|
+
tokenId: token.id,
|
|
2525
|
+
postDepositLock,
|
|
2526
|
+
iframeTitle: "Card checkout",
|
|
2527
|
+
iframeClassName: "h-[680px] w-full border-0",
|
|
2528
|
+
onCredited: (_depositTxHash, record) => {
|
|
2529
|
+
if (!ownsRecord(record)) return;
|
|
2530
|
+
onCredited?.();
|
|
2531
|
+
if (!postDepositLock) {
|
|
2532
|
+
setOwnedTerminal(true);
|
|
2533
|
+
onActiveFlowChange?.(false);
|
|
2534
|
+
}
|
|
2535
|
+
},
|
|
2536
|
+
onLockSubmitted: (_response, record) => {
|
|
2537
|
+
if (!ownsRecord(record)) return;
|
|
2538
|
+
setLockError(null);
|
|
2539
|
+
setLockSettled(true);
|
|
2540
|
+
setOwnedTerminal(true);
|
|
2541
|
+
onActiveFlowChange?.(false);
|
|
2542
|
+
onLockSubmitted?.();
|
|
2543
|
+
},
|
|
2544
|
+
onLockFailed: (nextError, record) => {
|
|
2545
|
+
if (!ownsRecord(record)) return;
|
|
2546
|
+
setLockError(nextError);
|
|
2547
|
+
setOwnedTerminal(true);
|
|
2548
|
+
onActiveFlowChange?.(false);
|
|
2549
|
+
onLockFailed?.(nextError);
|
|
2550
|
+
}
|
|
2551
|
+
});
|
|
2552
|
+
const ownedIntentId = ownedIntentIdRef.current ?? activeIntentId;
|
|
2553
|
+
useEffect(() => {
|
|
2554
|
+
if (activeIntentId && !ownedIntentIdRef.current) {
|
|
2555
|
+
ownedIntentIdRef.current = activeIntentId;
|
|
2556
|
+
}
|
|
2557
|
+
}, [activeIntentId]);
|
|
2558
|
+
let amountBaseUnits;
|
|
2559
|
+
try {
|
|
2560
|
+
amountBaseUnits = parseUnits(amount, token.decimals);
|
|
2561
|
+
} catch {
|
|
2562
|
+
}
|
|
2563
|
+
const minimumTargetBaseUnits = minDepositBaseUnits === void 0 ? void 0 : getTransakMinimumTargetBaseUnits(minDepositBaseUnits);
|
|
2564
|
+
const belowMinimum = amountBaseUnits !== void 0 && minimumTargetBaseUnits !== void 0 && amountBaseUnits < minimumTargetBaseUnits;
|
|
2565
|
+
const minimumUnknown = minimumTargetBaseUnits === void 0;
|
|
2566
|
+
const tokenMismatch = !matchesFrozenOnRampToken(token, selectedToken);
|
|
2567
|
+
const isSettling = status === "awaiting-delivery" || status === "verifying";
|
|
2568
|
+
const lockPending = !!allowance && status === "credited" && !lockSettled && !lockError;
|
|
2569
|
+
const ownedPending = ownedIntentId ? pending.filter((record) => matchesOnRampTransaction(record, ownedIntentId)) : [];
|
|
2570
|
+
const ownedFlowActive = !ownedTerminal && (Boolean(activeIntentId && activeIntentId === ownedIntentId) || ownedPending.length > 0 || lockPending);
|
|
2571
|
+
const canOpen = Boolean(selectedToken && depositAddress && amountBaseUnits && amountBaseUnits > 0n) && !tokenMismatch && !minimumUnknown && !belowMinimum && !isLaunching && !isWidgetOpen && !isSettling && status !== "credited" && (!activeIntentId || canRecreateSession);
|
|
2572
|
+
useEffect(() => {
|
|
2573
|
+
onActiveFlowChange?.(ownedFlowActive);
|
|
2574
|
+
}, [onActiveFlowChange, ownedFlowActive]);
|
|
2575
|
+
const unsafeToClose = isLaunching || lockPending;
|
|
2576
|
+
useEffect(() => {
|
|
2577
|
+
onUnsafeToCloseChange?.(unsafeToClose);
|
|
2578
|
+
return () => onUnsafeToCloseChange?.(false);
|
|
2579
|
+
}, [onUnsafeToCloseChange, unsafeToClose]);
|
|
2580
|
+
const runCheckout = useCallback(async () => {
|
|
2581
|
+
setActionError(null);
|
|
2582
|
+
try {
|
|
2583
|
+
assertTransakCheckoutPreconditions({ activeIntentId, canOpen, canRecreateSession });
|
|
2584
|
+
setLockError(null);
|
|
2585
|
+
setLockSettled(false);
|
|
2586
|
+
setOwnedTerminal(false);
|
|
2587
|
+
if (!activeIntentId) ownedIntentIdRef.current = null;
|
|
2588
|
+
if (activeIntentId) await recreateSession();
|
|
2589
|
+
else await launch({ providerAssetCode, quoteCurrencyAmount: amount });
|
|
2590
|
+
} catch (nextError) {
|
|
2591
|
+
setActionError(
|
|
2592
|
+
nextError instanceof Error ? nextError : new Error("Failed to open card checkout")
|
|
2593
|
+
);
|
|
2594
|
+
}
|
|
2595
|
+
}, [
|
|
2596
|
+
activeIntentId,
|
|
2597
|
+
amount,
|
|
2598
|
+
canOpen,
|
|
2599
|
+
canRecreateSession,
|
|
2600
|
+
launch,
|
|
2601
|
+
providerAssetCode,
|
|
2602
|
+
recreateSession
|
|
2603
|
+
]);
|
|
2604
|
+
const handleClose = useCallback(async () => {
|
|
2605
|
+
setActionError(null);
|
|
2606
|
+
try {
|
|
2607
|
+
await closeWidget();
|
|
2608
|
+
} catch (nextError) {
|
|
2609
|
+
setActionError(
|
|
2610
|
+
nextError instanceof Error ? nextError : new Error("Failed to close card checkout")
|
|
2611
|
+
);
|
|
2612
|
+
}
|
|
2613
|
+
}, [closeWidget]);
|
|
2614
|
+
const handleLeave = useCallback(() => {
|
|
2615
|
+
setActionError(null);
|
|
2616
|
+
onActiveFlowChange?.(false);
|
|
2617
|
+
onLeave?.();
|
|
2618
|
+
}, [onActiveFlowChange, onLeave]);
|
|
2619
|
+
return /* @__PURE__ */ jsxs("div", { className: "bg-muted flex flex-col gap-4 rounded-[10px] p-5", children: [
|
|
2620
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
2621
|
+
/* @__PURE__ */ jsx("h2", { className: "text-foreground text-[28px] leading-8 font-medium", children: "Complete your purchase" }),
|
|
2622
|
+
/* @__PURE__ */ jsxs("p", { className: "text-muted-foreground mt-1 text-sm", children: [
|
|
2623
|
+
"Buy ",
|
|
2624
|
+
token.symbol,
|
|
2625
|
+
" and deposit it directly into your Privana balance."
|
|
2626
|
+
] })
|
|
2627
|
+
] }),
|
|
2628
|
+
/* @__PURE__ */ jsxs("div", { className: "border-border bg-card rounded-lg border p-3 text-sm", children: [
|
|
2629
|
+
/* @__PURE__ */ jsxs("p", { className: "text-foreground font-medium", children: [
|
|
2630
|
+
"Target receipt: at least ",
|
|
2631
|
+
amount,
|
|
2632
|
+
" ",
|
|
2633
|
+
token.symbol
|
|
2634
|
+
] }),
|
|
2635
|
+
/* @__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." }),
|
|
2636
|
+
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." })
|
|
2637
|
+
] }),
|
|
2638
|
+
widget ? /* @__PURE__ */ jsxs("div", { className: "border-border bg-card overflow-hidden rounded-xl border", children: [
|
|
2639
|
+
/* @__PURE__ */ jsxs("div", { className: "border-border flex items-center justify-between border-b px-4 py-2 text-sm", children: [
|
|
2640
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium", children: "Card checkout" }),
|
|
2641
|
+
/* @__PURE__ */ jsx(Button, { type: "button", variant: "outline", size: "sm", onClick: () => void handleClose(), children: "Close" })
|
|
2642
|
+
] }),
|
|
2643
|
+
widget
|
|
2644
|
+
] }) : status === "credited" && !lockPending && !lockError ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-2 py-8 text-center", children: [
|
|
2645
|
+
/* @__PURE__ */ jsx(CircleCheckIcon, { className: "text-primary size-8", "aria-hidden": true }),
|
|
2646
|
+
/* @__PURE__ */ jsx("p", { className: "text-foreground text-sm font-medium", children: "Purchase credited" }),
|
|
2647
|
+
/* @__PURE__ */ jsxs("p", { className: "text-muted-foreground text-sm", children: [
|
|
2648
|
+
"Your ",
|
|
2649
|
+
token.symbol,
|
|
2650
|
+
" deposit is now available in your balance."
|
|
2651
|
+
] })
|
|
2652
|
+
] }) : !activeIntentId || canRecreateSession ? /* @__PURE__ */ jsxs(Button, { type: "button", disabled: !canOpen, onClick: () => void runCheckout(), children: [
|
|
2653
|
+
isLaunching && /* @__PURE__ */ jsx(Loader2, { className: "animate-spin", "aria-hidden": true }),
|
|
2654
|
+
isLaunching ? "Opening checkout\u2026" : activeIntentId ? "Reopen card checkout" : allowance ? "Sign policy and open checkout" : "Open card checkout"
|
|
2655
|
+
] }) : /* @__PURE__ */ jsx("p", { className: "text-muted-foreground text-sm", children: "This signed purchase is in recovery. Do not open another checkout for it." }),
|
|
2656
|
+
!depositAddress && !error && !actionError && /* @__PURE__ */ jsx("p", { className: "text-muted-foreground text-sm", children: "Preparing your secure deposit address\u2026" }),
|
|
2657
|
+
tokenMismatch && /* @__PURE__ */ jsx("p", { className: "text-destructive text-sm", role: "alert", children: "The token configuration changed. Close this purchase and start again." }),
|
|
2658
|
+
!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." }),
|
|
2659
|
+
belowMinimum && minimumTargetBaseUnits !== void 0 && /* @__PURE__ */ jsxs("p", { className: "text-destructive text-sm", role: "alert", children: [
|
|
2660
|
+
"Minimum target is ",
|
|
2661
|
+
formatUnits(minimumTargetBaseUnits, token.decimals),
|
|
2662
|
+
" ",
|
|
2663
|
+
token.symbol,
|
|
2664
|
+
", including a 5% delivery buffer."
|
|
2665
|
+
] }),
|
|
2666
|
+
isSettling && pending.length === 0 && /* @__PURE__ */ jsxs("p", { className: "text-muted-foreground flex items-center gap-2 text-sm", children: [
|
|
2667
|
+
/* @__PURE__ */ jsx(Loader2, { className: "size-4 animate-spin", "aria-hidden": true }),
|
|
2668
|
+
"Verifying your purchase\u2026"
|
|
2669
|
+
] }),
|
|
2670
|
+
lockPending && /* @__PURE__ */ jsxs("p", { className: "text-muted-foreground flex items-center gap-2 text-sm", children: [
|
|
2671
|
+
/* @__PURE__ */ jsx(Loader2, { className: "size-4 animate-spin", "aria-hidden": true }),
|
|
2672
|
+
"Purchase credited. Locking your funds\u2026"
|
|
2673
|
+
] }),
|
|
2674
|
+
pending.length > 0 && /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
|
|
2675
|
+
/* @__PURE__ */ jsx("p", { className: "text-foreground text-sm font-medium", children: "Validating purchases" }),
|
|
2676
|
+
pending.map((record) => {
|
|
2677
|
+
const isActivelyVerifying = record.transaction_id === activeVerificationId;
|
|
2678
|
+
const progress = parseFinalityProgress(finalityProgress[record.transaction_id]);
|
|
2679
|
+
const showRetry = canRetryOnRampVerification(record, activeVerificationId);
|
|
2680
|
+
return /* @__PURE__ */ jsxs(
|
|
2681
|
+
"div",
|
|
2682
|
+
{
|
|
2683
|
+
className: "border-border flex flex-col gap-2 rounded-md border p-2",
|
|
2684
|
+
children: [
|
|
2685
|
+
/* @__PURE__ */ jsxs("p", { className: "text-muted-foreground flex items-center gap-1 text-xs", children: [
|
|
2686
|
+
/* @__PURE__ */ jsx(Loader2, { className: "size-3 animate-spin", "aria-hidden": true }),
|
|
2687
|
+
record.on_chain_tx_hash ? progress ?? (isActivelyVerifying ? "Verifying\u2026" : "Ready to verify") : "Waiting for provider delivery\u2026"
|
|
2688
|
+
] }),
|
|
2689
|
+
rowError?.id === record.transaction_id && /* @__PURE__ */ jsx("p", { className: "text-destructive text-xs", children: rowError.message }),
|
|
2690
|
+
showRetry && /* @__PURE__ */ jsx(
|
|
2691
|
+
Button,
|
|
2692
|
+
{
|
|
2693
|
+
type: "button",
|
|
2694
|
+
variant: "outline",
|
|
2695
|
+
size: "sm",
|
|
2696
|
+
onClick: async () => {
|
|
2697
|
+
setRowError(null);
|
|
2698
|
+
try {
|
|
2699
|
+
await finishPendingVerification(record);
|
|
2700
|
+
} catch (nextError) {
|
|
2701
|
+
setRowError({
|
|
2702
|
+
id: record.transaction_id,
|
|
2703
|
+
message: nextError instanceof Error ? nextError.message : "Verification failed"
|
|
2704
|
+
});
|
|
2705
|
+
}
|
|
2706
|
+
},
|
|
2707
|
+
children: "Retry verification"
|
|
2708
|
+
}
|
|
2709
|
+
),
|
|
2710
|
+
!record.on_chain_tx_hash && /* @__PURE__ */ jsx(
|
|
2711
|
+
Button,
|
|
2712
|
+
{
|
|
2713
|
+
type: "button",
|
|
2714
|
+
variant: "outline",
|
|
2715
|
+
size: "sm",
|
|
2716
|
+
onClick: () => void refreshPending(),
|
|
2717
|
+
children: "Refresh delivery"
|
|
2718
|
+
}
|
|
2719
|
+
)
|
|
2720
|
+
]
|
|
2721
|
+
},
|
|
2722
|
+
record.transaction_id
|
|
2723
|
+
);
|
|
2724
|
+
})
|
|
2725
|
+
] }),
|
|
2726
|
+
onLeave && ownedFlowActive && !unsafeToClose && /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
2727
|
+
/* @__PURE__ */ jsx(Button, { type: "button", variant: "outline", onClick: handleLeave, children: "Leave checkout" }),
|
|
2728
|
+
/* @__PURE__ */ jsx("p", { className: "text-muted-foreground text-xs", children: "Privana will keep this signed purchase available for exact recovery." })
|
|
2729
|
+
] }),
|
|
2730
|
+
(actionError ?? error) && /* @__PURE__ */ jsx("p", { className: "text-destructive text-sm", role: "alert", children: (actionError ?? error)?.message }),
|
|
2731
|
+
lockError && /* @__PURE__ */ jsxs("p", { className: "text-destructive text-sm", role: "alert", children: [
|
|
2732
|
+
"Purchase credited, but locking the funds failed: ",
|
|
2733
|
+
lockError.message
|
|
2734
|
+
] })
|
|
2735
|
+
] });
|
|
2736
|
+
}
|
|
2737
|
+
function parseFinalityProgress(message) {
|
|
2738
|
+
if (!message) return null;
|
|
2739
|
+
const match = message.match(/(\d+\/\d+)\s+confirmations/i);
|
|
2740
|
+
return match ? `${match[1]} confirmations` : null;
|
|
2741
|
+
}
|
|
2449
2742
|
function CreditCardWidgetView({
|
|
2450
2743
|
token,
|
|
2744
|
+
onRamp,
|
|
2451
2745
|
amount,
|
|
2452
2746
|
allowance,
|
|
2747
|
+
lockServiceAddress,
|
|
2453
2748
|
onCredited,
|
|
2454
2749
|
onLockSubmitted,
|
|
2455
|
-
onLockFailed
|
|
2750
|
+
onLockFailed,
|
|
2751
|
+
onLeave,
|
|
2752
|
+
onUnsafeToCloseChange,
|
|
2753
|
+
onActiveFlowChange
|
|
2456
2754
|
}) {
|
|
2457
|
-
|
|
2755
|
+
if (onRamp.unavailableReason || !token || !onRamp.provider || !onRamp.providerAssetCode) {
|
|
2756
|
+
return /* @__PURE__ */ jsxs("div", { className: "bg-muted flex flex-col gap-2 rounded-[10px] p-5", children: [
|
|
2757
|
+
/* @__PURE__ */ jsx("h2", { className: "text-foreground text-[28px] leading-8 font-medium", children: "Card purchases unavailable" }),
|
|
2758
|
+
/* @__PURE__ */ jsx("p", { className: "text-destructive text-sm", children: onRamp.unavailableReason ?? "The card on-ramp is not configured for this token." })
|
|
2759
|
+
] });
|
|
2760
|
+
}
|
|
2761
|
+
if (onRamp.provider === "transak") {
|
|
2762
|
+
return /* @__PURE__ */ jsx(
|
|
2763
|
+
TransakCardWidgetView,
|
|
2764
|
+
{
|
|
2765
|
+
token,
|
|
2766
|
+
providerAssetCode: onRamp.providerAssetCode,
|
|
2767
|
+
amount,
|
|
2768
|
+
allowance,
|
|
2769
|
+
lockServiceAddress,
|
|
2770
|
+
onCredited,
|
|
2771
|
+
onLockSubmitted,
|
|
2772
|
+
onLockFailed,
|
|
2773
|
+
onLeave,
|
|
2774
|
+
onUnsafeToCloseChange,
|
|
2775
|
+
onActiveFlowChange
|
|
2776
|
+
}
|
|
2777
|
+
);
|
|
2778
|
+
}
|
|
2779
|
+
return /* @__PURE__ */ jsx(
|
|
2780
|
+
MoonPayCardWidgetView,
|
|
2781
|
+
{
|
|
2782
|
+
token,
|
|
2783
|
+
amount,
|
|
2784
|
+
allowance,
|
|
2785
|
+
lockServiceAddress,
|
|
2786
|
+
onCredited,
|
|
2787
|
+
onLockSubmitted,
|
|
2788
|
+
onLockFailed,
|
|
2789
|
+
onLeaveFlow: onLeave,
|
|
2790
|
+
onUnsafeToCloseChange,
|
|
2791
|
+
onActiveFlowChange
|
|
2792
|
+
}
|
|
2793
|
+
);
|
|
2794
|
+
}
|
|
2795
|
+
function MoonPayCardWidgetView({
|
|
2796
|
+
token,
|
|
2797
|
+
amount,
|
|
2798
|
+
allowance,
|
|
2799
|
+
lockServiceAddress,
|
|
2800
|
+
onCredited,
|
|
2801
|
+
onLockSubmitted,
|
|
2802
|
+
onLockFailed,
|
|
2803
|
+
onLeaveFlow,
|
|
2804
|
+
onUnsafeToCloseChange,
|
|
2805
|
+
onActiveFlowChange
|
|
2806
|
+
}) {
|
|
2807
|
+
const moonpayCurrencyCode = token.moonpayCurrencyCode;
|
|
2458
2808
|
const containerRef = useRef(null);
|
|
2459
2809
|
const [widgetTheme, setWidgetTheme] = useState();
|
|
2460
2810
|
useEffect(() => {
|
|
@@ -2462,26 +2812,32 @@ function CreditCardWidgetView({
|
|
|
2462
2812
|
}, []);
|
|
2463
2813
|
return /* @__PURE__ */ jsxs("div", { ref: containerRef, className: "bg-muted flex flex-col gap-6 rounded-[10px] p-5", children: [
|
|
2464
2814
|
/* @__PURE__ */ jsx("h2", { className: "text-foreground text-[28px] leading-8 font-medium", children: "Complete your purchase" }),
|
|
2465
|
-
|
|
2815
|
+
moonpayCurrencyCode ? /* @__PURE__ */ jsx(
|
|
2466
2816
|
FiatOnRampForm,
|
|
2467
2817
|
{
|
|
2468
2818
|
tokenId: token.id,
|
|
2819
|
+
frozenToken: token,
|
|
2469
2820
|
currencyCode: moonpayCurrencyCode,
|
|
2470
2821
|
quoteCurrencyAmount: amount || void 0,
|
|
2471
2822
|
lockAmount: true,
|
|
2472
2823
|
variant: "embedded",
|
|
2473
2824
|
autoStart: true,
|
|
2474
2825
|
theme: widgetTheme,
|
|
2826
|
+
onlyRouteActiveIntentCallbacks: true,
|
|
2827
|
+
onUnsafeToCloseChange,
|
|
2828
|
+
onActiveFlowChange,
|
|
2475
2829
|
postDepositLock: allowance ? {
|
|
2830
|
+
serviceAddress: lockServiceAddress,
|
|
2476
2831
|
maxAmount: BigInt(allowance.value),
|
|
2477
2832
|
lockDuration: allowance.lockDuration
|
|
2478
2833
|
} : void 0,
|
|
2479
2834
|
onCredited,
|
|
2480
2835
|
onLockSubmitted,
|
|
2481
|
-
onLockFailed
|
|
2836
|
+
onLockFailed,
|
|
2837
|
+
onLeaveFlow
|
|
2482
2838
|
}
|
|
2483
2839
|
) : /* @__PURE__ */ jsxs("p", { className: "text-muted-foreground text-sm", children: [
|
|
2484
|
-
token
|
|
2840
|
+
token.symbol,
|
|
2485
2841
|
" isn\u2019t available for card purchases yet."
|
|
2486
2842
|
] })
|
|
2487
2843
|
] });
|
|
@@ -2790,7 +3146,7 @@ function CopyIcon() {
|
|
|
2790
3146
|
}
|
|
2791
3147
|
);
|
|
2792
3148
|
}
|
|
2793
|
-
function
|
|
3149
|
+
function CircleCheckIcon2() {
|
|
2794
3150
|
return /* @__PURE__ */ jsxs("svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", children: [
|
|
2795
3151
|
/* @__PURE__ */ jsx("circle", { cx: "10", cy: "10", r: "9", stroke: "currentColor", strokeWidth: "1.5" }),
|
|
2796
3152
|
/* @__PURE__ */ jsx(
|
|
@@ -2909,7 +3265,7 @@ function PolicyTermRow({
|
|
|
2909
3265
|
"mt-0.5 shrink-0",
|
|
2910
3266
|
kind === "permission" ? "text-emerald-500" : "text-orange-500"
|
|
2911
3267
|
),
|
|
2912
|
-
children: kind === "permission" ? /* @__PURE__ */ jsx(
|
|
3268
|
+
children: kind === "permission" ? /* @__PURE__ */ jsx(CircleCheckIcon2, {}) : /* @__PURE__ */ jsx(CircleXIcon, {})
|
|
2913
3269
|
}
|
|
2914
3270
|
),
|
|
2915
3271
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
@@ -2969,6 +3325,7 @@ function AllowancePolicySection({
|
|
|
2969
3325
|
function DepositView({
|
|
2970
3326
|
source,
|
|
2971
3327
|
selectedToken,
|
|
3328
|
+
onRamp,
|
|
2972
3329
|
amount,
|
|
2973
3330
|
allowance,
|
|
2974
3331
|
externalMinimum,
|
|
@@ -2987,6 +3344,8 @@ function DepositView({
|
|
|
2987
3344
|
const isConnectedSource = source === "connected";
|
|
2988
3345
|
const isExternal = source === "external";
|
|
2989
3346
|
const isCreditCard = source === "credit-card";
|
|
3347
|
+
const isMoonPayCard = isCreditCard && isMoonPayProductOnRamp(onRamp);
|
|
3348
|
+
const isTransakCard = isCreditCard && onRamp.provider === "transak";
|
|
2990
3349
|
const isNative = selectedToken?.contract === zeroAddress;
|
|
2991
3350
|
const { data: nativeBalanceData } = useBalance$1({
|
|
2992
3351
|
address,
|
|
@@ -3010,15 +3369,15 @@ function DepositView({
|
|
|
3010
3369
|
} = useMoonpayLimits({
|
|
3011
3370
|
currencyCode: selectedToken?.moonpayCurrencyCode,
|
|
3012
3371
|
apiBaseUrl: networkConfig.moonpayApiUrl,
|
|
3013
|
-
enabled:
|
|
3372
|
+
enabled: isMoonPayCard
|
|
3014
3373
|
});
|
|
3015
3374
|
const hasValidAmount = !!amount && parseFloat(amount) > 0;
|
|
3016
|
-
const maxAmountDecimals =
|
|
3375
|
+
const maxAmountDecimals = isMoonPayCard ? 2 : selectedToken?.decimals;
|
|
3017
3376
|
const tooManyDecimals = hasValidAmount && maxAmountDecimals != null && amount.includes(".") && amount.split(".")[1].length > maxAmountDecimals;
|
|
3018
3377
|
const exceedsBalance = isConnectedSource && hasValidAmount && !tooManyDecimals && !!selectedToken && walletBalance != null && parseTokenAmount(amount, selectedToken.decimals) > walletBalance;
|
|
3019
|
-
const belowMoonpayMin =
|
|
3020
|
-
const moonpayLimitsUnready =
|
|
3021
|
-
const creditCardUnavailable = isCreditCard && !!
|
|
3378
|
+
const belowMoonpayMin = isMoonPayCard && hasValidAmount && moonpayMinBuy != null && parseFloat(amount) < moonpayMinBuy;
|
|
3379
|
+
const moonpayLimitsUnready = isMoonPayCard && !!onRamp.providerAssetCode && moonpayMinBuy == null;
|
|
3380
|
+
const creditCardUnavailable = isCreditCard && !!onRamp.unavailableReason;
|
|
3022
3381
|
const externalTokenUnavailable = isExternal && !!selectedToken && isNative;
|
|
3023
3382
|
const externalMinimumRequired = isExternal && !!allowance && !!selectedToken;
|
|
3024
3383
|
const externalMinimumLoading = externalMinimumRequired && externalMinimum === void 0;
|
|
@@ -3033,8 +3392,8 @@ function DepositView({
|
|
|
3033
3392
|
};
|
|
3034
3393
|
return /* @__PURE__ */ jsxs("div", { className: "bg-muted flex flex-col gap-6 rounded-[10px] p-5", children: [
|
|
3035
3394
|
isCreditCard ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
|
|
3036
|
-
/* @__PURE__ */ jsx("h2", { className: "text-foreground text-[28px] leading-8 font-medium", children: "Buy with
|
|
3037
|
-
/* @__PURE__ */ jsx("p", { className: "text-muted-foreground text-sm", children: "Enter your deposit amount and proceed to sign a policy." })
|
|
3395
|
+
/* @__PURE__ */ jsx("h2", { className: "text-foreground text-[28px] leading-8 font-medium", children: "Buy with card and deposit" }),
|
|
3396
|
+
/* @__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." })
|
|
3038
3397
|
] }) : /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
|
|
3039
3398
|
/* @__PURE__ */ jsxs("h2", { className: "text-foreground text-[28px] leading-8 font-medium", children: [
|
|
3040
3399
|
"Deposit from ",
|
|
@@ -3049,7 +3408,7 @@ function DepositView({
|
|
|
3049
3408
|
{
|
|
3050
3409
|
type: "button",
|
|
3051
3410
|
onClick: onSelectToken,
|
|
3052
|
-
disabled: isSubmitting,
|
|
3411
|
+
disabled: isSubmitting || isCreditCard && onRamp.tokenSelectionLocked,
|
|
3053
3412
|
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",
|
|
3054
3413
|
children: [
|
|
3055
3414
|
selectedToken ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
@@ -3062,7 +3421,7 @@ function DepositView({
|
|
|
3062
3421
|
] })
|
|
3063
3422
|
] })
|
|
3064
3423
|
] }) : /* @__PURE__ */ jsx("span", { className: "text-muted-foreground flex-1 text-sm", children: "Select token" }),
|
|
3065
|
-
/* @__PURE__ */ jsx("div", { className: "text-muted-foreground flex h-5 w-5 items-center justify-center", children: /* @__PURE__ */ jsx(ChevronRightIcon, {}) })
|
|
3424
|
+
(!isCreditCard || !onRamp.tokenSelectionLocked) && /* @__PURE__ */ jsx("div", { className: "text-muted-foreground flex h-5 w-5 items-center justify-center", children: /* @__PURE__ */ jsx(ChevronRightIcon, {}) })
|
|
3066
3425
|
]
|
|
3067
3426
|
}
|
|
3068
3427
|
)
|
|
@@ -3132,12 +3491,9 @@ function DepositView({
|
|
|
3132
3491
|
] }),
|
|
3133
3492
|
externalMinimumLoading && /* @__PURE__ */ jsx("p", { className: "text-muted-foreground text-sm", children: "Checking minimum deposit\u2026" }),
|
|
3134
3493
|
externalMinimumUnavailable && /* @__PURE__ */ jsx("p", { className: "text-destructive text-sm", children: "Couldn\u2019t load the minimum deposit. Please try again." }),
|
|
3135
|
-
|
|
3136
|
-
|
|
3137
|
-
creditCardUnavailable && /* @__PURE__ */
|
|
3138
|
-
selectedToken?.symbol ?? "This token",
|
|
3139
|
-
" isn\u2019t available for card purchases yet."
|
|
3140
|
-
] }),
|
|
3494
|
+
isMoonPayCard && moonpayLimitsError && /* @__PURE__ */ jsx("p", { className: "text-destructive text-sm", children: "Couldn\u2019t load purchase limits. Please try again." }),
|
|
3495
|
+
isMoonPayCard && moonpayLimitsLoading && /* @__PURE__ */ jsx("p", { className: "text-muted-foreground text-sm", children: "Checking purchase limits\u2026" }),
|
|
3496
|
+
creditCardUnavailable && /* @__PURE__ */ jsx("p", { className: "text-destructive text-sm", children: onRamp.unavailableReason }),
|
|
3141
3497
|
externalTokenUnavailable && /* @__PURE__ */ jsxs("p", { className: "text-destructive text-sm", children: [
|
|
3142
3498
|
selectedToken?.symbol ?? "This token",
|
|
3143
3499
|
" can\u2019t be used for external deposits. Choose an ERC20 token."
|
|
@@ -3164,7 +3520,7 @@ function DepositView({
|
|
|
3164
3520
|
if (selectedToken) onSubmit({ source, tokenId: selectedToken.id, amount });
|
|
3165
3521
|
},
|
|
3166
3522
|
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",
|
|
3167
|
-
children: needsConnect ? "Connect Wallet" : allowance ? "Sign Policy and Deposit" : "Deposit"
|
|
3523
|
+
children: needsConnect ? "Connect Wallet" : isTransakCard ? "Continue" : allowance ? "Sign Policy and Deposit" : "Deposit"
|
|
3168
3524
|
}
|
|
3169
3525
|
)
|
|
3170
3526
|
] });
|
|
@@ -3476,9 +3832,11 @@ function ExternalDepositView({
|
|
|
3476
3832
|
] })
|
|
3477
3833
|
] });
|
|
3478
3834
|
}
|
|
3479
|
-
function MoonPayGate({
|
|
3480
|
-
|
|
3481
|
-
|
|
3835
|
+
function MoonPayGate({
|
|
3836
|
+
enabled,
|
|
3837
|
+
apiKey,
|
|
3838
|
+
children
|
|
3839
|
+
}) {
|
|
3482
3840
|
if (!enabled || !apiKey) return /* @__PURE__ */ jsx(Fragment, { children });
|
|
3483
3841
|
return /* @__PURE__ */ jsx(MoonPayProvider, { apiKey, children });
|
|
3484
3842
|
}
|
|
@@ -3565,15 +3923,52 @@ function DepositModalContent({
|
|
|
3565
3923
|
onCloseBlockedChange,
|
|
3566
3924
|
onExit
|
|
3567
3925
|
}) {
|
|
3568
|
-
const {
|
|
3926
|
+
const {
|
|
3927
|
+
serviceName,
|
|
3928
|
+
enabledTokens,
|
|
3929
|
+
defaultToken,
|
|
3930
|
+
hostedAuthConfig,
|
|
3931
|
+
serviceAddress,
|
|
3932
|
+
getChainById: getChainById2,
|
|
3933
|
+
getTokenById,
|
|
3934
|
+
networkConfig,
|
|
3935
|
+
onRamp
|
|
3936
|
+
} = usePrivanaContext();
|
|
3569
3937
|
const { address } = useAccount();
|
|
3938
|
+
const { privateReadQueryScope } = usePrivateReadRequest();
|
|
3939
|
+
const [privateReadApiUrl, accountingChainId, beneficiaryAddress] = privateReadQueryScope;
|
|
3570
3940
|
const appName = serviceName ?? "Privana";
|
|
3571
3941
|
const [activeTab, setActiveTab] = useState(defaultTab);
|
|
3572
3942
|
const [view, setView] = useState("method");
|
|
3573
3943
|
const [source, setSource] = useState("connected");
|
|
3574
3944
|
const [selectedTokenId, setSelectedTokenId] = useState(defaultToken?.id ?? "");
|
|
3575
3945
|
const [amount, setAmount] = useState("");
|
|
3576
|
-
const
|
|
3946
|
+
const [cardFlow, setCardFlow] = useState(null);
|
|
3947
|
+
const [cardFlowActive, setCardFlowActive] = useState(false);
|
|
3948
|
+
const [cardUnsafeToClose, setCardUnsafeToClose] = useState(false);
|
|
3949
|
+
const nextCardFlowId = useRef(0);
|
|
3950
|
+
const stateSelectedToken = enabledTokens.find((t) => t.id === selectedTokenId) ?? defaultToken;
|
|
3951
|
+
const cardOnRamp = useMemo(
|
|
3952
|
+
() => resolveProductOnRamp({
|
|
3953
|
+
config: onRamp,
|
|
3954
|
+
enabledTokens,
|
|
3955
|
+
legacyToken: stateSelectedToken,
|
|
3956
|
+
moonpayApiKey: networkConfig.moonpayApiKey
|
|
3957
|
+
}),
|
|
3958
|
+
[enabledTokens, networkConfig.moonpayApiKey, onRamp, stateSelectedToken]
|
|
3959
|
+
);
|
|
3960
|
+
const cardOnRampScope = useMemo(
|
|
3961
|
+
() => ({
|
|
3962
|
+
apiUrl: privateReadApiUrl,
|
|
3963
|
+
accountingChainId,
|
|
3964
|
+
accountingContract: networkConfig.accountingContract,
|
|
3965
|
+
beneficiaryAddress
|
|
3966
|
+
}),
|
|
3967
|
+
[accountingChainId, beneficiaryAddress, networkConfig.accountingContract, privateReadApiUrl]
|
|
3968
|
+
);
|
|
3969
|
+
const mountedCardFlow = cardFlow && matchesProductOnRampScope(cardFlow.scope, cardOnRampScope) ? cardFlow : null;
|
|
3970
|
+
const displayedCardOnRamp = view === "credit-card-widget" && mountedCardFlow ? mountedCardFlow.selection : cardOnRamp;
|
|
3971
|
+
const selectedToken = source === "credit-card" ? displayedCardOnRamp.token : stateSelectedToken;
|
|
3577
3972
|
const externalDepositAddress = useDepositAddress({
|
|
3578
3973
|
enabled: source === "external" && (view === "deposit" || view === "external-deposit")
|
|
3579
3974
|
});
|
|
@@ -3587,6 +3982,9 @@ function DepositModalContent({
|
|
|
3587
3982
|
setView("method");
|
|
3588
3983
|
setAmount("");
|
|
3589
3984
|
setSelectedTokenId("");
|
|
3985
|
+
setCardFlow(null);
|
|
3986
|
+
setCardFlowActive(false);
|
|
3987
|
+
setCardUnsafeToClose(false);
|
|
3590
3988
|
}
|
|
3591
3989
|
}, [address, hostedAuthConfig]);
|
|
3592
3990
|
const openDeposit = (next) => {
|
|
@@ -3609,9 +4007,33 @@ function DepositModalContent({
|
|
|
3609
4007
|
}
|
|
3610
4008
|
};
|
|
3611
4009
|
const finishCardPurchase = () => {
|
|
4010
|
+
setCardFlowActive(false);
|
|
4011
|
+
setCardUnsafeToClose(false);
|
|
3612
4012
|
setAmount("");
|
|
3613
4013
|
onDepositSuccess?.();
|
|
3614
4014
|
};
|
|
4015
|
+
const leaveCardPurchase = useCallback(() => {
|
|
4016
|
+
setCardFlow(null);
|
|
4017
|
+
setCardFlowActive(false);
|
|
4018
|
+
setCardUnsafeToClose(false);
|
|
4019
|
+
setAmount("");
|
|
4020
|
+
setView("deposit");
|
|
4021
|
+
}, []);
|
|
4022
|
+
useEffect(() => {
|
|
4023
|
+
if (cardFlow && !matchesProductOnRampScope(cardFlow.scope, cardOnRampScope)) {
|
|
4024
|
+
leaveCardPurchase();
|
|
4025
|
+
}
|
|
4026
|
+
}, [cardFlow, cardOnRampScope, leaveCardPurchase]);
|
|
4027
|
+
const cardOutcomeCallbacks = mountedCardFlow ? createProductOnRampOutcomeCallbacks({
|
|
4028
|
+
requiresLock: mountedCardFlow.requiresLock,
|
|
4029
|
+
onComplete: finishCardPurchase,
|
|
4030
|
+
onLockFailed: (err) => {
|
|
4031
|
+
setCardFlowActive(false);
|
|
4032
|
+
setCardUnsafeToClose(false);
|
|
4033
|
+
setLockFailure(err);
|
|
4034
|
+
onLockFailed?.(err);
|
|
4035
|
+
}
|
|
4036
|
+
}) : null;
|
|
3615
4037
|
const {
|
|
3616
4038
|
txHash,
|
|
3617
4039
|
isGettingAddress,
|
|
@@ -3681,7 +4103,7 @@ function DepositModalContent({
|
|
|
3681
4103
|
setView("deposit");
|
|
3682
4104
|
}
|
|
3683
4105
|
}, [allowance, externalLock.session, view]);
|
|
3684
|
-
const isUnsafeToClose = (isGettingAddress || isSendingTransaction) && !cancelled || externalLock.isSigning || externalLock.isSubmittingLock;
|
|
4106
|
+
const isUnsafeToClose = (isGettingAddress || isSendingTransaction) && !cancelled || externalLock.isSigning || externalLock.isSubmittingLock || cardUnsafeToClose;
|
|
3685
4107
|
useEffect(() => {
|
|
3686
4108
|
onCloseBlockedChange?.(isUnsafeToClose);
|
|
3687
4109
|
}, [isUnsafeToClose, onCloseBlockedChange]);
|
|
@@ -3724,6 +4146,28 @@ function DepositModalContent({
|
|
|
3724
4146
|
return;
|
|
3725
4147
|
}
|
|
3726
4148
|
if (args.source === "credit-card") {
|
|
4149
|
+
if (cardFlow && cardFlowActive) {
|
|
4150
|
+
setView("credit-card-widget");
|
|
4151
|
+
return;
|
|
4152
|
+
}
|
|
4153
|
+
try {
|
|
4154
|
+
setCardFlow(
|
|
4155
|
+
createProductOnRampFlowSnapshot({
|
|
4156
|
+
id: ++nextCardFlowId.current,
|
|
4157
|
+
selection: cardOnRamp,
|
|
4158
|
+
amount: args.amount,
|
|
4159
|
+
allowance,
|
|
4160
|
+
lockServiceAddress: serviceAddress,
|
|
4161
|
+
moonpayApiKey: networkConfig.moonpayApiKey,
|
|
4162
|
+
scope: cardOnRampScope
|
|
4163
|
+
})
|
|
4164
|
+
);
|
|
4165
|
+
} catch (error) {
|
|
4166
|
+
toast.error(error instanceof Error ? error.message : "Card purchase is unavailable");
|
|
4167
|
+
return;
|
|
4168
|
+
}
|
|
4169
|
+
setCardFlowActive(false);
|
|
4170
|
+
setCardUnsafeToClose(false);
|
|
3727
4171
|
setView("credit-card-widget");
|
|
3728
4172
|
return;
|
|
3729
4173
|
}
|
|
@@ -3801,6 +4245,12 @@ function DepositModalContent({
|
|
|
3801
4245
|
setCancelled(false);
|
|
3802
4246
|
resetDeposit();
|
|
3803
4247
|
if (view === "external-deposit") setView("deposit");
|
|
4248
|
+
if (view === "credit-card-widget") {
|
|
4249
|
+
setCardFlow(null);
|
|
4250
|
+
setCardFlowActive(false);
|
|
4251
|
+
setCardUnsafeToClose(false);
|
|
4252
|
+
setView("deposit");
|
|
4253
|
+
}
|
|
3804
4254
|
};
|
|
3805
4255
|
const handleExternalLockRetry = () => {
|
|
3806
4256
|
externalLock.retryAfterCredit().catch((err) => {
|
|
@@ -3824,12 +4274,20 @@ function DepositModalContent({
|
|
|
3824
4274
|
retryVerification().catch(() => {
|
|
3825
4275
|
});
|
|
3826
4276
|
};
|
|
3827
|
-
const back = view === "external-deposit" ? { to: "deposit", label: "Deposit from External Wallet" } : view === "credit-card-widget" ? { to: "deposit", label: "Buy with
|
|
4277
|
+
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" };
|
|
3828
4278
|
const goBack = () => {
|
|
3829
4279
|
if (view === "external-deposit" && externalLock.session) {
|
|
3830
4280
|
toast.error("Cancel the active deposit from the address screen before going back");
|
|
3831
4281
|
return;
|
|
3832
4282
|
}
|
|
4283
|
+
if (view === "credit-card-widget" && (cardUnsafeToClose || cardFlowActive)) {
|
|
4284
|
+
toast.error("Finish or recover the active card purchase before going back");
|
|
4285
|
+
return;
|
|
4286
|
+
}
|
|
4287
|
+
if (view === "credit-card-widget") {
|
|
4288
|
+
setCardFlow(null);
|
|
4289
|
+
setCardUnsafeToClose(false);
|
|
4290
|
+
}
|
|
3833
4291
|
if (back.to === "method") {
|
|
3834
4292
|
setAmount("");
|
|
3835
4293
|
setSelectedTokenId("");
|
|
@@ -3915,8 +4373,8 @@ function DepositModalContent({
|
|
|
3915
4373
|
] }),
|
|
3916
4374
|
activeView === "method" && /* @__PURE__ */ jsxs("div", { className: "bg-muted flex flex-col gap-6 rounded-[10px] p-5", children: [
|
|
3917
4375
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
|
|
3918
|
-
/* @__PURE__ */ jsx("h2", { className: "text-foreground text-[28px] leading-8 font-medium", children: activeTab === "crypto" ? "Choose the deposit method" : "Buy with
|
|
3919
|
-
/* @__PURE__ */ jsx("p", { className: "text-muted-foreground text-sm", children: activeTab === "crypto" ? "Choose the deposit method." : "
|
|
4376
|
+
/* @__PURE__ */ jsx("h2", { className: "text-foreground text-[28px] leading-8 font-medium", children: activeTab === "crypto" ? "Choose the deposit method" : "Buy with card and deposit" }),
|
|
4377
|
+
/* @__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." })
|
|
3920
4378
|
] }),
|
|
3921
4379
|
/* @__PURE__ */ jsx(MethodTabs, { activeTab, onTabChange: setActiveTab }),
|
|
3922
4380
|
activeTab === "crypto" ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
|
|
@@ -3945,8 +4403,8 @@ function DepositModalContent({
|
|
|
3945
4403
|
] }) : /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-3", children: /* @__PURE__ */ jsx(
|
|
3946
4404
|
MethodOption,
|
|
3947
4405
|
{
|
|
3948
|
-
title: "
|
|
3949
|
-
description: "
|
|
4406
|
+
title: "Buy with card",
|
|
4407
|
+
description: "Purchase and deposit directly into your account.",
|
|
3950
4408
|
onClick: () => {
|
|
3951
4409
|
onSelectCreditCard?.();
|
|
3952
4410
|
openDeposit("credit-card");
|
|
@@ -3954,21 +4412,29 @@ function DepositModalContent({
|
|
|
3954
4412
|
}
|
|
3955
4413
|
) })
|
|
3956
4414
|
] }),
|
|
3957
|
-
activeView === "deposit" && /* @__PURE__ */ jsx(
|
|
3958
|
-
|
|
4415
|
+
activeView === "deposit" && /* @__PURE__ */ jsx(
|
|
4416
|
+
MoonPayGate,
|
|
3959
4417
|
{
|
|
3960
|
-
source,
|
|
3961
|
-
|
|
3962
|
-
|
|
3963
|
-
|
|
3964
|
-
|
|
3965
|
-
|
|
3966
|
-
|
|
3967
|
-
|
|
3968
|
-
|
|
3969
|
-
|
|
4418
|
+
enabled: source === "credit-card" && cardOnRamp.provider === "moonpay" && !cardOnRamp.unavailableReason,
|
|
4419
|
+
apiKey: networkConfig.moonpayApiKey,
|
|
4420
|
+
children: /* @__PURE__ */ jsx(
|
|
4421
|
+
DepositView,
|
|
4422
|
+
{
|
|
4423
|
+
source,
|
|
4424
|
+
selectedToken,
|
|
4425
|
+
onRamp: cardOnRamp,
|
|
4426
|
+
amount,
|
|
4427
|
+
allowance,
|
|
4428
|
+
externalMinimum,
|
|
4429
|
+
onAmountChange: setAmount,
|
|
4430
|
+
onSelectToken: () => setView("select-token"),
|
|
4431
|
+
onConnectWallet,
|
|
4432
|
+
onSubmit: handleSubmit,
|
|
4433
|
+
isSubmitting: isPending || externalLock.isSigning || externalLock.isSubmittingLock
|
|
4434
|
+
}
|
|
4435
|
+
)
|
|
3970
4436
|
}
|
|
3971
|
-
)
|
|
4437
|
+
),
|
|
3972
4438
|
activeView === "select-token" && /* @__PURE__ */ jsx(
|
|
3973
4439
|
TokenSelectorView,
|
|
3974
4440
|
{
|
|
@@ -3990,20 +4456,30 @@ function DepositModalContent({
|
|
|
3990
4456
|
lock: externalLock.session ? externalLock : void 0
|
|
3991
4457
|
}
|
|
3992
4458
|
),
|
|
3993
|
-
activeView === "credit-card-widget" &&
|
|
3994
|
-
|
|
4459
|
+
activeView === "credit-card-widget" && mountedCardFlow && /* @__PURE__ */ jsx(
|
|
4460
|
+
MoonPayGate,
|
|
3995
4461
|
{
|
|
3996
|
-
|
|
3997
|
-
|
|
3998
|
-
|
|
3999
|
-
|
|
4000
|
-
|
|
4001
|
-
|
|
4002
|
-
|
|
4003
|
-
|
|
4004
|
-
|
|
4462
|
+
enabled: mountedCardFlow.selection.provider === "moonpay",
|
|
4463
|
+
apiKey: mountedCardFlow.moonpayApiKey,
|
|
4464
|
+
children: /* @__PURE__ */ jsx(
|
|
4465
|
+
CreditCardWidgetView,
|
|
4466
|
+
{
|
|
4467
|
+
token: mountedCardFlow.selection.token,
|
|
4468
|
+
onRamp: mountedCardFlow.selection,
|
|
4469
|
+
amount: mountedCardFlow.amount,
|
|
4470
|
+
allowance: mountedCardFlow.allowance,
|
|
4471
|
+
lockServiceAddress: mountedCardFlow.lockServiceAddress,
|
|
4472
|
+
onUnsafeToCloseChange: setCardUnsafeToClose,
|
|
4473
|
+
onActiveFlowChange: setCardFlowActive,
|
|
4474
|
+
onCredited: cardOutcomeCallbacks?.onCredited,
|
|
4475
|
+
onLockSubmitted: cardOutcomeCallbacks?.onLockSubmitted,
|
|
4476
|
+
onLockFailed: cardOutcomeCallbacks?.onLockFailed,
|
|
4477
|
+
onLeave: leaveCardPurchase
|
|
4478
|
+
},
|
|
4479
|
+
mountedCardFlow.id
|
|
4480
|
+
)
|
|
4005
4481
|
}
|
|
4006
|
-
)
|
|
4482
|
+
)
|
|
4007
4483
|
] });
|
|
4008
4484
|
}
|
|
4009
4485
|
function DepositModal({ open, onClose, ...handlers }) {
|