finish bonding and unbonding setup

This commit is contained in:
fmtabbara
2021-09-15 20:37:24 +01:00
parent 64a5b4b593
commit e130131f16
12 changed files with 214 additions and 88 deletions
@@ -9,9 +9,11 @@ import React from 'react'
import { EnumNodeType } from '../types/global'
export const NodeTypeSelector = ({
disabled,
nodeType,
setNodeType,
}: {
disabled: boolean
nodeType: EnumNodeType
setNodeType: (nodeType: EnumNodeType) => void
}) => {
@@ -32,11 +34,13 @@ export const NodeTypeSelector = ({
value={EnumNodeType.mixnode}
control={<Radio />}
label="Mixnode"
disabled={disabled}
/>
<FormControlLabel
value={EnumNodeType.gateway}
control={<Radio />}
label="Gateway"
disabled={disabled}
/>
</RadioGroup>
</FormControl>
+1 -1
View File
@@ -1,6 +1,6 @@
import React, { createContext, useEffect, useState } from 'react'
import { useHistory } from 'react-router-dom'
import { Coin, TClientDetails, TSignInWithMnemonic } from '../types'
import { TClientDetails, TSignInWithMnemonic } from '../types'
import { TUseGetBalance, useGetBalance } from '../hooks/useGetBalance'
export const ADMIN_ADDRESS = 'punk1h3w4nj7kny5dfyjw2le4vm74z03v9vd4dstpu0'
@@ -0,0 +1,39 @@
import { useEffect, useState } from 'react'
import { checkGatewayOwnership, checkMixnodeOwnership } from '../requests'
import { EnumNodeType, TNodeOwnership } from '../types'
export const useCheckOwnership = () => {
const [ownership, setOwnership] = useState<TNodeOwnership>({
hasOwnership: false,
nodeType: undefined,
})
const [isLoading, setIsLoading] = useState(false)
const [error, setError] = useState<string>()
const checkOwnership = async () => {
const status = {} as TNodeOwnership
setIsLoading(true)
try {
const ownsMixnode = await checkMixnodeOwnership()
const ownsGateway = await checkGatewayOwnership()
if (ownsMixnode) {
status.hasOwnership = true
status.nodeType = EnumNodeType.mixnode
}
if (ownsGateway) {
status.hasOwnership = true
status.nodeType = EnumNodeType.gateway
}
setOwnership(status)
} catch (e) {
setError(e as string)
}
}
return { isLoading, error, ownership, checkOwnership }
}
+3 -3
View File
@@ -11,17 +11,17 @@ export type TUseGetBalance = {
export const useGetBalance = (): TUseGetBalance => {
const [balance, setBalance] = useState<Balance>()
const [error, setEror] = useState<string>()
const [error, setErorr] = useState<string>()
const [isLoading, setIsLoading] = useState(false)
const fetchBalance = () => {
setIsLoading(true)
setEror(undefined)
setErorr(undefined)
invoke('get_balance')
.then((balance) => {
setBalance(balance as Balance)
})
.catch((e) => setEror(e))
.catch((e) => setErorr(e))
setTimeout(() => {
setIsLoading(false)
}, 1000)
+20
View File
@@ -3,6 +3,8 @@ import {
Coin,
DelegationResult,
EnumNodeType,
Gateway,
MixNode,
Operation,
TauriTxResult,
TCreateAccount,
@@ -51,3 +53,21 @@ export const send = async (args: {
address: string
memo: string
}): Promise<TauriTxResult> => await invoke('send', args)
export const checkMixnodeOwnership = async (): Promise<boolean> =>
await invoke('owns_mixnode')
export const checkGatewayOwnership = async (): Promise<boolean> =>
await invoke('owns_gateway')
export const bond = async ({
type,
data,
amount,
}: {
type: EnumNodeType
data: MixNode | Gateway
amount: Coin
}): Promise<any> => await invoke(`bond_${type}`, { [type]: data, bond: amount })
export const unbond = async (type: EnumNodeType) =>
await invoke(`unbond_${type}`)
+42 -28
View File
@@ -1,4 +1,4 @@
import React from 'react'
import React, { useContext } from 'react'
import {
Button,
Checkbox,
@@ -11,14 +11,15 @@ import {
Theme,
} from '@material-ui/core'
import { useTheme } from '@material-ui/styles'
import { useForm } from 'react-hook-form'
import { Alert } from '@material-ui/lab'
import { yupResolver } from '@hookform/resolvers/yup'
import { useForm } from 'react-hook-form'
import { EnumNodeType } from '../../types/global'
import { NodeTypeSelector } from '../../components/NodeTypeSelector'
import { bond, majorToMinor } from '../../requests'
import { validationSchema } from './validationSchema'
import { Coin, Gateway, MixNode } from '../../types'
import { invoke } from '@tauri-apps/api'
import { Alert } from '@material-ui/lab'
import { ClientContext } from '../../context/main'
type TBondFormFields = {
withAdvancedOptions: boolean
@@ -57,29 +58,27 @@ const formatData = (data: TBondFormFields) => {
host: data.host,
version: data.version,
mix_port: data.mixPort,
amount: data.amount,
nodeType: data.nodeType,
}
if (data.nodeType === EnumNodeType.mixnode) {
payload.verloc_port = data.verlocPort
payload.http_api_port = data.httpApiPort
return payload as MixNode & { amount: number; nodeType: EnumNodeType }
}
if (data.nodeType == EnumNodeType.gateway) {
return payload as MixNode
} else {
payload.clients_port = data.clientsPort
payload.location = data.location
return payload as Gateway & { amount: number; nodeType: EnumNodeType }
return payload as Gateway
}
}
export const BondForm = ({
disabled,
fees,
onError,
onSuccess,
}: {
fees: { [key in EnumNodeType]: Coin }
disabled: boolean
fees?: { [key in EnumNodeType]: Coin }
onError: (message?: string) => void
onSuccess: (message?: string) => void
}) => {
@@ -94,6 +93,8 @@ export const BondForm = ({
defaultValues,
})
const { getBalance } = useContext(ClientContext)
const watchNodeType = watch('nodeType', defaultValues.nodeType)
const watchAdvancedOptions = watch(
'withAdvancedOptions',
@@ -102,12 +103,12 @@ export const BondForm = ({
const onSubmit = async (data: TBondFormFields) => {
const formattedData = formatData(data)
await invoke(`bond_${data.nodeType}`, {
[data.nodeType]: formattedData,
bond: { amount: formattedData?.amount, denom: 'Major' },
})
.then((res: any) => {
onSuccess(res)
const amount = await majorToMinor(data.amount)
await bond({ type: data.nodeType, data: formattedData, amount })
.then(() => {
getBalance.fetchBalance()
onSuccess(`Successfully bonded to ${data.identityKey}`)
})
.catch((e) => {
onError(e)
@@ -129,17 +130,20 @@ export const BondForm = ({
if (nodeType === EnumNodeType.mixnode)
setValue('location', undefined)
}}
disabled={disabled}
/>
</Grid>
<Grid item>
<Alert severity="info">
{`A fee of ${
watchNodeType === EnumNodeType.mixnode
? fees.mixnode.amount
: fees.gateway.amount
} PUNK will apply to this transaction`}
</Alert>
</Grid>
{fees && (
<Grid item>
<Alert severity="info">
{`A fee of ${
watchNodeType === EnumNodeType.mixnode
? fees.mixnode.amount
: fees.gateway.amount
} PUNK will apply to this transaction`}
</Alert>
</Grid>
)}
</Grid>
<Grid item xs={12}>
<TextField
@@ -152,6 +156,7 @@ export const BondForm = ({
fullWidth
error={!!errors.identityKey}
helperText={errors.identityKey?.message}
disabled={disabled}
/>
</Grid>
<Grid item xs={12}>
@@ -165,6 +170,7 @@ export const BondForm = ({
error={!!errors.sphinxKey}
helperText={errors.sphinxKey?.message}
fullWidth
disabled={disabled}
/>
</Grid>
<Grid item xs={12} sm={9}>
@@ -183,6 +189,7 @@ export const BondForm = ({
<InputAdornment position="end">punks</InputAdornment>
),
}}
disabled={disabled}
/>
</Grid>
@@ -197,6 +204,7 @@ export const BondForm = ({
fullWidth
error={!!errors.host}
helperText={errors.host?.message}
disabled={disabled}
/>
</Grid>
@@ -213,6 +221,7 @@ export const BondForm = ({
fullWidth
error={!!errors.location}
helperText={errors.location?.message}
disabled={disabled}
/>
)}
</Grid>
@@ -228,6 +237,7 @@ export const BondForm = ({
fullWidth
error={!!errors.version}
helperText={errors.version?.message}
disabled={disabled}
/>
</Grid>
@@ -275,6 +285,7 @@ export const BondForm = ({
helperText={
errors.mixPort?.message && 'A valid port value is required'
}
disabled={disabled}
/>
</Grid>
{watchNodeType === EnumNodeType.mixnode ? (
@@ -292,6 +303,7 @@ export const BondForm = ({
errors.verlocPort?.message &&
'A valid port value is required'
}
disabled={disabled}
/>
</Grid>
@@ -308,6 +320,7 @@ export const BondForm = ({
errors.httpApiPort?.message &&
'A valid port value is required'
}
disabled={disabled}
/>
</Grid>
</>
@@ -325,6 +338,7 @@ export const BondForm = ({
errors.clientsPort?.message &&
'A valid port value is required'
}
disabled={disabled}
/>
</Grid>
)}
@@ -343,7 +357,7 @@ export const BondForm = ({
}}
>
<Button
disabled={isSubmitting}
disabled={isSubmitting || disabled}
variant="contained"
color="primary"
type="submit"
+43 -16
View File
@@ -1,4 +1,4 @@
import React, { useEffect, useState } from 'react'
import React, { useContext, useEffect, useState } from 'react'
import { Box, Button, CircularProgress, Theme } from '@material-ui/core'
import { Alert } from '@material-ui/lab'
import { useTheme } from '@material-ui/styles'
@@ -9,34 +9,59 @@ import {
RequestStatus,
} from '../../components/RequestStatus'
import { Layout } from '../../layouts'
import { getGasFee } from '../../requests'
import { getGasFee, unbond } from '../../requests'
import { TFee } from '../../types'
import { useCheckOwnership } from '../../hooks/useCheckOwnership'
import { ClientContext } from '../../context/main'
export const Bond = () => {
const [status, setStatus] = useState(EnumRequestStatus.loading)
const [status, setStatus] = useState(EnumRequestStatus.initial)
const [message, setMessage] = useState<string>()
const [fees, setFees] = useState<TFee>()
const { checkOwnership, ownership } = useCheckOwnership()
const { getBalance } = useContext(ClientContext)
const theme: Theme = useTheme()
useEffect(() => {
const getFees = async () => {
const mixnode = await getGasFee('BondMixnode')
const gateway = await getGasFee('BondGateway')
setFees({
mixnode: mixnode,
gateway: gateway,
})
setStatus(EnumRequestStatus.initial)
if (status === EnumRequestStatus.initial) {
const initialiseForm = async () => {
await checkOwnership()
setFees({
mixnode: await getGasFee('BondMixnode'),
gateway: await getGasFee('BondGateway'),
})
setStatus(EnumRequestStatus.initial)
}
initialiseForm()
}
}, [status])
getFees()
}, [])
console.log(fees, status, message)
return (
<Layout>
<NymCard title="Bond" subheader="Bond a node or gateway" noPadding>
{ownership?.hasOwnership && (
<Alert
severity="warning"
action={
<Button
disabled={status === EnumRequestStatus.loading}
onClick={async () => {
setStatus(EnumRequestStatus.loading)
await unbond(ownership.nodeType!)
getBalance.fetchBalance()
setStatus(EnumRequestStatus.initial)
}}
>
Unbond
</Button>
}
style={{ margin: theme.spacing(2) }}
>
{`Looks like you already have a ${ownership.nodeType} bonded.`}
</Alert>
)}
{status === EnumRequestStatus.loading && (
<Box
style={{
@@ -50,7 +75,7 @@ export const Bond = () => {
)}
{status === EnumRequestStatus.initial && (
<BondForm
fees={fees!}
fees={!ownership.hasOwnership ? fees : undefined}
onError={(e?: string) => {
setMessage(e)
setStatus(EnumRequestStatus.error)
@@ -59,6 +84,7 @@ export const Bond = () => {
setMessage(message)
setStatus(EnumRequestStatus.success)
}}
disabled={ownership?.hasOwnership}
/>
)}
{(status === EnumRequestStatus.error ||
@@ -88,6 +114,7 @@ export const Bond = () => {
<Button
onClick={() => {
setStatus(EnumRequestStatus.initial)
checkOwnership()
}}
>
Again?
+3 -1
View File
@@ -73,7 +73,9 @@ const SignInContent = ({
}: {
showCreateAccount: () => void
}) => {
const [mnemonic, setMnemonic] = useState<string>('')
const [mnemonic, setMnemonic] = useState<string>(
'alley mutual arrange escape army vacuum cherry ozone frame steel current smile dad subject primary foster lazy want perfect fury general eye cannon motor'
)
const [inputError, setInputError] = useState<string>()
const [isLoading, setIsLoading] = useState(false)
@@ -1,34 +0,0 @@
import React, { useState } from 'react'
import { Alert } from '@material-ui/lab'
import { Button, Theme } from '@material-ui/core'
import { useTheme } from '@material-ui/styles'
export const UnbondForm = () => {
const theme: Theme = useTheme()
return (
<div>
<Alert severity="info" style={{ margin: theme.spacing(3) }}>
You don't currently have a bonded node
</Alert>
<div
style={{
display: 'flex',
alignItems: 'center',
justifyContent: 'flex-end',
borderTop: `1px solid ${theme.palette.grey[200]}`,
background: theme.palette.grey[100],
padding: theme.spacing(2),
}}
>
<Button
variant="contained"
color="primary"
type="submit"
disableElevation
>
Unbond
</Button>
</div>
</div>
)
}
+57 -2
View File
@@ -1,13 +1,68 @@
import React from 'react'
import React, { useContext, useEffect, useState } from 'react'
import { NymCard } from '../../components'
import { UnbondForm } from './UnbondForm'
import { Layout } from '../../layouts'
import { useCheckOwnership } from '../../hooks/useCheckOwnership'
import { Alert } from '@material-ui/lab'
import { Box, Button, CircularProgress, Theme } from '@material-ui/core'
import { ClientContext } from '../../context/main'
import { unbond } from '../../requests'
import { useTheme } from '@material-ui/styles'
export const Unbond = () => {
const [isLoading, setIsLoading] = useState(false)
const { checkOwnership, ownership } = useCheckOwnership()
const { getBalance } = useContext(ClientContext)
const theme: Theme = useTheme()
useEffect(() => {
const initialiseForm = async () => {
await checkOwnership()
}
initialiseForm()
}, [ownership.hasOwnership, checkOwnership])
return (
<Layout>
<NymCard title="Unbond" subheader="Unbond a mixnode or gateway" noPadding>
<UnbondForm />
{ownership?.hasOwnership && (
<Alert
severity="warning"
action={
<Button
disabled={isLoading}
onClick={async () => {
setIsLoading(true)
await unbond(ownership.nodeType!)
getBalance.fetchBalance()
setIsLoading(false)
}}
>
Unbond
</Button>
}
style={{ margin: theme.spacing(2) }}
>
{`Looks like you already have a ${ownership.nodeType} bonded.`}
</Alert>
)}
{!ownership.hasOwnership && (
<Alert severity="info" style={{ margin: theme.spacing(3) }}>
You don't currently have a bonded node
</Alert>
)}
{isLoading && (
<Box
style={{
display: 'flex',
justifyContent: 'center',
padding: theme.spacing(3),
}}
>
<CircularProgress size={48} />
</Box>
)}
</NymCard>
</Layout>
)
+2 -2
View File
@@ -6,8 +6,8 @@ export enum EnumNodeType {
}
export type TNodeOwnership = {
ownsMixnode: boolean
ownsGateway: boolean
hasOwnership: boolean
nodeType?: EnumNodeType
}
export type TClientDetails = {
-1
View File
@@ -75,7 +75,6 @@ export const validateVersion = (version: string): boolean => {
const validVersion = valid(version)
return validVersion !== null && minorVersion >= 11
} catch (e) {
console.log(e)
return false
}
}