fix: validators reported as idle in staking accounts (#12391)
* fix: validators reported as idle in staking accounts * refactor: detect validators via isStorageFallback in useOwnStashInfos * refactor: rename setMyStashesIndex to setSelectedIndex in Payouts * refactor: detect validators via isStorageFallback in useAccountInfo * updated comments to be more succinct * fix: reset Payouts toggle when own validators empty
This commit is contained in:
parent
65dd9cba45
commit
dad40a45da
@ -159,8 +159,13 @@ function getOptions (blockTime: BN, eraLength: BN | undefined, historyDepth: BN
|
||||
function Payouts ({ className = '', historyDepth, isInElection, ownPools, ownValidators }: Props): React.ReactElement<Props> {
|
||||
const { t } = useTranslation();
|
||||
const { api } = useApi();
|
||||
const [hasOwnValidators] = useState(() => ownValidators.length !== 0);
|
||||
const [myStashesIndex, setMyStashesIndex] = useState(() => hasOwnValidators ? 0 : 1);
|
||||
const [selectedIndex, setSelectedIndex] = useState<number | undefined>();
|
||||
const hasOwnValidators = ownValidators.length !== 0;
|
||||
// "Own validators" (index 0) is disabled when there are none. Testing that before
|
||||
// `selectedIndex` means we neither default to it, nor stay on it if the list empties.
|
||||
const myStashesIndex = hasOwnValidators
|
||||
? (selectedIndex ?? 0)
|
||||
: 1;
|
||||
const [eraSelectionIndex, setEraSelectionIndex] = useState(0);
|
||||
const eraLength = useCall<BN>(api.derive.session.eraLength);
|
||||
const blockTime = useBlockInterval();
|
||||
@ -226,7 +231,7 @@ function Payouts ({ className = '', historyDepth, isInElection, ownPools, ownVal
|
||||
<StyledDiv className={className}>
|
||||
<Button.Group>
|
||||
<ToggleGroup
|
||||
onChange={setMyStashesIndex}
|
||||
onChange={setSelectedIndex}
|
||||
options={valOptions}
|
||||
value={myStashesIndex}
|
||||
/>
|
||||
|
||||
@ -162,8 +162,13 @@ function getOptions (blockTime: BN, eraLength: BN | undefined, historyDepth: BN
|
||||
function Payouts ({ className = '', historyDepth, isInElection, ownPools, ownValidators }: Props): React.ReactElement<Props> {
|
||||
const { t } = useTranslation();
|
||||
const { api } = useApi();
|
||||
const [hasOwnValidators] = useState(() => ownValidators.length !== 0);
|
||||
const [myStashesIndex, setMyStashesIndex] = useState(() => hasOwnValidators ? 0 : 1);
|
||||
const [selectedIndex, setSelectedIndex] = useState<number | undefined>();
|
||||
const hasOwnValidators = ownValidators.length !== 0;
|
||||
// "Own validators" (index 0) is disabled when there are none. Testing that before
|
||||
// `selectedIndex` means we neither default to it, nor stay on it if the list empties.
|
||||
const myStashesIndex = hasOwnValidators
|
||||
? (selectedIndex ?? 0)
|
||||
: 1;
|
||||
const [eraSelectionIndex, setEraSelectionIndex] = useState(0);
|
||||
const eraLength = useCall<BN>(api.derive.session.eraLength);
|
||||
const blockTime = useBlockInterval();
|
||||
@ -229,7 +234,7 @@ function Payouts ({ className = '', historyDepth, isInElection, ownPools, ownVal
|
||||
<StyledDiv className={className}>
|
||||
<Button.Group>
|
||||
<ToggleGroup
|
||||
onChange={setMyStashesIndex}
|
||||
onChange={setSelectedIndex}
|
||||
options={valOptions}
|
||||
value={myStashesIndex}
|
||||
/>
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
// Copyright 2017-2026 @polkadot/react-hooks authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import type { Option } from '@polkadot/types';
|
||||
import type { Nominations, ValidatorPrefs } from '@polkadot/types/interfaces';
|
||||
import type { KeyringJson$Meta } from '@polkadot/ui-keyring/types';
|
||||
import type { HexString } from '@polkadot/util/types';
|
||||
@ -11,7 +12,6 @@ import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { keyring } from '@polkadot/ui-keyring';
|
||||
import { isFunction, isHex } from '@polkadot/util';
|
||||
|
||||
import { isEmpty } from './utils/isEmpty.js';
|
||||
import { createNamedHook } from './createNamedHook.js';
|
||||
import { useApi } from './useApi.js';
|
||||
import { useCall } from './useCall.js';
|
||||
@ -45,7 +45,7 @@ function useAccountInfoImpl (value: string | null, isContract = false): UseAccou
|
||||
const { accounts: { isAccount }, addresses: { isAddress } } = useKeyring();
|
||||
const accountInfo = useDeriveAccountInfo(value);
|
||||
const accountFlags = useDeriveAccountFlags(value);
|
||||
const nominator = useCall<Nominations>(api.query.staking?.nominators, [value]);
|
||||
const nominator = useCall<Option<Nominations>>(api.query.staking?.nominators, [value]);
|
||||
const validator = useCall<ValidatorPrefs>(api.query.staking?.validators, [value]);
|
||||
const [accountIndex, setAccountIndex] = useState<string | undefined>(undefined);
|
||||
const [tags, setSortedTags] = useState<string[]>([]);
|
||||
@ -57,17 +57,20 @@ function useAccountInfoImpl (value: string | null, isContract = false): UseAccou
|
||||
const [isEditingName, toggleIsEditingName, setIsEditingName] = useToggle();
|
||||
const [isEditingTags, toggleIsEditingTags, setIsEditingTags] = useToggle();
|
||||
|
||||
// `staking.validators` is a ValueQuery map, so a non-validator reads as the default
|
||||
// prefs - only `isStorageFallback` separates them (`undefined` when the entry exists)
|
||||
useEffect((): void => {
|
||||
validator && setFlags((flags) => ({
|
||||
...flags,
|
||||
isValidator: !isEmpty(validator)
|
||||
isValidator: !validator.isStorageFallback
|
||||
}));
|
||||
}, [validator]);
|
||||
|
||||
// `staking.nominators` is an OptionQuery map, so absence shows on the value itself
|
||||
useEffect((): void => {
|
||||
nominator && setFlags((flags) => ({
|
||||
...flags,
|
||||
isNominator: !isEmpty(nominator)
|
||||
isNominator: !nominator.isNone
|
||||
}));
|
||||
}, [nominator]);
|
||||
|
||||
|
||||
@ -12,7 +12,6 @@ import { useEffect, useMemo, useState } from 'react';
|
||||
|
||||
import { u8aConcat, u8aToHex } from '@polkadot/util';
|
||||
|
||||
import { isEmpty } from './utils/isEmpty.js';
|
||||
import { createNamedHook } from './createNamedHook.js';
|
||||
import { useAccounts } from './useAccounts.js';
|
||||
import { useApi } from './useApi.js';
|
||||
@ -38,7 +37,9 @@ const QUERY_OPTS = {
|
||||
|
||||
function getStakerState (stashId: string, allAccounts: string[], [isOwnStash, { claimedRewardsEras, controllerId: _controllerId, exposureMeta, exposurePaged, nextSessionIds: _nextSessionIds, nominators, rewardDestination, sessionIds: _sessionIds, stakingLedger, validatorPrefs }, validateInfo]: [boolean, DeriveStakingAccount, ValidatorInfo]): StakerState {
|
||||
const isStashNominating = !!(nominators?.length);
|
||||
const isStashValidating = !(Array.isArray(validateInfo) ? isEmpty(validateInfo[1] as ValidatorPrefs) : isEmpty(validateInfo));
|
||||
// `staking.validators` is a ValueQuery map, so a non-validator reads as the default
|
||||
// prefs - only `isStorageFallback` separates them (`undefined` when the entry exists)
|
||||
const isStashValidating = !validateInfo.isStorageFallback;
|
||||
const nextSessionIds = _nextSessionIds instanceof Map
|
||||
? [..._nextSessionIds.values()]
|
||||
: _nextSessionIds;
|
||||
|
||||
@ -1,16 +0,0 @@
|
||||
// Copyright 2017-2026 @polkadot/react-hooks authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import type { Struct } from '@polkadot/types-codec';
|
||||
|
||||
export const isEmpty = (struct: Struct) => {
|
||||
if (struct.values) {
|
||||
for (const v of struct.values()) {
|
||||
if (!v.isEmpty) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
Loading…
Reference in New Issue
Block a user