From 793dbdef7e6a7fc9dc44168ceb35afa1cc3eb7c2 Mon Sep 17 00:00:00 2001 From: Fouad Date: Thu, 22 Jul 2021 12:00:46 +0100 Subject: [PATCH] update types --- wallet-web/components/ExecFeeNotice.tsx | 7 +- wallet-web/components/bond/BondNodeForm.tsx | 775 +++++++++++--------- wallet-web/components/bond/NodeBond.tsx | 2 +- 3 files changed, 428 insertions(+), 356 deletions(-) diff --git a/wallet-web/components/ExecFeeNotice.tsx b/wallet-web/components/ExecFeeNotice.tsx index 5807ba0a46..39cb196e9a 100644 --- a/wallet-web/components/ExecFeeNotice.tsx +++ b/wallet-web/components/ExecFeeNotice.tsx @@ -1,15 +1,12 @@ import {Alert} from '@material-ui/lab'; import { getDisplayExecGasFee } from "../common/helpers"; -type ExecFeeNoticeProps = { - name: string -} -const ExecFeeNotice = (props: ExecFeeNoticeProps) => { +const ExecFeeNotice = ({name}: {name: string}) => { return ( The gas fee for - {props.name} + {name} {`is ${getDisplayExecGasFee()}`} ) diff --git a/wallet-web/components/bond/BondNodeForm.tsx b/wallet-web/components/bond/BondNodeForm.tsx index d5e0265ce6..fb150ff8e4 100644 --- a/wallet-web/components/bond/BondNodeForm.tsx +++ b/wallet-web/components/bond/BondNodeForm.tsx @@ -1,380 +1,455 @@ -import React from 'react'; -import Grid from '@material-ui/core/Grid'; -import TextField from '@material-ui/core/TextField'; -import { Button, Checkbox, FormControlLabel, InputAdornment } from "@material-ui/core"; +import React from "react"; +import Grid from "@material-ui/core/Grid"; +import TextField from "@material-ui/core/TextField"; +import { + Button, + Checkbox, + FormControlLabel, + InputAdornment, +} from "@material-ui/core"; import bs58 from "bs58"; -import semver from "semver" +import semver from "semver"; import { NodeType } from "../../common/node"; import { theme } from "../../lib/theme"; -import { basicRawCoinValueValidation, makeBasicStyle, validateRawPort } from "../../common/helpers"; +import { + basicRawCoinValueValidation, + makeBasicStyle, + validateRawPort, +} from "../../common/helpers"; import { Coin, nativeToPrintable } from "@nymproject/nym-validator-client"; import { DENOM } from "../../pages/_app"; import { printableBalanceToNative } from "@nymproject/nym-validator-client/dist/currency"; import { BondingInformation } from "./NodeBond"; -const DEFAULT_MIX_PORT = 1789 -const DEFAULT_VERLOC_PORT = 1790 -const DEFAULT_HTTP_API_PORT = 8000 -const DEFAULT_CLIENTS_PORT = 9000 +const DEFAULT_MIX_PORT = 1789; +const DEFAULT_VERLOC_PORT = 1790; +const DEFAULT_HTTP_API_PORT = 8000; +const DEFAULT_CLIENTS_PORT = 9000; -type BondNodeFormProps = { - type: NodeType - minimumMixnodeBond: Coin, - minimumGatewayBond: Coin, - onSubmit: (event: any) => void -} +type TBondNodeFormProps = { + type: NodeType; + minimumMixnodeBond: Coin; + minimumGatewayBond: Coin; + onSubmit: (event: any) => void; +}; -export default function BondNodeForm(props: BondNodeFormProps) { - const classes = makeBasicStyle(theme); +type TFormInput = { + amount: string; + host: string; + http_api_port: string; + mixPort: string; + verlocPort: string; + sphinxKey: string; + identityKey: string; + version: string; + location?: string; + clientsPort?: string; + httpApiPort?: string; +}; - const [validity, setValidity] = React.useState({ - validAmount: true, - validSphinxKey: true, - validIdentityKey: true, - validHost: true, - validVersion: true, - validLocation: true, - validMixPort: true, +export default function BondNodeForm(props: TBondNodeFormProps) { + const classes = makeBasicStyle(theme); - // this should have probably be somehow split to be subclasses of the validity matrix - // the above is more true now as more fields are added. This looks kinda disgusting... - // mixnode-specific: - validVerlocPort: true, - validHttpApiPort: true, + const [validity, setValidity] = React.useState({ + validAmount: true, + validSphinxKey: true, + validIdentityKey: true, + validHost: true, + validVersion: true, + validLocation: true, + validMixPort: true, - // gateway-specific: - validClientsPort: true, - }) + // this should have probably be somehow split to be subclasses of the validity matrix + // the above is more true now as more fields are added. This looks kinda disgusting... + // mixnode-specific: + validVerlocPort: true, + validHttpApiPort: true, - const [advancedShown, setAdvancedShown] = React.useState(false) + // gateway-specific: + validClientsPort: true, + }); - const handleCheckboxToggle = () => { - setAdvancedShown((prevSet) => !prevSet); + const [advancedShown, setAdvancedShown] = React.useState(false); + + const handleCheckboxToggle = () => { + setAdvancedShown((prevSet) => !prevSet); + }; + + const validateForm = ({ + amount, + sphinxKey, + identityKey, + host, + version, + verlocPort, + location, + mixPort, + httpApiPort, + clientsPort, + }: TFormInput): boolean => { + let validAmount = validateAmount(amount); + let validSphinxKey = validateKey(sphinxKey); + let validIdentityKey = validateKey(identityKey); + let validHost = validateHost(host); + let validVersion = validateVersion(version); + + let validLocation = + props.type == NodeType.Gateway ? validateLocation(location) : true; + + let newValidity = { + validAmount: validAmount, + validSphinxKey: validSphinxKey, + validIdentityKey: validIdentityKey, + validHost: validHost, + validVersion: validVersion, + validLocation: validLocation, + }; + + if (advancedShown) { + let validMixPort = validateRawPort(mixPort); + let validVerlocPort = + props.type == NodeType.Mixnode ? validateRawPort(verlocPort) : true; + let validHttpApiPort = + props.type == NodeType.Mixnode ? validateRawPort(httpApiPort) : true; + let validClientsPort = + props.type == NodeType.Gateway ? validateRawPort(clientsPort) : true; + + newValidity = { + ...newValidity, + ...{ + validMixPort: validMixPort, + validVerlocPort: validVerlocPort, + validHttpApiPort: validHttpApiPort, + validClientsPort: validClientsPort, + }, + }; } + setValidity((previousState) => { + return { ...previousState, ...newValidity }; + }); - const validateForm = (event: any): boolean => { - let validAmount = validateAmount(event.target.amount.value); - let validSphinxKey = validateKey(event.target.sphinxkey.value); - let validIdentityKey = validateKey(event.target.identity.value); - let validHost = validateHost(event.target.host.value); - let validVersion = validateVersion(event.target.version.value); + // just AND everything together + const reducer = (acc, current) => acc && current; + return Object.entries(newValidity) + .map((entry) => entry[1]) + .reduce(reducer, true); + }; - let validLocation = (props.type == NodeType.Gateway) ? validateLocation(event.target.location.value) : true; + const validateAmount = (rawValue: string): boolean => { + // tests basic coin value requirements, like no more than 6 decimal places, value lower than total supply, etc + if (!basicRawCoinValueValidation(rawValue)) { + return false; + } - let newValidity = { - validAmount: validAmount, - validSphinxKey: validSphinxKey, - validIdentityKey: validIdentityKey, - validHost: validHost, - validVersion: validVersion, + // this conversion seems really iffy but I'm not sure how to better approach it + let nativeValueString = printableBalanceToNative(rawValue); + let nativeValue = parseInt(nativeValueString); + if (props.type == NodeType.Mixnode) { + return nativeValue >= parseInt(props.minimumMixnodeBond.amount); + } else { + return nativeValue >= parseInt(props.minimumGatewayBond.amount); + } + }; - validLocation: validLocation, - } + const validateKey = (key: string): boolean => { + // it must be a valid base58 key + try { + const bytes = bs58.decode(key); + // of length 32 + return bytes.length === 32; + } catch { + return false; + } + }; - if (advancedShown) { - let validMixPort = validateRawPort(event.target.mixPort.value) - let validVerlocPort = (props.type == NodeType.Mixnode) ? validateRawPort(event.target.verlocPort.value) : true; - let validHttpApiPort = (props.type == NodeType.Mixnode) ? validateRawPort(event.target.httpApiPort.value) : true; - let validClientsPort = (props.type == NodeType.Gateway) ? validateRawPort(event.target.clientsPort.value) : true; + const validateHost = (host: string): boolean => { + // I don't think that proper checks are in scope of the change here + // what would need to be checked is whether one of the following is true: + // - host is an ipv4 address + // - host is an ipv6 address + // - host is a valid hostname - newValidity = { - ...newValidity, ...{ - validMixPort: validMixPort, - validVerlocPort: validVerlocPort, - validHttpApiPort: validHttpApiPort, - validClientsPort: validClientsPort, + // so at least perform the dumbest possible checks + // ipv4 needs 4 dot-separated octets + // ipv6 can have multiple possible representations, but it needs to contain at least two colons + // a hostname (in this case) needs to have a top level domain present + + const dot_occurrences = host.split(".").length - 1; + const colon_occurrences = host.split(":").length - 1; + + if (dot_occurrences == 3) { + // possible ipv4 + // make sure it has no ports attached! + return colon_occurrences == 0; + } else if (colon_occurrences >= 2) { + // possible ipv6 + return true; + } else if (dot_occurrences >= 1) { + // possible hostname + // make sure it has no ports attached! + return colon_occurrences == 0; + } + return false; + }; + + const validateVersion = (version: string): boolean => { + // check if its a valid semver + return semver.valid(version) && semver.minor(version) >= 11; + }; + + const validateLocation = (location: string): boolean => { + // right now only perform the stupid check of whether the user copy-pasted the tooltip... (with or without brackets) + return !location.trim().includes("physical location of your node"); + }; + + const constructMixnodeBondingInfo = ({ + amount, + host, + httpApiPort, + mixPort, + verlocPort, + sphinxKey, + identityKey, + version, + }: TFormInput): BondingInformation => { + return { + amount, + nodeDetails: { + host, + http_api_port: advancedShown + ? parseInt(httpApiPort) + : DEFAULT_HTTP_API_PORT, + mix_port: advancedShown ? parseInt(mixPort) : DEFAULT_MIX_PORT, + verloc_port: advancedShown ? parseInt(verlocPort) : DEFAULT_VERLOC_PORT, + sphinx_key: sphinxKey, + identity_key: identityKey, + version, + }, + }; + }; + + const constructGatewayBondingInfo = ( + data: TFormInput + ): BondingInformation => { + return { + amount: data.amount, + nodeDetails: { + host: data.host, + mix_port: advancedShown ? parseInt(data.mixPort) : DEFAULT_MIX_PORT, + clients_port: advancedShown + ? parseInt(data.clientsPort) + : DEFAULT_CLIENTS_PORT, + sphinx_key: data.sphinxKey, + identity_key: data.identityKey, + version: data.version, + location: data.location, + }, + }; + }; + + const submitForm = (event: React.FormEvent) => { + event.preventDefault(); + const target = event.target as unknown as TFormInput; + + if (validateForm(target)) { + if (props.type == NodeType.Mixnode) { + return props.onSubmit(constructMixnodeBondingInfo(target)); + } else { + return props.onSubmit(constructGatewayBondingInfo(target)); + } + } + }; + + let minimumBond = props.minimumMixnodeBond; + if (props.type == NodeType.Gateway) { + minimumBond = props.minimumGatewayBond; + } + + // if this whole interface wasn't to be completely redone in a month time, I would have definitely redone the form + // but I guess it's fine for time being + return ( +
+ + + {DENOM} + ), + }} + /> + - setValidity((previousState) => { - return {...previousState, ...newValidity} - }); + + + + + + + + + - // just AND everything together - const reducer = (acc, current) => acc && current; - return Object.entries(newValidity).map((entry) => entry[1]).reduce(reducer, true) - } + {/* if it's a gateway - get location */} + + {props.type === NodeType.Gateway && ( + + )} + - const validateAmount = (rawValue: string): boolean => { - // tests basic coin value requirements, like no more than 6 decimal places, value lower than total supply, etc - if (!basicRawCoinValueValidation(rawValue)) { - return false - } - - // this conversion seems really iffy but I'm not sure how to better approach it - let nativeValueString = printableBalanceToNative(rawValue) - let nativeValue = parseInt(nativeValueString) - if (props.type == NodeType.Mixnode) { - return nativeValue >= parseInt(props.minimumMixnodeBond.amount) - } else { - return nativeValue >= parseInt(props.minimumGatewayBond.amount) - } - } - - const validateKey = (key: string): boolean => { - // it must be a valid base58 key - try { - const bytes = bs58.decode(key); - // of length 32 - return bytes.length === 32 - } catch { - return false - } - } - - const validateHost = (host: string): boolean => { - // I don't think that proper checks are in scope of the change here - // what would need to be checked is whether one of the following is true: - // - host is an ipv4 address - // - host is an ipv6 address - // - host is a valid hostname - - // so at least perform the dumbest possible checks - // ipv4 needs 4 dot-separated octets - // ipv6 can have multiple possible representations, but it needs to contain at least two colons - // a hostname (in this case) needs to have a top level domain present - - const dot_occurrences = host.split('.').length - 1 - const colon_occurrences = host.split(':').length - 1 - - if (dot_occurrences == 3) { - // possible ipv4 - // make sure it has no ports attached! - return colon_occurrences == 0 - } else if (colon_occurrences >= 2) { - // possible ipv6 - return true - } else if (dot_occurrences >= 1) { - // possible hostname - // make sure it has no ports attached! - return colon_occurrences == 0 - } - return false - } - - const validateVersion = (version: string): boolean => { - // check if its a valid semver - return semver.valid(version) && semver.minor(version) >= 11 - - } - - const validateLocation = (location: string): boolean => { - // right now only perform the stupid check of whether the user copy-pasted the tooltip... (with or without brackets) - return !location.trim().includes("physical location of your node") - } - - const constructMixnodeBondingInfo = (event: any): BondingInformation => { - return { - amount: event.target.amount.value, - nodeDetails: { - host: event.target.host.value, - http_api_port: advancedShown ? parseInt(event.target.httpApiPort.value) : DEFAULT_HTTP_API_PORT, - mix_port: advancedShown ? parseInt(event.target.mixPort.value) : DEFAULT_MIX_PORT, - verloc_port: advancedShown ? parseInt(event.target.verlocPort.value) : DEFAULT_VERLOC_PORT, - sphinx_key: event.target.sphinxkey.value, - identity_key: event.target.identity.value, - version: event.target.version.value, - } - } - } - - const constructGatewayBondingInfo = (event: any): BondingInformation => { - return { - amount: event.target.amount.value, - nodeDetails: { - host: event.target.host.value, - mix_port: advancedShown ? parseInt(event.target.mixPort.value) : DEFAULT_MIX_PORT, - clients_port: advancedShown ? parseInt(event.target.clientsPort.value) : DEFAULT_CLIENTS_PORT, - sphinx_key: event.target.sphinxkey.value, - identity_key: event.target.identity.value, - version: event.target.version.value, - location: event.target.location.value - } - } - } - - const submitForm = (event: any) => { - event.preventDefault() - - if (validateForm(event)) { - if (props.type == NodeType.Mixnode) { - return props.onSubmit(constructMixnodeBondingInfo(event)) - } else { - return props.onSubmit(constructGatewayBondingInfo(event)) - } - } - } - - let minimumBond = props.minimumMixnodeBond; - if (props.type == NodeType.Gateway) { - minimumBond = props.minimumGatewayBond - } - - // if this whole interface wasn't to be completely redone in a month time, I would have definitely redone the form - // but I guess it's fine for time being - return ( - - - - {DENOM} - }} - /> - - - - - - - - - - - - - {/* if it's a gateway - get location */} - { - props.type === NodeType.Gateway && - - } - - - - - - - - - } - label="Show advanced options" - /> - - - {advancedShown && - - - - - - {/*yes, I also hate so many layers of indentation here*/} - {props.type === NodeType.Mixnode ? ( - - - - - - - - - - ) : ( - - - - )} - + + + + + + + } + label="Show advanced options" + /> + + + {advancedShown && ( + + + -
- -
- - ); -} \ No newline at end of file + {/*yes, I also hate so many layers of indentation here*/} + {props.type === NodeType.Mixnode ? ( + + + + + + + + + + ) : ( + + + + )} +
+ )} +
+ +
+ +
+ + ); +} diff --git a/wallet-web/components/bond/NodeBond.tsx b/wallet-web/components/bond/NodeBond.tsx index f7f1b18cf6..1eb7a706f6 100644 --- a/wallet-web/components/bond/NodeBond.tsx +++ b/wallet-web/components/bond/NodeBond.tsx @@ -150,7 +150,7 @@ const BondNode = () => {
- + Bond a {nodeType}