Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add validator management page #425

Open
wants to merge 18 commits into
base: develop
Choose a base branch
from
Open
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
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "portal",
"private": true,
"version": "3.1.0",
"version": "3.2.0",
"type": "module",
"scripts": {
"build:testnet": "NETWORK_NAME=testnet bash build.sh",
Expand Down
Binary file modified packages/core/bun.lockb
Binary file not shown.
1 change: 0 additions & 1 deletion packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
},
"author": "SKALE Labs",
"devDependencies": {
"ethers": "*.*.*",
"typescript": "^4.9.5"
}
}
19 changes: 19 additions & 0 deletions packages/core/src/types/staking/Delegation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,22 @@ export interface IDelegationInfo {
delegationId: bigint
delegationType: DelegationType
}

export interface IDelegationTotals {
proposed: {
count: number
amount: bigint
}
accepted: {
count: number
amount: bigint
}
delegated: {
count: number
amount: bigint
}
completed: {
count: number
amount: bigint
}
}
79 changes: 58 additions & 21 deletions src/App.scss
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,10 @@ body {
width: 100%;
}

.fullH {
Copy link
Contributor

Choose a reason for hiding this comment

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

Consistency: .fullH -> .fullHeight

height: 100%;
}

.mp__btnConnect {
position: relative;

Expand Down Expand Up @@ -457,6 +461,14 @@ body::-webkit-scrollbar {
background: rgb(244 139 54 / 13%);
}

.btnprimary {
Copy link
Contributor

Choose a reason for hiding this comment

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

Flagged for Consistency: .btnprimary -> .btnPrimary

background: rgba(147, 184, 236, 0.16);
}

.btnDisabled {
background: #262626;
}

.btnSmLoading {
Copy link
Contributor

Choose a reason for hiding this comment

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

Consistentcy: .btnSmallLoading

padding: 0.5em 1.5em 0.5em 3em !important;
}
Expand Down Expand Up @@ -543,6 +555,12 @@ body::-webkit-scrollbar {
}
}

.MuiToggleButton-root {
border-radius: 25px !important;
padding: 4px 10px;
border: none !important;
}

.copyBoard {
margin: 10px 0 !important;
padding: 13pt 15pt !important;
Expand Down Expand Up @@ -791,6 +809,22 @@ input[type=number] {
}
}

.chipNotification {
background: #e94e4e;
border-radius: 20px;
width: 20px;
height: 20px;
text-align: center;
display: flex;
align-items: center;
justify-content: center;

p {
color: #000000de !important;
font-weight: 600 !important;
}
}

