Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow nym node config updates #5066

Merged
merged 1 commit into from
Oct 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { CurrencyDenom } from '@nymproject/types';
import { TBondNymNodeArgs, TBondMixNodeArgs } from 'src/types';

const defaultNymNodeValues: TBondNymNodeArgs['nymnode'] = {
identity_key: 'H6rXWgsW89QsVyaNSS3qBe9zZFLhBS6Gn3YRkGFSoFW9',
identity_key: '',
custom_http_port: null,
host: '1.1.1.1',
};
Expand Down
30 changes: 8 additions & 22 deletions nym-wallet/src/components/Bonding/forms/nym-node/NymNodeData.tsx
Original file line number Diff line number Diff line change
@@ -1,31 +1,12 @@
import React from 'react';
import * as yup from 'yup';
import * as Yup from 'yup';
import { Stack, TextField, FormControlLabel, Checkbox } from '@mui/material';
import { useForm } from 'react-hook-form';
import { IdentityKeyFormField } from '@nymproject/react/mixnodes/IdentityKeyFormField';
import { yupResolver } from '@hookform/resolvers/yup';
import { isValidHostname, validateRawPort } from 'src/utils';
import { SimpleModal } from 'src/components/Modals/SimpleModal';
import { useFormContext } from './FormContext';

const yupValidationSchema = yup.object().shape({
identity_key: yup.string().required('Identity key is required'),
host: yup
.string()
.required('A host is required')
.test('no-whitespace', 'Host cannot contain whitespace', (value) => !/\s/.test(value || ''))
.test('valid-host', 'A valid host is required', (value) => (value ? isValidHostname(value) : false)),

custom_http_port: yup
.number()
.nullable()
.test('valid-http', 'A valid http port is required', (value) => {
if (value === null) {
return true;
}
return value ? validateRawPort(value) : false;
}),
});
import { settingsValidationSchema } from './settingsValidationSchema';

