Oversubscriptions by size index (#3573)
This commit is contained in:
parent
095caddd29
commit
d78770a094
@ -4,7 +4,9 @@
|
||||
|
||||
import React from 'react';
|
||||
import { AddressMini, Expander } from '@polkadot/react-components';
|
||||
import { useApi } from '@polkadot/react-hooks';
|
||||
|
||||
import { MAX_NOM_PAYOUTS } from '../../constants';
|
||||
import { useTranslation } from '../../translate';
|
||||
import useInactives from '../useInactives';
|
||||
|
||||
@ -15,13 +17,16 @@ interface Props {
|
||||
|
||||
function ListNominees ({ nominating, stashId }: Props): React.ReactElement<Props> {
|
||||
const { t } = useTranslation();
|
||||
const { api } = useApi();
|
||||
const { nomsActive, nomsChilled, nomsInactive, nomsOver, nomsWaiting } = useInactives(stashId, nominating);
|
||||
|
||||
const max = (api.consts.staking?.maxNominatorRewardedPerValidator || MAX_NOM_PAYOUTS).toString();
|
||||
|
||||
return (
|
||||
<>
|
||||
{nomsOver && nomsOver.length !== 0 && (
|
||||
<Expander
|
||||
help={t<string>('The validators that are over-subscribed, only the top 64 backing stake will be rewarded.')}
|
||||
help={t<string>('These validators are active but only the top {{max}} nominators by backing stake will be receiving rewards. The nominating stash is not one of those to be rewarded in the current era.', { replace: max })}
|
||||
summary={t<string>('Oversubscribed nominations ({{count}})', { replace: { count: nomsOver.length } })}
|
||||
>
|
||||
{nomsOver.map((nomineeId, index): React.ReactNode => (
|
||||
|
||||
@ -6,9 +6,12 @@ import { DeriveSessionIndexes } from '@polkadot/api-derive/types';
|
||||
import { EraIndex, Exposure, Nominations, SlashingSpans } from '@polkadot/types/interfaces';
|
||||
|
||||
import { useEffect, useState } from 'react';
|
||||
import { ApiPromise } from '@polkadot/api';
|
||||
import { useApi, useCall, useIsMountedRef } from '@polkadot/react-hooks';
|
||||
import { Option } from '@polkadot/types';
|
||||
|
||||
import { MAX_NOM_PAYOUTS } from '../constants';
|
||||
|
||||
interface Inactives {
|
||||
nomsActive?: string[];
|
||||
nomsChilled?: string[];
|
||||
@ -17,7 +20,9 @@ interface Inactives {
|
||||
nomsWaiting?: string[];
|
||||
}
|
||||
|
||||
function extractState (stashId: string, slashes: Option<SlashingSpans>[], nominees: string[], activeEra: EraIndex, submittedIn: EraIndex, exposures: Exposure[]): Inactives {
|
||||
function extractState (api: ApiPromise, stashId: string, slashes: Option<SlashingSpans>[], nominees: string[], activeEra: EraIndex, submittedIn: EraIndex, exposures: Exposure[]): Inactives {
|
||||
const max = (api.consts.staking?.maxNominatorRewardedPerValidator || MAX_NOM_PAYOUTS);
|
||||
|
||||
// chilled
|
||||
const nomsChilled = nominees.filter((_, index): boolean => {
|
||||
if (slashes[index].isNone) {
|
||||
@ -31,10 +36,11 @@ function extractState (stashId: string, slashes: Option<SlashingSpans>[], nomine
|
||||
|
||||
// all nominations that are oversubscribed
|
||||
const nomsOver = exposures
|
||||
.map((exposure, index) =>
|
||||
exposure.others.length > 64
|
||||
? nominees[index]
|
||||
: null
|
||||
.map(({ others }) => others.sort((a, b) => b.value.unwrap().cmp(a.value.unwrap())))
|
||||
.map((others, index) =>
|
||||
max.gtn(others.map(({ who }) => who.toString()).indexOf(stashId))
|
||||
? null
|
||||
: nominees[index]
|
||||
)
|
||||
.filter((nominee): nominee is string => !!nominee && !nomsChilled.includes(nominee));
|
||||
|
||||
@ -98,7 +104,7 @@ export default function useInactives (stashId: string, nominees?: string[]): Ina
|
||||
const slashes = exposuresAndSpans.slice(nominees.length) as Option<SlashingSpans>[];
|
||||
|
||||
mountedRef.current && setState(
|
||||
extractState(stashId, slashes, nominees, indexes.activeEra, optNominators.unwrapOrDefault().submittedIn, exposures)
|
||||
extractState(api, stashId, slashes, nominees, indexes.activeEra, optNominators.unwrapOrDefault().submittedIn, exposures)
|
||||
);
|
||||
}
|
||||
)
|
||||
|
||||
@ -5,7 +5,9 @@
|
||||
import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { Badge, Icon } from '@polkadot/react-components';
|
||||
import { useApi } from '@polkadot/react-hooks';
|
||||
|
||||
import { MAX_NOM_PAYOUTS } from './constants';
|
||||
import { useTranslation } from './translate';
|
||||
|
||||
interface Props {
|
||||
@ -14,6 +16,7 @@ interface Props {
|
||||
|
||||
function Ledgend ({ className }: Props): React.ReactElement<Props> {
|
||||
const { t } = useTranslation();
|
||||
const { api } = useApi();
|
||||
|
||||
return (
|
||||
<div className={className}>
|
||||
@ -48,7 +51,7 @@ function Ledgend ({ className }: Props): React.ReactElement<Props> {
|
||||
<span>
|
||||
<Badge
|
||||
color='red'
|
||||
info='64'
|
||||
info={(api.consts.staking?.maxNominatorRewardedPerValidator || MAX_NOM_PAYOUTS).toString()}
|
||||
/>
|
||||
{t('Oversubscribed')}
|
||||
</span>
|
||||
|
||||
@ -4,22 +4,27 @@
|
||||
|
||||
import React from 'react';
|
||||
import { Badge } from '@polkadot/react-components';
|
||||
import { useApi } from '@polkadot/react-hooks';
|
||||
|
||||
import { MAX_PAYOUTS } from './constants';
|
||||
import { MAX_NOM_PAYOUTS } from './constants';
|
||||
|
||||
interface Props {
|
||||
numNominators?: number;
|
||||
}
|
||||
|
||||
function MaxBadge ({ numNominators }: Props): React.ReactElement<Props> | null {
|
||||
if (!numNominators || (numNominators < MAX_PAYOUTS)) {
|
||||
const { api } = useApi();
|
||||
|
||||
const max = (api.consts.staking?.maxNominatorRewardedPerValidator || MAX_NOM_PAYOUTS);
|
||||
|
||||
if (!numNominators || max.gtn(numNominators)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Badge
|
||||
color='red'
|
||||
info='64'
|
||||
info={max.toString()}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@ -9,11 +9,11 @@ import { SortedTargets, TargetSortBy, ValidatorInfo } from '../types';
|
||||
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { Button, Icon, InputBalance, Table, Toggle } from '@polkadot/react-components';
|
||||
import { useAvailableSlashes } from '@polkadot/react-hooks';
|
||||
import { useApi, useAvailableSlashes } from '@polkadot/react-hooks';
|
||||
|
||||
import ElectionBanner from '../ElectionBanner';
|
||||
import Filtering from '../Filtering';
|
||||
import { MAX_NOMINATIONS } from '../constants';
|
||||
import { MAX_NOMINATIONS, MAX_NOM_PAYOUTS } from '../constants';
|
||||
import { useTranslation } from '../translate';
|
||||
import Nominate from './Nominate';
|
||||
import Summary from './Summary';
|
||||
@ -67,6 +67,7 @@ function extractNominees (ownNominators: StakerState[] = []): string[] {
|
||||
|
||||
function Targets ({ className = '', isInElection, ownStashes, targets: { avgStaked, calcWith, lastReward, lowStaked, nominators, setCalcWith, totalStaked, validators }, toggleFavorite }: Props): React.ReactElement<Props> {
|
||||
const { t } = useTranslation();
|
||||
const { api } = useApi();
|
||||
const allSlashes = useAvailableSlashes();
|
||||
const ownNominators = useOwnNominators(ownStashes);
|
||||
const [selected, setSelected] = useState<string[]>([]);
|
||||
@ -110,14 +111,14 @@ function Targets ({ className = '', isInElection, ownStashes, targets: { avgStak
|
||||
const _selectProfitable = useCallback(
|
||||
() => setSelected(
|
||||
(validators || []).reduce((result: string[], { hasIdentity, isElected, isFavorite, key, numNominators, rewardPayout }): string[] => {
|
||||
if ((numNominators < 64) && (result.length < MAX_NOMINATIONS) && (hasIdentity || !withIdentity) && (isElected || isFavorite) && !rewardPayout.isZero()) {
|
||||
if ((api.consts.staking?.maxNominatorRewardedPerValidator || MAX_NOM_PAYOUTS).gtn(numNominators) && (result.length < MAX_NOMINATIONS) && (hasIdentity || !withIdentity) && (isElected || isFavorite) && !rewardPayout.isZero()) {
|
||||
result.push(key);
|
||||
}
|
||||
|
||||
return result;
|
||||
}, [])
|
||||
),
|
||||
[validators, withIdentity]
|
||||
[api, validators, withIdentity]
|
||||
);
|
||||
|
||||
const labels = useMemo(
|
||||
|
||||
@ -2,8 +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 BN from 'bn.js';
|
||||
|
||||
export const MAX_NOMINATIONS = 16;
|
||||
|
||||
export const MAX_PAYOUTS = 64;
|
||||
export const MAX_NOM_PAYOUTS = new BN(64);
|
||||
|
||||
export const STORE_FAVS_BASE = 'staking:favorites';
|
||||
|
||||
Loading…
Reference in New Issue
Block a user