diff --git a/apps/app/app/content.tsx b/apps/app/app/content.tsx
index 1c95cd6c..b84fa98f 100644
--- a/apps/app/app/content.tsx
+++ b/apps/app/app/content.tsx
@@ -1,11 +1,12 @@
'use client'
import {Box, Divider, Grid, Stack, Typography} from '@mui/material'
+import {toCurrency} from '@phala/lib'
import phaIcon from '@phala/ui/icons/asset/pha.png'
import vphaIcon from '@phala/ui/icons/asset/vpha.png'
import {useAppKitAccount, useAppKitNetwork} from '@reown/appkit/react'
import Decimal from 'decimal.js'
-import {useMemo} from 'react'
+import {useCallback, useMemo} from 'react'
import {erc20Abi, formatUnits} from 'viem'
import {mainnet} from 'viem/chains'
import {useReadContract} from 'wagmi'
@@ -20,6 +21,7 @@ import {
VAULT_CONTRACT_ADDRESS,
} from '@/config'
import {useRewardRate, useSharePrice, useTotalAssets} from '@/hooks/staking'
+import {useAddTokenToWallet} from '@/hooks/use-add-token-to-wallet'
import {phalaNetwork, toAddress} from '@/lib/wagmi'
export default function HomeContent() {
@@ -29,6 +31,7 @@ export default function HomeContent() {
const sharePrice = useSharePrice()
const totalAssets = useTotalAssets()
const rewardRate = useRewardRate()
+ const {addTokenToWallet, addNetwork} = useAddTokenToWallet()
const isValidConnection = isConnected && chainId === ethChain.id
@@ -79,12 +82,16 @@ export default function HomeContent() {
const l1VphaInPha = useMemo(() => {
if (l1VphaBalance == null || sharePrice == null) return null
- return (l1VphaBalance * sharePrice) / BigInt(1e18)
+ return new Decimal(formatUnits(l1VphaBalance, 18)).mul(
+ formatUnits(sharePrice, 18),
+ )
}, [l1VphaBalance, sharePrice])
const l2VphaInPha = useMemo(() => {
if (l2VphaBalance == null || sharePrice == null) return null
- return (l2VphaBalance * sharePrice) / BigInt(1e18)
+ return new Decimal(formatUnits(l2VphaBalance, 18)).mul(
+ formatUnits(sharePrice, 18),
+ )
}, [l2VphaBalance, sharePrice])
const totalVphaBalance = useMemo(() => {
@@ -94,16 +101,47 @@ export default function HomeContent() {
const totalVphaInPha = useMemo(() => {
if (l1VphaInPha == null && l2VphaInPha == null) return null
- return (l1VphaInPha ?? 0n) + (l2VphaInPha ?? 0n)
+ return (l1VphaInPha ?? new Decimal(0)).add(l2VphaInPha ?? new Decimal(0))
}, [l1VphaInPha, l2VphaInPha])
const totalPhaValue = useMemo(() => {
if (!isValidConnection) return null
- const pha = l1PhaBalance ?? 0n
- const vpha = totalVphaInPha ?? 0n
- return pha + vpha
+ const pha = new Decimal(formatUnits(l1PhaBalance ?? 0n, 18))
+ const vpha = totalVphaInPha ?? new Decimal(0)
+ return pha.add(vpha)
}, [isValidConnection, l1PhaBalance, totalVphaInPha])
+ const addPhaToWallet = useCallback(() => {
+ addTokenToWallet({
+ chainId: mainnet.id,
+ address: PHA_CONTRACT_ADDRESS,
+ symbol: 'PHA',
+ image: 'https://app.phala.network/icons/pha.png',
+ })
+ }, [addTokenToWallet])
+
+ const addL1VphaToWallet = useCallback(() => {
+ addTokenToWallet({
+ chainId: mainnet.id,
+ address: VAULT_CONTRACT_ADDRESS,
+ symbol: 'vPHA',
+ image: 'https://app.phala.network/icons/vpha.png',
+ })
+ }, [addTokenToWallet])
+
+ const addL2VphaToWallet = useCallback(() => {
+ addTokenToWallet({
+ chainId: phalaNetwork.id,
+ address: L2_VPHA_CONTRACT_ADDRESS,
+ symbol: 'vPHA',
+ image: 'https://app.phala.network/icons/vpha.png',
+ })
+ }, [addTokenToWallet])
+
+ const addPhalaNetworkToWallet = useCallback(() => {
+ addNetwork(phalaNetwork.id)
+ }, [addNetwork])
+
return (
@@ -134,6 +172,7 @@ export default function HomeContent() {
contractAddress={PHA_CONTRACT_ADDRESS}
chainLabel="Ethereum"
highlight
+ onAddToWallet={addPhaToWallet}
actions={[
{
label: 'Stake',
@@ -164,13 +203,14 @@ export default function HomeContent() {
chainLabel="Ethereum"
subValue={
isValidConnection && l1VphaInPha != null
- ? `≈ ${formatUnits(l1VphaInPha, 18).slice(0, 12)} PHA`
+ ? `≈ ${toCurrency(l1VphaInPha)} PHA`
: undefined
}
+ onAddToWallet={addL1VphaToWallet}
actions={[
{
label: 'Unstake',
- href: '/staking',
+ href: '/staking?tab=unstake',
variant: 'outlined',
},
{
@@ -190,12 +230,15 @@ export default function HomeContent() {
balance={isValidConnection ? l2VphaBalance : null}
contractAddress={L2_VPHA_CONTRACT_ADDRESS}
contractExplorerUrl="https://explorer.phala.network"
- chainLabel="Phala L2"
+ chainLabel="Phala Mainnet"
subValue={
isValidConnection && l2VphaInPha != null
- ? `≈ ${formatUnits(l2VphaInPha, 18).slice(0, 12)} PHA`
+ ? `≈ ${toCurrency(l2VphaInPha)} PHA`
: undefined
}
+ onAddToWallet={addL2VphaToWallet}
+ addToWalletLabel="Add vPHA"
+ onAddNetwork={addPhalaNetworkToWallet}
actions={[
{
label: 'Bridge to L1',
diff --git a/apps/app/app/khala-assets/content.tsx b/apps/app/app/khala-assets/content.tsx
index a304eb66..83516f7f 100644
--- a/apps/app/app/khala-assets/content.tsx
+++ b/apps/app/app/khala-assets/content.tsx
@@ -41,7 +41,7 @@ export default function KhalaAssetsContent() {
target="_blank"
rel="noopener noreferrer"
>
- Phala L2
+ Phala Mainnet
, our new Ethereum Layer 2 network.
@@ -134,7 +134,7 @@ export default function KhalaAssetsContent() {
- How to transfer vPHA between Ethereum and Phala L2?
+ How to transfer vPHA between Ethereum and Phala Mainnet?
You can use{' '}
@@ -145,8 +145,8 @@ export default function KhalaAssetsContent() {
>
Phala Bridge
{' '}
- to transfer vPHA tokens between Ethereum (L1) and Phala L2. The
- bridge supports bidirectional transfers, allowing you to move
+ to transfer vPHA tokens between Ethereum (L1) and Phala Mainnet.
+ The bridge supports bidirectional transfers, allowing you to move
assets freely between both networks.
diff --git a/apps/app/app/providers.tsx b/apps/app/app/providers.tsx
index 2a941067..0b318f29 100644
--- a/apps/app/app/providers.tsx
+++ b/apps/app/app/providers.tsx
@@ -10,6 +10,7 @@ import {QueryCache, QueryClient} from '@tanstack/react-query'
import {ReactQueryDevtools} from '@tanstack/react-query-devtools'
import Decimal from 'decimal.js'
import {Provider as JotaiProvider} from 'jotai'
+import {NuqsAdapter} from 'nuqs/adapters/next/app'
import type {ReactNode} from 'react'
import {useState} from 'react'
import {SWRConfig} from 'swr'
@@ -46,32 +47,34 @@ export default function Providers({
)
return (
- {
- if (process.env.NODE_ENV === 'development') {
- console.error(key, error)
- }
- },
- }}
- >
-
-
-
-
-
-
+
+ {
+ if (process.env.NODE_ENV === 'development') {
+ console.error(key, error)
+ }
+ },
+ }}
+ >
+
+
+
+
+
+
-
-
- {children}
-
-
-
-
-
-
-
-
+
+
+ {children}
+
+
+
+
+
+
+
+
+
)
}
diff --git a/apps/app/components/asset-card.tsx b/apps/app/components/asset-card.tsx
index 51694292..ed097899 100644
--- a/apps/app/components/asset-card.tsx
+++ b/apps/app/components/asset-card.tsx
@@ -17,6 +17,7 @@ import type {FC, ReactNode} from 'react'
import {formatUnits} from 'viem'
import {explorerUrl} from '@/config'
+import MetaMaskButton from './metamask-button'
export interface AssetAction {
label: string
@@ -37,6 +38,9 @@ interface AssetCardProps {
subValue?: ReactNode
actions?: AssetAction[]
highlight?: boolean
+ onAddToWallet?: () => void
+ addToWalletLabel?: string
+ onAddNetwork?: () => void
}
const AssetCard: FC = ({
@@ -50,6 +54,9 @@ const AssetCard: FC = ({
subValue,
actions = [],
highlight = false,
+ onAddToWallet,
+ addToWalletLabel,
+ onAddNetwork,
}) => {
const tokenExplorerUrl = contractExplorerUrl
? `${contractExplorerUrl}/token/${contractAddress}`
@@ -163,42 +170,44 @@ const AssetCard: FC = ({
- {actions.length > 0 && (
-
- {actions.map((action) => (
-
- ) : (
-
- )
- }
- sx={{
- fontSize: '0.75rem',
- py: 0.5,
- px: 1.5,
- }}
- >
- {action.label}
-
- ))}
-
- )}
+
+ {actions.map((action) => (
+
+ ) : (
+
+ )
+ }
+ sx={{
+ fontSize: '0.75rem',
+ py: 0.5,
+ px: 1.5,
+ }}
+ >
+ {action.label}
+
+ ))}
+ {onAddNetwork && (
+
+ Add Phala Mainnet
+
+ )}
+ {onAddToWallet && (
+
+ {addToWalletLabel ?? `Add ${symbol}`}
+
+ )}
+
)
diff --git a/apps/app/components/chain-badge.tsx b/apps/app/components/chain-badge.tsx
new file mode 100644
index 00000000..11886eb8
--- /dev/null
+++ b/apps/app/components/chain-badge.tsx
@@ -0,0 +1,42 @@
+import {Typography, type TypographyProps} from '@mui/material'
+import type {FC} from 'react'
+
+type ChainType = 'ethereum' | 'phala'
+
+interface ChainBadgeProps extends Omit {
+ chain: ChainType
+}
+
+const chainConfig: Record = {
+ ethereum: {
+ label: 'Ethereum',
+ color: 'primary.main',
+ },
+ phala: {
+ label: 'Phala Mainnet',
+ color: 'secondary.main',
+ },
+}
+
+const ChainBadge: FC = ({chain, ...props}) => {
+ const config = chainConfig[chain]
+
+ return (
+
+ {config.label}
+
+ )
+}
+
+export default ChainBadge
diff --git a/apps/app/components/claim-assets.tsx b/apps/app/components/claim-assets.tsx
index 618c9cbc..dc97726b 100644
--- a/apps/app/components/claim-assets.tsx
+++ b/apps/app/components/claim-assets.tsx
@@ -35,6 +35,7 @@ import {useWaitForTransactionReceipt, useWriteContract} from 'wagmi'
import khalaClaimerAbi from '@/assets/khala_claimer_abi'
import phalaClaimerAbi from '@/assets/phala_claimer_abi'
import AppKitButton from '@/components/app-kit-button'
+import ChainBadge from '@/components/chain-badge'
import Property from '@/components/property'
import SwitchChainButton from '@/components/switch-chain-button'
import {
@@ -363,7 +364,7 @@ const ClaimAssets = ({chain}: {chain: ChainType}) => {
color="text.secondary"
component="span"
>
- ({toCurrency(data.staked)} vPHA on Phala L2)
+ ({toCurrency(data.staked)} vPHA on Phala Mainnet)
) : data ? (
@@ -492,23 +493,11 @@ const ClaimAssets = ({chain}: {chain: ChainType}) => {
-
- Ethereum
-
+
)}
- {/* Staked vPHA to Phala L2 */}
+ {/* Staked vPHA to Phala Mainnet */}
{logData.stakedVPHA.gt(0) && (
{
-
- Phala L2
-
+
)}
>
@@ -592,19 +569,7 @@ const ClaimAssets = ({chain}: {chain: ChainType}) => {
-
- Ethereum
-
+
)}
@@ -641,19 +606,7 @@ const ClaimAssets = ({chain}: {chain: ChainType}) => {
-
- Ethereum
-
+
)}
>
diff --git a/apps/app/components/gradient-text.tsx b/apps/app/components/gradient-text.tsx
new file mode 100644
index 00000000..2e7fdd6d
--- /dev/null
+++ b/apps/app/components/gradient-text.tsx
@@ -0,0 +1,32 @@
+import {Typography, type TypographyProps} from '@mui/material'
+import type {FC, ReactNode} from 'react'
+
+interface GradientTextProps extends Omit {
+ children: ReactNode
+ gradient?: 'primary' | 'secondary'
+}
+
+const GradientText: FC = ({
+ children,
+ gradient = 'primary',
+ ...props
+}) => {
+ return (
+ ({
+ background:
+ gradient === 'primary'
+ ? `linear-gradient(90deg, ${theme.palette.primary.main}, ${theme.palette.primary.light})`
+ : `linear-gradient(90deg, ${theme.palette.secondary.main}, ${theme.palette.secondary.light})`,
+ backgroundClip: 'text',
+ WebkitBackgroundClip: 'text',
+ WebkitTextFillColor: 'transparent',
+ })}
+ >
+ {children}
+
+ )
+}
+
+export default GradientText
diff --git a/apps/app/components/metamask-button.tsx b/apps/app/components/metamask-button.tsx
new file mode 100644
index 00000000..f9d520c4
--- /dev/null
+++ b/apps/app/components/metamask-button.tsx
@@ -0,0 +1,36 @@
+import {Button, type ButtonProps} from '@mui/material'
+import type {FC, ReactNode} from 'react'
+
+import MetaMaskIcon from './metamask-icon'
+
+interface MetaMaskButtonProps extends Omit {
+ children: ReactNode
+}
+
+const MetaMaskButton: FC = ({children, sx, ...props}) => {
+ return (
+ }
+ sx={{
+ fontSize: '0.75rem',
+ py: 0.5,
+ px: 1.5,
+ color: 'text.secondary',
+ borderColor: 'divider',
+ '&:hover': {
+ color: 'text.primary',
+ borderColor: 'text.secondary',
+ bgcolor: 'action.hover',
+ },
+ ...sx,
+ }}
+ {...props}
+ >
+ {children}
+
+ )
+}
+
+export default MetaMaskButton
diff --git a/apps/app/components/metamask-icon.tsx b/apps/app/components/metamask-icon.tsx
new file mode 100644
index 00000000..da3f3e37
--- /dev/null
+++ b/apps/app/components/metamask-icon.tsx
@@ -0,0 +1,163 @@
+import type {FC} from 'react'
+
+interface MetaMaskIconProps {
+ size?: number
+}
+
+const MetaMaskIcon: FC = ({size = 14}) => (
+
+)
+
+export default MetaMaskIcon
diff --git a/apps/app/components/portfolio-summary.tsx b/apps/app/components/portfolio-summary.tsx
index fe8a723f..962ce5b0 100644
--- a/apps/app/components/portfolio-summary.tsx
+++ b/apps/app/components/portfolio-summary.tsx
@@ -22,9 +22,9 @@ import {formatUnits} from 'viem'
import {ethChain} from '@/config'
interface PortfolioSummaryProps {
- totalPhaValue: bigint | null
+ totalPhaValue: Decimal | null
totalStakedVpha: bigint | null
- totalStakedInPha: bigint | null
+ totalStakedInPha: Decimal | null
stakingApr: Decimal | null
isConnected: boolean
}
@@ -124,9 +124,7 @@ const PortfolioSummary: FC = ({
WebkitTextFillColor: 'transparent',
}}
>
- {totalPhaValue != null
- ? toCurrency(formatUnits(totalPhaValue, 18))
- : '-'}
+ {totalPhaValue != null ? toCurrency(totalPhaValue) : '-'}
PHA
@@ -152,7 +150,7 @@ const PortfolioSummary: FC = ({
{totalStakedInPha != null
- ? `≈ ${toCurrency(formatUnits(totalStakedInPha, 18))} PHA`
+ ? `≈ ${toCurrency(totalStakedInPha)} PHA`
: '-'}
{stakingApr != null && (
diff --git a/apps/app/components/staking/stake.tsx b/apps/app/components/staking/stake.tsx
index c6ce630f..2fdf67b7 100644
--- a/apps/app/components/staking/stake.tsx
+++ b/apps/app/components/staking/stake.tsx
@@ -5,6 +5,7 @@ import {
Box,
Button,
Chip,
+ IconButton,
OutlinedInput,
Paper,
Slider,
@@ -13,6 +14,7 @@ import {
Tabs,
ToggleButton,
ToggleButtonGroup,
+ Tooltip,
Typography,
} from '@mui/material'
import {getDecimalPattern, toCurrency, trimAddress} from '@phala/lib'
@@ -22,8 +24,10 @@ import {formatDuration, intervalToDuration} from 'date-fns'
import Decimal from 'decimal.js'
import Image from 'next/image'
import {useSnackbar} from 'notistack'
+import {parseAsStringLiteral, useQueryState} from 'nuqs'
import {useCallback, useEffect, useMemo, useState} from 'react'
import {erc20Abi, formatUnits, parseUnits} from 'viem'
+import {mainnet} from 'viem/chains'
import {useWaitForTransactionReceipt, useWriteContract} from 'wagmi'
import vaultAbi from '@/assets/pha_vault_abi'
@@ -43,14 +47,20 @@ import {
useUnlockPeriod,
useUnlockRequests,
} from '@/hooks/staking'
+import {useAddTokenToWallet} from '@/hooks/use-add-token-to-wallet'
import {useValidConnection} from '@/hooks/use-valid-connection'
+import MetaMaskIcon from '../metamask-icon'
const oneUnit = parseUnits('1', 18)
+const tabParser = parseAsStringLiteral(['stake', 'unstake']).withDefault(
+ 'stake',
+)
+
const Stake = () => {
- const [tab, setTab] = useState(0)
- const isStake = tab === 0
- const isUnstake = tab === 1
+ const [tab, setTab] = useQueryState('tab', tabParser)
+ const isStake = tab === 'stake'
+ const isUnstake = tab === 'unstake'
const [useDex, setUseDex] = useState(false)
const tokenContractAddress = useMemo(() => {
if (isStake) {
@@ -60,6 +70,18 @@ const Stake = () => {
}, [isStake])
const {enqueueSnackbar} = useSnackbar()
const {address, isValidConnection} = useValidConnection()
+ const {addTokenToWallet: addToken} = useAddTokenToWallet()
+
+ const addTokenToWallet = useCallback(() => {
+ addToken({
+ chainId: mainnet.id,
+ address: tokenContractAddress,
+ symbol: isStake ? 'PHA' : 'vPHA',
+ image: isStake
+ ? 'https://app.phala.network/icons/pha.png'
+ : 'https://app.phala.network/icons/vpha.png',
+ })
+ }, [addToken, tokenContractAddress, isStake])
const shareRate = useSharesToAssets(oneUnit)
const assetRate = useAssetsToShares(oneUnit)
@@ -239,14 +261,14 @@ const Stake = () => {
{
+ onChange={(_, value: 'stake' | 'unstake') => {
setTab(value)
setAmountString('')
}}
sx={{width: 1}}
>
-
-
+
+
{
target="_blank"
sx={{display: {xs: 'none', sm: 'inline-flex'}}}
/>
+
+
+
+
+
{balance != null ? toCurrency(formatUnits(balance, 18)) : '-'}
diff --git a/apps/app/hooks/use-add-token-to-wallet.ts b/apps/app/hooks/use-add-token-to-wallet.ts
new file mode 100644
index 00000000..38d820aa
--- /dev/null
+++ b/apps/app/hooks/use-add-token-to-wallet.ts
@@ -0,0 +1,58 @@
+import {useCallback} from 'react'
+import {useSwitchChain, useWatchAsset} from 'wagmi'
+
+interface TokenInfo {
+ chainId: number
+ address: `0x${string}`
+ symbol: string
+ decimals?: number
+ image?: string
+}
+
+export function useAddTokenToWallet() {
+ const {switchChainAsync} = useSwitchChain()
+ const {watchAsset} = useWatchAsset()
+
+ const addTokenToWallet = useCallback(
+ async ({chainId, address, symbol, decimals = 18, image}: TokenInfo) => {
+ try {
+ await switchChainAsync({chainId})
+ } catch (error) {
+ console.error('Failed to switch network:', error)
+ return false
+ }
+
+ try {
+ watchAsset({
+ type: 'ERC20',
+ options: {
+ address,
+ symbol,
+ decimals,
+ image,
+ },
+ })
+ return true
+ } catch (error) {
+ console.error('Failed to add token to wallet:', error)
+ return false
+ }
+ },
+ [switchChainAsync, watchAsset],
+ )
+
+ const addNetwork = useCallback(
+ async (chainId: number) => {
+ try {
+ await switchChainAsync({chainId})
+ return true
+ } catch (error) {
+ console.error('Failed to add network to wallet:', error)
+ return false
+ }
+ },
+ [switchChainAsync],
+ )
+
+ return {addTokenToWallet, addNetwork}
+}
diff --git a/apps/app/package.json b/apps/app/package.json
index d8bdd2d3..f6e979f0 100644
--- a/apps/app/package.json
+++ b/apps/app/package.json
@@ -34,6 +34,7 @@
"jotai-devtools": "^0.13.0",
"next": "^16.0.4",
"notistack": "^3.0.2",
+ "nuqs": "^2.8.1",
"react": "^19.2.0",
"react-dom": "^19.2.0",
"sharp": "^0.34.5",
diff --git a/bun.lock b/bun.lock
index 73379a45..5104a591 100644
--- a/bun.lock
+++ b/bun.lock
@@ -43,6 +43,7 @@
"jotai-devtools": "^0.13.0",
"next": "^16.0.4",
"notistack": "^3.0.2",
+ "nuqs": "^2.8.1",
"react": "^19.2.0",
"react-dom": "^19.2.0",
"sharp": "^0.34.5",
@@ -627,6 +628,8 @@
"@solana/web3.js": ["@solana/web3.js@1.98.4", "", { "dependencies": { "@babel/runtime": "^7.25.0", "@noble/curves": "^1.4.2", "@noble/hashes": "^1.4.0", "@solana/buffer-layout": "^4.0.1", "@solana/codecs-numbers": "^2.1.0", "agentkeepalive": "^4.5.0", "bn.js": "^5.2.1", "borsh": "^0.7.0", "bs58": "^4.0.1", "buffer": "6.0.3", "fast-stable-stringify": "^1.0.0", "jayson": "^4.1.1", "node-fetch": "^2.7.0", "rpc-websockets": "^9.0.2", "superstruct": "^2.0.2" } }, "sha512-vv9lfnvjUsRiq//+j5pBdXig0IQdtzA0BRZ3bXEP4KaIyF1CcaydWqgyzQgfZMNIsWNWmG+AUHwPy4AHOD6gpw=="],
+ "@standard-schema/spec": ["@standard-schema/spec@1.0.0", "", {}, "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA=="],
+
"@substrate/connect": ["@substrate/connect@0.8.11", "", { "dependencies": { "@substrate/connect-extension-protocol": "^2.0.0", "@substrate/connect-known-chains": "^1.1.5", "@substrate/light-client-extension-helpers": "^1.0.0", "smoldot": "2.0.26" } }, "sha512-ofLs1PAO9AtDdPbdyTYj217Pe+lBfTLltdHDs3ds8no0BseoLeAGxpz1mHfi7zB4IxI3YyAiLjH6U8cw4pj4Nw=="],
"@substrate/connect-extension-protocol": ["@substrate/connect-extension-protocol@2.2.1", "", {}, "sha512-GoafTgm/Jey9E4Xlj4Z5ZBt/H4drH2CNq8VrAro80rtoznrXnFDNVivLQzZN0Xaj2g8YXSn9pC9Oc9IovYZJXw=="],
@@ -1207,6 +1210,8 @@
"notistack": ["notistack@3.0.2", "", { "dependencies": { "clsx": "^1.1.0", "goober": "^2.0.33" }, "peerDependencies": { "react": "^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-0R+/arLYbK5Hh7mEfR2adt0tyXJcCC9KkA2hc56FeWik2QN6Bm/S4uW+BjzDARsJth5u06nTjelSw/VSnB1YEA=="],
+ "nuqs": ["nuqs@2.8.1", "", { "dependencies": { "@standard-schema/spec": "1.0.0" }, "peerDependencies": { "@remix-run/react": ">=2", "@tanstack/react-router": "^1", "next": ">=14.2.0", "react": ">=18.2.0 || ^19.0.0-0", "react-router": "^5 || ^6 || ^7", "react-router-dom": "^5 || ^6 || ^7" }, "optionalPeers": ["@remix-run/react", "@tanstack/react-router", "next", "react-router", "react-router-dom"] }, "sha512-kIw8UW5KXXfVla6B9h0EKzSH/YDpee6lojniQoMyul8wq9brwV0kElE2Jzg4NSCLBo7n2E3wc1J3o7IyPYVlqQ=="],
+
"obj-multiplex": ["obj-multiplex@1.0.0", "", { "dependencies": { "end-of-stream": "^1.4.0", "once": "^1.4.0", "readable-stream": "^2.3.3" } }, "sha512-0GNJAOsHoBHeNTvl5Vt6IWnpUEcc3uSRxzBri7EDyIcMgYvnY2JL2qdeV5zTMjWQX5OHcD5amcW2HFfDh0gjIA=="],
"object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="],