Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
35 changes: 0 additions & 35 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,41 +18,6 @@
"editor.defaultFormatter": "biomejs.biome"
},
"biome.enabled": true,
"cSpell.words": [
"biomejs",
"bunx",
"crowdloan",
"fontawesome",
"fortawesome",
"karura",
"khala",
"lefthook",
"moonbase",
"moonriver",
"movr",
"orml",
"parachain",
"phala",
"polkadot",
"preinstall",
"readystate",
"roboto",
"staker",
"stakers",
"subbridge",
"Subscan",
"subsquid",
"svgs",
"sygma",
"talismn",
"tanstack",
"tokenomic",
"unsub",
"xtokens",
"connectkit",
"wagmi",
"walletconnect"
],
"editor.codeActionsOnSave": {
"quickfix.biome": "explicit",
"source.addMissingImports": "explicit",
Expand Down
10 changes: 1 addition & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,3 @@
# Phala Apps
# Phala Network Apps

[![Discord](https://img.shields.io/discord/697726436211163147?color=%235865F2&label=discord&style=for-the-badge)](https://discord.gg/phala-network)

Monorepo for apps in phala.

## Apps

### [Phala App](/apps/app)

### [SubBridge](/apps/subbridge)
File renamed without changes
213 changes: 213 additions & 0 deletions apps/app/app/content.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
'use client'

import {Box, Divider, Grid, Stack, Typography} from '@mui/material'
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 {erc20Abi, formatUnits} from 'viem'
import {mainnet} from 'viem/chains'
import {useReadContract} from 'wagmi'

import AssetCard from '@/components/asset-card'
import PortfolioSummary from '@/components/portfolio-summary'
import QuickActions from '@/components/quick-actions'
import {
ethChain,
L2_VPHA_CONTRACT_ADDRESS,
PHA_CONTRACT_ADDRESS,
VAULT_CONTRACT_ADDRESS,
} from '@/config'
import {useRewardRate, useSharePrice, useTotalAssets} from '@/hooks/staking'
import {phalaNetwork, toAddress} from '@/lib/wagmi'

export default function HomeContent() {
const {address: rawAddress, isConnected} = useAppKitAccount()
const {chainId} = useAppKitNetwork()
const address = toAddress(rawAddress)
const sharePrice = useSharePrice()
const totalAssets = useTotalAssets()
const rewardRate = useRewardRate()

const isValidConnection = isConnected && chainId === ethChain.id

const stakingApr = useMemo(() => {
if (rewardRate == null || !totalAssets) {
return null
}
return Decimal.mul(rewardRate.toString(), 365 * 24 * 60 * 60).div(
totalAssets.toString(),
)
}, [rewardRate, totalAssets])

const {data: l1PhaBalance} = useReadContract({
address: PHA_CONTRACT_ADDRESS,
abi: erc20Abi,
functionName: 'balanceOf',
args: address && [address],
chainId: mainnet.id,
query: {
enabled: isValidConnection && Boolean(address),
refetchInterval: 3_000,
},
})

const {data: l1VphaBalance} = useReadContract({
address: VAULT_CONTRACT_ADDRESS,
abi: erc20Abi,
functionName: 'balanceOf',
args: address && [address],
chainId: mainnet.id,
query: {
enabled: isValidConnection && Boolean(address),
refetchInterval: 3_000,
},
})

const {data: l2VphaBalance} = useReadContract({
address: L2_VPHA_CONTRACT_ADDRESS,
abi: erc20Abi,
functionName: 'balanceOf',
args: address && [address],
chainId: phalaNetwork.id,
query: {
enabled: isValidConnection && Boolean(address),
refetchInterval: 3_000,
},
})

const l1VphaInPha = useMemo(() => {
if (l1VphaBalance == null || sharePrice == null) return null
return (l1VphaBalance * sharePrice) / BigInt(1e18)
}, [l1VphaBalance, sharePrice])

const l2VphaInPha = useMemo(() => {
if (l2VphaBalance == null || sharePrice == null) return null
return (l2VphaBalance * sharePrice) / BigInt(1e18)
}, [l2VphaBalance, sharePrice])

const totalVphaBalance = useMemo(() => {
if (l1VphaBalance == null && l2VphaBalance == null) return null
return (l1VphaBalance ?? 0n) + (l2VphaBalance ?? 0n)
}, [l1VphaBalance, l2VphaBalance])

const totalVphaInPha = useMemo(() => {
if (l1VphaInPha == null && l2VphaInPha == null) return null
return (l1VphaInPha ?? 0n) + (l2VphaInPha ?? 0n)
}, [l1VphaInPha, l2VphaInPha])

const totalPhaValue = useMemo(() => {
if (!isValidConnection) return null
const pha = l1PhaBalance ?? 0n
const vpha = totalVphaInPha ?? 0n
return pha + vpha
}, [isValidConnection, l1PhaBalance, totalVphaInPha])

return (
<Box pb={10} pt={3}>
<Stack spacing={4}>
<PortfolioSummary
totalPhaValue={totalPhaValue}
totalStakedVpha={totalVphaBalance}
totalStakedInPha={totalVphaInPha}
stakingApr={stakingApr}
isConnected={isConnected}
/>

<QuickActions />

<Divider sx={{borderColor: 'divider'}} />

<Box>
<Typography variant="subtitle1" fontWeight={600} mb={2}>
Your Assets
</Typography>

<Grid container spacing={2}>
<Grid size={{xs: 12, md: 6}}>
<AssetCard
icon={phaIcon}
name="Phala Token"
symbol="PHA"
balance={isValidConnection ? l1PhaBalance : null}
contractAddress={PHA_CONTRACT_ADDRESS}
chainLabel="Ethereum"
highlight
actions={[
{
label: 'Stake',
href: '/staking',
variant: 'contained',
},
{
label: 'Bridge',
href: 'https://bridge.phala.network/',
external: true,
},
{
label: 'Swap',
href: `https://app.uniswap.org/swap?chain=mainnet&outputCurrency=${PHA_CONTRACT_ADDRESS}`,
external: true,
},
]}
/>
</Grid>

<Grid size={{xs: 12, md: 6}}>
<AssetCard
icon={vphaIcon}
name="Phala Vault"
symbol="vPHA"
balance={isValidConnection ? l1VphaBalance : null}
contractAddress={VAULT_CONTRACT_ADDRESS}
chainLabel="Ethereum"
subValue={
isValidConnection && l1VphaInPha != null
? `≈ ${formatUnits(l1VphaInPha, 18).slice(0, 12)} PHA`
: undefined
}
actions={[
{
label: 'Unstake',
href: '/staking',
variant: 'outlined',
},
{
label: 'Swap on DEX',
href: `https://app.uniswap.org/swap?chain=mainnet&inputCurrency=${VAULT_CONTRACT_ADDRESS}&outputCurrency=${PHA_CONTRACT_ADDRESS}`,
external: true,
},
]}
/>
</Grid>

<Grid size={{xs: 12, md: 6}}>
<AssetCard
icon={vphaIcon}
name="Phala Vault (L2)"
symbol="vPHA"
balance={isValidConnection ? l2VphaBalance : null}
contractAddress={L2_VPHA_CONTRACT_ADDRESS}
contractExplorerUrl="https://explorer.phala.network"
chainLabel="Phala L2"
subValue={
isValidConnection && l2VphaInPha != null
? `≈ ${formatUnits(l2VphaInPha, 18).slice(0, 12)} PHA`
: undefined
}
actions={[
{
label: 'Bridge to L1',
href: 'https://bridge.phala.network/',
external: true,
},
]}
/>
</Grid>
</Grid>
</Box>
</Stack>
</Box>
)
}
88 changes: 88 additions & 0 deletions apps/app/app/gpu-mining/content.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
'use client'

import OpenInNew from '@mui/icons-material/OpenInNew'
import {Box, Button, Link, Paper, Stack, Typography} from '@mui/material'
import Image from 'next/image'

import dephyLogo from '@/assets/dephy.svg'

export default function GpuMiningContent() {
return (
<Stack maxWidth={800} mx="auto" alignItems="center" mt={6} gap={4}>
<Typography variant="h4">GPU Mining</Typography>

<Paper sx={{background: 'transparent', p: 4, width: '100%'}}>
<Stack gap={4} alignItems="center">
<Typography variant="body1" color="text.secondary" textAlign="center">
Start mining with your GPU on the Phala Network. Access the Mining
Portal to manage your stake pools and monitor your mining
operations.
</Typography>

<Stack
direction={{xs: 'column', sm: 'row'}}
gap={2}
width="100%"
justifyContent="center"
>
<Button
component="a"
href="https://phala-stake-pool-lite.web.app/stakepool"
target="_blank"
rel="noopener noreferrer"
variant="contained"
size="large"
endIcon={<OpenInNew />}
sx={{
px: 4,
py: 1.5,
fontWeight: 600,
}}
>
Mining Portal
</Button>

<Button
component="a"
href="https://docs.phala.com/network/compute-providers/introduction"
target="_blank"
rel="noopener noreferrer"
variant="outlined"
size="large"
endIcon={<OpenInNew />}
sx={{
px: 4,
py: 1.5,
fontWeight: 600,
}}
>
Documentation
</Button>
</Stack>
</Stack>
</Paper>

<Box
sx={{
display: 'flex',
alignItems: 'center',
gap: 1,
color: 'text.secondary',
}}
>
<Typography variant="body2">Powered by</Typography>
<Link
href="https://dephy.io/"
target="_blank"
rel="noopener noreferrer"
sx={{
display: 'flex',
alignItems: 'center',
}}
>
<Image src={dephyLogo} alt="DePHY" height={24} />
</Link>
</Box>
</Stack>
)
}
13 changes: 13 additions & 0 deletions apps/app/app/gpu-mining/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import type {Metadata} from 'next'

import GpuMiningContent from './content'

export const metadata: Metadata = {
title: 'GPU Mining',
description:
'Start mining with your GPU on the Phala Network. Manage stake pools and monitor mining operations.',
}

export default function GpuMiningPage() {
return <GpuMiningContent />
}
File renamed without changes
File renamed without changes
File renamed without changes.
Loading