Compare commits

...

5 Commits

Author SHA1 Message Date
bee-worker c9c4e7d7d1 chore(master): release 0.23.0 (#609) 2023-02-23 01:25:09 +01:00
bee-worker d97bc27c14 docs: update supported bee (#612) 2023-02-21 10:30:59 +01:00
Cafe137 e215c61ea1 feat: upgrade bee-js to 5.2.0 (#611) 2023-02-21 10:16:16 +01:00
bee-worker 8298d0bc66 docs: update supported bee (#610) 2023-02-19 23:29:11 +01:00
Cafe137 fac72b1299 feat: add staking for full nodes (#590)
* feat: add staking

* feat: enable staking in full mode, add loading state

* chore: revert constants
2023-02-19 22:58:55 +01:00
9 changed files with 307 additions and 759 deletions
+8
View File
@@ -1,5 +1,13 @@
# Changelog # Changelog
## [0.23.0](https://github.com/ethersphere/bee-dashboard/compare/v0.22.0...v0.23.0) (2023-02-21)
### Features
* add staking for full nodes ([#590](https://github.com/ethersphere/bee-dashboard/issues/590)) ([fac72b1](https://github.com/ethersphere/bee-dashboard/commit/fac72b1299353c104231aa038c1bab9df78c1355))
* upgrade bee-js to 5.2.0 ([#611](https://github.com/ethersphere/bee-dashboard/issues/611)) ([e215c61](https://github.com/ethersphere/bee-dashboard/commit/e215c61ea1619fc388fe8b1904d160b04a1a5c0d))
## [0.22.0](https://github.com/ethersphere/bee-dashboard/compare/v0.21.1...v0.22.0) (2023-01-19) ## [0.22.0](https://github.com/ethersphere/bee-dashboard/compare/v0.21.1...v0.22.0) (2023-01-19)
+1 -1
View File
@@ -13,7 +13,7 @@
**Warning: This project is in alpha state. There might (and most probably will) be changes in the future to its API and **Warning: This project is in alpha state. There might (and most probably will) be changes in the future to its API and
working. Also, no guarantees can be made about its stability, efficiency, and security at this stage.** working. Also, no guarantees can be made about its stability, efficiency, and security at this stage.**
This project is intended to be used with **Bee version <!-- SUPPORTED_BEE_START -->1.9.0-13a47043<!-- SUPPORTED_BEE_END -->**. This project is intended to be used with **Bee version <!-- SUPPORTED_BEE_START -->1.12.0-88c1d236<!-- SUPPORTED_BEE_END -->**.
Using it with older or newer Bee versions is not recommended and may not work. Stay up to date by joining the Using it with older or newer Bee versions is not recommended and may not work. Stay up to date by joining the
[official Discord](https://discord.gg/GU22h2utj6) and by keeping an eye on the [official Discord](https://discord.gg/GU22h2utj6) and by keeping an eye on the
[releases tab](https://github.com/ethersphere/bee-dashboard/releases). [releases tab](https://github.com/ethersphere/bee-dashboard/releases).
+168 -737
View File
File diff suppressed because it is too large Load Diff
+5 -5
View File
@@ -1,6 +1,6 @@
{ {
"name": "@ethersphere/bee-dashboard", "name": "@ethersphere/bee-dashboard",
"version": "0.22.0", "version": "0.23.0",
"description": "An app which helps users to setup their Bee node and do actions like cash out cheques", "description": "An app which helps users to setup their Bee node and do actions like cash out cheques",
"keywords": [ "keywords": [
"bee", "bee",
@@ -26,7 +26,7 @@
"url": "https://github.com/ethersphere/bee-dashboard.git" "url": "https://github.com/ethersphere/bee-dashboard.git"
}, },
"dependencies": { "dependencies": {
"@ethersphere/bee-js": "^5.1.0", "@ethersphere/bee-js": "^5.2.0",
"@ethersphere/manifest-js": "1.2.1", "@ethersphere/manifest-js": "1.2.1",
"@ethersphere/swarm-cid": "^0.1.0", "@ethersphere/swarm-cid": "^0.1.0",
"@material-ui/core": "4.12.3", "@material-ui/core": "4.12.3",
@@ -48,9 +48,9 @@
"notistack": "1.0.10", "notistack": "1.0.10",
"opener": "1.5.2", "opener": "1.5.2",
"qrcode.react": "1.0.1", "qrcode.react": "1.0.1",
"react": ">=17.0.0 || >=18.0.0", "react": ">= 17.0.2",
"react-copy-to-clipboard": "5.0.4", "react-copy-to-clipboard": "5.0.4",
"react-dom": ">=17.0.0 || >=18.0.0", "react-dom": ">= 17.0.2",
"react-identicons": "1.2.5", "react-identicons": "1.2.5",
"react-router": "6.2.1", "react-router": "6.2.1",
"react-router-dom": "6.2.1", "react-router-dom": "6.2.1",
@@ -159,6 +159,6 @@
"engines": { "engines": {
"node": ">=14.0.0", "node": ">=14.0.0",
"npm": ">=6.9.0", "npm": ">=6.9.0",
"bee": "1.9.0-13a47043" "bee": "1.12.0-88c1d236"
} }
} }
+41
View File
@@ -0,0 +1,41 @@
import { BigNumber } from 'bignumber.js'
import { ReactElement, useContext } from 'react'
import Download from 'remixicon-react/DownloadLineIcon'
import WithdrawDepositModal from '../components/WithdrawDepositModal'
import { Context as BeeContext } from '../providers/Bee'
import { Context as SettingsContext } from '../providers/Settings'
interface Props {
onStarted: () => void
onFinished: () => void
}
export default function StakeModal({ onStarted, onFinished }: Props): ReactElement {
const { beeDebugApi } = useContext(SettingsContext)
const { refresh } = useContext(BeeContext)
return (
<WithdrawDepositModal
successMessage="Successfully deposited stake."
errorMessage="Error with depositing"
dialogMessage="Specify the amount of xBZZ you would like to stake. Your first stake must be at least 10 xBZZ. This will lock your tokens."
label="Stake"
icon={<Download size="1rem" />}
min={new BigNumber(0)}
action={async (amount: bigint) => {
if (!beeDebugApi) throw new Error('Bee Debug URL is not valid')
onStarted()
try {
await beeDebugApi.depositStake(amount.toString())
} finally {
refresh()
onFinished()
}
return 'unknown'
}}
/>
)
}
+16 -15
View File
@@ -1,6 +1,8 @@
import { BeeModes } from '@ethersphere/bee-js'
import { createStyles, makeStyles, Tab, Tabs, Theme } from '@material-ui/core' import { createStyles, makeStyles, Tab, Tabs, Theme } from '@material-ui/core'
import { ReactElement } from 'react' import { ReactElement, useContext } from 'react'
import { useNavigate } from 'react-router-dom' import { useNavigate } from 'react-router-dom'
import { Context } from '../../providers/Bee'
import { ACCOUNT_TABS } from '../../routes' import { ACCOUNT_TABS } from '../../routes'
const tabMap = { const tabMap = {
@@ -8,10 +10,11 @@ const tabMap = {
CHEQUEBOOK: 1, CHEQUEBOOK: 1,
STAMPS: 2, STAMPS: 2,
FEEDS: 3, FEEDS: 3,
STAKING: 4,
} }
interface Props { interface Props {
active: 'WALLET' | 'CHEQUEBOOK' | 'STAMPS' | 'FEEDS' active: 'WALLET' | 'CHEQUEBOOK' | 'STAMPS' | 'FEEDS' | 'STAKING'
} }
const useStyles = makeStyles((theme: Theme) => const useStyles = makeStyles((theme: Theme) =>
@@ -20,16 +23,12 @@ const useStyles = makeStyles((theme: Theme) =>
flexGrow: 1, flexGrow: 1,
marginBottom: theme.spacing(4), marginBottom: theme.spacing(4),
textTransform: 'none', textTransform: 'none',
marginLeft: theme.spacing(-0.25),
marginRight: theme.spacing(-0.25),
}, },
leftTab: { tab: {
marginRight: theme.spacing(0.125), marginLeft: theme.spacing(0.25),
}, marginRight: theme.spacing(0.25),
centerTab: {
marginLeft: theme.spacing(0.125),
marginRight: theme.spacing(0.125),
},
rightTab: {
marginLeft: theme.spacing(0.125),
}, },
}), }),
) )
@@ -37,6 +36,7 @@ const useStyles = makeStyles((theme: Theme) =>
export function AccountNavigation({ active }: Props): ReactElement { export function AccountNavigation({ active }: Props): ReactElement {
const classes = useStyles() const classes = useStyles()
const navigate = useNavigate() const navigate = useNavigate()
const { nodeInfo } = useContext(Context)
function onChange(event: React.ChangeEvent<Record<string, never>>, newValue: number) { function onChange(event: React.ChangeEvent<Record<string, never>>, newValue: number) {
navigate(ACCOUNT_TABS[newValue]) navigate(ACCOUNT_TABS[newValue])
@@ -45,10 +45,11 @@ export function AccountNavigation({ active }: Props): ReactElement {
return ( return (
<div className={classes.root}> <div className={classes.root}>
<Tabs value={tabMap[active]} onChange={onChange} variant="fullWidth"> <Tabs value={tabMap[active]} onChange={onChange} variant="fullWidth">
<Tab className={classes.leftTab} key="WALLET" label="Wallet" /> <Tab className={classes.tab} key="WALLET" label="Wallet" />
<Tab className={classes.centerTab} key="CHEQUEBOOK" label="Chequebook" /> <Tab className={classes.tab} key="CHEQUEBOOK" label="Chequebook" />
<Tab className={classes.centerTab} key="STAMPS" label="Stamps" /> <Tab className={classes.tab} key="STAMPS" label="Stamps" />
<Tab className={classes.rightTab} key="FEEDS" label="Feeds" /> <Tab className={classes.tab} key="FEEDS" label="Feeds" />
{nodeInfo?.beeMode === BeeModes.FULL ? <Tab className={classes.tab} key="STAKING" label="Staking" /> : null}
</Tabs> </Tabs>
</div> </div>
) )
@@ -0,0 +1,53 @@
import { ReactElement, useContext, useState } from 'react'
import ExpandableList from '../../../components/ExpandableList'
import ExpandableListItem from '../../../components/ExpandableListItem'
import ExpandableListItemActions from '../../../components/ExpandableListItemActions'
import { Loading } from '../../../components/Loading'
import TroubleshootConnectionCard from '../../../components/TroubleshootConnectionCard'
import StakeModal from '../../../containers/StakeModal'
import { CheckState, Context as BeeContext } from '../../../providers/Bee'
import { Context as BalanceContext } from '../../../providers/WalletBalance'
import { AccountNavigation } from '../AccountNavigation'
import { Header } from '../Header'
export function AccountStaking(): ReactElement {
const [loading, setLoading] = useState(false)
const { status, stake } = useContext(BeeContext)
const { balance } = useContext(BalanceContext)
if (status.all === CheckState.ERROR) return <TroubleshootConnectionCard />
function onStarted() {
setLoading(true)
}
function onFinished() {
setLoading(false)
}
return (
<>
<Header />
<AccountNavigation active="STAKING" />
<div>
{loading || stake?.toDecimal === undefined ? (
<Loading />
) : (
<ExpandableList label="Staking" defaultOpen>
<ExpandableListItem label="Staked BZZ" value={`${stake?.toSignificantDigits()} xBZZ`} />
{balance?.bzz ? (
<ExpandableListItem
label="Available xBZZ balance"
value={`${balance?.bzz.toSignificantDigits(4)} xBZZ`}
/>
) : null}
<ExpandableListItemActions>
<StakeModal onStarted={onStarted} onFinished={onFinished} />
</ExpandableListItemActions>
</ExpandableList>
)}
</div>
</>
)
}
+10
View File
@@ -13,6 +13,7 @@ import { createContext, ReactChild, ReactElement, useContext, useEffect, useStat
import semver from 'semver' import semver from 'semver'
import PackageJson from '../../package.json' import PackageJson from '../../package.json'
import { useLatestBeeRelease } from '../hooks/apiHooks' import { useLatestBeeRelease } from '../hooks/apiHooks'
import { BzzToken } from '../models/BzzToken'
import { Token } from '../models/Token' import { Token } from '../models/Token'
import type { Balance, ChequebookBalance, Settlements } from '../types' import type { Balance, ChequebookBalance, Settlements } from '../types'
import { Context as SettingsContext } from './Settings' import { Context as SettingsContext } from './Settings'
@@ -62,6 +63,7 @@ interface ContextInterface {
chequebookAddress: ChequebookAddressResponse | null chequebookAddress: ChequebookAddressResponse | null
peers: Peer[] | null peers: Peer[] | null
chequebookBalance: ChequebookBalance | null chequebookBalance: ChequebookBalance | null
stake: BzzToken | null
peerBalances: Balance[] | null peerBalances: Balance[] | null
peerCheques: LastChequesResponse | null peerCheques: LastChequesResponse | null
settlements: Settlements | null settlements: Settlements | null
@@ -98,6 +100,7 @@ const initialValues: ContextInterface = {
nodeInfo: null, nodeInfo: null,
topology: null, topology: null,
chequebookAddress: null, chequebookAddress: null,
stake: null,
peers: null, peers: null,
chequebookBalance: null, chequebookBalance: null,
peerBalances: null, peerBalances: null,
@@ -225,6 +228,7 @@ export function Provider({ children, isDesktop }: Props): ReactElement {
const [chequebookAddress, setChequebookAddress] = useState<ChequebookAddressResponse | null>(null) const [chequebookAddress, setChequebookAddress] = useState<ChequebookAddressResponse | null>(null)
const [peers, setPeers] = useState<Peer[] | null>(null) const [peers, setPeers] = useState<Peer[] | null>(null)
const [chequebookBalance, setChequebookBalance] = useState<ChequebookBalance | null>(null) const [chequebookBalance, setChequebookBalance] = useState<ChequebookBalance | null>(null)
const [stake, setStake] = useState<BzzToken | null>(null)
const [peerBalances, setPeerBalances] = useState<Balance[] | null>(null) const [peerBalances, setPeerBalances] = useState<Balance[] | null>(null)
const [peerCheques, setPeerCheques] = useState<LastChequesResponse | null>(null) const [peerCheques, setPeerCheques] = useState<LastChequesResponse | null>(null)
const [settlements, setSettlements] = useState<Settlements | null>(null) const [settlements, setSettlements] = useState<Settlements | null>(null)
@@ -388,6 +392,11 @@ export function Provider({ children, isDesktop }: Props): ReactElement {
.then(setChequebookBalance) .then(setChequebookBalance)
.catch(() => setChequebookBalance(null)), .catch(() => setChequebookBalance(null)),
beeDebugApi
.getStake({ timeout: TIMEOUT })
.then(stake => setStake(new BzzToken(stake)))
.catch(() => setStake(null)),
// Peer balances // Peer balances
peerBalanceWrapper() peerBalanceWrapper()
.then(setPeerBalances) .then(setPeerBalances)
@@ -471,6 +480,7 @@ export function Provider({ children, isDesktop }: Props): ReactElement {
chequebookAddress, chequebookAddress,
peers, peers,
chequebookBalance, chequebookBalance,
stake,
peerBalances, peerBalances,
peerCheques, peerCheques,
settlements, settlements,
+5 -1
View File
@@ -2,6 +2,7 @@ import { ReactElement, useContext } from 'react'
import { Route, Routes } from 'react-router-dom' import { Route, Routes } from 'react-router-dom'
import { AccountChequebook } from './pages/account/chequebook/AccountChequebook' import { AccountChequebook } from './pages/account/chequebook/AccountChequebook'
import { AccountFeeds } from './pages/account/feeds/AccountFeeds' import { AccountFeeds } from './pages/account/feeds/AccountFeeds'
import { AccountStaking } from './pages/account/staking/AccountStaking'
import { AccountStamps } from './pages/account/stamps/AccountStamps' import { AccountStamps } from './pages/account/stamps/AccountStamps'
import { AccountWallet } from './pages/account/wallet/AccountWallet' import { AccountWallet } from './pages/account/wallet/AccountWallet'
import CreateNewFeed from './pages/feeds/CreateNewFeed' import CreateNewFeed from './pages/feeds/CreateNewFeed'
@@ -14,10 +15,10 @@ import { UploadLander } from './pages/files/UploadLander'
import GiftCards from './pages/gift-code' import GiftCards from './pages/gift-code'
import Info from './pages/info' import Info from './pages/info'
import LightModeRestart from './pages/restart/LightModeRestart' import LightModeRestart from './pages/restart/LightModeRestart'
import TopUp from './pages/top-up'
import Settings from './pages/settings' import Settings from './pages/settings'
import { CreatePostageStampPage } from './pages/stamps/CreatePostageStampPage' import { CreatePostageStampPage } from './pages/stamps/CreatePostageStampPage'
import Status from './pages/status' import Status from './pages/status'
import TopUp from './pages/top-up'
import { BankCardTopUpIndex } from './pages/top-up/BankCardTopUpIndex' import { BankCardTopUpIndex } from './pages/top-up/BankCardTopUpIndex'
import { CryptoTopUpIndex } from './pages/top-up/CryptoTopUpIndex' import { CryptoTopUpIndex } from './pages/top-up/CryptoTopUpIndex'
import { GiftCardFund } from './pages/top-up/GiftCardFund' import { GiftCardFund } from './pages/top-up/GiftCardFund'
@@ -51,6 +52,7 @@ export enum ROUTES {
ACCOUNT_FEEDS_UPDATE = '/account/feeds/update/:hash', ACCOUNT_FEEDS_UPDATE = '/account/feeds/update/:hash',
ACCOUNT_FEEDS_VIEW = '/account/feeds/:uuid', ACCOUNT_FEEDS_VIEW = '/account/feeds/:uuid',
ACCOUNT_INVITATIONS = '/account/invitations', ACCOUNT_INVITATIONS = '/account/invitations',
ACCOUNT_STAKING = '/account/staking',
} }
export const ACCOUNT_TABS = [ export const ACCOUNT_TABS = [
@@ -58,6 +60,7 @@ export const ACCOUNT_TABS = [
ROUTES.ACCOUNT_CHEQUEBOOK, ROUTES.ACCOUNT_CHEQUEBOOK,
ROUTES.ACCOUNT_STAMPS, ROUTES.ACCOUNT_STAMPS,
ROUTES.ACCOUNT_FEEDS, ROUTES.ACCOUNT_FEEDS,
ROUTES.ACCOUNT_STAKING,
] ]
const BaseRouter = (): ReactElement => { const BaseRouter = (): ReactElement => {
@@ -88,6 +91,7 @@ const BaseRouter = (): ReactElement => {
<Route path={ROUTES.ACCOUNT_FEEDS_NEW} element={<CreateNewFeed />} /> <Route path={ROUTES.ACCOUNT_FEEDS_NEW} element={<CreateNewFeed />} />
<Route path={ROUTES.ACCOUNT_FEEDS_UPDATE} element={<UpdateFeed />} /> <Route path={ROUTES.ACCOUNT_FEEDS_UPDATE} element={<UpdateFeed />} />
<Route path={ROUTES.ACCOUNT_FEEDS_VIEW} element={<FeedSubpage />} /> <Route path={ROUTES.ACCOUNT_FEEDS_VIEW} element={<FeedSubpage />} />
<Route path={ROUTES.ACCOUNT_STAKING} element={<AccountStaking />} />
{isDesktop && <Route path={ROUTES.ACCOUNT_INVITATIONS} element={<GiftCards />} />} {isDesktop && <Route path={ROUTES.ACCOUNT_INVITATIONS} element={<GiftCards />} />}
</Routes> </Routes>
) )