Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion apps/hub/.env
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,5 @@
# – https://vercel.com/docs/cli/env#exporting-development-environment-variables


NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID="123"
NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID=""
NEXT_PUBLIC_STATUS_NETWORK_API_URL=""
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@status-im/web fyi, rename from NEXT_PUBLIC_API_URL to NEXT_PUBLIC_STATUS_NETWORK_API_URL

20 changes: 20 additions & 0 deletions apps/hub/.env.development
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# note: next lint doesn't use .env.development
# note: use .env.local instead for now
#
# – https://github.com/vercel/next.js/discussions/32354

# .env, .env.development, and .env.production files should be included in your repository as they define defaults.
# .env*.local should be added to .gitignore, as those files are intended to be ignored.
# .env.local is where secrets can be stored.
#
# – https://nextjs.org/docs/pages/building-your-application/configuring/environment-variables#default-environment-variables

# The vercel env pull sub-command will export development environment variables to a local .env file or a different file of your choice.
#
# `vercel env pull .env[.development].local`
#
# – https://vercel.com/docs/cli/env#exporting-development-environment-variables


NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID=""
NEXT_PUBLIC_STATUS_NETWORK_API_URL=""
2 changes: 1 addition & 1 deletion apps/hub/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
"rehype-slug": "^6.0.0",
"siwe": "^2.3.2",
"ts-pattern": "^5.6.2",
"viem": "^2.21.1",
"viem": "^2.29.1",
"wagmi": "2.15.2",
"zod": "^3.24.1"
},
Expand Down
24 changes: 9 additions & 15 deletions apps/hub/src/app/_components/connect-button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,45 +2,39 @@

import { Button, ShortenAddress } from '@status-im/status-network/components'
import { ConnectKitButton } from 'connectkit'
import { useAccount } from 'wagmi'

import type { ComponentProps } from 'react'

type Props = {
size?: ComponentProps<typeof Button>['size']
label?: string
shortLabel?: string
className?: string
/** If true, shows the label instead of the shortened address when connected */
alwaysShowLabel?: boolean
}