.chipTrending {
background: linear-gradient(180deg, #e56d36, #D0602D) !important;

Expand Down Expand Up @@ -825,12 +859,13 @@ input[type=number] {
}

.chipXs {
border-radius: 20px;
padding: 3px 6px;
border-radius: 15px;
padding: 6px 8px;
text-align: center;

svg {
width: 14px;
height: 14px;
width: 12px;
height: 12px;
}
}

Expand All @@ -844,16 +879,6 @@ input[type=number] {
}
}

.chipXs {
border-radius: 15px;
padding: 4px 6px;

svg {
width: 12px;
height: 12px;
}
}

.skChip {
background: linear-gradient(180deg, rgb(52 52 52), rgb(31 31 31));
}
Expand Down Expand Up @@ -885,6 +910,11 @@ input[type=number] {
color: #3cda94;
}

.chip_REWARDS {
background: linear-gradient(180deg, #3d390f, #2a230a);
color: #dac83c;
}

.chip_ACCEPTED {
background: linear-gradient(180deg, #233d0f, #0a1b07);
color: #3cda4e;
Expand Down Expand Up @@ -1149,7 +1179,6 @@ input[type=number] {
}
}


.trustedBadge {
color: #0095f6;
}
Expand All @@ -1158,12 +1187,6 @@ input[type=number] {
color: #ffb817;
}

.validatorCard {
height: 100% !important;
cursor: pointer;
}


.pOneLine {
overflow: hidden;
white-space: nowrap;
Expand Down Expand Up @@ -1426,7 +1449,21 @@ input[type=number] {
display: none;
}

.opacity0 {
opacity: 0;
}

.MuiTooltip-tooltip {
font-size: 0.8rem !important;
padding: 8px 12px !important;
}

.delegationFlowText {
border-top: 2px #4a4a4a solid;
margin: 0 10px;
padding: 2px 5px 0 5px;
}

.delegationFlowIcon {
margin-top: -20px;
}
122 changes: 119 additions & 3 deletions src/Portal.tsx
Copy link
Contributor

Choose a reason for hiding this comment

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

General note on useState setup in React.
You have mix and matched null and undefined.
Believe that the standard tends to lean toward undefined as the "best practice" but in this case just consistency flag that it might be good to have them all the same

Original file line number Diff line number Diff line change
Expand Up @@ -21,27 +21,143 @@
* @copyright SKALE Labs 2023-Present
*/

import { useState, useEffect } from 'react'
import { types } from '@/core'

import Box from '@mui/material/Box'
import CssBaseline from '@mui/material/CssBaseline'
import { useMetaportStore, useWagmiAccount, Debug, cls, cmn } from '@skalenetwork/metaport'
import {
useMetaportStore,
useWagmiAccount,
Debug,
cls,
cmn,
PROXY_ENDPOINTS
} from '@skalenetwork/metaport'

import Header from './Header'
import SkDrawer from './SkDrawer'
import Router from './Router'
import SkBottomNavigation from './SkBottomNavigation'
import ProfileModal from './components/profile/ProfileModal'

import { formatSChains } from './core/chain'
import { STATS_API } from './core/constants'
import { getValidatorDelegations } from './core/delegation/staking'
import { getValidator } from './core/delegation'
import { initContracts } from './core/contracts'

export default function Portal() {
const mpc = useMetaportStore((state) => state.mpc)

const [schains, setSchains] = useState<types.ISChain[]>([])
const [metrics, setMetrics] = useState<types.IMetrics | null>(null)
const [stats, setStats] = useState<types.IStats | null>(null)
const [validator, setValidator] = useState<types.staking.IValidator | null | undefined>(null)
const [validatorDelegations, setValidatorDelegations] = useState<
types.staking.IDelegation[] | null
>(null)
const [customAddress, setCustomAddress] = useState<types.AddressType | undefined>(undefined)
const [sc, setSc] = useState<types.staking.ISkaleContractsMap | null>(null)
const [loadCalled, setLoadCalled] = useState<boolean>(false)

const endpoint = PROXY_ENDPOINTS[mpc.config.skaleNetwork]
const statsApi = STATS_API[mpc.config.skaleNetwork]

const { address } = useWagmiAccount()
if (!mpc) return <div></div>

useEffect(() => {
initSkaleContracts()
loadData()
}, [])

useEffect(() => {
loadValidator()
}, [address, customAddress, sc])

async function initSkaleContracts() {
setLoadCalled(true)
if (loadCalled) return
setSc(await initContracts(mpc))
}

async function loadChains() {
try {
const response = await fetch(`https://${endpoint}/files/chains.json`)
const chainsJson = await response.json()
setSchains(formatSChains(chainsJson))
} catch (e) {
console.log('Failed to load chains')
console.error(e)
}
}

async function loadMetrics() {
try {
const response = await fetch(`https://${endpoint}/files/metrics.json`)
const metricsJson = await response.json()
setMetrics(metricsJson)
} catch (e) {
console.log('Failed to load metrics')
console.error(e)
}
}

async function loadStats() {
if (statsApi === null) return
try {
const response = await fetch(statsApi)
const statsResp = await response.json()
setStats(statsResp.payload)
} catch (e) {
console.log('Failed to load stats')
console.error(e)
}
}

async function loadValidator() {
const addr = customAddress ?? address
if (!sc || !addr) {
setValidator(null)
setValidatorDelegations(null)
return
}
const validatorData = await getValidator(sc.validatorService, addr)
setValidator(validatorData)
if (validatorData && validatorData.id) {
setValidatorDelegations(await getValidatorDelegations(sc, validatorData.id))
} else {
setValidator(undefined)
setValidatorDelegations(null)
}
}

async function loadData() {
loadChains()
loadMetrics()
loadStats()
loadValidator()
}

return (
<Box sx={{ display: 'flex' }} className="AppWrap">
<CssBaseline />
<Header address={address} mpc={mpc} />
<SkDrawer />
<SkDrawer validatorDelegations={validatorDelegations} />
<div className={cls(cmn.fullWidth)} id="appContentScroll">
<Router />
<Router
loadData={loadData}
schains={schains}
metrics={metrics}
stats={stats}
validator={validator}
validatorDelegations={validatorDelegations}
customAddress={customAddress}
setCustomAddress={setCustomAddress}
sc={sc}
loadValidator={loadValidator}
/>
<ProfileModal />
<div className={cls(cmn.mtop20, cmn.fullWidth)}>
<Debug />
Expand Down
Loading
Loading