feat: bee-js revamp (#690)

* chore: initial commit

* refactor: remove unnecessary wrappers

* style: add missing newline

* chore: bump bee-js

* chore: ignore any cast in fdp

* fix: remove cid import

* fix: make TextEncoder and TextDecoder available in jest

* refactor: dedupe stamp ttl second conversion

* refactor: use convenience methods from bee-js

* feat: update to bee-js for restored ens support

* fix: bump bee-js to get download fix

* fix: resolve feed before downloading reference

* fix: fix token displays

* fix: fix token input modal error message

* refactor: remove wallet balance provider

* chore: remove dead code

* refactor: upcoming bee js 0.15.0 (#692)

* chore: initial commit

* fix: do not break page when duration seconds is 0

* ci: remove cache

* chore: upgrade bee-js

* feat: bee-js and bee v2.6 compatibility

* chore: switch upcoming/bee-js to ethersphere/bee-js
This commit is contained in:
Cafe137
2025-07-16 17:10:14 +02:00
committed by GitHub
parent 082a8f52ef
commit 1249c0df71
62 changed files with 675 additions and 16303 deletions
+10 -9
View File
@@ -1,4 +1,5 @@
import { Box, Grid, Typography } from '@material-ui/core'
import { DAI } from '@ethersphere/bee-js'
import { ReactElement, useContext } from 'react'
import { useNavigate } from 'react-router'
import Check from 'remixicon-react/CheckLineIcon'
@@ -9,10 +10,9 @@ import { Loading } from '../../components/Loading'
import { SwarmButton } from '../../components/SwarmButton'
import { SwarmDivider } from '../../components/SwarmDivider'
import { Context } from '../../providers/Bee'
import { Context as BalanceProvider } from '../../providers/WalletBalance'
import { TopUpProgressIndicator } from './TopUpProgressIndicator'
const MINIMUM_XDAI = '0.5'
const MINIMUM_XDAI = DAI.fromDecimalString('0.5')
interface Props {
header: string
@@ -22,15 +22,14 @@ interface Props {
}
export default function Index({ header, title, p, next }: Props): ReactElement {
const { nodeAddresses } = useContext(Context)
const { balance } = useContext(BalanceProvider)
const { nodeAddresses, walletBalance } = useContext(Context)
const navigate = useNavigate()
if (!balance || !nodeAddresses) {
if (!walletBalance || !nodeAddresses) {
return <Loading />
}
const disabled = balance.dai.toDecimal.lt(MINIMUM_XDAI)
const disabled = walletBalance.nativeTokenBalance.lt(MINIMUM_XDAI)
return (
<>
@@ -44,17 +43,19 @@ export default function Index({ header, title, p, next }: Props): ReactElement {
<Box mb={4}>{p}</Box>
<SwarmDivider mb={4} />
<Box mb={0.25}>
<ExpandableListItemKey label="Funding wallet address" value={nodeAddresses.ethereum} expanded />
<ExpandableListItemKey label="Funding wallet address" value={nodeAddresses.ethereum.toChecksum()} expanded />
</Box>
<Box mb={4}>
<ExpandableListItem label="xDAI balance" value={balance.dai.toSignificantDigits(4)} />
<ExpandableListItem label="xDAI balance" value={walletBalance.nativeTokenBalance.toSignificantDigits(4)} />
</Box>
<Grid container direction="row" justifyContent="space-between">
<SwarmButton iconType={Check} onClick={() => navigate(next)} disabled={disabled}>
Proceed
</SwarmButton>
{disabled ? (
<Typography>Please deposit at least {MINIMUM_XDAI} xDAI to the address above in order to proceed.</Typography>
<Typography>
Please deposit at least {MINIMUM_XDAI.toSignificantDigits(4)} xDAI to the address above in order to proceed.
</Typography>
) : null}
</Grid>
</>
+13 -8
View File
@@ -1,5 +1,5 @@
import { BeeModes } from '@ethersphere/bee-js'
import { Box, Typography } from '@material-ui/core'
import { BeeModes } from '@ethersphere/bee-js'
import { useSnackbar } from 'notistack'
import { ReactElement, useContext, useEffect, useState } from 'react'
import { useNavigate, useParams } from 'react-router'
@@ -14,16 +14,14 @@ import { SwarmButton } from '../../components/SwarmButton'
import { SwarmDivider } from '../../components/SwarmDivider'
import { Context as BeeContext } from '../../providers/Bee'
import { Context as SettingsContext } from '../../providers/Settings'
import { Context as BalanceProvider } from '../../providers/WalletBalance'
import { ROUTES } from '../../routes'
import { sleepMs } from '../../utils'
import { restartBeeNode, upgradeToLightNode } from '../../utils/desktop'
import { ResolvedWallet } from '../../utils/wallet'
export function GiftCardFund(): ReactElement {
const { nodeAddresses, nodeInfo } = useContext(BeeContext)
const { nodeAddresses, nodeInfo, walletBalance } = useContext(BeeContext)
const { isDesktop, desktopUrl, rpcProvider, rpcProviderUrl } = useContext(SettingsContext)
const { balance } = useContext(BalanceProvider)
const [loading, setLoading] = useState(false)
const [wallet, setWallet] = useState<ResolvedWallet | null>(null)
@@ -41,7 +39,7 @@ export function GiftCardFund(): ReactElement {
ResolvedWallet.make(privateKeyString, rpcProvider).then(setWallet)
}, [privateKeyString, rpcProvider])
if (!wallet || !balance) {
if (!wallet || !walletBalance) {
return <Loading />
}
@@ -108,13 +106,20 @@ export function GiftCardFund(): ReactElement {
<ArrowDown size={24} color="#aaaaaa" />
</Box>
<Box mb={0.25}>
<ExpandableListItemKey label="Node wallet address" value={nodeAddresses?.ethereum || 'N/A'} expanded />
<ExpandableListItemKey
label="Node wallet address"
value={nodeAddresses?.ethereum.toChecksum() || 'N/A'}
expanded
/>
</Box>
<Box mb={0.25}>
<ExpandableListItem label="xDAI balance" value={`${balance.dai.toSignificantDigits(4)} xDAI`} />
<ExpandableListItem
label="xDAI balance"
value={`${walletBalance.nativeTokenBalance.toSignificantDigits(4)} xDAI`}
/>
</Box>
<Box mb={2}>
<ExpandableListItem label="xBZZ balance" value={`${balance.bzz.toSignificantDigits(4)} xBZZ`} />
<ExpandableListItem label="xBZZ balance" value={`${walletBalance.bzzBalance.toSignificantDigits(4)} xBZZ`} />
</Box>
<SwarmButton iconType={Check} onClick={onFund} disabled={loading} loading={loading}>
{canUpgradeToLightNode ? 'Send all funds to your node and Upgrade' : 'Send all funds to your node'}
+6 -7
View File
@@ -1,17 +1,16 @@
import { Box, Typography } from '@material-ui/core'
import { BZZ, DAI } from '@ethersphere/bee-js'
import { Wallet } from 'ethers'
import { useSnackbar } from 'notistack'
import { ReactElement, useContext, useState } from 'react'
import ArrowRight from 'remixicon-react/ArrowRightLineIcon'
import { useNavigate } from 'react-router'
import { Context as SettingsContext } from '../../providers/Settings'
import ArrowRight from 'remixicon-react/ArrowRightLineIcon'
import { HistoryHeader } from '../../components/HistoryHeader'
import { ProgressIndicator } from '../../components/ProgressIndicator'
import { SwarmButton } from '../../components/SwarmButton'
import { SwarmDivider } from '../../components/SwarmDivider'
import { SwarmTextInput } from '../../components/SwarmTextInput'
import { BzzToken } from '../../models/BzzToken'
import { DaiToken } from '../../models/DaiToken'
import { Context as SettingsContext } from '../../providers/Settings'
import { ROUTES } from '../../routes'
import { Rpc } from '../../utils/rpc'
@@ -29,10 +28,10 @@ export function GiftCardTopUpIndex(): ReactElement {
setLoading(true)
try {
const wallet = new Wallet(giftCode, rpcProvider)
const dai = new DaiToken(await Rpc._eth_getBalance(wallet.address, rpcProvider))
const bzz = new BzzToken(await Rpc._eth_getBalanceERC20(wallet.address, rpcProvider))
const dai = await Rpc._eth_getBalance(wallet.address, rpcProvider)
const bzz = await Rpc._eth_getBalanceERC20(wallet.address, rpcProvider)
if (dai.toDecimal.lt(0.001) || bzz.toDecimal.lt(0.001)) {
if (dai.lt(DAI.fromDecimalString('0.001')) || bzz.lt(BZZ.fromDecimalString('0.001'))) {
throw Error('Gift wallet does not have enough funds')
}
enqueueSnackbar('Successfully verified gift wallet', { variant: 'success' })
+38 -43
View File
@@ -1,5 +1,5 @@
import { BeeModes } from '@ethersphere/bee-js'
import { Box, Typography } from '@material-ui/core'
import { BeeModes, BZZ, DAI } from '@ethersphere/bee-js'
import { useSnackbar } from 'notistack'
import { ReactElement, useContext, useEffect, useState } from 'react'
import { useNavigate } from 'react-router'
@@ -13,14 +13,11 @@ import { Loading } from '../../components/Loading'
import { SwarmButton } from '../../components/SwarmButton'
import { SwarmDivider } from '../../components/SwarmDivider'
import { SwarmTextInput } from '../../components/SwarmTextInput'
import { BZZ_DECIMAL_PLACES, BzzToken } from '../../models/BzzToken'
import { DaiToken } from '../../models/DaiToken'
import { Context as BeeContext } from '../../providers/Bee'
import { Context as SettingsContext } from '../../providers/Settings'
import { Context as BalanceProvider } from '../../providers/WalletBalance'
import { ROUTES } from '../../routes'
import { sleepMs } from '../../utils'
import { SwapError, isSwapError, wrapWithSwapError } from '../../utils/SwapError'
import { isSwapError, SwapError, wrapWithSwapError } from '../../utils/SwapError'
import {
getBzzPriceAsDai,
getDesktopConfiguration,
@@ -31,8 +28,8 @@ import {
import { Rpc } from '../../utils/rpc'
import { TopUpProgressIndicator } from './TopUpProgressIndicator'
const MINIMUM_XDAI = '0.1'
const MINIMUM_XBZZ = '0.1'
const MINIMUM_XDAI = DAI.fromDecimalString('0.1')
const MINIMUM_XBZZ = BZZ.fromDecimalString('0.1')
const GENERIC_SWAP_FAILED_ERROR_MESSAGE = 'Failed to swap. The full error is printed to the console.'
@@ -44,15 +41,14 @@ export function Swap({ header }: Props): ReactElement {
const [loading, setLoading] = useState(false)
const [hasSwapped, setSwapped] = useState(false)
const [userInputSwap, setUserInputSwap] = useState<string | null>(null)
const [price, setPrice] = useState(DaiToken.fromDecimal('0.6'))
const [price, setPrice] = useState(DAI.fromDecimalString('0.3'))
const [error, setError] = useState<string | null>(null)
const [daiToSwap, setDaiToSwap] = useState<DaiToken | null>(null)
const [bzzAfterSwap, setBzzAfterSwap] = useState<BzzToken | null>(null)
const [daiAfterSwap, setDaiAfterSwap] = useState<DaiToken | null>(null)
const [daiToSwap, setDaiToSwap] = useState<DAI | null>(null)
const [bzzAfterSwap, setBzzAfterSwap] = useState<BZZ | null>(null)
const [daiAfterSwap, setDaiAfterSwap] = useState<DAI | null>(null)
const { rpcProviderUrl, isDesktop, desktopUrl } = useContext(SettingsContext)
const { nodeAddresses, nodeInfo } = useContext(BeeContext)
const { balance } = useContext(BalanceProvider)
const { nodeAddresses, nodeInfo, walletBalance } = useContext(BeeContext)
const navigate = useNavigate()
const { enqueueSnackbar } = useSnackbar()
@@ -65,30 +61,30 @@ export function Swap({ header }: Props): ReactElement {
// Set the initial xDAI to swap
useEffect(() => {
if (!balance || userInputSwap) {
if (!walletBalance || userInputSwap) {
return
}
const minimumOptimalValue = DaiToken.fromDecimal('1').plusBaseUnits(MINIMUM_XDAI).toDecimal
const minimumOptimalValue = DAI.fromDecimalString('1').plus(MINIMUM_XDAI)
if (balance.dai.toDecimal.isGreaterThanOrEqualTo(minimumOptimalValue)) {
if (walletBalance.nativeTokenBalance.gte(minimumOptimalValue)) {
// Balance has at least 1 + MINIMUM_XDAI xDai
setDaiToSwap(balance.dai.minusBaseUnits('1'))
setDaiToSwap(walletBalance.nativeTokenBalance.minus(DAI.fromDecimalString('1')))
} else {
// Balance is low, halve the amount
setDaiToSwap(new DaiToken(balance.dai.toBigNumber.dividedToIntegerBy(2)))
setDaiToSwap(walletBalance.nativeTokenBalance.divide(BigInt(2)))
}
}, [balance, userInputSwap])
}, [walletBalance, userInputSwap])
// Set the xDAI to swap based on user input
useEffect(() => {
setError(null)
try {
if (userInputSwap) {
const dai = DaiToken.fromDecimal(userInputSwap)
const dai = DAI.fromDecimalString(userInputSwap)
setDaiToSwap(dai)
if (dai.toDecimal.lte(0)) {
if (dai.lte(DAI.fromDecimalString('0'))) {
setError('xDAI to swap must be a positive number')
}
}
@@ -99,25 +95,23 @@ export function Swap({ header }: Props): ReactElement {
// Calculate the amount of tokens after swap
useEffect(() => {
if (!balance || !daiToSwap || error) {
if (!walletBalance || !daiToSwap || error) {
return
}
const daiAfterSwap = new DaiToken(balance.dai.toBigNumber.minus(daiToSwap.toBigNumber))
const daiAfterSwap = walletBalance.nativeTokenBalance.minus(daiToSwap)
setDaiAfterSwap(daiAfterSwap)
const tokensConverted = BzzToken.fromDecimal(
daiToSwap.toBigNumber.dividedBy(price.toBigNumber).decimalPlaces(BZZ_DECIMAL_PLACES),
)
const bzzAfterSwap = new BzzToken(tokensConverted.toBigNumber.plus(balance.bzz.toBigNumber))
const tokensConverted = daiToSwap.exchangeToBZZ(price)
const bzzAfterSwap = tokensConverted.plus(walletBalance.bzzBalance)
setBzzAfterSwap(bzzAfterSwap)
if (daiAfterSwap.toDecimal.lt(MINIMUM_XDAI)) {
setError(`Must keep at least ${MINIMUM_XDAI} xDAI after swap!`)
} else if (bzzAfterSwap.toDecimal.lt(MINIMUM_XBZZ)) {
setError(`Must have at least ${MINIMUM_XBZZ} xBZZ after swap!`)
if (daiAfterSwap.lt(MINIMUM_XDAI)) {
setError(`Must keep at least ${MINIMUM_XDAI.toSignificantDigits(4)} xDAI after swap!`)
} else if (bzzAfterSwap.lt(MINIMUM_XBZZ)) {
setError(`Must have at least ${MINIMUM_XBZZ.toSignificantDigits(4)} xBZZ after swap!`)
}
}, [error, balance, daiToSwap, price])
}, [error, walletBalance, daiToSwap, price])
if (!balance || !nodeAddresses || !daiToSwap || !bzzAfterSwap || !daiAfterSwap) {
if (!walletBalance || !nodeAddresses || !daiToSwap || !bzzAfterSwap || !daiAfterSwap) {
return <Loading />
}
@@ -135,9 +129,9 @@ export function Swap({ header }: Props): ReactElement {
}
}
async function sendSwapRequest(daiToSwap: DaiToken) {
async function sendSwapRequest(daiToSwap: DAI) {
try {
await performSwap(desktopUrl, daiToSwap.toString)
await performSwap(desktopUrl, daiToSwap)
} catch (error) {
// eslint-disable-next-line no-console
console.error(error)
@@ -145,7 +139,7 @@ export function Swap({ header }: Props): ReactElement {
}
}
async function performSwapWithChecks(daiToSwap: DaiToken) {
async function performSwapWithChecks(daiToSwap: DAI) {
if (!localStorage.getItem('apiKey')) {
throw new SwapError('API key is not set, reopen dashboard through Swarm Desktop')
}
@@ -186,7 +180,9 @@ export function Swap({ header }: Props): ReactElement {
: 'Successfully swapped. Balances will refresh soon. You may now navigate away.'
enqueueSnackbar(message, { variant: 'success' })
if (canUpgradeToLightNode) await restart()
if (canUpgradeToLightNode) {
await restart()
}
} catch (error) {
if (isSwapError(error)) {
// we have a custom and user friendly error message
@@ -201,7 +197,6 @@ export function Swap({ header }: Props): ReactElement {
console.error(error) // eslint-disable-line
}
} finally {
balance?.refresh()
setLoading(false)
}
}
@@ -217,15 +212,15 @@ export function Swap({ header }: Props): ReactElement {
</Box>
<Box mb={4}>
<Typography>
You need to swap xDAI to xBZZ in order to use Swarm. Make sure to keep at least {MINIMUM_XDAI} xDAI in order
to pay for transaction costs on the network.
You need to swap xDAI to xBZZ in order to use Swarm. Make sure to keep at least{' '}
{MINIMUM_XDAI.toSignificantDigits(4)} xDAI in order to pay for transaction costs on the network.
</Typography>
</Box>
<SwarmDivider mb={4} />
<Box mb={4}>
<Typography>
Your current balance is {balance.dai.toSignificantDigits(4)} xDAI and {balance.bzz.toSignificantDigits(4)}{' '}
xBZZ.
Your current balance is {walletBalance.nativeTokenBalance.toSignificantDigits(4)} xDAI and{' '}
{walletBalance.bzzBalance.toSignificantDigits(4)} xBZZ.
</Typography>
</Box>
<Box mb={4}>
@@ -242,7 +237,7 @@ export function Swap({ header }: Props): ReactElement {
<ArrowDown size={24} color="#aaaaaa" />
</Box>
<Box mb={0.25}>
<ExpandableListItemKey label="Funding wallet address" value={nodeAddresses.ethereum} expanded />
<ExpandableListItemKey label="Funding wallet address" value={nodeAddresses.ethereum.toChecksum()} expanded />
</Box>
<Box mb={0.25}>
<ExpandableListItem
+7 -9
View File
@@ -1,5 +1,5 @@
import { BeeModes } from '@ethersphere/bee-js'
import { Box, createStyles, Grid, makeStyles, Typography } from '@material-ui/core'
import { BeeModes, BZZ, DAI } from '@ethersphere/bee-js'
import { useSnackbar } from 'notistack'
import { ReactElement, useContext, useState } from 'react'
import { useNavigate } from 'react-router'
@@ -15,7 +15,6 @@ import { SwarmButton } from '../../components/SwarmButton'
import TroubleshootConnectionCard from '../../components/TroubleshootConnectionCard'
import { Context as BeeContext, CheckState } from '../../providers/Bee'
import { Context as SettingsContext } from '../../providers/Settings'
import { Context as BalanceProvider } from '../../providers/WalletBalance'
import { ROUTES } from '../../routes'
import { restartBeeNode, upgradeToLightNode } from '../../utils/desktop'
@@ -33,15 +32,14 @@ const useStyles = makeStyles(() =>
}),
)
const MINIMUM_XDAI = '0.05'
const MINIMUM_XBZZ = '0.1'
const MINIMUM_XDAI = DAI.fromDecimalString('0.05')
const MINIMUM_XBZZ = BZZ.fromDecimalString('0.1')
export default function TopUp(): ReactElement {
const navigate = useNavigate()
const styles = useStyles()
const { isDesktop, desktopUrl } = useContext(SettingsContext)
const { nodeInfo, status } = useContext(BeeContext)
const { balance } = useContext(BalanceProvider)
const { nodeInfo, status, walletBalance } = useContext(BeeContext)
const { rpcProviderUrl } = useContext(SettingsContext)
const [loading, setLoading] = useState(false)
const { enqueueSnackbar } = useSnackbar()
@@ -49,8 +47,8 @@ export default function TopUp(): ReactElement {
const canUpgradeToLightNode =
isDesktop &&
nodeInfo?.beeMode === BeeModes.ULTRA_LIGHT &&
balance?.dai.toDecimal.gte(MINIMUM_XDAI) &&
balance?.bzz.toDecimal.gte(MINIMUM_XBZZ)
walletBalance?.nativeTokenBalance.gte(MINIMUM_XDAI) &&
walletBalance?.bzzBalance.gte(MINIMUM_XBZZ)
async function restart() {
setLoading(true)
@@ -67,7 +65,7 @@ export default function TopUp(): ReactElement {
if (status.all === CheckState.ERROR) return <TroubleshootConnectionCard />
if (!balance) {
if (!walletBalance) {
return <Loading />
}