const ConnectButton = (props: Props) => {
const {
size = '32',
label = 'Connect wallet',
shortLabel = 'Connect',
className,
alwaysShowLabel = false,
} = props

const { address, isConnected } = useAccount()

return (
<ConnectKitButton.Custom>
{({ show }) => {
{({ show, isConnected, address }) => {
return (
<Button
onClick={show}
variant={isConnected ? 'secondary' : 'primary'}
size={size}
className={className}
>
{address && isConnected ? (
{address && isConnected && !alwaysShowLabel ? (
<ShortenAddress address={address} />
) : (
<>
<span className="hidden whitespace-nowrap lg:block">
{label}
</span>
<span className="block whitespace-nowrap lg:hidden">
{shortLabel}
</span>
</>
label
)}
</Button>
)
Expand Down
51 changes: 39 additions & 12 deletions apps/hub/src/app/_constants/chain.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,52 @@
import type { Chain } from 'wagmi/chains'
import { getDefaultConfig } from 'connectkit'
import { defineChain } from 'viem'
import { createConfig, http } from 'wagmi'
import { type Chain, mainnet } from 'wagmi/chains'

export const statusNetworkTestnet: Chain = {
id: Number(1660990954),
import { clientEnv } from './env.client.mjs'

import type {
CreateConfigParameters,
CreateConnectorFn,
Transport,
} from 'wagmi'

export const testnet = defineChain({
id: 1660990954,
name: 'Status Network Testnet',
nativeCurrency: {
decimals: 18,
name: 'Ether',
symbol: 'ETH',
},
testnet: true,
sourceId: 1660990954,
nativeCurrency: { name: 'Ether', symbol: 'ETH', decimals: 18 },
rpcUrls: {
default: {
http: ['https://public.sepolia.rpc.status.network'],
},
public: {
http: ['https://public.sepolia.rpc.status.network'],
},
},
blockExplorers: {
default: {
name: 'Status Explorer',
url: 'https://sepoliascan.status.network',
},
},
}
})

export const getDefaultWagmiConfig = () =>
getDefaultConfig({
chains: [mainnet, testnet],
transports: {
[mainnet.id]: http(mainnet.rpcUrls.default.http[0]),
[testnet.id]: http(testnet.rpcUrls.default.http[0]),
},
walletConnectProjectId:
clientEnv.NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID as string,
appName: 'Status Hub',
appDescription: 'Status Network DeFi Dashboard',
appUrl: 'https://status.app',
appIcon: 'https://status.app/icon.png',
}) as CreateConfigParameters<
readonly [Chain, ...Chain[]],
Record<number, Transport>,
readonly CreateConnectorFn[]
>

export const wagmiConfig = createConfig(getDefaultWagmiConfig())
3 changes: 3 additions & 0 deletions apps/hub/src/app/_constants/env.client.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,14 @@ export const envSchema = z.object({
NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID: z
.string()
.min(1, 'WalletConnect Project ID is required.'),
NEXT_PUBLIC_STATUS_NETWORK_API_URL: z.string().url(),
})

export const result = envSchema.strip().safeParse({
NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID:
process.env.NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID,
NEXT_PUBLIC_STATUS_NETWORK_API_URL:
process.env.NEXT_PUBLIC_STATUS_NETWORK_API_URL,
})

if (!result.success) {
Expand Down
1 change: 1 addition & 0 deletions apps/hub/src/app/_constants/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './address'
export * from './chain'
export * from './siwe'
export * from './staking'
73 changes: 73 additions & 0 deletions apps/hub/src/app/_constants/siwe.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { clientEnv } from './env.client.mjs'

import type { SIWEConfig } from 'connectkit'

// API configuration
const API_BASE_URL = clientEnv.NEXT_PUBLIC_STATUS_NETWORK_API_URL

const AUTH_ENDPOINTS = {
verify: `${API_BASE_URL}/auth/ethereum`,
session: `${API_BASE_URL}/auth/me`,
logout: `${API_BASE_URL}/auth/logout`,
} as const

// Helper for API calls
const fetchAPI = async (url: string, options?: RequestInit) => {
const response = await fetch(url, {
credentials: 'include', // Send cookies with cross-origin requests
headers: {
'Content-Type': 'application/json',
...options?.headers,
},
...options,
})
return response
}

export const siweConfig: SIWEConfig = {
getNonce: async () => {
return Math.random().toString(36).substring(2, 15)
},

createMessage: async () => {
const payload = { timestamp: Math.floor(Date.now() / 1000) }
return window.btoa(JSON.stringify(payload))
},

verifyMessage: async ({ message, signature }) => {
try {
const response = await fetchAPI(AUTH_ENDPOINTS.verify, {
method: 'POST',
body: JSON.stringify({ payload: message, signature }),
})
return response.ok
} catch {
return false
}
},

getSession: async () => {
try {
const response = await fetchAPI(AUTH_ENDPOINTS.session)
if (!response.ok) return null

const data = await response.json()
return data.result ?? null
} catch {
return null
}
},

signOut: async () => {
try {
const response = await fetchAPI(AUTH_ENDPOINTS.logout, {
method: 'POST',
})
return response.ok
} catch {
return false
}
},

signOutOnDisconnect: false,
}
15 changes: 0 additions & 15 deletions apps/hub/src/app/_providers/connectkit-provider.tsx

This file was deleted.

58 changes: 49 additions & 9 deletions apps/hub/src/app/_providers/index.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,61 @@
'use client'

import { VaultStateProvider } from '../_hooks/useVaultStateContext'
import { ConnectKitProvider } from './connectkit-provider'
import { QueryClientProvider } from './query-client-provider'
import { WagmiProvider } from './wagmi-provider'
import { ToastContainer } from '@status-im/components'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { ConnectKitProvider, SIWEProvider } from 'connectkit'
import { WagmiProvider } from 'wagmi'

import { testnet, wagmiConfig } from '~constants/chain'
import { siweConfig } from '~constants/siwe'
import { VaultStateProvider } from '~hooks/useVaultStateContext'

import { VaultProvider } from './vault-provider'

interface ProvidersProps {
children: React.ReactNode
}

const queryClient = new QueryClient({
defaultOptions: {
queries: {
retry: false,
retryOnMount: false,
refetchOnMount: false,
refetchOnWindowFocus: false,
refetchOnReconnect: false,
},
},
})

/**
* Application Providers
*
* Provider hierarchy (order matters):
* 1. WagmiProvider - Blockchain connection & wallet state
* 2. QueryClientProvider - React Query for data fetching
* 3. SiweProvider - SIWE authentication
* 4. ConnectKitProvider - Wallet connection UI
* 5. VaultStateProvider - Vault operation state machine
* 6. VaultProvider - Vault-specific features
*/
export function Providers({ children }: ProvidersProps) {
return (
<WagmiProvider>
<QueryClientProvider>
<ConnectKitProvider>
<VaultStateProvider>{children}</VaultStateProvider>
</ConnectKitProvider>
<WagmiProvider config={wagmiConfig}>
<QueryClientProvider client={queryClient}>
<SIWEProvider {...siweConfig}>
<ConnectKitProvider
options={{
initialChainId: testnet.id,
}}
>
<VaultStateProvider>
<VaultProvider>
{children}
<ToastContainer />
</VaultProvider>
</VaultStateProvider>
</ConnectKitProvider>
</SIWEProvider>
</QueryClientProvider>
</WagmiProvider>
)
Expand Down
31 changes: 0 additions & 31 deletions apps/hub/src/app/_providers/query-client-provider.tsx

This file was deleted.

Loading
Loading