Staking RPC & UI optimizations (#1833)

* Staking query optimization

* Final roundup

* Bump API with new derive  interfaces
This commit is contained in:
Jaco Greeff 2019-11-02 23:54:23 +01:00 committed by GitHub
parent 232eea0bbe
commit e3bca04936
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 166 additions and 193 deletions

View File

@ -10,10 +10,10 @@
"packages/*"
],
"resolutions": {
"@polkadot/api": "^0.96.0-beta.21",
"@polkadot/api-contract": "^0.96.0-beta.21",
"@polkadot/api": "^0.96.0-beta.22",
"@polkadot/api-contract": "^0.96.0-beta.22",
"@polkadot/keyring": "^1.6.1",
"@polkadot/types": "^0.96.0-beta.21",
"@polkadot/types": "^0.96.0-beta.22",
"@polkadot/util": "^1.6.1",
"@polkadot/util-crypto": "^1.6.1",
"babel-core": "^7.0.0-bridge.0",

View File

@ -7,7 +7,7 @@ import { AccountId } from '@polkadot/types/interfaces';
import { BareProps, I18nProps } from '@polkadot/react-components/types';
import BN from 'bn.js';
import React, { useContext, useState, useEffect } from 'react';
import React, { useContext } from 'react';
import { ApiContext, withCalls } from '@polkadot/react-api';
import { Bubble, IdentityIcon } from '@polkadot/react-components';
import { formatBalance, formatNumber } from '@polkadot/util';
@ -18,23 +18,11 @@ interface Props extends BareProps, I18nProps {
balances_totalIssuance?: BN;
chain_bestNumber?: BN;
chain_bestNumberLag?: BN;
session_validators?: AccountId[];
staking_intentions?: AccountId[];
staking_validators?: AccountId[];
}
function SummaryBar ({ balances_totalIssuance, chain_bestNumber, chain_bestNumberLag, staking_intentions, session_validators }: Props): React.ReactElement<Props> {
function SummaryBar ({ balances_totalIssuance, chain_bestNumber, chain_bestNumberLag, staking_validators }: Props): React.ReactElement<Props> {
const { api, systemChain, systemName, systemVersion } = useContext(ApiContext);
const [nextUp, setNextUp] = useState<AccountId[]>([]);
useEffect((): void => {
if (staking_intentions && session_validators) {
setNextUp(staking_intentions.filter((accountId): boolean =>
!session_validators.find((validatorId): boolean =>
validatorId.eq(accountId)
)
));
}
}, [staking_intentions, session_validators]);
return (
<summary>
@ -51,16 +39,13 @@ function SummaryBar ({ balances_totalIssuance, chain_bestNumber, chain_bestNumbe
<Bubble icon='bullseye' label='best #'>
{formatNumber(chain_bestNumber)} ({formatNumber(chain_bestNumberLag)} lag)
</Bubble>
<Bubble icon='chess queen' label='validators'>{
(session_validators || []).map((accountId, index): React.ReactNode => (
<IdentityIcon key={index} value={accountId} size={20} />
))
}</Bubble>
<Bubble icon='chess bishop' label='next up'>{
nextUp.map((accountId, index): React.ReactNode => (
<IdentityIcon key={index} value={accountId} size={20} />
))
}</Bubble>
{staking_validators && (
<Bubble icon='chess queen' label='validators'>{
staking_validators.map((accountId, index): React.ReactNode => (
<IdentityIcon key={index} value={accountId} size={20} />
))
}</Bubble>
)}
<Bubble icon='circle' label='total tokens'>
{formatBalance(balances_totalIssuance)}
</Bubble>
@ -74,7 +59,7 @@ export default translate(
withCalls<Props>(
'derive.chain.bestNumber',
'derive.chain.bestNumberLag',
'query.balances.totalIssuance',
'query.session.validators'
'derive.staking.validators',
'query.balances.totalIssuance'
)(SummaryBar)
);

View File

@ -11,7 +11,7 @@
"license": "Apache-2.0",
"dependencies": {
"@babel/runtime": "^7.6.3",
"@polkadot/api-contract": "^0.96.0-beta.21",
"@polkadot/api-contract": "^0.96.0-beta.22",
"@polkadot/react-components": "^0.37.0-beta.34"
}
}

View File

@ -32,7 +32,7 @@ function Summary ({ t }: Props): React.ReactElement<Props> {
</CardSummary>
</section>
<section className='ui--media-large'>
<SummarySession />
<SummarySession withEra={false} />
</section>
<section>
<CardSummary label={t('finalized')}>

View File

@ -1,4 +1,3 @@
/* eslint-disable @typescript-eslint/camelcase */
// Copyright 2017-2019 @polkadot/app-explorer authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
@ -14,57 +13,57 @@ import translate from './translate';
import { formatNumber } from '@polkadot/util';
interface Props extends I18nProps {
session_info?: DerivedSessionInfo;
sessionInfo?: DerivedSessionInfo;
withEra?: boolean;
withSession?: boolean;
}
function renderSession ({ session_info, t, withSession = true }: Props): React.ReactNode {
if (!withSession || !session_info) {
function renderSession ({ sessionInfo, t, withSession = true }: Props): React.ReactNode {
if (!withSession || !sessionInfo) {
return null;
}
const label = session_info.isEpoch && session_info.sessionLength.gtn(1)
const label = sessionInfo.isEpoch && sessionInfo.sessionLength.gtn(1)
? t('epoch')
: t('session');
return session_info.sessionLength.gtn(0)
return sessionInfo.sessionLength.gtn(0)
? (
<CardSummary
label={label}
progress={{
total: session_info.sessionLength,
value: session_info.sessionProgress
total: sessionInfo.sessionLength,
value: sessionInfo.sessionProgress
}}
/>
)
: (
<CardSummary label={label}>
{formatNumber(session_info.currentIndex)}
{formatNumber(sessionInfo.currentIndex)}
</CardSummary>
);
}
function renderEra ({ session_info, t, withEra = true }: Props): React.ReactNode {
if (!withEra || !session_info) {
function renderEra ({ sessionInfo, t, withEra = true }: Props): React.ReactNode {
if (!withEra || !sessionInfo) {
return null;
}
const label = t('era');
return session_info.sessionLength.gtn(0)
return sessionInfo.sessionLength.gtn(0)
? (
<CardSummary
label={label}
progress={{
total: session_info && session_info.eraLength,
value: session_info && session_info.eraProgress
total: sessionInfo.eraLength,
value: sessionInfo.eraProgress
}}
/>
)
: (
<CardSummary label={label}>
{formatNumber(session_info.currentEra)}
{formatNumber(sessionInfo.currentEra)}
</CardSummary>
);
}
@ -80,6 +79,6 @@ function SummarySession (props: Props): React.ReactElement<Props> {
export default translate(
withCalls<Props>(
'derive.session.info'
['derive.session.info', { propName: 'sessionInfo' }]
)(SummarySession)
);

View File

@ -19,7 +19,7 @@ import { formatNumber } from '@polkadot/util';
import translate from '../translate';
interface Props extends I18nProps {
address: string;
address: AccountId | string;
authorsMap: Record<string, string>;
className?: string;
currentElected: string[];
@ -69,7 +69,7 @@ function Address ({ address, authorsMap, className, currentElected, defaultName,
useEffect((): void => {
if (stakingInfo) {
const { controllerId, nextSessionId, stakers, stashId } = stakingInfo;
const { controllerId, nextSessionIds, stakers, stashId } = stakingInfo;
const nominators = withNominations && stakers
? stakers.others.map(({ who, value }): [AccountId, Balance] => [who, value.unwrap()])
: [];
@ -87,7 +87,7 @@ function Address ({ address, authorsMap, className, currentElected, defaultName,
),
isSelected: !!(_stashId && currentElected && currentElected.includes(_stashId)),
nominators,
sessionId: nextSessionId && nextSessionId.toString(),
sessionId: nextSessionIds && nextSessionIds[0] && nextSessionIds[0].toString(),
stashId: _stashId
});
}

View File

@ -2,9 +2,9 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { DerivedHeartbeats } from '@polkadot/api-derive/types';
import { AccountId } from '@polkadot/types/interfaces';
import { DerivedHeartbeats, DerivedStakingOverview } from '@polkadot/api-derive/types';
import { I18nProps } from '@polkadot/react-components/types';
import { EraPoints } from '@polkadot/types/interfaces';
import { ValidatorFilter } from '../types';
import React, { useContext, useEffect, useState } from 'react';
@ -16,27 +16,25 @@ import Address from './Address';
interface Props extends I18nProps {
authorsMap: Record<string, string>;
currentElected: string[];
currentValidators: string[];
eraPoints?: EraPoints;
lastAuthors?: string[];
next: string[];
recentlyOnline?: DerivedHeartbeats;
stakingOverview?: DerivedStakingOverview;
}
function renderColumn (addresses: string[], defaultName: string, withOnline: boolean, withPoints: boolean, filter: string, { authorsMap, currentElected, eraPoints, lastAuthors, recentlyOnline }: Props): React.ReactNode {
return addresses.map((address, index): React.ReactNode => (
function renderColumn (addresses: AccountId[] | string[], defaultName: string, withOnline: boolean, withPoints: boolean, filter: string, { authorsMap, lastAuthors, recentlyOnline, stakingOverview }: Props): React.ReactNode {
return (addresses as AccountId[]).map((address, index): React.ReactNode => (
<Address
address={address}
authorsMap={authorsMap}
currentElected={currentElected}
currentElected={stakingOverview && stakingOverview.currentElected}
defaultName={defaultName}
filter={filter}
lastAuthors={lastAuthors}
key={address}
key={address.toString()}
points={
withPoints && eraPoints
? eraPoints.individual[index]
withPoints && stakingOverview
? stakingOverview.eraPoints.individual[index]
: undefined
}
recentlyOnline={
@ -48,24 +46,26 @@ function renderColumn (addresses: string[], defaultName: string, withOnline: boo
));
}
function filterAccounts (list: string[] = [], without: string[]): string[] {
return list.filter((accountId): boolean => !without.includes(accountId));
function filterAccounts (list: string[] = [], without: AccountId[] | string[]): string[] {
return list.filter((accountId): boolean => !without.includes(accountId as any));
}
function CurrentList (props: Props): React.ReactElement<Props> {
const { isSubstrateV2 } = useContext(ApiContext);
const [filter, setFilter] = useState<ValidatorFilter>('all');
const [{ electedFiltered, nextFiltered }, setFiltered] = useState<{ electedFiltered: string[]; nextFiltered: string[] }>({ electedFiltered: [], nextFiltered: [] });
const { currentElected, currentValidators, next, t } = props;
const { next, stakingOverview, t } = props;
useEffect((): void => {
if (currentElected && currentValidators) {
if (stakingOverview) {
const elected = stakingOverview.currentElected.map((accountId): string => accountId.toString());
setFiltered({
electedFiltered: isSubstrateV2 ? filterAccounts(currentElected, currentValidators) : [],
nextFiltered: filterAccounts(next, currentElected)
electedFiltered: isSubstrateV2 ? filterAccounts(elected, stakingOverview.validators) : [],
nextFiltered: filterAccounts(next, elected)
});
}
}, [currentElected, currentValidators, next]);
}, [next, stakingOverview]);
return (
<div>
@ -90,7 +90,7 @@ function CurrentList (props: Props): React.ReactElement<Props> {
emptyText={t('No addresses found')}
headerText={t('validators')}
>
{renderColumn(currentValidators, t('validator'), true, true, filter, props)}
{stakingOverview && renderColumn(stakingOverview.validators, t('validator'), true, true, filter, props)}
</Column>
<Column
emptyText={t('No addresses found')}

View File

@ -3,40 +3,42 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { DerivedStakingOverview } from '@polkadot/api-derive/types';
import { I18nProps } from '@polkadot/react-components/types';
import BN from 'bn.js';
import React from 'react';
import styled from 'styled-components';
import SummarySession from '@polkadot/app-explorer/SummarySession';
import { CardSummary, IdentityIcon, SummaryBox } from '@polkadot/react-components';
import { withCalls, withMulti } from '@polkadot/react-api';
import translate from '../translate';
interface Props extends I18nProps {
allControllers: string[];
className?: string;
currentValidators: string[];
lastAuthors?: string[];
lastBlock: string;
staking_validatorCount?: BN;
lastBlock?: string;
next: string[];
stakingOverview?: DerivedStakingOverview;
}
function Summary ({ className, currentValidators, lastAuthors, lastBlock, next, style, staking_validatorCount, t }: Props): React.ReactElement<Props> {
function Summary ({ className, lastAuthors, lastBlock, next, stakingOverview, style, t }: Props): React.ReactElement<Props> {
return (
<SummaryBox
className={className}
style={style}
>
<section>
<CardSummary label={t('validators')}>
{currentValidators.length}/{staking_validatorCount ? staking_validatorCount.toString() : '-'}
</CardSummary>
<CardSummary label={t('waiting')}>
{next.length}
</CardSummary>
{stakingOverview && (
<CardSummary label={t('validators')}>
{stakingOverview.validators.length}{`/${stakingOverview.validatorCount.toString()}`}
</CardSummary>
)}
{next && (
<CardSummary label={t('waiting')}>
{next.length}
</CardSummary>
)}
</section>
<section>
<CardSummary
@ -61,7 +63,7 @@ function Summary ({ className, currentValidators, lastAuthors, lastBlock, next,
);
}
export default withMulti(
export default translate(
styled(Summary)`
.validator--Account-block-icon {
margin-right: 0.75rem;
@ -74,7 +76,5 @@ export default withMulti(
margin-left: -1.5rem;
}
}
`,
translate,
withCalls<Props>('query.staking.validatorCount')
`
);

View File

@ -4,7 +4,6 @@
// of the Apache-2.0 license. See the LICENSE file for details.
import { BareProps } from '@polkadot/react-components/types';
import { EraPoints } from '@polkadot/types/interfaces';
import { ComponentProps } from '../types';
import React, { useContext, useEffect, useState } from 'react';
@ -14,43 +13,39 @@ import { BlockAuthorsContext } from '@polkadot/react-query';
import CurrentList from './CurrentList';
import Summary from './Summary';
interface Props extends BareProps, ComponentProps {
eraPoints?: EraPoints;
}
interface Props extends BareProps, ComponentProps {}
export default function Overview ({ allControllers, allStashes, currentElected, currentValidators, eraPoints, recentlyOnline }: Props): React.ReactElement<Props> {
export default function Overview ({ allControllers, allStashes, recentlyOnline, stakingOverview }: Props): React.ReactElement<Props> {
const { isSubstrateV2 } = useContext(ApiContext);
const { byAuthor, lastBlockAuthors, lastBlockNumber } = useContext(BlockAuthorsContext);
const [next, setNext] = useState<string[]>([]);
const validators = stakingOverview && stakingOverview.validators;
useEffect((): void => {
setNext(
validators && setNext(
isSubstrateV2
// this is a V2 node currentValidators is a list of stashes
? allStashes.filter((address): boolean => !currentValidators.includes(address))
? allStashes.filter((address): boolean => !validators.includes(address as any))
// this is a V1 node currentValidators is a list of controllers
: allControllers.filter((address): boolean => !currentValidators.includes(address))
: allControllers.filter((address): boolean => !validators.includes(address as any))
);
}, [allControllers, allStashes, currentValidators]);
}, [allControllers, allStashes, validators]);
return (
<div className='staking--Overview'>
<Summary
allControllers={allControllers}
currentElected={currentElected}
currentValidators={currentValidators}
lastBlock={lastBlockNumber}
lastAuthors={lastBlockAuthors}
next={next}
stakingOverview={stakingOverview}
/>
<CurrentList
authorsMap={byAuthor}
currentElected={currentElected}
currentValidators={currentValidators}
eraPoints={eraPoints}
lastAuthors={lastBlockAuthors}
next={next}
recentlyOnline={recentlyOnline}
stakingOverview={stakingOverview}
/>
</div>
);

View File

@ -2,10 +2,10 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { DerivedHeartbeats } from '@polkadot/api-derive/types';
import { DerivedHeartbeats, DerivedStakingOverview } from '@polkadot/api-derive/types';
import { AppProps, I18nProps } from '@polkadot/react-components/types';
import { ApiProps } from '@polkadot/react-api/types';
import { AccountId, BlockNumber, EraPoints } from '@polkadot/types/interfaces';
import { AccountId, BlockNumber } from '@polkadot/types/interfaces';
import { SubjectInfo } from '@polkadot/ui-keyring/observable/types';
import { ComponentProps } from './types';
@ -27,16 +27,14 @@ interface Props extends AppProps, ApiProps, I18nProps {
allAccounts?: SubjectInfo;
allStashesAndControllers?: [string[], string[]];
bestNumber?: BlockNumber;
currentElected?: string[];
currentValidators?: string[];
eraPoints?: EraPoints;
recentlyOnline?: DerivedHeartbeats;
stakingOverview?: DerivedStakingOverview;
}
const EMPY_ACCOUNTS: string[] = [];
const EMPTY_ALL: [string[], string[]] = [EMPY_ACCOUNTS, EMPY_ACCOUNTS];
function App ({ allAccounts, allStashesAndControllers: [allStashes, allControllers] = EMPTY_ALL, className, currentElected, currentValidators, basePath, eraPoints, recentlyOnline, t }: Props): React.ReactElement<Props> {
function App ({ allAccounts, allStashesAndControllers: [allStashes, allControllers] = EMPTY_ALL, basePath, className, recentlyOnline, stakingOverview, t }: Props): React.ReactElement<Props> {
const _renderComponent = (Component: React.ComponentType<ComponentProps>): () => React.ReactNode => {
// eslint-disable-next-line react/display-name
return (): React.ReactNode => {
@ -49,10 +47,8 @@ function App ({ allAccounts, allStashesAndControllers: [allStashes, allControlle
allAccounts={allAccounts}
allControllers={allControllers}
allStashes={allStashes}
currentElected={currentElected || EMPY_ACCOUNTS}
currentValidators={currentValidators || EMPY_ACCOUNTS}
eraPoints={eraPoints}
recentlyOnline={recentlyOnline}
stakingOverview={stakingOverview}
/>
);
};
@ -108,18 +104,7 @@ export default withMulti(
.map((accountId): string => accountId.unwrap().toString())
]
}],
['query.session.validators', {
propName: 'currentValidators',
transform: (validators: AccountId[]): string[] =>
validators.map((accountId): string => accountId.toString())
}],
['query.staking.currentElected', {
propName: 'currentElected',
transform: (elected: AccountId[]): string[] =>
elected.map((accountId): string => accountId.toString())
}],
['query.staking.currentEra', { propName: 'currentEra' }],
['query.staking.currentEraPointsEarned', { paramName: 'currentEra', propName: 'eraPoints' }]
['derive.staking.overview', { propName: 'stakingOverview' }]
),
withObservable(accountObservable.subject, { propName: 'allAccounts' })
);

View File

@ -2,20 +2,25 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { DerivedFees, DerivedBalances, DerivedHeartbeats } from '@polkadot/api-derive/types';
import { DerivedFees, DerivedBalances, DerivedHeartbeats, DerivedStakingOverview } from '@polkadot/api-derive/types';
import { SubjectInfo } from '@polkadot/ui-keyring/observable/types';
import { EraPoints } from '@polkadot/types/interfaces';
import { u32 } from '@polkadot/types';
export type Nominators = Record<string, string[]>;
export interface DerivedStakingOverviewExt {
currentElected: string[];
eraPointsEarned: EraPoints;
validatorCount: u32;
}
export interface ComponentProps {
allAccounts?: SubjectInfo;
allControllers: string[];
allStashes: string[];
currentElected: string[];
currentValidators: string[];
eraPoints?: EraPoints;
recentlyOnline?: DerivedHeartbeats;
stakingOverview?: DerivedStakingOverview;
}
export interface CalculateBalanceProps {

View File

@ -97,14 +97,16 @@ function getCachedComponent (query: QueryTypes): CacheInstance {
paramName: 'params',
paramValid: true,
params: [[key]],
transform: ([data]: Option<Data>[]): Option<Data> => data
transform: ([data]: Option<Data>[]): Option<Data> => data,
withIndicator: true
});
} else {
// render function to create an element for the query results which is plugged to the api
renderHelper = withCallDiv('subscribe', {
paramName: 'params',
paramValid: true,
params: [key, ...values]
params: [key, ...values],
withIndicator: true
});
}

View File

@ -58,11 +58,8 @@ function Modules ({ onAdd, t }: Props): React.ReactElement<Props> {
const isLinked = isMap && key.creator.meta.type.asMap.linked.isTrue;
setKey({
defaultValues: key.creator.section === 'session'
? [{
isValid: true,
value: api.consts.session.dedupKeyPrefix.toHex()
}]
defaultValues: key.creator.section === 'session' && key.creator.meta.type.isDoubleMap
? [{ isValid: true, value: api.consts.session.dedupKeyPrefix.toHex() }]
: null,
isLinked,
key,

View File

@ -37,7 +37,7 @@ function Placeholder (): React.ReactElement {
const WarmUp = withCalls<{}>(
'derive.accounts.indexes',
'derive.balances.fees',
'query.session.validators'
'derive.staking.overview'
// This are very ineffective queries that
// (a) adds load to the RPC node when activated globally
// (b) is used in additional information (next-up)

View File

@ -31,7 +31,7 @@
"homepage": "https://github.com/polkadot-js/ui/tree/master/packages/ui-reactive#readme",
"dependencies": {
"@babel/runtime": "^7.6.3",
"@polkadot/api": "^0.96.0-beta.21",
"@polkadot/api": "^0.96.0-beta.22",
"@polkadot/extension-dapp": "^0.14.0-beta.1",
"edgeware-node-types": "^1.0.10",
"rxjs-compat": "^6.5.3"

View File

@ -43,7 +43,8 @@ export default function withCall<P extends ApiProps> (endpoint: string, {
paramValid = false,
propName,
skipIf = NO_SKIP,
transform = echoTransform
transform = echoTransform,
withIndicator = false
}: Options = {}): (Inner: React.ComponentType<ApiProps>) => React.ComponentType<any> {
return (Inner: React.ComponentType<ApiProps>): React.ComponentType<SubtractProps<P, ApiProps>> => {
class WithPromise extends React.Component<P, State> {
@ -83,14 +84,17 @@ export default function withCall<P extends ApiProps> (endpoint: string, {
public componentDidMount (): void {
this.isActive = true;
this.timerId = window.setInterval((): void => {
const elapsed = Date.now() - (this.state.callUpdatedAt || 0);
const callUpdated = elapsed <= 1500;
if (callUpdated !== this.state.callUpdated) {
this.nextState({ callUpdated });
}
}, 500);
if (withIndicator) {
this.timerId = window.setInterval((): void => {
const elapsed = Date.now() - (this.state.callUpdatedAt || 0);
const callUpdated = elapsed <= 1500;
if (callUpdated !== this.state.callUpdated) {
this.nextState({ callUpdated });
}
}, 500);
}
// The attachment takes time when a lot is available, set a timeout
// to first handle the current queue before subscribing

View File

@ -26,6 +26,7 @@ export interface Options {
propName?: string;
skipIf?: (props: any) => boolean;
transform?: Transform;
withIndicator?: boolean;
}
export type RenderFn = (value?: any) => React.ReactNode;

View File

@ -17,9 +17,9 @@ import StatusContext from './Status/Context';
import translate from './translate';
interface Props extends IdentityProps, I18nProps {
session_validators?: AccountId[];
staking_bonded?: string | null;
system_name?: string;
validators?: AccountId[];
}
// overrides based on the actual software node type
@ -41,7 +41,7 @@ export function getIdentityTheme (systemName: string): 'empty' {
return ((uiSettings.icon === 'default' && NODES[systemName]) || uiSettings.icon) as 'empty';
}
function IdentityIcon ({ className, onCopy, prefix, session_validators, size, staking_bonded, style, t, theme, value }: Props): React.ReactElement<Props> {
function IdentityIcon ({ className, onCopy, prefix, size, staking_bonded, style, t, theme, validators, value }: Props): React.ReactElement<Props> {
const { systemName } = useContext(ApiContext);
const { queueAction } = useContext(StatusContext);
const [isValidator, setIsValidator] = useState(false);
@ -53,13 +53,13 @@ function IdentityIcon ({ className, onCopy, prefix, session_validators, size, st
: null;
setIsValidator(
session_validators
? session_validators.some((validator): boolean =>
validators
? validators.some((validator): boolean =>
[address, staking_bonded].includes(validator.toString())
)
: false
);
}, [session_validators, value]);
}, [validators, value]);
const _onCopy = (account: string): void => {
onCopy && onCopy(account);
@ -89,7 +89,7 @@ export default withMulti(
IdentityIcon,
translate,
withCalls<Props>(
'query.session.validators',
['derive.staking.validators', { propName: 'validators' }],
['query.staking.bonded', {
paramName: 'value',
transform: (bonded: Option<AccountId>): string | null =>

View File

@ -2016,45 +2016,45 @@
once "^1.4.0"
universal-user-agent "^4.0.0"
"@polkadot/api-contract@^0.96.0-beta.21":
version "0.96.0-beta.21"
resolved "https://registry.yarnpkg.com/@polkadot/api-contract/-/api-contract-0.96.0-beta.21.tgz#5d77e123bcf066dfc5c1eac17e923588ed92a5d7"
integrity sha512-ESeZq59QOwYCtkQSiwKB3FPKtAYvU/qN15jmEFAA6nKyCZpE8CHpeMANEEjKh5nreEv+W+GTEBSplZ63y5j/fQ==
"@polkadot/api-contract@^0.96.0-beta.22":
version "0.96.0-beta.22"
resolved "https://registry.yarnpkg.com/@polkadot/api-contract/-/api-contract-0.96.0-beta.22.tgz#04e166aad0b9a20ca04d4845ddcb3fadec844886"
integrity sha512-IodK2QdJevNmIDeWfqMmwDB2gUbMZjwKmHCZUtOxR6MeutTSTRr/KRJH4fKDQ9oCWRs8phPLcooo3ngQ/xSncg==
dependencies:
"@babel/runtime" "^7.6.3"
"@polkadot/types" "^0.96.0-beta.21"
"@polkadot/types" "^0.96.0-beta.22"
"@polkadot/api-derive@^0.96.0-beta.21":
version "0.96.0-beta.21"
resolved "https://registry.yarnpkg.com/@polkadot/api-derive/-/api-derive-0.96.0-beta.21.tgz#3d0a7bad14dd3a9d60fd810ec95af027176855b4"
integrity sha512-QxXRW/jI+9ExXMpqsNO+epuN5UGfuQbbmlHyDfzP49wRXuCnGatPDZ52ynRK3UBWB8hSKPgdTXFsoDFMPm6ILw==
"@polkadot/api-derive@^0.96.0-beta.22":
version "0.96.0-beta.22"
resolved "https://registry.yarnpkg.com/@polkadot/api-derive/-/api-derive-0.96.0-beta.22.tgz#a00d59e96f097b2ab0c0c65a9bf97bf9c7ea44aa"
integrity sha512-lRVC1hWSOYfQMcmOdudnhb7hzK6tsGY194WlytFzAGIzxLYz7FWrVfA3JnxfytMPEHyznsZC9RCTSMvPAXUv/g==
dependencies:
"@babel/runtime" "^7.6.3"
"@polkadot/api" "^0.96.0-beta.21"
"@polkadot/types" "^0.96.0-beta.21"
"@polkadot/api" "^0.96.0-beta.22"
"@polkadot/types" "^0.96.0-beta.22"
"@polkadot/api-metadata@^0.96.0-beta.21":
version "0.96.0-beta.21"
resolved "https://registry.yarnpkg.com/@polkadot/api-metadata/-/api-metadata-0.96.0-beta.21.tgz#18b52f27f10cc52cd38003d1990344adee4b57d1"
integrity sha512-b+kuEbl0Cpymv6jA9wYHT4NH2rpMre8scix/1LLN931mMBftGSJ24PHeOH5ZocmWH0krK6FK+u+NeQ58ZuEfxQ==
"@polkadot/api-metadata@^0.96.0-beta.22":
version "0.96.0-beta.22"
resolved "https://registry.yarnpkg.com/@polkadot/api-metadata/-/api-metadata-0.96.0-beta.22.tgz#8ba272f5ebe62cf2edab75ed9a554943fbce4316"
integrity sha512-MkxuohC9F01rg0z/F141ky9poSTVowExpmvUnaJwt//UDDLERwauZ+DCS0+7xao0z6a7ciLn32I0/xW6T9o0GQ==
dependencies:
"@babel/runtime" "^7.6.3"
"@polkadot/types" "^0.96.0-beta.21"
"@polkadot/types" "^0.96.0-beta.22"
"@polkadot/util" "^1.6.1"
"@polkadot/util-crypto" "^1.6.1"
"@polkadot/api@^0.96.0-beta.21":
version "0.96.0-beta.21"
resolved "https://registry.yarnpkg.com/@polkadot/api/-/api-0.96.0-beta.21.tgz#91fa6db7acbb7402005727c24be4898c4a6654b6"
integrity sha512-17dxU5KGT4bi+mrOlPvPFhpAKXvMBcJJQ6Uv3h67czCCmU3vC/bFZ7lrGNRIDytEXQouQbGZVlZLosi6gBsjow==
"@polkadot/api@^0.96.0-beta.22":
version "0.96.0-beta.22"
resolved "https://registry.yarnpkg.com/@polkadot/api/-/api-0.96.0-beta.22.tgz#d26a6ce18b4e1fd2df31bc065ac4adff48038bfa"
integrity sha512-V2wDDUXO/ld6Nw7Rf1qEl7v8pChy23/FAY1qbvQGMPWhjtnb9KTq49R7nuXneOVVXB0ESnTTZETzXQBWLndaQw==
dependencies:
"@babel/runtime" "^7.6.3"
"@polkadot/api-derive" "^0.96.0-beta.21"
"@polkadot/api-metadata" "^0.96.0-beta.21"
"@polkadot/api-derive" "^0.96.0-beta.22"
"@polkadot/api-metadata" "^0.96.0-beta.22"
"@polkadot/keyring" "^1.6.1"
"@polkadot/rpc-core" "^0.96.0-beta.21"
"@polkadot/rpc-provider" "^0.96.0-beta.21"
"@polkadot/types" "^0.96.0-beta.21"
"@polkadot/rpc-core" "^0.96.0-beta.22"
"@polkadot/rpc-provider" "^0.96.0-beta.22"
"@polkadot/types" "^0.96.0-beta.22"
"@polkadot/util-crypto" "^1.6.1"
"@polkadot/dev-react@^0.32.0-beta.12":
@ -2156,10 +2156,10 @@
dependencies:
"@babel/runtime" "^7.6.3"
"@polkadot/jsonrpc@^0.96.0-beta.21":
version "0.96.0-beta.21"
resolved "https://registry.yarnpkg.com/@polkadot/jsonrpc/-/jsonrpc-0.96.0-beta.21.tgz#d8873b2aa0cdff96727c9050060fcff8f649a151"
integrity sha512-5IAc9fF6rSX6LPWB+xGcDxS3Kc9JwvEf0DKwgKZRfjE4W56n6r5lrqDX/LoCZ3CYXw9N6UgTTKB5IPgBVAoHrQ==
"@polkadot/jsonrpc@^0.96.0-beta.22":
version "0.96.0-beta.22"
resolved "https://registry.yarnpkg.com/@polkadot/jsonrpc/-/jsonrpc-0.96.0-beta.22.tgz#38b3437b7f4f7eb4800d9d71623f1b0e8777cf94"
integrity sha512-EF7GbdIB+jFXiWzBkHatc65mOO4dVT8r9lpXYaWQzuqkZOHrotTYJC7DQ0V2n04fo4IKlJPyb0TKh3+3X6/FTw==
dependencies:
"@babel/runtime" "^7.6.3"
@ -2197,25 +2197,25 @@
qrcode-generator "^1.4.4"
react-qr-reader "^2.2.1"
"@polkadot/rpc-core@^0.96.0-beta.21":
version "0.96.0-beta.21"
resolved "https://registry.yarnpkg.com/@polkadot/rpc-core/-/rpc-core-0.96.0-beta.21.tgz#22932216658b8bfdd803c369af7ec5c73aca6b71"
integrity sha512-LRmNqB5eUjIr+DrvJp+X2o5+OXtsJg+y65SQ1ei0voj35VM1/OmiuxyqEWIKRKwna3BNBm3PbeQDaHepeaRc9g==
"@polkadot/rpc-core@^0.96.0-beta.22":
version "0.96.0-beta.22"
resolved "https://registry.yarnpkg.com/@polkadot/rpc-core/-/rpc-core-0.96.0-beta.22.tgz#fa0e9f2e3609eeb18c91bf6163dd3f3c1bfc94a1"
integrity sha512-JXO1XiJiqtXYotGp6oTOWuSqWiEyH6nnu1R5CwrZ/+ShTOWgbplPMv91F7qT0IktDY4rRZ9WLjy4xYE9yUSnEw==
dependencies:
"@babel/runtime" "^7.6.3"
"@polkadot/jsonrpc" "^0.96.0-beta.21"
"@polkadot/rpc-provider" "^0.96.0-beta.21"
"@polkadot/types" "^0.96.0-beta.21"
"@polkadot/jsonrpc" "^0.96.0-beta.22"
"@polkadot/rpc-provider" "^0.96.0-beta.22"
"@polkadot/types" "^0.96.0-beta.22"
"@polkadot/util" "^1.6.1"
rxjs "^6.5.3"
"@polkadot/rpc-provider@^0.96.0-beta.21":
version "0.96.0-beta.21"
resolved "https://registry.yarnpkg.com/@polkadot/rpc-provider/-/rpc-provider-0.96.0-beta.21.tgz#44ba559ce92053a007301066fa29a3964328e146"
integrity sha512-awGbWL3WEV59OKy7vtikEd6T6mg5qlTycbUt5MqagfaqjyZK3aIHRLq6L4Td3z1hDdtgIkYxajms0xhPvbt0FQ==
"@polkadot/rpc-provider@^0.96.0-beta.22":
version "0.96.0-beta.22"
resolved "https://registry.yarnpkg.com/@polkadot/rpc-provider/-/rpc-provider-0.96.0-beta.22.tgz#cb885efa65cbc1da3a42a19bed5a5acf0ffea50c"
integrity sha512-WGLWt9PLEY7wm6aOLrSMTz98vUXXzQ2iApOkK3acSzuPneRCqauqLLjM2AAnX9bpS/YY+Mk0DDDrvAMxOYj7WQ==
dependencies:
"@babel/runtime" "^7.6.3"
"@polkadot/api-metadata" "^0.96.0-beta.21"
"@polkadot/api-metadata" "^0.96.0-beta.22"
"@polkadot/util" "^1.6.1"
"@polkadot/util-crypto" "^1.6.1"
"@types/nock" "^11.1.0"
@ -2230,10 +2230,10 @@
dependencies:
"@types/chrome" "^0.0.91"
"@polkadot/types@^0.96.0-beta.21":
version "0.96.0-beta.21"
resolved "https://registry.yarnpkg.com/@polkadot/types/-/types-0.96.0-beta.21.tgz#d1a808076ed63d154597a26f1d7317d3a96bbd39"
integrity sha512-utrP6TkPda7MiNyYEO1dl4zhezvlPy01MKKb7NG08RcmqgkwEL582jiIW33DJi9YMVhurDvzpqHjGnXtNSlftw==
"@polkadot/types@^0.96.0-beta.22":
version "0.96.0-beta.22"
resolved "https://registry.yarnpkg.com/@polkadot/types/-/types-0.96.0-beta.22.tgz#40a343e4fe0ae03567b765481040e34edb54eeb2"
integrity sha512-eY2CGgJG8ytbJgI2bQOmDvyeQ0eorJtD2eE5BBsTYFNgMvIWvUmyBqgi3CTMS3zG7QM7M8PQUU1T98vG8qhSPg==
dependencies:
"@babel/runtime" "^7.6.3"
"@polkadot/util" "^1.6.1"