@oasisprotocol/privana-sdk 0.2.0 → 0.2.1
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 +1 -1
- package/dist/index.cjs +253 -151
- 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 +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +254 -152
- package/dist/index.js.map +1 -1
- package/dist/powered_by_privana-YV2FNNVG.svg +4 -0
- package/dist/powered_by_privana.svg +4 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -8,7 +8,7 @@ import { twMerge } from 'tailwind-merge';
|
|
|
8
8
|
import { createSiweMessage } from 'viem/siwe';
|
|
9
9
|
import { WagmiContext, useAccount, useWalletClient, useConfig, useWriteContract, useSendTransaction, useChainId, useSwitchChain, useBalance as useBalance$1, useReadContract } from 'wagmi';
|
|
10
10
|
import { watchAccount, getAccount, getWalletClient } from 'wagmi/actions';
|
|
11
|
-
import { waitForTransactionReceipt as waitForTransactionReceipt$1, getTransaction, call } from 'viem/actions';
|
|
11
|
+
import { getTransactionReceipt as getTransactionReceipt$1, waitForTransactionReceipt as waitForTransactionReceipt$1, getTransaction, call } from 'viem/actions';
|
|
12
12
|
import { Slot } from '@radix-ui/react-slot';
|
|
13
13
|
import { cva } from 'class-variance-authority';
|
|
14
14
|
import * as DialogPrimitive from '@radix-ui/react-dialog';
|
|
@@ -29,7 +29,7 @@ var config_default = {
|
|
|
29
29
|
chainId: 23295,
|
|
30
30
|
name: "Sapphire Testnet",
|
|
31
31
|
accountingContract: "0xaF8e5de153A584528B57DD4B9B0195956BBDF571",
|
|
32
|
-
apiUrl: "https://
|
|
32
|
+
apiUrl: "https://testnet.privana.finance"
|
|
33
33
|
},
|
|
34
34
|
mainnet: {
|
|
35
35
|
chainId: 23294,
|
|
@@ -1608,6 +1608,12 @@ function getAction(client, actionFn, name) {
|
|
|
1608
1608
|
function getChainId2(config) {
|
|
1609
1609
|
return config.state.chainId;
|
|
1610
1610
|
}
|
|
1611
|
+
async function getTransactionReceipt(config, parameters) {
|
|
1612
|
+
const { chainId, ...rest } = parameters;
|
|
1613
|
+
const client = config.getClient({ chainId });
|
|
1614
|
+
const action = getAction(client, getTransactionReceipt$1, "getTransactionReceipt");
|
|
1615
|
+
return action(rest);
|
|
1616
|
+
}
|
|
1611
1617
|
async function waitForTransactionReceipt(config, parameters) {
|
|
1612
1618
|
const { chainId, timeout = 0, ...rest } = parameters;
|
|
1613
1619
|
const client = config.getClient({ chainId });
|
|
@@ -1688,6 +1694,36 @@ function useEnsureCorrectChain() {
|
|
|
1688
1694
|
}
|
|
1689
1695
|
|
|
1690
1696
|
// src/sdk/hooks/use-deposit.ts
|
|
1697
|
+
var STALE_MS = 30 * 60 * 1e3;
|
|
1698
|
+
function storageKey(address) {
|
|
1699
|
+
return `privana:pending-deposit:${address.toLowerCase()}`;
|
|
1700
|
+
}
|
|
1701
|
+
function savePendingDeposit(address, data) {
|
|
1702
|
+
try {
|
|
1703
|
+
sessionStorage.setItem(storageKey(address), JSON.stringify(data));
|
|
1704
|
+
} catch {
|
|
1705
|
+
}
|
|
1706
|
+
}
|
|
1707
|
+
function loadPendingDeposit(address) {
|
|
1708
|
+
try {
|
|
1709
|
+
const raw = sessionStorage.getItem(storageKey(address));
|
|
1710
|
+
if (!raw) return null;
|
|
1711
|
+
const data = JSON.parse(raw);
|
|
1712
|
+
if (Date.now() - data.savedAt > STALE_MS) {
|
|
1713
|
+
clearPendingDeposit(address);
|
|
1714
|
+
return null;
|
|
1715
|
+
}
|
|
1716
|
+
return data;
|
|
1717
|
+
} catch {
|
|
1718
|
+
return null;
|
|
1719
|
+
}
|
|
1720
|
+
}
|
|
1721
|
+
function clearPendingDeposit(address) {
|
|
1722
|
+
try {
|
|
1723
|
+
sessionStorage.removeItem(storageKey(address));
|
|
1724
|
+
} catch {
|
|
1725
|
+
}
|
|
1726
|
+
}
|
|
1691
1727
|
function useDeposit(options = {}) {
|
|
1692
1728
|
const { address } = useAccount();
|
|
1693
1729
|
const { client, enabledTokens, getChainById: getChainById2 } = usePrivanaContext();
|
|
@@ -1755,13 +1791,19 @@ function useDeposit(options = {}) {
|
|
|
1755
1791
|
const isSendingTx = isWritingContract || isSendingNative;
|
|
1756
1792
|
const sendError = writeError ?? sendNativeError;
|
|
1757
1793
|
const { ensureCorrectChain } = useEnsureCorrectChain();
|
|
1794
|
+
const invalidateGeneration = useCallback(() => {
|
|
1795
|
+
generationRef.current++;
|
|
1796
|
+
}, []);
|
|
1758
1797
|
useEffect(() => {
|
|
1759
1798
|
return () => {
|
|
1799
|
+
invalidateGeneration();
|
|
1760
1800
|
if (pollIntervalRef.current) {
|
|
1761
1801
|
clearTimeout(pollIntervalRef.current);
|
|
1802
|
+
pollIntervalRef.current = null;
|
|
1762
1803
|
}
|
|
1763
1804
|
};
|
|
1764
|
-
}, []);
|
|
1805
|
+
}, [invalidateGeneration]);
|
|
1806
|
+
const resumedAddressRef = useRef(void 0);
|
|
1765
1807
|
const stopPolling = useCallback(() => {
|
|
1766
1808
|
if (pollIntervalRef.current) {
|
|
1767
1809
|
clearTimeout(pollIntervalRef.current);
|
|
@@ -1771,6 +1813,7 @@ function useDeposit(options = {}) {
|
|
|
1771
1813
|
const reset = useCallback(() => {
|
|
1772
1814
|
generationRef.current++;
|
|
1773
1815
|
stopPolling();
|
|
1816
|
+
if (address) clearPendingDeposit(address);
|
|
1774
1817
|
verificationContextRef.current = null;
|
|
1775
1818
|
setDepositAddress(null);
|
|
1776
1819
|
setTxHash(void 0);
|
|
@@ -1783,7 +1826,7 @@ function useDeposit(options = {}) {
|
|
|
1783
1826
|
addressMutation.reset();
|
|
1784
1827
|
resetWriteContract();
|
|
1785
1828
|
resetSendTransaction();
|
|
1786
|
-
}, [addressMutation, resetWriteContract, resetSendTransaction, stopPolling]);
|
|
1829
|
+
}, [address, addressMutation, resetWriteContract, resetSendTransaction, stopPolling]);
|
|
1787
1830
|
const runVerification = useCallback(
|
|
1788
1831
|
async (ctx, generation) => {
|
|
1789
1832
|
const isStale = () => generation !== generationRef.current;
|
|
@@ -1811,6 +1854,7 @@ function useDeposit(options = {}) {
|
|
|
1811
1854
|
if (triggerResult.status === "credited") {
|
|
1812
1855
|
setIsWaitingForProcessing(false);
|
|
1813
1856
|
verificationContextRef.current = null;
|
|
1857
|
+
if (address) clearPendingDeposit(address);
|
|
1814
1858
|
queryClient.invalidateQueries({ queryKey: ["accounting-balance"] });
|
|
1815
1859
|
queryClient.invalidateQueries({ queryKey: ["accounting-history"] });
|
|
1816
1860
|
onCreditedRef.current?.(hash, triggerResult);
|
|
@@ -1844,6 +1888,7 @@ function useDeposit(options = {}) {
|
|
|
1844
1888
|
stopPolling();
|
|
1845
1889
|
setIsWaitingForProcessing(false);
|
|
1846
1890
|
verificationContextRef.current = null;
|
|
1891
|
+
if (address) clearPendingDeposit(address);
|
|
1847
1892
|
queryClient.invalidateQueries({ queryKey: ["accounting-balance"] });
|
|
1848
1893
|
queryClient.invalidateQueries({ queryKey: ["accounting-history"] });
|
|
1849
1894
|
onCreditedRef.current?.(hash, result);
|
|
@@ -1883,7 +1928,7 @@ function useDeposit(options = {}) {
|
|
|
1883
1928
|
);
|
|
1884
1929
|
}
|
|
1885
1930
|
},
|
|
1886
|
-
[client, executePrivateRead, pollInterval, pollTimeout, queryClient, stopPolling]
|
|
1931
|
+
[address, client, executePrivateRead, pollInterval, pollTimeout, queryClient, stopPolling]
|
|
1887
1932
|
);
|
|
1888
1933
|
const retryVerification = useCallback(async () => {
|
|
1889
1934
|
const ctx = verificationContextRef.current;
|
|
@@ -1895,6 +1940,55 @@ function useDeposit(options = {}) {
|
|
|
1895
1940
|
const generation = generationRef.current;
|
|
1896
1941
|
await runVerification(ctx, generation);
|
|
1897
1942
|
}, [runVerification, stopPolling]);
|
|
1943
|
+
useEffect(() => {
|
|
1944
|
+
if (!address || resumedAddressRef.current === address) return;
|
|
1945
|
+
const persisted = loadPendingDeposit(address);
|
|
1946
|
+
if (!persisted) return;
|
|
1947
|
+
resumedAddressRef.current = address;
|
|
1948
|
+
const hash = persisted.txHash;
|
|
1949
|
+
setTxHash(hash);
|
|
1950
|
+
setDepositAddress(persisted.depositAddress);
|
|
1951
|
+
setIsWaitingForConfirmation(true);
|
|
1952
|
+
const ctx = {
|
|
1953
|
+
hash,
|
|
1954
|
+
chainId: persisted.chainId,
|
|
1955
|
+
amount: BigInt(persisted.amount)
|
|
1956
|
+
};
|
|
1957
|
+
verificationContextRef.current = ctx;
|
|
1958
|
+
const generation = ++generationRef.current;
|
|
1959
|
+
const isStale = () => generation !== generationRef.current;
|
|
1960
|
+
(async () => {
|
|
1961
|
+
try {
|
|
1962
|
+
let confirmed = false;
|
|
1963
|
+
try {
|
|
1964
|
+
await getTransactionReceipt(config, { hash, chainId: persisted.chainId });
|
|
1965
|
+
confirmed = true;
|
|
1966
|
+
} catch {
|
|
1967
|
+
}
|
|
1968
|
+
if (!confirmed) {
|
|
1969
|
+
await waitForTransactionReceipt(config, {
|
|
1970
|
+
hash,
|
|
1971
|
+
chainId: persisted.chainId,
|
|
1972
|
+
confirmations
|
|
1973
|
+
});
|
|
1974
|
+
}
|
|
1975
|
+
if (isStale()) return;
|
|
1976
|
+
setIsWaitingForConfirmation(false);
|
|
1977
|
+
onDepositSuccessRef.current?.(hash);
|
|
1978
|
+
queryClient.invalidateQueries({ queryKey: ["readContract"] });
|
|
1979
|
+
await runVerification(ctx, generation);
|
|
1980
|
+
} catch (err) {
|
|
1981
|
+
if (isStale()) return;
|
|
1982
|
+
setIsWaitingForConfirmation(false);
|
|
1983
|
+
stopPolling();
|
|
1984
|
+
const error2 = err instanceof Error ? err : new Error("Deposit verification failed");
|
|
1985
|
+
setIsWaitingForProcessing(false);
|
|
1986
|
+
setDepositError(error2);
|
|
1987
|
+
setVerificationFailed(true);
|
|
1988
|
+
onErrorRef.current?.(error2);
|
|
1989
|
+
}
|
|
1990
|
+
})();
|
|
1991
|
+
}, [address, config, confirmations, queryClient, runVerification, stopPolling]);
|
|
1898
1992
|
const deposit = useCallback(
|
|
1899
1993
|
async (params) => {
|
|
1900
1994
|
if (verificationContextRef.current) {
|
|
@@ -1951,10 +2045,21 @@ function useDeposit(options = {}) {
|
|
|
1951
2045
|
amount: params.amount
|
|
1952
2046
|
};
|
|
1953
2047
|
verificationContextRef.current = ctx;
|
|
2048
|
+
savePendingDeposit(address, {
|
|
2049
|
+
txHash: hash,
|
|
2050
|
+
chainId: sourceChain.id,
|
|
2051
|
+
amount: params.amount.toString(),
|
|
2052
|
+
depositAddress: addrResponse,
|
|
2053
|
+
savedAt: Date.now()
|
|
2054
|
+
});
|
|
1954
2055
|
try {
|
|
1955
2056
|
setIsWaitingForConfirmation(true);
|
|
1956
2057
|
try {
|
|
1957
|
-
await waitForTransactionReceipt(config, {
|
|
2058
|
+
await waitForTransactionReceipt(config, {
|
|
2059
|
+
hash,
|
|
2060
|
+
chainId: sourceChain.id,
|
|
2061
|
+
confirmations
|
|
2062
|
+
});
|
|
1958
2063
|
} finally {
|
|
1959
2064
|
if (!isStale()) setIsWaitingForConfirmation(false);
|
|
1960
2065
|
}
|
|
@@ -3152,6 +3257,7 @@ function DepositForm({
|
|
|
3152
3257
|
selectedToken,
|
|
3153
3258
|
onTokenSelect,
|
|
3154
3259
|
onPendingChange,
|
|
3260
|
+
onUnsafeToCloseChange,
|
|
3155
3261
|
onSuccess
|
|
3156
3262
|
}) {
|
|
3157
3263
|
const { isConnected, address } = useAccount();
|
|
@@ -3180,7 +3286,7 @@ function DepositForm({
|
|
|
3180
3286
|
}
|
|
3181
3287
|
});
|
|
3182
3288
|
const walletBalance = isNative ? nativeBalanceData?.value : erc20Balance;
|
|
3183
|
-
const formattedWalletBalance = walletBalance ? formatTokenAmount(walletBalance.toString(), selectedToken.decimals) : "0";
|
|
3289
|
+
const formattedWalletBalance = walletBalance ? formatTokenAmount(walletBalance.toString(), selectedToken.decimals) : "0.00";
|
|
3184
3290
|
const handleMaxClick = () => {
|
|
3185
3291
|
if (formattedWalletBalance && parseFloat(formattedWalletBalance) > 0) {
|
|
3186
3292
|
setAmount(formattedWalletBalance.replace(/[\s\u2009]/g, ""));
|
|
@@ -3247,6 +3353,9 @@ function DepositForm({
|
|
|
3247
3353
|
useEffect(() => {
|
|
3248
3354
|
onPendingChange?.(isPending && !cancelled);
|
|
3249
3355
|
}, [isPending, cancelled, onPendingChange]);
|
|
3356
|
+
useEffect(() => {
|
|
3357
|
+
onUnsafeToCloseChange?.((isGettingAddress || isSendingTransaction) && !cancelled);
|
|
3358
|
+
}, [isGettingAddress, isSendingTransaction, cancelled, onUnsafeToCloseChange]);
|
|
3250
3359
|
const handleCancel = () => {
|
|
3251
3360
|
setCancelled(true);
|
|
3252
3361
|
reset();
|
|
@@ -3410,7 +3519,12 @@ function DepositForm({
|
|
|
3410
3519
|
)
|
|
3411
3520
|
] });
|
|
3412
3521
|
}
|
|
3413
|
-
function WithdrawForm({
|
|
3522
|
+
function WithdrawForm({
|
|
3523
|
+
selectedToken,
|
|
3524
|
+
onTokenSelect,
|
|
3525
|
+
onPendingChange,
|
|
3526
|
+
onUnsafeToCloseChange
|
|
3527
|
+
}) {
|
|
3414
3528
|
const { isConnected, address } = useAccount();
|
|
3415
3529
|
const { chains, getChainById: getChainById2 } = usePrivanaContext();
|
|
3416
3530
|
const [amount, setAmount] = useState("");
|
|
@@ -3463,8 +3577,10 @@ function WithdrawForm({ selectedToken, onTokenSelect, onPendingChange }) {
|
|
|
3463
3577
|
}
|
|
3464
3578
|
}, [error]);
|
|
3465
3579
|
useEffect(() => {
|
|
3466
|
-
|
|
3467
|
-
|
|
3580
|
+
const pending = isPending && !cancelled;
|
|
3581
|
+
onPendingChange?.(pending);
|
|
3582
|
+
onUnsafeToCloseChange?.(pending);
|
|
3583
|
+
}, [isPending, cancelled, onPendingChange, onUnsafeToCloseChange]);
|
|
3468
3584
|
const handleCancel = () => {
|
|
3469
3585
|
setCancelled(true);
|
|
3470
3586
|
reset();
|
|
@@ -3623,9 +3739,6 @@ function CloseIcon() {
|
|
|
3623
3739
|
}
|
|
3624
3740
|
) });
|
|
3625
3741
|
}
|
|
3626
|
-
function SearchIcon() {
|
|
3627
|
-
return /* @__PURE__ */ jsx("div", { className: "h-3 w-3 rounded-full border-[1.5px] border-current" });
|
|
3628
|
-
}
|
|
3629
3742
|
function ChevronRight() {
|
|
3630
3743
|
return /* @__PURE__ */ jsx("svg", { width: "10", height: "5", viewBox: "0 0 12 6", className: "-rotate-90", children: /* @__PURE__ */ jsx(
|
|
3631
3744
|
"path",
|
|
@@ -3686,7 +3799,7 @@ function BalanceCards({
|
|
|
3686
3799
|
});
|
|
3687
3800
|
const { totalLocked, isLoading: lockedLoading } = useLockedFunds({ enabled: showLockedFunds });
|
|
3688
3801
|
const formattedBalance = formatTokenAmount(balanceWei, selectedToken.decimals);
|
|
3689
|
-
const formattedLocked = showLockedFunds ? formatTokenAmount(String(totalLocked), selectedToken.decimals) : "0";
|
|
3802
|
+
const formattedLocked = showLockedFunds ? formatTokenAmount(String(totalLocked), selectedToken.decimals) : "0.00";
|
|
3690
3803
|
return /* @__PURE__ */ jsxs("div", { className: cn("flex gap-2", disabled && "opacity-50"), children: [
|
|
3691
3804
|
/* @__PURE__ */ jsxs(
|
|
3692
3805
|
"button",
|
|
@@ -3749,7 +3862,7 @@ function Tabs({
|
|
|
3749
3862
|
"div",
|
|
3750
3863
|
{
|
|
3751
3864
|
className: cn(
|
|
3752
|
-
"bg-input absolute top-1 bottom-1 left-1 w-[calc(50%-
|
|
3865
|
+
"bg-input absolute top-1 bottom-1 left-1 w-[calc(50%-8px)] rounded-md transition-transform duration-200",
|
|
3753
3866
|
activeTab === "withdraw" && "translate-x-[calc(100%+8px)]"
|
|
3754
3867
|
)
|
|
3755
3868
|
}
|
|
@@ -3784,7 +3897,7 @@ function Tabs({
|
|
|
3784
3897
|
}
|
|
3785
3898
|
);
|
|
3786
3899
|
}
|
|
3787
|
-
function LockedFundsView({ onBack
|
|
3900
|
+
function LockedFundsView({ onBack }) {
|
|
3788
3901
|
const { getTokenById } = usePrivanaContext();
|
|
3789
3902
|
const { locks, isLoading } = useLockedFunds();
|
|
3790
3903
|
const { unlockFunds, unlockAllExpired, isPending } = useUnlockFunds();
|
|
@@ -3817,27 +3930,17 @@ function LockedFundsView({ onBack, onClose }) {
|
|
|
3817
3930
|
};
|
|
3818
3931
|
const expiredCount = locks.filter((l) => l.is_expired).length;
|
|
3819
3932
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
3820
|
-
/* @__PURE__ */
|
|
3821
|
-
/* @__PURE__ */
|
|
3822
|
-
/* @__PURE__ */ jsx(
|
|
3823
|
-
"button",
|
|
3824
|
-
{
|
|
3825
|
-
onClick: onBack,
|
|
3826
|
-
className: "text-muted-foreground hover:text-foreground flex h-6 w-6 cursor-pointer items-center justify-center transition-colors",
|
|
3827
|
-
children: /* @__PURE__ */ jsx(ChevronLeft, {})
|
|
3828
|
-
}
|
|
3829
|
-
),
|
|
3830
|
-
/* @__PURE__ */ jsx("span", { className: "text-foreground text-xl leading-6 font-medium", children: "Locked Funds" })
|
|
3831
|
-
] }),
|
|
3832
|
-
onClose && /* @__PURE__ */ jsx(
|
|
3933
|
+
/* @__PURE__ */ jsx("div", { className: "flex items-center justify-between px-5 py-4", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
3934
|
+
/* @__PURE__ */ jsx(
|
|
3833
3935
|
"button",
|
|
3834
3936
|
{
|
|
3835
|
-
onClick:
|
|
3836
|
-
className: "text-muted-foreground hover:text-foreground flex h-6 w-6 cursor-pointer items-center justify-center transition-colors",
|
|
3837
|
-
children: /* @__PURE__ */ jsx(
|
|
3937
|
+
onClick: onBack,
|
|
3938
|
+
className: "text-muted-foreground hover:text-foreground -ml-2 flex h-6 w-6 cursor-pointer items-center justify-center transition-colors",
|
|
3939
|
+
children: /* @__PURE__ */ jsx(ChevronLeft, {})
|
|
3838
3940
|
}
|
|
3839
|
-
)
|
|
3840
|
-
|
|
3941
|
+
),
|
|
3942
|
+
/* @__PURE__ */ jsx("span", { className: "text-foreground text-xl leading-6 font-medium", children: "Locked Funds" })
|
|
3943
|
+
] }) }),
|
|
3841
3944
|
/* @__PURE__ */ jsxs("div", { className: "bg-muted flex min-h-0 flex-1 flex-col rounded-[10px] p-2", children: [
|
|
3842
3945
|
/* @__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: [
|
|
3843
3946
|
/* @__PURE__ */ jsx("div", { className: "bg-secondary h-10 w-10 rounded-full" }),
|
|
@@ -3922,34 +4025,24 @@ function BalanceTokenRow({ token }) {
|
|
|
3922
4025
|
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 })
|
|
3923
4026
|
] });
|
|
3924
4027
|
}
|
|
3925
|
-
function BalanceDetailsView({ onBack
|
|
4028
|
+
function BalanceDetailsView({ onBack }) {
|
|
3926
4029
|
const { enabledTokens, chains } = usePrivanaContext();
|
|
3927
4030
|
const [selectedChainId, setSelectedChainId] = useState(chains[0]?.id ?? 84532);
|
|
3928
4031
|
const chainTokens = useMemo(() => {
|
|
3929
4032
|
return enabledTokens.filter((t) => t.chainId === selectedChainId);
|
|
3930
4033
|
}, [enabledTokens, selectedChainId]);
|
|
3931
4034
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
3932
|
-
/* @__PURE__ */
|
|
3933
|
-
/* @__PURE__ */
|
|
3934
|
-
/* @__PURE__ */ jsx(
|
|
3935
|
-
"button",
|
|
3936
|
-
{
|
|
3937
|
-
onClick: onBack,
|
|
3938
|
-
className: "text-muted-foreground hover:text-foreground flex h-6 w-6 cursor-pointer items-center justify-center transition-colors",
|
|
3939
|
-
children: /* @__PURE__ */ jsx(ChevronLeft, {})
|
|
3940
|
-
}
|
|
3941
|
-
),
|
|
3942
|
-
/* @__PURE__ */ jsx("span", { className: "text-foreground text-xl leading-6 font-medium", children: "Token Balances" })
|
|
3943
|
-
] }),
|
|
3944
|
-
onClose && /* @__PURE__ */ jsx(
|
|
4035
|
+
/* @__PURE__ */ jsx("div", { className: "flex items-center justify-between px-5 py-4", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
4036
|
+
/* @__PURE__ */ jsx(
|
|
3945
4037
|
"button",
|
|
3946
4038
|
{
|
|
3947
|
-
onClick:
|
|
3948
|
-
className: "text-muted-foreground hover:text-foreground flex h-6 w-6 cursor-pointer items-center justify-center transition-colors",
|
|
3949
|
-
children: /* @__PURE__ */ jsx(
|
|
4039
|
+
onClick: onBack,
|
|
4040
|
+
className: "text-muted-foreground hover:text-foreground -ml-2 flex h-6 w-6 cursor-pointer items-center justify-center transition-colors",
|
|
4041
|
+
children: /* @__PURE__ */ jsx(ChevronLeft, {})
|
|
3950
4042
|
}
|
|
3951
|
-
)
|
|
3952
|
-
|
|
4043
|
+
),
|
|
4044
|
+
/* @__PURE__ */ jsx("span", { className: "text-foreground text-xl leading-6 font-medium", children: "Token Balances" })
|
|
4045
|
+
] }) }),
|
|
3953
4046
|
/* @__PURE__ */ jsxs("div", { className: "flex min-h-0 flex-1 gap-2", children: [
|
|
3954
4047
|
/* @__PURE__ */ jsxs("div", { className: "bg-muted flex flex-1 flex-col overflow-hidden rounded-[10px] p-2", children: [
|
|
3955
4048
|
/* @__PURE__ */ jsx("div", { className: "px-4 pt-4 pb-2", children: /* @__PURE__ */ jsx("span", { className: "text-muted-foreground text-sm", children: "Network" }) }),
|
|
@@ -4019,48 +4112,30 @@ function TokenRow({
|
|
|
4019
4112
|
}
|
|
4020
4113
|
function TokenSelectorView({
|
|
4021
4114
|
onBack,
|
|
4022
|
-
onClose,
|
|
4023
4115
|
onSelect,
|
|
4024
4116
|
selectedTokenId
|
|
4025
4117
|
}) {
|
|
4026
|
-
const [tokenSearch, setTokenSearch] = useState("");
|
|
4027
4118
|
const { enabledTokens, chains } = usePrivanaContext();
|
|
4028
4119
|
const [selectedChainId, setSelectedChainId] = useState(chains[0]?.id ?? 84532);
|
|
4029
4120
|
const chainTokens = useMemo(() => {
|
|
4030
4121
|
return enabledTokens.filter((t) => t.chainId === selectedChainId);
|
|
4031
4122
|
}, [enabledTokens, selectedChainId]);
|
|
4032
|
-
const filteredTokens = useMemo(() => {
|
|
4033
|
-
if (!tokenSearch) return chainTokens;
|
|
4034
|
-
return chainTokens.filter(
|
|
4035
|
-
(t) => t.symbol.toLowerCase().includes(tokenSearch.toLowerCase()) || t.name.toLowerCase().includes(tokenSearch.toLowerCase())
|
|
4036
|
-
);
|
|
4037
|
-
}, [tokenSearch, chainTokens]);
|
|
4038
4123
|
const handleTokenSelect = (token) => {
|
|
4039
4124
|
onSelect(token);
|
|
4040
4125
|
onBack();
|
|
4041
4126
|
};
|
|
4042
4127
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
4043
|
-
/* @__PURE__ */
|
|
4044
|
-
/* @__PURE__ */
|
|
4045
|
-
/* @__PURE__ */ jsx(
|
|
4046
|
-
"button",
|
|
4047
|
-
{
|
|
4048
|
-
onClick: onBack,
|
|
4049
|
-
className: "text-muted-foreground hover:text-foreground flex h-6 w-6 cursor-pointer items-center justify-center transition-colors",
|
|
4050
|
-
children: /* @__PURE__ */ jsx(ChevronLeft, {})
|
|
4051
|
-
}
|
|
4052
|
-
),
|
|
4053
|
-
/* @__PURE__ */ jsx("span", { className: "text-foreground text-xl leading-6 font-medium", children: "Select Token" })
|
|
4054
|
-
] }),
|
|
4055
|
-
onClose && /* @__PURE__ */ jsx(
|
|
4128
|
+
/* @__PURE__ */ jsx("div", { className: "flex items-center justify-between px-5 py-4", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
4129
|
+
/* @__PURE__ */ jsx(
|
|
4056
4130
|
"button",
|
|
4057
4131
|
{
|
|
4058
|
-
onClick:
|
|
4059
|
-
className: "text-muted-foreground hover:text-foreground flex h-6 w-6 cursor-pointer items-center justify-center transition-colors",
|
|
4060
|
-
children: /* @__PURE__ */ jsx(
|
|
4132
|
+
onClick: onBack,
|
|
4133
|
+
className: "text-muted-foreground hover:text-foreground -ml-2 flex h-6 w-6 cursor-pointer items-center justify-center transition-colors",
|
|
4134
|
+
children: /* @__PURE__ */ jsx(ChevronLeft, {})
|
|
4061
4135
|
}
|
|
4062
|
-
)
|
|
4063
|
-
|
|
4136
|
+
),
|
|
4137
|
+
/* @__PURE__ */ jsx("span", { className: "text-foreground text-xl leading-6 font-medium", children: "Select Token" })
|
|
4138
|
+
] }) }),
|
|
4064
4139
|
/* @__PURE__ */ jsxs("div", { className: "flex min-h-0 flex-1 gap-2", children: [
|
|
4065
4140
|
/* @__PURE__ */ jsxs("div", { className: "bg-muted flex flex-1 flex-col overflow-hidden rounded-[10px] p-2", children: [
|
|
4066
4141
|
/* @__PURE__ */ jsx("div", { className: "px-4 pt-4 pb-2", children: /* @__PURE__ */ jsx("span", { className: "text-muted-foreground text-sm", children: "Network" }) }),
|
|
@@ -4084,23 +4159,8 @@ function TokenSelectorView({
|
|
|
4084
4159
|
}) })
|
|
4085
4160
|
] }),
|
|
4086
4161
|
/* @__PURE__ */ jsxs("div", { className: "bg-muted flex flex-[2] flex-col overflow-hidden rounded-[10px] p-2", children: [
|
|
4087
|
-
/* @__PURE__ */
|
|
4088
|
-
|
|
4089
|
-
/* @__PURE__ */ jsx("div", { className: "px-3", children: /* @__PURE__ */ jsxs("div", { className: "border-border bg-input flex items-center gap-2.5 rounded-lg border px-3 py-2.5", children: [
|
|
4090
|
-
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: /* @__PURE__ */ jsx(SearchIcon, {}) }),
|
|
4091
|
-
/* @__PURE__ */ jsx(
|
|
4092
|
-
"input",
|
|
4093
|
-
{
|
|
4094
|
-
type: "text",
|
|
4095
|
-
placeholder: "Search",
|
|
4096
|
-
value: tokenSearch,
|
|
4097
|
-
onChange: (e) => setTokenSearch(e.target.value),
|
|
4098
|
-
className: "text-foreground placeholder:text-muted-foreground flex-1 bg-transparent text-sm outline-none"
|
|
4099
|
-
}
|
|
4100
|
-
)
|
|
4101
|
-
] }) })
|
|
4102
|
-
] }),
|
|
4103
|
-
/* @__PURE__ */ jsx("div", { className: "mt-2 flex-1 overflow-y-auto", children: filteredTokens.map((token) => /* @__PURE__ */ jsx(
|
|
4162
|
+
/* @__PURE__ */ jsx("div", { className: "px-4 pt-4 pb-2", children: /* @__PURE__ */ jsx("span", { className: "text-muted-foreground text-sm", children: "Token" }) }),
|
|
4163
|
+
/* @__PURE__ */ jsx("div", { className: "mt-2 flex-1 overflow-y-auto", children: chainTokens.map((token) => /* @__PURE__ */ jsx(
|
|
4104
4164
|
TokenRow,
|
|
4105
4165
|
{
|
|
4106
4166
|
token,
|
|
@@ -4114,9 +4174,8 @@ function TokenSelectorView({
|
|
|
4114
4174
|
] });
|
|
4115
4175
|
}
|
|
4116
4176
|
function ModalBody({
|
|
4117
|
-
onClose,
|
|
4118
4177
|
onViewChange,
|
|
4119
|
-
|
|
4178
|
+
onCloseBlockedChange,
|
|
4120
4179
|
showLockedFunds = true,
|
|
4121
4180
|
defaultTab = "deposit",
|
|
4122
4181
|
onDepositSuccess
|
|
@@ -4125,65 +4184,78 @@ function ModalBody({
|
|
|
4125
4184
|
const [selectedToken, setSelectedToken] = useState(defaultToken);
|
|
4126
4185
|
const [activeTab, setActiveTab] = useState(defaultTab);
|
|
4127
4186
|
const [currentView, setCurrentView] = useState("main");
|
|
4128
|
-
const [
|
|
4187
|
+
const [isInteractionPending, setIsInteractionPending] = useState(false);
|
|
4129
4188
|
useEffect(() => {
|
|
4130
4189
|
if (!selectedToken && defaultToken) {
|
|
4131
4190
|
setSelectedToken(defaultToken);
|
|
4132
4191
|
}
|
|
4133
4192
|
}, [selectedToken, defaultToken]);
|
|
4134
|
-
const
|
|
4135
|
-
|
|
4136
|
-
|
|
4193
|
+
const handlePendingChange = (isPending) => {
|
|
4194
|
+
setIsInteractionPending(isPending);
|
|
4195
|
+
};
|
|
4196
|
+
const handleCloseBlockedChange = (isBlocked) => {
|
|
4197
|
+
onCloseBlockedChange?.(isBlocked);
|
|
4137
4198
|
};
|
|
4138
4199
|
const handleViewChange = (view) => {
|
|
4139
|
-
|
|
4140
|
-
|
|
4200
|
+
const update = () => {
|
|
4201
|
+
setCurrentView(view);
|
|
4202
|
+
onViewChange?.(view);
|
|
4203
|
+
};
|
|
4204
|
+
if (typeof document !== "undefined" && typeof document.startViewTransition === "function") {
|
|
4205
|
+
document.documentElement.dataset.privanaVtDir = view === "main" ? "back" : "forward";
|
|
4206
|
+
const transition = document.startViewTransition(update);
|
|
4207
|
+
transition.finished.then(() => {
|
|
4208
|
+
delete document.documentElement.dataset.privanaVtDir;
|
|
4209
|
+
});
|
|
4210
|
+
} else {
|
|
4211
|
+
update();
|
|
4212
|
+
}
|
|
4141
4213
|
};
|
|
4142
4214
|
const handleTokenSelect = (token) => {
|
|
4143
4215
|
setSelectedToken(token);
|
|
4144
4216
|
};
|
|
4145
4217
|
if (tokensStatus === "loading" || !selectedToken) {
|
|
4146
|
-
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2
|
|
4218
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
|
|
4147
4219
|
/* @__PURE__ */ jsx("div", { className: "bg-secondary h-25 animate-pulse rounded-[10px]" }),
|
|
4148
4220
|
/* @__PURE__ */ jsx("div", { className: "bg-secondary h-11 animate-pulse rounded-[10px]" }),
|
|
4149
4221
|
/* @__PURE__ */ jsx("div", { className: "bg-secondary h-50 animate-pulse rounded-[10px]" })
|
|
4150
4222
|
] });
|
|
4151
4223
|
}
|
|
4152
4224
|
if (currentView === "locked-funds") {
|
|
4153
|
-
return /* @__PURE__ */ jsx(LockedFundsView, { onBack: () => handleViewChange("main")
|
|
4225
|
+
return /* @__PURE__ */ jsx(LockedFundsView, { onBack: () => handleViewChange("main") });
|
|
4154
4226
|
}
|
|
4155
4227
|
if (currentView === "balance-details") {
|
|
4156
|
-
return /* @__PURE__ */ jsx(BalanceDetailsView, { onBack: () => handleViewChange("main")
|
|
4228
|
+
return /* @__PURE__ */ jsx(BalanceDetailsView, { onBack: () => handleViewChange("main") });
|
|
4157
4229
|
}
|
|
4158
4230
|
if (currentView === "select-token") {
|
|
4159
4231
|
return /* @__PURE__ */ jsx(
|
|
4160
4232
|
TokenSelectorView,
|
|
4161
4233
|
{
|
|
4162
4234
|
onBack: () => handleViewChange("main"),
|
|
4163
|
-
onClose,
|
|
4164
4235
|
onSelect: handleTokenSelect,
|
|
4165
4236
|
selectedTokenId: selectedToken.id
|
|
4166
4237
|
}
|
|
4167
4238
|
);
|
|
4168
4239
|
}
|
|
4169
4240
|
return /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2 pb-4", children: [
|
|
4170
|
-
/* @__PURE__ */ jsx("div", { className: cn(
|
|
4241
|
+
/* @__PURE__ */ jsx("div", { className: cn(isInteractionPending && "pointer-events-none"), children: /* @__PURE__ */ jsx(
|
|
4171
4242
|
BalanceCards,
|
|
4172
4243
|
{
|
|
4173
4244
|
selectedToken,
|
|
4174
4245
|
onLockedFundsClick: () => handleViewChange("locked-funds"),
|
|
4175
4246
|
onBalanceClick: () => handleViewChange("balance-details"),
|
|
4176
4247
|
showLockedFunds,
|
|
4177
|
-
disabled:
|
|
4248
|
+
disabled: isInteractionPending
|
|
4178
4249
|
}
|
|
4179
4250
|
) }),
|
|
4180
|
-
/* @__PURE__ */ jsx("div", { className: cn(
|
|
4251
|
+
/* @__PURE__ */ jsx("div", { className: cn(isInteractionPending && "pointer-events-none"), children: /* @__PURE__ */ jsx(Tabs, { activeTab, onTabChange: setActiveTab, disabled: isInteractionPending }) }),
|
|
4181
4252
|
/* @__PURE__ */ jsx("div", { className: "bg-muted rounded-[10px] p-5", children: activeTab === "deposit" ? /* @__PURE__ */ jsx(
|
|
4182
4253
|
DepositForm,
|
|
4183
4254
|
{
|
|
4184
4255
|
selectedToken,
|
|
4185
4256
|
onTokenSelect: () => handleViewChange("select-token"),
|
|
4186
|
-
onPendingChange:
|
|
4257
|
+
onPendingChange: handlePendingChange,
|
|
4258
|
+
onUnsafeToCloseChange: handleCloseBlockedChange,
|
|
4187
4259
|
onSuccess: onDepositSuccess
|
|
4188
4260
|
}
|
|
4189
4261
|
) : /* @__PURE__ */ jsx(
|
|
@@ -4191,7 +4263,8 @@ function ModalBody({
|
|
|
4191
4263
|
{
|
|
4192
4264
|
selectedToken,
|
|
4193
4265
|
onTokenSelect: () => handleViewChange("select-token"),
|
|
4194
|
-
onPendingChange:
|
|
4266
|
+
onPendingChange: handlePendingChange,
|
|
4267
|
+
onUnsafeToCloseChange: handleCloseBlockedChange
|
|
4195
4268
|
}
|
|
4196
4269
|
) })
|
|
4197
4270
|
] }) });
|
|
@@ -4203,55 +4276,84 @@ function PrivanaModal({
|
|
|
4203
4276
|
defaultTab,
|
|
4204
4277
|
onDepositSuccess
|
|
4205
4278
|
}) {
|
|
4206
|
-
const [
|
|
4279
|
+
const [currentView, setCurrentView] = useState("main");
|
|
4207
4280
|
const titleId = useId();
|
|
4208
4281
|
const descId = useId();
|
|
4209
|
-
const
|
|
4210
|
-
|
|
4211
|
-
|
|
4212
|
-
}
|
|
4213
|
-
if (!isOpen) {
|
|
4214
|
-
onClose();
|
|
4215
|
-
}
|
|
4282
|
+
const [isCloseBlocked, setIsCloseBlocked] = useState(false);
|
|
4283
|
+
const handleClose = () => {
|
|
4284
|
+
if (!isCloseBlocked) onClose();
|
|
4216
4285
|
};
|
|
4217
|
-
return /* @__PURE__ */ jsx(
|
|
4218
|
-
|
|
4286
|
+
return /* @__PURE__ */ jsx(
|
|
4287
|
+
Dialog,
|
|
4219
4288
|
{
|
|
4220
|
-
|
|
4221
|
-
|
|
4222
|
-
|
|
4223
|
-
|
|
4224
|
-
|
|
4225
|
-
|
|
4226
|
-
|
|
4227
|
-
|
|
4228
|
-
|
|
4229
|
-
|
|
4230
|
-
|
|
4231
|
-
|
|
4232
|
-
|
|
4289
|
+
open,
|
|
4290
|
+
onOpenChange: (isOpen) => {
|
|
4291
|
+
if (!isOpen) handleClose();
|
|
4292
|
+
},
|
|
4293
|
+
children: /* @__PURE__ */ jsxs(
|
|
4294
|
+
DialogContent,
|
|
4295
|
+
{
|
|
4296
|
+
"data-privana": true,
|
|
4297
|
+
"data-view": currentView,
|
|
4298
|
+
showCloseButton: false,
|
|
4299
|
+
onInteractOutside: isCloseBlocked ? (e) => e.preventDefault() : void 0,
|
|
4300
|
+
onEscapeKeyDown: isCloseBlocked ? (e) => e.preventDefault() : void 0,
|
|
4301
|
+
className: "bg-card flex h-[596px] max-h-[95dvh] w-[560px] max-w-[95vw] flex-col gap-2 overflow-hidden rounded-2xl border-0 p-2 pb-[2.75rem]",
|
|
4302
|
+
"aria-labelledby": titleId,
|
|
4303
|
+
"aria-describedby": descId,
|
|
4304
|
+
children: [
|
|
4305
|
+
/* @__PURE__ */ jsx(
|
|
4233
4306
|
"button",
|
|
4234
4307
|
{
|
|
4235
|
-
|
|
4236
|
-
|
|
4308
|
+
"data-privana-close": true,
|
|
4309
|
+
onClick: handleClose,
|
|
4310
|
+
disabled: isCloseBlocked,
|
|
4311
|
+
"aria-label": "Close",
|
|
4312
|
+
className: cn(
|
|
4313
|
+
"absolute top-6 right-5 z-20 flex h-6 w-6 items-center justify-center transition-colors",
|
|
4314
|
+
isCloseBlocked ? "text-muted-foreground/40 cursor-not-allowed" : "text-muted-foreground hover:text-foreground cursor-pointer"
|
|
4315
|
+
),
|
|
4237
4316
|
children: /* @__PURE__ */ jsx(CloseIcon, {})
|
|
4238
4317
|
}
|
|
4318
|
+
),
|
|
4319
|
+
/* @__PURE__ */ jsxs(
|
|
4320
|
+
"div",
|
|
4321
|
+
{
|
|
4322
|
+
"data-privana-content": true,
|
|
4323
|
+
"data-view": currentView,
|
|
4324
|
+
className: "flex min-h-0 flex-1 flex-col gap-2",
|
|
4325
|
+
children: [
|
|
4326
|
+
/* @__PURE__ */ jsx(DialogTitle, { id: titleId, className: "sr-only", children: "Privana" }),
|
|
4327
|
+
/* @__PURE__ */ jsx(DialogDescription, { id: descId, className: "sr-only", children: "Deposit or withdraw tokens from your Privana" }),
|
|
4328
|
+
currentView === "main" && /* @__PURE__ */ jsx(DialogHeader, { children: /* @__PURE__ */ jsx("div", { className: "flex items-center px-5 py-4", children: /* @__PURE__ */ jsx("span", { className: "text-foreground text-xl leading-6 font-medium", children: "Privana" }) }) }),
|
|
4329
|
+
/* @__PURE__ */ jsx(
|
|
4330
|
+
ModalBody,
|
|
4331
|
+
{
|
|
4332
|
+
onCloseBlockedChange: setIsCloseBlocked,
|
|
4333
|
+
onViewChange: setCurrentView,
|
|
4334
|
+
showLockedFunds,
|
|
4335
|
+
defaultTab,
|
|
4336
|
+
onDepositSuccess
|
|
4337
|
+
}
|
|
4338
|
+
)
|
|
4339
|
+
]
|
|
4340
|
+
}
|
|
4341
|
+
),
|
|
4342
|
+
/* @__PURE__ */ jsx(
|
|
4343
|
+
"a",
|
|
4344
|
+
{
|
|
4345
|
+
"data-privana-footer": true,
|
|
4346
|
+
href: "https://privana.finance",
|
|
4347
|
+
target: "_blank",
|
|
4348
|
+
rel: "noopener noreferrer",
|
|
4349
|
+
"aria-label": "Powered by Privana"
|
|
4350
|
+
}
|
|
4239
4351
|
)
|
|
4240
|
-
]
|
|
4241
|
-
|
|
4242
|
-
|
|
4243
|
-
ModalBody,
|
|
4244
|
-
{
|
|
4245
|
-
onClose: isTransactionPending ? void 0 : onClose,
|
|
4246
|
-
onTransactionPendingChange: setIsTransactionPending,
|
|
4247
|
-
showLockedFunds,
|
|
4248
|
-
defaultTab,
|
|
4249
|
-
onDepositSuccess
|
|
4250
|
-
}
|
|
4251
|
-
)
|
|
4252
|
-
]
|
|
4352
|
+
]
|
|
4353
|
+
}
|
|
4354
|
+
)
|
|
4253
4355
|
}
|
|
4254
|
-
)
|
|
4356
|
+
);
|
|
4255
4357
|
}
|
|
4256
4358
|
function PrivanaInlineModal({
|
|
4257
4359
|
className,
|