From 5fcce2de48b9551fd6f087dd90e6594d7424f9ce Mon Sep 17 00:00:00 2001 From: pierre Date: Mon, 11 Jul 2022 22:02:32 +0200 Subject: [PATCH] fix(wallet-bonding): bonding context mock --- nym-wallet/src/context/bonding.tsx | 238 +++++++++++++++--- nym-wallet/src/context/mocks/bonding.tsx | 69 ++++- .../src/pages/bonding/bonding/BondingCard.tsx | 60 ++--- .../pages/bonding/bonding/SummaryModal.tsx | 16 +- .../src/pages/bonding/gateway/GatewayCard.tsx | 2 +- .../pages/bonding/gateway/unbond/Unbond.tsx | 133 ---------- .../src/pages/bonding/mixnode/MixnodeCard.tsx | 2 +- .../bonding/mixnode/bond-more/BondMore.tsx | 35 ++- .../mixnode/bond-more/SummaryModal.tsx | 83 ++++-- .../mixnode/compound/CompoundRewards.tsx | 36 ++- .../bonding/mixnode/compound/SummaryModal.tsx | 4 +- .../mixnode/node-settings/NodeSettings.tsx | 75 ++++-- .../mixnode/node-settings/SummaryModal.tsx | 4 +- .../bonding/mixnode/redeem/RedeemRewards.tsx | 36 ++- .../bonding/mixnode/redeem/SummaryModal.tsx | 4 +- .../bonding/mixnode/unbond/SummaryModal.tsx | 49 ---- .../src/pages/bonding/mixnode/unbond/index.ts | 3 - .../{gateway => }/unbond/SummaryModal.tsx | 2 +- .../bonding/{mixnode => }/unbond/Unbond.tsx | 77 +++--- .../bonding/{gateway => }/unbond/index.ts | 0 20 files changed, 521 insertions(+), 407 deletions(-) delete mode 100644 nym-wallet/src/pages/bonding/gateway/unbond/Unbond.tsx delete mode 100644 nym-wallet/src/pages/bonding/mixnode/unbond/SummaryModal.tsx delete mode 100644 nym-wallet/src/pages/bonding/mixnode/unbond/index.ts rename nym-wallet/src/pages/bonding/{gateway => }/unbond/SummaryModal.tsx (95%) rename nym-wallet/src/pages/bonding/{mixnode => }/unbond/Unbond.tsx (60%) rename nym-wallet/src/pages/bonding/{gateway => }/unbond/index.ts (100%) diff --git a/nym-wallet/src/context/bonding.tsx b/nym-wallet/src/context/bonding.tsx index ead3fd4099..0c888a6d98 100644 --- a/nym-wallet/src/context/bonding.tsx +++ b/nym-wallet/src/context/bonding.tsx @@ -1,4 +1,4 @@ -import { MajorCurrencyAmount, MixnodeStatus, TransactionExecuteResult } from '@nymproject/types'; +import { FeeDetails, MajorCurrencyAmount, MixnodeStatus, TransactionExecuteResult } from '@nymproject/types'; import React, { createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react'; import type { Network } from 'src/types'; import { TBondGatewayArgs, TBondMixNodeArgs } from 'src/types'; @@ -7,9 +7,28 @@ import { bondMixNode as bondMixNodeRequest, claimOperatorRewards, compoundOperatorRewards, + simulateBondGateway, + simulateBondMixnode, + simulateUnbondGateway, + simulateUnbondMixnode, + simulateVestingBondGateway, + simulateVestingBondMixnode, + simulateVestingUnbondGateway, + simulateVestingUnbondMixnode, + simulateUpdateMixnode, + simulateVestingUpdateMixnode, unbondGateway as unbondGatewayRequest, - unbondMixNode as unbondMixNodeRequest, + unbondMixNode as unbondMixnodeRequest, + vestingBondGateway, + vestingBondMixNode, + vestingUnbondGateway, + vestingUnbondMixnode, + updateMixnode as updateMixnodeRequest, + vestingUpdateMixnode as updateMixnodeVestingRequest, } from '../requests'; +import { useGetFee } from '../hooks/useGetFee'; +import { useCheckOwnership } from '../hooks/useCheckOwnership'; +import { AppContext } from './main'; const bounded: BondedMixnode = { bond: { denom: 'NYM', amount: '1234' }, @@ -53,22 +72,51 @@ export interface BondedGateway { location?: string; // TODO not yet available, only available in Network Explorer API } +export type TokenPool = 'locked' | 'balance'; + +export type FeeOperation = + | 'bondMixnode' + | 'bondMixnodeWithVesting' + | 'bondGateway' + | 'bondGatewayWithVesting' + | 'unbondMixnode' + | 'unbondGateway' + | 'updateMixnode' + | 'bondMore' + | 'compoundRewards' + | 'redeemRewards'; + export type TBondingContext = { - isLoading: boolean; + loading: boolean; error?: string; bondedMixnode?: BondedMixnode | null; bondedGateway?: BondedGateway | null; refresh: () => Promise; - bondMixnode: (data: TBondMixNodeArgs) => Promise; - bondGateway: (data: TBondGatewayArgs) => Promise; - unbondMixnode: () => Promise; - unbondGateway: () => Promise; - redeemRewards: () => Promise; - compoundRewards: () => Promise; + bondMixnode: ( + data: Omit, + tokenPool: TokenPool, + ) => Promise; + bondGateway: ( + data: Omit, + tokenPool: TokenPool, + ) => Promise; + bondMore: (signature: string, additionalBond: MajorCurrencyAmount) => Promise; + unbondMixnode: () => Promise; + unbondGateway: () => Promise; + redeemRewards: () => Promise; + compoundRewards: () => Promise; + updateMixnode: (pm: number) => Promise; + fee?: FeeDetails; + getFee: (feeOperation: FeeOperation, args: T) => Promise; + feeDetails?: FeeDetails; + feeLoading: boolean; + feeError?: string; + resetFeeState: () => void; }; export const BondingContext = createContext({ - isLoading: true, + loading: true, + feeLoading: false, refresh: async () => undefined, bondMixnode: async () => { throw new Error('Not implemented'); @@ -88,6 +136,16 @@ export const BondingContext = createContext({ compoundRewards: async () => { throw new Error('Not implemented'); }, + getFee(): Promise { + throw new Error('Not implemented'); + }, + resetFeeState(): void {}, + updateMixnode: async () => { + throw new Error('Not implemented'); + }, + bondMore(): Promise { + throw new Error('Not implemented'); + }, }); export const BondingContextProvider = ({ @@ -97,13 +155,24 @@ export const BondingContextProvider = ({ network?: Network; children?: React.ReactNode; }): JSX.Element => { - const [isLoading, setIsLoading] = useState(true); + const [loading, setLoading] = useState(true); const [error, setError] = useState(); const [bondedMixnode, setBondedMixnode] = useState(null); const [bondedGateway, setBondedGateway] = useState(null); + const { fee, resetFeeState, feeError, isFeeLoading } = useGetFee(); + const { ownership, checkOwnership } = useCheckOwnership(); + const { userBalance } = useContext(AppContext); + + const isVesting = Boolean(ownership.vestingPledge); + + useEffect(() => { + if (feeError) { + setError(`An error occurred while retrieving fee: ${feeError}`); + } + }, [feeError]); const resetState = () => { - setIsLoading(true); + setLoading(true); setError(undefined); setBondedGateway(null); setBondedMixnode(null); @@ -122,7 +191,7 @@ export const BondingContextProvider = ({ if (bounded && !('stake' in bounded)) { setBondedGateway(bounded); } - setIsLoading(false); + setLoading(false); }, [network]); useEffect(() => { @@ -130,75 +199,159 @@ export const BondingContextProvider = ({ refresh(); }, [network]); - const bondMixnode = async (data: TBondMixNodeArgs) => { - // TODO some logic - let tx; + const bondMixnode = async (data: Omit, tokenPool: TokenPool) => { + let tx: TransactionExecuteResult | undefined; + const payload = { + ...data, + fee: fee?.fee, + }; + setLoading(true); try { - tx = await bondMixNodeRequest(data); + if (tokenPool === 'balance') { + tx = await bondMixNodeRequest(payload); + await userBalance.fetchBalance(); + } + if (tokenPool === 'locked') { + tx = await vestingBondMixNode(payload); + await userBalance.fetchTokenAllocation(); + } + return tx; } catch (e: any) { - throw new Error(e); + setError(`an error occurred: ${e}`); + } finally { + setLoading(false); } - return tx; + return undefined; }; - const bondGateway = async (data: TBondGatewayArgs) => { - // TODO some logic - let tx; + const bondGateway = async (data: Omit, tokenPool: TokenPool) => { + let tx: TransactionExecuteResult | undefined; + const payload = { + ...data, + fee: fee?.fee, + }; + setLoading(true); try { - tx = await bondGatewayRequest(data); + if (tokenPool === 'balance') { + tx = await bondGatewayRequest(payload); + await userBalance.fetchBalance(); + } + if (tokenPool === 'locked') { + tx = await vestingBondGateway(payload); + await userBalance.fetchTokenAllocation(); + } + return tx; } catch (e: any) { - throw new Error(e); + setError(`an error occurred: ${e}`); + } finally { + setLoading(false); } - return tx; + return undefined; }; const unbondMixnode = async () => { - // TODO some logic let tx; + setLoading(true); try { - tx = await unbondMixNodeRequest(); + if (isVesting) tx = await vestingUnbondMixnode(fee?.fee); + if (!isVesting) tx = await unbondMixnodeRequest(fee?.fee); } catch (e: any) { - throw new Error(e); + setError(`an error occurred: ${e}`); + } finally { + await checkOwnership(); + setLoading(false); } return tx; }; const unbondGateway = async () => { - // TODO some logic let tx; + setLoading(true); try { - tx = await unbondGatewayRequest(); + if (isVesting) tx = await vestingUnbondGateway(fee?.fee); + if (!isVesting) tx = await unbondGatewayRequest(fee?.fee); } catch (e: any) { - throw new Error(e); + setError(`an error occurred: ${e}`); + } finally { + await checkOwnership(); + setLoading(false); + } + return tx; + }; + + const updateMixnode = async (pm: number) => { + let tx; + setLoading(true); + try { + if (isVesting) tx = await updateMixnodeRequest(pm); + if (!isVesting) tx = await updateMixnodeVestingRequest(pm); + } catch (e: any) { + setError(`an error occurred: ${e}`); + } finally { + setLoading(false); } return tx; }; const redeemRewards = async () => { - // TODO some logic let tx; + setLoading(true); try { - tx = await claimOperatorRewards(); + tx = await claimOperatorRewards(); // TODO use fee, need a new request } catch (e: any) { - throw new Error(e); + setError(`an error occurred: ${e}`); + } finally { + setLoading(false); } return tx; }; const compoundRewards = async () => { - // TODO some logic let tx; + setLoading(true); try { - tx = await compoundOperatorRewards(); + tx = await compoundOperatorRewards(); // TODO use fee, need a new request } catch (e: any) { - throw new Error(e); + setError(`an error occurred: ${e}`); + } finally { + setLoading(false); } return tx; }; + const bondMore = async (_signature: string, _additionalBond: MajorCurrencyAmount) => + // TODO to implement + undefined; + + const feeOps = useMemo( + () => ({ + bondMixnode: simulateBondMixnode, + bondMixnodeWithVesting: simulateVestingBondMixnode, + bondGateway: simulateBondGateway, + bondGatewayWithVesting: simulateVestingBondGateway, + unbondMixnode: isVesting ? simulateVestingUnbondMixnode : simulateUnbondMixnode, + unbondGateway: isVesting ? simulateVestingUnbondGateway : simulateUnbondGateway, + updateMixnode: isVesting ? simulateVestingUpdateMixnode : simulateUpdateMixnode, + bondMore: () => undefined as unknown as Promise, // TODO fee request to implement + compoundRewards: () => undefined as unknown as Promise, // TODO fee request to implement + redeemRewards: () => undefined as unknown as Promise, // TODO fee request to implement + }), + [isVesting], + ); + + const getFee = async (feeOperation: FeeOperation, args: any) => { + let details; + try { + details = feeOps[feeOperation](args); + } catch (e: any) { + setError(`An error occurred while retrieving fee: ${e}`); + } + return details; + }; + const memoizedValue = useMemo( () => ({ - isLoading, + loading, error, bondMixnode, bondedMixnode, @@ -206,11 +359,18 @@ export const BondingContextProvider = ({ bondGateway, unbondMixnode, unbondGateway, + updateMixnode, refresh, redeemRewards, compoundRewards, + feeLoading: isFeeLoading, + feeError, + getFee, + fee, + resetFeeState, + bondMore, }), - [isLoading, error, bondedMixnode, bondedGateway], + [loading, error, bondedMixnode, bondedGateway, isFeeLoading, feeError, fee, resetFeeState, isVesting], ); return {children}; diff --git a/nym-wallet/src/context/mocks/bonding.tsx b/nym-wallet/src/context/mocks/bonding.tsx index 1a87713c37..a25f33372d 100644 --- a/nym-wallet/src/context/mocks/bonding.tsx +++ b/nym-wallet/src/context/mocks/bonding.tsx @@ -1,7 +1,7 @@ -import { TransactionExecuteResult } from '@nymproject/types'; +import { FeeDetails, MajorCurrencyAmount, TransactionExecuteResult } from '@nymproject/types'; import React, { useCallback, useEffect, useMemo, useState } from 'react'; import type { Network } from 'src/types'; -import { BondedGateway, BondedMixnode, BondingContext } from '../bonding'; +import { BondedGateway, BondedMixnode, BondingContext, FeeOperation } from '../bonding'; import { mockSleep } from './utils'; const SLEEP_MS = 1000; @@ -37,6 +37,11 @@ const TxResultMock: TransactionExecuteResult = { fee: { amount: '1', denom: 'NYM' }, }; +const feeMock: FeeDetails = { + amount: { denom: 'NYM', amount: '1' }, + fee: { Auto: 1 }, +}; + export const MockBondingContextProvider = ({ network, children, @@ -44,7 +49,9 @@ export const MockBondingContextProvider = ({ network?: Network; children?: React.ReactNode; }): JSX.Element => { - const [isLoading, setIsLoading] = useState(true); + const [loading, setLoading] = useState(true); + const [feeLoading, setFeeLoading] = useState(false); + const [fee, setFee] = useState(); const [error, setError] = useState(); const [bondedData, setBondedData] = useState(null); const [bondedMixnode, setBondedMixnode] = useState(null); @@ -54,7 +61,7 @@ export const MockBondingContextProvider = ({ const triggerStateUpdate = () => setTrigger(new Date()); const resetState = () => { - setIsLoading(true); + setLoading(true); setError(undefined); setBondedGateway(null); setBondedMixnode(null); @@ -74,7 +81,7 @@ export const MockBondingContextProvider = ({ if (bounded && !('stake' in bounded)) { setBondedGateway(bounded); } - setIsLoading(false); + setLoading(false); }, [network]); useEffect(() => { @@ -83,44 +90,82 @@ export const MockBondingContextProvider = ({ }, [network, bondedData]); const bondMixnode = async (): Promise => { + setLoading(true); await mockSleep(SLEEP_MS); setBondedData(bondedMixnodeMock); + setLoading(false); return TxResultMock; }; const bondGateway = async (): Promise => { + setLoading(true); await mockSleep(SLEEP_MS); setBondedData(bondedGatewayMock); + setLoading(false); return TxResultMock; }; const unbondMixnode = async (): Promise => { + setLoading(true); await mockSleep(SLEEP_MS); setBondedData(null); + setLoading(false); return TxResultMock; }; const unbondGateway = async (): Promise => { + setLoading(true); await mockSleep(SLEEP_MS); setBondedData(null); + setLoading(false); return TxResultMock; }; - const redeemRewards = async (): Promise => { + const redeemRewards = async (): Promise => { + setLoading(true); await mockSleep(SLEEP_MS); triggerStateUpdate(); + setLoading(false); return [TxResultMock]; }; - const compoundRewards = async (): Promise => { + const compoundRewards = async (): Promise => { + setLoading(true); await mockSleep(SLEEP_MS); triggerStateUpdate(); + setLoading(false); return [TxResultMock]; }; + const updateMixnode = async (): Promise => { + setLoading(true); + await mockSleep(SLEEP_MS); + triggerStateUpdate(); + setLoading(false); + return TxResultMock; + }; + + const bondMore = async (_signature: string, _additionalBond: MajorCurrencyAmount) => { + setLoading(true); + await mockSleep(SLEEP_MS); + triggerStateUpdate(); + setLoading(false); + return TxResultMock; + }; + + const getFee = async (_feeOperation: FeeOperation, _args: any) => { + setFeeLoading(true); + await mockSleep(SLEEP_MS); + setFeeLoading(false); + setFee(feeMock); + return feeMock; + }; + + const resetFeeState = () => {}; + const memoizedValue = useMemo( () => ({ - isLoading, + loading, error, bondMixnode, bondGateway, @@ -129,8 +174,14 @@ export const MockBondingContextProvider = ({ refresh, redeemRewards, compoundRewards, + fee, + feeLoading, + getFee, + resetFeeState, + updateMixnode, + bondMore, }), - [isLoading, error, bondedMixnode, bondedGateway, trigger], + [loading, error, bondedMixnode, bondedGateway, trigger, fee], ); return {children}; diff --git a/nym-wallet/src/pages/bonding/bonding/BondingCard.tsx b/nym-wallet/src/pages/bonding/bonding/BondingCard.tsx index a72b992dca..409f29fb67 100644 --- a/nym-wallet/src/pages/bonding/bonding/BondingCard.tsx +++ b/nym-wallet/src/pages/bonding/bonding/BondingCard.tsx @@ -17,15 +17,8 @@ import { NodeData, } from '../types'; import AmountModal from './AmountModal'; -import { AppContext, urls } from '../../../context'; +import { AppContext, urls, useBondingContext } from '../../../context'; import SummaryModal from './SummaryModal'; -import { - bondGateway as bondGatewayRequest, - bondMixNode as bondMixNodeRequest, - vestingBondGateway, - vestingBondMixNode, -} from '../../../requests'; -import { useGetFee } from '../../../hooks/useGetFee'; const initialState: BondState = { showModal: false, @@ -71,15 +64,20 @@ const BondingCard = () => { const [state, dispatch] = useReducer(reducer, initialState); const { formStep, showModal } = state; - const { userBalance, clientDetails, network } = useContext(AppContext); - const { fee } = useGetFee(); + const { clientDetails, network } = useContext(AppContext); + const { error, bondMixnode: bondMixnodeRequest, bondGateway: bondGatewayRequest } = useBondingContext(); useEffect(() => { dispatch({ type: 'reset' }); }, [clientDetails]); + useEffect(() => { + if (error) { + dispatch({ type: 'set_error', payload: error }); + } + }, [error]); + const bondMixnode = async () => { - let tx: TransactionExecuteResult | undefined; const { signature, identityKey, sphinxKey, host, version, mixPort, verlocPort, httpApiPort } = state.nodeData as NodeData; const { profitMargin, amount, tokenPool } = state.amountData as MixnodeAmount; @@ -96,30 +94,20 @@ const BondingCard = () => { http_api_port: httpApiPort, }, pledge: amount, - fee: fee?.fee, }; if (tokenPool !== 'locked' && tokenPool !== 'balance') { throw new Error(`token pool [${tokenPool}] not supported`); } - try { - if (tokenPool === 'balance') { - tx = await bondMixNodeRequest(payload); - await userBalance.fetchBalance(); - } - if (tokenPool === 'locked') { - tx = await vestingBondMixNode(payload); - await userBalance.fetchTokenAllocation(); - } + const tx = await bondMixnodeRequest(payload, tokenPool); + if (tx) { dispatch({ type: 'set_bond_status', payload: 'success' }); - return tx; - } catch (e: any) { - dispatch({ type: 'set_error', payload: e }); + } else { + dispatch({ type: 'set_bond_status', payload: 'error' }); } - return undefined; + return tx; }; const bondGateway = async () => { - let tx: TransactionExecuteResult | undefined; const { signature, identityKey, sphinxKey, host, version, location, mixPort, clientsPort } = state.nodeData as NodeData; const { amount, tokenPool } = state.amountData as GatewayAmount; @@ -135,21 +123,15 @@ const BondingCard = () => { clients_port: clientsPort, }, pledge: amount, - fee: fee?.fee, }; - try { - if (tokenPool === 'balance') { - tx = await bondGatewayRequest(payload); - await userBalance.fetchBalance(); - } - if (tokenPool === 'locked') { - tx = await vestingBondGateway(payload); - await userBalance.fetchTokenAllocation(); - } + if (tokenPool !== 'locked' && tokenPool !== 'balance') { + throw new Error(`token pool [${tokenPool}] not supported`); + } + const tx = await bondGatewayRequest(payload, tokenPool); + if (tx) { dispatch({ type: 'set_bond_status', payload: 'success' }); - return tx; - } catch (e: any) { - dispatch({ type: 'set_error', payload: e }); + } else { + dispatch({ type: 'set_bond_status', payload: 'error' }); } return tx; }; diff --git a/nym-wallet/src/pages/bonding/bonding/SummaryModal.tsx b/nym-wallet/src/pages/bonding/bonding/SummaryModal.tsx index 92de6abcf4..ea0b1c8499 100644 --- a/nym-wallet/src/pages/bonding/bonding/SummaryModal.tsx +++ b/nym-wallet/src/pages/bonding/bonding/SummaryModal.tsx @@ -1,14 +1,8 @@ import React, { useEffect } from 'react'; import { Divider, Stack, Typography } from '@mui/material'; -import { - simulateBondGateway, - simulateBondMixnode, - simulateVestingBondGateway, - simulateVestingBondMixnode, -} from '../../../requests'; import { GatewayAmount, GatewayData, MixnodeAmount, MixnodeData, NodeData } from '../types'; -import { useGetFee } from '../../../hooks/useGetFee'; import { SimpleModal } from '../../../components/Modals/SimpleModal'; +import { useBondingContext } from '../../../context'; export interface Props { open: boolean; @@ -21,7 +15,7 @@ export interface Props { } const SummaryModal = ({ open, onClose, onSubmit, node, amount, onCancel, onError }: Props) => { - const { fee, getFee, resetFeeState, feeError, isFeeLoading } = useGetFee(); + const { fee, getFee, resetFeeState, feeError, feeLoading } = useBondingContext(); useEffect(() => { if (feeError) onError(feeError); @@ -31,7 +25,7 @@ const SummaryModal = ({ open, onClose, onSubmit, node, amount, onCancel, onError const { signature, host, version, mixPort, identityKey, sphinxKey } = node; try { if (node.nodeType === 'mixnode') { - await getFee(amount.tokenPool === 'locked' ? simulateVestingBondMixnode : simulateBondMixnode, { + await getFee(amount.tokenPool === 'locked' ? 'bondMixnodeWithVesting' : 'bondMixnode', { ownerSignature: signature, mixnode: { identity_key: identityKey, @@ -46,7 +40,7 @@ const SummaryModal = ({ open, onClose, onSubmit, node, amount, onCancel, onError pledge: amount.amount, }); } else { - await getFee(amount.tokenPool === 'locked' ? simulateVestingBondGateway : simulateBondGateway, { + await getFee(amount.tokenPool === 'locked' ? 'bondGatewayWithVesting' : 'bondGateway', { ownerSignature: signature, gateway: { identity_key: identityKey, @@ -98,7 +92,7 @@ const SummaryModal = ({ open, onClose, onSubmit, node, amount, onCancel, onError Fee for this operation - {isFeeLoading ? ( + {feeLoading ? ( loading ) : ( {fee ? `${fee.amount?.amount} ${fee.amount?.denom}` : ''} diff --git a/nym-wallet/src/pages/bonding/gateway/GatewayCard.tsx b/nym-wallet/src/pages/bonding/gateway/GatewayCard.tsx index 383b9674c3..dc7fd3c8bf 100644 --- a/nym-wallet/src/pages/bonding/gateway/GatewayCard.tsx +++ b/nym-wallet/src/pages/bonding/gateway/GatewayCard.tsx @@ -4,7 +4,7 @@ import EditIcon from '@mui/icons-material/Edit'; import { BondedGateway } from '../../../context'; import { NodeTable, BondedNodeCard, Cell, Header, NodeMenu } from '../components'; import { GatewayFlow } from './types'; -import Unbond from './unbond'; +import Unbond from '../unbond'; const headers: Header[] = [ { diff --git a/nym-wallet/src/pages/bonding/gateway/unbond/Unbond.tsx b/nym-wallet/src/pages/bonding/gateway/unbond/Unbond.tsx deleted file mode 100644 index 4e7c36b2b1..0000000000 --- a/nym-wallet/src/pages/bonding/gateway/unbond/Unbond.tsx +++ /dev/null @@ -1,133 +0,0 @@ -import * as React from 'react'; -import { useContext, useEffect, useState } from 'react'; -import { MajorCurrencyAmount } from '@nymproject/types'; -import { Link } from '@nymproject/react/link/Link'; -import { Typography } from '@mui/material'; -import { ErrorOutline } from '@mui/icons-material'; -import { AppContext, BondedGateway, BondedMixnode, urls } from '../../../../context'; -import SummaryModal from './SummaryModal'; -import { ConfirmationModal } from '../../../../components'; -import { - simulateUnbondGateway, - simulateVestingUnbondGateway, - unbondGateway, - vestingUnbondGateway, -} from '../../../../requests'; -import { useCheckOwnership } from '../../../../hooks/useCheckOwnership'; -import { useGetFee } from '../../../../hooks/useGetFee'; -import { LoadingModal } from '../../../../components/Modals/LoadingModal'; - -interface Props { - node: BondedGateway; - show: boolean; - onClose: () => void; -} - -type UnbondStatus = 'success' | 'error'; - -const Unbond = ({ node, show, onClose }: Props) => { - const [isLoading, setIsLoading] = useState(false); - const [step, setStep] = useState<1 | 2>(1); - const [txHash, setTxHash] = useState(); - const [status, setStatus] = useState(); - const [error, setError] = useState(); - - const { fee, getFee, resetFeeState, isFeeLoading } = useGetFee(); - - const { network } = useContext(AppContext); - const { checkOwnership, ownership } = useCheckOwnership(); - - const isVesting = Boolean(ownership.vestingPledge); - - const unbond = async () => { - let tx; - setIsLoading(true); - try { - if (isVesting) tx = await vestingUnbondGateway(fee?.fee); - if (!isVesting) tx = await unbondGateway(fee?.fee); - setTxHash(tx?.transaction_hash); - setStatus('success'); - } catch (err: any) { - setStatus('error'); - setError(err as string); - } finally { - await checkOwnership(); - setIsLoading(false); - } - }; - - const fetchFee = async () => { - try { - if (isVesting) await getFee(simulateVestingUnbondGateway, {}); - if (!isVesting) await getFee(simulateUnbondGateway, {}); - } catch (e: any) { - setStatus('error'); - setError(e as string); - } - }; - - useEffect(() => { - fetchFee(); - }, [node, isVesting]); - - const submit = async () => { - if (status === 'error') { - // Fetch fee failed - return; - } - unbond(); - resetFeeState(); - setStep(2); - }; - - const reset = () => { - setStep(1); - onClose(); - }; - - if (isFeeLoading || isLoading) return ; - - return ( - <> - - {status === 'success' && ( - - This operation can take up to one hour to process - - View on blockchain - - - )} - {status === 'error' && ( - - Error: {error} - - - )} - - ); -}; - -export default Unbond; diff --git a/nym-wallet/src/pages/bonding/mixnode/MixnodeCard.tsx b/nym-wallet/src/pages/bonding/mixnode/MixnodeCard.tsx index 8e9bc3d8ff..1ec5a26f24 100644 --- a/nym-wallet/src/pages/bonding/mixnode/MixnodeCard.tsx +++ b/nym-wallet/src/pages/bonding/mixnode/MixnodeCard.tsx @@ -9,7 +9,7 @@ import NodeSettings from './node-settings'; import BondMore from './bond-more'; import { MixnodeFlow } from './types'; import RedeemRewards from './redeem'; -import Unbond from './unbond'; +import Unbond from '../unbond'; import CompoundRewards from './compound'; import { Bond as BondIcon, Unbond as UnbondIcon } from '../../../svg-icons'; diff --git a/nym-wallet/src/pages/bonding/mixnode/bond-more/BondMore.tsx b/nym-wallet/src/pages/bonding/mixnode/bond-more/BondMore.tsx index e96525051a..513a772f7b 100644 --- a/nym-wallet/src/pages/bonding/mixnode/bond-more/BondMore.tsx +++ b/nym-wallet/src/pages/bonding/mixnode/bond-more/BondMore.tsx @@ -1,9 +1,10 @@ import * as React from 'react'; -import { useContext, useEffect, useState } from 'react'; +import { useContext, useState } from 'react'; import { MajorCurrencyAmount, TransactionExecuteResult } from '@nymproject/types'; import { Link } from '@nymproject/react/link/Link'; import { Typography } from '@mui/material'; -import { AppContext, BondedMixnode, urls } from '../../../../context'; +import { ErrorOutline } from '@mui/icons-material'; +import { AppContext, BondedMixnode, urls, useBondingContext } from '../../../../context'; import SummaryModal from './SummaryModal'; import { ConfirmationModal } from '../../../../components'; import BondModal from './BondModal'; @@ -17,20 +18,18 @@ interface Props { const BondMore = ({ mixnode, show, onClose }: Props) => { const [addBond, setAddBond] = useState({ amount: '0', denom: 'NYM' }); const [signature, setSignature] = useState(); - const [fee, setFee] = useState({ amount: '0', denom: 'NYM' }); const [step, setStep] = useState<1 | 2 | 3>(1); const [tx, setTx] = useState(); const { network } = useContext(AppContext); - - useEffect(() => { - setFee({ amount: '42', denom: 'NYM' }); // TODO fetch real fee amount - }, [addBond]); + const { bondMore, error } = useBondingContext(); const submit = async () => { - // TODO send request to update bond - setStep(3); // on success - // setTx(requestResult) + const txResult = await bondMore(signature as string, addBond); + if (txResult) { + setStep(3); + } + setTx(txResult); }; const reset = () => { @@ -59,10 +58,9 @@ const BondMore = ({ mixnode, show, onClose }: Props) => { onCancel={() => setStep(1)} currentBond={mixnode.bond} addBond={addBond} - fee={fee as MajorCurrencyAmount} /> { View on blockchain + {error && ( + + Error: {error} + + + )} ); }; diff --git a/nym-wallet/src/pages/bonding/mixnode/bond-more/SummaryModal.tsx b/nym-wallet/src/pages/bonding/mixnode/bond-more/SummaryModal.tsx index ac8baddfbb..29b5b7cfa1 100644 --- a/nym-wallet/src/pages/bonding/mixnode/bond-more/SummaryModal.tsx +++ b/nym-wallet/src/pages/bonding/mixnode/bond-more/SummaryModal.tsx @@ -1,7 +1,11 @@ import * as React from 'react'; import { Divider, Stack, Typography } from '@mui/material'; import { MajorCurrencyAmount } from '@nymproject/types'; +import { useEffect } from 'react'; +import { ErrorOutline } from '@mui/icons-material'; import { SimpleModal } from '../../../../components/Modals/SimpleModal'; +import { useBondingContext } from '../../../../context'; +import { ConfirmationModal } from '../../../../components'; export interface Props { open: boolean; @@ -10,33 +14,60 @@ export interface Props { onCancel: () => void; currentBond: MajorCurrencyAmount; addBond: MajorCurrencyAmount; - fee: MajorCurrencyAmount; } -const SummaryModal = ({ open, onClose, onConfirm, onCancel, currentBond, addBond, fee }: Props) => ( - - - Current bond - {`${currentBond.amount} ${currentBond.denom}`} - - - - Additional bond - {`${addBond.amount} ${addBond.denom}`} - - - - Fee for this operation - {`${fee.amount} ${fee.denom}`} - - -); +const SummaryModal = ({ open, onClose, onConfirm, onCancel, currentBond, addBond }: Props) => { + const { getFee, fee, error } = useBondingContext(); + + const fetchFee = async () => { + await getFee('bondMore', {}); + }; + + useEffect(() => { + fetchFee(); + }, []); + + if (error) { + return ( + + Error: {error} + + + ); + } + + return ( + + + Current bond + {`${currentBond.amount} ${currentBond.denom}`} + + + + Additional bond + {`${addBond.amount} ${addBond.denom}`} + + + + Fee for this operation + {fee ? `${fee.amount?.amount} ${fee.amount?.denom}` : ''} + + + ); +}; export default SummaryModal; diff --git a/nym-wallet/src/pages/bonding/mixnode/compound/CompoundRewards.tsx b/nym-wallet/src/pages/bonding/mixnode/compound/CompoundRewards.tsx index 3b1ec1ce0e..4c86067805 100644 --- a/nym-wallet/src/pages/bonding/mixnode/compound/CompoundRewards.tsx +++ b/nym-wallet/src/pages/bonding/mixnode/compound/CompoundRewards.tsx @@ -1,9 +1,10 @@ import * as React from 'react'; import { useContext, useEffect, useState } from 'react'; -import { MajorCurrencyAmount, TransactionExecuteResult } from '@nymproject/types'; +import { TransactionExecuteResult } from '@nymproject/types'; import { Link } from '@nymproject/react/link/Link'; import { Typography } from '@mui/material'; -import { AppContext, BondedMixnode, urls } from '../../../../context'; +import { ErrorOutline } from '@mui/icons-material'; +import { AppContext, BondedMixnode, urls, useBondingContext } from '../../../../context'; import SummaryModal from './SummaryModal'; import { ConfirmationModal } from '../../../../components'; @@ -14,20 +15,26 @@ interface Props { } const CompoundRewards = ({ mixnode, show, onClose }: Props) => { - const [fee, setFee] = useState({ amount: '0', denom: 'NYM' }); const [step, setStep] = useState<1 | 2>(1); const [tx, setTx] = useState(); const { network } = useContext(AppContext); + const { compoundRewards, error, fee, getFee } = useBondingContext(); + + const fetchFee = async () => { + await getFee('compoundRewards', {}); + }; useEffect(() => { - setFee({ amount: '42', denom: 'NYM' }); // TODO fetch real fee amount + fetchFee(); }, []); const submit = async () => { - // TODO send request to compound rewards - setStep(2); // on success - // setTx(requestResult) + const txResult = await compoundRewards(); + if (txResult) { + setStep(2); + } + setTx(txResult?.[0]); }; const reset = () => { @@ -43,7 +50,7 @@ const CompoundRewards = ({ mixnode, show, onClose }: Props) => { onConfirm={submit} onCancel={reset} rewards={mixnode.operatorRewards} - fee={fee as MajorCurrencyAmount} + fee={fee?.amount} /> { View on blockchain + {error && ( + + Error: {error} + + + )} ); }; diff --git a/nym-wallet/src/pages/bonding/mixnode/compound/SummaryModal.tsx b/nym-wallet/src/pages/bonding/mixnode/compound/SummaryModal.tsx index ae6f2e6ef2..f2629a78a6 100644 --- a/nym-wallet/src/pages/bonding/mixnode/compound/SummaryModal.tsx +++ b/nym-wallet/src/pages/bonding/mixnode/compound/SummaryModal.tsx @@ -9,7 +9,7 @@ export interface Props { onConfirm: () => Promise; onCancel: () => void; rewards: MajorCurrencyAmount; - fee: MajorCurrencyAmount; + fee?: MajorCurrencyAmount | null; } const SummaryModal = ({ open, onClose, onConfirm, onCancel, rewards, fee }: Props) => ( @@ -29,7 +29,7 @@ const SummaryModal = ({ open, onClose, onConfirm, onCancel, rewards, fee }: Prop Fee for this operation - {`${fee.amount} ${fee.denom}`} + {fee ? `${fee?.amount} ${fee?.denom}` : ''} Rewards will be added to your bonding pool diff --git a/nym-wallet/src/pages/bonding/mixnode/node-settings/NodeSettings.tsx b/nym-wallet/src/pages/bonding/mixnode/node-settings/NodeSettings.tsx index 9f4728c42d..9fc21d77dd 100644 --- a/nym-wallet/src/pages/bonding/mixnode/node-settings/NodeSettings.tsx +++ b/nym-wallet/src/pages/bonding/mixnode/node-settings/NodeSettings.tsx @@ -3,8 +3,9 @@ import { useContext, useEffect, useState } from 'react'; import { MajorCurrencyAmount, TransactionExecuteResult } from '@nymproject/types'; import { Link } from '@nymproject/react/link/Link'; import { Typography } from '@mui/material'; +import { ErrorOutline } from '@mui/icons-material'; import ProfitMarginModal from './ProfitMarginModal'; -import { AppContext, BondedMixnode, urls } from '../../../../context'; +import { AppContext, BondedMixnode, urls, useBondingContext } from '../../../../context'; import SummaryModal from './SummaryModal'; import { ConfirmationModal } from '../../../../components'; @@ -18,21 +19,36 @@ interface Props { const MOCK_ESTIMATED_OP_REWARD: MajorCurrencyAmount = { amount: '42', denom: 'NYM' }; const NodeSettings = ({ mixnode, show, onClose }: Props) => { + const [status, setStatus] = useState<'success' | 'error'>(); const [profitMargin, setProfitMargin] = useState(); - const [fee, setFee] = useState({ amount: '0', denom: 'NYM' }); - const [step, setStep] = useState<1 | 2 | 3>(1); + const [step, setStep] = useState<1 | 2>(1); const [tx, setTx] = useState(); const { network } = useContext(AppContext); + const { updateMixnode, error, fee, getFee } = useBondingContext(); useEffect(() => { - setFee({ amount: '42', denom: 'NYM' }); // TODO fetch real fee amount - }, [profitMargin]); + if (error) { + setStatus('error'); + } + }, [error]); + + const fetchFee = async () => { + await getFee('updateMixnode', {}); + }; + + useEffect(() => { + fetchFee(); + }, []); const submit = async () => { - // TODO send request to update profit margin - setStep(3); // on success - // setTx(requestResult) + const txResult = await updateMixnode(profitMargin as number); + if (txResult) { + setStatus('success'); + } else { + setStatus('error'); + } + setTx(txResult); }; const reset = () => { @@ -60,21 +76,36 @@ const NodeSettings = ({ mixnode, show, onClose }: Props) => { onCancel={() => setStep(1)} currentPm={mixnode.profitMargin} newPm={profitMargin as number} - fee={fee as MajorCurrencyAmount} + fee={fee?.amount} /> - - This operation can take up to one hour to process - - View on blockchain - - + {status === 'success' && ( + + This operation can take up to one hour to process + + View on blockchain + + + )} + {status === 'error' && ( + + Error: {error} + + + )} ); }; diff --git a/nym-wallet/src/pages/bonding/mixnode/node-settings/SummaryModal.tsx b/nym-wallet/src/pages/bonding/mixnode/node-settings/SummaryModal.tsx index 6abc0e5f4f..a24ae2e05d 100644 --- a/nym-wallet/src/pages/bonding/mixnode/node-settings/SummaryModal.tsx +++ b/nym-wallet/src/pages/bonding/mixnode/node-settings/SummaryModal.tsx @@ -10,7 +10,7 @@ export interface Props { onCancel: () => void; currentPm: number; newPm: number; - fee: MajorCurrencyAmount; + fee?: MajorCurrencyAmount | null; } const SummaryModal = ({ open, onClose, onConfirm, onCancel, currentPm, newPm, fee }: Props) => ( @@ -35,7 +35,7 @@ const SummaryModal = ({ open, onClose, onConfirm, onCancel, currentPm, newPm, fe Fee for this operation - {`${fee.amount} ${fee.denom}`} + {fee ? `${fee?.amount} ${fee?.denom}` : ''} ); diff --git a/nym-wallet/src/pages/bonding/mixnode/redeem/RedeemRewards.tsx b/nym-wallet/src/pages/bonding/mixnode/redeem/RedeemRewards.tsx index 84e1debea9..eec43ac487 100644 --- a/nym-wallet/src/pages/bonding/mixnode/redeem/RedeemRewards.tsx +++ b/nym-wallet/src/pages/bonding/mixnode/redeem/RedeemRewards.tsx @@ -1,9 +1,10 @@ import * as React from 'react'; import { useContext, useEffect, useState } from 'react'; -import { MajorCurrencyAmount, TransactionExecuteResult } from '@nymproject/types'; +import { TransactionExecuteResult } from '@nymproject/types'; import { Link } from '@nymproject/react/link/Link'; import { Typography } from '@mui/material'; -import { AppContext, BondedMixnode, urls } from '../../../../context'; +import { ErrorOutline } from '@mui/icons-material'; +import { AppContext, BondedMixnode, urls, useBondingContext } from '../../../../context'; import SummaryModal from './SummaryModal'; import { ConfirmationModal } from '../../../../components'; @@ -14,20 +15,26 @@ interface Props { } const RedeemRewards = ({ mixnode, show, onClose }: Props) => { - const [fee, setFee] = useState({ amount: '0', denom: 'NYM' }); const [step, setStep] = useState<1 | 2>(1); const [tx, setTx] = useState(); const { network } = useContext(AppContext); + const { redeemRewards, error, fee, getFee } = useBondingContext(); + + const fetchFee = async () => { + await getFee('redeemRewards', {}); + }; useEffect(() => { - setFee({ amount: '42', denom: 'NYM' }); // TODO fetch real fee amount + fetchFee(); }, []); const submit = async () => { - // TODO send request to redeem rewards - setStep(2); // on success - // setTx(requestResult) + const txResult = await redeemRewards(); + if (txResult) { + setStep(2); + } + setTx(txResult?.[0]); }; const reset = () => { @@ -43,7 +50,7 @@ const RedeemRewards = ({ mixnode, show, onClose }: Props) => { onConfirm={submit} onCancel={reset} rewards={mixnode.operatorRewards} - fee={fee as MajorCurrencyAmount} + fee={fee?.amount} /> { View on blockchain + {error && ( + + Error: {error} + + + )} ); }; diff --git a/nym-wallet/src/pages/bonding/mixnode/redeem/SummaryModal.tsx b/nym-wallet/src/pages/bonding/mixnode/redeem/SummaryModal.tsx index b226e8bc5b..c802ca79d4 100644 --- a/nym-wallet/src/pages/bonding/mixnode/redeem/SummaryModal.tsx +++ b/nym-wallet/src/pages/bonding/mixnode/redeem/SummaryModal.tsx @@ -9,7 +9,7 @@ export interface Props { onConfirm: () => Promise; onCancel: () => void; rewards: MajorCurrencyAmount; - fee: MajorCurrencyAmount; + fee?: MajorCurrencyAmount | null; } const SummaryModal = ({ open, onClose, onConfirm, onCancel, rewards, fee }: Props) => ( @@ -29,7 +29,7 @@ const SummaryModal = ({ open, onClose, onConfirm, onCancel, rewards, fee }: Prop Fee for this operation - {`${fee.amount} ${fee.denom}`} + {fee ? `${fee.amount} ${fee.denom}` : ''} Rewards will be transferred to the account you are logged in with diff --git a/nym-wallet/src/pages/bonding/mixnode/unbond/SummaryModal.tsx b/nym-wallet/src/pages/bonding/mixnode/unbond/SummaryModal.tsx deleted file mode 100644 index 088f09d802..0000000000 --- a/nym-wallet/src/pages/bonding/mixnode/unbond/SummaryModal.tsx +++ /dev/null @@ -1,49 +0,0 @@ -import * as React from 'react'; -import { Divider, Stack, Typography } from '@mui/material'; -import { MajorCurrencyAmount } from '@nymproject/types'; -import { SimpleModal } from '../../../../components/Modals/SimpleModal'; - -export interface Props { - open: boolean; - onClose: () => void; - onConfirm: () => Promise; - onCancel: () => void; - bond: MajorCurrencyAmount; - rewards?: MajorCurrencyAmount; - fee: MajorCurrencyAmount; -} - -const SummaryModal = ({ open, onClose, onConfirm, onCancel, bond, rewards, fee }: Props) => ( - - - Amount to unbond - {`${bond.amount} ${bond.denom}`} - - - {rewards?.amount && ( - <> - - Operator rewards - {`${rewards.amount} ${rewards.denom}`} - - - - )} - - Fee for this operation - {`${fee.amount} ${fee.denom}`} - - - Tokens will be transferred to account you are logged in with now - -); - -export default SummaryModal; diff --git a/nym-wallet/src/pages/bonding/mixnode/unbond/index.ts b/nym-wallet/src/pages/bonding/mixnode/unbond/index.ts deleted file mode 100644 index a0dd1d709c..0000000000 --- a/nym-wallet/src/pages/bonding/mixnode/unbond/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -import Unbond from './Unbond'; - -export default Unbond; diff --git a/nym-wallet/src/pages/bonding/gateway/unbond/SummaryModal.tsx b/nym-wallet/src/pages/bonding/unbond/SummaryModal.tsx similarity index 95% rename from nym-wallet/src/pages/bonding/gateway/unbond/SummaryModal.tsx rename to nym-wallet/src/pages/bonding/unbond/SummaryModal.tsx index 088f09d802..94205c3bdf 100644 --- a/nym-wallet/src/pages/bonding/gateway/unbond/SummaryModal.tsx +++ b/nym-wallet/src/pages/bonding/unbond/SummaryModal.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import { Divider, Stack, Typography } from '@mui/material'; import { MajorCurrencyAmount } from '@nymproject/types'; -import { SimpleModal } from '../../../../components/Modals/SimpleModal'; +import { SimpleModal } from '../../../components/Modals/SimpleModal'; export interface Props { open: boolean; diff --git a/nym-wallet/src/pages/bonding/mixnode/unbond/Unbond.tsx b/nym-wallet/src/pages/bonding/unbond/Unbond.tsx similarity index 60% rename from nym-wallet/src/pages/bonding/mixnode/unbond/Unbond.tsx rename to nym-wallet/src/pages/bonding/unbond/Unbond.tsx index 450382268a..1c0fee570b 100644 --- a/nym-wallet/src/pages/bonding/mixnode/unbond/Unbond.tsx +++ b/nym-wallet/src/pages/bonding/unbond/Unbond.tsx @@ -4,21 +4,14 @@ import { MajorCurrencyAmount } from '@nymproject/types'; import { Link } from '@nymproject/react/link/Link'; import { Typography } from '@mui/material'; import { ErrorOutline } from '@mui/icons-material'; -import { AppContext, BondedMixnode, urls } from '../../../../context'; +import { AppContext, BondedGateway, BondedMixnode, urls, useBondingContext } from '../../../context'; import SummaryModal from './SummaryModal'; -import { ConfirmationModal } from '../../../../components'; -import { - simulateUnbondMixnode, - simulateVestingUnbondMixnode, - unbondMixNode, - vestingUnbondMixnode, -} from '../../../../requests'; -import { useCheckOwnership } from '../../../../hooks/useCheckOwnership'; -import { useGetFee } from '../../../../hooks/useGetFee'; -import { LoadingModal } from '../../../../components/Modals/LoadingModal'; +import { ConfirmationModal } from '../../../components'; +import { LoadingModal } from '../../../components/Modals/LoadingModal'; +import { NodeType } from '../types'; interface Props { - node: BondedMixnode; + node: BondedMixnode | BondedGateway; show: boolean; onClose: () => void; } @@ -26,49 +19,55 @@ interface Props { type UnbondStatus = 'success' | 'error'; const Unbond = ({ node, show, onClose }: Props) => { - const [isLoading, setIsLoading] = useState(false); const [step, setStep] = useState<1 | 2>(1); const [txHash, setTxHash] = useState(); const [status, setStatus] = useState(); - const [error, setError] = useState(); - - const { fee, getFee, resetFeeState, isFeeLoading } = useGetFee(); + const [nodeType, setNodeType] = useState('mixnode'); const { network } = useContext(AppContext); - const { checkOwnership, ownership } = useCheckOwnership(); + const { fee, getFee, resetFeeState, feeLoading, feeError, loading, unbondMixnode, unbondGateway, error } = + useBondingContext(); - const isVesting = Boolean(ownership.vestingPledge); + useEffect(() => { + if (error || feeError) { + setStatus('error'); + } + }, [error, feeError]); + + useEffect(() => { + if ('profitMarfin' in node) { + setNodeType('mixnode'); + } else { + setNodeType('gateway'); + } + }, [node]); const unbond = async () => { let tx; - setIsLoading(true); - try { - if (isVesting) tx = await vestingUnbondMixnode(fee?.fee); - if (!isVesting) tx = await unbondMixNode(fee?.fee); - setTxHash(tx?.transaction_hash); - setStatus('success'); - } catch (err: any) { - setStatus('error'); - setError(err as string); - } finally { - await checkOwnership(); - setIsLoading(false); + if (nodeType === 'mixnode') { + tx = await unbondMixnode(); + } else { + tx = await unbondGateway(); } + if (!tx) { + setStatus('error'); + } + setStatus('success'); + setTxHash(tx?.transaction_hash); + return tx; }; const fetchFee = async () => { - try { - if (isVesting) await getFee(simulateVestingUnbondMixnode, {}); - if (!isVesting) await getFee(simulateUnbondMixnode, {}); - } catch (e: any) { - setStatus('error'); - setError(e as string); + if (nodeType === 'mixnode') { + await getFee('unbondMixnode', {}); + } else { + await getFee('unbondGateway', {}); } }; useEffect(() => { fetchFee(); - }, [node, isVesting]); + }, [node]); const submit = async () => { if (status === 'error') { @@ -85,7 +84,7 @@ const Unbond = ({ node, show, onClose }: Props) => { onClose(); }; - if (isFeeLoading || isLoading) return ; + if (feeLoading || loading) return ; return ( <> @@ -95,7 +94,7 @@ const Unbond = ({ node, show, onClose }: Props) => { onConfirm={submit} onCancel={reset} bond={node.bond} - rewards={(node as BondedMixnode).operatorRewards} + rewards={nodeType === 'mixnode' ? (node as BondedMixnode).operatorRewards : undefined} fee={fee?.amount as MajorCurrencyAmount} /> {status === 'success' && ( diff --git a/nym-wallet/src/pages/bonding/gateway/unbond/index.ts b/nym-wallet/src/pages/bonding/unbond/index.ts similarity index 100% rename from nym-wallet/src/pages/bonding/gateway/unbond/index.ts rename to nym-wallet/src/pages/bonding/unbond/index.ts