@oasisprotocol/privana-sdk 0.5.3 → 0.5.5
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 +29 -57
- package/dist/{chunk-7KEQHWZB.cjs → chunk-7VNAGKRC.cjs} +917 -365
- package/dist/chunk-7VNAGKRC.cjs.map +1 -0
- package/dist/{chunk-DZURIIRE.js → chunk-PMBU2F2R.js} +918 -366
- package/dist/chunk-PMBU2F2R.js.map +1 -0
- package/dist/index.cjs +1495 -2600
- 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 +17 -46
- package/dist/index.d.ts +17 -46
- package/dist/index.js +1359 -2461
- package/dist/index.js.map +1 -1
- package/dist/on-ramp.cjs +3 -3
- package/dist/on-ramp.d.cts +81 -52
- package/dist/on-ramp.d.ts +81 -52
- package/dist/on-ramp.js +1 -1
- package/dist/{pending-lock-f4bWWTyN.d.cts → pending-lock-IgzZyg9C.d.cts} +23 -19
- package/dist/{pending-lock-f4bWWTyN.d.ts → pending-lock-IgzZyg9C.d.ts} +23 -19
- package/package.json +1 -1
- package/dist/chunk-7KEQHWZB.cjs.map +0 -1
- package/dist/chunk-DZURIIRE.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
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,
|
|
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, canUseSharedBrowserStorage, DEFAULT_LOCK_DURATION_SECONDS, parseTokenAmount, Skeleton, shortenAddress, formatCountdown, FiatOnRampForm, getExplorerAddressUrl, getExplorerLabel, formatTimeRemaining, getSharedBrowserStorageItem, removeSharedBrowserStorageItem, setSharedBrowserStorageItem } from './chunk-PMBU2F2R.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-PMBU2F2R.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
7
|
import { zeroAddress, erc20Abi, formatUnits } from 'viem';
|
|
8
|
+
import { MoonPayProvider, MoonPayContext } from '@moonpay/moonpay-react';
|
|
8
9
|
import * as DialogPrimitive from '@radix-ui/react-dialog';
|
|
9
10
|
import { XIcon } from 'lucide-react';
|
|
10
11
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
11
12
|
import { toast } from 'sonner';
|
|
12
13
|
import { QRCodeSVG } from 'qrcode.react';
|
|
13
|
-
import { MoonPayProvider, MoonPayContext } from '@moonpay/moonpay-react';
|
|
14
14
|
|
|
15
15
|
// src/sdk/hooks/use-privana-client.ts
|
|
16
16
|
function usePrivanaClient() {
|
|
@@ -1488,16 +1488,6 @@ function DialogContent({
|
|
|
1488
1488
|
)
|
|
1489
1489
|
] });
|
|
1490
1490
|
}
|
|
1491
|
-
function DialogHeader({ className, ...props }) {
|
|
1492
|
-
return /* @__PURE__ */ jsx(
|
|
1493
|
-
"div",
|
|
1494
|
-
{
|
|
1495
|
-
"data-slot": "dialog-header",
|
|
1496
|
-
className: cn("flex flex-col gap-2 text-center sm:text-left", className),
|
|
1497
|
-
...props
|
|
1498
|
-
}
|
|
1499
|
-
);
|
|
1500
|
-
}
|
|
1501
1491
|
function DialogTitle({ className, ...props }) {
|
|
1502
1492
|
return /* @__PURE__ */ jsx(
|
|
1503
1493
|
DialogPrimitive.Title,
|
|
@@ -1521,2479 +1511,1361 @@ function DialogDescription({
|
|
|
1521
1511
|
}
|
|
1522
1512
|
);
|
|
1523
1513
|
}
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
{
|
|
1538
|
-
d: "M1000 2000c554.17 0 1000-445.83 1000-1000S1554.17 0 1000 0 0 445.83 0 1000s445.83 1000 1000 1000z",
|
|
1539
|
-
fill: "#2775ca"
|
|
1540
|
-
}
|
|
1541
|
-
),
|
|
1542
|
-
/* @__PURE__ */ jsx(
|
|
1543
|
-
"path",
|
|
1544
|
-
{
|
|
1545
|
-
d: "M1275 1158.33c0-145.83-87.5-195.83-262.5-216.66-125-16.67-150-50-150-108.34s41.67-95.83 125-95.83c75 0 116.67 25 137.5 87.5 4.17 12.5 16.67 20.83 29.17 20.83h66.66c16.67 0 29.17-12.5 29.17-29.16v-4.17c-16.67-91.67-91.67-162.5-187.5-170.83v-100c0-16.67-12.5-29.17-33.33-33.34h-62.5c-16.67 0-29.17 12.5-33.34 33.34v95.83c-125 16.67-204.16 100-204.16 204.17 0 137.5 83.33 191.66 258.33 212.5 116.67 20.83 154.17 45.83 154.17 112.5s-58.34 112.5-137.5 112.5c-108.34 0-145.84-45.84-158.34-108.34-4.16-16.66-16.66-25-29.16-25h-70.84c-16.66 0-29.16 12.5-29.16 29.17v4.17c16.66 104.16 83.33 179.16 220.83 200v100c0 16.66 12.5 29.16 33.33 33.33h62.5c16.67 0 29.17-12.5 33.34-33.33v-100c125-20.84 208.33-108.34 208.33-220.84z",
|
|
1546
|
-
fill: "#fff"
|
|
1547
|
-
}
|
|
1548
|
-
),
|
|
1549
|
-
/* @__PURE__ */ jsx(
|
|
1550
|
-
"path",
|
|
1551
|
-
{
|
|
1552
|
-
d: "M787.5 1595.83c-325-116.66-491.67-479.16-370.83-800 62.5-175 200-308.33 370.83-370.83 16.67-8.33 25-20.83 25-41.67V325c0-16.67-8.33-29.17-25-33.33-4.17 0-12.5 0-16.67 4.16-395.83 125-612.5 545.84-487.5 941.67 75 233.33 254.17 412.5 487.5 487.5 16.67 8.33 33.34 0 37.5-16.67 4.17-4.16 4.17-8.33 4.17-16.66v-58.34c0-12.5-12.5-29.16-25-37.5zM1229.17 295.83c-16.67-8.33-33.34 0-37.5 16.67-4.17 4.17-4.17 8.33-4.17 16.67v58.33c0 16.67 12.5 33.33 25 41.67 325 116.66 491.67 479.16 370.83 800-62.5 175-200 308.33-370.83 370.83-16.67 8.33-25 20.83-25 41.67V1700c0 16.67 8.33 29.17 25 33.33 4.17 0 12.5 0 16.67-4.16 395.83-125 612.5-545.84 487.5-941.67-75-237.5-258.34-416.67-487.5-491.67z",
|
|
1553
|
-
fill: "#fff"
|
|
1554
|
-
}
|
|
1555
|
-
)
|
|
1556
|
-
]
|
|
1557
|
-
}
|
|
1558
|
-
);
|
|
1514
|
+
|
|
1515
|
+
// src/sdk/hooks/external-deposit-lock.ts
|
|
1516
|
+
var ACTIVE_SESSION_PREFIX = "privana:external-deposit-lock:active:";
|
|
1517
|
+
var SESSION_PREFIX = "privana:external-deposit-lock:session:";
|
|
1518
|
+
var ExternalDepositLockSessionChangedError = class _ExternalDepositLockSessionChangedError extends Error {
|
|
1519
|
+
constructor() {
|
|
1520
|
+
super("External deposit lock session changed");
|
|
1521
|
+
this.name = "ExternalDepositLockSessionChangedError";
|
|
1522
|
+
Object.setPrototypeOf(this, _ExternalDepositLockSessionChangedError.prototype);
|
|
1523
|
+
}
|
|
1524
|
+
};
|
|
1525
|
+
function externalDepositSessionId(chainId, tokenId) {
|
|
1526
|
+
return `${chainId}:${tokenId.toLowerCase()}`;
|
|
1559
1527
|
}
|
|
1560
|
-
function
|
|
1561
|
-
return
|
|
1562
|
-
"svg",
|
|
1563
|
-
{
|
|
1564
|
-
width: size,
|
|
1565
|
-
height: size,
|
|
1566
|
-
viewBox: "0 0 2500 2500",
|
|
1567
|
-
xmlns: "http://www.w3.org/2000/svg",
|
|
1568
|
-
className,
|
|
1569
|
-
children: [
|
|
1570
|
-
/* @__PURE__ */ jsx("circle", { cx: "1250", cy: "1250", r: "1250", fill: "#0052FF" }),
|
|
1571
|
-
/* @__PURE__ */ jsx(
|
|
1572
|
-
"path",
|
|
1573
|
-
{
|
|
1574
|
-
d: "M1247.8,2500c691.6,0,1252.2-559.6,1252.2-1250C2500,559.6,1939.4,0,1247.8,0C591.7,0,53.5,503.8,0,1144.9h1655.1v210.2H0C53.5,1996.2,591.7,2500,1247.8,2500z",
|
|
1575
|
-
fill: "white"
|
|
1576
|
-
}
|
|
1577
|
-
)
|
|
1578
|
-
]
|
|
1579
|
-
}
|
|
1580
|
-
);
|
|
1528
|
+
function isExternalDepositBlockInSession(session, blockNumber) {
|
|
1529
|
+
return Number.isSafeInteger(blockNumber) && blockNumber > session.startBlock;
|
|
1581
1530
|
}
|
|
1582
|
-
function
|
|
1583
|
-
return
|
|
1584
|
-
"svg",
|
|
1585
|
-
{
|
|
1586
|
-
width: size,
|
|
1587
|
-
height: size,
|
|
1588
|
-
viewBox: "0 0 250 250",
|
|
1589
|
-
fill: "none",
|
|
1590
|
-
xmlns: "http://www.w3.org/2000/svg",
|
|
1591
|
-
className,
|
|
1592
|
-
children: [
|
|
1593
|
-
/* @__PURE__ */ jsx(
|
|
1594
|
-
"path",
|
|
1595
|
-
{
|
|
1596
|
-
d: "M0 125C0 55.9644 55.9644 0 125 0C194.036 0 250 55.9644 250 125C250 194.036 194.036 250 125 250C55.9644 250 0 194.036 0 125Z",
|
|
1597
|
-
fill: "#627EEA"
|
|
1598
|
-
}
|
|
1599
|
-
),
|
|
1600
|
-
/* @__PURE__ */ jsx(
|
|
1601
|
-
"path",
|
|
1602
|
-
{
|
|
1603
|
-
d: "M125.047 30.5V100.351L184.086 126.732L125.047 30.5Z",
|
|
1604
|
-
fill: "white",
|
|
1605
|
-
fillOpacity: "0.602"
|
|
1606
|
-
}
|
|
1607
|
-
),
|
|
1608
|
-
/* @__PURE__ */ jsx("path", { d: "M125.047 30.5L66 126.732L125.047 100.351V30.5Z", fill: "white" }),
|
|
1609
|
-
/* @__PURE__ */ jsx(
|
|
1610
|
-
"path",
|
|
1611
|
-
{
|
|
1612
|
-
d: "M125.047 172V219.462L184.125 137.728L125.047 172Z",
|
|
1613
|
-
fill: "white",
|
|
1614
|
-
fillOpacity: "0.602"
|
|
1615
|
-
}
|
|
1616
|
-
),
|
|
1617
|
-
/* @__PURE__ */ jsx("path", { d: "M125.047 219.462V171.992L66 137.728L125.047 219.462Z", fill: "white" }),
|
|
1618
|
-
/* @__PURE__ */ jsx(
|
|
1619
|
-
"path",
|
|
1620
|
-
{
|
|
1621
|
-
d: "M125.047 161.013L184.086 126.733L125.047 100.368V161.013Z",
|
|
1622
|
-
fill: "white",
|
|
1623
|
-
fillOpacity: "0.2"
|
|
1624
|
-
}
|
|
1625
|
-
),
|
|
1626
|
-
/* @__PURE__ */ jsx("path", { d: "M66 126.733L125.047 161.013V100.368L66 126.733Z", fill: "white", fillOpacity: "0.602" })
|
|
1627
|
-
]
|
|
1628
|
-
}
|
|
1629
|
-
);
|
|
1531
|
+
function isCurrentExternalDepositVerification(session, txHash) {
|
|
1532
|
+
return session.creditedAmount === void 0 && session.verification?.hash.toLowerCase() === txHash.toLowerCase();
|
|
1630
1533
|
}
|
|
1631
|
-
function
|
|
1632
|
-
const
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
return /* @__PURE__ */ jsx(
|
|
1640
|
-
"div",
|
|
1641
|
-
{
|
|
1642
|
-
className: "bg-muted flex items-center justify-center rounded-full text-xs font-bold",
|
|
1643
|
-
style: { width: iconSize, height: iconSize },
|
|
1644
|
-
children: symbol.slice(0, 2)
|
|
1645
|
-
}
|
|
1646
|
-
);
|
|
1534
|
+
function getExternalDepositMinimum(response, chainId) {
|
|
1535
|
+
const value = response?.min_deposit?.[String(chainId)]?.erc20;
|
|
1536
|
+
if (value === void 0) return void 0;
|
|
1537
|
+
try {
|
|
1538
|
+
const amount = BigInt(value);
|
|
1539
|
+
return amount >= 0n ? amount : void 0;
|
|
1540
|
+
} catch {
|
|
1541
|
+
return void 0;
|
|
1647
1542
|
}
|
|
1648
1543
|
}
|
|
1649
|
-
function
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1544
|
+
function activeSessionKey(owner) {
|
|
1545
|
+
return `${ACTIVE_SESSION_PREFIX}${owner.toLowerCase()}`;
|
|
1546
|
+
}
|
|
1547
|
+
function sessionKey(owner, sessionId) {
|
|
1548
|
+
return `${SESSION_PREFIX}${owner.toLowerCase()}:${sessionId}`;
|
|
1549
|
+
}
|
|
1550
|
+
function activeSessionId(owner) {
|
|
1551
|
+
const value = getSharedBrowserStorageItem(activeSessionKey(owner));
|
|
1552
|
+
return value || void 0;
|
|
1553
|
+
}
|
|
1554
|
+
function isPositiveIntegerString(value) {
|
|
1555
|
+
if (typeof value !== "string") return false;
|
|
1556
|
+
try {
|
|
1557
|
+
return BigInt(value) > 0n;
|
|
1558
|
+
} catch {
|
|
1559
|
+
return false;
|
|
1663
1560
|
}
|
|
1664
1561
|
}
|
|
1665
|
-
function
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
)
|
|
1562
|
+
function isSessionRecord(value) {
|
|
1563
|
+
if (!value || typeof value !== "object") return false;
|
|
1564
|
+
const record = value;
|
|
1565
|
+
if (record.version !== 1 || typeof record.owner !== "string" || typeof record.serviceAddress !== "string" || !Number.isInteger(record.chainId) || (record.chainId ?? 0) <= 0 || typeof record.tokenId !== "string" || !Number.isSafeInteger(record.startBlock) || (record.startBlock ?? -1) < 0 || !isPositiveIntegerString(record.depositAmount) || !isPositiveIntegerString(record.maxLockAmount) || !Number.isInteger(record.lockDuration) || (record.lockDuration ?? 0) <= 0 || typeof record.generation !== "string" || !record.generation || record.submissionAmbiguous !== void 0 && typeof record.submissionAmbiguous !== "boolean" || record.creditedAmount !== void 0 && !isPositiveIntegerString(record.creditedAmount)) {
|
|
1566
|
+
return false;
|
|
1567
|
+
}
|
|
1568
|
+
if (record.verification && (typeof record.verification.hash !== "string" || record.verification.chainId !== record.chainId || !isPositiveIntegerString(record.verification.amount) || record.verification.logIndex !== void 0 && (!Number.isInteger(record.verification.logIndex) || record.verification.logIndex < 0))) {
|
|
1569
|
+
return false;
|
|
1570
|
+
}
|
|
1571
|
+
if (record.verification && record.creditedAmount !== void 0) return false;
|
|
1572
|
+
if (record.submissionAmbiguous && record.creditedAmount === void 0) return false;
|
|
1573
|
+
if (!record.payload) {
|
|
1574
|
+
return record.creditedAmount !== void 0 && !record.submissionAmbiguous;
|
|
1575
|
+
}
|
|
1576
|
+
if (typeof record.payload.signature !== "string" || typeof record.payload.token_id !== "string" || typeof record.payload.service_address !== "string" || record.payload.signature !== record.generation || record.payload.token_id.toLowerCase() !== record.tokenId.toLowerCase() || record.payload.service_address.toLowerCase() !== record.serviceAddress.toLowerCase() || !isPositiveIntegerString(record.payload.amount)) {
|
|
1577
|
+
return false;
|
|
1578
|
+
}
|
|
1579
|
+
return BigInt(record.payload.amount) <= BigInt(record.maxLockAmount);
|
|
1676
1580
|
}
|
|
1677
|
-
function
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
{
|
|
1681
|
-
d: "M0 0l6 6 6-6",
|
|
1682
|
-
stroke: "currentColor",
|
|
1683
|
-
strokeWidth: "1.5",
|
|
1684
|
-
strokeLinecap: "round",
|
|
1685
|
-
strokeLinejoin: "round",
|
|
1686
|
-
fill: "none"
|
|
1687
|
-
}
|
|
1688
|
-
) });
|
|
1581
|
+
function writeSessionRecord(session) {
|
|
1582
|
+
const id = externalDepositSessionId(session.chainId, session.tokenId);
|
|
1583
|
+
return setSharedBrowserStorageItem(sessionKey(session.owner, id), JSON.stringify(session));
|
|
1689
1584
|
}
|
|
1690
|
-
function
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1585
|
+
function saveExternalDepositLockSession(session, expectedSession = null) {
|
|
1586
|
+
if (!isSessionRecord(session)) throw new Error("Invalid external deposit lock session");
|
|
1587
|
+
const current = loadExternalDepositLockSession(session.owner);
|
|
1588
|
+
if (expectedSession === null && current || expectedSession !== null && (!current || !isSameSessionSnapshot(current, expectedSession))) {
|
|
1589
|
+
throw new ExternalDepositLockSessionChangedError();
|
|
1590
|
+
}
|
|
1591
|
+
const nextId = externalDepositSessionId(session.chainId, session.tokenId);
|
|
1592
|
+
const previousId = activeSessionId(session.owner);
|
|
1593
|
+
if (!writeSessionRecord(session)) {
|
|
1594
|
+
throw new Error("Unable to persist external deposit lock session");
|
|
1595
|
+
}
|
|
1596
|
+
if (previousId !== nextId) {
|
|
1597
|
+
if (!setSharedBrowserStorageItem(activeSessionKey(session.owner), nextId)) {
|
|
1598
|
+
removeSharedBrowserStorageItem(sessionKey(session.owner, nextId));
|
|
1599
|
+
throw new Error("Unable to persist external deposit lock session");
|
|
1700
1600
|
}
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
function ChevronDownIcon({
|
|
1704
|
-
direction = "down",
|
|
1705
|
-
className
|
|
1706
|
-
}) {
|
|
1707
|
-
return /* @__PURE__ */ jsx(
|
|
1708
|
-
"svg",
|
|
1709
|
-
{
|
|
1710
|
-
width: "16",
|
|
1711
|
-
height: "16",
|
|
1712
|
-
viewBox: "0 0 16 16",
|
|
1713
|
-
fill: "none",
|
|
1714
|
-
className: cn(
|
|
1715
|
-
"transition-transform",
|
|
1716
|
-
direction === "right" && "-rotate-90",
|
|
1717
|
-
direction === "up" && "rotate-180",
|
|
1718
|
-
className
|
|
1719
|
-
),
|
|
1720
|
-
children: /* @__PURE__ */ jsx(
|
|
1721
|
-
"path",
|
|
1722
|
-
{
|
|
1723
|
-
d: "M4 6l4 4 4-4",
|
|
1724
|
-
stroke: "currentColor",
|
|
1725
|
-
strokeWidth: "1.5",
|
|
1726
|
-
strokeLinecap: "round",
|
|
1727
|
-
strokeLinejoin: "round"
|
|
1728
|
-
}
|
|
1729
|
-
)
|
|
1601
|
+
if (previousId) {
|
|
1602
|
+
removeSharedBrowserStorageItem(sessionKey(session.owner, previousId));
|
|
1730
1603
|
}
|
|
1731
|
-
|
|
1604
|
+
}
|
|
1732
1605
|
}
|
|
1733
|
-
function
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
strokeLinejoin: "round",
|
|
1745
|
-
children: [
|
|
1746
|
-
/* @__PURE__ */ jsx("rect", { x: "9", y: "9", width: "13", height: "13", rx: "2", ry: "2" }),
|
|
1747
|
-
/* @__PURE__ */ jsx("path", { d: "M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" })
|
|
1748
|
-
]
|
|
1606
|
+
function loadExternalDepositLockSession(owner) {
|
|
1607
|
+
const id = activeSessionId(owner);
|
|
1608
|
+
if (!id) return void 0;
|
|
1609
|
+
const key = sessionKey(owner, id);
|
|
1610
|
+
try {
|
|
1611
|
+
const raw = getSharedBrowserStorageItem(key);
|
|
1612
|
+
const parsed = raw ? JSON.parse(raw) : void 0;
|
|
1613
|
+
if (!isSessionRecord(parsed) || parsed.owner.toLowerCase() !== owner.toLowerCase() || externalDepositSessionId(parsed.chainId, parsed.tokenId) !== id) {
|
|
1614
|
+
removeSharedBrowserStorageItem(key);
|
|
1615
|
+
removeSharedBrowserStorageItem(activeSessionKey(owner));
|
|
1616
|
+
return void 0;
|
|
1749
1617
|
}
|
|
1750
|
-
|
|
1618
|
+
return parsed;
|
|
1619
|
+
} catch {
|
|
1620
|
+
removeSharedBrowserStorageItem(key);
|
|
1621
|
+
removeSharedBrowserStorageItem(activeSessionKey(owner));
|
|
1622
|
+
return void 0;
|
|
1623
|
+
}
|
|
1751
1624
|
}
|
|
1752
|
-
function
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
)
|
|
1765
|
-
|
|
1625
|
+
function subscribeExternalDepositLockSession(owner, onChange) {
|
|
1626
|
+
if (typeof window === "undefined") return () => void 0;
|
|
1627
|
+
let localStorage;
|
|
1628
|
+
try {
|
|
1629
|
+
localStorage = window.localStorage;
|
|
1630
|
+
} catch {
|
|
1631
|
+
return () => void 0;
|
|
1632
|
+
}
|
|
1633
|
+
const activeKey = activeSessionKey(owner);
|
|
1634
|
+
const ownerSessionPrefix = `${SESSION_PREFIX}${owner.toLowerCase()}:`;
|
|
1635
|
+
const handleStorage = (event) => {
|
|
1636
|
+
if (event.storageArea !== localStorage) return;
|
|
1637
|
+
if (event.key !== null && event.key !== activeKey && !event.key.startsWith(ownerSessionPrefix)) {
|
|
1638
|
+
return;
|
|
1639
|
+
}
|
|
1640
|
+
onChange(loadExternalDepositLockSession(owner));
|
|
1641
|
+
};
|
|
1642
|
+
window.addEventListener("storage", handleStorage);
|
|
1643
|
+
return () => window.removeEventListener("storage", handleStorage);
|
|
1766
1644
|
}
|
|
1767
|
-
function
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
strokeLinecap: "round",
|
|
1777
|
-
strokeLinejoin: "round"
|
|
1778
|
-
}
|
|
1779
|
-
)
|
|
1780
|
-
] });
|
|
1645
|
+
function clearExternalDepositLockSession(owner, expectedSessionId, expectedGeneration) {
|
|
1646
|
+
const id = activeSessionId(owner);
|
|
1647
|
+
if (!id || expectedSessionId && id !== expectedSessionId) return;
|
|
1648
|
+
if (expectedGeneration) {
|
|
1649
|
+
const current = loadExternalDepositLockSession(owner);
|
|
1650
|
+
if (!current || current.generation !== expectedGeneration) return;
|
|
1651
|
+
}
|
|
1652
|
+
removeSharedBrowserStorageItem(sessionKey(owner, id));
|
|
1653
|
+
removeSharedBrowserStorageItem(activeSessionKey(owner));
|
|
1781
1654
|
}
|
|
1782
|
-
function
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
{
|
|
1786
|
-
d: "M0 4h22m0 0l-4-4m4 4l-4 4",
|
|
1787
|
-
stroke: "currentColor",
|
|
1788
|
-
strokeWidth: "1.5",
|
|
1789
|
-
strokeLinecap: "round",
|
|
1790
|
-
strokeLinejoin: "round"
|
|
1791
|
-
}
|
|
1792
|
-
) });
|
|
1655
|
+
function isSameVerification(left, right) {
|
|
1656
|
+
if (!left || !right) return left === right;
|
|
1657
|
+
return left.hash.toLowerCase() === right.hash.toLowerCase() && left.chainId === right.chainId && left.amount === right.amount && (left.logIndex ?? 0) === (right.logIndex ?? 0);
|
|
1793
1658
|
}
|
|
1794
|
-
function
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
{
|
|
1798
|
-
d: "M2.5 6l2.5 2.5 4.5-4.5",
|
|
1799
|
-
stroke: "currentColor",
|
|
1800
|
-
strokeWidth: "1.5",
|
|
1801
|
-
strokeLinecap: "round",
|
|
1802
|
-
strokeLinejoin: "round"
|
|
1803
|
-
}
|
|
1804
|
-
) });
|
|
1659
|
+
function isSamePayload(left, right) {
|
|
1660
|
+
if (!left || !right) return left === right;
|
|
1661
|
+
return left.service_address.toLowerCase() === right.service_address.toLowerCase() && left.token_id.toLowerCase() === right.token_id.toLowerCase() && left.amount === right.amount && left.expiry === right.expiry && left.nonce === right.nonce && left.signature === right.signature;
|
|
1805
1662
|
}
|
|
1806
|
-
function
|
|
1807
|
-
return
|
|
1808
|
-
|
|
1663
|
+
function isSameSessionSnapshot(left, right) {
|
|
1664
|
+
return left.version === right.version && left.owner.toLowerCase() === right.owner.toLowerCase() && left.serviceAddress.toLowerCase() === right.serviceAddress.toLowerCase() && left.chainId === right.chainId && left.tokenId.toLowerCase() === right.tokenId.toLowerCase() && left.startBlock === right.startBlock && left.depositAmount === right.depositAmount && left.maxLockAmount === right.maxLockAmount && left.lockDuration === right.lockDuration && left.generation === right.generation && left.creditedAmount === right.creditedAmount && left.submissionAmbiguous === right.submissionAmbiguous && isSameVerification(left.verification, right.verification) && isSamePayload(left.payload, right.payload);
|
|
1665
|
+
}
|
|
1666
|
+
function isSameExternalDepositLockSession(left, right) {
|
|
1667
|
+
return isSameSessionSnapshot(left, right);
|
|
1668
|
+
}
|
|
1669
|
+
function clearExternalDepositVerification(session) {
|
|
1670
|
+
if (!session.verification || session.creditedAmount) return void 0;
|
|
1671
|
+
const current = loadExternalDepositLockSession(session.owner);
|
|
1672
|
+
if (!current || current.generation !== session.generation || current.creditedAmount || !isSameVerification(current.verification, session.verification)) {
|
|
1673
|
+
return void 0;
|
|
1674
|
+
}
|
|
1675
|
+
const next = { ...current, verification: void 0 };
|
|
1676
|
+
if (!writeSessionRecord(next)) {
|
|
1677
|
+
throw new Error("Unable to clear failed deposit verification");
|
|
1678
|
+
}
|
|
1679
|
+
return next;
|
|
1680
|
+
}
|
|
1681
|
+
function discardExternalDepositLockSession(session) {
|
|
1682
|
+
const current = loadExternalDepositLockSession(session.owner);
|
|
1683
|
+
if (!current) return true;
|
|
1684
|
+
if (!isSameSessionSnapshot(current, session)) return false;
|
|
1685
|
+
clearExternalDepositLockSession(
|
|
1686
|
+
current.owner,
|
|
1687
|
+
externalDepositSessionId(current.chainId, current.tokenId),
|
|
1688
|
+
current.generation
|
|
1689
|
+
);
|
|
1690
|
+
return loadExternalDepositLockSession(current.owner) === void 0;
|
|
1691
|
+
}
|
|
1692
|
+
function clearSubmittedPayload(session, signature, clearAmbiguous = false) {
|
|
1693
|
+
const current = loadExternalDepositLockSession(session.owner);
|
|
1694
|
+
if (!current?.payload || current.payload.signature !== signature || current.submissionAmbiguous && !clearAmbiguous) {
|
|
1695
|
+
return false;
|
|
1696
|
+
}
|
|
1697
|
+
return writeSessionRecord({ ...current, submissionAmbiguous: void 0, payload: void 0 });
|
|
1698
|
+
}
|
|
1699
|
+
function markSubmissionAmbiguous(session, signature) {
|
|
1700
|
+
const current = loadExternalDepositLockSession(session.owner);
|
|
1701
|
+
if (!current?.payload || current.payload.signature !== signature) return false;
|
|
1702
|
+
if (current.submissionAmbiguous) return true;
|
|
1703
|
+
return writeSessionRecord({ ...current, submissionAmbiguous: true });
|
|
1704
|
+
}
|
|
1705
|
+
function ambiguousSubmissionError(error) {
|
|
1706
|
+
return new PostDepositLockError(
|
|
1707
|
+
"Lock submission could not be confirmed. Retry only the saved signature, or check locked funds before stopping recovery.",
|
|
1708
|
+
error.reason,
|
|
1709
|
+
error.signedAmount,
|
|
1710
|
+
error.creditedAmount,
|
|
1809
1711
|
{
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
strokeWidth: "1.5",
|
|
1813
|
-
strokeLinecap: "round",
|
|
1814
|
-
strokeLinejoin: "round"
|
|
1712
|
+
cause: error.cause,
|
|
1713
|
+
submissionMayHaveSucceeded: true
|
|
1815
1714
|
}
|
|
1816
|
-
)
|
|
1715
|
+
);
|
|
1817
1716
|
}
|
|
1818
|
-
function
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
/* @__PURE__ */ jsx("path", { d: "M10 2a8 8 0 016.93 4", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" })
|
|
1822
|
-
] });
|
|
1717
|
+
function isDefinitiveSubmissionFailure(error) {
|
|
1718
|
+
const cause = error.cause;
|
|
1719
|
+
return cause instanceof AccountingApiError && cause.statusCode !== 408 && cause.statusCode < 500;
|
|
1823
1720
|
}
|
|
1824
|
-
function
|
|
1825
|
-
|
|
1826
|
-
const active = steps.find((s) => s.status === "active");
|
|
1827
|
-
const total = steps.length;
|
|
1828
|
-
const progress = (completed + (active ? 0.5 : 0)) / total * 100;
|
|
1829
|
-
return /* @__PURE__ */ jsxs("div", { className: "flex w-full flex-col gap-4", children: [
|
|
1830
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
|
|
1831
|
-
/* @__PURE__ */ jsx("div", { className: "text-primary", children: /* @__PURE__ */ jsx(Spinner, { size: 20 }) }),
|
|
1832
|
-
/* @__PURE__ */ jsx("span", { className: "text-foreground text-sm font-medium", children: active?.label ?? title })
|
|
1833
|
-
] }),
|
|
1834
|
-
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5", children: [
|
|
1835
|
-
/* @__PURE__ */ jsx("div", { className: "bg-secondary h-1.5 w-full overflow-hidden rounded-full", children: /* @__PURE__ */ jsx(
|
|
1836
|
-
"div",
|
|
1837
|
-
{
|
|
1838
|
-
className: "bg-primary h-full rounded-full transition-all duration-500",
|
|
1839
|
-
style: { width: `${progress}%` }
|
|
1840
|
-
}
|
|
1841
|
-
) }),
|
|
1842
|
-
/* @__PURE__ */ jsxs("span", { className: "text-muted-foreground text-xs", children: [
|
|
1843
|
-
"Step ",
|
|
1844
|
-
Math.max(1, completed + (active ? 1 : 0)),
|
|
1845
|
-
" of ",
|
|
1846
|
-
total
|
|
1847
|
-
] })
|
|
1848
|
-
] }),
|
|
1849
|
-
onCancel && /* @__PURE__ */ jsx(
|
|
1850
|
-
"button",
|
|
1851
|
-
{
|
|
1852
|
-
onClick: onCancel,
|
|
1853
|
-
className: "border-border text-foreground hover:bg-secondary flex h-10 w-full cursor-pointer items-center justify-center rounded-[10px] border px-3 py-2 text-sm font-medium transition-colors",
|
|
1854
|
-
children: "Cancel"
|
|
1855
|
-
}
|
|
1856
|
-
)
|
|
1857
|
-
] });
|
|
1721
|
+
function submissionLockName(session) {
|
|
1722
|
+
return `privana:external-deposit-lock:submit:${session.owner.toLowerCase()}:${externalDepositSessionId(session.chainId, session.tokenId)}`;
|
|
1858
1723
|
}
|
|
1859
|
-
function
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
explorerLabel,
|
|
1864
|
-
onDone
|
|
1865
|
-
}) {
|
|
1866
|
-
return /* @__PURE__ */ jsxs("div", { className: "flex w-full flex-col gap-4", children: [
|
|
1867
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
|
|
1868
|
-
/* @__PURE__ */ jsx("div", { className: "flex h-7 w-7 shrink-0 items-center justify-center rounded-full bg-emerald-500/10 text-emerald-400", children: /* @__PURE__ */ jsx(CheckIcon, {}) }),
|
|
1869
|
-
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-0.5", children: [
|
|
1870
|
-
/* @__PURE__ */ jsx("span", { className: "text-foreground text-sm font-medium", children: title }),
|
|
1871
|
-
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground text-xs", children: message })
|
|
1872
|
-
] })
|
|
1873
|
-
] }),
|
|
1874
|
-
/* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
|
|
1875
|
-
explorerUrl && /* @__PURE__ */ jsxs(
|
|
1876
|
-
"a",
|
|
1877
|
-
{
|
|
1878
|
-
href: explorerUrl,
|
|
1879
|
-
target: "_blank",
|
|
1880
|
-
rel: "noopener noreferrer",
|
|
1881
|
-
className: "border-border text-foreground hover:bg-secondary flex h-10 flex-1 items-center justify-center gap-1.5 rounded-[10px] border text-sm transition-colors",
|
|
1882
|
-
children: [
|
|
1883
|
-
explorerLabel ?? "View on Explorer",
|
|
1884
|
-
/* @__PURE__ */ jsx(ExternalLinkIcon, {})
|
|
1885
|
-
]
|
|
1886
|
-
}
|
|
1887
|
-
),
|
|
1888
|
-
/* @__PURE__ */ jsx(
|
|
1889
|
-
"button",
|
|
1890
|
-
{
|
|
1891
|
-
onClick: onDone,
|
|
1892
|
-
className: "bg-primary text-primary-foreground hover:bg-primary/90 flex h-10 flex-1 cursor-pointer items-center justify-center rounded-[10px] px-3 py-2 text-sm font-medium transition-colors",
|
|
1893
|
-
children: "Done"
|
|
1894
|
-
}
|
|
1895
|
-
)
|
|
1896
|
-
] })
|
|
1897
|
-
] });
|
|
1724
|
+
async function withSubmissionLock(session, task) {
|
|
1725
|
+
const locks = typeof navigator === "undefined" ? void 0 : navigator.locks;
|
|
1726
|
+
if (!locks) return task(false);
|
|
1727
|
+
return locks.request(submissionLockName(session), () => task(true));
|
|
1898
1728
|
}
|
|
1899
|
-
function
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1729
|
+
function externalDepositRetryAmount(session) {
|
|
1730
|
+
if (!session.creditedAmount) throw new Error("No credited external deposit to recover");
|
|
1731
|
+
const creditedAmount = BigInt(session.creditedAmount);
|
|
1732
|
+
const maxLockAmount = BigInt(session.maxLockAmount);
|
|
1733
|
+
return creditedAmount < maxLockAmount ? creditedAmount : maxLockAmount;
|
|
1734
|
+
}
|
|
1735
|
+
async function submitExternalDepositLock(client, session) {
|
|
1736
|
+
return withSubmissionLock(session, async (crossTabExclusive) => {
|
|
1737
|
+
const current = loadExternalDepositLockSession(session.owner);
|
|
1738
|
+
if (!current || current.generation !== session.generation) {
|
|
1739
|
+
throw new PostDepositLockError(
|
|
1740
|
+
"External deposit lock session changed before submission",
|
|
1741
|
+
"not-found",
|
|
1742
|
+
BigInt(session.maxLockAmount),
|
|
1743
|
+
session.creditedAmount ? BigInt(session.creditedAmount) : void 0
|
|
1744
|
+
);
|
|
1908
1745
|
}
|
|
1909
|
-
|
|
1746
|
+
const result = await submitExternalDepositLockAttempt(client, current, crossTabExclusive);
|
|
1747
|
+
clearExternalDepositLockSession(
|
|
1748
|
+
current.owner,
|
|
1749
|
+
externalDepositSessionId(current.chainId, current.tokenId),
|
|
1750
|
+
current.generation
|
|
1751
|
+
);
|
|
1752
|
+
return result;
|
|
1753
|
+
});
|
|
1910
1754
|
}
|
|
1911
|
-
function
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
}
|
|
1938
|
-
),
|
|
1939
|
-
/* @__PURE__ */ jsx(
|
|
1940
|
-
"button",
|
|
1941
|
-
{
|
|
1942
|
-
onClick: onDone,
|
|
1943
|
-
disabled: isPending,
|
|
1944
|
-
className: "bg-primary text-primary-foreground hover:bg-primary/90 flex h-10 flex-1 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",
|
|
1945
|
-
children: isPending ? pendingLabel : actionLabel
|
|
1755
|
+
async function submitExternalDepositLockAttempt(client, session, crossTabExclusive) {
|
|
1756
|
+
const creditedAmount = session.creditedAmount ? BigInt(session.creditedAmount) : void 0;
|
|
1757
|
+
if (!creditedAmount) {
|
|
1758
|
+
throw new PostDepositLockError(
|
|
1759
|
+
"External deposit has not been credited",
|
|
1760
|
+
"submission-failed",
|
|
1761
|
+
BigInt(session.maxLockAmount)
|
|
1762
|
+
);
|
|
1763
|
+
}
|
|
1764
|
+
const payload = session.payload;
|
|
1765
|
+
if (!payload) {
|
|
1766
|
+
throw new PostDepositLockError(
|
|
1767
|
+
"No persisted signed policy found for this deposit session",
|
|
1768
|
+
"not-found",
|
|
1769
|
+
BigInt(session.maxLockAmount),
|
|
1770
|
+
creditedAmount
|
|
1771
|
+
);
|
|
1772
|
+
}
|
|
1773
|
+
try {
|
|
1774
|
+
return await submitPendingLock({
|
|
1775
|
+
client,
|
|
1776
|
+
payload,
|
|
1777
|
+
creditedAmount,
|
|
1778
|
+
beforeSubmit: () => {
|
|
1779
|
+
if (!markSubmissionAmbiguous(session, payload.signature)) {
|
|
1780
|
+
throw new Error("Unable to persist lock submission recovery state");
|
|
1946
1781
|
}
|
|
1947
|
-
)
|
|
1948
|
-
] })
|
|
1949
|
-
] });
|
|
1950
|
-
}
|
|
1951
|
-
function TransactionErrorView({
|
|
1952
|
-
title,
|
|
1953
|
-
message,
|
|
1954
|
-
explorerUrl,
|
|
1955
|
-
explorerLabel,
|
|
1956
|
-
onRetry,
|
|
1957
|
-
onDismiss,
|
|
1958
|
-
isRetrying,
|
|
1959
|
-
retryLabel = "Retry Verification",
|
|
1960
|
-
dismissLabel = "Close"
|
|
1961
|
-
}) {
|
|
1962
|
-
return /* @__PURE__ */ jsxs("div", { className: "flex w-full flex-col gap-4", children: [
|
|
1963
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
|
|
1964
|
-
/* @__PURE__ */ jsx("div", { className: "flex h-7 w-7 shrink-0 items-center justify-center rounded-full bg-amber-500/10 text-amber-400", children: /* @__PURE__ */ jsx(WarningIcon, {}) }),
|
|
1965
|
-
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-0.5", children: [
|
|
1966
|
-
/* @__PURE__ */ jsx("span", { className: "text-foreground text-sm font-medium", children: title }),
|
|
1967
|
-
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground text-xs", children: message })
|
|
1968
|
-
] })
|
|
1969
|
-
] }),
|
|
1970
|
-
explorerUrl && /* @__PURE__ */ jsxs(
|
|
1971
|
-
"a",
|
|
1972
|
-
{
|
|
1973
|
-
href: explorerUrl,
|
|
1974
|
-
target: "_blank",
|
|
1975
|
-
rel: "noopener noreferrer",
|
|
1976
|
-
className: "border-border text-foreground hover:bg-secondary flex h-10 w-full items-center justify-center gap-1.5 rounded-[10px] border text-sm transition-colors",
|
|
1977
|
-
children: [
|
|
1978
|
-
explorerLabel ?? "View on Explorer",
|
|
1979
|
-
/* @__PURE__ */ jsx(ExternalLinkIcon, {})
|
|
1980
|
-
]
|
|
1981
1782
|
}
|
|
1982
|
-
)
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
1783
|
+
});
|
|
1784
|
+
} catch (err) {
|
|
1785
|
+
if (err instanceof PostDepositLockError && err.reason === "submission-failed" && crossTabExclusive && !session.submissionAmbiguous && isDefinitiveSubmissionFailure(err)) {
|
|
1786
|
+
if (!clearSubmittedPayload(session, payload.signature, true)) {
|
|
1787
|
+
const latest = loadExternalDepositLockSession(session.owner);
|
|
1788
|
+
if (latest?.submissionAmbiguous) throw ambiguousSubmissionError(err);
|
|
1789
|
+
}
|
|
1790
|
+
} else if (err instanceof PostDepositLockError && err.reason === "submission-failed") {
|
|
1791
|
+
const ambiguous = markSubmissionAmbiguous(session, payload.signature) || loadExternalDepositLockSession(session.owner)?.submissionAmbiguous === true;
|
|
1792
|
+
if (ambiguous) throw ambiguousSubmissionError(err);
|
|
1793
|
+
} else {
|
|
1794
|
+
const current = loadExternalDepositLockSession(session.owner);
|
|
1795
|
+
if (session.submissionAmbiguous || current?.submissionAmbiguous) {
|
|
1796
|
+
if (err instanceof PostDepositLockError) throw ambiguousSubmissionError(err);
|
|
1797
|
+
throw err;
|
|
1798
|
+
}
|
|
1799
|
+
if (!clearSubmittedPayload(session, payload.signature)) {
|
|
1800
|
+
const latest = loadExternalDepositLockSession(session.owner);
|
|
1801
|
+
if (latest?.submissionAmbiguous && err instanceof PostDepositLockError) {
|
|
1802
|
+
throw ambiguousSubmissionError(err);
|
|
2000
1803
|
}
|
|
2001
|
-
)
|
|
2002
|
-
] })
|
|
2003
|
-
] });
|
|
2004
|
-
}
|
|
2005
|
-
function DepositForm({
|
|
2006
|
-
selectedToken,
|
|
2007
|
-
onTokenSelect,
|
|
2008
|
-
onPendingChange,
|
|
2009
|
-
onUnsafeToCloseChange,
|
|
2010
|
-
onSuccess
|
|
2011
|
-
}) {
|
|
2012
|
-
const { isConnected, address } = useAccount();
|
|
2013
|
-
const { chains, getChainById: getChainById2 } = usePrivanaContext();
|
|
2014
|
-
const [amount, setAmount] = useState("");
|
|
2015
|
-
const [showSuccess, setShowSuccess] = useState(false);
|
|
2016
|
-
const [showTimeout, setShowTimeout] = useState(false);
|
|
2017
|
-
const [cancelled, setCancelled] = useState(false);
|
|
2018
|
-
const targetChain = getChainById2(selectedToken.chainId) ?? chains[0];
|
|
2019
|
-
const isNative = selectedToken.contract === zeroAddress;
|
|
2020
|
-
const { data: nativeBalanceData } = useBalance$1({
|
|
2021
|
-
address,
|
|
2022
|
-
chainId: targetChain?.id,
|
|
2023
|
-
query: {
|
|
2024
|
-
enabled: !!address && isNative
|
|
2025
|
-
}
|
|
2026
|
-
});
|
|
2027
|
-
const { data: erc20Balance } = useReadContract({
|
|
2028
|
-
address: selectedToken.contract,
|
|
2029
|
-
abi: erc20Abi,
|
|
2030
|
-
functionName: "balanceOf",
|
|
2031
|
-
args: address ? [address] : void 0,
|
|
2032
|
-
chainId: targetChain?.id,
|
|
2033
|
-
query: {
|
|
2034
|
-
enabled: !!address && !isNative
|
|
2035
|
-
}
|
|
2036
|
-
});
|
|
2037
|
-
const walletBalance = isNative ? nativeBalanceData?.value : erc20Balance;
|
|
2038
|
-
const formattedWalletBalance = walletBalance ? formatTokenAmount(walletBalance.toString(), selectedToken.decimals) : "0.00";
|
|
2039
|
-
const handleMaxClick = () => {
|
|
2040
|
-
if (formattedWalletBalance && parseFloat(formattedWalletBalance) > 0) {
|
|
2041
|
-
setAmount(formattedWalletBalance.replace(/[\s\u2009]/g, ""));
|
|
2042
|
-
}
|
|
2043
|
-
};
|
|
2044
|
-
const hasValidAmount = amount && parseFloat(amount) > 0;
|
|
2045
|
-
const tooManyDecimals = hasValidAmount && amount.includes(".") && amount.split(".")[1].length > selectedToken.decimals;
|
|
2046
|
-
const exceedsBalance = hasValidAmount && !tooManyDecimals && walletBalance != null && parseTokenAmount(amount, selectedToken.decimals) > walletBalance;
|
|
2047
|
-
const {
|
|
2048
|
-
txHash,
|
|
2049
|
-
isGettingAddress,
|
|
2050
|
-
isSwitchingChain,
|
|
2051
|
-
isSendingTransaction,
|
|
2052
|
-
isWaitingForConfirmation,
|
|
2053
|
-
isWaitingForProcessing,
|
|
2054
|
-
verificationFailed,
|
|
2055
|
-
isPending,
|
|
2056
|
-
error,
|
|
2057
|
-
deposit,
|
|
2058
|
-
retryVerification,
|
|
2059
|
-
reset
|
|
2060
|
-
} = useDeposit({
|
|
2061
|
-
onCredited: () => {
|
|
2062
|
-
setAmount("");
|
|
2063
|
-
if (onSuccess) {
|
|
2064
|
-
reset();
|
|
2065
|
-
onSuccess();
|
|
2066
|
-
} else {
|
|
2067
|
-
setShowSuccess(true);
|
|
2068
1804
|
}
|
|
2069
|
-
},
|
|
2070
|
-
onCheckTimeout: () => {
|
|
2071
|
-
setAmount("");
|
|
2072
|
-
setShowTimeout(true);
|
|
2073
1805
|
}
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
1806
|
+
throw err;
|
|
1807
|
+
}
|
|
1808
|
+
}
|
|
1809
|
+
function useExternalDepositLock({
|
|
1810
|
+
allowance,
|
|
1811
|
+
onLockSubmitted,
|
|
1812
|
+
onLockFailed
|
|
1813
|
+
}) {
|
|
1814
|
+
const { client, networkConfig, serviceAddress, getTokenById, tokensStatus } = usePrivanaContext();
|
|
1815
|
+
const config = useConfig();
|
|
1816
|
+
const queryClient = useQueryClient();
|
|
1817
|
+
const { address } = useAccount();
|
|
1818
|
+
const { privateReadAddress } = usePrivateReadRequest();
|
|
1819
|
+
const { ensureCorrectChain } = useEnsureCorrectChain();
|
|
1820
|
+
const [isSigning, setIsSigning] = useState(false);
|
|
1821
|
+
const [isSubmittingLock, setIsSubmittingLock] = useState(false);
|
|
1822
|
+
const [session, setSession] = useState(null);
|
|
1823
|
+
const sessionRef = useRef(null);
|
|
1824
|
+
const signingRef = useRef(false);
|
|
1825
|
+
const settlingRef = useRef(false);
|
|
1826
|
+
const pendingCreditedTransitionRef = useRef(null);
|
|
1827
|
+
const hydratedScopeRef = useRef(null);
|
|
1828
|
+
const beneficiaryRef = useRef(privateReadAddress);
|
|
1829
|
+
beneficiaryRef.current = privateReadAddress;
|
|
1830
|
+
const onLockSubmittedRef = useRef(onLockSubmitted);
|
|
1831
|
+
const onLockFailedRef = useRef(onLockFailed);
|
|
1832
|
+
useEffect(() => {
|
|
1833
|
+
onLockSubmittedRef.current = onLockSubmitted;
|
|
1834
|
+
onLockFailedRef.current = onLockFailed;
|
|
1835
|
+
}, [onLockSubmitted, onLockFailed]);
|
|
1836
|
+
const installSession = useCallback((next) => {
|
|
1837
|
+
sessionRef.current = next;
|
|
1838
|
+
setSession(next);
|
|
1839
|
+
}, []);
|
|
1840
|
+
const preserveCreditedFallback = useCallback(
|
|
1841
|
+
(durable) => {
|
|
1842
|
+
const pending = pendingCreditedTransitionRef.current;
|
|
1843
|
+
if (pending && durable && isSameExternalDepositLockSession(durable, pending.predecessor)) {
|
|
1844
|
+
return pending.credited;
|
|
1845
|
+
}
|
|
1846
|
+
pendingCreditedTransitionRef.current = null;
|
|
1847
|
+
return durable;
|
|
2083
1848
|
},
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
1849
|
+
[]
|
|
1850
|
+
);
|
|
1851
|
+
const notifyFailure = useCallback((error) => {
|
|
1852
|
+
onLockFailedRef.current?.(error);
|
|
1853
|
+
}, []);
|
|
1854
|
+
const submitSession = useCallback(
|
|
1855
|
+
async (active) => {
|
|
1856
|
+
if (settlingRef.current) return;
|
|
1857
|
+
settlingRef.current = true;
|
|
1858
|
+
setIsSubmittingLock(true);
|
|
1859
|
+
let result;
|
|
1860
|
+
try {
|
|
1861
|
+
let submission = active;
|
|
1862
|
+
const storedBeforeSubmit = loadExternalDepositLockSession(active.owner);
|
|
1863
|
+
if (storedBeforeSubmit?.generation === active.generation) {
|
|
1864
|
+
if (active.creditedAmount && !storedBeforeSubmit.creditedAmount) {
|
|
1865
|
+
const pending = pendingCreditedTransitionRef.current;
|
|
1866
|
+
if (!pending || !isSameExternalDepositLockSession(active, pending.credited) || !isSameExternalDepositLockSession(storedBeforeSubmit, pending.predecessor)) {
|
|
1867
|
+
throw new ExternalDepositLockSessionChangedError();
|
|
1868
|
+
}
|
|
1869
|
+
saveExternalDepositLockSession(pending.credited, pending.predecessor);
|
|
1870
|
+
pendingCreditedTransitionRef.current = null;
|
|
1871
|
+
submission = pending.credited;
|
|
1872
|
+
} else {
|
|
1873
|
+
submission = storedBeforeSubmit;
|
|
1874
|
+
}
|
|
1875
|
+
}
|
|
1876
|
+
result = await submitExternalDepositLock(client, submission);
|
|
1877
|
+
} catch (err) {
|
|
1878
|
+
const stored = loadExternalDepositLockSession(active.owner);
|
|
1879
|
+
const error = err instanceof PostDepositLockError ? err : new PostDepositLockError(
|
|
1880
|
+
err instanceof Error ? err.message : "Lock submission failed",
|
|
1881
|
+
"submission-failed",
|
|
1882
|
+
BigInt(active.maxLockAmount),
|
|
1883
|
+
active.creditedAmount ? BigInt(active.creditedAmount) : void 0,
|
|
1884
|
+
{ cause: err }
|
|
1885
|
+
);
|
|
1886
|
+
if (err instanceof ExternalDepositLockSessionChangedError) {
|
|
1887
|
+
pendingCreditedTransitionRef.current = null;
|
|
1888
|
+
installSession(stored ?? null);
|
|
1889
|
+
return;
|
|
1890
|
+
}
|
|
1891
|
+
if (!stored || stored.generation !== active.generation) {
|
|
1892
|
+
pendingCreditedTransitionRef.current = null;
|
|
1893
|
+
installSession(stored ?? null);
|
|
1894
|
+
return;
|
|
1895
|
+
}
|
|
1896
|
+
if (active.creditedAmount && !stored.creditedAmount) {
|
|
1897
|
+
const pending = pendingCreditedTransitionRef.current;
|
|
1898
|
+
if (pending && isSameExternalDepositLockSession(active, pending.credited) && isSameExternalDepositLockSession(stored, pending.predecessor)) {
|
|
1899
|
+
installSession(pending.credited);
|
|
1900
|
+
notifyFailure(error);
|
|
1901
|
+
return;
|
|
1902
|
+
}
|
|
1903
|
+
pendingCreditedTransitionRef.current = null;
|
|
1904
|
+
installSession(stored);
|
|
1905
|
+
return;
|
|
1906
|
+
}
|
|
1907
|
+
installSession(active.creditedAmount && !stored.creditedAmount ? active : stored);
|
|
1908
|
+
notifyFailure(error);
|
|
1909
|
+
return;
|
|
1910
|
+
} finally {
|
|
1911
|
+
settlingRef.current = false;
|
|
1912
|
+
setIsSubmittingLock(false);
|
|
1913
|
+
}
|
|
1914
|
+
installSession(loadExternalDepositLockSession(active.owner) ?? null);
|
|
1915
|
+
queryClient.invalidateQueries({ queryKey: ["accounting-balance"] });
|
|
1916
|
+
queryClient.invalidateQueries({ queryKey: ["accounting-locked-funds"] });
|
|
1917
|
+
queryClient.invalidateQueries({ queryKey: ["accounting-total-locked-balance"] });
|
|
1918
|
+
queryClient.invalidateQueries({ queryKey: ["accounting-history"] });
|
|
1919
|
+
onLockSubmittedRef.current?.(result);
|
|
2087
1920
|
},
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
1921
|
+
[client, installSession, notifyFailure, queryClient]
|
|
1922
|
+
);
|
|
1923
|
+
const validateRestoredSession = useCallback(
|
|
1924
|
+
(restored) => {
|
|
1925
|
+
if (!restored || !serviceAddress) return null;
|
|
1926
|
+
const token = getTokenById(restored.tokenId);
|
|
1927
|
+
const invalid = restored.serviceAddress.toLowerCase() !== serviceAddress.toLowerCase() || !token || token.chainId !== restored.chainId || token.contract === zeroAddress || !restored.creditedAmount && !restored.payload;
|
|
1928
|
+
if (!invalid) return restored;
|
|
1929
|
+
clearExternalDepositLockSession(
|
|
1930
|
+
restored.owner,
|
|
1931
|
+
externalDepositSessionId(restored.chainId, restored.tokenId),
|
|
1932
|
+
restored.generation
|
|
1933
|
+
);
|
|
1934
|
+
return null;
|
|
2091
1935
|
},
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
status: isWaitingForProcessing ? "active" : "pending"
|
|
2095
|
-
}
|
|
2096
|
-
];
|
|
1936
|
+
[getTokenById, serviceAddress]
|
|
1937
|
+
);
|
|
2097
1938
|
useEffect(() => {
|
|
2098
|
-
if (
|
|
2099
|
-
|
|
1939
|
+
if (!privateReadAddress || !serviceAddress || tokensStatus !== "ready") {
|
|
1940
|
+
setSession(null);
|
|
1941
|
+
return;
|
|
2100
1942
|
}
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
onUnsafeToCloseChange?.((isGettingAddress || isSendingTransaction) && !cancelled);
|
|
2107
|
-
}, [isGettingAddress, isSendingTransaction, cancelled, onUnsafeToCloseChange]);
|
|
2108
|
-
const handleCancel = () => {
|
|
2109
|
-
setCancelled(true);
|
|
2110
|
-
reset();
|
|
2111
|
-
};
|
|
2112
|
-
const handleDone = () => {
|
|
2113
|
-
setShowSuccess(false);
|
|
2114
|
-
setShowTimeout(false);
|
|
2115
|
-
setCancelled(false);
|
|
2116
|
-
reset();
|
|
2117
|
-
};
|
|
2118
|
-
const handleDismissVerificationError = () => {
|
|
2119
|
-
setAmount("");
|
|
2120
|
-
setCancelled(false);
|
|
2121
|
-
reset();
|
|
2122
|
-
};
|
|
2123
|
-
const handleRetryVerification = () => {
|
|
2124
|
-
retryVerification().catch(() => {
|
|
2125
|
-
});
|
|
2126
|
-
};
|
|
2127
|
-
const explorerTxUrl = txHash && targetChain?.explorerUrl ? `${targetChain.explorerUrl}/tx/${txHash}` : void 0;
|
|
2128
|
-
const handleSubmit = async () => {
|
|
2129
|
-
if (!amount || !selectedToken || exceedsBalance) return;
|
|
2130
|
-
setCancelled(false);
|
|
2131
|
-
const amountInWei = parseTokenAmount(amount, selectedToken.decimals);
|
|
2132
|
-
await deposit({
|
|
2133
|
-
tokenId: selectedToken.id,
|
|
2134
|
-
amount: amountInWei
|
|
2135
|
-
});
|
|
2136
|
-
};
|
|
2137
|
-
const getButtonText = () => {
|
|
2138
|
-
if (!isConnected) return "Connect Wallet";
|
|
2139
|
-
if (isSwitchingChain) return "Switching\u2026";
|
|
2140
|
-
return "Deposit";
|
|
2141
|
-
};
|
|
2142
|
-
if (showSuccess) {
|
|
2143
|
-
return /* @__PURE__ */ jsx(
|
|
2144
|
-
TransactionSuccessView,
|
|
2145
|
-
{
|
|
2146
|
-
title: "Deposit Successful",
|
|
2147
|
-
message: `Your ${selectedToken.symbol} deposit has been processed.`,
|
|
2148
|
-
onDone: handleDone
|
|
2149
|
-
}
|
|
1943
|
+
const hydrationKey = `${privateReadAddress.toLowerCase()}:${serviceAddress.toLowerCase()}`;
|
|
1944
|
+
const shouldResume = hydratedScopeRef.current !== hydrationKey;
|
|
1945
|
+
hydratedScopeRef.current = hydrationKey;
|
|
1946
|
+
const restored = preserveCreditedFallback(
|
|
1947
|
+
validateRestoredSession(loadExternalDepositLockSession(privateReadAddress))
|
|
2150
1948
|
);
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
1949
|
+
installSession(restored);
|
|
1950
|
+
if (!restored) {
|
|
1951
|
+
return;
|
|
1952
|
+
}
|
|
1953
|
+
if (!shouldResume) return;
|
|
1954
|
+
if (restored.creditedAmount && restored.payload) {
|
|
1955
|
+
void submitSession(restored);
|
|
1956
|
+
} else if (restored.creditedAmount) {
|
|
1957
|
+
notifyFailure(
|
|
1958
|
+
new PostDepositLockError(
|
|
1959
|
+
"Deposit credited; sign a fresh policy to lock the funds",
|
|
1960
|
+
"not-found",
|
|
1961
|
+
BigInt(restored.maxLockAmount),
|
|
1962
|
+
BigInt(restored.creditedAmount)
|
|
1963
|
+
)
|
|
1964
|
+
);
|
|
1965
|
+
}
|
|
1966
|
+
}, [
|
|
1967
|
+
installSession,
|
|
1968
|
+
notifyFailure,
|
|
1969
|
+
privateReadAddress,
|
|
1970
|
+
preserveCreditedFallback,
|
|
1971
|
+
serviceAddress,
|
|
1972
|
+
submitSession,
|
|
1973
|
+
tokensStatus,
|
|
1974
|
+
validateRestoredSession
|
|
1975
|
+
]);
|
|
1976
|
+
useEffect(() => {
|
|
1977
|
+
if (!privateReadAddress || !serviceAddress || tokensStatus !== "ready") return;
|
|
1978
|
+
const reconcile = (restored) => {
|
|
1979
|
+
installSession(preserveCreditedFallback(validateRestoredSession(restored)));
|
|
1980
|
+
};
|
|
1981
|
+
const unsubscribe = subscribeExternalDepositLockSession(privateReadAddress, reconcile);
|
|
1982
|
+
reconcile(loadExternalDepositLockSession(privateReadAddress));
|
|
1983
|
+
return unsubscribe;
|
|
1984
|
+
}, [
|
|
1985
|
+
installSession,
|
|
1986
|
+
preserveCreditedFallback,
|
|
1987
|
+
privateReadAddress,
|
|
1988
|
+
serviceAddress,
|
|
1989
|
+
tokensStatus,
|
|
1990
|
+
validateRestoredSession
|
|
1991
|
+
]);
|
|
1992
|
+
const signAndPersist = useCallback(
|
|
1993
|
+
async ({ tokenId, amount }) => {
|
|
1994
|
+
if (!allowance) throw new Error("No allowance configured for this deposit");
|
|
1995
|
+
if (signingRef.current || settlingRef.current) {
|
|
1996
|
+
throw new Error("A policy operation is already in progress");
|
|
2159
1997
|
}
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
if (verificationFailed) {
|
|
2163
|
-
const baseMessage = "Your transfer was sent on-chain but we could not verify the deposit. The funds are already at the deposit address. Retry verification instead of starting a new deposit.";
|
|
2164
|
-
const detail = error?.message;
|
|
2165
|
-
const message = detail ? `${baseMessage} (${detail})` : baseMessage;
|
|
2166
|
-
return /* @__PURE__ */ jsx(
|
|
2167
|
-
TransactionErrorView,
|
|
2168
|
-
{
|
|
2169
|
-
title: "Verification failed",
|
|
2170
|
-
message,
|
|
2171
|
-
explorerUrl: explorerTxUrl,
|
|
2172
|
-
explorerLabel: "View transaction",
|
|
2173
|
-
onRetry: handleRetryVerification,
|
|
2174
|
-
onDismiss: handleDismissVerificationError
|
|
1998
|
+
if (!canUseSharedBrowserStorage()) {
|
|
1999
|
+
throw new Error("Browser storage is required for locked deposit recovery");
|
|
2175
2000
|
}
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
const canCancel = isGettingAddress || isSendingTransaction;
|
|
2180
|
-
return /* @__PURE__ */ jsx(
|
|
2181
|
-
TransactionProgressView,
|
|
2182
|
-
{
|
|
2183
|
-
title: "Depositing\u2026",
|
|
2184
|
-
steps: depositSteps,
|
|
2185
|
-
onCancel: canCancel ? handleCancel : void 0
|
|
2001
|
+
const owner = requireDepositLockOwner(address, privateReadAddress);
|
|
2002
|
+
if (sessionRef.current || loadExternalDepositLockSession(owner)) {
|
|
2003
|
+
throw new Error("Finish or cancel the active external deposit before starting another");
|
|
2186
2004
|
}
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2005
|
+
const token = getTokenById(tokenId);
|
|
2006
|
+
if (!token) throw new Error(`Unknown token ID: ${tokenId}`);
|
|
2007
|
+
if (token.contract === zeroAddress) {
|
|
2008
|
+
throw new Error("External deposits support ERC20 tokens only");
|
|
2009
|
+
}
|
|
2010
|
+
const targetService = requireServiceAddress(serviceAddress);
|
|
2011
|
+
const lockDuration = allowance.lockDuration ?? DEFAULT_LOCK_DURATION_SECONDS;
|
|
2012
|
+
signingRef.current = true;
|
|
2013
|
+
setIsSigning(true);
|
|
2014
|
+
try {
|
|
2015
|
+
await ensureCorrectChain(networkConfig.chainId);
|
|
2016
|
+
const signingWalletClient = await getWalletClient(config, {
|
|
2017
|
+
chainId: networkConfig.chainId
|
|
2018
|
+
});
|
|
2019
|
+
const payload = await createSignedLockRequest({
|
|
2020
|
+
client,
|
|
2021
|
+
walletClient: signingWalletClient,
|
|
2022
|
+
userAddress: owner,
|
|
2023
|
+
networkConfig,
|
|
2024
|
+
serviceAddress: targetService,
|
|
2025
|
+
tokenId: token.id,
|
|
2026
|
+
amount: clampLockAmount(amount, BigInt(allowance.value)),
|
|
2027
|
+
lockDuration
|
|
2028
|
+
});
|
|
2029
|
+
const startBlock = await getBlockNumber(config, { chainId: token.chainId });
|
|
2030
|
+
if (startBlock > BigInt(Number.MAX_SAFE_INTEGER)) {
|
|
2031
|
+
throw new Error("Source-chain block number exceeds the supported range");
|
|
2208
2032
|
}
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
if (value.split(".").length <= 2) {
|
|
2231
|
-
setAmount(value);
|
|
2232
|
-
}
|
|
2233
|
-
},
|
|
2234
|
-
className: cn(
|
|
2235
|
-
"text-foreground flex-1 bg-transparent text-sm outline-none",
|
|
2236
|
-
"placeholder:text-muted-foreground/50"
|
|
2237
|
-
)
|
|
2238
|
-
}
|
|
2239
|
-
),
|
|
2240
|
-
/* @__PURE__ */ jsx(
|
|
2241
|
-
"button",
|
|
2242
|
-
{
|
|
2243
|
-
onClick: handleMaxClick,
|
|
2244
|
-
className: "bg-secondary text-foreground hover:bg-secondary/80 cursor-pointer rounded px-3 py-2.5 text-xs font-semibold transition-colors",
|
|
2245
|
-
children: "MAX"
|
|
2246
|
-
}
|
|
2247
|
-
)
|
|
2248
|
-
] }),
|
|
2249
|
-
tooManyDecimals && /* @__PURE__ */ jsxs("p", { className: "text-destructive text-sm", children: [
|
|
2250
|
-
"Too many decimal places (max: ",
|
|
2251
|
-
selectedToken.decimals,
|
|
2252
|
-
")"
|
|
2253
|
-
] }),
|
|
2254
|
-
exceedsBalance && /* @__PURE__ */ jsx("p", { className: "text-destructive text-sm", children: "Insufficient balance" })
|
|
2255
|
-
] }),
|
|
2256
|
-
/* @__PURE__ */ jsx(
|
|
2257
|
-
"button",
|
|
2258
|
-
{
|
|
2259
|
-
onClick: handleSubmit,
|
|
2260
|
-
disabled: !isConnected || !hasValidAmount || tooManyDecimals || !!exceedsBalance || isPending,
|
|
2261
|
-
className: cn(
|
|
2262
|
-
"flex h-10 w-full cursor-pointer items-center justify-center rounded-[10px] px-3 py-2 text-sm font-medium transition-colors",
|
|
2263
|
-
"bg-primary text-primary-foreground hover:bg-primary/90",
|
|
2264
|
-
"disabled:cursor-not-allowed disabled:opacity-50"
|
|
2265
|
-
),
|
|
2266
|
-
children: getButtonText()
|
|
2033
|
+
if (beneficiaryRef.current?.toLowerCase() !== owner.toLowerCase()) {
|
|
2034
|
+
throw new Error("Authenticated deposit account changed while signing");
|
|
2035
|
+
}
|
|
2036
|
+
const next = {
|
|
2037
|
+
version: 1,
|
|
2038
|
+
owner,
|
|
2039
|
+
serviceAddress: targetService,
|
|
2040
|
+
chainId: token.chainId,
|
|
2041
|
+
tokenId: token.id,
|
|
2042
|
+
startBlock: Number(startBlock),
|
|
2043
|
+
depositAmount: amount.toString(),
|
|
2044
|
+
maxLockAmount: String(payload.amount),
|
|
2045
|
+
lockDuration,
|
|
2046
|
+
generation: payload.signature,
|
|
2047
|
+
payload
|
|
2048
|
+
};
|
|
2049
|
+
saveExternalDepositLockSession(next, null);
|
|
2050
|
+
installSession(next);
|
|
2051
|
+
} finally {
|
|
2052
|
+
signingRef.current = false;
|
|
2053
|
+
setIsSigning(false);
|
|
2267
2054
|
}
|
|
2268
|
-
)
|
|
2269
|
-
] });
|
|
2270
|
-
}
|
|
2271
|
-
function WithdrawForm({
|
|
2272
|
-
selectedToken,
|
|
2273
|
-
onTokenSelect,
|
|
2274
|
-
onPendingChange,
|
|
2275
|
-
onUnsafeToCloseChange
|
|
2276
|
-
}) {
|
|
2277
|
-
const { isConnected, address } = useAccount();
|
|
2278
|
-
const { chains, getChainById: getChainById2 } = usePrivanaContext();
|
|
2279
|
-
const [amount, setAmount] = useState("");
|
|
2280
|
-
const [showSuccess, setShowSuccess] = useState(false);
|
|
2281
|
-
const [showTimeout, setShowTimeout] = useState(false);
|
|
2282
|
-
const [cancelled, setCancelled] = useState(false);
|
|
2283
|
-
const targetChain = getChainById2(selectedToken.chainId) ?? chains[0];
|
|
2284
|
-
const {
|
|
2285
|
-
balanceWei,
|
|
2286
|
-
isLoading: isBalanceLoading,
|
|
2287
|
-
isError: isBalanceError
|
|
2288
|
-
} = useBalance({
|
|
2289
|
-
tokenId: selectedToken.id
|
|
2290
|
-
});
|
|
2291
|
-
const formattedBalance = formatTokenAmount(balanceWei, selectedToken.decimals);
|
|
2292
|
-
const { withdraw, isPending, currentStep, error, reset } = useWithdraw({
|
|
2293
|
-
onProcessingSuccess: () => {
|
|
2294
|
-
setAmount("");
|
|
2295
|
-
setShowSuccess(true);
|
|
2296
2055
|
},
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2056
|
+
[
|
|
2057
|
+
address,
|
|
2058
|
+
allowance,
|
|
2059
|
+
client,
|
|
2060
|
+
config,
|
|
2061
|
+
ensureCorrectChain,
|
|
2062
|
+
getTokenById,
|
|
2063
|
+
installSession,
|
|
2064
|
+
networkConfig,
|
|
2065
|
+
privateReadAddress,
|
|
2066
|
+
serviceAddress
|
|
2067
|
+
]
|
|
2068
|
+
);
|
|
2069
|
+
const settleAfterCredit = useCallback(
|
|
2070
|
+
async (txHash, creditedAmount) => {
|
|
2071
|
+
const active = sessionRef.current;
|
|
2072
|
+
if (!active || settlingRef.current) return;
|
|
2073
|
+
if (!isCurrentExternalDepositVerification(active, txHash)) {
|
|
2074
|
+
return;
|
|
2075
|
+
}
|
|
2076
|
+
if (creditedAmount <= 0n) throw new Error("Credited amount must be positive");
|
|
2077
|
+
const credited = {
|
|
2078
|
+
...active,
|
|
2079
|
+
verification: void 0,
|
|
2080
|
+
creditedAmount: creditedAmount.toString()
|
|
2081
|
+
};
|
|
2082
|
+
try {
|
|
2083
|
+
saveExternalDepositLockSession(credited, active);
|
|
2084
|
+
pendingCreditedTransitionRef.current = null;
|
|
2085
|
+
} catch (err) {
|
|
2086
|
+
const stored = loadExternalDepositLockSession(active.owner);
|
|
2087
|
+
if (err instanceof ExternalDepositLockSessionChangedError || !stored || !isSameExternalDepositLockSession(stored, active)) {
|
|
2088
|
+
pendingCreditedTransitionRef.current = null;
|
|
2089
|
+
installSession(stored ?? null);
|
|
2090
|
+
return;
|
|
2091
|
+
}
|
|
2092
|
+
pendingCreditedTransitionRef.current = { predecessor: active, credited };
|
|
2093
|
+
installSession(credited);
|
|
2094
|
+
notifyFailure(
|
|
2095
|
+
new PostDepositLockError(
|
|
2096
|
+
err instanceof Error ? err.message : "Unable to persist credited deposit state",
|
|
2097
|
+
"submission-failed",
|
|
2098
|
+
BigInt(active.maxLockAmount),
|
|
2099
|
+
creditedAmount,
|
|
2100
|
+
{ cause: err }
|
|
2101
|
+
)
|
|
2102
|
+
);
|
|
2103
|
+
return;
|
|
2104
|
+
}
|
|
2105
|
+
installSession(credited);
|
|
2106
|
+
await submitSession(credited);
|
|
2312
2107
|
},
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2108
|
+
[installSession, notifyFailure, submitSession]
|
|
2109
|
+
);
|
|
2110
|
+
const recordVerification = useCallback(
|
|
2111
|
+
(context) => {
|
|
2112
|
+
const active = sessionRef.current;
|
|
2113
|
+
if (!active || active.creditedAmount) {
|
|
2114
|
+
throw new Error("No external deposit session is awaiting verification");
|
|
2115
|
+
}
|
|
2116
|
+
if (active.verification) {
|
|
2117
|
+
const sameTransfer = active.verification.hash.toLowerCase() === context.hash.toLowerCase() && active.verification.chainId === context.chainId && active.verification.amount === context.amount.toString() && (active.verification.logIndex ?? 0) === (context.logIndex ?? 0);
|
|
2118
|
+
if (sameTransfer) return;
|
|
2119
|
+
throw new Error("Another transfer is already being verified for this deposit session");
|
|
2120
|
+
}
|
|
2121
|
+
if (context.chainId !== active.chainId || context.amount <= 0n) {
|
|
2122
|
+
throw new Error("Discovered transfer does not match the signed deposit session");
|
|
2123
|
+
}
|
|
2124
|
+
const current = loadExternalDepositLockSession(active.owner);
|
|
2125
|
+
if (!current || current.generation !== active.generation) {
|
|
2126
|
+
throw new Error("The signed deposit session changed before verification");
|
|
2127
|
+
}
|
|
2128
|
+
const next = {
|
|
2129
|
+
...active,
|
|
2130
|
+
verification: {
|
|
2131
|
+
hash: context.hash,
|
|
2132
|
+
chainId: context.chainId,
|
|
2133
|
+
amount: context.amount.toString(),
|
|
2134
|
+
logIndex: context.logIndex
|
|
2135
|
+
}
|
|
2136
|
+
};
|
|
2137
|
+
saveExternalDepositLockSession(next, active);
|
|
2138
|
+
installSession(next);
|
|
2317
2139
|
},
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
toast.error(error.message.length > 100 ? `${error.message.slice(0, 100)}...` : error.message);
|
|
2140
|
+
[installSession]
|
|
2141
|
+
);
|
|
2142
|
+
const retryAfterCredit = useCallback(async () => {
|
|
2143
|
+
const active = sessionRef.current;
|
|
2144
|
+
if (!active?.creditedAmount) throw new Error("No credited external deposit to recover");
|
|
2145
|
+
if (signingRef.current || settlingRef.current) {
|
|
2146
|
+
throw new Error("A policy operation is already in progress");
|
|
2326
2147
|
}
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
const pending = isPending && !cancelled;
|
|
2330
|
-
onPendingChange?.(pending);
|
|
2331
|
-
onUnsafeToCloseChange?.(pending);
|
|
2332
|
-
}, [isPending, cancelled, onPendingChange, onUnsafeToCloseChange]);
|
|
2333
|
-
const handleCancel = () => {
|
|
2334
|
-
setCancelled(true);
|
|
2335
|
-
reset();
|
|
2336
|
-
};
|
|
2337
|
-
const handleDone = () => {
|
|
2338
|
-
setShowSuccess(false);
|
|
2339
|
-
setShowTimeout(false);
|
|
2340
|
-
setCancelled(false);
|
|
2341
|
-
reset();
|
|
2342
|
-
};
|
|
2343
|
-
const handleWithdraw = async () => {
|
|
2344
|
-
if (!amount || !selectedToken || exceedsBalance) return;
|
|
2345
|
-
setCancelled(false);
|
|
2346
|
-
const amountInWei = parseTokenAmount(amount, selectedToken.decimals);
|
|
2347
|
-
await withdraw({
|
|
2348
|
-
tokenId: selectedToken.id,
|
|
2349
|
-
amount: amountInWei
|
|
2350
|
-
});
|
|
2351
|
-
};
|
|
2352
|
-
const handleMaxClick = () => {
|
|
2353
|
-
if (formattedBalance && parseFloat(formattedBalance) > 0) {
|
|
2354
|
-
setAmount(formattedBalance.replace(/[\s\u2009]/g, ""));
|
|
2148
|
+
if (privateReadAddress?.toLowerCase() !== active.owner.toLowerCase()) {
|
|
2149
|
+
throw new Error("Authenticated deposit account does not match the credited deposit");
|
|
2355
2150
|
}
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
if (
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
);
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
);
|
|
2396
|
-
}
|
|
2397
|
-
return /* @__PURE__ */ jsxs("div", { className: "flex w-full flex-col gap-6", children: [
|
|
2398
|
-
/* @__PURE__ */ jsxs("div", { className: "flex w-full flex-col gap-3", children: [
|
|
2399
|
-
/* @__PURE__ */ jsx("label", { className: "text-muted-foreground text-sm", children: "Token" }),
|
|
2400
|
-
/* @__PURE__ */ jsxs(
|
|
2401
|
-
"button",
|
|
2402
|
-
{
|
|
2403
|
-
onClick: onTokenSelect,
|
|
2404
|
-
className: "border-border bg-input flex w-full cursor-pointer items-center gap-3 rounded-lg border p-3",
|
|
2405
|
-
children: [
|
|
2406
|
-
/* @__PURE__ */ jsx("div", { className: "h-8 w-8 shrink-0 overflow-hidden rounded-full", children: getTokenIcon(selectedToken.symbol, 32) }),
|
|
2407
|
-
/* @__PURE__ */ jsxs("div", { className: "flex flex-1 flex-col items-start gap-1", children: [
|
|
2408
|
-
/* @__PURE__ */ jsx("span", { className: "text-foreground text-sm font-medium", children: selectedToken.symbol }),
|
|
2409
|
-
/* @__PURE__ */ jsxs("span", { className: "text-muted-foreground text-xs", children: [
|
|
2410
|
-
"on ",
|
|
2411
|
-
targetChain?.name ?? "Base Sepolia"
|
|
2412
|
-
] })
|
|
2413
|
-
] }),
|
|
2414
|
-
/* @__PURE__ */ jsx("div", { className: "text-muted-foreground flex h-5 w-5 items-center justify-center", children: /* @__PURE__ */ jsx(ChevronRightIcon, {}) })
|
|
2415
|
-
]
|
|
2416
|
-
}
|
|
2417
|
-
)
|
|
2418
|
-
] }),
|
|
2419
|
-
/* @__PURE__ */ jsxs("div", { className: "flex w-full flex-col gap-3", children: [
|
|
2420
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
|
|
2421
|
-
/* @__PURE__ */ jsx("label", { className: "text-muted-foreground text-sm", children: "Amount" }),
|
|
2422
|
-
/* @__PURE__ */ jsxs("span", { className: "text-muted-foreground text-sm", children: [
|
|
2423
|
-
formattedBalance,
|
|
2424
|
-
" ",
|
|
2425
|
-
selectedToken.symbol
|
|
2426
|
-
] })
|
|
2427
|
-
] }),
|
|
2428
|
-
/* @__PURE__ */ jsxs("div", { className: "border-border bg-input flex items-center gap-2 rounded-[10px] border py-1 pr-1 pl-3", children: [
|
|
2429
|
-
/* @__PURE__ */ jsx(
|
|
2430
|
-
"input",
|
|
2431
|
-
{
|
|
2432
|
-
type: "text",
|
|
2433
|
-
inputMode: "decimal",
|
|
2434
|
-
placeholder: "Enter Amount",
|
|
2435
|
-
value: amount,
|
|
2436
|
-
onChange: (e) => {
|
|
2437
|
-
const value = e.target.value.replace(/[^0-9.,]/g, "").replace(/,/g, ".");
|
|
2438
|
-
if (value.split(".").length <= 2) {
|
|
2439
|
-
setAmount(value);
|
|
2440
|
-
}
|
|
2441
|
-
},
|
|
2442
|
-
className: cn(
|
|
2443
|
-
"text-foreground flex-1 bg-transparent text-sm outline-none",
|
|
2444
|
-
"placeholder:text-muted-foreground/50"
|
|
2445
|
-
)
|
|
2446
|
-
}
|
|
2447
|
-
),
|
|
2448
|
-
/* @__PURE__ */ jsx(
|
|
2449
|
-
"button",
|
|
2450
|
-
{
|
|
2451
|
-
onClick: handleMaxClick,
|
|
2452
|
-
className: "bg-secondary text-foreground hover:bg-secondary/80 cursor-pointer rounded px-3 py-2.5 text-xs font-semibold transition-colors",
|
|
2453
|
-
children: "MAX"
|
|
2454
|
-
}
|
|
2455
|
-
)
|
|
2456
|
-
] }),
|
|
2457
|
-
tooManyDecimals && /* @__PURE__ */ jsxs("p", { className: "text-destructive text-sm", children: [
|
|
2458
|
-
"Too many decimal places (max: ",
|
|
2459
|
-
selectedToken.decimals,
|
|
2460
|
-
")"
|
|
2461
|
-
] }),
|
|
2462
|
-
exceedsBalance && /* @__PURE__ */ jsx("p", { className: "text-destructive text-sm", children: "Insufficient balance" })
|
|
2463
|
-
] }),
|
|
2464
|
-
/* @__PURE__ */ jsx(
|
|
2465
|
-
"button",
|
|
2466
|
-
{
|
|
2467
|
-
onClick: handleWithdraw,
|
|
2468
|
-
disabled: !isConnected || !hasValidAmount || tooManyDecimals || !!exceedsBalance || isPending,
|
|
2469
|
-
className: cn(
|
|
2470
|
-
"flex h-10 w-full cursor-pointer items-center justify-center rounded-[10px] px-3 py-2 text-sm font-medium transition-colors",
|
|
2471
|
-
"bg-primary text-primary-foreground hover:bg-primary/90",
|
|
2472
|
-
"disabled:cursor-not-allowed disabled:opacity-50"
|
|
2473
|
-
),
|
|
2474
|
-
children: getButtonText()
|
|
2475
|
-
}
|
|
2476
|
-
)
|
|
2477
|
-
] });
|
|
2478
|
-
}
|
|
2479
|
-
function BalanceCards({
|
|
2480
|
-
selectedToken,
|
|
2481
|
-
onLockedFundsClick,
|
|
2482
|
-
onBalanceClick,
|
|
2483
|
-
showLockedFunds = true,
|
|
2484
|
-
disabled
|
|
2485
|
-
}) {
|
|
2486
|
-
const { balanceWei, isLoading: balanceLoading } = useBalance({
|
|
2487
|
-
tokenId: selectedToken.id
|
|
2488
|
-
});
|
|
2489
|
-
const { totalLocked, isLoading: lockedLoading } = useLockedFunds({ enabled: showLockedFunds });
|
|
2490
|
-
const formattedBalance = formatTokenAmount(balanceWei, selectedToken.decimals);
|
|
2491
|
-
const formattedLocked = showLockedFunds ? formatTokenAmount(String(totalLocked), selectedToken.decimals) : "0.00";
|
|
2492
|
-
return /* @__PURE__ */ jsxs("div", { className: cn("flex gap-2", disabled && "opacity-50"), children: [
|
|
2493
|
-
/* @__PURE__ */ jsxs(
|
|
2494
|
-
"button",
|
|
2495
|
-
{
|
|
2496
|
-
onClick: onBalanceClick,
|
|
2497
|
-
disabled,
|
|
2498
|
-
className: cn(
|
|
2499
|
-
"bg-muted flex flex-1 flex-col gap-2 rounded-[10px] p-5 text-left transition-colors",
|
|
2500
|
-
disabled ? "cursor-not-allowed" : "hover:bg-muted/80 cursor-pointer"
|
|
2501
|
-
),
|
|
2502
|
-
children: [
|
|
2503
|
-
/* @__PURE__ */ jsxs("div", { className: "flex w-full items-center justify-between", children: [
|
|
2504
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
|
|
2505
|
-
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground text-sm", children: "Balance" }),
|
|
2506
|
-
/* @__PURE__ */ jsx("span", { className: "bg-secondary text-muted-foreground rounded-full px-2 py-[5px] text-[10px] font-bold", children: selectedToken.symbol })
|
|
2507
|
-
] }),
|
|
2508
|
-
/* @__PURE__ */ jsx("div", { className: "text-muted-foreground flex h-6 w-6 items-center justify-center", children: /* @__PURE__ */ jsx(ChevronRightIcon, {}) })
|
|
2509
|
-
] }),
|
|
2510
|
-
/* @__PURE__ */ jsx("div", { className: "text-foreground text-xl font-medium", children: balanceLoading ? /* @__PURE__ */ jsx("span", { className: "bg-secondary inline-block h-6 w-24 animate-pulse rounded" }) : formattedBalance })
|
|
2511
|
-
]
|
|
2512
|
-
}
|
|
2513
|
-
),
|
|
2514
|
-
showLockedFunds && /* @__PURE__ */ jsxs(
|
|
2515
|
-
"button",
|
|
2516
|
-
{
|
|
2517
|
-
onClick: onLockedFundsClick,
|
|
2518
|
-
disabled,
|
|
2519
|
-
className: cn(
|
|
2520
|
-
"bg-muted flex flex-1 flex-col gap-2 rounded-[10px] p-5 text-left transition-colors",
|
|
2521
|
-
disabled ? "cursor-not-allowed" : "hover:bg-muted/80 cursor-pointer"
|
|
2522
|
-
),
|
|
2523
|
-
children: [
|
|
2524
|
-
/* @__PURE__ */ jsxs("div", { className: "flex w-full items-center justify-between", children: [
|
|
2525
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
|
|
2526
|
-
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground text-sm", children: "Locked Funds" }),
|
|
2527
|
-
/* @__PURE__ */ jsx("span", { className: "bg-secondary text-muted-foreground rounded-full px-2 py-[5px] text-[10px] font-bold", children: selectedToken.symbol })
|
|
2528
|
-
] }),
|
|
2529
|
-
/* @__PURE__ */ jsx("div", { className: "text-muted-foreground flex h-6 w-6 items-center justify-center", children: /* @__PURE__ */ jsx(ChevronRightIcon, {}) })
|
|
2530
|
-
] }),
|
|
2531
|
-
/* @__PURE__ */ jsx("div", { className: "text-foreground text-xl font-medium", children: lockedLoading ? /* @__PURE__ */ jsx("span", { className: "bg-secondary inline-block h-6 w-20 animate-pulse rounded" }) : formattedLocked })
|
|
2532
|
-
]
|
|
2151
|
+
const token = getTokenById(active.tokenId);
|
|
2152
|
+
if (!token || token.chainId !== active.chainId || token.contract === zeroAddress) {
|
|
2153
|
+
throw new Error("The credited token is no longer available");
|
|
2154
|
+
}
|
|
2155
|
+
const targetService = requireServiceAddress(serviceAddress);
|
|
2156
|
+
if (targetService.toLowerCase() !== active.serviceAddress.toLowerCase()) {
|
|
2157
|
+
throw new Error("The service for this credited deposit has changed");
|
|
2158
|
+
}
|
|
2159
|
+
if (active.payload) {
|
|
2160
|
+
await submitSession(active);
|
|
2161
|
+
return;
|
|
2162
|
+
}
|
|
2163
|
+
if (active.submissionAmbiguous) {
|
|
2164
|
+
throw new Error(
|
|
2165
|
+
"The previous lock submission may have succeeded; a fresh signature is unsafe"
|
|
2166
|
+
);
|
|
2167
|
+
}
|
|
2168
|
+
const owner = requireDepositLockOwner(address, privateReadAddress);
|
|
2169
|
+
const amount = externalDepositRetryAmount(active);
|
|
2170
|
+
let retrySession;
|
|
2171
|
+
signingRef.current = true;
|
|
2172
|
+
setIsSigning(true);
|
|
2173
|
+
try {
|
|
2174
|
+
await ensureCorrectChain(networkConfig.chainId);
|
|
2175
|
+
const signingWalletClient = await getWalletClient(config, {
|
|
2176
|
+
chainId: networkConfig.chainId
|
|
2177
|
+
});
|
|
2178
|
+
const payload = await createSignedLockRequest({
|
|
2179
|
+
client,
|
|
2180
|
+
walletClient: signingWalletClient,
|
|
2181
|
+
userAddress: owner,
|
|
2182
|
+
networkConfig,
|
|
2183
|
+
serviceAddress: targetService,
|
|
2184
|
+
tokenId: active.tokenId,
|
|
2185
|
+
amount,
|
|
2186
|
+
lockDuration: active.lockDuration
|
|
2187
|
+
});
|
|
2188
|
+
if (beneficiaryRef.current?.toLowerCase() !== owner.toLowerCase()) {
|
|
2189
|
+
throw new Error("Authenticated deposit account changed while signing");
|
|
2533
2190
|
}
|
|
2534
|
-
|
|
2535
|
-
|
|
2191
|
+
retrySession = {
|
|
2192
|
+
...active,
|
|
2193
|
+
depositAmount: amount.toString(),
|
|
2194
|
+
generation: payload.signature,
|
|
2195
|
+
verification: void 0,
|
|
2196
|
+
submissionAmbiguous: void 0,
|
|
2197
|
+
payload
|
|
2198
|
+
};
|
|
2199
|
+
saveExternalDepositLockSession(retrySession, active);
|
|
2200
|
+
installSession(retrySession);
|
|
2201
|
+
} finally {
|
|
2202
|
+
signingRef.current = false;
|
|
2203
|
+
setIsSigning(false);
|
|
2204
|
+
}
|
|
2205
|
+
await submitSession(retrySession);
|
|
2206
|
+
}, [
|
|
2207
|
+
address,
|
|
2208
|
+
client,
|
|
2209
|
+
config,
|
|
2210
|
+
ensureCorrectChain,
|
|
2211
|
+
getTokenById,
|
|
2212
|
+
installSession,
|
|
2213
|
+
networkConfig,
|
|
2214
|
+
privateReadAddress,
|
|
2215
|
+
serviceAddress,
|
|
2216
|
+
submitSession
|
|
2217
|
+
]);
|
|
2218
|
+
const clearVerification = useCallback(() => {
|
|
2219
|
+
const active = sessionRef.current;
|
|
2220
|
+
if (!active?.verification || active.creditedAmount) return false;
|
|
2221
|
+
const next = clearExternalDepositVerification(active);
|
|
2222
|
+
if (!next) {
|
|
2223
|
+
installSession(loadExternalDepositLockSession(active.owner) ?? null);
|
|
2224
|
+
return false;
|
|
2225
|
+
}
|
|
2226
|
+
installSession(next);
|
|
2227
|
+
return true;
|
|
2228
|
+
}, [installSession]);
|
|
2229
|
+
const discardSession = useCallback(() => {
|
|
2230
|
+
const active = sessionRef.current;
|
|
2231
|
+
if (!active) return true;
|
|
2232
|
+
if (signingRef.current || settlingRef.current) return false;
|
|
2233
|
+
const pending = pendingCreditedTransitionRef.current;
|
|
2234
|
+
const discardTarget = pending && isSameExternalDepositLockSession(active, pending.credited) ? pending.predecessor : active;
|
|
2235
|
+
const discarded = discardExternalDepositLockSession(discardTarget);
|
|
2236
|
+
const restored = loadExternalDepositLockSession(active.owner) ?? null;
|
|
2237
|
+
if (discarded) pendingCreditedTransitionRef.current = null;
|
|
2238
|
+
installSession(restored);
|
|
2239
|
+
return discarded && !restored;
|
|
2240
|
+
}, [installSession]);
|
|
2241
|
+
return {
|
|
2242
|
+
isSigning,
|
|
2243
|
+
isSubmittingLock,
|
|
2244
|
+
session,
|
|
2245
|
+
signAndPersist,
|
|
2246
|
+
recordVerification,
|
|
2247
|
+
settleAfterCredit,
|
|
2248
|
+
retryAfterCredit,
|
|
2249
|
+
clearVerification,
|
|
2250
|
+
discardSession
|
|
2251
|
+
};
|
|
2536
2252
|
}
|
|
2537
|
-
function
|
|
2538
|
-
activeTab,
|
|
2539
|
-
onTabChange,
|
|
2540
|
-
disabled
|
|
2541
|
-
}) {
|
|
2253
|
+
function USDCIcon({ className, size = 24 }) {
|
|
2542
2254
|
return /* @__PURE__ */ jsxs(
|
|
2543
|
-
"
|
|
2255
|
+
"svg",
|
|
2544
2256
|
{
|
|
2545
|
-
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
|
|
2257
|
+
width: size,
|
|
2258
|
+
height: size,
|
|
2259
|
+
viewBox: "0 0 2000 2000",
|
|
2260
|
+
fill: "none",
|
|
2261
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
2262
|
+
className,
|
|
2549
2263
|
children: [
|
|
2550
2264
|
/* @__PURE__ */ jsx(
|
|
2551
|
-
"
|
|
2265
|
+
"path",
|
|
2552
2266
|
{
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
activeTab === "withdraw" && "translate-x-[calc(100%+8px)]"
|
|
2556
|
-
)
|
|
2267
|
+
d: "M1000 2000c554.17 0 1000-445.83 1000-1000S1554.17 0 1000 0 0 445.83 0 1000s445.83 1000 1000 1000z",
|
|
2268
|
+
fill: "#2775ca"
|
|
2557
2269
|
}
|
|
2558
2270
|
),
|
|
2559
2271
|
/* @__PURE__ */ jsx(
|
|
2560
|
-
"
|
|
2272
|
+
"path",
|
|
2561
2273
|
{
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
className: cn(
|
|
2565
|
-
"relative z-10 flex-1 rounded-md px-3 py-[9px] text-sm transition-colors",
|
|
2566
|
-
activeTab === "deposit" ? "text-foreground" : "text-muted-foreground",
|
|
2567
|
-
disabled ? "cursor-not-allowed" : "cursor-pointer"
|
|
2568
|
-
),
|
|
2569
|
-
children: "Deposit"
|
|
2274
|
+
d: "M1275 1158.33c0-145.83-87.5-195.83-262.5-216.66-125-16.67-150-50-150-108.34s41.67-95.83 125-95.83c75 0 116.67 25 137.5 87.5 4.17 12.5 16.67 20.83 29.17 20.83h66.66c16.67 0 29.17-12.5 29.17-29.16v-4.17c-16.67-91.67-91.67-162.5-187.5-170.83v-100c0-16.67-12.5-29.17-33.33-33.34h-62.5c-16.67 0-29.17 12.5-33.34 33.34v95.83c-125 16.67-204.16 100-204.16 204.17 0 137.5 83.33 191.66 258.33 212.5 116.67 20.83 154.17 45.83 154.17 112.5s-58.34 112.5-137.5 112.5c-108.34 0-145.84-45.84-158.34-108.34-4.16-16.66-16.66-25-29.16-25h-70.84c-16.66 0-29.16 12.5-29.16 29.17v4.17c16.66 104.16 83.33 179.16 220.83 200v100c0 16.66 12.5 29.16 33.33 33.33h62.5c16.67 0 29.17-12.5 33.34-33.33v-100c125-20.84 208.33-108.34 208.33-220.84z",
|
|
2275
|
+
fill: "#fff"
|
|
2570
2276
|
}
|
|
2571
2277
|
),
|
|
2572
2278
|
/* @__PURE__ */ jsx(
|
|
2573
|
-
"
|
|
2279
|
+
"path",
|
|
2574
2280
|
{
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
className: cn(
|
|
2578
|
-
"relative z-10 flex-1 rounded-md px-3 py-[9px] text-sm transition-colors",
|
|
2579
|
-
activeTab === "withdraw" ? "text-foreground" : "text-muted-foreground",
|
|
2580
|
-
disabled ? "cursor-not-allowed" : "cursor-pointer"
|
|
2581
|
-
),
|
|
2582
|
-
children: "Withdraw"
|
|
2281
|
+
d: "M787.5 1595.83c-325-116.66-491.67-479.16-370.83-800 62.5-175 200-308.33 370.83-370.83 16.67-8.33 25-20.83 25-41.67V325c0-16.67-8.33-29.17-25-33.33-4.17 0-12.5 0-16.67 4.16-395.83 125-612.5 545.84-487.5 941.67 75 233.33 254.17 412.5 487.5 487.5 16.67 8.33 33.34 0 37.5-16.67 4.17-4.16 4.17-8.33 4.17-16.66v-58.34c0-12.5-12.5-29.16-25-37.5zM1229.17 295.83c-16.67-8.33-33.34 0-37.5 16.67-4.17 4.17-4.17 8.33-4.17 16.67v58.33c0 16.67 12.5 33.33 25 41.67 325 116.66 491.67 479.16 370.83 800-62.5 175-200 308.33-370.83 370.83-16.67 8.33-25 20.83-25 41.67V1700c0 16.67 8.33 29.17 25 33.33 4.17 0 12.5 0 16.67-4.16 395.83-125 612.5-545.84 487.5-941.67-75-237.5-258.34-416.67-487.5-491.67z",
|
|
2282
|
+
fill: "#fff"
|
|
2583
2283
|
}
|
|
2584
2284
|
)
|
|
2585
2285
|
]
|
|
2586
2286
|
}
|
|
2587
2287
|
);
|
|
2588
2288
|
}
|
|
2589
|
-
function
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
});
|
|
2611
|
-
});
|
|
2612
|
-
return Object.values(sectionMap);
|
|
2613
|
-
}, [getTokenById, locks]);
|
|
2614
|
-
const toggleSection = (title) => {
|
|
2615
|
-
setCollapsedSections((prev) => ({
|
|
2616
|
-
...prev,
|
|
2617
|
-
[title]: !prev[title]
|
|
2618
|
-
}));
|
|
2619
|
-
};
|
|
2620
|
-
const expiredCount = locks.filter((l) => l.is_expired).length;
|
|
2621
|
-
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2622
|
-
/* @__PURE__ */ jsx("div", { className: "flex items-center justify-between px-5 py-4", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
2623
|
-
/* @__PURE__ */ jsx(
|
|
2624
|
-
"button",
|
|
2625
|
-
{
|
|
2626
|
-
onClick: onBack,
|
|
2627
|
-
className: "text-muted-foreground hover:text-foreground -ml-2 flex h-6 w-6 cursor-pointer items-center justify-center transition-colors",
|
|
2628
|
-
children: /* @__PURE__ */ jsx(ChevronLeftIcon, {})
|
|
2629
|
-
}
|
|
2630
|
-
),
|
|
2631
|
-
/* @__PURE__ */ jsx("span", { className: "text-foreground text-xl leading-6 font-medium", children: "Locked Funds" })
|
|
2632
|
-
] }) }),
|
|
2633
|
-
/* @__PURE__ */ jsxs("div", { className: "bg-muted flex min-h-0 flex-1 flex-col rounded-[10px] p-2", children: [
|
|
2634
|
-
/* @__PURE__ */ jsx("div", { className: "flex-1 overflow-y-auto", children: isLoading ? /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-2 p-3", children: [1, 2].map((i) => /* @__PURE__ */ jsxs("div", { className: "flex animate-pulse items-center gap-3 rounded-lg p-3", children: [
|
|
2635
|
-
/* @__PURE__ */ jsx("div", { className: "bg-secondary h-10 w-10 rounded-full" }),
|
|
2636
|
-
/* @__PURE__ */ jsxs("div", { className: "flex-1", children: [
|
|
2637
|
-
/* @__PURE__ */ jsx("div", { className: "bg-secondary mb-2 h-3.5 w-24 rounded" }),
|
|
2638
|
-
/* @__PURE__ */ jsx("div", { className: "bg-secondary h-3 w-32 rounded" })
|
|
2639
|
-
] })
|
|
2640
|
-
] }, i)) }) : sections.length === 0 ? /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center p-8", children: /* @__PURE__ */ jsx("span", { className: "text-muted-foreground text-sm", children: "No locked funds" }) }) : sections.map((section) => /* @__PURE__ */ jsxs("div", { children: [
|
|
2641
|
-
/* @__PURE__ */ jsxs(
|
|
2642
|
-
"button",
|
|
2643
|
-
{
|
|
2644
|
-
onClick: () => toggleSection(section.title),
|
|
2645
|
-
className: "text-muted-foreground hover:bg-secondary flex w-full cursor-pointer items-center justify-between rounded-lg px-4 py-4 transition-colors",
|
|
2646
|
-
children: [
|
|
2647
|
-
/* @__PURE__ */ jsx("span", { className: "text-sm", children: section.title }),
|
|
2648
|
-
/* @__PURE__ */ jsx(
|
|
2649
|
-
ChevronDownIcon,
|
|
2650
|
-
{
|
|
2651
|
-
direction: collapsedSections[section.title] ? "right" : "down"
|
|
2652
|
-
}
|
|
2653
|
-
)
|
|
2654
|
-
]
|
|
2655
|
-
}
|
|
2656
|
-
),
|
|
2657
|
-
!collapsedSections[section.title] && section.items.map((item) => /* @__PURE__ */ jsxs(
|
|
2658
|
-
"div",
|
|
2659
|
-
{
|
|
2660
|
-
className: cn(
|
|
2661
|
-
"flex items-center justify-between gap-3 rounded-lg p-3",
|
|
2662
|
-
item.isExpired && "bg-secondary"
|
|
2663
|
-
),
|
|
2664
|
-
children: [
|
|
2665
|
-
/* @__PURE__ */ jsxs("div", { className: "flex flex-1 items-center gap-3", children: [
|
|
2666
|
-
/* @__PURE__ */ jsx("div", { className: "bg-secondary h-10 w-10 rounded-full" }),
|
|
2667
|
-
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
|
|
2668
|
-
/* @__PURE__ */ jsxs("span", { className: "text-foreground text-sm font-medium", children: [
|
|
2669
|
-
item.amount,
|
|
2670
|
-
" USDC"
|
|
2671
|
-
] }),
|
|
2672
|
-
/* @__PURE__ */ jsxs("span", { className: "text-muted-foreground text-xs", children: [
|
|
2673
|
-
"Service: ",
|
|
2674
|
-
shortenAddress(item.serviceAddress)
|
|
2675
|
-
] })
|
|
2676
|
-
] })
|
|
2677
|
-
] }),
|
|
2678
|
-
/* @__PURE__ */ jsxs("div", { className: "flex flex-1 flex-col items-end gap-2", children: [
|
|
2679
|
-
item.isExpired ? /* @__PURE__ */ jsx(
|
|
2680
|
-
"button",
|
|
2681
|
-
{
|
|
2682
|
-
onClick: () => unlockFunds({ lockId: Number(item.lockId) }),
|
|
2683
|
-
disabled: isPending,
|
|
2684
|
-
className: "text-foreground hover:text-foreground/80 cursor-pointer text-sm transition-colors disabled:opacity-50",
|
|
2685
|
-
children: "Click to unlock"
|
|
2686
|
-
}
|
|
2687
|
-
) : /* @__PURE__ */ jsx("span", { className: "text-sm text-amber-500", children: item.time }),
|
|
2688
|
-
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground text-xs", children: "on Base Sepolia" })
|
|
2689
|
-
] })
|
|
2690
|
-
]
|
|
2691
|
-
},
|
|
2692
|
-
`${item.serviceAddress}-${item.lockId}`
|
|
2693
|
-
))
|
|
2694
|
-
] }, section.title)) }),
|
|
2695
|
-
expiredCount > 0 && /* @__PURE__ */ jsx("div", { className: "p-3", children: /* @__PURE__ */ jsxs(
|
|
2696
|
-
"button",
|
|
2697
|
-
{
|
|
2698
|
-
onClick: () => unlockAllExpired(),
|
|
2699
|
-
disabled: isPending,
|
|
2700
|
-
className: "border-border text-foreground hover:bg-secondary flex h-10 w-full cursor-pointer items-center justify-center rounded-[10px] border px-3 py-2 text-sm font-medium transition-colors disabled:opacity-50",
|
|
2701
|
-
children: [
|
|
2702
|
-
"Unlock All (",
|
|
2703
|
-
expiredCount,
|
|
2704
|
-
")"
|
|
2705
|
-
]
|
|
2706
|
-
}
|
|
2707
|
-
) })
|
|
2708
|
-
] })
|
|
2709
|
-
] });
|
|
2710
|
-
}
|
|
2711
|
-
function BalanceTokenRow({ token }) {
|
|
2712
|
-
const { balanceWei, isLoading } = useBalance({
|
|
2713
|
-
tokenId: token.id
|
|
2714
|
-
});
|
|
2715
|
-
const formattedBalance = formatTokenAmount(balanceWei, token.decimals);
|
|
2716
|
-
return /* @__PURE__ */ jsxs("div", { className: "flex w-full items-center gap-2 rounded-lg px-3 py-2.5", children: [
|
|
2717
|
-
/* @__PURE__ */ jsx("div", { className: "h-[18px] w-[18px] overflow-hidden rounded-full", children: getTokenIcon(token.symbol, 18) }),
|
|
2718
|
-
/* @__PURE__ */ jsx("span", { className: "text-foreground flex-1 text-sm", children: token.symbol }),
|
|
2719
|
-
isLoading ? /* @__PURE__ */ jsx("span", { className: "bg-secondary h-4 w-16 animate-pulse rounded" }) : /* @__PURE__ */ jsx("span", { className: "text-muted-foreground text-sm", children: formattedBalance })
|
|
2720
|
-
] });
|
|
2721
|
-
}
|
|
2722
|
-
function BalanceDetailsView({ onBack }) {
|
|
2723
|
-
const { enabledTokens, chains } = usePrivanaContext();
|
|
2724
|
-
const [selectedChainId, setSelectedChainId] = useState(chains[0]?.id ?? 84532);
|
|
2725
|
-
const chainTokens = useMemo(() => {
|
|
2726
|
-
return enabledTokens.filter((t) => t.chainId === selectedChainId);
|
|
2727
|
-
}, [enabledTokens, selectedChainId]);
|
|
2728
|
-
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2729
|
-
/* @__PURE__ */ jsx("div", { className: "flex items-center justify-between px-5 py-4", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
2730
|
-
/* @__PURE__ */ jsx(
|
|
2731
|
-
"button",
|
|
2732
|
-
{
|
|
2733
|
-
onClick: onBack,
|
|
2734
|
-
className: "text-muted-foreground hover:text-foreground -ml-2 flex h-6 w-6 cursor-pointer items-center justify-center transition-colors",
|
|
2735
|
-
children: /* @__PURE__ */ jsx(ChevronLeftIcon, {})
|
|
2736
|
-
}
|
|
2737
|
-
),
|
|
2738
|
-
/* @__PURE__ */ jsx("span", { className: "text-foreground text-xl leading-6 font-medium", children: "Token Balances" })
|
|
2739
|
-
] }) }),
|
|
2740
|
-
/* @__PURE__ */ jsxs("div", { className: "flex min-h-0 flex-1 gap-2", children: [
|
|
2741
|
-
/* @__PURE__ */ jsxs("div", { className: "bg-muted flex flex-1 flex-col overflow-hidden rounded-[10px] p-2", children: [
|
|
2742
|
-
/* @__PURE__ */ jsx("div", { className: "px-4 pt-4 pb-2", children: /* @__PURE__ */ jsx("span", { className: "text-muted-foreground text-sm", children: "Network" }) }),
|
|
2743
|
-
/* @__PURE__ */ jsx("div", { className: "mt-1 flex-1 overflow-y-auto", children: chains.map((chain) => {
|
|
2744
|
-
const isSelected = selectedChainId === chain.id;
|
|
2745
|
-
return /* @__PURE__ */ jsxs(
|
|
2746
|
-
"button",
|
|
2747
|
-
{
|
|
2748
|
-
onClick: () => setSelectedChainId(chain.id),
|
|
2749
|
-
className: cn(
|
|
2750
|
-
"hover:bg-secondary flex w-full cursor-pointer items-center gap-2 rounded-lg px-3 py-2.5 text-left transition-colors",
|
|
2751
|
-
isSelected && "bg-secondary"
|
|
2752
|
-
),
|
|
2753
|
-
children: [
|
|
2754
|
-
/* @__PURE__ */ jsx("div", { className: "h-[18px] w-[18px] overflow-hidden rounded-full", children: getChainIcon(chain.id, 18) }),
|
|
2755
|
-
/* @__PURE__ */ jsx("span", { className: "text-foreground flex-1 text-sm", children: chain.name })
|
|
2756
|
-
]
|
|
2757
|
-
},
|
|
2758
|
-
chain.id
|
|
2759
|
-
);
|
|
2760
|
-
}) })
|
|
2761
|
-
] }),
|
|
2762
|
-
/* @__PURE__ */ jsxs("div", { className: "bg-muted flex flex-[2] flex-col overflow-hidden rounded-[10px] p-2", children: [
|
|
2763
|
-
/* @__PURE__ */ jsx("div", { className: "px-4 pt-4 pb-2", children: /* @__PURE__ */ jsx("span", { className: "text-muted-foreground text-sm", children: "Token Balance" }) }),
|
|
2764
|
-
/* @__PURE__ */ jsx("div", { className: "mt-2 flex-1 overflow-y-auto", children: chainTokens.map((token) => /* @__PURE__ */ jsx(BalanceTokenRow, { token }, token.id)) })
|
|
2765
|
-
] })
|
|
2766
|
-
] })
|
|
2767
|
-
] });
|
|
2289
|
+
function BaseIcon({ className, size = 24 }) {
|
|
2290
|
+
return /* @__PURE__ */ jsxs(
|
|
2291
|
+
"svg",
|
|
2292
|
+
{
|
|
2293
|
+
width: size,
|
|
2294
|
+
height: size,
|
|
2295
|
+
viewBox: "0 0 2500 2500",
|
|
2296
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
2297
|
+
className,
|
|
2298
|
+
children: [
|
|
2299
|
+
/* @__PURE__ */ jsx("circle", { cx: "1250", cy: "1250", r: "1250", fill: "#0052FF" }),
|
|
2300
|
+
/* @__PURE__ */ jsx(
|
|
2301
|
+
"path",
|
|
2302
|
+
{
|
|
2303
|
+
d: "M1247.8,2500c691.6,0,1252.2-559.6,1252.2-1250C2500,559.6,1939.4,0,1247.8,0C591.7,0,53.5,503.8,0,1144.9h1655.1v210.2H0C53.5,1996.2,591.7,2500,1247.8,2500z",
|
|
2304
|
+
fill: "white"
|
|
2305
|
+
}
|
|
2306
|
+
)
|
|
2307
|
+
]
|
|
2308
|
+
}
|
|
2309
|
+
);
|
|
2768
2310
|
}
|
|
2769
|
-
function
|
|
2770
|
-
token,
|
|
2771
|
-
isSelected,
|
|
2772
|
-
onClick
|
|
2773
|
-
}) {
|
|
2774
|
-
const { address } = useAccount();
|
|
2775
|
-
const isNative = token.contract === zeroAddress;
|
|
2776
|
-
const { data: nativeBalanceData } = useBalance$1({
|
|
2777
|
-
address,
|
|
2778
|
-
chainId: token.chainId,
|
|
2779
|
-
query: { enabled: !!address && isNative }
|
|
2780
|
-
});
|
|
2781
|
-
const { data: erc20Balance } = useReadContract({
|
|
2782
|
-
address: token.contract,
|
|
2783
|
-
abi: erc20Abi,
|
|
2784
|
-
functionName: "balanceOf",
|
|
2785
|
-
args: address ? [address] : void 0,
|
|
2786
|
-
chainId: token.chainId,
|
|
2787
|
-
query: { enabled: !!address && !isNative }
|
|
2788
|
-
});
|
|
2789
|
-
const walletBalance = isNative ? nativeBalanceData?.value : erc20Balance;
|
|
2790
|
-
const formattedBalance = walletBalance ? formatTokenAmount(walletBalance.toString(), token.decimals) : "0.00";
|
|
2311
|
+
function WETHIcon({ className, size = 24 }) {
|
|
2791
2312
|
return /* @__PURE__ */ jsxs(
|
|
2792
|
-
"
|
|
2313
|
+
"svg",
|
|
2793
2314
|
{
|
|
2794
|
-
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
|
|
2798
|
-
|
|
2315
|
+
width: size,
|
|
2316
|
+
height: size,
|
|
2317
|
+
viewBox: "0 0 250 250",
|
|
2318
|
+
fill: "none",
|
|
2319
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
2320
|
+
className,
|
|
2799
2321
|
children: [
|
|
2800
|
-
/* @__PURE__ */ jsx(
|
|
2801
|
-
|
|
2802
|
-
|
|
2322
|
+
/* @__PURE__ */ jsx(
|
|
2323
|
+
"path",
|
|
2324
|
+
{
|
|
2325
|
+
d: "M0 125C0 55.9644 55.9644 0 125 0C194.036 0 250 55.9644 250 125C250 194.036 194.036 250 125 250C55.9644 250 0 194.036 0 125Z",
|
|
2326
|
+
fill: "#627EEA"
|
|
2327
|
+
}
|
|
2328
|
+
),
|
|
2329
|
+
/* @__PURE__ */ jsx(
|
|
2330
|
+
"path",
|
|
2331
|
+
{
|
|
2332
|
+
d: "M125.047 30.5V100.351L184.086 126.732L125.047 30.5Z",
|
|
2333
|
+
fill: "white",
|
|
2334
|
+
fillOpacity: "0.602"
|
|
2335
|
+
}
|
|
2336
|
+
),
|
|
2337
|
+
/* @__PURE__ */ jsx("path", { d: "M125.047 30.5L66 126.732L125.047 100.351V30.5Z", fill: "white" }),
|
|
2338
|
+
/* @__PURE__ */ jsx(
|
|
2339
|
+
"path",
|
|
2340
|
+
{
|
|
2341
|
+
d: "M125.047 172V219.462L184.125 137.728L125.047 172Z",
|
|
2342
|
+
fill: "white",
|
|
2343
|
+
fillOpacity: "0.602"
|
|
2344
|
+
}
|
|
2345
|
+
),
|
|
2346
|
+
/* @__PURE__ */ jsx("path", { d: "M125.047 219.462V171.992L66 137.728L125.047 219.462Z", fill: "white" }),
|
|
2347
|
+
/* @__PURE__ */ jsx(
|
|
2348
|
+
"path",
|
|
2349
|
+
{
|
|
2350
|
+
d: "M125.047 161.013L184.086 126.733L125.047 100.368V161.013Z",
|
|
2351
|
+
fill: "white",
|
|
2352
|
+
fillOpacity: "0.2"
|
|
2353
|
+
}
|
|
2354
|
+
),
|
|
2355
|
+
/* @__PURE__ */ jsx("path", { d: "M66 126.733L125.047 161.013V100.368L66 126.733Z", fill: "white", fillOpacity: "0.602" })
|
|
2803
2356
|
]
|
|
2804
2357
|
}
|
|
2805
2358
|
);
|
|
2806
2359
|
}
|
|
2807
|
-
function
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
})
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
const handleTokenSelect = (token) => {
|
|
2818
|
-
onSelect(token);
|
|
2819
|
-
onBack();
|
|
2820
|
-
};
|
|
2821
|
-
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2822
|
-
/* @__PURE__ */ jsx("div", { className: "flex items-center justify-between px-5 py-4", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
2823
|
-
/* @__PURE__ */ jsx(
|
|
2824
|
-
"button",
|
|
2360
|
+
function getTokenIcon(symbol, size) {
|
|
2361
|
+
const iconSize = size ?? 24;
|
|
2362
|
+
switch (symbol.toUpperCase()) {
|
|
2363
|
+
case "USDC":
|
|
2364
|
+
return /* @__PURE__ */ jsx(USDCIcon, { size: iconSize });
|
|
2365
|
+
case "WETH":
|
|
2366
|
+
return /* @__PURE__ */ jsx(WETHIcon, { size: iconSize });
|
|
2367
|
+
default:
|
|
2368
|
+
return /* @__PURE__ */ jsx(
|
|
2369
|
+
"div",
|
|
2825
2370
|
{
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
children:
|
|
2371
|
+
className: "bg-muted flex items-center justify-center rounded-full text-xs font-bold",
|
|
2372
|
+
style: { width: iconSize, height: iconSize },
|
|
2373
|
+
children: symbol.slice(0, 2)
|
|
2829
2374
|
}
|
|
2830
|
-
)
|
|
2831
|
-
/* @__PURE__ */ jsx("span", { className: "text-foreground text-xl leading-6 font-medium", children: "Select Token" })
|
|
2832
|
-
] }) }),
|
|
2833
|
-
/* @__PURE__ */ jsxs("div", { className: "flex min-h-0 flex-1 gap-2", children: [
|
|
2834
|
-
/* @__PURE__ */ jsxs("div", { className: "bg-muted flex flex-1 flex-col overflow-hidden rounded-[10px] p-2", children: [
|
|
2835
|
-
/* @__PURE__ */ jsx("div", { className: "px-4 pt-4 pb-2", children: /* @__PURE__ */ jsx("span", { className: "text-muted-foreground text-sm", children: "Network" }) }),
|
|
2836
|
-
/* @__PURE__ */ jsx("div", { className: "mt-1 flex-1 overflow-y-auto", children: chains.map((chain) => {
|
|
2837
|
-
const isSelected = selectedChainId === chain.id;
|
|
2838
|
-
return /* @__PURE__ */ jsxs(
|
|
2839
|
-
"button",
|
|
2840
|
-
{
|
|
2841
|
-
onClick: () => setSelectedChainId(chain.id),
|
|
2842
|
-
className: cn(
|
|
2843
|
-
"hover:bg-secondary flex w-full cursor-pointer items-center gap-2 rounded-lg px-3 py-2.5 text-left transition-colors",
|
|
2844
|
-
isSelected && "bg-secondary"
|
|
2845
|
-
),
|
|
2846
|
-
children: [
|
|
2847
|
-
/* @__PURE__ */ jsx("div", { className: "h-[18px] w-[18px] overflow-hidden rounded-full", children: getChainIcon(chain.id, 18) }),
|
|
2848
|
-
/* @__PURE__ */ jsx("span", { className: "text-foreground flex-1 text-sm", children: chain.name })
|
|
2849
|
-
]
|
|
2850
|
-
},
|
|
2851
|
-
chain.id
|
|
2852
|
-
);
|
|
2853
|
-
}) })
|
|
2854
|
-
] }),
|
|
2855
|
-
/* @__PURE__ */ jsxs("div", { className: "bg-muted flex flex-[2] flex-col overflow-hidden rounded-[10px] p-2", children: [
|
|
2856
|
-
/* @__PURE__ */ jsx("div", { className: "px-4 pt-4 pb-2", children: /* @__PURE__ */ jsx("span", { className: "text-muted-foreground text-sm", children: "Token" }) }),
|
|
2857
|
-
/* @__PURE__ */ jsx("div", { className: "mt-2 flex-1 overflow-y-auto", children: chainTokens.map((token) => /* @__PURE__ */ jsx(
|
|
2858
|
-
TokenRow,
|
|
2859
|
-
{
|
|
2860
|
-
token,
|
|
2861
|
-
isSelected: selectedTokenId === token.id,
|
|
2862
|
-
onClick: () => handleTokenSelect(token)
|
|
2863
|
-
},
|
|
2864
|
-
token.id
|
|
2865
|
-
)) })
|
|
2866
|
-
] })
|
|
2867
|
-
] })
|
|
2868
|
-
] });
|
|
2869
|
-
}
|
|
2870
|
-
function ModalBody({
|
|
2871
|
-
onViewChange,
|
|
2872
|
-
onCloseBlockedChange,
|
|
2873
|
-
showLockedFunds = true,
|
|
2874
|
-
defaultTab = "deposit",
|
|
2875
|
-
onDepositSuccess
|
|
2876
|
-
}) {
|
|
2877
|
-
const { defaultToken, tokensStatus } = usePrivanaContext();
|
|
2878
|
-
const [selectedToken, setSelectedToken] = useState(defaultToken);
|
|
2879
|
-
const [activeTab, setActiveTab] = useState(defaultTab);
|
|
2880
|
-
const [currentView, setCurrentView] = useState("main");
|
|
2881
|
-
const [isInteractionPending, setIsInteractionPending] = useState(false);
|
|
2882
|
-
useEffect(() => {
|
|
2883
|
-
if (!selectedToken && defaultToken) {
|
|
2884
|
-
setSelectedToken(defaultToken);
|
|
2885
|
-
}
|
|
2886
|
-
}, [selectedToken, defaultToken]);
|
|
2887
|
-
const handlePendingChange = (isPending) => {
|
|
2888
|
-
setIsInteractionPending(isPending);
|
|
2889
|
-
};
|
|
2890
|
-
const handleCloseBlockedChange = (isBlocked) => {
|
|
2891
|
-
onCloseBlockedChange?.(isBlocked);
|
|
2892
|
-
};
|
|
2893
|
-
const handleViewChange = (view) => {
|
|
2894
|
-
const update = () => {
|
|
2895
|
-
setCurrentView(view);
|
|
2896
|
-
onViewChange?.(view);
|
|
2897
|
-
};
|
|
2898
|
-
if (typeof document !== "undefined" && typeof document.startViewTransition === "function") {
|
|
2899
|
-
document.documentElement.dataset.privanaVtDir = view === "main" ? "back" : "forward";
|
|
2900
|
-
const transition = document.startViewTransition(update);
|
|
2901
|
-
transition.finished.then(() => {
|
|
2902
|
-
delete document.documentElement.dataset.privanaVtDir;
|
|
2903
|
-
});
|
|
2904
|
-
} else {
|
|
2905
|
-
update();
|
|
2906
|
-
}
|
|
2907
|
-
};
|
|
2908
|
-
const handleTokenSelect = (token) => {
|
|
2909
|
-
setSelectedToken(token);
|
|
2910
|
-
};
|
|
2911
|
-
if (tokensStatus === "loading" || !selectedToken) {
|
|
2912
|
-
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
|
|
2913
|
-
/* @__PURE__ */ jsx("div", { className: "bg-secondary h-25 animate-pulse rounded-[10px]" }),
|
|
2914
|
-
/* @__PURE__ */ jsx("div", { className: "bg-secondary h-11 animate-pulse rounded-[10px]" }),
|
|
2915
|
-
/* @__PURE__ */ jsx("div", { className: "bg-secondary h-50 animate-pulse rounded-[10px]" })
|
|
2916
|
-
] });
|
|
2917
|
-
}
|
|
2918
|
-
if (currentView === "locked-funds") {
|
|
2919
|
-
return /* @__PURE__ */ jsx(LockedFundsView, { onBack: () => handleViewChange("main") });
|
|
2920
|
-
}
|
|
2921
|
-
if (currentView === "balance-details") {
|
|
2922
|
-
return /* @__PURE__ */ jsx(BalanceDetailsView, { onBack: () => handleViewChange("main") });
|
|
2375
|
+
);
|
|
2923
2376
|
}
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
|
|
2377
|
+
}
|
|
2378
|
+
function getChainIcon(chainId, size) {
|
|
2379
|
+
const iconSize = size ?? 24;
|
|
2380
|
+
switch (chainId) {
|
|
2381
|
+
case 84532:
|
|
2382
|
+
return /* @__PURE__ */ jsx(BaseIcon, { size: iconSize });
|
|
2383
|
+
default:
|
|
2384
|
+
return /* @__PURE__ */ jsx(
|
|
2385
|
+
"div",
|
|
2386
|
+
{
|
|
2387
|
+
className: "bg-muted flex items-center justify-center rounded-full text-xs font-bold",
|
|
2388
|
+
style: { width: iconSize, height: iconSize },
|
|
2389
|
+
children: "?"
|
|
2390
|
+
}
|
|
2391
|
+
);
|
|
2933
2392
|
}
|
|
2934
|
-
return /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2 pb-4", children: [
|
|
2935
|
-
/* @__PURE__ */ jsx("div", { className: cn(isInteractionPending && "pointer-events-none"), children: /* @__PURE__ */ jsx(
|
|
2936
|
-
BalanceCards,
|
|
2937
|
-
{
|
|
2938
|
-
selectedToken,
|
|
2939
|
-
onLockedFundsClick: () => handleViewChange("locked-funds"),
|
|
2940
|
-
onBalanceClick: () => handleViewChange("balance-details"),
|
|
2941
|
-
showLockedFunds,
|
|
2942
|
-
disabled: isInteractionPending
|
|
2943
|
-
}
|
|
2944
|
-
) }),
|
|
2945
|
-
/* @__PURE__ */ jsx("div", { className: cn(isInteractionPending && "pointer-events-none"), children: /* @__PURE__ */ jsx(Tabs, { activeTab, onTabChange: setActiveTab, disabled: isInteractionPending }) }),
|
|
2946
|
-
/* @__PURE__ */ jsx("div", { className: "bg-muted rounded-[10px] p-5", children: activeTab === "deposit" ? /* @__PURE__ */ jsx(
|
|
2947
|
-
DepositForm,
|
|
2948
|
-
{
|
|
2949
|
-
selectedToken,
|
|
2950
|
-
onTokenSelect: () => handleViewChange("select-token"),
|
|
2951
|
-
onPendingChange: handlePendingChange,
|
|
2952
|
-
onUnsafeToCloseChange: handleCloseBlockedChange,
|
|
2953
|
-
onSuccess: onDepositSuccess
|
|
2954
|
-
}
|
|
2955
|
-
) : /* @__PURE__ */ jsx(
|
|
2956
|
-
WithdrawForm,
|
|
2957
|
-
{
|
|
2958
|
-
selectedToken,
|
|
2959
|
-
onTokenSelect: () => handleViewChange("select-token"),
|
|
2960
|
-
onPendingChange: handlePendingChange,
|
|
2961
|
-
onUnsafeToCloseChange: handleCloseBlockedChange
|
|
2962
|
-
}
|
|
2963
|
-
) })
|
|
2964
|
-
] }) });
|
|
2965
2393
|
}
|
|
2966
|
-
function
|
|
2967
|
-
|
|
2968
|
-
|
|
2969
|
-
|
|
2970
|
-
|
|
2971
|
-
|
|
2972
|
-
|
|
2973
|
-
const [currentView, setCurrentView] = useState("main");
|
|
2974
|
-
const titleId = useId();
|
|
2975
|
-
const descId = useId();
|
|
2976
|
-
const [isCloseBlocked, setIsCloseBlocked] = useState(false);
|
|
2977
|
-
const handleClose = () => {
|
|
2978
|
-
if (!isCloseBlocked) onClose();
|
|
2979
|
-
};
|
|
2980
|
-
return /* @__PURE__ */ jsx(
|
|
2981
|
-
Dialog,
|
|
2982
|
-
{
|
|
2983
|
-
open,
|
|
2984
|
-
onOpenChange: (isOpen) => {
|
|
2985
|
-
if (!isOpen) handleClose();
|
|
2986
|
-
},
|
|
2987
|
-
children: /* @__PURE__ */ jsxs(
|
|
2988
|
-
DialogContent,
|
|
2394
|
+
function TokenSelectorView({ selectedTokenId, onSelect }) {
|
|
2395
|
+
const { enabledTokens } = usePrivanaContext();
|
|
2396
|
+
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: [
|
|
2397
|
+
enabledTokens.map((token) => {
|
|
2398
|
+
const isSelected = selectedTokenId === token.id;
|
|
2399
|
+
return /* @__PURE__ */ jsxs(
|
|
2400
|
+
"button",
|
|
2989
2401
|
{
|
|
2990
|
-
"
|
|
2991
|
-
|
|
2992
|
-
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
"aria-labelledby": titleId,
|
|
2997
|
-
"aria-describedby": descId,
|
|
2402
|
+
type: "button",
|
|
2403
|
+
onClick: () => onSelect(token.id),
|
|
2404
|
+
className: cn(
|
|
2405
|
+
"hover:bg-secondary flex w-full cursor-pointer items-center gap-3 rounded-lg px-3 py-2 text-left transition-colors",
|
|
2406
|
+
isSelected && "bg-secondary"
|
|
2407
|
+
),
|
|
2998
2408
|
children: [
|
|
2999
|
-
/* @__PURE__ */ jsx(
|
|
3000
|
-
|
|
3001
|
-
{
|
|
3002
|
-
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
className: cn(
|
|
3007
|
-
"absolute top-6 right-5 z-20 flex h-6 w-6 items-center justify-center transition-colors",
|
|
3008
|
-
isCloseBlocked ? "text-muted-foreground/40 cursor-not-allowed" : "text-muted-foreground hover:text-foreground cursor-pointer"
|
|
3009
|
-
),
|
|
3010
|
-
children: /* @__PURE__ */ jsx(CloseIcon, {})
|
|
3011
|
-
}
|
|
3012
|
-
),
|
|
3013
|
-
/* @__PURE__ */ jsxs(
|
|
3014
|
-
"div",
|
|
2409
|
+
/* @__PURE__ */ jsx("div", { className: "h-6 w-6 shrink-0 overflow-hidden rounded-full", children: getTokenIcon(token.symbol, 24) }),
|
|
2410
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
2411
|
+
/* @__PURE__ */ jsx("div", { className: "text-foreground text-sm font-medium", children: token.symbol }),
|
|
2412
|
+
/* @__PURE__ */ jsx("div", { className: "text-muted-foreground text-[11px]", children: token.name })
|
|
2413
|
+
] }),
|
|
2414
|
+
isSelected && /* @__PURE__ */ jsx("div", { className: "bg-primary flex h-4 w-4 shrink-0 items-center justify-center rounded-full", children: /* @__PURE__ */ jsx(
|
|
2415
|
+
"svg",
|
|
3015
2416
|
{
|
|
3016
|
-
"
|
|
3017
|
-
"
|
|
3018
|
-
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
-
|
|
3024
|
-
|
|
3025
|
-
|
|
3026
|
-
|
|
3027
|
-
|
|
3028
|
-
|
|
3029
|
-
|
|
3030
|
-
|
|
3031
|
-
}
|
|
3032
|
-
)
|
|
3033
|
-
]
|
|
2417
|
+
width: "10",
|
|
2418
|
+
height: "10",
|
|
2419
|
+
viewBox: "0 0 10 10",
|
|
2420
|
+
fill: "none",
|
|
2421
|
+
className: "text-primary-foreground",
|
|
2422
|
+
children: /* @__PURE__ */ jsx(
|
|
2423
|
+
"path",
|
|
2424
|
+
{
|
|
2425
|
+
d: "M2 5L4 7L8 3",
|
|
2426
|
+
stroke: "currentColor",
|
|
2427
|
+
strokeWidth: "1.5",
|
|
2428
|
+
strokeLinecap: "round",
|
|
2429
|
+
strokeLinejoin: "round"
|
|
2430
|
+
}
|
|
2431
|
+
)
|
|
3034
2432
|
}
|
|
3035
|
-
)
|
|
3036
|
-
/* @__PURE__ */ jsx(
|
|
3037
|
-
"a",
|
|
3038
|
-
{
|
|
3039
|
-
"data-privana-footer": true,
|
|
3040
|
-
href: "https://privana.finance",
|
|
3041
|
-
target: "_blank",
|
|
3042
|
-
rel: "noopener noreferrer",
|
|
3043
|
-
"aria-label": "Powered by Privana"
|
|
3044
|
-
}
|
|
3045
|
-
)
|
|
2433
|
+
) })
|
|
3046
2434
|
]
|
|
3047
|
-
}
|
|
3048
|
-
|
|
3049
|
-
|
|
3050
|
-
|
|
2435
|
+
},
|
|
2436
|
+
token.id
|
|
2437
|
+
);
|
|
2438
|
+
}),
|
|
2439
|
+
enabledTokens.length === 0 && /* @__PURE__ */ jsx("p", { className: "text-muted-foreground px-3 py-6 text-center text-sm", children: "No tokens available" })
|
|
2440
|
+
] }) });
|
|
3051
2441
|
}
|
|
3052
|
-
function
|
|
3053
|
-
|
|
3054
|
-
|
|
3055
|
-
|
|
3056
|
-
|
|
2442
|
+
function CreditCardWidgetView({
|
|
2443
|
+
token,
|
|
2444
|
+
amount,
|
|
2445
|
+
allowance,
|
|
2446
|
+
onCredited,
|
|
2447
|
+
onLockSubmitted,
|
|
2448
|
+
onLockFailed
|
|
3057
2449
|
}) {
|
|
3058
|
-
|
|
3059
|
-
|
|
2450
|
+
const moonpayCurrencyCode = token?.moonpayCurrencyCode;
|
|
2451
|
+
const containerRef = useRef(null);
|
|
2452
|
+
const [widgetTheme, setWidgetTheme] = useState();
|
|
2453
|
+
useEffect(() => {
|
|
2454
|
+
if (containerRef.current) setWidgetTheme(resolveSdkTheme(containerRef.current));
|
|
2455
|
+
}, []);
|
|
2456
|
+
return /* @__PURE__ */ jsxs("div", { ref: containerRef, className: "bg-muted flex flex-col gap-6 rounded-[10px] p-5", children: [
|
|
2457
|
+
/* @__PURE__ */ jsx("h2", { className: "text-foreground text-[28px] leading-8 font-medium", children: "Complete your purchase" }),
|
|
2458
|
+
token && moonpayCurrencyCode ? /* @__PURE__ */ jsx(
|
|
2459
|
+
FiatOnRampForm,
|
|
2460
|
+
{
|
|
2461
|
+
tokenId: token.id,
|
|
2462
|
+
currencyCode: moonpayCurrencyCode,
|
|
2463
|
+
quoteCurrencyAmount: amount || void 0,
|
|
2464
|
+
lockAmount: true,
|
|
2465
|
+
variant: "embedded",
|
|
2466
|
+
autoStart: true,
|
|
2467
|
+
theme: widgetTheme,
|
|
2468
|
+
postDepositLock: allowance ? {
|
|
2469
|
+
maxAmount: BigInt(allowance.value),
|
|
2470
|
+
lockDuration: allowance.lockDuration
|
|
2471
|
+
} : void 0,
|
|
2472
|
+
onCredited,
|
|
2473
|
+
onLockSubmitted,
|
|
2474
|
+
onLockFailed
|
|
2475
|
+
}
|
|
2476
|
+
) : /* @__PURE__ */ jsxs("p", { className: "text-muted-foreground text-sm", children: [
|
|
2477
|
+
token?.symbol ?? "This token",
|
|
2478
|
+
" isn\u2019t available for card purchases yet."
|
|
2479
|
+
] })
|
|
2480
|
+
] });
|
|
2481
|
+
}
|
|
2482
|
+
function resolveSdkTheme(el) {
|
|
2483
|
+
const scheme = getComputedStyle(el).colorScheme;
|
|
2484
|
+
if (scheme === "dark") return "dark";
|
|
2485
|
+
if (scheme === "light") return "light";
|
|
2486
|
+
return el.closest(".dark") ? "dark" : "light";
|
|
2487
|
+
}
|
|
2488
|
+
function CheckIcon() {
|
|
2489
|
+
return /* @__PURE__ */ jsx("svg", { width: "14", height: "14", viewBox: "0 0 12 12", fill: "none", children: /* @__PURE__ */ jsx(
|
|
2490
|
+
"path",
|
|
3060
2491
|
{
|
|
3061
|
-
"
|
|
3062
|
-
|
|
3063
|
-
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
children: /* @__PURE__ */ jsx(
|
|
3067
|
-
ModalBody,
|
|
3068
|
-
{
|
|
3069
|
-
showLockedFunds,
|
|
3070
|
-
defaultTab,
|
|
3071
|
-
onDepositSuccess
|
|
3072
|
-
}
|
|
3073
|
-
)
|
|
2492
|
+
d: "M2.5 6l2.5 2.5 4.5-4.5",
|
|
2493
|
+
stroke: "currentColor",
|
|
2494
|
+
strokeWidth: "1.5",
|
|
2495
|
+
strokeLinecap: "round",
|
|
2496
|
+
strokeLinejoin: "round"
|
|
3074
2497
|
}
|
|
3075
|
-
);
|
|
2498
|
+
) });
|
|
3076
2499
|
}
|
|
3077
|
-
function
|
|
3078
|
-
children
|
|
3079
|
-
|
|
3080
|
-
variant = "outline",
|
|
3081
|
-
size = "default",
|
|
3082
|
-
asChild = false,
|
|
3083
|
-
renderButton,
|
|
3084
|
-
hideWhenDisconnected = true,
|
|
3085
|
-
showLockedFunds = true,
|
|
3086
|
-
defaultTab,
|
|
3087
|
-
onDepositSuccess,
|
|
3088
|
-
...buttonProps
|
|
3089
|
-
}) {
|
|
3090
|
-
const [modalOpen, setModalOpen] = useState(false);
|
|
3091
|
-
const { isConnected } = useAccount();
|
|
3092
|
-
if (hideWhenDisconnected && !isConnected) {
|
|
3093
|
-
return null;
|
|
3094
|
-
}
|
|
3095
|
-
const handleClick = () => setModalOpen(true);
|
|
3096
|
-
const buttonElement = renderButton ? renderButton({ onClick: handleClick, isOpen: modalOpen }) : /* @__PURE__ */ jsx(
|
|
3097
|
-
Button,
|
|
2500
|
+
function ExternalLinkIcon() {
|
|
2501
|
+
return /* @__PURE__ */ jsx("svg", { width: "12", height: "12", viewBox: "0 0 12 12", fill: "none", children: /* @__PURE__ */ jsx(
|
|
2502
|
+
"path",
|
|
3098
2503
|
{
|
|
3099
|
-
|
|
3100
|
-
|
|
3101
|
-
|
|
3102
|
-
|
|
3103
|
-
|
|
3104
|
-
disabled: !isConnected,
|
|
3105
|
-
...buttonProps,
|
|
3106
|
-
children: children ?? "Privana"
|
|
2504
|
+
d: "M3.5 1.5h7v7M10.5 1.5L1.5 10.5",
|
|
2505
|
+
stroke: "currentColor",
|
|
2506
|
+
strokeWidth: "1.5",
|
|
2507
|
+
strokeLinecap: "round",
|
|
2508
|
+
strokeLinejoin: "round"
|
|
3107
2509
|
}
|
|
3108
|
-
);
|
|
3109
|
-
|
|
3110
|
-
|
|
3111
|
-
|
|
3112
|
-
|
|
2510
|
+
) });
|
|
2511
|
+
}
|
|
2512
|
+
function Spinner({ size = 20 }) {
|
|
2513
|
+
return /* @__PURE__ */ jsxs("svg", { width: size, height: size, viewBox: "0 0 20 20", fill: "none", className: "animate-spin", children: [
|
|
2514
|
+
/* @__PURE__ */ jsx("circle", { cx: "10", cy: "10", r: "8", stroke: "currentColor", strokeWidth: "2", opacity: "0.15" }),
|
|
2515
|
+
/* @__PURE__ */ jsx("path", { d: "M10 2a8 8 0 016.93 4", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" })
|
|
2516
|
+
] });
|
|
2517
|
+
}
|
|
2518
|
+
function TransactionProgressView({ title, steps, onCancel }) {
|
|
2519
|
+
const completed = steps.filter((s) => s.status === "completed").length;
|
|
2520
|
+
const active = steps.find((s) => s.status === "active");
|
|
2521
|
+
const total = steps.length;
|
|
2522
|
+
const progress = (completed + (active ? 0.5 : 0)) / total * 100;
|
|
2523
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex w-full flex-col gap-4", children: [
|
|
2524
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
|
|
2525
|
+
/* @__PURE__ */ jsx("div", { className: "text-primary", children: /* @__PURE__ */ jsx(Spinner, { size: 20 }) }),
|
|
2526
|
+
/* @__PURE__ */ jsx("span", { className: "text-foreground text-sm font-medium", children: active?.label ?? title })
|
|
2527
|
+
] }),
|
|
2528
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5", children: [
|
|
2529
|
+
/* @__PURE__ */ jsx("div", { className: "bg-secondary h-1.5 w-full overflow-hidden rounded-full", children: /* @__PURE__ */ jsx(
|
|
2530
|
+
"div",
|
|
2531
|
+
{
|
|
2532
|
+
className: "bg-primary h-full rounded-full transition-all duration-500",
|
|
2533
|
+
style: { width: `${progress}%` }
|
|
2534
|
+
}
|
|
2535
|
+
) }),
|
|
2536
|
+
/* @__PURE__ */ jsxs("span", { className: "text-muted-foreground text-xs", children: [
|
|
2537
|
+
"Step ",
|
|
2538
|
+
Math.max(1, completed + (active ? 1 : 0)),
|
|
2539
|
+
" of ",
|
|
2540
|
+
total
|
|
2541
|
+
] })
|
|
2542
|
+
] }),
|
|
2543
|
+
onCancel && /* @__PURE__ */ jsx(
|
|
2544
|
+
"button",
|
|
3113
2545
|
{
|
|
3114
|
-
|
|
3115
|
-
|
|
3116
|
-
|
|
3117
|
-
defaultTab,
|
|
3118
|
-
onDepositSuccess
|
|
2546
|
+
onClick: onCancel,
|
|
2547
|
+
className: "border-border text-foreground hover:bg-secondary flex h-10 w-full cursor-pointer items-center justify-center rounded-[10px] border px-3 py-2 text-sm font-medium transition-colors",
|
|
2548
|
+
children: "Cancel"
|
|
3119
2549
|
}
|
|
3120
2550
|
)
|
|
3121
2551
|
] });
|
|
3122
2552
|
}
|
|
3123
|
-
|
|
3124
|
-
|
|
3125
|
-
|
|
3126
|
-
|
|
3127
|
-
|
|
3128
|
-
|
|
3129
|
-
|
|
3130
|
-
|
|
3131
|
-
|
|
3132
|
-
|
|
3133
|
-
|
|
3134
|
-
|
|
3135
|
-
|
|
3136
|
-
}
|
|
3137
|
-
|
|
3138
|
-
|
|
3139
|
-
|
|
3140
|
-
|
|
3141
|
-
|
|
3142
|
-
|
|
3143
|
-
|
|
3144
|
-
|
|
3145
|
-
|
|
3146
|
-
|
|
3147
|
-
|
|
3148
|
-
|
|
3149
|
-
|
|
3150
|
-
|
|
3151
|
-
|
|
3152
|
-
|
|
3153
|
-
|
|
3154
|
-
|
|
3155
|
-
|
|
3156
|
-
|
|
3157
|
-
|
|
3158
|
-
}
|
|
3159
|
-
|
|
3160
|
-
|
|
3161
|
-
|
|
3162
|
-
}
|
|
3163
|
-
function isPositiveIntegerString(value) {
|
|
3164
|
-
if (typeof value !== "string") return false;
|
|
3165
|
-
try {
|
|
3166
|
-
return BigInt(value) > 0n;
|
|
3167
|
-
} catch {
|
|
3168
|
-
return false;
|
|
3169
|
-
}
|
|
3170
|
-
}
|
|
3171
|
-
function isSessionRecord(value) {
|
|
3172
|
-
if (!value || typeof value !== "object") return false;
|
|
3173
|
-
const record = value;
|
|
3174
|
-
if (record.version !== 1 || typeof record.owner !== "string" || typeof record.serviceAddress !== "string" || !Number.isInteger(record.chainId) || (record.chainId ?? 0) <= 0 || typeof record.tokenId !== "string" || !Number.isSafeInteger(record.startBlock) || (record.startBlock ?? -1) < 0 || !isPositiveIntegerString(record.depositAmount) || !isPositiveIntegerString(record.maxLockAmount) || !Number.isInteger(record.lockDuration) || (record.lockDuration ?? 0) <= 0 || typeof record.generation !== "string" || !record.generation || record.submissionAmbiguous !== void 0 && typeof record.submissionAmbiguous !== "boolean" || record.creditedAmount !== void 0 && !isPositiveIntegerString(record.creditedAmount)) {
|
|
3175
|
-
return false;
|
|
3176
|
-
}
|
|
3177
|
-
if (record.verification && (typeof record.verification.hash !== "string" || record.verification.chainId !== record.chainId || !isPositiveIntegerString(record.verification.amount) || record.verification.logIndex !== void 0 && (!Number.isInteger(record.verification.logIndex) || record.verification.logIndex < 0))) {
|
|
3178
|
-
return false;
|
|
3179
|
-
}
|
|
3180
|
-
if (record.verification && record.creditedAmount !== void 0) return false;
|
|
3181
|
-
if (record.submissionAmbiguous && record.creditedAmount === void 0) return false;
|
|
3182
|
-
if (!record.payload) {
|
|
3183
|
-
return record.creditedAmount !== void 0 && !record.submissionAmbiguous;
|
|
3184
|
-
}
|
|
3185
|
-
if (typeof record.payload.signature !== "string" || typeof record.payload.token_id !== "string" || typeof record.payload.service_address !== "string" || record.payload.signature !== record.generation || record.payload.token_id.toLowerCase() !== record.tokenId.toLowerCase() || record.payload.service_address.toLowerCase() !== record.serviceAddress.toLowerCase() || !isPositiveIntegerString(record.payload.amount)) {
|
|
3186
|
-
return false;
|
|
3187
|
-
}
|
|
3188
|
-
return BigInt(record.payload.amount) <= BigInt(record.maxLockAmount);
|
|
2553
|
+
function TransactionSuccessView({
|
|
2554
|
+
title,
|
|
2555
|
+
message,
|
|
2556
|
+
explorerUrl,
|
|
2557
|
+
explorerLabel,
|
|
2558
|
+
onDone
|
|
2559
|
+
}) {
|
|
2560
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex w-full flex-col gap-4", children: [
|
|
2561
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
|
|
2562
|
+
/* @__PURE__ */ jsx("div", { className: "flex h-7 w-7 shrink-0 items-center justify-center rounded-full bg-emerald-500/10 text-emerald-400", children: /* @__PURE__ */ jsx(CheckIcon, {}) }),
|
|
2563
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-0.5", children: [
|
|
2564
|
+
/* @__PURE__ */ jsx("span", { className: "text-foreground text-sm font-medium", children: title }),
|
|
2565
|
+
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground text-xs", children: message })
|
|
2566
|
+
] })
|
|
2567
|
+
] }),
|
|
2568
|
+
/* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
|
|
2569
|
+
explorerUrl && /* @__PURE__ */ jsxs(
|
|
2570
|
+
"a",
|
|
2571
|
+
{
|
|
2572
|
+
href: explorerUrl,
|
|
2573
|
+
target: "_blank",
|
|
2574
|
+
rel: "noopener noreferrer",
|
|
2575
|
+
className: "border-border text-foreground hover:bg-secondary flex h-10 flex-1 items-center justify-center gap-1.5 rounded-[10px] border text-sm transition-colors",
|
|
2576
|
+
children: [
|
|
2577
|
+
explorerLabel ?? "View on Explorer",
|
|
2578
|
+
/* @__PURE__ */ jsx(ExternalLinkIcon, {})
|
|
2579
|
+
]
|
|
2580
|
+
}
|
|
2581
|
+
),
|
|
2582
|
+
/* @__PURE__ */ jsx(
|
|
2583
|
+
"button",
|
|
2584
|
+
{
|
|
2585
|
+
onClick: onDone,
|
|
2586
|
+
className: "bg-primary text-primary-foreground hover:bg-primary/90 flex h-10 flex-1 cursor-pointer items-center justify-center rounded-[10px] px-3 py-2 text-sm font-medium transition-colors",
|
|
2587
|
+
children: "Done"
|
|
2588
|
+
}
|
|
2589
|
+
)
|
|
2590
|
+
] })
|
|
2591
|
+
] });
|
|
3189
2592
|
}
|
|
3190
|
-
function
|
|
3191
|
-
|
|
3192
|
-
|
|
2593
|
+
function WarningIcon() {
|
|
2594
|
+
return /* @__PURE__ */ jsx("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", children: /* @__PURE__ */ jsx(
|
|
2595
|
+
"path",
|
|
2596
|
+
{
|
|
2597
|
+
d: "M7 5v2.5M7 10h.005M6.13 2.5h1.74L13 11.5H1L6.13 2.5z",
|
|
2598
|
+
stroke: "currentColor",
|
|
2599
|
+
strokeWidth: "1.5",
|
|
2600
|
+
strokeLinecap: "round",
|
|
2601
|
+
strokeLinejoin: "round"
|
|
2602
|
+
}
|
|
2603
|
+
) });
|
|
3193
2604
|
}
|
|
3194
|
-
function
|
|
3195
|
-
|
|
3196
|
-
|
|
3197
|
-
|
|
3198
|
-
|
|
3199
|
-
|
|
3200
|
-
|
|
3201
|
-
|
|
3202
|
-
|
|
3203
|
-
|
|
3204
|
-
|
|
3205
|
-
|
|
3206
|
-
|
|
3207
|
-
|
|
3208
|
-
|
|
3209
|
-
|
|
3210
|
-
|
|
3211
|
-
|
|
3212
|
-
|
|
3213
|
-
|
|
3214
|
-
|
|
3215
|
-
|
|
3216
|
-
|
|
3217
|
-
|
|
3218
|
-
|
|
3219
|
-
|
|
3220
|
-
const raw = getSharedBrowserStorageItem(key);
|
|
3221
|
-
const parsed = raw ? JSON.parse(raw) : void 0;
|
|
3222
|
-
if (!isSessionRecord(parsed) || parsed.owner.toLowerCase() !== owner.toLowerCase() || externalDepositSessionId(parsed.chainId, parsed.tokenId) !== id) {
|
|
3223
|
-
removeSharedBrowserStorageItem(key);
|
|
3224
|
-
removeSharedBrowserStorageItem(activeSessionKey(owner));
|
|
3225
|
-
return void 0;
|
|
3226
|
-
}
|
|
3227
|
-
return parsed;
|
|
3228
|
-
} catch {
|
|
3229
|
-
removeSharedBrowserStorageItem(key);
|
|
3230
|
-
removeSharedBrowserStorageItem(activeSessionKey(owner));
|
|
3231
|
-
return void 0;
|
|
3232
|
-
}
|
|
3233
|
-
}
|
|
3234
|
-
function subscribeExternalDepositLockSession(owner, onChange) {
|
|
3235
|
-
if (typeof window === "undefined") return () => void 0;
|
|
3236
|
-
let localStorage;
|
|
3237
|
-
try {
|
|
3238
|
-
localStorage = window.localStorage;
|
|
3239
|
-
} catch {
|
|
3240
|
-
return () => void 0;
|
|
3241
|
-
}
|
|
3242
|
-
const activeKey = activeSessionKey(owner);
|
|
3243
|
-
const ownerSessionPrefix = `${SESSION_PREFIX}${owner.toLowerCase()}:`;
|
|
3244
|
-
const handleStorage = (event) => {
|
|
3245
|
-
if (event.storageArea !== localStorage) return;
|
|
3246
|
-
if (event.key !== null && event.key !== activeKey && !event.key.startsWith(ownerSessionPrefix)) {
|
|
3247
|
-
return;
|
|
3248
|
-
}
|
|
3249
|
-
onChange(loadExternalDepositLockSession(owner));
|
|
3250
|
-
};
|
|
3251
|
-
window.addEventListener("storage", handleStorage);
|
|
3252
|
-
return () => window.removeEventListener("storage", handleStorage);
|
|
3253
|
-
}
|
|
3254
|
-
function clearExternalDepositLockSession(owner, expectedSessionId, expectedGeneration) {
|
|
3255
|
-
const id = activeSessionId(owner);
|
|
3256
|
-
if (!id || expectedSessionId && id !== expectedSessionId) return;
|
|
3257
|
-
if (expectedGeneration) {
|
|
3258
|
-
const current = loadExternalDepositLockSession(owner);
|
|
3259
|
-
if (!current || current.generation !== expectedGeneration) return;
|
|
3260
|
-
}
|
|
3261
|
-
removeSharedBrowserStorageItem(sessionKey(owner, id));
|
|
3262
|
-
removeSharedBrowserStorageItem(activeSessionKey(owner));
|
|
3263
|
-
}
|
|
3264
|
-
function isSameVerification(left, right) {
|
|
3265
|
-
if (!left || !right) return left === right;
|
|
3266
|
-
return left.hash.toLowerCase() === right.hash.toLowerCase() && left.chainId === right.chainId && left.amount === right.amount && (left.logIndex ?? 0) === (right.logIndex ?? 0);
|
|
3267
|
-
}
|
|
3268
|
-
function isSamePayload(left, right) {
|
|
3269
|
-
if (!left || !right) return left === right;
|
|
3270
|
-
return left.service_address.toLowerCase() === right.service_address.toLowerCase() && left.token_id.toLowerCase() === right.token_id.toLowerCase() && left.amount === right.amount && left.expiry === right.expiry && left.nonce === right.nonce && left.signature === right.signature;
|
|
3271
|
-
}
|
|
3272
|
-
function isSameSessionSnapshot(left, right) {
|
|
3273
|
-
return left.version === right.version && left.owner.toLowerCase() === right.owner.toLowerCase() && left.serviceAddress.toLowerCase() === right.serviceAddress.toLowerCase() && left.chainId === right.chainId && left.tokenId.toLowerCase() === right.tokenId.toLowerCase() && left.startBlock === right.startBlock && left.depositAmount === right.depositAmount && left.maxLockAmount === right.maxLockAmount && left.lockDuration === right.lockDuration && left.generation === right.generation && left.creditedAmount === right.creditedAmount && left.submissionAmbiguous === right.submissionAmbiguous && isSameVerification(left.verification, right.verification) && isSamePayload(left.payload, right.payload);
|
|
3274
|
-
}
|
|
3275
|
-
function isSameExternalDepositLockSession(left, right) {
|
|
3276
|
-
return isSameSessionSnapshot(left, right);
|
|
3277
|
-
}
|
|
3278
|
-
function clearExternalDepositVerification(session) {
|
|
3279
|
-
if (!session.verification || session.creditedAmount) return void 0;
|
|
3280
|
-
const current = loadExternalDepositLockSession(session.owner);
|
|
3281
|
-
if (!current || current.generation !== session.generation || current.creditedAmount || !isSameVerification(current.verification, session.verification)) {
|
|
3282
|
-
return void 0;
|
|
3283
|
-
}
|
|
3284
|
-
const next = { ...current, verification: void 0 };
|
|
3285
|
-
if (!writeSessionRecord(next)) {
|
|
3286
|
-
throw new Error("Unable to clear failed deposit verification");
|
|
3287
|
-
}
|
|
3288
|
-
return next;
|
|
3289
|
-
}
|
|
3290
|
-
function discardExternalDepositLockSession(session) {
|
|
3291
|
-
const current = loadExternalDepositLockSession(session.owner);
|
|
3292
|
-
if (!current) return true;
|
|
3293
|
-
if (!isSameSessionSnapshot(current, session)) return false;
|
|
3294
|
-
clearExternalDepositLockSession(
|
|
3295
|
-
current.owner,
|
|
3296
|
-
externalDepositSessionId(current.chainId, current.tokenId),
|
|
3297
|
-
current.generation
|
|
3298
|
-
);
|
|
3299
|
-
return loadExternalDepositLockSession(current.owner) === void 0;
|
|
3300
|
-
}
|
|
3301
|
-
function clearSubmittedPayload(session, signature, clearAmbiguous = false) {
|
|
3302
|
-
const current = loadExternalDepositLockSession(session.owner);
|
|
3303
|
-
if (!current?.payload || current.payload.signature !== signature || current.submissionAmbiguous && !clearAmbiguous) {
|
|
3304
|
-
return false;
|
|
3305
|
-
}
|
|
3306
|
-
return writeSessionRecord({ ...current, submissionAmbiguous: void 0, payload: void 0 });
|
|
3307
|
-
}
|
|
3308
|
-
function markSubmissionAmbiguous(session, signature) {
|
|
3309
|
-
const current = loadExternalDepositLockSession(session.owner);
|
|
3310
|
-
if (!current?.payload || current.payload.signature !== signature) return false;
|
|
3311
|
-
if (current.submissionAmbiguous) return true;
|
|
3312
|
-
return writeSessionRecord({ ...current, submissionAmbiguous: true });
|
|
3313
|
-
}
|
|
3314
|
-
function ambiguousSubmissionError(error) {
|
|
3315
|
-
return new PostDepositLockError(
|
|
3316
|
-
"Lock submission could not be confirmed. Retry only the saved signature, or check locked funds before stopping recovery.",
|
|
3317
|
-
error.reason,
|
|
3318
|
-
error.signedAmount,
|
|
3319
|
-
error.creditedAmount,
|
|
3320
|
-
{
|
|
3321
|
-
cause: error.cause,
|
|
3322
|
-
submissionMayHaveSucceeded: true
|
|
3323
|
-
}
|
|
3324
|
-
);
|
|
3325
|
-
}
|
|
3326
|
-
function isDefinitiveSubmissionFailure(error) {
|
|
3327
|
-
const cause = error.cause;
|
|
3328
|
-
return cause instanceof AccountingApiError && cause.statusCode !== 408 && cause.statusCode < 500;
|
|
3329
|
-
}
|
|
3330
|
-
function submissionLockName(session) {
|
|
3331
|
-
return `privana:external-deposit-lock:submit:${session.owner.toLowerCase()}:${externalDepositSessionId(session.chainId, session.tokenId)}`;
|
|
3332
|
-
}
|
|
3333
|
-
async function withSubmissionLock(session, task) {
|
|
3334
|
-
const locks = typeof navigator === "undefined" ? void 0 : navigator.locks;
|
|
3335
|
-
if (!locks) return task(false);
|
|
3336
|
-
return locks.request(submissionLockName(session), () => task(true));
|
|
3337
|
-
}
|
|
3338
|
-
function externalDepositRetryAmount(session) {
|
|
3339
|
-
if (!session.creditedAmount) throw new Error("No credited external deposit to recover");
|
|
3340
|
-
const creditedAmount = BigInt(session.creditedAmount);
|
|
3341
|
-
const maxLockAmount = BigInt(session.maxLockAmount);
|
|
3342
|
-
return creditedAmount < maxLockAmount ? creditedAmount : maxLockAmount;
|
|
3343
|
-
}
|
|
3344
|
-
async function submitExternalDepositLock(client, session) {
|
|
3345
|
-
return withSubmissionLock(session, async (crossTabExclusive) => {
|
|
3346
|
-
const current = loadExternalDepositLockSession(session.owner);
|
|
3347
|
-
if (!current || current.generation !== session.generation) {
|
|
3348
|
-
throw new PostDepositLockError(
|
|
3349
|
-
"External deposit lock session changed before submission",
|
|
3350
|
-
"not-found",
|
|
3351
|
-
BigInt(session.maxLockAmount),
|
|
3352
|
-
session.creditedAmount ? BigInt(session.creditedAmount) : void 0
|
|
3353
|
-
);
|
|
3354
|
-
}
|
|
3355
|
-
const result = await submitExternalDepositLockAttempt(client, current, crossTabExclusive);
|
|
3356
|
-
clearExternalDepositLockSession(
|
|
3357
|
-
current.owner,
|
|
3358
|
-
externalDepositSessionId(current.chainId, current.tokenId),
|
|
3359
|
-
current.generation
|
|
3360
|
-
);
|
|
3361
|
-
return result;
|
|
3362
|
-
});
|
|
3363
|
-
}
|
|
3364
|
-
async function submitExternalDepositLockAttempt(client, session, crossTabExclusive) {
|
|
3365
|
-
const creditedAmount = session.creditedAmount ? BigInt(session.creditedAmount) : void 0;
|
|
3366
|
-
if (!creditedAmount) {
|
|
3367
|
-
throw new PostDepositLockError(
|
|
3368
|
-
"External deposit has not been credited",
|
|
3369
|
-
"submission-failed",
|
|
3370
|
-
BigInt(session.maxLockAmount)
|
|
3371
|
-
);
|
|
3372
|
-
}
|
|
3373
|
-
const payload = session.payload;
|
|
3374
|
-
if (!payload) {
|
|
3375
|
-
throw new PostDepositLockError(
|
|
3376
|
-
"No persisted signed policy found for this deposit session",
|
|
3377
|
-
"not-found",
|
|
3378
|
-
BigInt(session.maxLockAmount),
|
|
3379
|
-
creditedAmount
|
|
3380
|
-
);
|
|
3381
|
-
}
|
|
3382
|
-
try {
|
|
3383
|
-
return await submitPendingLock({
|
|
3384
|
-
client,
|
|
3385
|
-
payload,
|
|
3386
|
-
creditedAmount,
|
|
3387
|
-
beforeSubmit: () => {
|
|
3388
|
-
if (!markSubmissionAmbiguous(session, payload.signature)) {
|
|
3389
|
-
throw new Error("Unable to persist lock submission recovery state");
|
|
3390
|
-
}
|
|
3391
|
-
}
|
|
3392
|
-
});
|
|
3393
|
-
} catch (err) {
|
|
3394
|
-
if (err instanceof PostDepositLockError && err.reason === "submission-failed" && crossTabExclusive && !session.submissionAmbiguous && isDefinitiveSubmissionFailure(err)) {
|
|
3395
|
-
if (!clearSubmittedPayload(session, payload.signature, true)) {
|
|
3396
|
-
const latest = loadExternalDepositLockSession(session.owner);
|
|
3397
|
-
if (latest?.submissionAmbiguous) throw ambiguousSubmissionError(err);
|
|
3398
|
-
}
|
|
3399
|
-
} else if (err instanceof PostDepositLockError && err.reason === "submission-failed") {
|
|
3400
|
-
const ambiguous = markSubmissionAmbiguous(session, payload.signature) || loadExternalDepositLockSession(session.owner)?.submissionAmbiguous === true;
|
|
3401
|
-
if (ambiguous) throw ambiguousSubmissionError(err);
|
|
3402
|
-
} else {
|
|
3403
|
-
const current = loadExternalDepositLockSession(session.owner);
|
|
3404
|
-
if (session.submissionAmbiguous || current?.submissionAmbiguous) {
|
|
3405
|
-
if (err instanceof PostDepositLockError) throw ambiguousSubmissionError(err);
|
|
3406
|
-
throw err;
|
|
3407
|
-
}
|
|
3408
|
-
if (!clearSubmittedPayload(session, payload.signature)) {
|
|
3409
|
-
const latest = loadExternalDepositLockSession(session.owner);
|
|
3410
|
-
if (latest?.submissionAmbiguous && err instanceof PostDepositLockError) {
|
|
3411
|
-
throw ambiguousSubmissionError(err);
|
|
3412
|
-
}
|
|
3413
|
-
}
|
|
3414
|
-
}
|
|
3415
|
-
throw err;
|
|
3416
|
-
}
|
|
3417
|
-
}
|
|
3418
|
-
function useExternalDepositLock({
|
|
3419
|
-
allowance,
|
|
3420
|
-
onLockSubmitted,
|
|
3421
|
-
onLockFailed
|
|
3422
|
-
}) {
|
|
3423
|
-
const { client, networkConfig, serviceAddress, getTokenById, tokensStatus } = usePrivanaContext();
|
|
3424
|
-
const config = useConfig();
|
|
3425
|
-
const queryClient = useQueryClient();
|
|
3426
|
-
const { address } = useAccount();
|
|
3427
|
-
const { privateReadAddress } = usePrivateReadRequest();
|
|
3428
|
-
const { ensureCorrectChain } = useEnsureCorrectChain();
|
|
3429
|
-
const [isSigning, setIsSigning] = useState(false);
|
|
3430
|
-
const [isSubmittingLock, setIsSubmittingLock] = useState(false);
|
|
3431
|
-
const [session, setSession] = useState(null);
|
|
3432
|
-
const sessionRef = useRef(null);
|
|
3433
|
-
const signingRef = useRef(false);
|
|
3434
|
-
const settlingRef = useRef(false);
|
|
3435
|
-
const pendingCreditedTransitionRef = useRef(null);
|
|
3436
|
-
const hydratedScopeRef = useRef(null);
|
|
3437
|
-
const beneficiaryRef = useRef(privateReadAddress);
|
|
3438
|
-
beneficiaryRef.current = privateReadAddress;
|
|
3439
|
-
const onLockSubmittedRef = useRef(onLockSubmitted);
|
|
3440
|
-
const onLockFailedRef = useRef(onLockFailed);
|
|
3441
|
-
useEffect(() => {
|
|
3442
|
-
onLockSubmittedRef.current = onLockSubmitted;
|
|
3443
|
-
onLockFailedRef.current = onLockFailed;
|
|
3444
|
-
}, [onLockSubmitted, onLockFailed]);
|
|
3445
|
-
const installSession = useCallback((next) => {
|
|
3446
|
-
sessionRef.current = next;
|
|
3447
|
-
setSession(next);
|
|
3448
|
-
}, []);
|
|
3449
|
-
const preserveCreditedFallback = useCallback(
|
|
3450
|
-
(durable) => {
|
|
3451
|
-
const pending = pendingCreditedTransitionRef.current;
|
|
3452
|
-
if (pending && durable && isSameExternalDepositLockSession(durable, pending.predecessor)) {
|
|
3453
|
-
return pending.credited;
|
|
3454
|
-
}
|
|
3455
|
-
pendingCreditedTransitionRef.current = null;
|
|
3456
|
-
return durable;
|
|
3457
|
-
},
|
|
3458
|
-
[]
|
|
3459
|
-
);
|
|
3460
|
-
const notifyFailure = useCallback((error) => {
|
|
3461
|
-
onLockFailedRef.current?.(error);
|
|
3462
|
-
}, []);
|
|
3463
|
-
const submitSession = useCallback(
|
|
3464
|
-
async (active) => {
|
|
3465
|
-
if (settlingRef.current) return;
|
|
3466
|
-
settlingRef.current = true;
|
|
3467
|
-
setIsSubmittingLock(true);
|
|
3468
|
-
let result;
|
|
3469
|
-
try {
|
|
3470
|
-
let submission = active;
|
|
3471
|
-
const storedBeforeSubmit = loadExternalDepositLockSession(active.owner);
|
|
3472
|
-
if (storedBeforeSubmit?.generation === active.generation) {
|
|
3473
|
-
if (active.creditedAmount && !storedBeforeSubmit.creditedAmount) {
|
|
3474
|
-
const pending = pendingCreditedTransitionRef.current;
|
|
3475
|
-
if (!pending || !isSameExternalDepositLockSession(active, pending.credited) || !isSameExternalDepositLockSession(storedBeforeSubmit, pending.predecessor)) {
|
|
3476
|
-
throw new ExternalDepositLockSessionChangedError();
|
|
3477
|
-
}
|
|
3478
|
-
saveExternalDepositLockSession(pending.credited, pending.predecessor);
|
|
3479
|
-
pendingCreditedTransitionRef.current = null;
|
|
3480
|
-
submission = pending.credited;
|
|
3481
|
-
} else {
|
|
3482
|
-
submission = storedBeforeSubmit;
|
|
3483
|
-
}
|
|
3484
|
-
}
|
|
3485
|
-
result = await submitExternalDepositLock(client, submission);
|
|
3486
|
-
} catch (err) {
|
|
3487
|
-
const stored = loadExternalDepositLockSession(active.owner);
|
|
3488
|
-
const error = err instanceof PostDepositLockError ? err : new PostDepositLockError(
|
|
3489
|
-
err instanceof Error ? err.message : "Lock submission failed",
|
|
3490
|
-
"submission-failed",
|
|
3491
|
-
BigInt(active.maxLockAmount),
|
|
3492
|
-
active.creditedAmount ? BigInt(active.creditedAmount) : void 0,
|
|
3493
|
-
{ cause: err }
|
|
3494
|
-
);
|
|
3495
|
-
if (err instanceof ExternalDepositLockSessionChangedError) {
|
|
3496
|
-
pendingCreditedTransitionRef.current = null;
|
|
3497
|
-
installSession(stored ?? null);
|
|
3498
|
-
return;
|
|
3499
|
-
}
|
|
3500
|
-
if (!stored || stored.generation !== active.generation) {
|
|
3501
|
-
pendingCreditedTransitionRef.current = null;
|
|
3502
|
-
installSession(stored ?? null);
|
|
3503
|
-
return;
|
|
3504
|
-
}
|
|
3505
|
-
if (active.creditedAmount && !stored.creditedAmount) {
|
|
3506
|
-
const pending = pendingCreditedTransitionRef.current;
|
|
3507
|
-
if (pending && isSameExternalDepositLockSession(active, pending.credited) && isSameExternalDepositLockSession(stored, pending.predecessor)) {
|
|
3508
|
-
installSession(pending.credited);
|
|
3509
|
-
notifyFailure(error);
|
|
3510
|
-
return;
|
|
3511
|
-
}
|
|
3512
|
-
pendingCreditedTransitionRef.current = null;
|
|
3513
|
-
installSession(stored);
|
|
3514
|
-
return;
|
|
3515
|
-
}
|
|
3516
|
-
installSession(active.creditedAmount && !stored.creditedAmount ? active : stored);
|
|
3517
|
-
notifyFailure(error);
|
|
3518
|
-
return;
|
|
3519
|
-
} finally {
|
|
3520
|
-
settlingRef.current = false;
|
|
3521
|
-
setIsSubmittingLock(false);
|
|
3522
|
-
}
|
|
3523
|
-
installSession(loadExternalDepositLockSession(active.owner) ?? null);
|
|
3524
|
-
queryClient.invalidateQueries({ queryKey: ["accounting-balance"] });
|
|
3525
|
-
queryClient.invalidateQueries({ queryKey: ["accounting-locked-funds"] });
|
|
3526
|
-
queryClient.invalidateQueries({ queryKey: ["accounting-total-locked-balance"] });
|
|
3527
|
-
queryClient.invalidateQueries({ queryKey: ["accounting-history"] });
|
|
3528
|
-
onLockSubmittedRef.current?.(result);
|
|
3529
|
-
},
|
|
3530
|
-
[client, installSession, notifyFailure, queryClient]
|
|
3531
|
-
);
|
|
3532
|
-
const validateRestoredSession = useCallback(
|
|
3533
|
-
(restored) => {
|
|
3534
|
-
if (!restored || !serviceAddress) return null;
|
|
3535
|
-
const token = getTokenById(restored.tokenId);
|
|
3536
|
-
const invalid = restored.serviceAddress.toLowerCase() !== serviceAddress.toLowerCase() || !token || token.chainId !== restored.chainId || token.contract === zeroAddress || !restored.creditedAmount && !restored.payload;
|
|
3537
|
-
if (!invalid) return restored;
|
|
3538
|
-
clearExternalDepositLockSession(
|
|
3539
|
-
restored.owner,
|
|
3540
|
-
externalDepositSessionId(restored.chainId, restored.tokenId),
|
|
3541
|
-
restored.generation
|
|
3542
|
-
);
|
|
3543
|
-
return null;
|
|
3544
|
-
},
|
|
3545
|
-
[getTokenById, serviceAddress]
|
|
3546
|
-
);
|
|
3547
|
-
useEffect(() => {
|
|
3548
|
-
if (!privateReadAddress || !serviceAddress || tokensStatus !== "ready") {
|
|
3549
|
-
setSession(null);
|
|
3550
|
-
return;
|
|
3551
|
-
}
|
|
3552
|
-
const hydrationKey = `${privateReadAddress.toLowerCase()}:${serviceAddress.toLowerCase()}`;
|
|
3553
|
-
const shouldResume = hydratedScopeRef.current !== hydrationKey;
|
|
3554
|
-
hydratedScopeRef.current = hydrationKey;
|
|
3555
|
-
const restored = preserveCreditedFallback(
|
|
3556
|
-
validateRestoredSession(loadExternalDepositLockSession(privateReadAddress))
|
|
3557
|
-
);
|
|
3558
|
-
installSession(restored);
|
|
3559
|
-
if (!restored) {
|
|
3560
|
-
return;
|
|
3561
|
-
}
|
|
3562
|
-
if (!shouldResume) return;
|
|
3563
|
-
if (restored.creditedAmount && restored.payload) {
|
|
3564
|
-
void submitSession(restored);
|
|
3565
|
-
} else if (restored.creditedAmount) {
|
|
3566
|
-
notifyFailure(
|
|
3567
|
-
new PostDepositLockError(
|
|
3568
|
-
"Deposit credited; sign a fresh policy to lock the funds",
|
|
3569
|
-
"not-found",
|
|
3570
|
-
BigInt(restored.maxLockAmount),
|
|
3571
|
-
BigInt(restored.creditedAmount)
|
|
3572
|
-
)
|
|
3573
|
-
);
|
|
3574
|
-
}
|
|
3575
|
-
}, [
|
|
3576
|
-
installSession,
|
|
3577
|
-
notifyFailure,
|
|
3578
|
-
privateReadAddress,
|
|
3579
|
-
preserveCreditedFallback,
|
|
3580
|
-
serviceAddress,
|
|
3581
|
-
submitSession,
|
|
3582
|
-
tokensStatus,
|
|
3583
|
-
validateRestoredSession
|
|
3584
|
-
]);
|
|
3585
|
-
useEffect(() => {
|
|
3586
|
-
if (!privateReadAddress || !serviceAddress || tokensStatus !== "ready") return;
|
|
3587
|
-
const reconcile = (restored) => {
|
|
3588
|
-
installSession(preserveCreditedFallback(validateRestoredSession(restored)));
|
|
3589
|
-
};
|
|
3590
|
-
const unsubscribe = subscribeExternalDepositLockSession(privateReadAddress, reconcile);
|
|
3591
|
-
reconcile(loadExternalDepositLockSession(privateReadAddress));
|
|
3592
|
-
return unsubscribe;
|
|
3593
|
-
}, [
|
|
3594
|
-
installSession,
|
|
3595
|
-
preserveCreditedFallback,
|
|
3596
|
-
privateReadAddress,
|
|
3597
|
-
serviceAddress,
|
|
3598
|
-
tokensStatus,
|
|
3599
|
-
validateRestoredSession
|
|
3600
|
-
]);
|
|
3601
|
-
const signAndPersist = useCallback(
|
|
3602
|
-
async ({ tokenId, amount }) => {
|
|
3603
|
-
if (!allowance) throw new Error("No allowance configured for this deposit");
|
|
3604
|
-
if (signingRef.current || settlingRef.current) {
|
|
3605
|
-
throw new Error("A policy operation is already in progress");
|
|
3606
|
-
}
|
|
3607
|
-
if (!canUseSharedBrowserStorage()) {
|
|
3608
|
-
throw new Error("Browser storage is required for locked deposit recovery");
|
|
3609
|
-
}
|
|
3610
|
-
const owner = requireDepositLockOwner(address, privateReadAddress);
|
|
3611
|
-
if (sessionRef.current || loadExternalDepositLockSession(owner)) {
|
|
3612
|
-
throw new Error("Finish or cancel the active external deposit before starting another");
|
|
3613
|
-
}
|
|
3614
|
-
const token = getTokenById(tokenId);
|
|
3615
|
-
if (!token) throw new Error(`Unknown token ID: ${tokenId}`);
|
|
3616
|
-
if (token.contract === zeroAddress) {
|
|
3617
|
-
throw new Error("External deposits support ERC20 tokens only");
|
|
3618
|
-
}
|
|
3619
|
-
const targetService = requireServiceAddress(serviceAddress);
|
|
3620
|
-
const lockDuration = allowance.lockDuration ?? DEFAULT_LOCK_DURATION_SECONDS;
|
|
3621
|
-
signingRef.current = true;
|
|
3622
|
-
setIsSigning(true);
|
|
3623
|
-
try {
|
|
3624
|
-
await ensureCorrectChain(networkConfig.chainId);
|
|
3625
|
-
const signingWalletClient = await getWalletClient(config, {
|
|
3626
|
-
chainId: networkConfig.chainId
|
|
3627
|
-
});
|
|
3628
|
-
const payload = await createSignedLockRequest({
|
|
3629
|
-
client,
|
|
3630
|
-
walletClient: signingWalletClient,
|
|
3631
|
-
userAddress: owner,
|
|
3632
|
-
networkConfig,
|
|
3633
|
-
serviceAddress: targetService,
|
|
3634
|
-
tokenId: token.id,
|
|
3635
|
-
amount: clampLockAmount(amount, BigInt(allowance.value)),
|
|
3636
|
-
lockDuration
|
|
3637
|
-
});
|
|
3638
|
-
const startBlock = await getBlockNumber(config, { chainId: token.chainId });
|
|
3639
|
-
if (startBlock > BigInt(Number.MAX_SAFE_INTEGER)) {
|
|
3640
|
-
throw new Error("Source-chain block number exceeds the supported range");
|
|
3641
|
-
}
|
|
3642
|
-
if (beneficiaryRef.current?.toLowerCase() !== owner.toLowerCase()) {
|
|
3643
|
-
throw new Error("Authenticated deposit account changed while signing");
|
|
3644
|
-
}
|
|
3645
|
-
const next = {
|
|
3646
|
-
version: 1,
|
|
3647
|
-
owner,
|
|
3648
|
-
serviceAddress: targetService,
|
|
3649
|
-
chainId: token.chainId,
|
|
3650
|
-
tokenId: token.id,
|
|
3651
|
-
startBlock: Number(startBlock),
|
|
3652
|
-
depositAmount: amount.toString(),
|
|
3653
|
-
maxLockAmount: String(payload.amount),
|
|
3654
|
-
lockDuration,
|
|
3655
|
-
generation: payload.signature,
|
|
3656
|
-
payload
|
|
3657
|
-
};
|
|
3658
|
-
saveExternalDepositLockSession(next, null);
|
|
3659
|
-
installSession(next);
|
|
3660
|
-
} finally {
|
|
3661
|
-
signingRef.current = false;
|
|
3662
|
-
setIsSigning(false);
|
|
3663
|
-
}
|
|
3664
|
-
},
|
|
3665
|
-
[
|
|
3666
|
-
address,
|
|
3667
|
-
allowance,
|
|
3668
|
-
client,
|
|
3669
|
-
config,
|
|
3670
|
-
ensureCorrectChain,
|
|
3671
|
-
getTokenById,
|
|
3672
|
-
installSession,
|
|
3673
|
-
networkConfig,
|
|
3674
|
-
privateReadAddress,
|
|
3675
|
-
serviceAddress
|
|
3676
|
-
]
|
|
3677
|
-
);
|
|
3678
|
-
const settleAfterCredit = useCallback(
|
|
3679
|
-
async (txHash, creditedAmount) => {
|
|
3680
|
-
const active = sessionRef.current;
|
|
3681
|
-
if (!active || settlingRef.current) return;
|
|
3682
|
-
if (!isCurrentExternalDepositVerification(active, txHash)) {
|
|
3683
|
-
return;
|
|
3684
|
-
}
|
|
3685
|
-
if (creditedAmount <= 0n) throw new Error("Credited amount must be positive");
|
|
3686
|
-
const credited = {
|
|
3687
|
-
...active,
|
|
3688
|
-
verification: void 0,
|
|
3689
|
-
creditedAmount: creditedAmount.toString()
|
|
3690
|
-
};
|
|
3691
|
-
try {
|
|
3692
|
-
saveExternalDepositLockSession(credited, active);
|
|
3693
|
-
pendingCreditedTransitionRef.current = null;
|
|
3694
|
-
} catch (err) {
|
|
3695
|
-
const stored = loadExternalDepositLockSession(active.owner);
|
|
3696
|
-
if (err instanceof ExternalDepositLockSessionChangedError || !stored || !isSameExternalDepositLockSession(stored, active)) {
|
|
3697
|
-
pendingCreditedTransitionRef.current = null;
|
|
3698
|
-
installSession(stored ?? null);
|
|
3699
|
-
return;
|
|
3700
|
-
}
|
|
3701
|
-
pendingCreditedTransitionRef.current = { predecessor: active, credited };
|
|
3702
|
-
installSession(credited);
|
|
3703
|
-
notifyFailure(
|
|
3704
|
-
new PostDepositLockError(
|
|
3705
|
-
err instanceof Error ? err.message : "Unable to persist credited deposit state",
|
|
3706
|
-
"submission-failed",
|
|
3707
|
-
BigInt(active.maxLockAmount),
|
|
3708
|
-
creditedAmount,
|
|
3709
|
-
{ cause: err }
|
|
3710
|
-
)
|
|
3711
|
-
);
|
|
3712
|
-
return;
|
|
3713
|
-
}
|
|
3714
|
-
installSession(credited);
|
|
3715
|
-
await submitSession(credited);
|
|
3716
|
-
},
|
|
3717
|
-
[installSession, notifyFailure, submitSession]
|
|
3718
|
-
);
|
|
3719
|
-
const recordVerification = useCallback(
|
|
3720
|
-
(context) => {
|
|
3721
|
-
const active = sessionRef.current;
|
|
3722
|
-
if (!active || active.creditedAmount) {
|
|
3723
|
-
throw new Error("No external deposit session is awaiting verification");
|
|
3724
|
-
}
|
|
3725
|
-
if (active.verification) {
|
|
3726
|
-
const sameTransfer = active.verification.hash.toLowerCase() === context.hash.toLowerCase() && active.verification.chainId === context.chainId && active.verification.amount === context.amount.toString() && (active.verification.logIndex ?? 0) === (context.logIndex ?? 0);
|
|
3727
|
-
if (sameTransfer) return;
|
|
3728
|
-
throw new Error("Another transfer is already being verified for this deposit session");
|
|
3729
|
-
}
|
|
3730
|
-
if (context.chainId !== active.chainId || context.amount <= 0n) {
|
|
3731
|
-
throw new Error("Discovered transfer does not match the signed deposit session");
|
|
3732
|
-
}
|
|
3733
|
-
const current = loadExternalDepositLockSession(active.owner);
|
|
3734
|
-
if (!current || current.generation !== active.generation) {
|
|
3735
|
-
throw new Error("The signed deposit session changed before verification");
|
|
3736
|
-
}
|
|
3737
|
-
const next = {
|
|
3738
|
-
...active,
|
|
3739
|
-
verification: {
|
|
3740
|
-
hash: context.hash,
|
|
3741
|
-
chainId: context.chainId,
|
|
3742
|
-
amount: context.amount.toString(),
|
|
3743
|
-
logIndex: context.logIndex
|
|
2605
|
+
function TransactionWarningView({
|
|
2606
|
+
title,
|
|
2607
|
+
message,
|
|
2608
|
+
onDone,
|
|
2609
|
+
actionLabel = "Done",
|
|
2610
|
+
pendingLabel = actionLabel,
|
|
2611
|
+
isPending = false,
|
|
2612
|
+
onDismiss,
|
|
2613
|
+
dismissLabel = "Dismiss"
|
|
2614
|
+
}) {
|
|
2615
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex w-full flex-col gap-4", children: [
|
|
2616
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
|
|
2617
|
+
/* @__PURE__ */ jsx("div", { className: "flex h-7 w-7 shrink-0 items-center justify-center rounded-full bg-amber-500/10 text-amber-400", children: /* @__PURE__ */ jsx(WarningIcon, {}) }),
|
|
2618
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-0.5", children: [
|
|
2619
|
+
/* @__PURE__ */ jsx("span", { className: "text-foreground text-sm font-medium", children: title }),
|
|
2620
|
+
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground text-xs", children: message })
|
|
2621
|
+
] })
|
|
2622
|
+
] }),
|
|
2623
|
+
/* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
|
|
2624
|
+
onDismiss && /* @__PURE__ */ jsx(
|
|
2625
|
+
"button",
|
|
2626
|
+
{
|
|
2627
|
+
onClick: onDismiss,
|
|
2628
|
+
disabled: isPending,
|
|
2629
|
+
className: "border-border text-foreground hover:bg-secondary flex h-10 flex-1 cursor-pointer items-center justify-center rounded-[10px] border px-3 py-2 text-sm font-medium transition-colors disabled:cursor-not-allowed disabled:opacity-50",
|
|
2630
|
+
children: dismissLabel
|
|
3744
2631
|
}
|
|
3745
|
-
|
|
3746
|
-
|
|
3747
|
-
|
|
3748
|
-
|
|
3749
|
-
|
|
3750
|
-
|
|
3751
|
-
|
|
3752
|
-
|
|
3753
|
-
|
|
3754
|
-
|
|
3755
|
-
|
|
3756
|
-
|
|
3757
|
-
if (privateReadAddress?.toLowerCase() !== active.owner.toLowerCase()) {
|
|
3758
|
-
throw new Error("Authenticated deposit account does not match the credited deposit");
|
|
3759
|
-
}
|
|
3760
|
-
const token = getTokenById(active.tokenId);
|
|
3761
|
-
if (!token || token.chainId !== active.chainId || token.contract === zeroAddress) {
|
|
3762
|
-
throw new Error("The credited token is no longer available");
|
|
3763
|
-
}
|
|
3764
|
-
const targetService = requireServiceAddress(serviceAddress);
|
|
3765
|
-
if (targetService.toLowerCase() !== active.serviceAddress.toLowerCase()) {
|
|
3766
|
-
throw new Error("The service for this credited deposit has changed");
|
|
3767
|
-
}
|
|
3768
|
-
if (active.payload) {
|
|
3769
|
-
await submitSession(active);
|
|
3770
|
-
return;
|
|
3771
|
-
}
|
|
3772
|
-
if (active.submissionAmbiguous) {
|
|
3773
|
-
throw new Error(
|
|
3774
|
-
"The previous lock submission may have succeeded; a fresh signature is unsafe"
|
|
3775
|
-
);
|
|
3776
|
-
}
|
|
3777
|
-
const owner = requireDepositLockOwner(address, privateReadAddress);
|
|
3778
|
-
const amount = externalDepositRetryAmount(active);
|
|
3779
|
-
let retrySession;
|
|
3780
|
-
signingRef.current = true;
|
|
3781
|
-
setIsSigning(true);
|
|
3782
|
-
try {
|
|
3783
|
-
await ensureCorrectChain(networkConfig.chainId);
|
|
3784
|
-
const signingWalletClient = await getWalletClient(config, {
|
|
3785
|
-
chainId: networkConfig.chainId
|
|
3786
|
-
});
|
|
3787
|
-
const payload = await createSignedLockRequest({
|
|
3788
|
-
client,
|
|
3789
|
-
walletClient: signingWalletClient,
|
|
3790
|
-
userAddress: owner,
|
|
3791
|
-
networkConfig,
|
|
3792
|
-
serviceAddress: targetService,
|
|
3793
|
-
tokenId: active.tokenId,
|
|
3794
|
-
amount,
|
|
3795
|
-
lockDuration: active.lockDuration
|
|
3796
|
-
});
|
|
3797
|
-
if (beneficiaryRef.current?.toLowerCase() !== owner.toLowerCase()) {
|
|
3798
|
-
throw new Error("Authenticated deposit account changed while signing");
|
|
3799
|
-
}
|
|
3800
|
-
retrySession = {
|
|
3801
|
-
...active,
|
|
3802
|
-
depositAmount: amount.toString(),
|
|
3803
|
-
generation: payload.signature,
|
|
3804
|
-
verification: void 0,
|
|
3805
|
-
submissionAmbiguous: void 0,
|
|
3806
|
-
payload
|
|
3807
|
-
};
|
|
3808
|
-
saveExternalDepositLockSession(retrySession, active);
|
|
3809
|
-
installSession(retrySession);
|
|
3810
|
-
} finally {
|
|
3811
|
-
signingRef.current = false;
|
|
3812
|
-
setIsSigning(false);
|
|
3813
|
-
}
|
|
3814
|
-
await submitSession(retrySession);
|
|
3815
|
-
}, [
|
|
3816
|
-
address,
|
|
3817
|
-
client,
|
|
3818
|
-
config,
|
|
3819
|
-
ensureCorrectChain,
|
|
3820
|
-
getTokenById,
|
|
3821
|
-
installSession,
|
|
3822
|
-
networkConfig,
|
|
3823
|
-
privateReadAddress,
|
|
3824
|
-
serviceAddress,
|
|
3825
|
-
submitSession
|
|
3826
|
-
]);
|
|
3827
|
-
const clearVerification = useCallback(() => {
|
|
3828
|
-
const active = sessionRef.current;
|
|
3829
|
-
if (!active?.verification || active.creditedAmount) return false;
|
|
3830
|
-
const next = clearExternalDepositVerification(active);
|
|
3831
|
-
if (!next) {
|
|
3832
|
-
installSession(loadExternalDepositLockSession(active.owner) ?? null);
|
|
3833
|
-
return false;
|
|
3834
|
-
}
|
|
3835
|
-
installSession(next);
|
|
3836
|
-
return true;
|
|
3837
|
-
}, [installSession]);
|
|
3838
|
-
const discardSession = useCallback(() => {
|
|
3839
|
-
const active = sessionRef.current;
|
|
3840
|
-
if (!active) return true;
|
|
3841
|
-
if (signingRef.current || settlingRef.current) return false;
|
|
3842
|
-
const pending = pendingCreditedTransitionRef.current;
|
|
3843
|
-
const discardTarget = pending && isSameExternalDepositLockSession(active, pending.credited) ? pending.predecessor : active;
|
|
3844
|
-
const discarded = discardExternalDepositLockSession(discardTarget);
|
|
3845
|
-
const restored = loadExternalDepositLockSession(active.owner) ?? null;
|
|
3846
|
-
if (discarded) pendingCreditedTransitionRef.current = null;
|
|
3847
|
-
installSession(restored);
|
|
3848
|
-
return discarded && !restored;
|
|
3849
|
-
}, [installSession]);
|
|
3850
|
-
return {
|
|
3851
|
-
isSigning,
|
|
3852
|
-
isSubmittingLock,
|
|
3853
|
-
session,
|
|
3854
|
-
signAndPersist,
|
|
3855
|
-
recordVerification,
|
|
3856
|
-
settleAfterCredit,
|
|
3857
|
-
retryAfterCredit,
|
|
3858
|
-
clearVerification,
|
|
3859
|
-
discardSession
|
|
3860
|
-
};
|
|
2632
|
+
),
|
|
2633
|
+
/* @__PURE__ */ jsx(
|
|
2634
|
+
"button",
|
|
2635
|
+
{
|
|
2636
|
+
onClick: onDone,
|
|
2637
|
+
disabled: isPending,
|
|
2638
|
+
className: "bg-primary text-primary-foreground hover:bg-primary/90 flex h-10 flex-1 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",
|
|
2639
|
+
children: isPending ? pendingLabel : actionLabel
|
|
2640
|
+
}
|
|
2641
|
+
)
|
|
2642
|
+
] })
|
|
2643
|
+
] });
|
|
3861
2644
|
}
|
|
3862
|
-
|
|
3863
|
-
|
|
3864
|
-
|
|
3865
|
-
|
|
3866
|
-
|
|
3867
|
-
|
|
3868
|
-
|
|
2645
|
+
function TransactionErrorView({
|
|
2646
|
+
title,
|
|
2647
|
+
message,
|
|
2648
|
+
explorerUrl,
|
|
2649
|
+
explorerLabel,
|
|
2650
|
+
onRetry,
|
|
2651
|
+
onDismiss,
|
|
2652
|
+
isRetrying,
|
|
2653
|
+
retryLabel = "Retry Verification",
|
|
2654
|
+
dismissLabel = "Close"
|
|
3869
2655
|
}) {
|
|
3870
|
-
|
|
3871
|
-
|
|
3872
|
-
|
|
3873
|
-
|
|
3874
|
-
|
|
3875
|
-
|
|
3876
|
-
|
|
3877
|
-
|
|
3878
|
-
|
|
3879
|
-
|
|
3880
|
-
|
|
3881
|
-
|
|
3882
|
-
|
|
3883
|
-
|
|
3884
|
-
|
|
3885
|
-
|
|
3886
|
-
|
|
3887
|
-
|
|
2656
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex w-full flex-col gap-4", children: [
|
|
2657
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
|
|
2658
|
+
/* @__PURE__ */ jsx("div", { className: "flex h-7 w-7 shrink-0 items-center justify-center rounded-full bg-amber-500/10 text-amber-400", children: /* @__PURE__ */ jsx(WarningIcon, {}) }),
|
|
2659
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-0.5", children: [
|
|
2660
|
+
/* @__PURE__ */ jsx("span", { className: "text-foreground text-sm font-medium", children: title }),
|
|
2661
|
+
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground text-xs", children: message })
|
|
2662
|
+
] })
|
|
2663
|
+
] }),
|
|
2664
|
+
explorerUrl && /* @__PURE__ */ jsxs(
|
|
2665
|
+
"a",
|
|
2666
|
+
{
|
|
2667
|
+
href: explorerUrl,
|
|
2668
|
+
target: "_blank",
|
|
2669
|
+
rel: "noopener noreferrer",
|
|
2670
|
+
className: "border-border text-foreground hover:bg-secondary flex h-10 w-full items-center justify-center gap-1.5 rounded-[10px] border text-sm transition-colors",
|
|
2671
|
+
children: [
|
|
2672
|
+
explorerLabel ?? "View on Explorer",
|
|
2673
|
+
/* @__PURE__ */ jsx(ExternalLinkIcon, {})
|
|
2674
|
+
]
|
|
3888
2675
|
}
|
|
3889
|
-
|
|
3890
|
-
|
|
3891
|
-
|
|
3892
|
-
minBuyAmount: asNumber(data.baseCurrency?.minBuyAmount),
|
|
3893
|
-
maxBuyAmount: asNumber(data.baseCurrency?.maxBuyAmount)
|
|
3894
|
-
};
|
|
3895
|
-
}
|
|
3896
|
-
});
|
|
3897
|
-
return {
|
|
3898
|
-
minBuyAmount: query.data?.minBuyAmount,
|
|
3899
|
-
maxBuyAmount: query.data?.maxBuyAmount,
|
|
3900
|
-
isLoading: query.isLoading,
|
|
3901
|
-
error: query.error ?? null
|
|
3902
|
-
};
|
|
3903
|
-
}
|
|
3904
|
-
function TokenSelectorView2({ selectedTokenId, onSelect }) {
|
|
3905
|
-
const { enabledTokens } = usePrivanaContext();
|
|
3906
|
-
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: [
|
|
3907
|
-
enabledTokens.map((token) => {
|
|
3908
|
-
const isSelected = selectedTokenId === token.id;
|
|
3909
|
-
return /* @__PURE__ */ jsxs(
|
|
2676
|
+
),
|
|
2677
|
+
/* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
|
|
2678
|
+
onDismiss && /* @__PURE__ */ jsx(
|
|
3910
2679
|
"button",
|
|
3911
2680
|
{
|
|
3912
|
-
|
|
3913
|
-
|
|
3914
|
-
className:
|
|
3915
|
-
|
|
3916
|
-
|
|
3917
|
-
|
|
3918
|
-
|
|
3919
|
-
|
|
3920
|
-
|
|
3921
|
-
|
|
3922
|
-
|
|
3923
|
-
|
|
3924
|
-
|
|
3925
|
-
|
|
3926
|
-
|
|
3927
|
-
|
|
3928
|
-
|
|
3929
|
-
viewBox: "0 0 10 10",
|
|
3930
|
-
fill: "none",
|
|
3931
|
-
className: "text-primary-foreground",
|
|
3932
|
-
children: /* @__PURE__ */ jsx(
|
|
3933
|
-
"path",
|
|
3934
|
-
{
|
|
3935
|
-
d: "M2 5L4 7L8 3",
|
|
3936
|
-
stroke: "currentColor",
|
|
3937
|
-
strokeWidth: "1.5",
|
|
3938
|
-
strokeLinecap: "round",
|
|
3939
|
-
strokeLinejoin: "round"
|
|
3940
|
-
}
|
|
3941
|
-
)
|
|
3942
|
-
}
|
|
3943
|
-
) })
|
|
3944
|
-
]
|
|
3945
|
-
},
|
|
3946
|
-
token.id
|
|
3947
|
-
);
|
|
3948
|
-
}),
|
|
3949
|
-
enabledTokens.length === 0 && /* @__PURE__ */ jsx("p", { className: "text-muted-foreground px-3 py-6 text-center text-sm", children: "No tokens available" })
|
|
3950
|
-
] }) });
|
|
2681
|
+
onClick: onDismiss,
|
|
2682
|
+
disabled: isRetrying,
|
|
2683
|
+
className: "border-border text-foreground hover:bg-secondary flex h-10 flex-1 cursor-pointer items-center justify-center rounded-[10px] border px-3 py-2 text-sm font-medium transition-colors disabled:cursor-not-allowed disabled:opacity-50",
|
|
2684
|
+
children: dismissLabel
|
|
2685
|
+
}
|
|
2686
|
+
),
|
|
2687
|
+
/* @__PURE__ */ jsx(
|
|
2688
|
+
"button",
|
|
2689
|
+
{
|
|
2690
|
+
onClick: onRetry,
|
|
2691
|
+
disabled: isRetrying,
|
|
2692
|
+
className: "bg-primary text-primary-foreground hover:bg-primary/90 flex h-10 flex-1 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",
|
|
2693
|
+
children: isRetrying ? "Retrying\u2026" : retryLabel
|
|
2694
|
+
}
|
|
2695
|
+
)
|
|
2696
|
+
] })
|
|
2697
|
+
] });
|
|
3951
2698
|
}
|
|
3952
|
-
function
|
|
3953
|
-
|
|
3954
|
-
|
|
3955
|
-
|
|
3956
|
-
|
|
3957
|
-
|
|
3958
|
-
|
|
2699
|
+
function CloseIcon() {
|
|
2700
|
+
return /* @__PURE__ */ jsx("svg", { width: "10", height: "10", viewBox: "0 0 12 12", fill: "none", children: /* @__PURE__ */ jsx(
|
|
2701
|
+
"path",
|
|
2702
|
+
{
|
|
2703
|
+
d: "M11.99997 11.99997l-5.99995-5.99995-6.00002-6.00002m6.00002 6.00002l6.00001-6.00002m-12.00003 12.00003l6.00002-6.00001",
|
|
2704
|
+
stroke: "currentColor",
|
|
2705
|
+
strokeWidth: "1.5",
|
|
2706
|
+
strokeLinecap: "round",
|
|
2707
|
+
strokeLinejoin: "round"
|
|
2708
|
+
}
|
|
2709
|
+
) });
|
|
2710
|
+
}
|
|
2711
|
+
function ChevronRightIcon() {
|
|
2712
|
+
return /* @__PURE__ */ jsx("svg", { width: "10", height: "5", viewBox: "0 0 12 6", className: "-rotate-90", children: /* @__PURE__ */ jsx(
|
|
2713
|
+
"path",
|
|
2714
|
+
{
|
|
2715
|
+
d: "M0 0l6 6 6-6",
|
|
2716
|
+
stroke: "currentColor",
|
|
2717
|
+
strokeWidth: "1.5",
|
|
2718
|
+
strokeLinecap: "round",
|
|
2719
|
+
strokeLinejoin: "round",
|
|
2720
|
+
fill: "none"
|
|
2721
|
+
}
|
|
2722
|
+
) });
|
|
2723
|
+
}
|
|
2724
|
+
function ChevronLeftIcon() {
|
|
2725
|
+
return /* @__PURE__ */ jsx("svg", { width: "10", height: "5", viewBox: "0 0 12 6", className: "rotate-90", children: /* @__PURE__ */ jsx(
|
|
2726
|
+
"path",
|
|
2727
|
+
{
|
|
2728
|
+
d: "M0 0l6 6 6-6",
|
|
2729
|
+
stroke: "currentColor",
|
|
2730
|
+
strokeWidth: "1.5",
|
|
2731
|
+
strokeLinecap: "round",
|
|
2732
|
+
strokeLinejoin: "round",
|
|
2733
|
+
fill: "none"
|
|
2734
|
+
}
|
|
2735
|
+
) });
|
|
2736
|
+
}
|
|
2737
|
+
function ChevronDownIcon({
|
|
2738
|
+
direction = "down",
|
|
2739
|
+
className
|
|
3959
2740
|
}) {
|
|
3960
|
-
|
|
3961
|
-
|
|
3962
|
-
|
|
3963
|
-
|
|
3964
|
-
|
|
3965
|
-
|
|
3966
|
-
|
|
3967
|
-
|
|
3968
|
-
|
|
3969
|
-
|
|
2741
|
+
return /* @__PURE__ */ jsx(
|
|
2742
|
+
"svg",
|
|
2743
|
+
{
|
|
2744
|
+
width: "16",
|
|
2745
|
+
height: "16",
|
|
2746
|
+
viewBox: "0 0 16 16",
|
|
2747
|
+
fill: "none",
|
|
2748
|
+
className: cn(
|
|
2749
|
+
"transition-transform",
|
|
2750
|
+
direction === "right" && "-rotate-90",
|
|
2751
|
+
direction === "up" && "rotate-180",
|
|
2752
|
+
className
|
|
2753
|
+
),
|
|
2754
|
+
children: /* @__PURE__ */ jsx(
|
|
2755
|
+
"path",
|
|
2756
|
+
{
|
|
2757
|
+
d: "M4 6l4 4 4-4",
|
|
2758
|
+
stroke: "currentColor",
|
|
2759
|
+
strokeWidth: "1.5",
|
|
2760
|
+
strokeLinecap: "round",
|
|
2761
|
+
strokeLinejoin: "round"
|
|
2762
|
+
}
|
|
2763
|
+
)
|
|
2764
|
+
}
|
|
2765
|
+
);
|
|
2766
|
+
}
|
|
2767
|
+
function CopyIcon() {
|
|
2768
|
+
return /* @__PURE__ */ jsxs(
|
|
2769
|
+
"svg",
|
|
2770
|
+
{
|
|
2771
|
+
width: "16",
|
|
2772
|
+
height: "16",
|
|
2773
|
+
viewBox: "0 0 24 24",
|
|
2774
|
+
fill: "none",
|
|
2775
|
+
stroke: "currentColor",
|
|
2776
|
+
strokeWidth: "2",
|
|
2777
|
+
strokeLinecap: "round",
|
|
2778
|
+
strokeLinejoin: "round",
|
|
2779
|
+
children: [
|
|
2780
|
+
/* @__PURE__ */ jsx("rect", { x: "9", y: "9", width: "13", height: "13", rx: "2", ry: "2" }),
|
|
2781
|
+
/* @__PURE__ */ jsx("path", { d: "M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" })
|
|
2782
|
+
]
|
|
2783
|
+
}
|
|
2784
|
+
);
|
|
2785
|
+
}
|
|
2786
|
+
function CircleCheckIcon() {
|
|
2787
|
+
return /* @__PURE__ */ jsxs("svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", children: [
|
|
2788
|
+
/* @__PURE__ */ jsx("circle", { cx: "10", cy: "10", r: "9", stroke: "currentColor", strokeWidth: "1.5" }),
|
|
2789
|
+
/* @__PURE__ */ jsx(
|
|
2790
|
+
"path",
|
|
2791
|
+
{
|
|
2792
|
+
d: "M6 10l2.5 2.5L14 7.5",
|
|
2793
|
+
stroke: "currentColor",
|
|
2794
|
+
strokeWidth: "1.5",
|
|
2795
|
+
strokeLinecap: "round",
|
|
2796
|
+
strokeLinejoin: "round"
|
|
2797
|
+
}
|
|
2798
|
+
)
|
|
2799
|
+
] });
|
|
2800
|
+
}
|
|
2801
|
+
function CircleXIcon() {
|
|
2802
|
+
return /* @__PURE__ */ jsxs("svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", children: [
|
|
2803
|
+
/* @__PURE__ */ jsx("circle", { cx: "10", cy: "10", r: "9", stroke: "currentColor", strokeWidth: "1.5" }),
|
|
2804
|
+
/* @__PURE__ */ jsx(
|
|
2805
|
+
"path",
|
|
3970
2806
|
{
|
|
3971
|
-
|
|
3972
|
-
|
|
3973
|
-
|
|
3974
|
-
|
|
3975
|
-
|
|
3976
|
-
autoStart: true,
|
|
3977
|
-
theme: widgetTheme,
|
|
3978
|
-
postDepositLock: allowance ? {
|
|
3979
|
-
maxAmount: BigInt(allowance.value),
|
|
3980
|
-
lockDuration: allowance.lockDuration
|
|
3981
|
-
} : void 0,
|
|
3982
|
-
onCredited,
|
|
3983
|
-
onLockSubmitted,
|
|
3984
|
-
onLockFailed
|
|
2807
|
+
d: "M7 7l6 6M13 7l-6 6",
|
|
2808
|
+
stroke: "currentColor",
|
|
2809
|
+
strokeWidth: "1.5",
|
|
2810
|
+
strokeLinecap: "round",
|
|
2811
|
+
strokeLinejoin: "round"
|
|
3985
2812
|
}
|
|
3986
|
-
)
|
|
3987
|
-
token?.symbol ?? "This token",
|
|
3988
|
-
" isn\u2019t available for card purchases yet."
|
|
3989
|
-
] })
|
|
2813
|
+
)
|
|
3990
2814
|
] });
|
|
3991
2815
|
}
|
|
3992
|
-
function
|
|
3993
|
-
|
|
3994
|
-
|
|
3995
|
-
|
|
3996
|
-
|
|
2816
|
+
function ArrowRightIcon({ className }) {
|
|
2817
|
+
return /* @__PURE__ */ jsx("svg", { width: "24", height: "8", viewBox: "0 0 24 8", fill: "none", className, children: /* @__PURE__ */ jsx(
|
|
2818
|
+
"path",
|
|
2819
|
+
{
|
|
2820
|
+
d: "M0 4h22m0 0l-4-4m4 4l-4 4",
|
|
2821
|
+
stroke: "currentColor",
|
|
2822
|
+
strokeWidth: "1.5",
|
|
2823
|
+
strokeLinecap: "round",
|
|
2824
|
+
strokeLinejoin: "round"
|
|
2825
|
+
}
|
|
2826
|
+
) });
|
|
2827
|
+
}
|
|
2828
|
+
var DEFAULT_MOONPAY_API_URL = "https://api.moonpay.com/v3";
|
|
2829
|
+
function useMoonpayLimits({
|
|
2830
|
+
currencyCode,
|
|
2831
|
+
baseCurrencyCode = "usd",
|
|
2832
|
+
paymentMethod = "credit_debit_card",
|
|
2833
|
+
apiBaseUrl = DEFAULT_MOONPAY_API_URL,
|
|
2834
|
+
enabled = true
|
|
2835
|
+
}) {
|
|
2836
|
+
const { apiKey } = useContext(MoonPayContext) ?? {};
|
|
2837
|
+
const canFetch = enabled && !!apiKey && !!currencyCode;
|
|
2838
|
+
const query = useQuery({
|
|
2839
|
+
queryKey: ["moonpay-limits", apiBaseUrl, currencyCode, baseCurrencyCode, paymentMethod, apiKey],
|
|
2840
|
+
enabled: canFetch,
|
|
2841
|
+
staleTime: 5 * 6e4,
|
|
2842
|
+
queryFn: async () => {
|
|
2843
|
+
const params = new URLSearchParams({
|
|
2844
|
+
apiKey,
|
|
2845
|
+
baseCurrencyCode,
|
|
2846
|
+
paymentMethod,
|
|
2847
|
+
areFeesIncluded: "true"
|
|
2848
|
+
});
|
|
2849
|
+
const res = await fetch(
|
|
2850
|
+
`${apiBaseUrl}/currencies/${currencyCode}/limits?${params.toString()}`
|
|
2851
|
+
);
|
|
2852
|
+
if (!res.ok) {
|
|
2853
|
+
throw new Error(`MoonPay limits request failed: ${res.status}`);
|
|
2854
|
+
}
|
|
2855
|
+
const data = await res.json();
|
|
2856
|
+
const asNumber = (value) => typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
2857
|
+
return {
|
|
2858
|
+
minBuyAmount: asNumber(data.baseCurrency?.minBuyAmount),
|
|
2859
|
+
maxBuyAmount: asNumber(data.baseCurrency?.maxBuyAmount)
|
|
2860
|
+
};
|
|
2861
|
+
}
|
|
2862
|
+
});
|
|
2863
|
+
return {
|
|
2864
|
+
minBuyAmount: query.data?.minBuyAmount,
|
|
2865
|
+
maxBuyAmount: query.data?.maxBuyAmount,
|
|
2866
|
+
isLoading: query.isLoading,
|
|
2867
|
+
error: query.error ?? null
|
|
2868
|
+
};
|
|
3997
2869
|
}
|
|
3998
2870
|
function PrivanaIcon({ className, size = 32 }) {
|
|
3999
2871
|
return /* @__PURE__ */ jsxs(
|
|
@@ -4087,81 +2959,6 @@ function AllowancePolicySection({
|
|
|
4087
2959
|
] })
|
|
4088
2960
|
] });
|
|
4089
2961
|
}
|
|
4090
|
-
function MoonPayGate({ enabled, children }) {
|
|
4091
|
-
const { networkConfig } = usePrivanaContext();
|
|
4092
|
-
const apiKey = networkConfig.moonpayApiKey;
|
|
4093
|
-
if (!enabled || !apiKey) return /* @__PURE__ */ jsx(Fragment, { children });
|
|
4094
|
-
return /* @__PURE__ */ jsx(MoonPayProvider, { apiKey, children });
|
|
4095
|
-
}
|
|
4096
|
-
function formatPostDepositLockFailure(error, token) {
|
|
4097
|
-
if (error?.reason === "credited-below-signed" && error.creditedAmount !== void 0 && error.signedAmount !== void 0 && token) {
|
|
4098
|
-
const creditedAmount = `${formatUnits(error.creditedAmount, token.decimals)} ${token.symbol}`;
|
|
4099
|
-
const signedAmount = `${formatUnits(error.signedAmount, token.decimals)} ${token.symbol}`;
|
|
4100
|
-
return `Credited amount (${creditedAmount}) is below the signed lock amount (${signedAmount})`;
|
|
4101
|
-
}
|
|
4102
|
-
return error?.message ?? "Lock submission failed";
|
|
4103
|
-
}
|
|
4104
|
-
function MethodTabs({
|
|
4105
|
-
activeTab,
|
|
4106
|
-
onTabChange
|
|
4107
|
-
}) {
|
|
4108
|
-
return /* @__PURE__ */ jsxs("div", { className: "bg-secondary relative flex gap-2 overflow-hidden rounded-[10px] p-1", children: [
|
|
4109
|
-
/* @__PURE__ */ jsx(
|
|
4110
|
-
"div",
|
|
4111
|
-
{
|
|
4112
|
-
className: cn(
|
|
4113
|
-
"bg-input absolute top-1 bottom-1 left-1 w-[calc(50%-8px)] rounded-md transition-transform duration-200",
|
|
4114
|
-
activeTab === "credit-card" && "translate-x-[calc(100%+8px)]"
|
|
4115
|
-
)
|
|
4116
|
-
}
|
|
4117
|
-
),
|
|
4118
|
-
/* @__PURE__ */ jsx(
|
|
4119
|
-
"button",
|
|
4120
|
-
{
|
|
4121
|
-
type: "button",
|
|
4122
|
-
onClick: () => onTabChange("crypto"),
|
|
4123
|
-
className: cn(
|
|
4124
|
-
"relative z-10 flex-1 cursor-pointer rounded-md px-3 py-[9px] text-sm font-medium transition-colors",
|
|
4125
|
-
activeTab === "crypto" ? "text-foreground" : "text-muted-foreground"
|
|
4126
|
-
),
|
|
4127
|
-
children: "Crypto"
|
|
4128
|
-
}
|
|
4129
|
-
),
|
|
4130
|
-
/* @__PURE__ */ jsx(
|
|
4131
|
-
"button",
|
|
4132
|
-
{
|
|
4133
|
-
type: "button",
|
|
4134
|
-
onClick: () => onTabChange("credit-card"),
|
|
4135
|
-
className: cn(
|
|
4136
|
-
"relative z-10 flex-1 cursor-pointer rounded-md px-3 py-[9px] text-sm font-medium transition-colors",
|
|
4137
|
-
activeTab === "credit-card" ? "text-foreground" : "text-muted-foreground"
|
|
4138
|
-
),
|
|
4139
|
-
children: "Credit Card"
|
|
4140
|
-
}
|
|
4141
|
-
)
|
|
4142
|
-
] });
|
|
4143
|
-
}
|
|
4144
|
-
function MethodOption({
|
|
4145
|
-
title,
|
|
4146
|
-
description,
|
|
4147
|
-
onClick
|
|
4148
|
-
}) {
|
|
4149
|
-
return /* @__PURE__ */ jsxs(
|
|
4150
|
-
"button",
|
|
4151
|
-
{
|
|
4152
|
-
type: "button",
|
|
4153
|
-
onClick,
|
|
4154
|
-
className: "bg-input hover:bg-input/70 border-border flex w-full cursor-pointer items-center gap-3 rounded-lg border p-3 text-left transition-colors",
|
|
4155
|
-
children: [
|
|
4156
|
-
/* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-1 flex-col gap-1", children: [
|
|
4157
|
-
/* @__PURE__ */ jsx("span", { className: "text-foreground text-sm leading-[14px] font-medium", children: title }),
|
|
4158
|
-
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground text-xs leading-3", children: description })
|
|
4159
|
-
] }),
|
|
4160
|
-
/* @__PURE__ */ jsx("div", { className: "text-muted-foreground flex h-5 w-5 items-center justify-center", children: /* @__PURE__ */ jsx(ChevronRightIcon, {}) })
|
|
4161
|
-
]
|
|
4162
|
-
}
|
|
4163
|
-
);
|
|
4164
|
-
}
|
|
4165
2962
|
function DepositView({
|
|
4166
2963
|
source,
|
|
4167
2964
|
selectedToken,
|
|
@@ -4672,6 +3469,81 @@ function ExternalDepositView({
|
|
|
4672
3469
|
] })
|
|
4673
3470
|
] });
|
|
4674
3471
|
}
|
|
3472
|
+
function MoonPayGate({ enabled, children }) {
|
|
3473
|
+
const { networkConfig } = usePrivanaContext();
|
|
3474
|
+
const apiKey = networkConfig.moonpayApiKey;
|
|
3475
|
+
if (!enabled || !apiKey) return /* @__PURE__ */ jsx(Fragment, { children });
|
|
3476
|
+
return /* @__PURE__ */ jsx(MoonPayProvider, { apiKey, children });
|
|
3477
|
+
}
|
|
3478
|
+
function formatPostDepositLockFailure(error, token) {
|
|
3479
|
+
if (error?.reason === "credited-below-signed" && error.creditedAmount !== void 0 && error.signedAmount !== void 0 && token) {
|
|
3480
|
+
const creditedAmount = `${formatUnits(error.creditedAmount, token.decimals)} ${token.symbol}`;
|
|
3481
|
+
const signedAmount = `${formatUnits(error.signedAmount, token.decimals)} ${token.symbol}`;
|
|
3482
|
+
return `Credited amount (${creditedAmount}) is below the signed lock amount (${signedAmount})`;
|
|
3483
|
+
}
|
|
3484
|
+
return error?.message ?? "Lock submission failed";
|
|
3485
|
+
}
|
|
3486
|
+
function MethodTabs({
|
|
3487
|
+
activeTab,
|
|
3488
|
+
onTabChange
|
|
3489
|
+
}) {
|
|
3490
|
+
return /* @__PURE__ */ jsxs("div", { className: "bg-secondary relative flex gap-2 overflow-hidden rounded-[10px] p-1", children: [
|
|
3491
|
+
/* @__PURE__ */ jsx(
|
|
3492
|
+
"div",
|
|
3493
|
+
{
|
|
3494
|
+
className: cn(
|
|
3495
|
+
"bg-input absolute top-1 bottom-1 left-1 w-[calc(50%-8px)] rounded-md transition-transform duration-200",
|
|
3496
|
+
activeTab === "credit-card" && "translate-x-[calc(100%+8px)]"
|
|
3497
|
+
)
|
|
3498
|
+
}
|
|
3499
|
+
),
|
|
3500
|
+
/* @__PURE__ */ jsx(
|
|
3501
|
+
"button",
|
|
3502
|
+
{
|
|
3503
|
+
type: "button",
|
|
3504
|
+
onClick: () => onTabChange("crypto"),
|
|
3505
|
+
className: cn(
|
|
3506
|
+
"relative z-10 flex-1 cursor-pointer rounded-md px-3 py-[9px] text-sm font-medium transition-colors",
|
|
3507
|
+
activeTab === "crypto" ? "text-foreground" : "text-muted-foreground"
|
|
3508
|
+
),
|
|
3509
|
+
children: "Crypto"
|
|
3510
|
+
}
|
|
3511
|
+
),
|
|
3512
|
+
/* @__PURE__ */ jsx(
|
|
3513
|
+
"button",
|
|
3514
|
+
{
|
|
3515
|
+
type: "button",
|
|
3516
|
+
onClick: () => onTabChange("credit-card"),
|
|
3517
|
+
className: cn(
|
|
3518
|
+
"relative z-10 flex-1 cursor-pointer rounded-md px-3 py-[9px] text-sm font-medium transition-colors",
|
|
3519
|
+
activeTab === "credit-card" ? "text-foreground" : "text-muted-foreground"
|
|
3520
|
+
),
|
|
3521
|
+
children: "Credit Card"
|
|
3522
|
+
}
|
|
3523
|
+
)
|
|
3524
|
+
] });
|
|
3525
|
+
}
|
|
3526
|
+
function MethodOption({
|
|
3527
|
+
title,
|
|
3528
|
+
description,
|
|
3529
|
+
onClick
|
|
3530
|
+
}) {
|
|
3531
|
+
return /* @__PURE__ */ jsxs(
|
|
3532
|
+
"button",
|
|
3533
|
+
{
|
|
3534
|
+
type: "button",
|
|
3535
|
+
onClick,
|
|
3536
|
+
className: "bg-input hover:bg-input/70 border-border flex w-full cursor-pointer items-center gap-3 rounded-lg border p-3 text-left transition-colors",
|
|
3537
|
+
children: [
|
|
3538
|
+
/* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-1 flex-col gap-1", children: [
|
|
3539
|
+
/* @__PURE__ */ jsx("span", { className: "text-foreground text-sm leading-[14px] font-medium", children: title }),
|
|
3540
|
+
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground text-xs leading-3", children: description })
|
|
3541
|
+
] }),
|
|
3542
|
+
/* @__PURE__ */ jsx("div", { className: "text-muted-foreground flex h-5 w-5 items-center justify-center", children: /* @__PURE__ */ jsx(ChevronRightIcon, {}) })
|
|
3543
|
+
]
|
|
3544
|
+
}
|
|
3545
|
+
);
|
|
3546
|
+
}
|
|
4675
3547
|
function DepositModalContent({
|
|
4676
3548
|
defaultTab = "crypto",
|
|
4677
3549
|
allowance,
|
|
@@ -5091,7 +3963,7 @@ function DepositModalContent({
|
|
|
5091
3963
|
}
|
|
5092
3964
|
) }),
|
|
5093
3965
|
activeView === "select-token" && /* @__PURE__ */ jsx(
|
|
5094
|
-
|
|
3966
|
+
TokenSelectorView,
|
|
5095
3967
|
{
|
|
5096
3968
|
selectedTokenId: selectedToken?.id,
|
|
5097
3969
|
onSelect: (id) => {
|
|
@@ -5186,7 +4058,8 @@ function WithdrawView({
|
|
|
5186
4058
|
amount,
|
|
5187
4059
|
onAmountChange,
|
|
5188
4060
|
onSelectToken,
|
|
5189
|
-
onPendingChange
|
|
4061
|
+
onPendingChange,
|
|
4062
|
+
onWithdrawSuccess
|
|
5190
4063
|
}) {
|
|
5191
4064
|
const { chains, getChainById: getChainById2 } = usePrivanaContext();
|
|
5192
4065
|
const { isConnected, address } = useAccount();
|
|
@@ -5206,7 +4079,12 @@ function WithdrawView({
|
|
|
5206
4079
|
const { withdraw, isPending, currentStep, error, reset } = useWithdraw({
|
|
5207
4080
|
onProcessingSuccess: () => {
|
|
5208
4081
|
onAmountChange("");
|
|
5209
|
-
|
|
4082
|
+
if (onWithdrawSuccess) {
|
|
4083
|
+
reset();
|
|
4084
|
+
onWithdrawSuccess();
|
|
4085
|
+
} else {
|
|
4086
|
+
setShowSuccess(true);
|
|
4087
|
+
}
|
|
5210
4088
|
},
|
|
5211
4089
|
onProcessingTimeout: () => {
|
|
5212
4090
|
onAmountChange("");
|
|
@@ -5379,7 +4257,8 @@ function WithdrawView({
|
|
|
5379
4257
|
function WithdrawModalContent({
|
|
5380
4258
|
onClose,
|
|
5381
4259
|
onPendingChange,
|
|
5382
|
-
onBack
|
|
4260
|
+
onBack,
|
|
4261
|
+
onWithdrawSuccess
|
|
5383
4262
|
}) {
|
|
5384
4263
|
const { serviceName, enabledTokens, defaultToken, hostedAuthConfig } = usePrivanaContext();
|
|
5385
4264
|
const { address } = useAccount();
|
|
@@ -5445,11 +4324,12 @@ function WithdrawModalContent({
|
|
|
5445
4324
|
amount,
|
|
5446
4325
|
onAmountChange: setAmount,
|
|
5447
4326
|
onSelectToken: () => setView("select-token"),
|
|
5448
|
-
onPendingChange: handlePendingChange
|
|
4327
|
+
onPendingChange: handlePendingChange,
|
|
4328
|
+
onWithdrawSuccess
|
|
5449
4329
|
}
|
|
5450
4330
|
),
|
|
5451
4331
|
view === "select-token" && /* @__PURE__ */ jsx(
|
|
5452
|
-
|
|
4332
|
+
TokenSelectorView,
|
|
5453
4333
|
{
|
|
5454
4334
|
selectedTokenId: selectedToken?.id,
|
|
5455
4335
|
onSelect: (id) => {
|
|
@@ -5460,7 +4340,7 @@ function WithdrawModalContent({
|
|
|
5460
4340
|
)
|
|
5461
4341
|
] });
|
|
5462
4342
|
}
|
|
5463
|
-
function WithdrawModal({ open, onClose }) {
|
|
4343
|
+
function WithdrawModal({ open, onClose, onWithdrawSuccess }) {
|
|
5464
4344
|
const titleId = useId();
|
|
5465
4345
|
const descId = useId();
|
|
5466
4346
|
const [isCloseBlocked, setIsCloseBlocked] = useState(false);
|
|
@@ -5487,14 +4367,21 @@ function WithdrawModal({ open, onClose }) {
|
|
|
5487
4367
|
children: [
|
|
5488
4368
|
/* @__PURE__ */ jsx(DialogTitle, { id: titleId, className: "sr-only", children: "Withdraw" }),
|
|
5489
4369
|
/* @__PURE__ */ jsx(DialogDescription, { id: descId, className: "sr-only", children: "Withdraw funds from your account." }),
|
|
5490
|
-
/* @__PURE__ */ jsx(
|
|
4370
|
+
/* @__PURE__ */ jsx(
|
|
4371
|
+
WithdrawModalContent,
|
|
4372
|
+
{
|
|
4373
|
+
onClose: handleClose,
|
|
4374
|
+
onPendingChange: setIsCloseBlocked,
|
|
4375
|
+
onWithdrawSuccess
|
|
4376
|
+
}
|
|
4377
|
+
)
|
|
5491
4378
|
]
|
|
5492
4379
|
}
|
|
5493
4380
|
)
|
|
5494
4381
|
}
|
|
5495
4382
|
);
|
|
5496
4383
|
}
|
|
5497
|
-
function WithdrawInlineModal({ className }) {
|
|
4384
|
+
function WithdrawInlineModal({ className, onWithdrawSuccess }) {
|
|
5498
4385
|
return /* @__PURE__ */ jsx(
|
|
5499
4386
|
"div",
|
|
5500
4387
|
{
|
|
@@ -5503,7 +4390,7 @@ function WithdrawInlineModal({ className }) {
|
|
|
5503
4390
|
"bg-card relative flex w-[560px] max-w-full flex-col gap-2 overflow-hidden rounded-2xl p-2 shadow-lg",
|
|
5504
4391
|
className
|
|
5505
4392
|
),
|
|
5506
|
-
children: /* @__PURE__ */ jsx(WithdrawModalContent, {})
|
|
4393
|
+
children: /* @__PURE__ */ jsx(WithdrawModalContent, { onWithdrawSuccess })
|
|
5507
4394
|
}
|
|
5508
4395
|
);
|
|
5509
4396
|
}
|
|
@@ -5755,6 +4642,7 @@ function WalletModalContent({
|
|
|
5755
4642
|
onFundSession,
|
|
5756
4643
|
onEndSession,
|
|
5757
4644
|
onDepositSuccess,
|
|
4645
|
+
onWithdrawSuccess,
|
|
5758
4646
|
onClose,
|
|
5759
4647
|
onCloseBlockedChange,
|
|
5760
4648
|
...depositHandlers
|
|
@@ -5919,7 +4807,17 @@ function WalletModalContent({
|
|
|
5919
4807
|
retryLabel: "Try again"
|
|
5920
4808
|
}
|
|
5921
4809
|
) }),
|
|
5922
|
-
view === "withdraw" && /* @__PURE__ */ jsx(
|
|
4810
|
+
view === "withdraw" && /* @__PURE__ */ jsx(
|
|
4811
|
+
WithdrawModalContent,
|
|
4812
|
+
{
|
|
4813
|
+
onBack: exitWithdraw,
|
|
4814
|
+
onPendingChange: setWithdrawPending,
|
|
4815
|
+
onWithdrawSuccess: () => {
|
|
4816
|
+
exitWithdraw();
|
|
4817
|
+
onWithdrawSuccess?.();
|
|
4818
|
+
}
|
|
4819
|
+
}
|
|
4820
|
+
),
|
|
5923
4821
|
view === "deposit" && /* @__PURE__ */ jsx(
|
|
5924
4822
|
DepositModalContent,
|
|
5925
4823
|
{
|
|
@@ -5990,6 +4888,6 @@ function WalletInlineModal({ className, ...handlers }) {
|
|
|
5990
4888
|
);
|
|
5991
4889
|
}
|
|
5992
4890
|
|
|
5993
|
-
export { DepositInlineModal, DepositModal,
|
|
4891
|
+
export { DepositInlineModal, DepositModal, PrivanaIcon, WalletInlineModal, WalletModal, WithdrawInlineModal, WithdrawModal, getChainIcon, getTokenIcon, useBalance, useBatchBalances, useDeposit, useDepositAddress, useExpiredLocks, useHistory, useHostedRedirectAuth, useLockFunds, useLockedFunds, useModifyLock, usePendingDeposits, usePendingWithdrawals, usePrivanaClient, useTokenInfo, useTokenList, useTotalLockedBalance, useTransfer, useUnlockFunds, useWithdraw };
|
|
5994
4892
|
//# sourceMappingURL=index.js.map
|
|
5995
4893
|
//# sourceMappingURL=index.js.map
|