@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.cjs
CHANGED
|
@@ -51,7 +51,7 @@ var config_default = {
|
|
|
51
51
|
chainId: 23295,
|
|
52
52
|
name: "Sapphire Testnet",
|
|
53
53
|
accountingContract: "0xaF8e5de153A584528B57DD4B9B0195956BBDF571",
|
|
54
|
-
apiUrl: "https://
|
|
54
|
+
apiUrl: "https://testnet.privana.finance"
|
|
55
55
|
},
|
|
56
56
|
mainnet: {
|
|
57
57
|
chainId: 23294,
|
|
@@ -1630,6 +1630,12 @@ function getAction(client, actionFn, name) {
|
|
|
1630
1630
|
function getChainId2(config) {
|
|
1631
1631
|
return config.state.chainId;
|
|
1632
1632
|
}
|
|
1633
|
+
async function getTransactionReceipt(config, parameters) {
|
|
1634
|
+
const { chainId, ...rest } = parameters;
|
|
1635
|
+
const client = config.getClient({ chainId });
|
|
1636
|
+
const action = getAction(client, actions$1.getTransactionReceipt, "getTransactionReceipt");
|
|
1637
|
+
return action(rest);
|
|
1638
|
+
}
|
|
1633
1639
|
async function waitForTransactionReceipt(config, parameters) {
|
|
1634
1640
|
const { chainId, timeout = 0, ...rest } = parameters;
|
|
1635
1641
|
const client = config.getClient({ chainId });
|
|
@@ -1710,6 +1716,36 @@ function useEnsureCorrectChain() {
|
|
|
1710
1716
|
}
|
|
1711
1717
|
|
|
1712
1718
|
// src/sdk/hooks/use-deposit.ts
|
|
1719
|
+
var STALE_MS = 30 * 60 * 1e3;
|
|
1720
|
+
function storageKey(address) {
|
|
1721
|
+
return `privana:pending-deposit:${address.toLowerCase()}`;
|
|
1722
|
+
}
|
|
1723
|
+
function savePendingDeposit(address, data) {
|
|
1724
|
+
try {
|
|
1725
|
+
sessionStorage.setItem(storageKey(address), JSON.stringify(data));
|
|
1726
|
+
} catch {
|
|
1727
|
+
}
|
|
1728
|
+
}
|
|
1729
|
+
function loadPendingDeposit(address) {
|
|
1730
|
+
try {
|
|
1731
|
+
const raw = sessionStorage.getItem(storageKey(address));
|
|
1732
|
+
if (!raw) return null;
|
|
1733
|
+
const data = JSON.parse(raw);
|
|
1734
|
+
if (Date.now() - data.savedAt > STALE_MS) {
|
|
1735
|
+
clearPendingDeposit(address);
|
|
1736
|
+
return null;
|
|
1737
|
+
}
|
|
1738
|
+
return data;
|
|
1739
|
+
} catch {
|
|
1740
|
+
return null;
|
|
1741
|
+
}
|
|
1742
|
+
}
|
|
1743
|
+
function clearPendingDeposit(address) {
|
|
1744
|
+
try {
|
|
1745
|
+
sessionStorage.removeItem(storageKey(address));
|
|
1746
|
+
} catch {
|
|
1747
|
+
}
|
|
1748
|
+
}
|
|
1713
1749
|
function useDeposit(options = {}) {
|
|
1714
1750
|
const { address } = wagmi.useAccount();
|
|
1715
1751
|
const { client, enabledTokens, getChainById: getChainById2 } = usePrivanaContext();
|
|
@@ -1777,13 +1813,19 @@ function useDeposit(options = {}) {
|
|
|
1777
1813
|
const isSendingTx = isWritingContract || isSendingNative;
|
|
1778
1814
|
const sendError = writeError ?? sendNativeError;
|
|
1779
1815
|
const { ensureCorrectChain } = useEnsureCorrectChain();
|
|
1816
|
+
const invalidateGeneration = react.useCallback(() => {
|
|
1817
|
+
generationRef.current++;
|
|
1818
|
+
}, []);
|
|
1780
1819
|
react.useEffect(() => {
|
|
1781
1820
|
return () => {
|
|
1821
|
+
invalidateGeneration();
|
|
1782
1822
|
if (pollIntervalRef.current) {
|
|
1783
1823
|
clearTimeout(pollIntervalRef.current);
|
|
1824
|
+
pollIntervalRef.current = null;
|
|
1784
1825
|
}
|
|
1785
1826
|
};
|
|
1786
|
-
}, []);
|
|
1827
|
+
}, [invalidateGeneration]);
|
|
1828
|
+
const resumedAddressRef = react.useRef(void 0);
|
|
1787
1829
|
const stopPolling = react.useCallback(() => {
|
|
1788
1830
|
if (pollIntervalRef.current) {
|
|
1789
1831
|
clearTimeout(pollIntervalRef.current);
|
|
@@ -1793,6 +1835,7 @@ function useDeposit(options = {}) {
|
|
|
1793
1835
|
const reset = react.useCallback(() => {
|
|
1794
1836
|
generationRef.current++;
|
|
1795
1837
|
stopPolling();
|
|
1838
|
+
if (address) clearPendingDeposit(address);
|
|
1796
1839
|
verificationContextRef.current = null;
|
|
1797
1840
|
setDepositAddress(null);
|
|
1798
1841
|
setTxHash(void 0);
|
|
@@ -1805,7 +1848,7 @@ function useDeposit(options = {}) {
|
|
|
1805
1848
|
addressMutation.reset();
|
|
1806
1849
|
resetWriteContract();
|
|
1807
1850
|
resetSendTransaction();
|
|
1808
|
-
}, [addressMutation, resetWriteContract, resetSendTransaction, stopPolling]);
|
|
1851
|
+
}, [address, addressMutation, resetWriteContract, resetSendTransaction, stopPolling]);
|
|
1809
1852
|
const runVerification = react.useCallback(
|
|
1810
1853
|
async (ctx, generation) => {
|
|
1811
1854
|
const isStale = () => generation !== generationRef.current;
|
|
@@ -1833,6 +1876,7 @@ function useDeposit(options = {}) {
|
|
|
1833
1876
|
if (triggerResult.status === "credited") {
|
|
1834
1877
|
setIsWaitingForProcessing(false);
|
|
1835
1878
|
verificationContextRef.current = null;
|
|
1879
|
+
if (address) clearPendingDeposit(address);
|
|
1836
1880
|
queryClient.invalidateQueries({ queryKey: ["accounting-balance"] });
|
|
1837
1881
|
queryClient.invalidateQueries({ queryKey: ["accounting-history"] });
|
|
1838
1882
|
onCreditedRef.current?.(hash, triggerResult);
|
|
@@ -1866,6 +1910,7 @@ function useDeposit(options = {}) {
|
|
|
1866
1910
|
stopPolling();
|
|
1867
1911
|
setIsWaitingForProcessing(false);
|
|
1868
1912
|
verificationContextRef.current = null;
|
|
1913
|
+
if (address) clearPendingDeposit(address);
|
|
1869
1914
|
queryClient.invalidateQueries({ queryKey: ["accounting-balance"] });
|
|
1870
1915
|
queryClient.invalidateQueries({ queryKey: ["accounting-history"] });
|
|
1871
1916
|
onCreditedRef.current?.(hash, result);
|
|
@@ -1905,7 +1950,7 @@ function useDeposit(options = {}) {
|
|
|
1905
1950
|
);
|
|
1906
1951
|
}
|
|
1907
1952
|
},
|
|
1908
|
-
[client, executePrivateRead, pollInterval, pollTimeout, queryClient, stopPolling]
|
|
1953
|
+
[address, client, executePrivateRead, pollInterval, pollTimeout, queryClient, stopPolling]
|
|
1909
1954
|
);
|
|
1910
1955
|
const retryVerification = react.useCallback(async () => {
|
|
1911
1956
|
const ctx = verificationContextRef.current;
|
|
@@ -1917,6 +1962,55 @@ function useDeposit(options = {}) {
|
|
|
1917
1962
|
const generation = generationRef.current;
|
|
1918
1963
|
await runVerification(ctx, generation);
|
|
1919
1964
|
}, [runVerification, stopPolling]);
|
|
1965
|
+
react.useEffect(() => {
|
|
1966
|
+
if (!address || resumedAddressRef.current === address) return;
|
|
1967
|
+
const persisted = loadPendingDeposit(address);
|
|
1968
|
+
if (!persisted) return;
|
|
1969
|
+
resumedAddressRef.current = address;
|
|
1970
|
+
const hash = persisted.txHash;
|
|
1971
|
+
setTxHash(hash);
|
|
1972
|
+
setDepositAddress(persisted.depositAddress);
|
|
1973
|
+
setIsWaitingForConfirmation(true);
|
|
1974
|
+
const ctx = {
|
|
1975
|
+
hash,
|
|
1976
|
+
chainId: persisted.chainId,
|
|
1977
|
+
amount: BigInt(persisted.amount)
|
|
1978
|
+
};
|
|
1979
|
+
verificationContextRef.current = ctx;
|
|
1980
|
+
const generation = ++generationRef.current;
|
|
1981
|
+
const isStale = () => generation !== generationRef.current;
|
|
1982
|
+
(async () => {
|
|
1983
|
+
try {
|
|
1984
|
+
let confirmed = false;
|
|
1985
|
+
try {
|
|
1986
|
+
await getTransactionReceipt(config, { hash, chainId: persisted.chainId });
|
|
1987
|
+
confirmed = true;
|
|
1988
|
+
} catch {
|
|
1989
|
+
}
|
|
1990
|
+
if (!confirmed) {
|
|
1991
|
+
await waitForTransactionReceipt(config, {
|
|
1992
|
+
hash,
|
|
1993
|
+
chainId: persisted.chainId,
|
|
1994
|
+
confirmations
|
|
1995
|
+
});
|
|
1996
|
+
}
|
|
1997
|
+
if (isStale()) return;
|
|
1998
|
+
setIsWaitingForConfirmation(false);
|
|
1999
|
+
onDepositSuccessRef.current?.(hash);
|
|
2000
|
+
queryClient.invalidateQueries({ queryKey: ["readContract"] });
|
|
2001
|
+
await runVerification(ctx, generation);
|
|
2002
|
+
} catch (err) {
|
|
2003
|
+
if (isStale()) return;
|
|
2004
|
+
setIsWaitingForConfirmation(false);
|
|
2005
|
+
stopPolling();
|
|
2006
|
+
const error2 = err instanceof Error ? err : new Error("Deposit verification failed");
|
|
2007
|
+
setIsWaitingForProcessing(false);
|
|
2008
|
+
setDepositError(error2);
|
|
2009
|
+
setVerificationFailed(true);
|
|
2010
|
+
onErrorRef.current?.(error2);
|
|
2011
|
+
}
|
|
2012
|
+
})();
|
|
2013
|
+
}, [address, config, confirmations, queryClient, runVerification, stopPolling]);
|
|
1920
2014
|
const deposit = react.useCallback(
|
|
1921
2015
|
async (params) => {
|
|
1922
2016
|
if (verificationContextRef.current) {
|
|
@@ -1973,10 +2067,21 @@ function useDeposit(options = {}) {
|
|
|
1973
2067
|
amount: params.amount
|
|
1974
2068
|
};
|
|
1975
2069
|
verificationContextRef.current = ctx;
|
|
2070
|
+
savePendingDeposit(address, {
|
|
2071
|
+
txHash: hash,
|
|
2072
|
+
chainId: sourceChain.id,
|
|
2073
|
+
amount: params.amount.toString(),
|
|
2074
|
+
depositAddress: addrResponse,
|
|
2075
|
+
savedAt: Date.now()
|
|
2076
|
+
});
|
|
1976
2077
|
try {
|
|
1977
2078
|
setIsWaitingForConfirmation(true);
|
|
1978
2079
|
try {
|
|
1979
|
-
await waitForTransactionReceipt(config, {
|
|
2080
|
+
await waitForTransactionReceipt(config, {
|
|
2081
|
+
hash,
|
|
2082
|
+
chainId: sourceChain.id,
|
|
2083
|
+
confirmations
|
|
2084
|
+
});
|
|
1980
2085
|
} finally {
|
|
1981
2086
|
if (!isStale()) setIsWaitingForConfirmation(false);
|
|
1982
2087
|
}
|
|
@@ -3174,6 +3279,7 @@ function DepositForm({
|
|
|
3174
3279
|
selectedToken,
|
|
3175
3280
|
onTokenSelect,
|
|
3176
3281
|
onPendingChange,
|
|
3282
|
+
onUnsafeToCloseChange,
|
|
3177
3283
|
onSuccess
|
|
3178
3284
|
}) {
|
|
3179
3285
|
const { isConnected, address } = wagmi.useAccount();
|
|
@@ -3202,7 +3308,7 @@ function DepositForm({
|
|
|
3202
3308
|
}
|
|
3203
3309
|
});
|
|
3204
3310
|
const walletBalance = isNative ? nativeBalanceData?.value : erc20Balance;
|
|
3205
|
-
const formattedWalletBalance = walletBalance ? formatTokenAmount(walletBalance.toString(), selectedToken.decimals) : "0";
|
|
3311
|
+
const formattedWalletBalance = walletBalance ? formatTokenAmount(walletBalance.toString(), selectedToken.decimals) : "0.00";
|
|
3206
3312
|
const handleMaxClick = () => {
|
|
3207
3313
|
if (formattedWalletBalance && parseFloat(formattedWalletBalance) > 0) {
|
|
3208
3314
|
setAmount(formattedWalletBalance.replace(/[\s\u2009]/g, ""));
|
|
@@ -3269,6 +3375,9 @@ function DepositForm({
|
|
|
3269
3375
|
react.useEffect(() => {
|
|
3270
3376
|
onPendingChange?.(isPending && !cancelled);
|
|
3271
3377
|
}, [isPending, cancelled, onPendingChange]);
|
|
3378
|
+
react.useEffect(() => {
|
|
3379
|
+
onUnsafeToCloseChange?.((isGettingAddress || isSendingTransaction) && !cancelled);
|
|
3380
|
+
}, [isGettingAddress, isSendingTransaction, cancelled, onUnsafeToCloseChange]);
|
|
3272
3381
|
const handleCancel = () => {
|
|
3273
3382
|
setCancelled(true);
|
|
3274
3383
|
reset();
|
|
@@ -3432,7 +3541,12 @@ function DepositForm({
|
|
|
3432
3541
|
)
|
|
3433
3542
|
] });
|
|
3434
3543
|
}
|
|
3435
|
-
function WithdrawForm({
|
|
3544
|
+
function WithdrawForm({
|
|
3545
|
+
selectedToken,
|
|
3546
|
+
onTokenSelect,
|
|
3547
|
+
onPendingChange,
|
|
3548
|
+
onUnsafeToCloseChange
|
|
3549
|
+
}) {
|
|
3436
3550
|
const { isConnected, address } = wagmi.useAccount();
|
|
3437
3551
|
const { chains, getChainById: getChainById2 } = usePrivanaContext();
|
|
3438
3552
|
const [amount, setAmount] = react.useState("");
|
|
@@ -3485,8 +3599,10 @@ function WithdrawForm({ selectedToken, onTokenSelect, onPendingChange }) {
|
|
|
3485
3599
|
}
|
|
3486
3600
|
}, [error]);
|
|
3487
3601
|
react.useEffect(() => {
|
|
3488
|
-
|
|
3489
|
-
|
|
3602
|
+
const pending = isPending && !cancelled;
|
|
3603
|
+
onPendingChange?.(pending);
|
|
3604
|
+
onUnsafeToCloseChange?.(pending);
|
|
3605
|
+
}, [isPending, cancelled, onPendingChange, onUnsafeToCloseChange]);
|
|
3490
3606
|
const handleCancel = () => {
|
|
3491
3607
|
setCancelled(true);
|
|
3492
3608
|
reset();
|
|
@@ -3645,9 +3761,6 @@ function CloseIcon() {
|
|
|
3645
3761
|
}
|
|
3646
3762
|
) });
|
|
3647
3763
|
}
|
|
3648
|
-
function SearchIcon() {
|
|
3649
|
-
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-3 w-3 rounded-full border-[1.5px] border-current" });
|
|
3650
|
-
}
|
|
3651
3764
|
function ChevronRight() {
|
|
3652
3765
|
return /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "10", height: "5", viewBox: "0 0 12 6", className: "-rotate-90", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3653
3766
|
"path",
|
|
@@ -3708,7 +3821,7 @@ function BalanceCards({
|
|
|
3708
3821
|
});
|
|
3709
3822
|
const { totalLocked, isLoading: lockedLoading } = useLockedFunds({ enabled: showLockedFunds });
|
|
3710
3823
|
const formattedBalance = formatTokenAmount(balanceWei, selectedToken.decimals);
|
|
3711
|
-
const formattedLocked = showLockedFunds ? formatTokenAmount(String(totalLocked), selectedToken.decimals) : "0";
|
|
3824
|
+
const formattedLocked = showLockedFunds ? formatTokenAmount(String(totalLocked), selectedToken.decimals) : "0.00";
|
|
3712
3825
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex gap-2", disabled && "opacity-50"), children: [
|
|
3713
3826
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
3714
3827
|
"button",
|
|
@@ -3771,7 +3884,7 @@ function Tabs({
|
|
|
3771
3884
|
"div",
|
|
3772
3885
|
{
|
|
3773
3886
|
className: cn(
|
|
3774
|
-
"bg-input absolute top-1 bottom-1 left-1 w-[calc(50%-
|
|
3887
|
+
"bg-input absolute top-1 bottom-1 left-1 w-[calc(50%-8px)] rounded-md transition-transform duration-200",
|
|
3775
3888
|
activeTab === "withdraw" && "translate-x-[calc(100%+8px)]"
|
|
3776
3889
|
)
|
|
3777
3890
|
}
|
|
@@ -3806,7 +3919,7 @@ function Tabs({
|
|
|
3806
3919
|
}
|
|
3807
3920
|
);
|
|
3808
3921
|
}
|
|
3809
|
-
function LockedFundsView({ onBack
|
|
3922
|
+
function LockedFundsView({ onBack }) {
|
|
3810
3923
|
const { getTokenById } = usePrivanaContext();
|
|
3811
3924
|
const { locks, isLoading } = useLockedFunds();
|
|
3812
3925
|
const { unlockFunds, unlockAllExpired, isPending } = useUnlockFunds();
|
|
@@ -3839,27 +3952,17 @@ function LockedFundsView({ onBack, onClose }) {
|
|
|
3839
3952
|
};
|
|
3840
3953
|
const expiredCount = locks.filter((l) => l.is_expired).length;
|
|
3841
3954
|
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
3842
|
-
/* @__PURE__ */ jsxRuntime.
|
|
3843
|
-
/* @__PURE__ */ jsxRuntime.
|
|
3844
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3845
|
-
"button",
|
|
3846
|
-
{
|
|
3847
|
-
onClick: onBack,
|
|
3848
|
-
className: "text-muted-foreground hover:text-foreground flex h-6 w-6 cursor-pointer items-center justify-center transition-colors",
|
|
3849
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(ChevronLeft, {})
|
|
3850
|
-
}
|
|
3851
|
-
),
|
|
3852
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-foreground text-xl leading-6 font-medium", children: "Locked Funds" })
|
|
3853
|
-
] }),
|
|
3854
|
-
onClose && /* @__PURE__ */ jsxRuntime.jsx(
|
|
3955
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-between px-5 py-4", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
3956
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3855
3957
|
"button",
|
|
3856
3958
|
{
|
|
3857
|
-
onClick:
|
|
3858
|
-
className: "text-muted-foreground hover:text-foreground flex h-6 w-6 cursor-pointer items-center justify-center transition-colors",
|
|
3859
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3959
|
+
onClick: onBack,
|
|
3960
|
+
className: "text-muted-foreground hover:text-foreground -ml-2 flex h-6 w-6 cursor-pointer items-center justify-center transition-colors",
|
|
3961
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(ChevronLeft, {})
|
|
3860
3962
|
}
|
|
3861
|
-
)
|
|
3862
|
-
|
|
3963
|
+
),
|
|
3964
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-foreground text-xl leading-6 font-medium", children: "Locked Funds" })
|
|
3965
|
+
] }) }),
|
|
3863
3966
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-muted flex min-h-0 flex-1 flex-col rounded-[10px] p-2", children: [
|
|
3864
3967
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 overflow-y-auto", children: isLoading ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-2 p-3", children: [1, 2].map((i) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex animate-pulse items-center gap-3 rounded-lg p-3", children: [
|
|
3865
3968
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "bg-secondary h-10 w-10 rounded-full" }),
|
|
@@ -3944,34 +4047,24 @@ function BalanceTokenRow({ token }) {
|
|
|
3944
4047
|
isLoading ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "bg-secondary h-4 w-16 animate-pulse rounded" }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground text-sm", children: formattedBalance })
|
|
3945
4048
|
] });
|
|
3946
4049
|
}
|
|
3947
|
-
function BalanceDetailsView({ onBack
|
|
4050
|
+
function BalanceDetailsView({ onBack }) {
|
|
3948
4051
|
const { enabledTokens, chains } = usePrivanaContext();
|
|
3949
4052
|
const [selectedChainId, setSelectedChainId] = react.useState(chains[0]?.id ?? 84532);
|
|
3950
4053
|
const chainTokens = react.useMemo(() => {
|
|
3951
4054
|
return enabledTokens.filter((t) => t.chainId === selectedChainId);
|
|
3952
4055
|
}, [enabledTokens, selectedChainId]);
|
|
3953
4056
|
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
3954
|
-
/* @__PURE__ */ jsxRuntime.
|
|
3955
|
-
/* @__PURE__ */ jsxRuntime.
|
|
3956
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3957
|
-
"button",
|
|
3958
|
-
{
|
|
3959
|
-
onClick: onBack,
|
|
3960
|
-
className: "text-muted-foreground hover:text-foreground flex h-6 w-6 cursor-pointer items-center justify-center transition-colors",
|
|
3961
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(ChevronLeft, {})
|
|
3962
|
-
}
|
|
3963
|
-
),
|
|
3964
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-foreground text-xl leading-6 font-medium", children: "Token Balances" })
|
|
3965
|
-
] }),
|
|
3966
|
-
onClose && /* @__PURE__ */ jsxRuntime.jsx(
|
|
4057
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-between px-5 py-4", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
4058
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3967
4059
|
"button",
|
|
3968
4060
|
{
|
|
3969
|
-
onClick:
|
|
3970
|
-
className: "text-muted-foreground hover:text-foreground flex h-6 w-6 cursor-pointer items-center justify-center transition-colors",
|
|
3971
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4061
|
+
onClick: onBack,
|
|
4062
|
+
className: "text-muted-foreground hover:text-foreground -ml-2 flex h-6 w-6 cursor-pointer items-center justify-center transition-colors",
|
|
4063
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(ChevronLeft, {})
|
|
3972
4064
|
}
|
|
3973
|
-
)
|
|
3974
|
-
|
|
4065
|
+
),
|
|
4066
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-foreground text-xl leading-6 font-medium", children: "Token Balances" })
|
|
4067
|
+
] }) }),
|
|
3975
4068
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-h-0 flex-1 gap-2", children: [
|
|
3976
4069
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-muted flex flex-1 flex-col overflow-hidden rounded-[10px] p-2", children: [
|
|
3977
4070
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-4 pt-4 pb-2", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground text-sm", children: "Network" }) }),
|
|
@@ -4041,48 +4134,30 @@ function TokenRow({
|
|
|
4041
4134
|
}
|
|
4042
4135
|
function TokenSelectorView({
|
|
4043
4136
|
onBack,
|
|
4044
|
-
onClose,
|
|
4045
4137
|
onSelect,
|
|
4046
4138
|
selectedTokenId
|
|
4047
4139
|
}) {
|
|
4048
|
-
const [tokenSearch, setTokenSearch] = react.useState("");
|
|
4049
4140
|
const { enabledTokens, chains } = usePrivanaContext();
|
|
4050
4141
|
const [selectedChainId, setSelectedChainId] = react.useState(chains[0]?.id ?? 84532);
|
|
4051
4142
|
const chainTokens = react.useMemo(() => {
|
|
4052
4143
|
return enabledTokens.filter((t) => t.chainId === selectedChainId);
|
|
4053
4144
|
}, [enabledTokens, selectedChainId]);
|
|
4054
|
-
const filteredTokens = react.useMemo(() => {
|
|
4055
|
-
if (!tokenSearch) return chainTokens;
|
|
4056
|
-
return chainTokens.filter(
|
|
4057
|
-
(t) => t.symbol.toLowerCase().includes(tokenSearch.toLowerCase()) || t.name.toLowerCase().includes(tokenSearch.toLowerCase())
|
|
4058
|
-
);
|
|
4059
|
-
}, [tokenSearch, chainTokens]);
|
|
4060
4145
|
const handleTokenSelect = (token) => {
|
|
4061
4146
|
onSelect(token);
|
|
4062
4147
|
onBack();
|
|
4063
4148
|
};
|
|
4064
4149
|
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
4065
|
-
/* @__PURE__ */ jsxRuntime.
|
|
4066
|
-
/* @__PURE__ */ jsxRuntime.
|
|
4067
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4068
|
-
"button",
|
|
4069
|
-
{
|
|
4070
|
-
onClick: onBack,
|
|
4071
|
-
className: "text-muted-foreground hover:text-foreground flex h-6 w-6 cursor-pointer items-center justify-center transition-colors",
|
|
4072
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(ChevronLeft, {})
|
|
4073
|
-
}
|
|
4074
|
-
),
|
|
4075
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-foreground text-xl leading-6 font-medium", children: "Select Token" })
|
|
4076
|
-
] }),
|
|
4077
|
-
onClose && /* @__PURE__ */ jsxRuntime.jsx(
|
|
4150
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-between px-5 py-4", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
4151
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4078
4152
|
"button",
|
|
4079
4153
|
{
|
|
4080
|
-
onClick:
|
|
4081
|
-
className: "text-muted-foreground hover:text-foreground flex h-6 w-6 cursor-pointer items-center justify-center transition-colors",
|
|
4082
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4154
|
+
onClick: onBack,
|
|
4155
|
+
className: "text-muted-foreground hover:text-foreground -ml-2 flex h-6 w-6 cursor-pointer items-center justify-center transition-colors",
|
|
4156
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(ChevronLeft, {})
|
|
4083
4157
|
}
|
|
4084
|
-
)
|
|
4085
|
-
|
|
4158
|
+
),
|
|
4159
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-foreground text-xl leading-6 font-medium", children: "Select Token" })
|
|
4160
|
+
] }) }),
|
|
4086
4161
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-h-0 flex-1 gap-2", children: [
|
|
4087
4162
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-muted flex flex-1 flex-col overflow-hidden rounded-[10px] p-2", children: [
|
|
4088
4163
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-4 pt-4 pb-2", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground text-sm", children: "Network" }) }),
|
|
@@ -4106,23 +4181,8 @@ function TokenSelectorView({
|
|
|
4106
4181
|
}) })
|
|
4107
4182
|
] }),
|
|
4108
4183
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-muted flex flex-[2] flex-col overflow-hidden rounded-[10px] p-2", children: [
|
|
4109
|
-
/* @__PURE__ */ jsxRuntime.
|
|
4110
|
-
|
|
4111
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-3", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border-border bg-input flex items-center gap-2.5 rounded-lg border px-3 py-2.5", children: [
|
|
4112
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: /* @__PURE__ */ jsxRuntime.jsx(SearchIcon, {}) }),
|
|
4113
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4114
|
-
"input",
|
|
4115
|
-
{
|
|
4116
|
-
type: "text",
|
|
4117
|
-
placeholder: "Search",
|
|
4118
|
-
value: tokenSearch,
|
|
4119
|
-
onChange: (e) => setTokenSearch(e.target.value),
|
|
4120
|
-
className: "text-foreground placeholder:text-muted-foreground flex-1 bg-transparent text-sm outline-none"
|
|
4121
|
-
}
|
|
4122
|
-
)
|
|
4123
|
-
] }) })
|
|
4124
|
-
] }),
|
|
4125
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-2 flex-1 overflow-y-auto", children: filteredTokens.map((token) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
4184
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-4 pt-4 pb-2", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground text-sm", children: "Token" }) }),
|
|
4185
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-2 flex-1 overflow-y-auto", children: chainTokens.map((token) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
4126
4186
|
TokenRow,
|
|
4127
4187
|
{
|
|
4128
4188
|
token,
|
|
@@ -4136,9 +4196,8 @@ function TokenSelectorView({
|
|
|
4136
4196
|
] });
|
|
4137
4197
|
}
|
|
4138
4198
|
function ModalBody({
|
|
4139
|
-
onClose,
|
|
4140
4199
|
onViewChange,
|
|
4141
|
-
|
|
4200
|
+
onCloseBlockedChange,
|
|
4142
4201
|
showLockedFunds = true,
|
|
4143
4202
|
defaultTab = "deposit",
|
|
4144
4203
|
onDepositSuccess
|
|
@@ -4147,65 +4206,78 @@ function ModalBody({
|
|
|
4147
4206
|
const [selectedToken, setSelectedToken] = react.useState(defaultToken);
|
|
4148
4207
|
const [activeTab, setActiveTab] = react.useState(defaultTab);
|
|
4149
4208
|
const [currentView, setCurrentView] = react.useState("main");
|
|
4150
|
-
const [
|
|
4209
|
+
const [isInteractionPending, setIsInteractionPending] = react.useState(false);
|
|
4151
4210
|
react.useEffect(() => {
|
|
4152
4211
|
if (!selectedToken && defaultToken) {
|
|
4153
4212
|
setSelectedToken(defaultToken);
|
|
4154
4213
|
}
|
|
4155
4214
|
}, [selectedToken, defaultToken]);
|
|
4156
|
-
const
|
|
4157
|
-
|
|
4158
|
-
|
|
4215
|
+
const handlePendingChange = (isPending) => {
|
|
4216
|
+
setIsInteractionPending(isPending);
|
|
4217
|
+
};
|
|
4218
|
+
const handleCloseBlockedChange = (isBlocked) => {
|
|
4219
|
+
onCloseBlockedChange?.(isBlocked);
|
|
4159
4220
|
};
|
|
4160
4221
|
const handleViewChange = (view) => {
|
|
4161
|
-
|
|
4162
|
-
|
|
4222
|
+
const update = () => {
|
|
4223
|
+
setCurrentView(view);
|
|
4224
|
+
onViewChange?.(view);
|
|
4225
|
+
};
|
|
4226
|
+
if (typeof document !== "undefined" && typeof document.startViewTransition === "function") {
|
|
4227
|
+
document.documentElement.dataset.privanaVtDir = view === "main" ? "back" : "forward";
|
|
4228
|
+
const transition = document.startViewTransition(update);
|
|
4229
|
+
transition.finished.then(() => {
|
|
4230
|
+
delete document.documentElement.dataset.privanaVtDir;
|
|
4231
|
+
});
|
|
4232
|
+
} else {
|
|
4233
|
+
update();
|
|
4234
|
+
}
|
|
4163
4235
|
};
|
|
4164
4236
|
const handleTokenSelect = (token) => {
|
|
4165
4237
|
setSelectedToken(token);
|
|
4166
4238
|
};
|
|
4167
4239
|
if (tokensStatus === "loading" || !selectedToken) {
|
|
4168
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2
|
|
4240
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2", children: [
|
|
4169
4241
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "bg-secondary h-25 animate-pulse rounded-[10px]" }),
|
|
4170
4242
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "bg-secondary h-11 animate-pulse rounded-[10px]" }),
|
|
4171
4243
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "bg-secondary h-50 animate-pulse rounded-[10px]" })
|
|
4172
4244
|
] });
|
|
4173
4245
|
}
|
|
4174
4246
|
if (currentView === "locked-funds") {
|
|
4175
|
-
return /* @__PURE__ */ jsxRuntime.jsx(LockedFundsView, { onBack: () => handleViewChange("main")
|
|
4247
|
+
return /* @__PURE__ */ jsxRuntime.jsx(LockedFundsView, { onBack: () => handleViewChange("main") });
|
|
4176
4248
|
}
|
|
4177
4249
|
if (currentView === "balance-details") {
|
|
4178
|
-
return /* @__PURE__ */ jsxRuntime.jsx(BalanceDetailsView, { onBack: () => handleViewChange("main")
|
|
4250
|
+
return /* @__PURE__ */ jsxRuntime.jsx(BalanceDetailsView, { onBack: () => handleViewChange("main") });
|
|
4179
4251
|
}
|
|
4180
4252
|
if (currentView === "select-token") {
|
|
4181
4253
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
4182
4254
|
TokenSelectorView,
|
|
4183
4255
|
{
|
|
4184
4256
|
onBack: () => handleViewChange("main"),
|
|
4185
|
-
onClose,
|
|
4186
4257
|
onSelect: handleTokenSelect,
|
|
4187
4258
|
selectedTokenId: selectedToken.id
|
|
4188
4259
|
}
|
|
4189
4260
|
);
|
|
4190
4261
|
}
|
|
4191
4262
|
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2 pb-4", children: [
|
|
4192
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: cn(
|
|
4263
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: cn(isInteractionPending && "pointer-events-none"), children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4193
4264
|
BalanceCards,
|
|
4194
4265
|
{
|
|
4195
4266
|
selectedToken,
|
|
4196
4267
|
onLockedFundsClick: () => handleViewChange("locked-funds"),
|
|
4197
4268
|
onBalanceClick: () => handleViewChange("balance-details"),
|
|
4198
4269
|
showLockedFunds,
|
|
4199
|
-
disabled:
|
|
4270
|
+
disabled: isInteractionPending
|
|
4200
4271
|
}
|
|
4201
4272
|
) }),
|
|
4202
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: cn(
|
|
4273
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: cn(isInteractionPending && "pointer-events-none"), children: /* @__PURE__ */ jsxRuntime.jsx(Tabs, { activeTab, onTabChange: setActiveTab, disabled: isInteractionPending }) }),
|
|
4203
4274
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "bg-muted rounded-[10px] p-5", children: activeTab === "deposit" ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
4204
4275
|
DepositForm,
|
|
4205
4276
|
{
|
|
4206
4277
|
selectedToken,
|
|
4207
4278
|
onTokenSelect: () => handleViewChange("select-token"),
|
|
4208
|
-
onPendingChange:
|
|
4279
|
+
onPendingChange: handlePendingChange,
|
|
4280
|
+
onUnsafeToCloseChange: handleCloseBlockedChange,
|
|
4209
4281
|
onSuccess: onDepositSuccess
|
|
4210
4282
|
}
|
|
4211
4283
|
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -4213,7 +4285,8 @@ function ModalBody({
|
|
|
4213
4285
|
{
|
|
4214
4286
|
selectedToken,
|
|
4215
4287
|
onTokenSelect: () => handleViewChange("select-token"),
|
|
4216
|
-
onPendingChange:
|
|
4288
|
+
onPendingChange: handlePendingChange,
|
|
4289
|
+
onUnsafeToCloseChange: handleCloseBlockedChange
|
|
4217
4290
|
}
|
|
4218
4291
|
) })
|
|
4219
4292
|
] }) });
|
|
@@ -4225,55 +4298,84 @@ function PrivanaModal({
|
|
|
4225
4298
|
defaultTab,
|
|
4226
4299
|
onDepositSuccess
|
|
4227
4300
|
}) {
|
|
4228
|
-
const [
|
|
4301
|
+
const [currentView, setCurrentView] = react.useState("main");
|
|
4229
4302
|
const titleId = react.useId();
|
|
4230
4303
|
const descId = react.useId();
|
|
4231
|
-
const
|
|
4232
|
-
|
|
4233
|
-
|
|
4234
|
-
}
|
|
4235
|
-
if (!isOpen) {
|
|
4236
|
-
onClose();
|
|
4237
|
-
}
|
|
4304
|
+
const [isCloseBlocked, setIsCloseBlocked] = react.useState(false);
|
|
4305
|
+
const handleClose = () => {
|
|
4306
|
+
if (!isCloseBlocked) onClose();
|
|
4238
4307
|
};
|
|
4239
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
4240
|
-
|
|
4308
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
4309
|
+
Dialog,
|
|
4241
4310
|
{
|
|
4242
|
-
|
|
4243
|
-
|
|
4244
|
-
|
|
4245
|
-
|
|
4246
|
-
|
|
4247
|
-
|
|
4248
|
-
|
|
4249
|
-
|
|
4250
|
-
|
|
4251
|
-
|
|
4252
|
-
|
|
4253
|
-
|
|
4254
|
-
|
|
4311
|
+
open,
|
|
4312
|
+
onOpenChange: (isOpen) => {
|
|
4313
|
+
if (!isOpen) handleClose();
|
|
4314
|
+
},
|
|
4315
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4316
|
+
DialogContent,
|
|
4317
|
+
{
|
|
4318
|
+
"data-privana": true,
|
|
4319
|
+
"data-view": currentView,
|
|
4320
|
+
showCloseButton: false,
|
|
4321
|
+
onInteractOutside: isCloseBlocked ? (e) => e.preventDefault() : void 0,
|
|
4322
|
+
onEscapeKeyDown: isCloseBlocked ? (e) => e.preventDefault() : void 0,
|
|
4323
|
+
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]",
|
|
4324
|
+
"aria-labelledby": titleId,
|
|
4325
|
+
"aria-describedby": descId,
|
|
4326
|
+
children: [
|
|
4327
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4255
4328
|
"button",
|
|
4256
4329
|
{
|
|
4257
|
-
|
|
4258
|
-
|
|
4330
|
+
"data-privana-close": true,
|
|
4331
|
+
onClick: handleClose,
|
|
4332
|
+
disabled: isCloseBlocked,
|
|
4333
|
+
"aria-label": "Close",
|
|
4334
|
+
className: cn(
|
|
4335
|
+
"absolute top-6 right-5 z-20 flex h-6 w-6 items-center justify-center transition-colors",
|
|
4336
|
+
isCloseBlocked ? "text-muted-foreground/40 cursor-not-allowed" : "text-muted-foreground hover:text-foreground cursor-pointer"
|
|
4337
|
+
),
|
|
4259
4338
|
children: /* @__PURE__ */ jsxRuntime.jsx(CloseIcon, {})
|
|
4260
4339
|
}
|
|
4340
|
+
),
|
|
4341
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
4342
|
+
"div",
|
|
4343
|
+
{
|
|
4344
|
+
"data-privana-content": true,
|
|
4345
|
+
"data-view": currentView,
|
|
4346
|
+
className: "flex min-h-0 flex-1 flex-col gap-2",
|
|
4347
|
+
children: [
|
|
4348
|
+
/* @__PURE__ */ jsxRuntime.jsx(DialogTitle, { id: titleId, className: "sr-only", children: "Privana" }),
|
|
4349
|
+
/* @__PURE__ */ jsxRuntime.jsx(DialogDescription, { id: descId, className: "sr-only", children: "Deposit or withdraw tokens from your Privana" }),
|
|
4350
|
+
currentView === "main" && /* @__PURE__ */ jsxRuntime.jsx(DialogHeader, { children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center px-5 py-4", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-foreground text-xl leading-6 font-medium", children: "Privana" }) }) }),
|
|
4351
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4352
|
+
ModalBody,
|
|
4353
|
+
{
|
|
4354
|
+
onCloseBlockedChange: setIsCloseBlocked,
|
|
4355
|
+
onViewChange: setCurrentView,
|
|
4356
|
+
showLockedFunds,
|
|
4357
|
+
defaultTab,
|
|
4358
|
+
onDepositSuccess
|
|
4359
|
+
}
|
|
4360
|
+
)
|
|
4361
|
+
]
|
|
4362
|
+
}
|
|
4363
|
+
),
|
|
4364
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4365
|
+
"a",
|
|
4366
|
+
{
|
|
4367
|
+
"data-privana-footer": true,
|
|
4368
|
+
href: "https://privana.finance",
|
|
4369
|
+
target: "_blank",
|
|
4370
|
+
rel: "noopener noreferrer",
|
|
4371
|
+
"aria-label": "Powered by Privana"
|
|
4372
|
+
}
|
|
4261
4373
|
)
|
|
4262
|
-
]
|
|
4263
|
-
|
|
4264
|
-
|
|
4265
|
-
ModalBody,
|
|
4266
|
-
{
|
|
4267
|
-
onClose: isTransactionPending ? void 0 : onClose,
|
|
4268
|
-
onTransactionPendingChange: setIsTransactionPending,
|
|
4269
|
-
showLockedFunds,
|
|
4270
|
-
defaultTab,
|
|
4271
|
-
onDepositSuccess
|
|
4272
|
-
}
|
|
4273
|
-
)
|
|
4274
|
-
]
|
|
4374
|
+
]
|
|
4375
|
+
}
|
|
4376
|
+
)
|
|
4275
4377
|
}
|
|
4276
|
-
)
|
|
4378
|
+
);
|
|
4277
4379
|
}
|
|
4278
4380
|
function PrivanaInlineModal({
|
|
4279
4381
|
className,
|