From d4231ea531c5e2f431d150bb25d06b4008ef0e92 Mon Sep 17 00:00:00 2001 From: Dexter Edwards Date: Tue, 13 Dec 2022 15:37:11 +0000 Subject: [PATCH] Fix/rest delegations (#2392) * chore: create use delegations hook * chore: add polling to use delegations * chore: remove polling logic from hook * chore: remove delegations from staking form * chore: fix more delegations queries * chore: rename file * fix: spelling issues --- apps/token/.env | 2 +- .../vega-wallet/__generated__/Delegations.ts | 30 -- .../token/src/components/vega-wallet/hooks.ts | 302 ++++++++---------- .../vega-wallet/use-party-delegations.ts | 77 +++++ .../components/vega-wallet/vega-wallet.tsx | 12 +- .../routes/staking/__generated__/Staking.ts | 29 -- .../token/src/routes/staking/staking-form.tsx | 62 +--- .../token/src/routes/staking/staking-node.tsx | 39 ++- .../staking/staking-nodes-container.tsx | 8 - libs/react-helpers/src/hooks/use-fetch.ts | 6 +- 10 files changed, 249 insertions(+), 318 deletions(-) create mode 100644 apps/token/src/components/vega-wallet/use-party-delegations.ts diff --git a/apps/token/.env b/apps/token/.env index 2c47f7911..b3b14a45e 100644 --- a/apps/token/.env +++ b/apps/token/.env @@ -4,7 +4,7 @@ NX_VEGA_CONFIG_URL=https://static.vega.xyz/assets/testnet-network.json NX_VEGA_URL=https://api.n07.testnet.vega.xyz/graphql NX_ETHEREUM_PROVIDER_URL=https://ropsten.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8 NX_ETHERSCAN_URL=https://ropsten.etherscan.io -NX_VEGA_REST=https://api.n07.testnet.vega.xyz +NX_VEGA_REST=https://api.vega.xyz NX_FAIRGROUND=false NX_VEGA_NETWORKS='{"DEVNET":"https://dev.token.vega.xyz","STAGNET3":"https://stagnet3.token.vega.xyz","TESTNET":"https://token.fairground.wtf","MAINNET":"https://token.vega.xyz"}' NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions diff --git a/apps/token/src/components/vega-wallet/__generated__/Delegations.ts b/apps/token/src/components/vega-wallet/__generated__/Delegations.ts index 520783ad2..41d6f64cb 100644 --- a/apps/token/src/components/vega-wallet/__generated__/Delegations.ts +++ b/apps/token/src/components/vega-wallet/__generated__/Delegations.ts @@ -17,35 +17,6 @@ export interface Delegations_epoch { id: string; } -export interface Delegations_party_delegations_node { - __typename: "Node"; - /** - * The node url eg n01.vega.xyz - */ - id: string; - name: string; -} - -export interface Delegations_party_delegations { - __typename: "Delegation"; - /** - * The amount field formatted by the client - */ - amountFormatted: string; - /** - * Amount delegated - */ - amount: string; - /** - * URL of node you are delegating to - */ - node: Delegations_party_delegations_node; - /** - * Epoch of delegation - */ - epoch: number; -} - export interface Delegations_party_stake { __typename: "PartyStake"; /** @@ -118,7 +89,6 @@ export interface Delegations_party { * Party identifier */ id: string; - delegations: Delegations_party_delegations[] | null; /** * The staking information for this Party */ diff --git a/apps/token/src/components/vega-wallet/hooks.ts b/apps/token/src/components/vega-wallet/hooks.ts index 2929306a7..f460a26f2 100644 --- a/apps/token/src/components/vega-wallet/hooks.ts +++ b/apps/token/src/components/vega-wallet/hooks.ts @@ -1,24 +1,22 @@ -import { gql, useApolloClient } from '@apollo/client'; -import * as Sentry from '@sentry/react'; +import { gql, useQuery } from '@apollo/client'; import keyBy from 'lodash/keyBy'; import uniq from 'lodash/uniq'; -import React from 'react'; import { useTranslation } from 'react-i18next'; import noIcon from '../../images/token-no-icon.png'; import vegaBlack from '../../images/vega_black.png'; import { BigNumber } from '../../lib/bignumber'; import { addDecimal } from '../../lib/decimals'; -import type { WalletCardAssetProps } from '../wallet-card'; import type { Delegations, - Delegations_party_delegations, DelegationsVariables, } from './__generated__/Delegations'; import { useVegaWallet } from '@vegaprotocol/wallet'; import { useContracts } from '../../contexts/contracts/contracts-context'; -import { isAssetTypeERC20 } from '@vegaprotocol/react-helpers'; +import { isAssetTypeERC20, toBigNum } from '@vegaprotocol/react-helpers'; import { AccountType } from '@vegaprotocol/types'; +import { usePartyDelegations } from './use-party-delegations'; +import { useAppState } from '../../contexts/app-state/app-state-context'; const DELEGATIONS_QUERY = gql` query Delegations($partyId: ID!) { @@ -27,15 +25,6 @@ const DELEGATIONS_QUERY = gql` } party(id: $partyId) { id - delegations { - amountFormatted @client - amount - node { - id - name - } - epoch - } stake { currentStakeAvailable currentStakeAvailableFormatted @client @@ -61,173 +50,132 @@ const DELEGATIONS_QUERY = gql` `; export const usePollForDelegations = () => { + const { + appState: { decimals }, + } = useAppState(); const { token: vegaToken } = useContracts(); const { t } = useTranslation(); const { keypair } = useVegaWallet(); - const client = useApolloClient(); - const [delegations, setDelegations] = React.useState< - Delegations_party_delegations[] - >([]); - const [delegatedNodes, setDelegatedNodes] = React.useState< + const delegations = usePartyDelegations(keypair?.pub); + + const { data } = useQuery( + DELEGATIONS_QUERY, { - nodeId: string; - name: string; - hasStakePending: boolean; - currentEpochStake?: BigNumber; - nextEpochStake?: BigNumber; - }[] - >([]); - const [accounts, setAccounts] = React.useState([]); - const [currentStakeAvailable, setCurrentStakeAvailable] = - React.useState(new BigNumber(0)); - - React.useEffect(() => { - // eslint-disable-next-line - let interval: any; - let mounted = true; - - if (keypair?.pub) { - // start polling for delegation - interval = setInterval(() => { - client - .query({ - query: DELEGATIONS_QUERY, - variables: { partyId: keypair.pub }, - fetchPolicy: 'network-only', - }) - .then((res) => { - if (!mounted) return; - const filter = - res.data.party?.delegations?.filter((d) => { - return d.epoch.toString() === res.data.epoch.id; - }) || []; - const sortedDelegations = [...filter].sort((a, b) => { - return new BigNumber(b.amountFormatted) - .minus(a.amountFormatted) - .toNumber(); - }); - setDelegations(sortedDelegations); - setCurrentStakeAvailable( - new BigNumber( - res.data.party?.stake.currentStakeAvailableFormatted || 0 - ) - ); - const accounts = res.data.party?.accounts || []; - setAccounts( - accounts - .filter((a) => a.type === AccountType.General) - .map((a) => { - const isVega = - isAssetTypeERC20(a.asset) && - a.asset.source.contractAddress === vegaToken.address; - - return { - isVega, - name: a.asset.name, - subheading: isVega ? t('collateral') : a.asset.symbol, - symbol: a.asset.symbol, - decimals: a.asset.decimals, - balance: new BigNumber( - addDecimal(new BigNumber(a.balance), a.asset.decimals) - ), - image: isVega ? vegaBlack : noIcon, - border: isVega, - address: isAssetTypeERC20(a.asset) - ? a.asset.source.contractAddress - : undefined, - }; - }) - .sort((a, b) => { - // Put VEGA at the top of the list - if (a.isVega) { - return -1; - } - if (b.isVega) { - return 1; - } - // Secondary sort by name - if (a.name < b.name) { - return -1; - } - if (a.name > b.name) { - return 1; - } - return 0; - }) - ); - const delegatedNextEpoch = keyBy( - res.data.party?.delegations?.filter((d) => { - return d.epoch === Number(res.data.epoch.id) + 1; - }) || [], - 'node.id' - ); - const delegatedThisEpoch = keyBy( - res.data.party?.delegations?.filter((d) => { - return d.epoch === Number(res.data.epoch.id); - }) || [], - 'node.id' - ); - const nodesDelegated = uniq([ - ...Object.keys(delegatedNextEpoch), - ...Object.keys(delegatedThisEpoch), - ]); - - const delegatedAmounts = nodesDelegated - .map((d) => ({ - nodeId: d, - name: - delegatedThisEpoch[d]?.node?.name || - delegatedNextEpoch[d]?.node?.name, - hasStakePending: !!( - (delegatedThisEpoch[d]?.amountFormatted || - delegatedNextEpoch[d]?.amountFormatted) && - delegatedThisEpoch[d]?.amountFormatted !== - delegatedNextEpoch[d]?.amountFormatted && - delegatedNextEpoch[d] !== undefined - ), - currentEpochStake: - delegatedThisEpoch[d] && - new BigNumber(delegatedThisEpoch[d].amountFormatted), - nextEpochStake: - delegatedNextEpoch[d] && - new BigNumber(delegatedNextEpoch[d].amountFormatted), - })) - .sort((a, b) => { - if ( - new BigNumber(a.currentEpochStake || 0).isLessThan( - b.currentEpochStake || 0 - ) - ) - return 1; - if ( - new BigNumber(a.currentEpochStake || 0).isGreaterThan( - b.currentEpochStake || 0 - ) - ) - return -1; - if ((!a.name && b.name) || a.name < b.name) return 1; - if ((!b.name && a.name) || a.name > b.name) return -1; - if (a.nodeId > b.nodeId) return 1; - if (a.nodeId < b.nodeId) return -1; - return 0; - }); - - setDelegatedNodes(delegatedAmounts); - }) - .catch((err: Error) => { - Sentry.captureException(err); - // If query fails stop interval. Its almost certain that the query - // will just continue to fail - clearInterval(interval); - }); - }, 100000); + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion, @typescript-eslint/no-non-null-asserted-optional-chain + variables: { partyId: keypair?.pub! }, + skip: !keypair?.pub, } + ); - return () => { - clearInterval(interval); - mounted = false; - }; - }, [client, keypair?.pub, t, vegaToken.address]); + const filter = + delegations?.filter((d) => { + return d.epochSeq === data?.epoch.id; + }) || []; + const sortedDelegations = [...filter].sort((a, b) => { + return new BigNumber(b.amount).minus(a.amount).toNumber(); + }); - return { delegations, currentStakeAvailable, delegatedNodes, accounts }; + const partyAccounts = data?.party?.accounts || []; + const accounts = partyAccounts + .filter((a) => a.type === AccountType.General) + .map((a) => { + const isVega = + isAssetTypeERC20(a.asset) && + a.asset.source.contractAddress === vegaToken.address; + + return { + isVega, + name: a.asset.name, + subheading: isVega ? t('collateral') : a.asset.symbol, + symbol: a.asset.symbol, + decimals: a.asset.decimals, + balance: new BigNumber( + addDecimal(new BigNumber(a.balance), a.asset.decimals) + ), + image: isVega ? vegaBlack : noIcon, + border: isVega, + address: isAssetTypeERC20(a.asset) + ? a.asset.source.contractAddress + : undefined, + }; + }) + .sort((a, b) => { + // Put VEGA at the top of the list + if (a.isVega) { + return -1; + } + if (b.isVega) { + return 1; + } + // Secondary sort by name + if (a.name < b.name) { + return -1; + } + if (a.name > b.name) { + return 1; + } + return 0; + }); + const delegatedNextEpoch = keyBy( + delegations?.filter((d) => { + return Number(d.epochSeq) === Number(data?.epoch.id) + 1; + }) || [], + 'nodeId' + ); + const delegatedThisEpoch = keyBy( + delegations?.filter((d) => { + return d.epochSeq === data?.epoch.id; + }) || [], + 'nodeId' + ); + const nodesDelegated = uniq([ + ...Object.keys(delegatedNextEpoch), + ...Object.keys(delegatedThisEpoch), + ]); + + const delegatedAmounts = nodesDelegated + .map((d) => ({ + nodeId: d, + name: + delegatedThisEpoch[d]?.node?.name || delegatedNextEpoch[d]?.node?.name, + hasStakePending: !!( + (delegatedThisEpoch[d]?.amount || delegatedNextEpoch[d]?.amount) && + delegatedThisEpoch[d]?.amount !== delegatedNextEpoch[d]?.amount && + delegatedNextEpoch[d] !== undefined + ), + currentEpochStake: + delegatedThisEpoch[d] && + toBigNum(delegatedThisEpoch[d].amount, decimals), + nextEpochStake: + delegatedNextEpoch[d] && + toBigNum(delegatedNextEpoch[d].amount, decimals), + })) + .sort((a, b) => { + if ( + new BigNumber(a.currentEpochStake || 0).isLessThan( + b.currentEpochStake || 0 + ) + ) + return 1; + if ( + new BigNumber(a.currentEpochStake || 0).isGreaterThan( + b.currentEpochStake || 0 + ) + ) + return -1; + if ((!a.name && b.name) || a.name || '' < (b.name || '')) return 1; + if ((!b.name && a.name) || a.name || '' > (b.name || '')) return -1; + if (a.nodeId > b.nodeId) return 1; + if (a.nodeId < b.nodeId) return -1; + return 0; + }); + + return { + delegations: sortedDelegations, + currentStakeAvailable: new BigNumber( + data?.party?.stake.currentStakeAvailableFormatted || 0 + ), + delegatedNodes: delegatedAmounts, + accounts, + }; }; diff --git a/apps/token/src/components/vega-wallet/use-party-delegations.ts b/apps/token/src/components/vega-wallet/use-party-delegations.ts new file mode 100644 index 000000000..63281dee7 --- /dev/null +++ b/apps/token/src/components/vega-wallet/use-party-delegations.ts @@ -0,0 +1,77 @@ +import { useFetch } from '@vegaprotocol/react-helpers'; +import { useEffect, useMemo, useState } from 'react'; + +export interface Delegation { + party: string; + nodeId: string; + amount: string; + epochSeq: string; +} + +export interface RankingScore { + stakeScore: string; + performanceScore: string; + previousStatus: string; + status: string; + votingPower: number; + rankingScore: string; +} + +export interface Node { + id: string; + pubKey: string; + tmPubKey: string; + ethereumAdddress: string; + infoUrl: string; + location: string; + stakedByOperator: string; + stakedByDelegates: string; + stakedTotal: string; + maxIntendedStake: string; + pendingStake: string; + epochData?: any; + status: string; + delegations: Delegation[]; + rewardScore?: any; + rankingScore: RankingScore; + name: string; + avatarUrl: string; +} + +export interface NodesQuery { + nodes: Node[]; +} + +export interface DelegationsQuery { + delegations: Delegation[]; +} + +export interface DelegationsNode extends Delegation { + node: Node | undefined; +} + +export const usePartyDelegations = (partyId: string | undefined) => { + const delegationsUrl = `${process.env['NX_VEGA_REST']}delegations?party=${partyId}`; + const { state: delegationsData, refetch: refetchDelegations } = + useFetch(delegationsUrl); + const { state: nodesData } = useFetch( + `${process.env['NX_VEGA_REST']}nodes` + ); + useEffect(() => { + const interval = setInterval(() => refetchDelegations(), 10000); + return () => { + if (interval) { + clearInterval(interval); + } + }; + }, [refetchDelegations]); + + const delegations = useMemo(() => { + if (!delegationsData.data) return []; + return delegationsData.data?.delegations.map((d) => ({ + ...d, + node: nodesData.data?.nodes.find(({ id }) => d.nodeId === id), + })); + }, [delegationsData.data, nodesData.data?.nodes]); + return delegations; +}; diff --git a/apps/token/src/components/vega-wallet/vega-wallet.tsx b/apps/token/src/components/vega-wallet/vega-wallet.tsx index a458d21ee..6c7760177 100644 --- a/apps/token/src/components/vega-wallet/vega-wallet.tsx +++ b/apps/token/src/components/vega-wallet/vega-wallet.tsx @@ -25,6 +25,7 @@ import { usePollForDelegations } from './hooks'; import type { VegaKeyExtended } from '@vegaprotocol/wallet'; import { useVegaWallet } from '@vegaprotocol/wallet'; import { Button, ButtonLink } from '@vegaprotocol/ui-toolkit'; +import { toBigNum } from '@vegaprotocol/react-helpers'; export const VegaWallet = () => { const { t } = useTranslation(); @@ -122,12 +123,13 @@ const VegaWalletConnected = ({ vegaKeys }: VegaWalletConnectedProps) => { usePollForDelegations(); const unstaked = React.useMemo(() => { - const totalDelegated = delegations.reduce( - (acc, cur) => acc.plus(cur.amountFormatted), - new BigNumber(0) - ); + const totalDelegated = + delegations?.reduce( + (acc, cur) => acc.plus(toBigNum(cur.amount, decimals)), + new BigNumber(0) + ) || new BigNumber(0); return BigNumber.max(currentStakeAvailable.minus(totalDelegated), 0); - }, [currentStakeAvailable, delegations]); + }, [currentStakeAvailable, decimals, delegations]); const footer = (
diff --git a/apps/token/src/routes/staking/__generated__/Staking.ts b/apps/token/src/routes/staking/__generated__/Staking.ts index 99380a75f..7d6261be5 100644 --- a/apps/token/src/routes/staking/__generated__/Staking.ts +++ b/apps/token/src/routes/staking/__generated__/Staking.ts @@ -21,34 +21,6 @@ export interface Staking_party_stake { currentStakeAvailableFormatted: string; } -export interface Staking_party_delegations_node { - __typename: "Node"; - /** - * The node url eg n01.vega.xyz - */ - id: string; -} - -export interface Staking_party_delegations { - __typename: "Delegation"; - /** - * Amount delegated - */ - amount: string; - /** - * The amount field formatted by the client - */ - amountFormatted: string; - /** - * Epoch of delegation - */ - epoch: number; - /** - * URL of node you are delegating to - */ - node: Staking_party_delegations_node; -} - export interface Staking_party { __typename: "Party"; /** @@ -59,7 +31,6 @@ export interface Staking_party { * The staking information for this Party */ stake: Staking_party_stake; - delegations: Staking_party_delegations[] | null; } export interface Staking_epoch_timestamps { diff --git a/apps/token/src/routes/staking/staking-form.tsx b/apps/token/src/routes/staking/staking-form.tsx index 666639328..53b84d2da 100644 --- a/apps/token/src/routes/staking/staking-form.tsx +++ b/apps/token/src/routes/staking/staking-form.tsx @@ -31,25 +31,7 @@ import type { } from '@vegaprotocol/wallet'; import { useVegaWallet } from '@vegaprotocol/wallet'; import { useNetworkParam } from '@vegaprotocol/react-helpers'; - -export const PARTY_DELEGATIONS_QUERY = gql` - query PartyDelegations($partyId: ID!) { - party(id: $partyId) { - id - delegations { - amount - amountFormatted @client - node { - id - } - epoch - } - } - epoch { - id - } - } -`; +import { usePartyDelegations } from '../../components/vega-wallet/use-party-delegations'; enum FormState { Default, @@ -75,6 +57,7 @@ interface StakingFormProps { nodeName: string; availableStakeToAdd: BigNumber; availableStakeToRemove: BigNumber; + currentEpoch: string | undefined; } export const StakingForm = ({ @@ -83,6 +66,7 @@ export const StakingForm = ({ nodeName, availableStakeToAdd, availableStakeToRemove, + currentEpoch, }: StakingFormProps) => { const params = useSearchParams(); const navigate = useNavigate(); @@ -99,6 +83,7 @@ export const StakingForm = ({ RemoveType.EndOfEpoch ); // Clear the amount when the staking method changes + const delegations = usePartyDelegations(pubkey); React.useEffect(() => { setAmount(''); }, [action, setAmount]); @@ -159,39 +144,18 @@ export const StakingForm = ({ } React.useEffect(() => { - // eslint-disable-next-line - let interval: any; - if (formState === FormState.Pending) { - // start polling for delegation - interval = setInterval(() => { - client - .query({ - query: PARTY_DELEGATIONS_QUERY, - variables: { partyId: pubkey }, - fetchPolicy: 'network-only', - }) - .then((res) => { - const delegation = res.data.party?.delegations?.find((d) => { - return ( - d.node.id === nodeId && - d.epoch === Number(res.data.epoch.id) + 1 - ); - }); + const delegation = delegations?.find((d) => { + return ( + d.nodeId === nodeId && Number(d.epochSeq) === Number(currentEpoch) + 1 + ); + }); - if (delegation) { - setFormState(FormState.Success); - clearInterval(interval); - } - }) - .catch((err) => { - Sentry.captureException(err); - }); - }, 1000); + if (delegation) { + setFormState(FormState.Success); + } } - - return () => clearInterval(interval); - }, [formState, client, pubkey, nodeId]); + }, [formState, client, pubkey, nodeId, delegations, currentEpoch]); if (formState === FormState.Failure) { return ; diff --git a/apps/token/src/routes/staking/staking-node.tsx b/apps/token/src/routes/staking/staking-node.tsx index 510a58091..aa8300dc3 100644 --- a/apps/token/src/routes/staking/staking-node.tsx +++ b/apps/token/src/routes/staking/staking-node.tsx @@ -12,6 +12,9 @@ import { StakingNodesContainer } from './staking-nodes-container'; import { StakingWalletsContainer } from './staking-wallets-container'; import { ValidatorTable } from './validator-table'; import { YourStake } from './your-stake'; +import { usePartyDelegations } from '../../components/vega-wallet/use-party-delegations'; +import { useAppState } from '../../contexts/app-state/app-state-context'; +import { toBigNum } from '@vegaprotocol/react-helpers'; export const StakingNodeContainer = () => { return ( @@ -36,6 +39,9 @@ interface StakingNodeProps { export const StakingNode = ({ vegaKey, data }: StakingNodeProps) => { const { node } = useParams<{ node: string }>(); + const { + appState: { decimals }, + } = useAppState(); const { t } = useTranslation(); const nodeInfo = React.useMemo(() => { @@ -45,36 +51,36 @@ export const StakingNode = ({ vegaKey, data }: StakingNodeProps) => { const currentEpoch = React.useMemo(() => { return data?.epoch.id; }, [data?.epoch.id]); - + const partyDelegations = usePartyDelegations(vegaKey.pub); const stakeThisEpoch = React.useMemo(() => { - const delegations = data?.party?.delegations || []; + const delegations = partyDelegations || []; const amountsThisEpoch = delegations - .filter((d) => d.node.id === node) - .filter((d) => d.epoch === Number(currentEpoch)) - .map((d) => new BigNumber(d.amountFormatted)); + .filter((d) => d.nodeId === node) + .filter((d) => d.epochSeq === currentEpoch) + .map((d) => toBigNum(d.amount, decimals)); return BigNumber.sum.apply(null, [new BigNumber(0), ...amountsThisEpoch]); - }, [data?.party?.delegations, node, currentEpoch]); + }, [partyDelegations, node, currentEpoch, decimals]); const stakeNextEpoch = React.useMemo(() => { - const delegations = data?.party?.delegations || []; + const delegations = partyDelegations || []; const amountsNextEpoch = delegations - .filter((d) => d.node.id === node) - .filter((d) => d.epoch === Number(currentEpoch) + 1) - .map((d) => new BigNumber(d.amountFormatted)); + .filter((d) => d.nodeId === node) + .filter((d) => Number(d.epochSeq) === Number(currentEpoch) + 1) + .map((d) => toBigNum(d.amount, decimals)); if (!amountsNextEpoch.length) { return stakeThisEpoch; } return BigNumber.sum.apply(null, [new BigNumber(0), ...amountsNextEpoch]); - }, [currentEpoch, data?.party?.delegations, node, stakeThisEpoch]); + }, [currentEpoch, decimals, node, partyDelegations, stakeThisEpoch]); const currentDelegationAmount = React.useMemo(() => { - if (!data?.party?.delegations) return new BigNumber(0); - const amounts = data.party.delegations - .filter((d) => d.epoch === Number(currentEpoch) + 1) - .map((d) => new BigNumber(d.amountFormatted)); + if (!partyDelegations?.length) return new BigNumber(0); + const amounts = partyDelegations + .filter((d) => Number(d.epochSeq) === Number(currentEpoch) + 1) + .map((d) => toBigNum(d.amount, decimals)); return BigNumber.sum.apply(null, [new BigNumber(0), ...amounts]); - }, [currentEpoch, data?.party?.delegations]); + }, [currentEpoch, decimals, partyDelegations]); const unstaked = React.useMemo(() => { const value = new BigNumber( @@ -125,6 +131,7 @@ export const StakingNode = ({ vegaKey, data }: StakingNodeProps) => {
( const fetchReducer = (state: State, action: Action): State => { switch (action.type) { case ActionType.LOADING: - return { ...initialState, loading: true }; + return { ...state, loading: true }; case ActionType.FETCHED: - return { ...initialState, data: action.payload, loading: false }; + return { ...state, data: action.payload, loading: false }; case ActionType.ERROR: - return { ...initialState, error: action.error, loading: false }; + return { ...state, error: action.error, loading: false }; } };