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
This commit is contained in:
+1
-1
@@ -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
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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, DelegationsVariables>(
|
||||
DELEGATIONS_QUERY,
|
||||
{
|
||||
nodeId: string;
|
||||
name: string;
|
||||
hasStakePending: boolean;
|
||||
currentEpochStake?: BigNumber;
|
||||
nextEpochStake?: BigNumber;
|
||||
}[]
|
||||
>([]);
|
||||
const [accounts, setAccounts] = React.useState<WalletCardAssetProps[]>([]);
|
||||
const [currentStakeAvailable, setCurrentStakeAvailable] =
|
||||
React.useState<BigNumber>(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<Delegations, DelegationsVariables>({
|
||||
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,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -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<DelegationsQuery>(delegationsUrl);
|
||||
const { state: nodesData } = useFetch<NodesQuery>(
|
||||
`${process.env['NX_VEGA_REST']}nodes`
|
||||
);
|
||||
useEffect(() => {
|
||||
const interval = setInterval(() => refetchDelegations(), 10000);
|
||||
return () => {
|
||||
if (interval) {
|
||||
clearInterval(interval);
|
||||
}
|
||||
};
|
||||
}, [refetchDelegations]);
|
||||
|
||||
const delegations = useMemo<DelegationsNode[] | undefined>(() => {
|
||||
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;
|
||||
};
|
||||
@@ -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<BigNumber>(
|
||||
(acc, cur) => acc.plus(cur.amountFormatted),
|
||||
new BigNumber(0)
|
||||
);
|
||||
const totalDelegated =
|
||||
delegations?.reduce<BigNumber>(
|
||||
(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 = (
|
||||
<div className="flex justify-end">
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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<PartyDelegations, PartyDelegationsVariables>({
|
||||
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 <StakeFailure nodeName={nodeName} />;
|
||||
|
||||
@@ -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) => {
|
||||
</section>
|
||||
<section>
|
||||
<StakingForm
|
||||
currentEpoch={data?.epoch.id}
|
||||
pubkey={vegaKey.pub}
|
||||
nodeId={nodeInfo.id}
|
||||
nodeName={nodeInfo.name}
|
||||
|
||||
@@ -15,14 +15,6 @@ export const STAKING_QUERY = gql`
|
||||
currentStakeAvailable
|
||||
currentStakeAvailableFormatted @client
|
||||
}
|
||||
delegations {
|
||||
amount
|
||||
amountFormatted @client
|
||||
epoch
|
||||
node {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
epoch {
|
||||
id
|
||||
|
||||
@@ -42,11 +42,11 @@ export const useFetch = <T>(
|
||||
const fetchReducer = (state: State<T>, action: Action<T>): State<T> => {
|
||||
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 };
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user