finish bonding and unbonding setup
This commit is contained in:
@@ -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,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 }
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
@@ -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}`)
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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?
|
||||
|
||||
@@ -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>
|
||||
)
|
||||
}
|
||||
@@ -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>
|
||||
)
|
||||
|
||||
@@ -6,8 +6,8 @@ export enum EnumNodeType {
|
||||
}
|
||||
|
||||
export type TNodeOwnership = {
|
||||
ownsMixnode: boolean
|
||||
ownsGateway: boolean
|
||||
hasOwnership: boolean
|
||||
nodeType?: EnumNodeType
|
||||
}
|
||||
|
||||
export type TClientDetails = {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user