type NymNodeDataProps = {
onClose: () => void;
Expand All @@ -34,6 +15,11 @@ type NymNodeDataProps = {
step: number;
};

const validationSchema = Yup.object().shape({
identity_key: Yup.string().required('Identity key is required'),
...settingsValidationSchema.fields,
});

const NymNodeData = ({ onClose, onNext, step }: NymNodeDataProps) => {
const { setNymNodeData, nymNodeData } = useFormContext();
const {
Expand All @@ -44,7 +30,7 @@ const NymNodeData = ({ onClose, onNext, step }: NymNodeDataProps) => {
} = useForm({
mode: 'all',
defaultValues: nymNodeData,
resolver: yupResolver(yupValidationSchema),
resolver: yupResolver(validationSchema),
});

const [showAdvancedOptions, setShowAdvancedOptions] = React.useState(false);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { isValidHostname, validateRawPort } from 'src/utils';
import * as Yup from 'yup';

const settingsValidationSchema = Yup.object().shape({
host: Yup.string()
.required('A host is required')
.test('no-whitespace', 'Host cannot contain whitespace', (value) => !/\s/.test(value || ''))
.test('valid-host', 'A valid host is required', (value) => (value ? isValidHostname(value) : false)),

custom_http_port: Yup.number()
.nullable()
.test('valid-http', 'A valid http port is required', (value) => {
if (value === null) {
return true;
}
return value ? validateRawPort(value) : false;
}),
});

export { settingsValidationSchema };
26 changes: 26 additions & 0 deletions nym-wallet/src/context/bonding.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
migrateLegacyMixnode as migrateLegacyMixnodeReq,
migrateLegacyGateway as migrateLegacyGatewayReq,
bondNymNode,
updateNymNodeConfig as updateNymNodeConfigReq,
} from '../requests';

export type TBondedNode = TBondedMixnode | TBondedGateway | TBondedNymNode;
Expand All @@ -34,6 +35,10 @@ export type TBondingContext = {
unbond: (fee?: FeeDetails) => Promise<TransactionExecuteResult | undefined>;
bond: (args: TBondNymNodeArgs) => Promise<TransactionExecuteResult | undefined>;
updateBondAmount: (data: TUpdateBondArgs) => Promise<TransactionExecuteResult | undefined>;
updateNymNodeConfig: (data: {
host: string;
custom_http_port: number | null;
}) => Promise<TransactionExecuteResult | undefined>;
redeemRewards: (fee?: FeeDetails) => Promise<TransactionExecuteResult | undefined>;
generateNymNodeMsgPayload: (data: TNymNodeSignatureArgs) => Promise<string | undefined>;
migrateVestedMixnode: () => Promise<TransactionExecuteResult | undefined>;
Expand All @@ -52,6 +57,9 @@ export const BondingContext = createContext<TBondingContext>({
updateBondAmount: async () => {
throw new Error('Not implemented');
},
updateNymNodeConfig: async () => {
throw new Error('Not implemented');
},
redeemRewards: async () => {
throw new Error('Not implemented');
},
Expand Down Expand Up @@ -140,6 +148,23 @@ export const BondingContextProvider: FCWithChildren = ({ children }): JSX.Elemen
return tx;
};

const updateNymNodeConfig = async (data: { host: string; custom_http_port: number | null }) => {
let tx;
setIsLoading(true);
try {
tx = await updateNymNodeConfigReq(data);
if (clientDetails?.client_address) {
await getNodeDetails(clientDetails?.client_address);
}
} catch (e) {
Console.warn(e);
setError(`an error occurred: ${e}`);
} finally {
setIsLoading(false);
}
return tx;
};

const redeemRewards = async (fee?: FeeDetails) => {
let tx;
setIsLoading(true);
Expand Down Expand Up @@ -225,6 +250,7 @@ export const BondingContextProvider: FCWithChildren = ({ children }): JSX.Elemen
refresh,
redeemRewards,
updateBondAmount,
updateNymNodeConfig,
generateNymNodeMsgPayload,
migrateVestedMixnode,
migrateLegacyNode,
Expand Down
9 changes: 9 additions & 0 deletions nym-wallet/src/context/mocks/bonding.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,14 @@ export const MockBondingContextProvider = ({
return TxResultMock;
};

const updateNymNodeConfig = async (): Promise<TransactionExecuteResult> => {
setIsLoading(true);
await mockSleep(SLEEP_MS);
triggerStateUpdate();
setIsLoading(false);
return TxResultMock;
};

const redeemRewards = async (): Promise<TransactionExecuteResult | undefined> => {
setIsLoading(true);
await mockSleep(SLEEP_MS);
Expand Down Expand Up @@ -212,6 +220,7 @@ export const MockBondingContextProvider = ({
isVestingAccount: false,
migrateVestedMixnode: async () => undefined,
migrateLegacyNode: async () => undefined,
updateNymNodeConfig,
}),
[isLoading, error, bondedMixnode, bondedGateway, trigger, fee],
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,21 @@ import { useForm } from 'react-hook-form';
import { yupResolver } from '@hookform/resolvers/yup';
import { Box, Button, Divider, Grid, Stack, TextField, Typography } from '@mui/material';
import { useTheme } from '@mui/material/styles';
import { updateNymNodeConfig } from 'src/requests';
import { SimpleModal } from 'src/components/Modals/SimpleModal';
import { bondedInfoParametersValidationSchema } from 'src/components/Bonding/forms/legacyForms/mixnodeValidationSchema';
import { Console } from 'src/utils/console';
import { Alert } from 'src/components/Alert';
import { ConfirmTx } from 'src/components/ConfirmTX';
import { useGetFee } from 'src/hooks/useGetFee';
import { LoadingModal } from 'src/components/Modals/LoadingModal';
import { BalanceWarning } from 'src/components/FeeWarning';
import { AppContext } from 'src/context';
import { AppContext, useBondingContext } from 'src/context';
import { TBondedNymNode } from 'src/requests/nymNodeDetails';
import { settingsValidationSchema } from 'src/components/Bonding/forms/nym-node/settingsValidationSchema';

export const GeneralNymNodeSettings = ({ bondedNode }: { bondedNode: TBondedNymNode }) => {
const [openConfirmationModal, setOpenConfirmationModal] = useState<boolean>(false);
const { fee, resetFeeState } = useGetFee();
const { userBalance } = useContext(AppContext);
const { updateNymNodeConfig } = useBondingContext();

const theme = useTheme();

Expand All @@ -27,28 +26,26 @@ export const GeneralNymNodeSettings = ({ bondedNode }: { bondedNode: TBondedNymN
handleSubmit,
formState: { errors, isSubmitting, isDirty, isValid },
} = useForm({
resolver: yupResolver(bondedInfoParametersValidationSchema),
resolver: yupResolver(settingsValidationSchema),
mode: 'onChange',
defaultValues: {
host: bondedNode.host,
customHttpPort: bondedNode.customHttpPort,
custom_http_port: bondedNode.customHttpPort,
},
});

const onSubmit = async (data: { host?: string; customHttpPort?: number | null }) => {
const onSubmit = async ({ host, custom_http_port }: { host: string; custom_http_port: number | null }) => {
resetFeeState();
const { host, customHttpPort } = data;
if (host && customHttpPort) {

try {
const NymNodeConfigParams = {
host,
custom_http_port: customHttpPort,
custom_http_port,
};
try {
await updateNymNodeConfig(NymNodeConfigParams);
setOpenConfirmationModal(true);
} catch (error) {
Console.error(error);
}
await updateNymNodeConfig(NymNodeConfigParams);
setOpenConfirmationModal(true);
} catch (error) {
Console.error(error);
}
};

Expand All @@ -59,7 +56,7 @@ export const GeneralNymNodeSettings = ({ bondedNode }: { bondedNode: TBondedNymN
open
header="Update node settings"
fee={fee}
onConfirm={handleSubmit((d) => onSubmit(d))}
onConfirm={handleSubmit(onSubmit)}
onPrev={resetFeeState}
onClose={resetFeeState}
>
Expand All @@ -70,7 +67,6 @@ export const GeneralNymNodeSettings = ({ bondedNode }: { bondedNode: TBondedNymN
)}
</ConfirmTx>
)}
{isSubmitting && <LoadingModal />}
<Alert
title={
<Stack>
Expand All @@ -93,12 +89,12 @@ export const GeneralNymNodeSettings = ({ bondedNode }: { bondedNode: TBondedNymN
<Grid spacing={3} item container alignItems="center" xs={12} md={6}>
<Grid item width={1}>
<TextField
{...register('customHttpPort')}
name="customHttpPort"
{...register('custom_http_port')}
name="custom_http_port"
label="Custom HTTP port"
fullWidth
error={!!errors.customHttpPort}
helperText={errors.customHttpPort?.message}
error={!!errors.custom_http_port}
helperText={errors.custom_http_port?.message}
InputLabelProps={{ shrink: true }}
/>
</Grid>
Expand Down Expand Up @@ -134,7 +130,7 @@ export const GeneralNymNodeSettings = ({ bondedNode }: { bondedNode: TBondedNymN
size="large"
variant="contained"
disabled={isSubmitting || !isDirty || !isValid}
onClick={handleSubmit(() => undefined)}
onClick={handleSubmit(onSubmit)}
sx={{ m: 3, mr: 0 }}
fullWidth
>
Expand All @@ -152,7 +148,7 @@ export const GeneralNymNodeSettings = ({ bondedNode }: { bondedNode: TBondedNymN
hideCloseIcon
displayInfoIcon
onOk={async () => {
await setOpenConfirmationModal(false);
setOpenConfirmationModal(false);
}}
buttonFullWidth
sx={{
Expand Down
2 changes: 1 addition & 1 deletion nym-wallet/src/types/global.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ export type TNodeDescription = {

export type TNodeConfigUpdateArgs = {
host: string;
custom_http_port: number;
custom_http_port: number | null;
};

export type TDelegateArgs = {
Expand Down
Loading