diff --git a/nym-wallet/src/components/Balance/VestingTimeline.tsx b/nym-wallet/src/components/Balance/VestingTimeline.tsx
index 52e137f4c8..cfb489056d 100644
--- a/nym-wallet/src/components/Balance/VestingTimeline.tsx
+++ b/nym-wallet/src/components/Balance/VestingTimeline.tsx
@@ -26,7 +26,7 @@ export const VestingTimeline: FCWithChildren<{ percentageComplete: number }> = (
const nextPeriod =
typeof currentVestingPeriod === 'object' && !!vestingAccountInfo?.periods
- ? Number(vestingAccountInfo?.periods[currentVestingPeriod.in + 1]?.start_time)
+ ? Number(vestingAccountInfo?.periods[currentVestingPeriod.In + 1]?.start_time)
: undefined;
return (
diff --git a/nym-wallet/src/components/Balance/cards/VestingSchedule.tsx b/nym-wallet/src/components/Balance/cards/VestingSchedule.tsx
index e713565680..b26b999970 100644
--- a/nym-wallet/src/components/Balance/cards/VestingSchedule.tsx
+++ b/nym-wallet/src/components/Balance/cards/VestingSchedule.tsx
@@ -23,7 +23,7 @@ const columnsHeaders: Array<{ title: string; align: TableCellProps['align'] }> =
const vestingPeriod = (current?: Period, original?: number) => {
if (current === 'After') return 'Complete';
- if (typeof current === 'object' && typeof original === 'number') return `${current.in + 1}/${original}`;
+ if (typeof current === 'object' && typeof original === 'number') return `${current.In + 1}/${original}`;
return 'N/A';
};
diff --git a/nym-wallet/src/components/Bonding/Bond.tsx b/nym-wallet/src/components/Bonding/Bond.tsx
index d240b31035..79a19c3396 100644
--- a/nym-wallet/src/components/Bonding/Bond.tsx
+++ b/nym-wallet/src/components/Bonding/Bond.tsx
@@ -20,7 +20,7 @@ export const Bond = ({
}}
>
- Bond a mix node or a gateway. Learn how to set up and run a node{' '}
+ Bond a nym node. Learn how to set up and run a Nym node{' '}
here
diff --git a/nym-wallet/src/components/Bonding/BondUpdateCard.tsx b/nym-wallet/src/components/Bonding/BondUpdateCard.tsx
new file mode 100644
index 0000000000..9cd24d0af8
--- /dev/null
+++ b/nym-wallet/src/components/Bonding/BondUpdateCard.tsx
@@ -0,0 +1,44 @@
+import React from 'react';
+import { Box, Button, Stack, Tooltip, Typography } from '@mui/material';
+import { NymCard } from 'src/components';
+
+export const BondUpdateCard = ({ setSuccesfullUpdate }: { setSuccesfullUpdate: (staus: boolean) => void }) => (
+
+
+ Upgrade your node!
+
+ }
+ subheader={
+
+
+ It seems like your node is running outdated binaries.
+
+ Update to the latest stable Nym node binary now*
+ The update takes less than a minute!
+
+ *Without updating, legacy node settings can be changed in the Nym CLI.
+
+
+ }
+ Action={
+
+
+
+
+
+
+
+ }
+ />
+
+);
diff --git a/nym-wallet/src/components/Bonding/BondedGateway.tsx b/nym-wallet/src/components/Bonding/BondedGateway.tsx
index 2c1c5f6127..ab8ee84209 100644
--- a/nym-wallet/src/components/Bonding/BondedGateway.tsx
+++ b/nym-wallet/src/components/Bonding/BondedGateway.tsx
@@ -1,11 +1,13 @@
import React from 'react';
-import { Box, Button, Stack, Typography } from '@mui/material';
+import { Box, Button, Stack, Tooltip, Typography } from '@mui/material';
import { Link } from '@nymproject/react/link/Link';
-import { TBondedGateway, urls } from 'src/context';
+import { urls } from 'src/context';
import { NymCard } from 'src/components';
import { Network } from 'src/types';
import { IdentityKey } from 'src/components/IdentityKey';
import { useNavigate } from 'react-router-dom';
+import { UpgradeRounded } from '@mui/icons-material';
+import { TBondedGateway } from 'src/requests/gatewayDetails';
import { Node as NodeIcon } from '../../svg-icons/node';
import { Cell, Header, NodeTable } from './NodeTable';
import { BondedGatewayActions, TBondedGatwayActions } from './BondedGatewayAction';
@@ -39,10 +41,12 @@ const headers: Header[] = [
export const BondedGateway = ({
gateway,
network,
+ onShowMigrateToNymNodeModal,
onActionSelect,
}: {
gateway: TBondedGateway;
network?: Network;
+ onShowMigrateToNymNodeModal: () => void;
onActionSelect: (action: TBondedGatwayActions) => void;
}) => {
const { name, bond, ip, identityKey, routingScore } = gateway;
@@ -91,16 +95,29 @@ export const BondedGateway = ({
}
Action={
-
+
+
+
+
+
+
-
+
}
>
diff --git a/nym-wallet/src/components/Bonding/BondedMixnode.tsx b/nym-wallet/src/components/Bonding/BondedMixnode.tsx
index e569cd7aec..5d0fc68e64 100644
--- a/nym-wallet/src/components/Bonding/BondedMixnode.tsx
+++ b/nym-wallet/src/components/Bonding/BondedMixnode.tsx
@@ -2,12 +2,14 @@ import React, { useEffect, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { Box, Button, Chip, Stack, Tooltip, Typography } from '@mui/material';
import { Link } from '@nymproject/react/link/Link';
-import { isMixnode, Network } from 'src/types';
-import { TBondedMixnode, urls } from 'src/context';
+import { Network } from 'src/types';
+import { urls } from 'src/context';
import { NymCard } from 'src/components';
import { IdentityKey } from 'src/components/IdentityKey';
import { NodeStatus } from 'src/components/NodeStatus';
import { getIntervalAsDate } from 'src/utils';
+import { UpgradeRounded } from '@mui/icons-material';
+import { TBondedMixnode } from 'src/requests/mixnodeDetails';
import { Node as NodeIcon } from '../../svg-icons/node';
import { Cell, Header, NodeTable } from './NodeTable';
import { BondedMixnodeActions, TBondedMixnodeActions } from './BondedMixnodeActions';
@@ -60,10 +62,12 @@ const headers: Header[] = [
export const BondedMixnode = ({
mixnode,
network,
+ onShowMigrateToNymNodeModal,
onActionSelect,
}: {
mixnode: TBondedMixnode;
network?: Network;
+ onShowMigrateToNymNodeModal: () => void;
onActionSelect: (action: TBondedMixnodeActions) => void;
}) => {
const [nextEpoch, setNextEpoch] = useState();
@@ -81,6 +85,7 @@ export const BondedMixnode = ({
status,
identityKey,
host,
+ isUnbonding,
} = mixnode;
const getNextInterval = async () => {
@@ -165,9 +170,13 @@ export const BondedMixnode = ({
}
Action={
- {isMixnode(mixnode) && (
+
- )}
+ }
+ variant="contained"
+ disableElevation
+ onClick={onShowMigrateToNymNodeModal}
+ disabled={isUnbonding}
+ >
+ Migrate to Nym Node
+
+
+
{nextEpoch instanceof Error ? null : (
Next epoch starts at {nextEpoch}
diff --git a/nym-wallet/src/components/Bonding/BondedNymNode.tsx b/nym-wallet/src/components/Bonding/BondedNymNode.tsx
new file mode 100644
index 0000000000..6186891e7f
--- /dev/null
+++ b/nym-wallet/src/components/Bonding/BondedNymNode.tsx
@@ -0,0 +1,206 @@
+import React, { useEffect, useState } from 'react';
+import { useNavigate } from 'react-router-dom';
+import { Box, Button, Chip, Stack, Tooltip, Typography } from '@mui/material';
+import { Link } from '@nymproject/react/link/Link';
+import { Network } from 'src/types';
+import { urls } from 'src/context';
+import { NymCard } from 'src/components';
+import { IdentityKey } from 'src/components/IdentityKey';
+import { getIntervalAsDate } from 'src/utils';
+import { TBondedNymNode } from 'src/requests/nymNodeDetails';
+import { Node as NodeIcon } from '../../svg-icons/node';
+import { Cell, Header, NodeTable } from './NodeTable';
+import { BondedNymNodeActions, TBondedNymNodeActions } from './BondedNymNodeActions';
+
+const textWhenNotName = 'This node has not yet set a name';
+
+const headers: Header[] = [
+ {
+ header: 'Stake',
+ id: 'stake',
+ sx: { pl: 0 },
+ },
+ {
+ header: 'Bond',
+ id: 'bond',
+ },
+ {
+ header: 'Stake saturation',
+ id: 'stake-saturation',
+ },
+ {
+ header: 'PM',
+ id: 'profit-margin',
+ tooltipText:
+ 'The percentage of the node rewards that you as the node operator will take before the rest of the reward is shared between you and the delegators.',
+ },
+ {
+ header: 'Operating cost',
+ id: 'operator-cost',
+ tooltipText:
+ 'Monthly operational costs of running your node. The cost also influences how the rewards are split between you and your delegators. ',
+ },
+ {
+ header: 'Operator rewards',
+ id: 'operator-rewards',
+ tooltipText:
+ 'This is your (operator) rewards including the PM and cost. Rewards are automatically compounded every epoch. You can redeem your rewards at any time.',
+ },
+ {
+ header: 'No. delegators',
+ id: 'delegators',
+ },
+ {
+ id: 'menu-button',
+ sx: { width: 34, maxWidth: 34 },
+ },
+];
+
+export const BondedNymNode = ({
+ nymnode,
+ network,
+ onActionSelect,
+}: {
+ nymnode: TBondedNymNode;
+ network?: Network;
+ onActionSelect: (action: TBondedNymNodeActions) => void;
+}) => {
+ const [nextEpoch, setNextEpoch] = useState();
+ const navigate = useNavigate();
+ const {
+ name,
+ nodeId,
+ stake,
+ bond,
+ stakeSaturation,
+ profitMargin,
+ operatorRewards,
+ operatorCost,
+ delegators,
+ identityKey,
+ host,
+ } = nymnode;
+
+ const getNextInterval = async () => {
+ try {
+ const { nextEpoch: newNextEpoch } = await getIntervalAsDate();
+ setNextEpoch(newNextEpoch);
+ } catch {
+ setNextEpoch(Error());
+ }
+ };
+ const cells: Cell[] = [
+ {
+ cell: `${stake.amount} ${stake.denom}`,
+ id: 'stake-cell',
+ },
+ {
+ cell: `${bond.amount} ${bond.denom}`,
+ id: 'bond-cell',
+ },
+ {
+ cell: `${stakeSaturation}%`,
+ id: 'stake-saturation-cell',
+ },
+ {
+ cell: `${profitMargin}%`,
+ id: 'pm-cell',
+ },
+ {
+ cell: operatorCost ? `${operatorCost.amount} ${operatorCost.denom}` : '-',
+ id: 'operator-cost-cell',
+ },
+ {
+ cell: operatorRewards ? `${operatorRewards.amount} ${operatorRewards.denom}` : '-',
+ id: 'operator-rewards-cell',
+ },
+ {
+ cell: delegators,
+ id: 'delegators-cell',
+ },
+ {
+ cell: nymnode.isUnbonding ? (
+
+ ) : (
+
+ ),
+ id: 'actions-cell',
+ align: 'right',
+ },
+ ];
+
+ useEffect(() => {
+ getNextInterval();
+ }, []);
+
+ return (
+
+
+
+
+ Nym node
+
+
+ {name?.includes(textWhenNotName) ? null : (
+
+ {name}
+
+ )}
+
+
+
+
+
+
+ }
+ Action={
+
+
+
+
+
+
+
+
+
+ {nextEpoch instanceof Error ? null : (
+
+ Next epoch starts at {nextEpoch}
+
+ )}
+
+ }
+ >
+
+ {network && (
+
+ Check more stats of your node on the{' '}
+
+ explorer
+
+
+ )}
+
+ {/* */}
+
+ );
+};
diff --git a/nym-wallet/src/components/Bonding/BondedNymNodeActions.tsx b/nym-wallet/src/components/Bonding/BondedNymNodeActions.tsx
new file mode 100644
index 0000000000..3125bbd2e1
--- /dev/null
+++ b/nym-wallet/src/components/Bonding/BondedNymNodeActions.tsx
@@ -0,0 +1,49 @@
+import React, { useState } from 'react';
+import { Typography } from '@mui/material';
+import { ActionsMenu, ActionsMenuItem } from 'src/components/ActionsMenu';
+import { Unbond as UnbondIcon, Bond as BondIcon } from '../../svg-icons';
+
+export type TBondedNymNodeActions = 'nodeSettings' | 'updateBond' | 'unbond' | 'redeem';
+
+export const BondedNymNodeActions = ({
+ onActionSelect,
+ disabledRedeemAndCompound,
+ disabledUpdateBond,
+}: {
+ onActionSelect: (action: TBondedNymNodeActions) => void;
+ disabledRedeemAndCompound: boolean;
+ disabledUpdateBond?: boolean;
+}) => {
+ const [isOpen, setIsOpen] = useState(false);
+
+ const handleOpen = () => setIsOpen(true);
+ const handleClose = () => setIsOpen(false);
+
+ const handleActionClick = (action: TBondedNymNodeActions) => {
+ onActionSelect(action);
+ handleClose();
+ };
+
+ return (
+
+ {!disabledUpdateBond && (
+ }
+ onClick={() => handleActionClick('updateBond')}
+ />
+ )}
+ R}
+ onClick={() => handleActionClick('redeem')}
+ disabled={disabledRedeemAndCompound}
+ />
+ }
+ onClick={() => handleActionClick('unbond')}
+ />
+
+ );
+};
diff --git a/nym-wallet/src/components/Bonding/NodeStats.tsx b/nym-wallet/src/components/Bonding/NodeStats.tsx
index eb22b50727..8c492968c7 100644
--- a/nym-wallet/src/components/Bonding/NodeStats.tsx
+++ b/nym-wallet/src/components/Bonding/NodeStats.tsx
@@ -1,9 +1,8 @@
import React from 'react';
-import { Stack, Typography, Box, useTheme, Grid, LinearProgress, LinearProgressProps, Button } from '@mui/material';
-import { useNavigate } from 'react-router-dom';
-import { TBondedMixnode } from 'src/context';
+import { Stack, Typography, Box, useTheme, Grid, LinearProgress, LinearProgressProps } from '@mui/material';
import { Cell, Pie, PieChart, Legend, ResponsiveContainer } from 'recharts';
import { SelectionChance } from '@nymproject/types';
+import { TBondedMixnode } from 'src/requests/mixnodeDetails';
import { NymCard } from '../NymCard';
import { InfoTooltip } from '../InfoToolTip';
@@ -50,10 +49,9 @@ const StatRow = ({
export const NodeStats = ({ mixnode }: { mixnode: TBondedMixnode }) => {
const { activeSetProbability, routingScore } = mixnode;
const theme = useTheme();
- const navigate = useNavigate();
// clamp routing score to [0-100]
- const score = Math.min(Math.max(routingScore, 0), 100);
+ const score = Math.min(Math.max(routingScore || 0, 0), 100);
const data = [
{ key: 'routingScore', value: score },
@@ -74,10 +72,6 @@ export const NodeStats = ({ mixnode }: { mixnode: TBondedMixnode }) => {
}
};
- const handleGoToTestNode = () => {
- navigate('/bonding/node-settings', { state: 'test-node' });
- };
-
const renderLegend = () => (
{
Node stats
}
- Action={
-
- }
>
diff --git a/nym-wallet/src/components/Bonding/forms/BondMixnodeForm.tsx b/nym-wallet/src/components/Bonding/forms/BondMixnodeForm.tsx
deleted file mode 100644
index 274878310f..0000000000
--- a/nym-wallet/src/components/Bonding/forms/BondMixnodeForm.tsx
+++ /dev/null
@@ -1,50 +0,0 @@
-import React from 'react';
-import { Box } from '@mui/material';
-import { CurrencyDenom, TNodeType } from '@nymproject/types';
-import { NodeTypeSelector } from 'src/components';
-import { MixnodeAmount, MixnodeData, Signature } from 'src/pages/bonding/types';
-import MixnodeInitForm from './MixnodeInitForm';
-import MixnodeAmountForm from './MixnodeAmountForm';
-import MixnodeSignatureForm from './MixnodeSignatureForm';
-
-export const BondMixnodeForm = ({
- step,
- denom,
- mixnodeData,
- amountData,
- hasVestingTokens,
- onSelectNodeType,
- onValidateMixnodeData,
- onValidateAmountData,
- onValidateSignature,
-}: {
- step: 1 | 2 | 3 | 4;
- mixnodeData: MixnodeData;
- amountData: MixnodeAmount;
- denom: CurrencyDenom;
- hasVestingTokens: boolean;
- onSelectNodeType: (nodeType: TNodeType) => void;
- onValidateMixnodeData: (data: MixnodeData) => void;
- onValidateAmountData: (data: MixnodeAmount) => Promise;
- onValidateSignature: (signature: Signature) => void;
-}) => (
- <>
- {step === 1 && (
- <>
-
-
-
-
- >
- )}
- {step === 2 && (
-
- )}
- {step === 3 && }
- >
-);
diff --git a/nym-wallet/src/components/Bonding/forms/GatewaySignatureForm.tsx b/nym-wallet/src/components/Bonding/forms/GatewaySignatureForm.tsx
deleted file mode 100644
index fd7c25fcea..0000000000
--- a/nym-wallet/src/components/Bonding/forms/GatewaySignatureForm.tsx
+++ /dev/null
@@ -1,94 +0,0 @@
-import React, { useEffect, useState } from 'react';
-import { Stack, TextField, Typography } from '@mui/material';
-import { useForm } from 'react-hook-form';
-import { gatewayToTauri } from '../utils';
-import { CopyToClipboard } from '../../CopyToClipboard';
-import { useBondingContext } from '../../../context';
-import { Console } from '../../../utils/console';
-import { ErrorModal } from '../../Modals/ErrorModal';
-import { GatewayData, GatewayAmount, Signature } from '../../../pages/bonding/types';
-
-const GatewaySignatureForm = ({
- gateway,
- amount,
- onNext,
-}: {
- gateway: GatewayData;
- amount: GatewayAmount;
- onNext: (data: Signature) => void;
-}) => {
- const [message, setMessage] = useState();
- const [error, setError] = useState();
- const { generateGatewayMsgPayload } = useBondingContext();
-
- const { register, handleSubmit } = useForm();
-
- const handleOnNext = (event: { detail: { step: number } }) => {
- if (event.detail.step === 3) {
- handleSubmit(onNext)();
- }
- };
-
- useEffect(() => {
- window.addEventListener('validate_bond_gateway_step' as any, handleOnNext);
- return () => window.removeEventListener('validate_bond_gateway_step' as any, handleOnNext);
- }, []);
-
- const generateMessage = async () => {
- try {
- setMessage(
- await generateGatewayMsgPayload({
- pledge: amount.amount,
- gateway: gatewayToTauri(gateway),
- tokenPool: amount.tokenPool as 'balance' | 'locked',
- }),
- );
- } catch (e) {
- Console.error(e);
- setError('Something went wrong while generating the payload signature');
- }
- };
-
- useEffect(() => {
- generateMessage();
- }, [gateway, amount]);
-
- if (error) {
- return {}} />;
- }
-
- return (
-
-
- Copy the message below and sign it:
-
- If you are using a nym-gateway:
-
- nym-gateway sign --id <your-node-id> --contract-msg <payload-generated-by-the-wallet>
-
- If you are using a nym-node:
-
- nym-node sign --id <your-node-id> --contract-msg <payload-generated-by-the-wallet>
-
- Then paste the signature in the next field.
-
-
-
- Copy Message
- {message && }
-
-
-
- );
-};
-
-export default GatewaySignatureForm;
diff --git a/nym-wallet/src/components/Bonding/forms/MixnodeSignatureForm.tsx b/nym-wallet/src/components/Bonding/forms/MixnodeSignatureForm.tsx
deleted file mode 100644
index 1cce8d2ccd..0000000000
--- a/nym-wallet/src/components/Bonding/forms/MixnodeSignatureForm.tsx
+++ /dev/null
@@ -1,95 +0,0 @@
-import React, { useEffect, useState } from 'react';
-import { Stack, TextField, Typography } from '@mui/material';
-import { useForm } from 'react-hook-form';
-import { costParamsToTauri, mixnodeToTauri } from '../utils';
-import { CopyToClipboard } from '../../CopyToClipboard';
-import { useBondingContext } from '../../../context';
-import { Console } from '../../../utils/console';
-import { ErrorModal } from '../../Modals/ErrorModal';
-import { MixnodeAmount, MixnodeData, Signature } from '../../../pages/bonding/types';
-
-const MixnodeSignatureForm = ({
- mixnode,
- amount,
- onNext,
-}: {
- mixnode: MixnodeData;
- amount: MixnodeAmount;
- onNext: (data: Signature) => void;
-}) => {
- const [message, setMessage] = useState('');
- const [error, setError] = useState();
- const { generateMixnodeMsgPayload } = useBondingContext();
-
- const { register, handleSubmit } = useForm();
-
- const handleOnNext = (event: { detail: { step: number } }) => {
- if (event.detail.step === 3) {
- handleSubmit(onNext)();
- }
- };
-
- useEffect(() => {
- window.addEventListener('validate_bond_mixnode_step' as any, handleOnNext);
- return () => window.removeEventListener('validate_bond_mixnode_step' as any, handleOnNext);
- }, []);
-
- const generateMessage = async () => {
- try {
- setMessage(
- (await generateMixnodeMsgPayload({
- pledge: amount.amount,
- mixnode: mixnodeToTauri(mixnode),
- costParams: costParamsToTauri(amount),
- tokenPool: amount.tokenPool as 'balance' | 'locked',
- })) as string,
- );
- } catch (e) {
- Console.error(e);
- setError('Something went wrong while generating the payload signature');
- }
- };
-
- useEffect(() => {
- generateMessage();
- }, [mixnode, amount]);
-
- if (error) {
- return {}} />;
- }
-
- return (
-
-
- Copy the message below and sign it:
-
- If you are using a nym-mixnode:
-
- nym-mixnode sign --id <your-node-id> --contract-msg <payload-generated-by-the-wallet>
-
- If you are using a nym-node:
-
- nym-node sign --id <your-node-id> --contract-msg <payload-generated-by-the-wallet>
-
- Then paste the signature in the next field.
-
-
-
- Copy Message
- {message && }
-
-
-
- );
-};
-
-export default MixnodeSignatureForm;
diff --git a/nym-wallet/src/components/Bonding/forms/BondGatewayForm.tsx b/nym-wallet/src/components/Bonding/forms/legacyForms/BondGatewayForm.tsx
similarity index 78%
rename from nym-wallet/src/components/Bonding/forms/BondGatewayForm.tsx
rename to nym-wallet/src/components/Bonding/forms/legacyForms/BondGatewayForm.tsx
index efb812d969..843d604053 100644
--- a/nym-wallet/src/components/Bonding/forms/BondGatewayForm.tsx
+++ b/nym-wallet/src/components/Bonding/forms/legacyForms/BondGatewayForm.tsx
@@ -2,10 +2,9 @@ import React from 'react';
import { Box } from '@mui/material';
import { NodeTypeSelector } from 'src/components';
import { CurrencyDenom, TNodeType } from '@nymproject/types';
-import { GatewayAmount, GatewayData, Signature } from 'src/pages/bonding/types';
+import { GatewayAmount, GatewayData } from 'src/pages/bonding/types';
import GatewayInitForm from './GatewayInitForm';
import GatewayAmountForm from './GatewayAmountForm';
-import GatewaySignatureForm from './GatewaySignatureForm';
export const BondGatewayForm = ({
step,
@@ -16,7 +15,6 @@ export const BondGatewayForm = ({
onSelectNodeType,
onValidateGatewayData,
onValidateAmountData,
- onValidateSignature,
}: {
step: 1 | 2 | 3 | 4;
gatewayData: GatewayData;
@@ -26,7 +24,6 @@ export const BondGatewayForm = ({
onSelectNodeType: (nodeType: TNodeType) => void;
onValidateGatewayData: (data: GatewayData) => void;
onValidateAmountData: (data: GatewayAmount) => Promise;
- onValidateSignature: (signature: Signature) => void;
}) => (
<>
{step === 1 && (
@@ -45,6 +42,5 @@ export const BondGatewayForm = ({
onNext={onValidateAmountData}
/>
)}
- {step === 3 && }
>
);
diff --git a/nym-wallet/src/components/Bonding/forms/GatewayAmountForm.tsx b/nym-wallet/src/components/Bonding/forms/legacyForms/GatewayAmountForm.tsx
similarity index 94%
rename from nym-wallet/src/components/Bonding/forms/GatewayAmountForm.tsx
rename to nym-wallet/src/components/Bonding/forms/legacyForms/GatewayAmountForm.tsx
index 2cef9a59da..7135d2b154 100644
--- a/nym-wallet/src/components/Bonding/forms/GatewayAmountForm.tsx
+++ b/nym-wallet/src/components/Bonding/forms/legacyForms/GatewayAmountForm.tsx
@@ -5,9 +5,9 @@ import { yupResolver } from '@hookform/resolvers/yup/dist/yup';
import { CurrencyFormField } from '@nymproject/react/currency/CurrencyFormField';
import { Box, Stack } from '@mui/material';
import { amountSchema } from './gatewayValidationSchema';
-import { checkHasEnoughFunds, checkHasEnoughLockedTokens } from '../../../utils';
-import { GatewayAmount } from '../../../pages/bonding/types';
-import { TokenPoolSelector } from '../../TokenPoolSelector';
+import { checkHasEnoughFunds, checkHasEnoughLockedTokens } from '../../../../utils';
+import { GatewayAmount } from '../../../../pages/bonding/types';
+import { TokenPoolSelector } from '../../../TokenPoolSelector';
const GatewayAmountForm = ({
denom,
diff --git a/nym-wallet/src/components/Bonding/forms/GatewayInitForm.tsx b/nym-wallet/src/components/Bonding/forms/legacyForms/GatewayInitForm.tsx
similarity index 98%
rename from nym-wallet/src/components/Bonding/forms/GatewayInitForm.tsx
rename to nym-wallet/src/components/Bonding/forms/legacyForms/GatewayInitForm.tsx
index 670c5a9e0a..5a891700c9 100644
--- a/nym-wallet/src/components/Bonding/forms/GatewayInitForm.tsx
+++ b/nym-wallet/src/components/Bonding/forms/legacyForms/GatewayInitForm.tsx
@@ -4,7 +4,7 @@ import { clean } from 'semver';
import { Checkbox, FormControlLabel, Stack, TextField } from '@mui/material';
import { IdentityKeyFormField } from '@nymproject/react/mixnodes/IdentityKeyFormField';
import { yupResolver } from '@hookform/resolvers/yup/dist/yup';
-import { GatewayData } from '../../../pages/bonding/types';
+import { GatewayData } from '../../../../pages/bonding/types';
import { gatewayValidationSchema } from './gatewayValidationSchema';
const GatewayInitForm = ({
diff --git a/nym-wallet/src/components/Bonding/forms/MixnodeAmountForm.tsx b/nym-wallet/src/components/Bonding/forms/legacyForms/MixnodeAmountForm.tsx
similarity index 93%
rename from nym-wallet/src/components/Bonding/forms/MixnodeAmountForm.tsx
rename to nym-wallet/src/components/Bonding/forms/legacyForms/MixnodeAmountForm.tsx
index f24f9138b7..13176dadf6 100644
--- a/nym-wallet/src/components/Bonding/forms/MixnodeAmountForm.tsx
+++ b/nym-wallet/src/components/Bonding/forms/legacyForms/MixnodeAmountForm.tsx
@@ -5,11 +5,11 @@ import { yupResolver } from '@hookform/resolvers/yup/dist/yup';
import { CurrencyFormField } from '@nymproject/react/currency/CurrencyFormField';
import { CurrencyDenom } from '@nymproject/types';
import { amountSchema } from './mixnodeValidationSchema';
-import { MixnodeAmount } from '../../../pages/bonding/types';
-import { AppContext } from '../../../context';
-import { checkHasEnoughFunds, checkHasEnoughLockedTokens } from '../../../utils';
-import { TokenPoolSelector } from '../../TokenPoolSelector';
-import { ModalListItem } from '../../Modals/ModalListItem';
+import { MixnodeAmount } from '../../../../pages/bonding/types';
+import { AppContext } from '../../../../context';
+import { checkHasEnoughFunds, checkHasEnoughLockedTokens } from '../../../../utils';
+import { TokenPoolSelector } from '../../../TokenPoolSelector';
+import { ModalListItem } from '../../../Modals/ModalListItem';
const MixnodeAmountForm = ({
amountData,
diff --git a/nym-wallet/src/components/Bonding/forms/MixnodeInitForm.tsx b/nym-wallet/src/components/Bonding/forms/legacyForms/MixnodeInitForm.tsx
similarity index 98%
rename from nym-wallet/src/components/Bonding/forms/MixnodeInitForm.tsx
rename to nym-wallet/src/components/Bonding/forms/legacyForms/MixnodeInitForm.tsx
index 3c97bb22ce..0032bb3364 100644
--- a/nym-wallet/src/components/Bonding/forms/MixnodeInitForm.tsx
+++ b/nym-wallet/src/components/Bonding/forms/legacyForms/MixnodeInitForm.tsx
@@ -5,7 +5,7 @@ import { Checkbox, FormControlLabel, Stack, TextField } from '@mui/material';
import { IdentityKeyFormField } from '@nymproject/react/mixnodes/IdentityKeyFormField';
import { yupResolver } from '@hookform/resolvers/yup/dist/yup';
import { mixnodeValidationSchema } from './mixnodeValidationSchema';
-import { MixnodeData } from '../../../pages/bonding/types';
+import { MixnodeData } from '../../../../pages/bonding/types';
const MixnodeInitForm = ({ mixnodeData, onNext }: { mixnodeData: MixnodeData; onNext: (data: any) => void }) => {
const [showAdvancedOptions, setShowAdvancedOptions] = useState(false);
diff --git a/nym-wallet/src/components/Bonding/forms/gatewayValidationSchema.ts b/nym-wallet/src/components/Bonding/forms/legacyForms/gatewayValidationSchema.ts
similarity index 100%
rename from nym-wallet/src/components/Bonding/forms/gatewayValidationSchema.ts
rename to nym-wallet/src/components/Bonding/forms/legacyForms/gatewayValidationSchema.ts
diff --git a/nym-wallet/src/components/Bonding/forms/mixnodeValidationSchema.ts b/nym-wallet/src/components/Bonding/forms/legacyForms/mixnodeValidationSchema.ts
similarity index 98%
rename from nym-wallet/src/components/Bonding/forms/mixnodeValidationSchema.ts
rename to nym-wallet/src/components/Bonding/forms/legacyForms/mixnodeValidationSchema.ts
index a72364377c..c11324457c 100644
--- a/nym-wallet/src/components/Bonding/forms/mixnodeValidationSchema.ts
+++ b/nym-wallet/src/components/Bonding/forms/legacyForms/mixnodeValidationSchema.ts
@@ -8,7 +8,7 @@ import {
validateRawPort,
validateVersion,
} from 'src/utils';
-import { TauriContractStateParams } from '../../../types';
+import { TauriContractStateParams } from '../../../../types';
export const mixnodeValidationSchema = Yup.object().shape({
identityKey: Yup.string()
diff --git a/nym-wallet/src/components/Bonding/forms/nym-node/FormContext.tsx b/nym-wallet/src/components/Bonding/forms/nym-node/FormContext.tsx
new file mode 100644
index 0000000000..6ad0bcadbc
--- /dev/null
+++ b/nym-wallet/src/components/Bonding/forms/nym-node/FormContext.tsx
@@ -0,0 +1,98 @@
+import React, { createContext, useContext, useMemo, useState } from 'react';
+import { CurrencyDenom } from '@nymproject/types';
+import { TBondNymNodeArgs, TBondMixNodeArgs } from 'src/types';
+
+const defaultNymNodeValues: TBondNymNodeArgs['nymNode'] = {
+ identity_key: 'H6rXWgsW89QsVyaNSS3qBe9zZFLhBS6Gn3YRkGFSoFW9',
+ custom_http_port: 1,
+ host: '1.1.1.1',
+};
+
+const defaultCostParams = (denom: CurrencyDenom): TBondNymNodeArgs['costParams'] => ({
+ interval_operating_cost: { amount: '40', denom },
+ profit_margin_percent: '10',
+});
+
+const defaultAmount = (denom: CurrencyDenom): TBondMixNodeArgs['pledge'] => ({
+ amount: '100',
+ denom,
+});
+
+interface FormContextType {
+ step: 1 | 2 | 3 | 4;
+ setStep: React.Dispatch>;
+ nymNodeData: TBondNymNodeArgs['nymNode'];
+ setNymNodeData: React.Dispatch>;
+ costParams: TBondNymNodeArgs['costParams'];
+ setCostParams: React.Dispatch>;
+ amountData: TBondMixNodeArgs['pledge'];
+ setAmountData: React.Dispatch>;
+ signature?: string;
+ setSignature: React.Dispatch>;
+ onError: (e: string) => void;
+}
+
+const FormContext = createContext({
+ step: 1,
+ setStep: () => {},
+ nymNodeData: defaultNymNodeValues,
+ setNymNodeData: () => {},
+ costParams: defaultCostParams('nym'),
+ setCostParams: () => {},
+ amountData: defaultAmount('nym'),
+ setAmountData: () => {},
+ signature: undefined,
+ setSignature: () => {},
+
+ onError: () => {},
+});
+
+const FormContextProvider = ({ children }: { children: React.ReactNode }) => {
+ // TODO - Make denom dynamic
+ const denom = 'nym';
+
+ const [step, setStep] = useState<1 | 2 | 3 | 4>(1);
+ const [nymNodeData, setNymNodeData] = useState(defaultNymNodeValues);
+ const [costParams, setCostParams] = useState(defaultCostParams(denom));
+ const [amountData, setAmountData] = useState(defaultAmount(denom));
+ const [signature, setSignature] = useState();
+
+ const onError = (e: string) => {
+ console.error(e);
+ };
+
+ const value = useMemo(
+ () => ({
+ step,
+ setStep,
+ nymNodeData,
+ setNymNodeData,
+ costParams,
+ setCostParams,
+ amountData,
+ setAmountData,
+ signature,
+ setSignature,
+ onError,
+ }),
+ [
+ step,
+ setStep,
+ nymNodeData,
+ setNymNodeData,
+ costParams,
+ setCostParams,
+ amountData,
+ setAmountData,
+ signature,
+ setSignature,
+ onError,
+ ],
+ );
+
+ return {children};
+};
+
+export const useFormContext = () => useContext(FormContext);
+
+export default FormContextProvider;
diff --git a/nym-wallet/src/components/Bonding/forms/nym-node/NymNodeAmount.tsx b/nym-wallet/src/components/Bonding/forms/nym-node/NymNodeAmount.tsx
new file mode 100644
index 0000000000..550dd639ad
--- /dev/null
+++ b/nym-wallet/src/components/Bonding/forms/nym-node/NymNodeAmount.tsx
@@ -0,0 +1,120 @@
+import React from 'react';
+import { Stack, TextField, Box, FormHelperText } from '@mui/material';
+import { useForm } from 'react-hook-form';
+import { TBondNymNodeArgs } from 'src/types';
+import { yupResolver } from '@hookform/resolvers/yup';
+import { SimpleModal } from 'src/components/Modals/SimpleModal';
+import { CurrencyFormField } from '@nymproject/react/currency/CurrencyFormField';
+import { checkHasEnoughFunds } from 'src/utils';
+import { nymNodeAmountSchema } from './amountValidationSchema';
+
+const defaultNymNodeCostParamValues: TBondNymNodeArgs['costParams'] = {
+ profit_margin_percent: '10',
+ interval_operating_cost: { amount: '40', denom: 'nym' },
+};
+
+const defaultNymNodePledgeValue: TBondNymNodeArgs['pledge'] = {
+ amount: '100',
+ denom: 'nym',
+};
+
+type NymNodeDataProps = {
+ onClose: () => void;
+ onBack: () => void;
+ onNext: () => Promise;
+ step: number;
+};
+
+const NymNodeAmount = ({ onClose, onBack, onNext, step }: NymNodeDataProps) => {
+ const {
+ formState: { errors },
+ register,
+ getValues,
+ setValue,
+ setError,
+ handleSubmit,
+ } = useForm({
+ mode: 'all',
+ defaultValues: {
+ pledge: defaultNymNodePledgeValue,
+ ...defaultNymNodeCostParamValues,
+ },
+ resolver: yupResolver(nymNodeAmountSchema()),
+ });
+
+ console.log(errors, 'errors');
+
+ const handleRequestValidation = async () => {
+ const values = getValues();
+
+ const hasSufficientTokens = await checkHasEnoughFunds(values.pledge.amount);
+
+ if (hasSufficientTokens) {
+ handleSubmit(onNext)();
+ } else {
+ setError('pledge.amount', { message: 'Not enough tokens' });
+ }
+ };
+
+ return (
+ 0}
+ >
+
+ {
+ setValue('pledge.amount', newValue.amount, { shouldValidate: true });
+ }}
+ validationError={errors.pledge?.amount?.message}
+ denom={defaultNymNodePledgeValue.denom}
+ initialValue={defaultNymNodePledgeValue.amount}
+ />
+
+
+ {
+ setValue('interval_operating_cost', newValue, { shouldValidate: true });
+ }}
+ validationError={errors.interval_operating_cost?.amount?.message}
+ denom={defaultNymNodeCostParamValues.interval_operating_cost.denom}
+ initialValue={defaultNymNodeCostParamValues.interval_operating_cost.amount}
+ />
+
+ Monthly operational costs of running your node. If your node is in the active set the amount will be paid
+ back to you from the rewards.
+
+
+
+
+
+ The percentage of node rewards that you as the node operator take before rewards are distributed to operator
+ and delegators.
+
+
+
+
+ );
+};
+
+export default NymNodeAmount;
diff --git a/nym-wallet/src/components/Bonding/forms/nym-node/NymNodeData.tsx b/nym-wallet/src/components/Bonding/forms/nym-node/NymNodeData.tsx
new file mode 100644
index 0000000000..e32068a9c6
--- /dev/null
+++ b/nym-wallet/src/components/Bonding/forms/nym-node/NymNodeData.tsx
@@ -0,0 +1,110 @@
+import React from 'react';
+import { Stack, TextField, FormControlLabel, Checkbox } from '@mui/material';
+import { useForm } from 'react-hook-form';
+import { IdentityKeyFormField } from '@nymproject/react/mixnodes/IdentityKeyFormField';
+import { TBondNymNodeArgs } from 'src/types';
+import { yupResolver } from '@hookform/resolvers/yup';
+import * as yup from 'yup';
+import { isValidHostname, validateRawPort } from 'src/utils';
+import { SimpleModal } from 'src/components/Modals/SimpleModal';
+
+const defaultNymNodeValues: TBondNymNodeArgs['nymNode'] = {
+ identity_key: 'H6rXWgsW89QsVyaNSS3qBe9zZFLhBS6Gn3YRkGFSoFW9',
+ custom_http_port: 1,
+ host: '1.1.1.1',
+};
+
+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()
+ .required('A custom http port is required')
+ .test('valid-http', 'A valid http port is required', (value) => (value ? validateRawPort(value) : false)),
+});
+
+type NymNodeDataProps = {
+ onClose: () => void;
+ onBack: () => void;
+ onNext: () => Promise;
+ step: number;
+};
+
+const NymNodeData = ({ onClose, onNext, step }: NymNodeDataProps) => {
+ const {
+ formState: { errors },
+ register,
+ setValue,
+ handleSubmit,
+ } = useForm({
+ mode: 'all',
+ defaultValues: defaultNymNodeValues,
+ resolver: yupResolver(yupValidationSchema),
+ });
+
+ const [showAdvancedOptions, setShowAdvancedOptions] = React.useState(false);
+
+ const handleNext = async () => {
+ handleSubmit(onNext)();
+ };
+
+ return (
+ 0}
+ >
+
+ setValue('identity_key', value, { shouldValidate: true })}
+ showTickOnValid={false}
+ />
+
+
+
+ setShowAdvancedOptions((show) => !show)} checked={showAdvancedOptions} />}
+ label="Show advanced options"
+ />
+ {showAdvancedOptions && (
+
+
+
+ )}
+
+
+ );
+};
+
+export default NymNodeData;
diff --git a/nym-wallet/src/components/Bonding/forms/nym-node/NymNodeSignature.tsx b/nym-wallet/src/components/Bonding/forms/nym-node/NymNodeSignature.tsx
new file mode 100644
index 0000000000..e1e5814d55
--- /dev/null
+++ b/nym-wallet/src/components/Bonding/forms/nym-node/NymNodeSignature.tsx
@@ -0,0 +1,111 @@
+import React, { useEffect, useState } from 'react';
+import { Stack, TextField, Typography } from '@mui/material';
+import { useForm } from 'react-hook-form';
+import { CopyToClipboard } from 'src/components/CopyToClipboard';
+import { ErrorModal } from 'src/components/Modals/ErrorModal';
+import { SimpleModal } from 'src/components/Modals/SimpleModal';
+import { useBondingContext } from 'src/context';
+import { TBondNymNodeArgs } from 'src/types';
+import { Signature } from 'src/pages/bonding/types';
+
+const NymNodeSignature = ({
+ nymNode,
+ pledge,
+ costParams,
+ step,
+ onNext,
+ onClose,
+ onBack,
+}: {
+ nymNode: TBondNymNodeArgs['nymNode'];
+ pledge: TBondNymNodeArgs['pledge'];
+ costParams: TBondNymNodeArgs['costParams'];
+ step: number;
+ onNext: (data: Signature) => void;
+ onClose: () => void;
+ onBack: () => void;
+}) => {
+ const [message, setMessage] = useState('');
+ const [error, setError] = useState();
+ const { generateNymNodeMsgPayload } = useBondingContext();
+
+ const {
+ register,
+ formState: { errors },
+ } = useForm();
+
+ const generateMessage = async () => {
+ try {
+ const msg = await generateNymNodeMsgPayload({
+ nymNode,
+ pledge,
+ costParams,
+ });
+
+ if (msg) {
+ setMessage(msg);
+ }
+ } catch (e) {
+ console.error(e);
+ setError('Something went wrong while generating the payload signature');
+ }
+ };
+
+ useEffect(() => {
+ generateMessage();
+ }, [nymNode, pledge, costParams]);
+
+ const onSubmit = async (data: Signature) => {
+ onNext(data);
+ };
+
+ if (error) {
+ return {}} />;
+ }
+
+ return (
+
+ onSubmit({
+ signature: 'signature',
+ })
+ }
+ onClose={onClose}
+ header="Bond Nym Node"
+ subHeader={`Step ${step}/3`}
+ okLabel="Next"
+ onBack={onBack}
+ okDisabled={Object.keys(errors).length > 0}
+ >
+
+
+ Copy the message below and sign it:
+
+ If you are using a nym-node:
+
+ nym-node sign --id <your-node-id> --contract-msg <payload-generated-by-the-wallet>
+
+ Then paste the signature in the next field.
+
+
+
+ Copy Message
+ {message && }
+
+
+
+
+ );
+};
+
+export default NymNodeSignature;
diff --git a/nym-wallet/src/components/Bonding/forms/nym-node/amountValidationSchema.ts b/nym-wallet/src/components/Bonding/forms/nym-node/amountValidationSchema.ts
new file mode 100644
index 0000000000..1868a4f2e2
--- /dev/null
+++ b/nym-wallet/src/components/Bonding/forms/nym-node/amountValidationSchema.ts
@@ -0,0 +1,58 @@
+import * as Yup from 'yup';
+import { TauriContractStateParams } from 'src/types';
+import { isLessThan, isGreaterThan, validateAmount } from 'src/utils';
+
+const operatingCostAndPmValidation = (params?: TauriContractStateParams) => {
+ const defaultParams = {
+ profit_margin_percent: {
+ minimum: parseFloat(params?.profit_margin.minimum || '0%'),
+ maximum: parseFloat(params?.profit_margin.maximum || '100%'),
+ },
+
+ interval_operating_cost: {
+ minimum: parseFloat(params?.operating_cost.minimum.amount || '0'),
+ maximum: parseFloat(params?.operating_cost.maximum.amount || '1000000000'),
+ },
+ };
+
+ return {
+ profit_margin_percent: Yup.number()
+ .required('Profit Percentage is required')
+ .min(defaultParams.profit_margin_percent.minimum)
+ .max(defaultParams.profit_margin_percent.maximum),
+ interval_operating_cost: Yup.object().shape({
+ amount: Yup.string()
+ .required('An operating cost is required')
+ // eslint-disable-next-line prefer-arrow-callback
+ .test('valid-operating-cost', 'A valid amount is required', async function isValidAmount(this, value) {
+ if (
+ value &&
+ (!Number(value) ||
+ isLessThan(+value, defaultParams.interval_operating_cost.minimum) ||
+ isGreaterThan(+value, Number(defaultParams.interval_operating_cost.maximum)))
+ ) {
+ return this.createError({
+ message: `A valid amount is required (min ${defaultParams?.interval_operating_cost.minimum} - max ${defaultParams?.interval_operating_cost.maximum})`,
+ });
+ }
+ return true;
+ }),
+ }),
+ };
+};
+
+export const nymNodeAmountSchema = (params?: TauriContractStateParams) =>
+ Yup.object().shape({
+ pledge: Yup.object().shape({
+ amount: Yup.string()
+ .required('An amount is required')
+ .test('valid-amount', 'Pledge error', async function isValidAmount(this, value) {
+ const isValid = await validateAmount(value || '', '100');
+ if (!isValid) {
+ return this.createError({ message: 'A valid amount is required (min 100)' });
+ }
+ return true;
+ }),
+ }),
+ ...operatingCostAndPmValidation(params),
+ });
diff --git a/nym-wallet/src/components/Bonding/modals/BondGatewayModal.tsx b/nym-wallet/src/components/Bonding/modals/BondGatewayModal.tsx
index defdac3f95..1060b7c533 100644
--- a/nym-wallet/src/components/Bonding/modals/BondGatewayModal.tsx
+++ b/nym-wallet/src/components/Bonding/modals/BondGatewayModal.tsx
@@ -4,15 +4,11 @@ import { CurrencyDenom, TNodeType } from '@nymproject/types';
import { ConfirmTx } from 'src/components/ConfirmTX';
import { ModalListItem } from 'src/components/Modals/ModalListItem';
import { SimpleModal } from 'src/components/Modals/SimpleModal';
-import { TPoolOption } from 'src/components/TokenPoolSelector';
import { useGetFee } from 'src/hooks/useGetFee';
-import { GatewayAmount, GatewayData, Signature } from 'src/pages/bonding/types';
-import { simulateBondGateway, simulateVestingBondGateway } from 'src/requests';
-import { TBondGatewayArgs } from 'src/types';
+import { GatewayAmount, GatewayData } from 'src/pages/bonding/types';
import { BalanceWarning } from 'src/components/FeeWarning';
import { AppContext } from 'src/context';
-import { BondGatewayForm } from '../forms/BondGatewayForm';
-import { gatewayToTauri } from '../utils';
+import { BondGatewayForm } from '../forms/legacyForms/BondGatewayForm';
const defaultGatewayValues: GatewayData = {
identityKey: '',
@@ -34,14 +30,12 @@ const defaultAmountValues = (denom: CurrencyDenom) => ({
export const BondGatewayModal = ({
denom,
hasVestingTokens,
- onBondGateway,
onSelectNodeType,
onClose,
onError,
}: {
denom: CurrencyDenom;
hasVestingTokens: boolean;
- onBondGateway: (data: TBondGatewayArgs, tokenPool: TPoolOption) => void;
onSelectNodeType: (type: TNodeType) => void;
onClose: () => void;
onError: (e: string) => void;
@@ -49,9 +43,8 @@ export const BondGatewayModal = ({
const [step, setStep] = useState<1 | 2 | 3>(1);
const [gatewayData, setGatewayData] = useState(defaultGatewayValues);
const [amountData, setAmountData] = useState(defaultAmountValues(denom));
- const [signature, setSignature] = useState();
- const { fee, getFee, resetFeeState, feeError } = useGetFee();
+ const { fee, resetFeeState, feeError } = useGetFee();
const { userBalance } = useContext(AppContext);
useEffect(() => {
@@ -83,32 +76,7 @@ export const BondGatewayModal = ({
setStep(3);
};
- const handleUpdateSignature = async (data: Signature) => {
- setSignature(data.signature);
-
- const payload = {
- pledge: amountData.amount,
- msgSignature: data.signature,
- gateway: gatewayToTauri(gatewayData),
- };
-
- if (amountData.tokenPool === 'balance') {
- await getFee(simulateBondGateway, payload);
- } else {
- await getFee(simulateVestingBondGateway, payload);
- }
- };
-
- const handleConfirm = async () => {
- await onBondGateway(
- {
- pledge: amountData.amount,
- msgSignature: signature as string,
- gateway: gatewayToTauri(gatewayData),
- },
- amountData.tokenPool as TPoolOption,
- );
- };
+ const handleConfirm = async () => {};
if (fee) {
return (
@@ -154,7 +122,6 @@ export const BondGatewayModal = ({
hasVestingTokens={hasVestingTokens}
onValidateGatewayData={handleUpdateGatwayData}
onValidateAmountData={handleUpdateAmountData}
- onValidateSignature={handleUpdateSignature}
onSelectNodeType={onSelectNodeType}
/>
diff --git a/nym-wallet/src/components/Bonding/modals/BondMixnodeModal.tsx b/nym-wallet/src/components/Bonding/modals/BondMixnodeModal.tsx
deleted file mode 100644
index 4e4c39f9cf..0000000000
--- a/nym-wallet/src/components/Bonding/modals/BondMixnodeModal.tsx
+++ /dev/null
@@ -1,163 +0,0 @@
-import React, { useContext, useEffect, useState } from 'react';
-import { CurrencyDenom, TNodeType } from '@nymproject/types';
-import { ConfirmTx } from 'src/components/ConfirmTX';
-import { ModalListItem } from 'src/components/Modals/ModalListItem';
-import { SimpleModal } from 'src/components/Modals/SimpleModal';
-import { TPoolOption } from 'src/components/TokenPoolSelector';
-import { useGetFee } from 'src/hooks/useGetFee';
-import { MixnodeAmount, MixnodeData, Signature } from 'src/pages/bonding/types';
-import { simulateBondMixnode, simulateVestingBondMixnode } from 'src/requests';
-import { TBondMixNodeArgs } from 'src/types';
-import { BalanceWarning } from 'src/components/FeeWarning';
-import { AppContext } from 'src/context';
-import { BondMixnodeForm } from '../forms/BondMixnodeForm';
-import { costParamsToTauri, mixnodeToTauri } from '../utils';
-
-const defaultMixnodeValues: MixnodeData = {
- identityKey: '',
- sphinxKey: '',
- ownerSignature: '',
- host: '',
- version: '',
- mixPort: 1789,
- verlocPort: 1790,
- httpApiPort: 8000,
-};
-
-const defaultAmountValues = (denom: CurrencyDenom) => ({
- amount: { amount: '100', denom },
- operatorCost: { amount: '40', denom },
- profitMargin: '10',
- tokenPool: 'balance',
-});
-
-export const BondMixnodeModal = ({
- denom,
- hasVestingTokens,
- onBondMixnode,
- onSelectNodeType,
- onClose,
- onError,
-}: {
- denom: CurrencyDenom;
- hasVestingTokens: boolean;
- onBondMixnode: (data: TBondMixNodeArgs, tokenPool: TPoolOption) => void;
- onSelectNodeType: (type: TNodeType) => void;
- onClose: () => void;
- onError: (e: string) => void;
-}) => {
- const [step, setStep] = useState<1 | 2 | 3 | 4>(1);
- const [mixnodeData, setMixnodeData] = useState(defaultMixnodeValues);
- const [amountData, setAmountData] = useState(defaultAmountValues(denom));
- const [signature, setSignature] = useState();
-
- const { fee, getFee, resetFeeState, feeError } = useGetFee();
- const { userBalance } = useContext(AppContext);
-
- useEffect(() => {
- if (feeError) {
- onError(feeError);
- }
- }, [feeError]);
-
- const validateStep = async (s: number) => {
- const event = new CustomEvent('validate_bond_mixnode_step', { detail: { step: s } });
- window.dispatchEvent(event);
- };
-
- const handleBack = () => {
- if (step === 2) {
- setStep(1);
- } else if (step === 3) {
- setStep(2);
- }
- };
-
- const handleUpdateMixnodeData = (data: MixnodeData) => {
- setMixnodeData(data);
- setStep(2);
- };
-
- const handleUpdateAmountData = async (data: MixnodeAmount) => {
- setAmountData({ ...data });
- setStep(3);
- };
-
- const handleUpdateSignature = async (data: Signature) => {
- setSignature(data.signature);
-
- const payload = {
- pledge: amountData.amount,
- msgSignature: data.signature,
- mixnode: mixnodeToTauri(mixnodeData),
- costParams: costParamsToTauri(amountData),
- };
-
- if (amountData.tokenPool === 'balance') {
- await getFee(simulateBondMixnode, payload);
- } else {
- await getFee(simulateVestingBondMixnode, payload);
- }
- };
-
- const handleConfirm = async () => {
- await onBondMixnode(
- {
- pledge: amountData.amount,
- msgSignature: signature as string,
- mixnode: mixnodeToTauri(mixnodeData),
- costParams: costParamsToTauri(amountData),
- },
- amountData.tokenPool as TPoolOption,
- );
- };
-
- if (fee) {
- return (
-
-
-
- {fee.amount?.amount && userBalance.balance && (
-
- )}
-
- );
- }
-
- return (
- {
- await validateStep(step);
- }}
- onBack={step === 2 || step === 3 ? handleBack : undefined}
- onClose={onClose}
- header="Bond mixnode"
- subHeader={`Step ${step}/3`}
- okLabel="Next"
- >
-
-
- );
-};
diff --git a/nym-wallet/src/components/Bonding/modals/BondNymNodeModal.tsx b/nym-wallet/src/components/Bonding/modals/BondNymNodeModal.tsx
new file mode 100644
index 0000000000..bfed31e765
--- /dev/null
+++ b/nym-wallet/src/components/Bonding/modals/BondNymNodeModal.tsx
@@ -0,0 +1,88 @@
+import React, { useContext, useEffect } from 'react';
+import { ConfirmTx } from 'src/components/ConfirmTX';
+import { ModalListItem } from 'src/components/Modals/ModalListItem';
+import { useGetFee } from 'src/hooks/useGetFee';
+import { Signature } from 'src/pages/bonding/types';
+import { BalanceWarning } from 'src/components/FeeWarning';
+import { AppContext } from 'src/context';
+import FormContextProvider, { useFormContext } from '../forms/nym-node/FormContext';
+import NymNodeData from '../forms/nym-node/NymNodeData';
+import NymNodeAmount from '../forms/nym-node/NymNodeAmount';
+import NymNodeSignature from '../forms/nym-node/NymNodeSignature';
+
+export const BondNymNodeModal = ({ onClose }: { onClose: () => void }) => {
+ const { fee, resetFeeState, feeError } = useGetFee();
+ const { userBalance } = useContext(AppContext);
+ const { setStep, step, onError, setSignature, amountData, costParams, nymNodeData } = useFormContext();
+
+ useEffect(() => {
+ if (feeError) {
+ onError(feeError);
+ }
+ }, [feeError]);
+
+ const handleUpdateMixnodeData = async () => {
+ setStep(2);
+ };
+
+ const handleUpdateSignature = async (data: Signature) => {
+ setSignature(data.signature);
+ };
+
+ const handleConfirm = async () => {};
+
+ if (fee) {
+ return (
+
+
+
+ {fee.amount?.amount && userBalance.balance && (
+
+ )}
+
+ );
+ }
+
+ if (step === 1) {
+ return ;
+ }
+
+ if (step === 2) {
+ return setStep(1)} onNext={async () => setStep(3)} step={step} />;
+ }
+
+ if (step === 3) {
+ return (
+ setStep(2)}
+ step={step}
+ />
+ );
+ }
+
+ return null;
+};
+
+export const BondNymNodeModalWithState = ({ open, onClose }: { open: boolean; onClose: () => void }) => {
+ if (!open) {
+ return null;
+ }
+
+ return (
+
+
+
+ );
+};
diff --git a/nym-wallet/src/components/Bonding/modals/MigrateLegacyNode.tsx b/nym-wallet/src/components/Bonding/modals/MigrateLegacyNode.tsx
new file mode 100644
index 0000000000..1a04601200
--- /dev/null
+++ b/nym-wallet/src/components/Bonding/modals/MigrateLegacyNode.tsx
@@ -0,0 +1,28 @@
+import React from 'react';
+import { Box, Typography } from '@mui/material';
+import { SimpleModal } from 'src/components/Modals/SimpleModal';
+
+const MigrateLegacyNode = ({
+ open,
+ onClose,
+ handleMigrate,
+}: {
+ open: boolean;
+ onClose: () => void;
+ handleMigrate: () => Promise;
+}) => (
+ Migrate Legacy Node}
+ onOk={handleMigrate}
+ okLabel="Migrate"
+ onClose={onClose}
+ sx={{ maxWidth: 500 }}
+ >
+
+ You have a legacy node that needs to be migrated to the new system.
+
+
+);
+
+export default MigrateLegacyNode;
diff --git a/nym-wallet/src/components/Bonding/modals/NodeSettingsModal.tsx b/nym-wallet/src/components/Bonding/modals/NodeSettingsModal.tsx
index 0aa53e7368..8d87405d13 100644
--- a/nym-wallet/src/components/Bonding/modals/NodeSettingsModal.tsx
+++ b/nym-wallet/src/components/Bonding/modals/NodeSettingsModal.tsx
@@ -2,7 +2,6 @@ import React, { useEffect, useState } from 'react';
import { Box, Button, FormHelperText, TextField, Typography } from '@mui/material';
import { SimpleModal } from 'src/components/Modals/SimpleModal';
import { Node as NodeIcon } from 'src/svg-icons/node';
-import { TBondedMixnode } from 'src/context';
import { Tabs } from 'src/components/Tabs';
import { ModalListItem } from 'src/components/Modals/ModalListItem';
import { attachDefaultOperatingCost, isDecimal, toPercentFloatString } from 'src/utils';
@@ -11,6 +10,7 @@ import { ConfirmTx } from 'src/components/ConfirmTX';
import { simulateUpdateMixnodeCostParams, simulateVestingUpdateMixnodeCostParams } from 'src/requests';
import { LoadingModal } from 'src/components/Modals/LoadingModal';
import { FeeDetails } from '@nymproject/types';
+import { TBondedMixnode } from 'src/requests/mixnodeDetails';
// Now we are using the node setting page instead of this modal
export const NodeSettings = ({
diff --git a/nym-wallet/src/components/Bonding/modals/RedeemRewardsModal.tsx b/nym-wallet/src/components/Bonding/modals/RedeemRewardsModal.tsx
index 11279278f6..8e00ddbfa5 100644
--- a/nym-wallet/src/components/Bonding/modals/RedeemRewardsModal.tsx
+++ b/nym-wallet/src/components/Bonding/modals/RedeemRewardsModal.tsx
@@ -5,9 +5,10 @@ import { SimpleModal } from 'src/components/Modals/SimpleModal';
import { ModalFee } from 'src/components/Modals/ModalFee';
import { useGetFee } from 'src/hooks/useGetFee';
import { simulateClaimOperatorReward, simulateVestingClaimOperatorReward } from 'src/requests';
-import { AppContext, TBondedMixnode } from 'src/context';
+import { AppContext } from 'src/context';
import { BalanceWarning } from 'src/components/FeeWarning';
import { Box } from '@mui/material';
+import { TBondedMixnode } from 'src/requests/mixnodeDetails';
export const RedeemRewardsModal = ({
node,
diff --git a/nym-wallet/src/components/Bonding/modals/UnbondModal.tsx b/nym-wallet/src/components/Bonding/modals/UnbondModal.tsx
index 41eeb45211..51e779a563 100644
--- a/nym-wallet/src/components/Bonding/modals/UnbondModal.tsx
+++ b/nym-wallet/src/components/Bonding/modals/UnbondModal.tsx
@@ -1,9 +1,10 @@
import * as React from 'react';
import { useEffect } from 'react';
import { Typography } from '@mui/material';
-import { TBondedGateway, TBondedMixnode } from 'src/context';
import { useGetFee } from 'src/hooks/useGetFee';
import { isGateway, isMixnode } from 'src/types';
+import { TBondedGateway } from 'src/requests/gatewayDetails';
+import { TBondedMixnode } from 'src/requests/mixnodeDetails';
import { ModalFee } from '../../Modals/ModalFee';
import { ModalListItem } from '../../Modals/ModalListItem';
import { SimpleModal } from '../../Modals/SimpleModal';
diff --git a/nym-wallet/src/components/Bonding/modals/UpdateBondAmountModal.tsx b/nym-wallet/src/components/Bonding/modals/UpdateBondAmountModal.tsx
index 2148313b70..978675bd9b 100644
--- a/nym-wallet/src/components/Bonding/modals/UpdateBondAmountModal.tsx
+++ b/nym-wallet/src/components/Bonding/modals/UpdateBondAmountModal.tsx
@@ -10,8 +10,9 @@ import { useGetFee } from 'src/hooks/useGetFee';
import { decCoinToDisplay, validateAmount } from 'src/utils';
import { simulateUpdateBond, simulateVestingUpdateBond } from 'src/requests';
import { TSimulateUpdateBondArgs, TUpdateBondArgs } from 'src/types';
-import { AppContext, TBondedMixnode } from 'src/context';
+import { AppContext } from 'src/context';
import { BalanceWarning } from 'src/components/FeeWarning';
+import { TBondedMixnode } from 'src/requests/mixnodeDetails';
import { TPoolOption } from '../../TokenPoolSelector';
export const UpdateBondAmountModal = ({
diff --git a/nym-wallet/src/components/Bonding/modals/UpdateBondAmountNymNode.tsx b/nym-wallet/src/components/Bonding/modals/UpdateBondAmountNymNode.tsx
new file mode 100644
index 0000000000..e634b1c354
--- /dev/null
+++ b/nym-wallet/src/components/Bonding/modals/UpdateBondAmountNymNode.tsx
@@ -0,0 +1,153 @@
+import React, { useContext, useEffect, useState } from 'react';
+import { Box, Stack } from '@mui/material';
+import Big from 'big.js';
+import { CurrencyFormField } from '@nymproject/react/currency/CurrencyFormField';
+import { ModalListItem } from 'src/components/Modals/ModalListItem';
+import { SimpleModal } from 'src/components/Modals/SimpleModal';
+import { DecCoin } from '@nymproject/types';
+import { ConfirmTx } from 'src/components/ConfirmTX';
+import { useGetFee } from 'src/hooks/useGetFee';
+import { decCoinToDisplay, validateAmount } from 'src/utils';
+import { simulateUpdateBond } from 'src/requests';
+import { TSimulateUpdateBondArgs, TUpdateBondArgs } from 'src/types';
+import { AppContext } from 'src/context';
+import { BalanceWarning } from 'src/components/FeeWarning';
+import { TBondedNymNode } from 'src/requests/nymNodeDetails';
+import { TPoolOption } from '../../TokenPoolSelector';
+
+export const UpdateBondAmountNymNode = ({
+ node,
+ onUpdateBond,
+ onClose,
+ onError,
+}: {
+ node: TBondedNymNode;
+ onUpdateBond: (data: TUpdateBondArgs, tokenPool: TPoolOption) => Promise;
+ onClose: () => void;
+ onError: (e: string) => void;
+}) => {
+ const { bond: currentBond, stakeSaturation, uncappedStakeSaturation } = node;
+
+ const { fee, getFee, resetFeeState, feeError } = useGetFee();
+ const [newBond, setNewBond] = useState();
+ const [errorAmount, setErrorAmount] = useState(false);
+
+ const { printBalance, userBalance } = useContext(AppContext);
+
+ useEffect(() => {
+ if (feeError) {
+ onError(feeError);
+ }
+ }, [feeError]);
+
+ const handleConfirm = async () => {
+ if (!newBond) {
+ return;
+ }
+
+ await onUpdateBond(
+ {
+ currentPledge: currentBond,
+ newPledge: newBond,
+ fee: fee?.fee,
+ },
+ 'balance',
+ );
+ };
+
+ const handleAmountChanged = async (value: DecCoin) => {
+ const { amount } = value;
+ setNewBond(value);
+ if (!amount || !Number(amount)) {
+ setErrorAmount(true);
+ } else if (Big(amount).eq(currentBond.amount)) {
+ setErrorAmount(true);
+ } else {
+ const validAmount = await validateAmount(amount, '1');
+ if (!validAmount) {
+ setErrorAmount(true);
+ return;
+ }
+ setErrorAmount(false);
+ }
+ };
+
+ const handleOnOk = async () => {
+ if (!newBond) {
+ return;
+ }
+
+ await getFee(simulateUpdateBond, {
+ currentPledge: currentBond,
+ newPledge: newBond,
+ });
+ };
+
+ const newBondToDisplay = () => {
+ const coin = decCoinToDisplay(newBond as DecCoin);
+ return `${coin.amount} ${coin.denom}`;
+ };
+
+ if (fee)
+ return (
+
+
+
+ {userBalance.balance?.amount.amount && fee?.amount?.amount && (
+
+
+
+ )}
+
+ );
+
+ return (
+
+
+
+ {
+ handleAmountChanged(value);
+ }}
+ fullWidth
+ validationError={errorAmount ? 'Please enter a valid amount' : undefined}
+ />
+
+
+
+
+
+ {uncappedStakeSaturation ? (
+
+ ) : (
+
+ )}
+
+
+
+
+ );
+};
diff --git a/nym-wallet/src/components/Bonding/utils.ts b/nym-wallet/src/components/Bonding/utils.ts
index 6e7b05a651..bb3be55e60 100644
--- a/nym-wallet/src/components/Bonding/utils.ts
+++ b/nym-wallet/src/components/Bonding/utils.ts
@@ -1,4 +1,4 @@
-import { Gateway, MixNode, MixNodeCostParams } from '@nymproject/types';
+import { Gateway, MixNode, NodeCostParams } from '@nymproject/types';
import { GatewayData, MixnodeAmount, MixnodeData } from '../../pages/bonding/types';
import { toPercentFloatString } from '../../utils';
@@ -14,7 +14,7 @@ export function mixnodeToTauri(data: MixnodeData): MixNode {
};
}
-export function costParamsToTauri(data: MixnodeAmount): MixNodeCostParams {
+export function costParamsToTauri(data: MixnodeAmount): NodeCostParams {
return {
profit_margin_percent: toPercentFloatString(data.profitMargin),
interval_operating_cost: {
diff --git a/nym-wallet/src/components/NodeStatus.tsx b/nym-wallet/src/components/NodeStatus.tsx
index 00ec32197d..99f92bcd18 100644
--- a/nym-wallet/src/components/NodeStatus.tsx
+++ b/nym-wallet/src/components/NodeStatus.tsx
@@ -32,5 +32,4 @@ export const NodeStatus = ({ status }: { status: MixnodeStatus }) => {
default:
return null;
}
- return null;
};
diff --git a/nym-wallet/src/components/NymCard.tsx b/nym-wallet/src/components/NymCard.tsx
index 768f0811ab..ae3d84fe23 100644
--- a/nym-wallet/src/components/NymCard.tsx
+++ b/nym-wallet/src/components/NymCard.tsx
@@ -20,7 +20,7 @@ export const NymCard: FCWithChildren<{
dataTestid?: string;
sx?: SxProps;
sxTitle?: SxProps;
- children: React.ReactNode;
+ children?: React.ReactNode;
}> = ({ title, subheader, Action, Icon, noPadding, borderless, children, dataTestid, sx, sxTitle }) => (
Promise;
- bondMixnode: (data: TBondMixNodeArgs, tokenPool: TokenPool) => Promise;
- bondGateway: (data: TBondGatewayArgs, tokenPool: TokenPool) => Promise;
- unbond: (fee?: FeeDetails) => Promise;
- updateBondAmount: (data: TUpdateBondArgs, tokenPool: TokenPool) => Promise;
- redeemRewards: (fee?: FeeDetails) => Promise;
- updateMixnode: (pm: string, fee?: FeeDetails) => Promise;
- generateMixnodeMsgPayload: (data: TBondMixnodeSignatureArgs) => Promise;
- generateGatewayMsgPayload: (data: TBondGatewaySignatureArgs) => Promise;
+ bondedNode?: TBondedNode | null;
isVestingAccount: boolean;
+ refresh: () => void;
+ unbond: (fee?: FeeDetails) => Promise;
+ updateBondAmount: (data: TUpdateBondArgs) => Promise;
+ redeemRewards: (fee?: FeeDetails) => Promise;
+ generateNymNodeMsgPayload: (data: TNymNodeSignatureArgs) => Promise;
migrateVestedMixnode: () => Promise;
+ migrateLegacyNode: () => Promise;
};
export const BondingContext = createContext({
isLoading: true,
refresh: async () => undefined,
- bondMixnode: async () => {
- throw new Error('Not implemented');
- },
- bondGateway: async () => {
- throw new Error('Not implemented');
- },
unbond: async () => {
throw new Error('Not implemented');
},
@@ -150,29 +50,27 @@ export const BondingContext = createContext({
redeemRewards: async () => {
throw new Error('Not implemented');
},
- updateMixnode: async () => {
- throw new Error('Not implemented');
- },
- generateMixnodeMsgPayload: async () => {
- throw new Error('Not implemented');
- },
- generateGatewayMsgPayload: async () => {
+ generateNymNodeMsgPayload: async () => {
throw new Error('Not implemented');
},
migrateVestedMixnode: async () => {
throw new Error('Not implemented');
},
+ migrateLegacyNode: async () => {
+ throw new Error('Not implemented');
+ },
isVestingAccount: false,
});
export const BondingContextProvider: FCWithChildren = ({ children }): JSX.Element => {
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState();
- const [bondedNode, setBondedNode] = useState();
+
const [isVestingAccount, setIsVestingAccount] = useState(false);
- const { userBalance, clientDetails } = useContext(AppContext);
- const { ownership, isLoading: isOwnershipLoading } = useCheckOwnership();
+ const { userBalance, clientDetails, network } = useContext(AppContext);
+
+ const { bondedNode, isLoading: isBondedNodeLoading } = useGetNodeDetails(clientDetails?.client_address, network);
useEffect(() => {
userBalance.fetchBalance();
@@ -186,317 +84,19 @@ export const BondingContextProvider: FCWithChildren = ({ children }): JSX.Elemen
const resetState = () => {
setError(undefined);
- setBondedNode(undefined);
- };
-
- /**
- * Fetch mixnode **optional** data.
- * ⚠ The underlying queries are allowed to fail.
- */
- const fetchMixnodeDetails = async (mixId: number, host: string, port: number) => {
- const details: {
- status: MixnodeStatus;
- stakeSaturation: string;
- estimatedRewards?: DecCoin;
- uptime: number;
- averageUptime?: number;
- setProbability?: InclusionProbabilityResponse;
- nodeDescription?: TNodeDescription | undefined;
- operatorRewards?: DecCoin;
- uncappedSaturation?: number;
- } = {
- status: 'not_found',
- stakeSaturation: '0',
- uptime: 0,
- };
-
- const statusReq: TauriReq = {
- name: 'getMixnodeStatus',
- request: () => getMixnodeStatus(mixId),
- onFulfilled: (value) => {
- details.status = value.status;
- },
- };
-
- const uptimeReq: TauriReq = {
- name: 'getMixnodeUptime',
- request: () => getMixnodeUptime(mixId),
- onFulfilled: (value) => {
- details.uptime = value;
- },
- };
-
- const stakeSaturationReq: TauriReq = {
- name: 'getMixnodeStakeSaturation',
- request: () => getMixnodeStakeSaturation(mixId),
- onFulfilled: (value) => {
- details.stakeSaturation = decimalToPercentage(value.saturation);
- const rawUncappedSaturation = decimalToFloatApproximation(value.uncapped_saturation);
- if (rawUncappedSaturation && rawUncappedSaturation > 1) {
- details.uncappedSaturation = Math.round(rawUncappedSaturation * 100);
- }
- },
- };
-
- const rewardReq: TauriReq = {
- name: 'getMixnodeRewardEstimation',
- request: () => getMixnodeRewardEstimation(mixId),
- onFulfilled: (value) => {
- const estimatedRewards = unymToNym(value.estimation.total_node_reward);
- if (estimatedRewards) {
- details.estimatedRewards = {
- amount: estimatedRewards,
- denom: 'nym',
- };
- }
- },
- };
-
- const inclusionReq: TauriReq = {
- name: 'getInclusionProbability',
- request: () => getInclusionProbability(mixId),
- onFulfilled: (value) => {
- details.setProbability = value;
- },
- };
-
- const avgUptimeReq: TauriReq = {
- name: 'getMixnodeAvgUptime',
- request: () => getMixnodeAvgUptime(),
- onFulfilled: (value) => {
- details.averageUptime = value as number | undefined;
- },
- };
-
- const nodeDescReq: TauriReq = {
- name: 'getNodeDescription',
- request: () => getNodeDescriptionRequest(host, port),
- onFulfilled: (value) => {
- details.nodeDescription = value;
- },
- };
-
- const operatorRewardsReq: TauriReq = {
- name: 'getPendingOperatorRewards',
- request: () => getPendingOperatorRewards(clientDetails?.client_address || ''),
- onFulfilled: (value) => {
- details.operatorRewards = decCoinToDisplay(value);
- },
- };
-
- await fireRequests([
- statusReq,
- uptimeReq,
- stakeSaturationReq,
- rewardReq,
- inclusionReq,
- avgUptimeReq,
- nodeDescReq,
- operatorRewardsReq,
- ]);
-
- return details;
- };
-
- /**
- * Fetch gateway **optional** data.
- * ⚠ The underlying queries are allowed to fail.
- */
- const fetchGatewayDetails = async (identityKey: string, host: string, port: number) => {
- const details: {
- routingScore?: { current: number; average: number } | undefined;
- nodeDescription?: TNodeDescription | undefined;
- } = {};
-
- const reportReq: TauriReq = {
- name: 'getGatewayReport',
- request: () => getGatewayReport(identityKey),
- onFulfilled: (value) => {
- details.routingScore = { current: value.most_recent, average: value.last_day };
- },
- };
-
- const nodeDescReq: TauriReq = {
- name: 'getNodeDescription',
- request: () => getNodeDescriptionRequest(host, port),
- onFulfilled: (value) => {
- details.nodeDescription = value;
- },
- };
-
- await fireRequests([reportReq, nodeDescReq]);
-
- return details;
- };
-
- const calculateStake = (pledge: string, delegations: string) => {
- let stake;
- try {
- stake = unymToNym(Big(pledge).plus(delegations));
- } catch (e: any) {
- Console.warn(`not a valid decimal number: ${e}`);
- }
- return stake;
- };
-
- const refresh = useCallback(async () => {
- setIsLoading(true);
- setError(undefined);
-
- if (ownership.hasOwnership && ownership.nodeType === EnumNodeType.mixnode && clientDetails) {
- try {
- const data = await getMixnodeBondDetails();
- if (data) {
- const {
- bond_information,
- rewarding_details,
- bond_information: { mix_id },
- } = data;
-
- const {
- status,
- stakeSaturation,
- uncappedSaturation: uncappedStakeSaturation,
- estimatedRewards,
- uptime,
- operatorRewards,
- averageUptime,
- nodeDescription,
- setProbability,
- } = await fetchMixnodeDetails(
- mix_id,
- bond_information.mix_node.host,
- bond_information.mix_node.http_api_port,
- );
-
- setBondedNode({
- id: data.bond_information.mix_id,
- name: nodeDescription?.name,
- mixId: mix_id,
- identityKey: bond_information.mix_node.identity_key,
- stake: {
- amount: calculateStake(rewarding_details.operator, rewarding_details.delegates),
- denom: bond_information.original_pledge.denom,
- },
- bond: decCoinToDisplay(bond_information.original_pledge),
- profitMargin: toPercentIntegerString(rewarding_details.cost_params.profit_margin_percent),
- delegators: rewarding_details.unique_delegations,
- proxy: bond_information.proxy,
- operatorRewards,
- uptime,
- status,
- stakeSaturation,
- uncappedStakeSaturation,
- operatorCost: decCoinToDisplay(rewarding_details.cost_params.interval_operating_cost),
- host: bond_information.mix_node.host.replace(/\s/g, ''),
- routingScore: averageUptime,
- activeSetProbability: setProbability?.in_active,
- standbySetProbability: setProbability?.in_reserve,
- estimatedRewards,
- httpApiPort: bond_information.mix_node.http_api_port,
- mixPort: bond_information.mix_node.mix_port,
- verlocPort: bond_information.mix_node.verloc_port,
- version: bond_information.mix_node.version,
- isUnbonding: bond_information.is_unbonding,
- } as TBondedMixnode);
- }
- } catch (e: any) {
- Console.warn(e);
- setError(`While fetching current bond state, an error occurred: ${e}`);
- }
- }
-
- if (ownership.hasOwnership && ownership.nodeType === EnumNodeType.gateway) {
- try {
- const data = await getGatewayBondDetails();
- if (data) {
- const { gateway, proxy } = data;
- const { nodeDescription, routingScore } = await fetchGatewayDetails(
- gateway.identity_key,
- data.gateway.host,
- data.gateway.clients_port,
- );
- setBondedNode({
- name: nodeDescription?.name,
- identityKey: gateway.identity_key,
- mixPort: gateway.mix_port,
- httpApiPort: gateway.clients_port,
- host: gateway.host,
- ip: gateway.host,
- location: gateway.location,
- bond: decCoinToDisplay(data.pledge_amount),
- proxy,
- routingScore,
- version: gateway.version,
- } as TBondedGateway);
- }
- } catch (e: any) {
- Console.warn(e);
- setError(`While fetching current bond state, an error occurred: ${e}`);
- }
- }
-
- if (!ownership.hasOwnership) {
- resetState();
- }
setIsLoading(false);
- }, [ownership]);
-
- useEffect(() => {
- refresh();
- }, [ownership, refresh]);
-
- const bondMixnode = async (data: TBondMixNodeArgs, tokenPool: TokenPool) => {
- let tx: TransactionExecuteResult | undefined;
- setIsLoading(true);
- try {
- if (tokenPool === 'balance') {
- tx = await bondMixNodeRequest(data);
- await userBalance.fetchBalance();
- }
- if (tokenPool === 'locked') {
- tx = await vestingBondMixNode(data);
- await userBalance.fetchTokenAllocation();
- }
- return tx;
- } catch (e: any) {
- Console.warn(e);
- setError(`an error occurred: ${e}`);
- } finally {
- setIsLoading(false);
- }
- return undefined;
};
- const bondGateway = async (data: TBondGatewayArgs, tokenPool: TokenPool) => {
- let tx: TransactionExecuteResult | undefined;
- setIsLoading(true);
- try {
- if (tokenPool === 'balance') {
- tx = await bondGatewayRequest(data);
- await userBalance.fetchBalance();
- }
- if (tokenPool === 'locked') {
- tx = await vestingBondGateway(data);
- await userBalance.fetchTokenAllocation();
- }
- return tx;
- } catch (e: any) {
- Console.warn(e);
- setError(`an error occurred: ${e}`);
- } finally {
- setIsLoading(false);
- }
- return undefined;
+ const refresh = () => {
+ resetState();
};
const unbond = async (fee?: FeeDetails) => {
let tx;
setIsLoading(true);
try {
- if (bondedNode && isMixnode(bondedNode) && bondedNode.proxy) tx = await vestingUnbondMixnode(fee?.fee);
+ if (bondedNode && isNymNode(bondedNode)) tx = await unbondNymNodeRequest(fee?.fee);
if (bondedNode && isMixnode(bondedNode) && !bondedNode.proxy) tx = await unbondMixnodeRequest(fee?.fee);
- if (bondedNode && isGateway(bondedNode) && bondedNode.proxy) tx = await vestingUnbondGateway(fee?.fee);
if (bondedNode && isGateway(bondedNode) && !bondedNode.proxy) tx = await unbondGatewayRequest(fee?.fee);
} catch (e) {
Console.warn(e);
@@ -507,35 +107,11 @@ export const BondingContextProvider: FCWithChildren = ({ children }): JSX.Elemen
return tx;
};
- const updateMixnode = async (pm: string, fee?: FeeDetails) => {
- let tx;
- setIsLoading(true);
-
- // TODO: this will have to be updated with allowing users to provide their operating cost in the form
- const defaultCostParams = await attachDefaultOperatingCost(toPercentFloatString(pm));
-
- try {
- // JS: this check is not entirely valid. you can have proxy field set whilst not using the vesting contract,
- // you have to check if proxy exists AND if it matches the known vesting contract address!
- if (bondedNode?.proxy) {
- tx = await updateMixnodeVestingCostParamsRequest(defaultCostParams, fee?.fee);
- } else {
- tx = await updateMixnodeCostParamsRequest(defaultCostParams, fee?.fee);
- }
- } catch (e: any) {
- Console.warn(e);
- setError(`an error occurred: ${e}`);
- } finally {
- setIsLoading(false);
- }
- return tx;
- };
-
const redeemRewards = async (fee?: FeeDetails) => {
let tx;
setIsLoading(true);
try {
- if (bondedNode?.proxy) tx = await vestingClaimOperatorReward(fee?.fee);
+ if (bondedNode && !isNymNode(bondedNode)) tx = await vestingClaimOperatorReward(fee?.fee);
else tx = await claimOperatorReward(fee?.fee);
} catch (e: any) {
setError(`an error occurred: ${e}`);
@@ -545,18 +121,12 @@ export const BondingContextProvider: FCWithChildren = ({ children }): JSX.Elemen
return tx;
};
- const updateBondAmount = async (data: TUpdateBondArgs, tokenPool: TokenPool) => {
+ const updateBondAmount = async (data: TUpdateBondArgs) => {
let tx: TransactionExecuteResult | undefined;
setIsLoading(true);
try {
- if (tokenPool === 'balance') {
- tx = await updateBondReq(data);
- await userBalance.fetchBalance();
- }
- if (tokenPool === 'locked') {
- tx = await vestingUpdateBondReq(data);
- await userBalance.fetchTokenAllocation();
- }
+ tx = await updateBondReq(data);
+ await userBalance.fetchBalance();
return tx;
} catch (e: any) {
@@ -568,40 +138,26 @@ export const BondingContextProvider: FCWithChildren = ({ children }): JSX.Elemen
return undefined;
};
- const generateMixnodeMsgPayload = async (data: TBondMixnodeSignatureArgs) => {
- let message;
+ const generateNymNodeMsgPayload = async (data: TNymNodeSignatureArgs) => {
setIsLoading(true);
- try {
- if (data.tokenPool === 'locked') {
- message = await vestingGenerateMixnodeMsgPayloadReq(data);
- } else {
- message = await generateMixnodeMsgPayloadReq(data);
- }
- } catch (e) {
- Console.warn(e);
- setError(`an error occurred: ${e}`);
- } finally {
- setIsLoading(false);
- }
- return message;
- };
- const generateGatewayMsgPayload = async (data: TBondGatewaySignatureArgs) => {
- let message;
- setIsLoading(true);
try {
- if (data.tokenPool === 'locked') {
- message = await vestingGenerateGatewayMsgPayloadReq(data);
- } else {
- message = await generateGatewayMsgPayloadReq(data);
- }
+ const message = await generateNymNodeMsgPayloadReq({
+ nymNode: data.nymNode,
+ pledge: data.pledge,
+ costParams: {
+ ...data.costParams,
+ profit_margin_percent: toPercentFloatString(data.costParams.profit_margin_percent),
+ },
+ });
+ return message;
} catch (e) {
Console.warn(e);
setError(`an error occurred: ${e}`);
} finally {
setIsLoading(false);
}
- return message;
+ return undefined;
};
const migrateVestedMixnode = async () => {
@@ -611,24 +167,36 @@ export const BondingContextProvider: FCWithChildren = ({ children }): JSX.Elemen
return tx;
};
+ const migrateLegacyNode = async () => {
+ setIsLoading(true);
+ let tx: TransactionExecuteResult | undefined;
+
+ if (bondedNode && isMixnode(bondedNode)) {
+ tx = await migrateLegacyMixnodeReq();
+ }
+ if (bondedNode && isGateway(bondedNode)) {
+ tx = await migrateLegacyGatewayReq();
+ }
+
+ setIsLoading(false);
+ return tx;
+ };
+
const memoizedValue = useMemo(
() => ({
- isLoading: isLoading || isOwnershipLoading,
+ isLoading: isLoading || isBondedNodeLoading,
error,
- bondMixnode,
bondedNode,
- bondGateway,
unbond,
- updateMixnode,
refresh,
redeemRewards,
updateBondAmount,
- generateMixnodeMsgPayload,
- generateGatewayMsgPayload,
+ generateNymNodeMsgPayload,
migrateVestedMixnode,
+ migrateLegacyNode,
isVestingAccount,
}),
- [isLoading, isOwnershipLoading, error, bondedNode, isVestingAccount],
+ [isLoading, error, bondedNode, isVestingAccount, isBondedNodeLoading],
);
return {children};
diff --git a/nym-wallet/src/context/mocks/bonding.tsx b/nym-wallet/src/context/mocks/bonding.tsx
index e961272c66..2ef46237f9 100644
--- a/nym-wallet/src/context/mocks/bonding.tsx
+++ b/nym-wallet/src/context/mocks/bonding.tsx
@@ -1,9 +1,10 @@
import { FeeDetails, TransactionExecuteResult } from '@nymproject/types';
import React, { useCallback, useEffect, useMemo, useState } from 'react';
-import type { Network } from 'src/types';
-import { BondingContext, TBondedGateway, TBondedMixnode } from '../bonding';
+import type { Network, TNymNodeSignatureArgs } from 'src/types';
+import { TBondedMixnode } from 'src/requests/mixnodeDetails';
+import { TBondedGateway } from 'src/requests/gatewayDetails';
+import { BondingContext } from '../bonding';
import { mockSleep } from './utils';
-import { TBondGatewaySignatureArgs, TBondMixnodeSignatureArgs } from '../../types';
const SLEEP_MS = 1000;
@@ -30,10 +31,11 @@ const bondedMixnodeMock: TBondedMixnode = {
version: '1.0.2',
isUnbonding: false,
uptime: 1,
+ proxy: null,
+ uncappedStakeSaturation: 100,
};
const bondedGatewayMock: TBondedGateway = {
- id: 1,
name: 'Monster node',
identityKey: 'WayM2fYbtN6kxMwp1TrmQ4VwPks3URR5pBgWPWhzT98F',
ip: '112.43.234.57',
@@ -41,17 +43,18 @@ const bondedGatewayMock: TBondedGateway = {
host: '1.2.34.5 ',
httpApiPort: 8000,
mixPort: 1789,
- verlocPort: 1790,
version: '1.0.2',
routingScore: {
average: 100,
current: 100,
},
+ location: 'Germany',
+ proxy: null,
};
const TxResultMock: TransactionExecuteResult = {
logs_json: '',
- data_json: '',
+ msg_responses_json: '',
transaction_hash: '55303CD4B91FAC4C2715E40EBB52BB3B92829D9431B3A279D37B5CC58432E354',
gas_info: {
gas_wanted: { gas_units: BigInt(1) },
@@ -170,15 +173,7 @@ export const MockBondingContextProvider = ({
return feeMock;
};
- const generateMixnodeMsgPayload = async (_data: TBondMixnodeSignatureArgs) => {
- setIsLoading(true);
- await mockSleep(SLEEP_MS);
- triggerStateUpdate();
- setIsLoading(false);
- return '77dcaba7f41409984f4ebce4a386f59b10f1e65ed5514d1acdccae30174bd84b';
- };
-
- const generateGatewayMsgPayload = async (_data: TBondGatewaySignatureArgs) => {
+ const generateNymNodeMsgPayload = async (_data: TNymNodeSignatureArgs) => {
setIsLoading(true);
await mockSleep(SLEEP_MS);
triggerStateUpdate();
@@ -204,10 +199,10 @@ export const MockBondingContextProvider = ({
updateMixnode,
updateBondAmount,
checkOwnership,
- generateMixnodeMsgPayload,
- generateGatewayMsgPayload,
+ generateNymNodeMsgPayload,
isVestingAccount: false,
migrateVestedMixnode: async () => undefined,
+ migrateLegacyNode: async () => undefined,
}),
[isLoading, error, bondedMixnode, bondedGateway, trigger, fee],
);
diff --git a/nym-wallet/src/context/mocks/delegations.tsx b/nym-wallet/src/context/mocks/delegations.tsx
index 0c984d7369..f2aea600bc 100644
--- a/nym-wallet/src/context/mocks/delegations.tsx
+++ b/nym-wallet/src/context/mocks/delegations.tsx
@@ -108,7 +108,7 @@ export const MockDelegationContextProvider: FCWithChildren = ({ children }) => {
return {
logs_json: '',
- data_json: '',
+ msg_responses_json: '',
gas_info: {
gas_wanted: { gas_units: BigInt(1) },
gas_used: { gas_units: BigInt(1) },
@@ -183,7 +183,7 @@ export const MockDelegationContextProvider: FCWithChildren = ({ children }) => {
return {
logs_json: '',
- data_json: '',
+ msg_responses_json: '',
transaction_hash: '',
gas_info: {
gas_wanted: { gas_units: BigInt(1) },
@@ -195,8 +195,9 @@ export const MockDelegationContextProvider: FCWithChildren = ({ children }) => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const undelegateVesting = async (mix_id: number, _fee?: FeeDetails) => ({
- logs_json: '',
+ msg_responses_json: '',
data_json: '',
+ logs_json: '',
transaction_hash: '',
gas_info: {
gas_wanted: { gas_units: BigInt(1) },
diff --git a/nym-wallet/src/context/mocks/rewards.tsx b/nym-wallet/src/context/mocks/rewards.tsx
index c89fdb00b3..fe84e5cfe2 100644
--- a/nym-wallet/src/context/mocks/rewards.tsx
+++ b/nym-wallet/src/context/mocks/rewards.tsx
@@ -65,8 +65,8 @@ export const MockRewardsContextProvider: FCWithChildren = ({ children }) => {
amount: '1',
denom: 'nym',
},
- data_json: '[]',
logs_json: '[]',
+ msg_responses_json: '[]',
gas_info: {
gas_wanted: { gas_units: BigInt(1) },
gas_used: { gas_units: BigInt(1) },
@@ -78,7 +78,7 @@ export const MockRewardsContextProvider: FCWithChildren = ({ children }) => {
amount: '1',
denom: 'nym',
},
- data_json: '[]',
+ msg_responses_json: '[]',
logs_json: '[]',
gas_info: {
gas_wanted: { gas_units: BigInt(1) },
diff --git a/nym-wallet/src/hooks/useGetNodeDetails.ts b/nym-wallet/src/hooks/useGetNodeDetails.ts
new file mode 100644
index 0000000000..9049b87ce5
--- /dev/null
+++ b/nym-wallet/src/hooks/useGetNodeDetails.ts
@@ -0,0 +1,69 @@
+import { useEffect, useState } from 'react';
+import { TBondedNode } from 'src/context';
+import { getGatewayDetails } from 'src/requests/gatewayDetails';
+import { getMixnodeDetails } from 'src/requests/mixnodeDetails';
+import { getNymNodeDetails } from 'src/requests/nymNodeDetails';
+import { fireRequests, TauriReq } from 'src/utils';
+
+const useGetNodeDetails = (clientAddress?: string, network?: string) => {
+ const [bondedNode, setBondedNode] = useState(null);
+ const [isLoading, setIsLoading] = useState(false);
+ const [isError, setIsError] = useState(false);
+
+ const getNodeDetails = async (address: string) => {
+ setIsError(false);
+ setBondedNode(null);
+ setIsLoading(true);
+
+ // Check if the address has a Nym node bonded
+ const nymnode: TauriReq = {
+ name: 'getNymNodeBondDetails',
+ request: () => getNymNodeDetails(address),
+ onFulfilled: (value) => {
+ if (value) {
+ setBondedNode(value);
+ }
+ },
+ };
+
+ // Check if the address has a Mix node bonded
+ const mixnode: TauriReq = {
+ name: 'getMixnodeDetails',
+ request: () => getMixnodeDetails(address),
+ onFulfilled: (value) => {
+ if (value) {
+ setBondedNode(value);
+ }
+ },
+ };
+
+ // Check if the address has a Gateway bonded
+ const gateway: TauriReq = {
+ name: 'getGatewayDetails',
+ request: () => getGatewayDetails(),
+ onFulfilled: (value) => {
+ if (value) {
+ setBondedNode(value);
+ }
+ },
+ };
+
+ await fireRequests([nymnode, mixnode, gateway]);
+
+ setIsLoading(false);
+ };
+
+ useEffect(() => {
+ if (clientAddress) {
+ getNodeDetails(clientAddress);
+ }
+ }, [clientAddress, network]);
+
+ return {
+ bondedNode,
+ isLoading,
+ isError,
+ };
+};
+
+export default useGetNodeDetails;
diff --git a/nym-wallet/src/pages/Admin/index.tsx b/nym-wallet/src/pages/Admin/index.tsx
index 978360f254..7a0876c5a3 100644
--- a/nym-wallet/src/pages/Admin/index.tsx
+++ b/nym-wallet/src/pages/Admin/index.tsx
@@ -26,29 +26,15 @@ const AdminForm: FCWithChildren<{
-
-
-
diff --git a/nym-wallet/src/pages/bonding/Bonding.tsx b/nym-wallet/src/pages/bonding/Bonding.tsx
index 3ab472d1e4..843ada1f5a 100644
--- a/nym-wallet/src/pages/bonding/Bonding.tsx
+++ b/nym-wallet/src/pages/bonding/Bonding.tsx
@@ -2,55 +2,76 @@ import React, { useContext, useEffect, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { FeeDetails } from '@nymproject/types';
import { Alert, AlertTitle, Box, Button, Typography } from '@mui/material';
-import { TPoolOption } from 'src/components';
import { Bond } from 'src/components/Bonding/Bond';
import { BondedMixnode } from 'src/components/Bonding/BondedMixnode';
import { TBondedMixnodeActions } from 'src/components/Bonding/BondedMixnodeActions';
-import { BondGatewayModal } from 'src/components/Bonding/modals/BondGatewayModal';
-import { BondMixnodeModal } from 'src/components/Bonding/modals/BondMixnodeModal';
import { UpdateBondAmountModal } from 'src/components/Bonding/modals/UpdateBondAmountModal';
import { BondOversaturatedModal } from 'src/components/Bonding/modals/BondOversaturatedModal';
import { ConfirmationDetailProps, ConfirmationDetailsModal } from 'src/components/Bonding/modals/ConfirmationModal';
import { ErrorModal } from 'src/components/Modals/ErrorModal';
import { LoadingModal } from 'src/components/Modals/LoadingModal';
import { AppContext, urls } from 'src/context/main';
-import { isGateway, isMixnode, TBondGatewayArgs, TBondMixNodeArgs, TUpdateBondArgs } from 'src/types';
+import { isGateway, isMixnode, isNymNode, TUpdateBondArgs } from 'src/types';
import { BondedGateway } from 'src/components/Bonding/BondedGateway';
import { RedeemRewardsModal } from 'src/components/Bonding/modals/RedeemRewardsModal';
import { VestingWarningModal } from 'src/components/VestingWarningModal';
+import MigrateLegacyNode from 'src/components/Bonding/modals/MigrateLegacyNode';
+import { BondedNymNode } from 'src/components/Bonding/BondedNymNode';
+import { UpdateBondAmountNymNode } from 'src/components/Bonding/modals/UpdateBondAmountNymNode';
+import { BondNymNodeModalWithState } from 'src/components/Bonding/modals/BondNymNodeModal';
import { BondingContextProvider, useBondingContext } from '../../context';
export const Bonding = () => {
const [showModal, setShowModal] = useState<
- 'bond-mixnode' | 'bond-gateway' | 'update-bond' | 'update-bond-oversaturated' | 'unbond' | 'redeem'
+ | 'bond-mixnode'
+ | 'bond-nymnode'
+ | 'bond-gateway'
+ | 'update-bond'
+ | 'update-bond-oversaturated'
+ | 'unbond'
+ | 'redeem'
+ | 'update-bond-nymnode'
>();
- const [confirmationDetails, setConfirmationDetails] = useState();
- const [uncappedSaturation, setUncappedSaturation] = useState();
- const [showMigrationModal, setShowMigrationModal] = useState(false);
- const {
- network,
- clientDetails,
- userBalance: { originalVesting },
- } = useContext(AppContext);
+
+ const { network } = useContext(AppContext);
const navigate = useNavigate();
const {
bondedNode,
- bondMixnode,
- bondGateway,
- redeemRewards,
isLoading,
- updateBondAmount,
error,
+ redeemRewards,
+ updateBondAmount,
refresh,
migrateVestedMixnode,
+ migrateLegacyNode,
} = useBondingContext();
+ const shouldShowMigrateLegacyNodeModal = () => {
+ if (!bondedNode) {
+ return false;
+ }
+ if (isMixnode(bondedNode) && !bondedNode.isUnbonding) {
+ return true;
+ }
+ if (isGateway(bondedNode)) {
+ return true;
+ }
+ return false;
+ };
+
+ const [confirmationDetails, setConfirmationDetails] = useState();
+ const [uncappedSaturation, setUncappedSaturation] = useState();
+ const [showMigrationModal, setShowMigrationModal] = useState(false);
+ const [showMigrateLegacyNodeModal, setShowMigrateLegacyNodeModal] = useState(false);
+
useEffect(() => {
if (bondedNode && isMixnode(bondedNode) && bondedNode.uncappedStakeSaturation) {
setUncappedSaturation(bondedNode.uncappedStakeSaturation);
}
+
+ setShowMigrateLegacyNodeModal(shouldShowMigrateLegacyNodeModal());
}, [bondedNode]);
const handleMigrateVestedMixnode = async () => {
@@ -65,6 +86,18 @@ export const Bonding = () => {
}
};
+ const handleMigrateLegacyNode = async () => {
+ setShowMigrateLegacyNodeModal(false);
+ const tx = await migrateLegacyNode();
+ if (tx) {
+ setConfirmationDetails({
+ status: 'success',
+ title: 'Migration successful',
+ txUrl: `${urls(network).blockExplorer}/transaction/${tx?.transaction_hash}`,
+ });
+ }
+ };
+
const handleCloseModal = async () => {
setShowModal(undefined);
refresh();
@@ -79,35 +112,10 @@ export const Bonding = () => {
});
};
- const handleBondMixnode = async (data: TBondMixNodeArgs, tokenPool: TPoolOption) => {
- setShowModal(undefined);
- const tx = await bondMixnode(data, tokenPool);
- if (tx) {
- setConfirmationDetails({
- status: 'success',
- title: 'Bond successful',
- txUrl: `${urls(network).blockExplorer}/transaction/${tx?.transaction_hash}`,
- });
- }
- return undefined;
- };
-
- const handleBondGateway = async (data: TBondGatewayArgs, tokenPool: TPoolOption) => {
- setShowModal(undefined);
- const tx = await bondGateway(data, tokenPool);
- if (tx) {
- setConfirmationDetails({
- status: 'success',
- title: 'Bond successful',
- txUrl: `${urls(network).blockExplorer}/transaction/${tx?.transaction_hash}`,
- });
- }
- };
-
- const handleUpdateBond = async (data: TUpdateBondArgs, tokenPool: TPoolOption) => {
+ const handleUpdateBond = async (data: TUpdateBondArgs) => {
setShowModal(undefined);
- const tx = await updateBondAmount(data, tokenPool);
+ const tx = await updateBondAmount(data);
if (tx) {
setConfirmationDetails({
status: 'success',
@@ -154,13 +162,34 @@ export const Bonding = () => {
return undefined;
};
+ const handleBondedNymNodeAction = async (action: TBondedMixnodeActions) => {
+ switch (action) {
+ case 'unbond': {
+ navigate('/bonding/node-settings', { state: 'unbond' });
+ break;
+ }
+ case 'updateBond': {
+ setShowModal('update-bond-nymnode');
+ break;
+ }
+ case 'redeem': {
+ setShowModal('redeem');
+ break;
+ }
+ default: {
+ return undefined;
+ }
+ }
+ return undefined;
+ };
+
if (error) {
return refresh()} />;
}
return (
- {bondedNode?.proxy && (
+ {bondedNode && !isNymNode(bondedNode) && bondedNode?.proxy && (
Your bonded node is using tokens from the vesting contract!
@@ -187,41 +216,41 @@ export const Bonding = () => {
}}
/>
- {!bondedNode && setShowModal('bond-mixnode')} />}
+ setShowMigrateLegacyNodeModal(false)}
+ handleMigrate={handleMigrateLegacyNode}
+ />
+
+ {!bondedNode && setShowModal('bond-nymnode')} />}
+
+ {bondedNode && isNymNode(bondedNode) && (
+ handleBondedNymNodeAction(action)}
+ />
+ )}
{bondedNode && isMixnode(bondedNode) && (
setShowMigrateLegacyNodeModal(true)}
onActionSelect={(action) => handleBondedMixnodeAction(action)}
/>
)}
{bondedNode && isGateway(bondedNode) && (
-
- )}
-
- {showModal === 'bond-mixnode' && (
- setShowModal('bond-gateway')}
- onClose={() => setShowModal(undefined)}
- onError={handleError}
+ setShowMigrateLegacyNodeModal(true)}
+ onActionSelect={handleBondedMixnodeAction}
/>
)}
- {showModal === 'bond-gateway' && (
- setShowModal('bond-mixnode')}
- onClose={() => setShowModal(undefined)}
- onError={handleError}
- />
- )}
+
{showModal === 'update-bond-oversaturated' && uncappedSaturation && (
{
/>
)}
+ {showModal === 'update-bond-nymnode' && bondedNode && isNymNode(bondedNode) && (
+ setShowModal(undefined)}
+ onError={handleError}
+ />
+ )}
+
{showModal === 'redeem' && bondedNode && isMixnode(bondedNode) && (
{
- {isMixnode(bondedNode) ? 'Node' : 'Gateway'} Settings
+ Nym Node Settings
{
}}
>
- You should NOT shutdown your {isMixnode(bondedNode) ? 'mix node' : 'gateway'} until the unbond process is
- complete
+ You should NOT shutdown your node until the unbond process is complete
)}
diff --git a/nym-wallet/src/pages/bonding/node-settings/apy-playground/index.tsx b/nym-wallet/src/pages/bonding/node-settings/apy-playground/index.tsx
index 65edb35bc5..c288dc96e7 100644
--- a/nym-wallet/src/pages/bonding/node-settings/apy-playground/index.tsx
+++ b/nym-wallet/src/pages/bonding/node-settings/apy-playground/index.tsx
@@ -4,10 +4,10 @@ import { ResultsTable } from 'src/components/RewardsPlayground/ResultsTable';
import { getDelegationSummary } from 'src/requests';
import { NodeDetails } from 'src/components/RewardsPlayground/NodeDetail';
import { CalculateArgs, Inputs } from 'src/components/RewardsPlayground/Inputs';
-import { TBondedMixnode } from 'src/context';
import { useSnackbar } from 'notistack';
import { LoadingModal } from 'src/components/Modals/LoadingModal';
import { Console } from 'src/utils/console';
+import { TBondedMixnode } from 'src/requests/mixnodeDetails';
import { computeEstimate, computeStakeSaturation, handleCalculatePeriodRewards } from './utils';
export type DefaultInputValues = {
diff --git a/nym-wallet/src/pages/bonding/node-settings/node-settings.constant.tsx b/nym-wallet/src/pages/bonding/node-settings/node-settings.constant.tsx
index 74e8d7cf5b..b308c03716 100644
--- a/nym-wallet/src/pages/bonding/node-settings/node-settings.constant.tsx
+++ b/nym-wallet/src/pages/bonding/node-settings/node-settings.constant.tsx
@@ -1,7 +1,13 @@
-export const makeNavItems = (isMixnode: boolean) => {
- const navItems: NavItems[] = ['General', 'Unbond'];
+import { TBondedNode } from 'src/context';
+import { isNymNode } from 'src/types';
- if (isMixnode) navItems.splice(1, 0, 'Test my node', 'Playground');
+export const makeNavItems = (bondedNode: TBondedNode) => {
+ const navItems: NavItems[] = ['Unbond'];
+
+ if (isNymNode(bondedNode)) {
+ // add these items to the beginning of the array "General", "Test my node", "Playground"
+ navItems.unshift('General', 'Test my node', 'Playground');
+ }
return navItems;
};
diff --git a/nym-wallet/src/pages/bonding/node-settings/node-test/index.tsx b/nym-wallet/src/pages/bonding/node-settings/node-test/index.tsx
index ba9bf522f3..2e1dc533f8 100644
--- a/nym-wallet/src/pages/bonding/node-settings/node-test/index.tsx
+++ b/nym-wallet/src/pages/bonding/node-settings/node-test/index.tsx
@@ -10,6 +10,7 @@ import { ErrorModal } from 'src/components/Modals/ErrorModal';
import { PrintResults } from 'src/components/TestNode/PrintResults';
import { MAINNET_VALIDATOR_URL, QA_VALIDATOR_URL } from 'src/constants';
import { TestStatus } from 'src/components/TestNode/types';
+import { isMixnode } from 'src/types';
export const NodeTestPage = () => {
const [nodeTestClient, setNodeTestClient] = useState();
@@ -37,7 +38,7 @@ export const NodeTestPage = () => {
};
const handleTestNode = async () => {
- if (nodeTestClient && bondedNode) {
+ if (nodeTestClient && bondedNode && isMixnode(bondedNode)) {
setResults(undefined);
setTestDate(format(new Date(), 'dd/MM/yyyy HH:mm'));
setIsLoading(true);
@@ -87,7 +88,7 @@ export const NodeTestPage = () => {
{isLoading && }
{error && setError(undefined)} />}
- {printResults && results && (
+ {printResults && results && bondedNode && isMixnode(bondedNode) && (
Promise;
onError: (e: string) => void;
@@ -15,6 +15,9 @@ export const NodeUnbondPage = ({ bondedNode, onConfirm, onError }: Props) => {
const [confirmField, setConfirmField] = useState('');
const [isConfirmed, setIsConfirmed] = useState(false);
// TODO: Check what happens with a gateway
+
+ const shouldDisplayWarning = isMixnode(bondedNode) || isNymNode(bondedNode);
+
return (
@@ -24,7 +27,7 @@ export const NodeUnbondPage = ({ bondedNode, onConfirm, onError }: Props) => {
Unbond
- {isMixnode(bondedNode) && (
+ {shouldDisplayWarning && (
theme.palette.nym.text.muted }}>
Remember you should only unbond if you want to remove your node from the network for good.
@@ -35,7 +38,7 @@ export const NodeUnbondPage = ({ bondedNode, onConfirm, onError }: Props) => {
- {isMixnode(bondedNode) && (
+ {shouldDisplayWarning && (
)}
@@ -68,7 +71,7 @@ export const NodeUnbondPage = ({ bondedNode, onConfirm, onError }: Props) => {
- {isConfirmed && (
+ {isConfirmed && !isNymNode(bondedNode) && (
{
diff --git a/nym-wallet/src/pages/bonding/node-settings/settings-pages/general-settings/GeneralGatewaySettings.tsx b/nym-wallet/src/pages/bonding/node-settings/settings-pages/general-settings/GeneralGatewaySettings.tsx
index 892c1e245c..7f8bdb6d08 100644
--- a/nym-wallet/src/pages/bonding/node-settings/settings-pages/general-settings/GeneralGatewaySettings.tsx
+++ b/nym-wallet/src/pages/bonding/node-settings/settings-pages/general-settings/GeneralGatewaySettings.tsx
@@ -10,16 +10,17 @@ import {
updateGatewayConfig,
vestingUpdateGatewayConfig,
} from 'src/requests';
-import { TBondedGateway, useBondingContext } from 'src/context/bonding';
+import { useBondingContext } from 'src/context/bonding';
import { SimpleModal } from 'src/components/Modals/SimpleModal';
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 { updateGatewayValidationSchema } from 'src/components/Bonding/forms/gatewayValidationSchema';
+import { updateGatewayValidationSchema } from 'src/components/Bonding/forms/legacyForms/gatewayValidationSchema';
import { BalanceWarning } from 'src/components/FeeWarning';
import { AppContext } from 'src/context';
+import { TBondedGateway } from 'src/requests/gatewayDetails';
export const GeneralGatewaySettings = ({ bondedNode }: { bondedNode: TBondedGateway }) => {
const [openConfirmationModal, setOpenConfirmationModal] = useState(false);
@@ -56,7 +57,6 @@ export const GeneralGatewaySettings = ({ bondedNode }: { bondedNode: TBondedGate
location,
version: clean(version) as string,
clients_port: httpApiPort,
- verloc_port: bondedNode.verlocPort,
};
if (bondedNode.proxy) {
@@ -206,7 +206,6 @@ export const GeneralGatewaySettings = ({ bondedNode }: { bondedNode: TBondedGate
clients_port: data.httpApiPort,
location: bondedNode.location!,
version: data.version,
- verloc_port: bondedNode.verlocPort,
}),
)}
sx={{ m: 3 }}
diff --git a/nym-wallet/src/pages/bonding/node-settings/settings-pages/general-settings/GeneralMixnodeSettings.tsx b/nym-wallet/src/pages/bonding/node-settings/settings-pages/general-settings/GeneralMixnodeSettings.tsx
index 509c605174..08304622c7 100644
--- a/nym-wallet/src/pages/bonding/node-settings/settings-pages/general-settings/GeneralMixnodeSettings.tsx
+++ b/nym-wallet/src/pages/bonding/node-settings/settings-pages/general-settings/GeneralMixnodeSettings.tsx
@@ -6,9 +6,8 @@ import { Box, Button, Divider, Grid, Stack, TextField, Typography } from '@mui/m
import { useTheme } from '@mui/material/styles';
import { isMixnode } from 'src/types';
import { simulateUpdateMixnodeConfig, simulateVestingUpdateMixnodeConfig, updateMixnodeConfig } from 'src/requests';
-import { TBondedGateway, TBondedMixnode } from 'src/context/bonding';
import { SimpleModal } from 'src/components/Modals/SimpleModal';
-import { bondedInfoParametersValidationSchema } from 'src/components/Bonding/forms/mixnodeValidationSchema';
+import { bondedInfoParametersValidationSchema } from 'src/components/Bonding/forms/legacyForms/mixnodeValidationSchema';
import { Console } from 'src/utils/console';
import { Alert } from 'src/components/Alert';
import { vestingUpdateMixnodeConfig } from 'src/requests/vesting';
@@ -17,8 +16,9 @@ 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 { TBondedMixnode } from 'src/requests/mixnodeDetails';
-export const GeneralMixnodeSettings = ({ bondedNode }: { bondedNode: TBondedMixnode | TBondedGateway }) => {
+export const GeneralMixnodeSettings = ({ bondedNode }: { bondedNode: TBondedMixnode }) => {
const [openConfirmationModal, setOpenConfirmationModal] = useState(false);
const { getFee, fee, resetFeeState } = useGetFee();
const { userBalance } = useContext(AppContext);
diff --git a/nym-wallet/src/pages/bonding/node-settings/settings-pages/general-settings/GeneralNymNodeSettings.tsx b/nym-wallet/src/pages/bonding/node-settings/settings-pages/general-settings/GeneralNymNodeSettings.tsx
new file mode 100644
index 0000000000..76721d9937
--- /dev/null
+++ b/nym-wallet/src/pages/bonding/node-settings/settings-pages/general-settings/GeneralNymNodeSettings.tsx
@@ -0,0 +1,182 @@
+import React, { useContext, useState } from 'react';
+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 { TBondedNymNode } from 'src/requests/nymNodeDetails';
+
+export const GeneralNymNodeSettings = ({ bondedNode }: { bondedNode: TBondedNymNode }) => {
+ const [openConfirmationModal, setOpenConfirmationModal] = useState(false);
+ const { fee, resetFeeState } = useGetFee();
+ const { userBalance } = useContext(AppContext);
+
+ const theme = useTheme();
+
+ const {
+ register,
+ handleSubmit,
+ formState: { errors, isSubmitting, isDirty, isValid },
+ } = useForm({
+ resolver: yupResolver(bondedInfoParametersValidationSchema),
+ mode: 'onChange',
+ defaultValues: {
+ host: bondedNode.host,
+ customHttpPort: bondedNode.customHttpPort,
+ },
+ });
+
+ const onSubmit = async (data: { host?: string; customHttpPort?: number | null }) => {
+ resetFeeState();
+ const { host, customHttpPort } = data;
+ if (host && customHttpPort) {
+ const NymNodeConfigParams = {
+ host,
+ custom_http_port: customHttpPort,
+ };
+ try {
+ await updateNymNodeConfig(NymNodeConfigParams);
+ setOpenConfirmationModal(true);
+ } catch (error) {
+ Console.error(error);
+ }
+ }
+ };
+
+ return (
+
+ {fee && (
+ onSubmit(d))}
+ onPrev={resetFeeState}
+ onClose={resetFeeState}
+ >
+ {fee.amount?.amount && userBalance?.balance?.amount.amount && (
+
+
+
+ )}
+
+ )}
+ {isSubmitting && }
+
+
+ Changing these values will ONLY change the data about your node on the blockchain.
+
+ Remember to change your node’s config file with the same values too.
+
+ }
+ bgColor={`${theme.palette.nym.nymWallet.text.blue}0D !important`}
+ dismissable
+ />
+
+
+
+
+ Port
+
+
+
+
+
+
+
+
+
+
+
+
+ Host
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {
+ await setOpenConfirmationModal(false);
+ }}
+ buttonFullWidth
+ sx={{
+ width: '450px',
+ display: 'flex',
+ flexDirection: 'column',
+ alignItems: 'center',
+ justifyContent: 'center',
+ }}
+ headerStyles={{
+ width: '100%',
+ mb: 1,
+ textAlign: 'center',
+ color: theme.palette.nym.nymWallet.text.blue,
+ fontSize: 16,
+ }}
+ subHeaderStyles={{
+ width: '100%',
+ mb: 1,
+ textAlign: 'center',
+ color: 'main',
+ fontSize: 14,
+ }}
+ />
+
+ );
+};
diff --git a/nym-wallet/src/pages/bonding/node-settings/settings-pages/general-settings/ParametersSettings.tsx b/nym-wallet/src/pages/bonding/node-settings/settings-pages/general-settings/ParametersSettings.tsx
index 4f2032ac30..6f8ed79ec9 100644
--- a/nym-wallet/src/pages/bonding/node-settings/settings-pages/general-settings/ParametersSettings.tsx
+++ b/nym-wallet/src/pages/bonding/node-settings/settings-pages/general-settings/ParametersSettings.tsx
@@ -14,7 +14,7 @@ import {
Typography,
} from '@mui/material';
import { useTheme } from '@mui/material/styles';
-import { CurrencyDenom, MixNodeCostParams } from '@nymproject/types';
+import { CurrencyDenom, NodeCostParams } from '@nymproject/types';
import { CurrencyFormField } from '@nymproject/react/currency/CurrencyFormField';
import { isMixnode } from 'src/types';
import {
@@ -22,11 +22,9 @@ import {
simulateUpdateMixnodeCostParams,
simulateVestingUpdateMixnodeCostParams,
updateMixnodeCostParams,
- vestingUpdateMixnodeCostParams,
} from 'src/requests';
-import { TBondedMixnode } from 'src/context/bonding';
import { SimpleModal } from 'src/components/Modals/SimpleModal';
-import { bondedNodeParametersValidationSchema } from 'src/components/Bonding/forms/mixnodeValidationSchema';
+import { bondedNodeParametersValidationSchema } from 'src/components/Bonding/forms/legacyForms/mixnodeValidationSchema';
import { Console } from 'src/utils/console';
import { getIntervalAsDate } from 'src/utils';
import { Alert } from 'src/components/Alert';
@@ -36,6 +34,7 @@ import { useGetFee } from 'src/hooks/useGetFee';
import { ConfirmTx } from 'src/components/ConfirmTX';
import { LoadingModal } from 'src/components/Modals/LoadingModal';
import { InfoOutlined } from '@mui/icons-material';
+import { TBondedMixnode } from 'src/requests/mixnodeDetails';
const operatorCostHint = `This is your (operator) rewards including the PM and cost. Rewards are automatically compounded every epoch.You can redeem your rewards at any time.
`;
@@ -45,7 +44,7 @@ const profitMarginHint =
export const ParametersSettings = ({ bondedNode }: { bondedNode: TBondedMixnode }): JSX.Element => {
const [openConfirmationModal, setOpenConfirmationModal] = useState(false);
const [intervalTime, setIntervalTime] = useState();
- const [pendingUpdates, setPendingUpdates] = useState();
+ const [pendingUpdates, setPendingUpdates] = useState();
const { clientDetails } = useContext(AppContext);
const theme = useTheme();
@@ -115,11 +114,8 @@ export const ParametersSettings = ({ bondedNode }: { bondedNode: TBondedMixnode
},
};
try {
- if (bondedNode.proxy) {
- await vestingUpdateMixnodeCostParams(mixNodeCostParams);
- } else {
- await updateMixnodeCostParams(mixNodeCostParams);
- }
+ await updateMixnodeCostParams(mixNodeCostParams);
+
await getPendingEvents();
reset();
setOpenConfirmationModal(true);
diff --git a/nym-wallet/src/pages/bonding/node-settings/settings-pages/general-settings/index.tsx b/nym-wallet/src/pages/bonding/node-settings/settings-pages/general-settings/index.tsx
index b49958ae42..7c1f4568b4 100644
--- a/nym-wallet/src/pages/bonding/node-settings/settings-pages/general-settings/index.tsx
+++ b/nym-wallet/src/pages/bonding/node-settings/settings-pages/general-settings/index.tsx
@@ -1,12 +1,13 @@
import React, { useState } from 'react';
import { Box, Button, Divider, Grid } from '@mui/material';
-import { isGateway, isMixnode } from 'src/types';
-import { TBondedMixnode, TBondedGateway } from 'src/context/bonding';
+import { isGateway, isMixnode, isNymNode } from 'src/types';
+import { TBondedNode } from 'src/context/bonding';
import { GeneralMixnodeSettings } from './GeneralMixnodeSettings';
import { ParametersSettings } from './ParametersSettings';
import { GeneralGatewaySettings } from './GeneralGatewaySettings';
+import { GeneralNymNodeSettings } from './GeneralNymNodeSettings';
-const makeGeneralNav = (bondedNode: TBondedMixnode | TBondedGateway) => {
+const makeGeneralNav = (bondedNode: TBondedNode) => {
const navItems = ['Info'];
if (isMixnode(bondedNode)) {
navItems.push('Parameters');
@@ -15,7 +16,7 @@ const makeGeneralNav = (bondedNode: TBondedMixnode | TBondedGateway) => {
return navItems;
};
-export const NodeGeneralSettings = ({ bondedNode }: { bondedNode: TBondedMixnode | TBondedGateway }) => {
+export const NodeGeneralSettings = ({ bondedNode }: { bondedNode: TBondedNode }) => {
const [navSelection, setNavSelection] = useState(0);
const getSettings = () => {
@@ -23,10 +24,12 @@ export const NodeGeneralSettings = ({ bondedNode }: { bondedNode: TBondedMixnode
case 0: {
if (isMixnode(bondedNode)) return ;
if (isGateway(bondedNode)) return ;
+ if (isNymNode(bondedNode)) return ;
break;
}
case 1: {
if (isMixnode(bondedNode)) return ;
+ if (isNymNode(bondedNode)) return null;
break;
}
default:
diff --git a/nym-wallet/src/pages/bonding/types.ts b/nym-wallet/src/pages/bonding/types.ts
index 0e2b4a6c8d..d2c8d3ae9f 100644
--- a/nym-wallet/src/pages/bonding/types.ts
+++ b/nym-wallet/src/pages/bonding/types.ts
@@ -1,4 +1,4 @@
-import { DecCoin, MixNodeCostParams, TNodeType, TransactionExecuteResult } from '@nymproject/types';
+import { DecCoin, NodeCostParams, TNodeType, TransactionExecuteResult } from '@nymproject/types';
import { TPoolOption } from 'src/components';
export type FormStep = 1 | 2 | 3 | 4;
@@ -61,5 +61,5 @@ export interface BondState {
export interface ChangeMixCostParams {
mix_id: number;
- new_costs: MixNodeCostParams;
+ new_costs: NodeCostParams;
}
diff --git a/nym-wallet/src/pages/node-settings/system-variables.tsx b/nym-wallet/src/pages/node-settings/system-variables.tsx
index 761d98444c..13fb9a60c6 100644
--- a/nym-wallet/src/pages/node-settings/system-variables.tsx
+++ b/nym-wallet/src/pages/node-settings/system-variables.tsx
@@ -7,8 +7,7 @@ import { yupResolver } from '@hookform/resolvers/yup';
import { InclusionProbabilityResponse, SelectionChance } from '@nymproject/types';
import { validationSchema } from './validationSchema';
import { InfoTooltip } from '../../components';
-import { useCheckOwnership } from '../../hooks/useCheckOwnership';
-import { updateMixnodeCostParams, vestingUpdateMixnodeCostParams } from '../../requests';
+import { updateMixnodeCostParams } from '../../requests';
import { AppContext } from '../../context';
import { Console } from '../../utils/console';
import { attachDefaultOperatingCost, toPercentFloatString } from '../../utils';
@@ -74,7 +73,6 @@ export const SystemVariables = ({
}) => {
const [nodeUpdateResponse, setNodeUpdateResponse] = useState<'success' | 'failed'>();
const { mixnodeDetails } = useContext(AppContext);
- const { ownership } = useCheckOwnership();
const {
register,
@@ -106,12 +104,6 @@ export const SystemVariables = ({
await updateMixnodeCostParams(defaultCostParams);
};
- const vestingUpdateMixnodeProfitMargin = async (profitMarginPercent: string) => {
- // TODO: this will have to be updated with allowing users to provide their operating cost in the form
- const defaultCostParams = await attachDefaultOperatingCost(toPercentFloatString(profitMarginPercent));
- await vestingUpdateMixnodeCostParams(defaultCostParams);
- };
-
if (!mixnodeDetails) return null;
return (
@@ -175,12 +167,7 @@ export const SystemVariables = ({