Limit operator exposure by default (#4036)
This commit is contained in:
parent
e432067ace
commit
cdb7a255d7
@ -32,13 +32,22 @@ interface Props {
|
||||
withIdentity: boolean;
|
||||
}
|
||||
|
||||
function checkIdentity (api: ApiPromise, accountInfo: DeriveAccountInfo): boolean {
|
||||
function checkIdentity (api: ApiPromise, accountInfo: DeriveAccountInfo): [boolean, string | null] {
|
||||
let hasIdentity = false;
|
||||
let parentId: string | null = null;
|
||||
|
||||
const { accountId, identity, nickname } = accountInfo;
|
||||
|
||||
if (accountId) {
|
||||
parentId = accountId.toString();
|
||||
}
|
||||
|
||||
if (api.query.identity && api.query.identity.identityOf) {
|
||||
hasIdentity = !!(identity?.display && identity.display.toString());
|
||||
|
||||
if (identity.parent) {
|
||||
parentId = identity.parent.toString();
|
||||
}
|
||||
} else if (nickname) {
|
||||
hasIdentity = !!nickname.toString();
|
||||
}
|
||||
@ -49,7 +58,7 @@ function checkIdentity (api: ApiPromise, accountInfo: DeriveAccountInfo): boolea
|
||||
hasIdentity = !!account?.meta?.name;
|
||||
}
|
||||
|
||||
return hasIdentity;
|
||||
return [hasIdentity, parentId];
|
||||
}
|
||||
|
||||
function Validator ({ allSlashes, canSelect, filterName, info, isNominated, isSelected, toggleFavorite, toggleSelected, withElected, withIdentity }: Props): React.ReactElement<Props> | null {
|
||||
@ -59,7 +68,10 @@ function Validator ({ allSlashes, canSelect, filterName, info, isNominated, isSe
|
||||
|
||||
useEffect((): void => {
|
||||
if (accountInfo) {
|
||||
info.hasIdentity = checkIdentity(api, accountInfo);
|
||||
const [hasIdentity, parentId] = checkIdentity(api, accountInfo);
|
||||
|
||||
info.hasIdentity = hasIdentity;
|
||||
info.parentId = parentId;
|
||||
}
|
||||
}, [api, accountInfo, info]);
|
||||
|
||||
|
||||
@ -5,6 +5,7 @@ import { DeriveStakingOverview } from '@polkadot/api-derive/types';
|
||||
import { StakerState } from '@polkadot/react-hooks/types';
|
||||
import { SortedTargets, TargetSortBy, ValidatorInfo } from '../types';
|
||||
|
||||
import BN from 'bn.js';
|
||||
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { Button, Icon, InputBalance, Table, Toggle } from '@polkadot/react-components';
|
||||
@ -28,6 +29,11 @@ interface Props {
|
||||
toggleFavorite: (address: string) => void;
|
||||
}
|
||||
|
||||
interface Flags {
|
||||
withIdentity: boolean;
|
||||
withGroup: boolean;
|
||||
}
|
||||
|
||||
interface SortState {
|
||||
sortBy: TargetSortBy;
|
||||
sortFromMax: boolean;
|
||||
@ -64,6 +70,28 @@ function extractNominees (ownNominators: StakerState[] = []): string[] {
|
||||
return myNominees;
|
||||
}
|
||||
|
||||
function selectProfitable (maxPaid: BN, list: ValidatorInfo[], { withGroup, withIdentity }: Flags): string[] {
|
||||
const parentIds: (string | null)[] = [];
|
||||
const result: string[] = [];
|
||||
|
||||
for (let i = 0; i < list.length && result.length < MAX_NOMINATIONS; i++) {
|
||||
const { hasIdentity, isElected, isFavorite, key, numNominators, parentId, rewardPayout } = list[i];
|
||||
|
||||
if (
|
||||
(!withIdentity || hasIdentity) &&
|
||||
(isElected || isFavorite) &&
|
||||
!rewardPayout.isZero() &&
|
||||
(!maxPaid || maxPaid.gtn(numNominators)) &&
|
||||
(!withGroup || (isFavorite || !parentIds.includes(parentId)))
|
||||
) {
|
||||
result.push(key);
|
||||
parentId && parentIds.push(parentId);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
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();
|
||||
@ -72,6 +100,7 @@ function Targets ({ className = '', isInElection, ownStashes, targets: { avgStak
|
||||
const [selected, setSelected] = useState<string[]>([]);
|
||||
const [nameFilter, setNameFilter] = useState<string>('');
|
||||
const [withElected, setWithElected] = useState(false);
|
||||
const [withGroup, setWithGroup] = useState(true);
|
||||
const [withIdentity, setWithIdentity] = useState(false);
|
||||
const [{ sortBy, sortFromMax }, setSortBy] = useState<SortState>({ sortBy: 'rankOverall', sortFromMax: true });
|
||||
const [sorted, setSorted] = useState<number[] | undefined>();
|
||||
@ -108,18 +137,12 @@ function Targets ({ className = '', isInElection, ownStashes, targets: { avgStak
|
||||
);
|
||||
|
||||
const _selectProfitable = useCallback(
|
||||
() => setSelected((): string[] => {
|
||||
const max = api.consts.staking?.maxNominatorRewardedPerValidator;
|
||||
|
||||
return (validators || []).reduce((result: string[], { hasIdentity, isElected, isFavorite, key, numNominators, rewardPayout }): string[] => {
|
||||
if ((result.length < MAX_NOMINATIONS) && (hasIdentity || !withIdentity) && (isElected || isFavorite) && !rewardPayout.isZero() && (!max || max.gtn(numNominators))) {
|
||||
result.push(key);
|
||||
}
|
||||
|
||||
return result;
|
||||
}, []);
|
||||
}),
|
||||
[api, validators, withIdentity]
|
||||
() => setSelected(selectProfitable(
|
||||
api.consts.staking.maxNominatorRewardedPerValidator,
|
||||
validators || [],
|
||||
{ withGroup, withIdentity }
|
||||
)),
|
||||
[api, validators, withGroup, withIdentity]
|
||||
);
|
||||
|
||||
const labelsRef = useRef({
|
||||
@ -162,6 +185,12 @@ function Targets ({ className = '', isInElection, ownStashes, targets: { avgStak
|
||||
setWithIdentity={setWithIdentity}
|
||||
withIdentity={withIdentity}
|
||||
>
|
||||
<Toggle
|
||||
className='staking--buttonToggle'
|
||||
label={t<string>('limit single operator exposure')}
|
||||
onChange={setWithGroup}
|
||||
value={withGroup}
|
||||
/>
|
||||
<Toggle
|
||||
className='staking--buttonToggle'
|
||||
label={t<string>('limit to elected')}
|
||||
@ -171,7 +200,7 @@ function Targets ({ className = '', isInElection, ownStashes, targets: { avgStak
|
||||
</Filtering>
|
||||
</div>
|
||||
)
|
||||
), [calcWith, setCalcWith, nameFilter, sorted, t, withElected, withIdentity]);
|
||||
), [calcWith, setCalcWith, nameFilter, sorted, t, withElected, withGroup, withIdentity]);
|
||||
|
||||
return (
|
||||
<div className={className}>
|
||||
|
||||
@ -54,6 +54,7 @@ export interface ValidatorInfo extends ValidatorInfoRank {
|
||||
isNominating: boolean;
|
||||
key: string;
|
||||
numNominators: number;
|
||||
parentId: string | null;
|
||||
rewardPayout: BN;
|
||||
rewardSplit: BN;
|
||||
validatorPayment: BN;
|
||||
|
||||
@ -108,6 +108,7 @@ function extractSingle (allAccounts: string[], amount: BN = baseBalance(), { inf
|
||||
isNominating,
|
||||
key,
|
||||
numNominators: (exposure.others || []).length,
|
||||
parentId: null,
|
||||
rankBondOther: 0,
|
||||
rankBondOwn: 0,
|
||||
rankBondTotal: 0,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user