Small target opts (incl. non-selected sorting) (#4159)
* Small target opts (incl. non-selected sorting) * Remove last dangling validatorPayment
This commit is contained in:
parent
6bef8aa443
commit
f86cc1a689
@ -4,7 +4,11 @@
|
||||
import BN from 'bn.js';
|
||||
import React, { useMemo } from 'react';
|
||||
|
||||
import type { DeriveSessionIndexes } from '@polkadot/api-derive/types';
|
||||
import type { Option } from '@polkadot/types';
|
||||
import type { Balance } from '@polkadot/types/interfaces';
|
||||
import { CardSummary, SummaryBox } from '@polkadot/react-components';
|
||||
import { useApi, useCall } from '@polkadot/react-hooks';
|
||||
import { FormatBalance } from '@polkadot/react-query';
|
||||
|
||||
import { useTranslation } from '../translate';
|
||||
@ -12,7 +16,6 @@ import { useTranslation } from '../translate';
|
||||
interface Props {
|
||||
avgStaked?: BN;
|
||||
lowStaked?: BN;
|
||||
lastReward?: BN;
|
||||
numNominators?: number;
|
||||
numValidators?: number;
|
||||
stakedReturn: number;
|
||||
@ -20,8 +23,19 @@ interface Props {
|
||||
totalStaked?: BN;
|
||||
}
|
||||
|
||||
function Summary ({ avgStaked, lastReward, lowStaked, numNominators, numValidators, stakedReturn, totalIssuance, totalStaked }: Props): React.ReactElement<Props> {
|
||||
const transformReward = {
|
||||
transform: (optBalance: Option<Balance>) => optBalance.unwrapOrDefault()
|
||||
};
|
||||
|
||||
const transformEra = {
|
||||
transform: ({ activeEra }: DeriveSessionIndexes) => activeEra.gtn(0) ? activeEra.subn(1) : undefined
|
||||
};
|
||||
|
||||
function Summary ({ avgStaked, lowStaked, numNominators, numValidators, stakedReturn, totalIssuance, totalStaked }: Props): React.ReactElement<Props> {
|
||||
const { t } = useTranslation();
|
||||
const { api } = useApi();
|
||||
const lastEra = useCall<BN | undefined>(api.derive.session.indexes, undefined, transformEra);
|
||||
const lastReward = useCall<BN>(lastEra && api.query.staking.erasValidatorReward, [lastEra], transformReward);
|
||||
|
||||
const progressStake = useMemo(
|
||||
() => totalIssuance && totalStaked && totalStaked.gtn(0)
|
||||
|
||||
@ -67,7 +67,7 @@ function Validator ({ allSlashes, canSelect, filterName, info, isNominated, isSe
|
||||
return null;
|
||||
}
|
||||
|
||||
const { accountId, bondOther, bondOwn, bondTotal, commissionPer, isCommission, isElected, isFavorite, key, lastPayout, numNominators, rankOverall, stakedReturnCmp, validatorPayment } = info;
|
||||
const { accountId, bondOther, bondOwn, bondTotal, commissionPer, isCommission, isElected, isFavorite, key, lastPayout, numNominators, rankOverall, stakedReturnCmp } = info;
|
||||
|
||||
return (
|
||||
<tr>
|
||||
@ -125,13 +125,7 @@ function Validator ({ allSlashes, canSelect, filterName, info, isNominated, isSe
|
||||
</td>
|
||||
<td className='number media--1200 no-pad-right'>{numNominators || ''}</td>
|
||||
<td className='number media--1200 no-pad-left'>{nominatedBy.length || ''}</td>
|
||||
<td className='number media--1100'>
|
||||
{
|
||||
isCommission
|
||||
? `${commissionPer.toFixed(2)}%`
|
||||
: <FormatBalance value={validatorPayment} />
|
||||
}
|
||||
</td>
|
||||
<td className='number media--1100'>{isCommission && `${commissionPer.toFixed(2)}%`}</td>
|
||||
<td className='number together'>{!bondTotal.isZero() && <FormatBalance value={bondTotal} />}</td>
|
||||
<td className='number together media--900'>{!bondOwn.isZero() && <FormatBalance value={bondOwn} />}</td>
|
||||
<td className='number together media--1600'>{!bondOther.isZero() && <FormatBalance value={bondOther} />}</td>
|
||||
|
||||
@ -169,7 +169,7 @@ function selectProfitable (list: ValidatorInfo[]): string[] {
|
||||
return result;
|
||||
}
|
||||
|
||||
function Targets ({ className = '', isInElection, ownStashes, targets: { avgStaked, inflation: { stakedReturn }, lastReward, lowStaked, medianComm, nominators, totalIssuance, totalStaked, validatorIds, validators }, toggleFavorite }: Props): React.ReactElement<Props> {
|
||||
function Targets ({ className = '', isInElection, ownStashes, targets: { avgStaked, inflation: { stakedReturn }, lowStaked, medianComm, nominators, totalIssuance, totalStaked, validatorIds, validators }, toggleFavorite }: Props): React.ReactElement<Props> {
|
||||
const { t } = useTranslation();
|
||||
const { api } = useApi();
|
||||
const allSlashes = useAvailableSlashes();
|
||||
@ -270,7 +270,7 @@ function Targets ({ className = '', isInElection, ownStashes, targets: { avgStak
|
||||
<>{labelsRef.current[header]}<Icon icon={sortBy === header ? (sortFromMax ? 'chevron-down' : 'chevron-up') : 'minus'} /></>,
|
||||
`${sorted ? `isClickable ${sortBy === header ? 'highlight--border' : ''} number` : 'number'} ${CLASSES[header] || ''}`,
|
||||
1,
|
||||
() => _sort(header as 'rankComm')
|
||||
() => _sort(header as 'rankOverall')
|
||||
]),
|
||||
[],
|
||||
[]
|
||||
@ -337,7 +337,6 @@ function Targets ({ className = '', isInElection, ownStashes, targets: { avgStak
|
||||
<div className={className}>
|
||||
<Summary
|
||||
avgStaked={avgStaked}
|
||||
lastReward={lastReward}
|
||||
lowStaked={lowStaked}
|
||||
numNominators={nominators?.length}
|
||||
numValidators={validators?.length}
|
||||
|
||||
@ -38,10 +38,8 @@ interface ValidatorInfoRank {
|
||||
rankBondOther: number;
|
||||
rankBondOwn: number;
|
||||
rankBondTotal: number;
|
||||
rankComm: number;
|
||||
rankNumNominators: number;
|
||||
rankOverall: number;
|
||||
rankPayment: number;
|
||||
rankReward: number;
|
||||
}
|
||||
|
||||
@ -63,11 +61,9 @@ export interface ValidatorInfo extends ValidatorInfoRank {
|
||||
lastPayout?: BN;
|
||||
numNominators: number;
|
||||
numRecentPayouts: number;
|
||||
rewardSplit: BN;
|
||||
skipRewards: boolean;
|
||||
stakedReturn: number;
|
||||
stakedReturnCmp: number;
|
||||
validatorPayment: BN;
|
||||
validatorPrefs?: ValidatorPrefs | ValidatorPrefsTo196;
|
||||
}
|
||||
|
||||
@ -77,7 +73,6 @@ export interface SortedTargets {
|
||||
avgStaked?: BN;
|
||||
electedIds?: string[];
|
||||
inflation: Inflation;
|
||||
lastReward?: BN;
|
||||
lowStaked?: BN;
|
||||
medianComm: number;
|
||||
nominators?: string[];
|
||||
|
||||
@ -6,8 +6,6 @@ import { useMemo } from 'react';
|
||||
|
||||
import type { ApiPromise } from '@polkadot/api';
|
||||
import type { DeriveSessionInfo, DeriveStakingElected, DeriveStakingWaiting } from '@polkadot/api-derive/types';
|
||||
import type { Option } from '@polkadot/types';
|
||||
import type { Balance, ValidatorPrefsTo196 } from '@polkadot/types/interfaces';
|
||||
import { registry } from '@polkadot/react-api';
|
||||
import { calcInflation, useAccounts, useApi, useCall } from '@polkadot/react-hooks';
|
||||
import { BN_ONE, BN_ZERO } from '@polkadot/util';
|
||||
@ -18,11 +16,9 @@ interface LastEra {
|
||||
activeEra: BN;
|
||||
eraLength: BN;
|
||||
lastEra: BN;
|
||||
lastEraEnd: BN;
|
||||
sessionLength: BN;
|
||||
}
|
||||
|
||||
const PERBILL = new BN(1_000_000_000);
|
||||
const EMPTY_PARTIAL = {};
|
||||
|
||||
function mapIndex (mapBy: TargetSortBy): (info: ValidatorInfo, index: number) => ValidatorInfo {
|
||||
@ -62,24 +58,18 @@ function sortValidators (list: ValidatorInfo[]): ValidatorInfo[] {
|
||||
.map(mapIndex('rankBondOwn'))
|
||||
.sort((a, b) => b.bondTotal.cmp(a.bondTotal))
|
||||
.map(mapIndex('rankBondTotal'))
|
||||
.sort((a, b) => b.validatorPayment.cmp(a.validatorPayment))
|
||||
.map(mapIndex('rankPayment'))
|
||||
// .sort((a, b) => b.validatorPayment.cmp(a.validatorPayment))
|
||||
// .map(mapIndex('rankPayment'))
|
||||
.sort((a, b) => a.stakedReturnCmp - b.stakedReturnCmp)
|
||||
.map(mapIndex('rankReward'))
|
||||
// ignored, not used atm
|
||||
// .sort((a, b) => b.numNominators - a.numNominators)
|
||||
// .map(mapIndex('rankNumNominators'))
|
||||
.sort((a, b): number => {
|
||||
const cmp = b.stakedReturnCmp - a.stakedReturnCmp;
|
||||
|
||||
return cmp !== 0
|
||||
? cmp
|
||||
: a.rankReward === b.rankReward
|
||||
? a.rankPayment === b.rankPayment
|
||||
? b.rankBondTotal - a.rankBondTotal
|
||||
: b.rankPayment - a.rankPayment
|
||||
: b.rankReward - a.rankReward;
|
||||
})
|
||||
.sort((a, b) =>
|
||||
(b.stakedReturnCmp - a.stakedReturnCmp) ||
|
||||
(a.commissionPer - b.commissionPer) ||
|
||||
(b.rankBondTotal - a.rankBondTotal)
|
||||
)
|
||||
.map(mapIndex('rankOverall'))
|
||||
.sort((a, b) =>
|
||||
a.isFavorite === b.isFavorite
|
||||
@ -88,7 +78,7 @@ function sortValidators (list: ValidatorInfo[]): ValidatorInfo[] {
|
||||
);
|
||||
}
|
||||
|
||||
function extractSingle (allAccounts: string[], derive: DeriveStakingElected | DeriveStakingWaiting, favorites: string[], perValidatorReward: BN, { activeEra, eraLength, lastEra, sessionLength }: LastEra, historyDepth?: BN): [ValidatorInfo[], string[]] {
|
||||
function extractSingle (allAccounts: string[], derive: DeriveStakingElected | DeriveStakingWaiting, favorites: string[], { activeEra, eraLength, lastEra, sessionLength }: LastEra, historyDepth?: BN): [ValidatorInfo[], string[]] {
|
||||
const nominators: Record<string, boolean> = {};
|
||||
const emptyExposure = registry.createType('Exposure');
|
||||
const earliestEra = historyDepth && lastEra.sub(historyDepth).addn(1);
|
||||
@ -102,9 +92,6 @@ function extractSingle (allAccounts: string[], derive: DeriveStakingElected | De
|
||||
bondTotal = bondOwn = stakingLedger.total.unwrap();
|
||||
}
|
||||
|
||||
const validatorPayment = (validatorPrefs as unknown as ValidatorPrefsTo196).validatorPayment
|
||||
? (validatorPrefs as unknown as ValidatorPrefsTo196).validatorPayment.unwrap() as BN
|
||||
: validatorPrefs.commission.unwrap().mul(perValidatorReward).div(PERBILL);
|
||||
const key = accountId.toString();
|
||||
const lastEraPayout = !lastEra.isZero()
|
||||
? stakingLedger.claimedRewards[stakingLedger.claimedRewards.length - 1]
|
||||
@ -148,16 +135,12 @@ function extractSingle (allAccounts: string[], derive: DeriveStakingElected | De
|
||||
rankBondOther: 0,
|
||||
rankBondOwn: 0,
|
||||
rankBondTotal: 0,
|
||||
rankComm: 0,
|
||||
rankNumNominators: 0,
|
||||
rankOverall: 0,
|
||||
rankPayment: 0,
|
||||
rankReward: 0,
|
||||
rewardSplit: perValidatorReward.sub(validatorPayment),
|
||||
skipRewards,
|
||||
stakedReturn: 0,
|
||||
stakedReturnCmp: 0,
|
||||
validatorPayment,
|
||||
validatorPrefs
|
||||
};
|
||||
});
|
||||
@ -165,10 +148,9 @@ function extractSingle (allAccounts: string[], derive: DeriveStakingElected | De
|
||||
return [list, Object.keys(nominators)];
|
||||
}
|
||||
|
||||
function extractInfo (api: ApiPromise, allAccounts: string[], electedDerive: DeriveStakingElected, waitingDerive: DeriveStakingWaiting, favorites: string[], totalIssuance: BN, lastEraInfo: LastEra, lastReward: BN, historyDepth?: BN): Partial<SortedTargets> {
|
||||
const perValidatorReward = lastReward.divn(electedDerive.info.length);
|
||||
const [elected, nominators] = extractSingle(allAccounts, electedDerive, favorites, perValidatorReward, lastEraInfo, historyDepth);
|
||||
const [waiting] = extractSingle(allAccounts, waitingDerive, favorites, perValidatorReward, lastEraInfo);
|
||||
function extractInfo (api: ApiPromise, allAccounts: string[], electedDerive: DeriveStakingElected, waitingDerive: DeriveStakingWaiting, favorites: string[], totalIssuance: BN, lastEraInfo: LastEra, historyDepth?: BN): Partial<SortedTargets> {
|
||||
const [elected, nominators] = extractSingle(allAccounts, electedDerive, favorites, lastEraInfo, historyDepth);
|
||||
const [waiting] = extractSingle(allAccounts, waitingDerive, favorites, lastEraInfo);
|
||||
const activeTotals = elected
|
||||
.filter(({ isActive }) => isActive)
|
||||
.map(({ bondTotal }) => bondTotal)
|
||||
@ -215,19 +197,14 @@ function extractInfo (api: ApiPromise, allAccounts: string[], electedDerive: Der
|
||||
}
|
||||
|
||||
const transformEra = {
|
||||
transform: ({ activeEra, activeEraStart, eraLength, sessionLength }: DeriveSessionInfo): LastEra => ({
|
||||
transform: ({ activeEra, eraLength, sessionLength }: DeriveSessionInfo): LastEra => ({
|
||||
activeEra,
|
||||
eraLength,
|
||||
lastEra: activeEra.gtn(0) ? activeEra.subn(1) : BN_ZERO,
|
||||
lastEraEnd: activeEra.gtn(0) && activeEraStart.isSome ? activeEraStart.unwrap() : BN_ZERO,
|
||||
lastEra: activeEra.isZero() ? BN_ZERO : activeEra.subn(1),
|
||||
sessionLength
|
||||
})
|
||||
};
|
||||
|
||||
const transformReward = {
|
||||
transform: (optBalance: Option<Balance>) => optBalance.unwrapOrDefault()
|
||||
};
|
||||
|
||||
export default function useSortedTargets (favorites: string[]): SortedTargets {
|
||||
const { api } = useApi();
|
||||
const { allAccounts } = useAccounts();
|
||||
@ -236,14 +213,13 @@ export default function useSortedTargets (favorites: string[]): SortedTargets {
|
||||
const electedInfo = useCall<DeriveStakingElected>(api.derive.staking.electedInfo);
|
||||
const waitingInfo = useCall<DeriveStakingWaiting>(api.derive.staking.waitingInfo);
|
||||
const lastEraInfo = useCall<LastEra>(api.derive.session.info, undefined, transformEra);
|
||||
const lastReward = useCall<BN>(lastEraInfo && api.query.staking.erasValidatorReward, [lastEraInfo?.lastEra], transformReward);
|
||||
|
||||
const partial = useMemo(
|
||||
() => electedInfo && lastEraInfo && lastReward && totalIssuance && waitingInfo
|
||||
? extractInfo(api, allAccounts, electedInfo, waitingInfo, favorites, totalIssuance, lastEraInfo, lastReward, historyDepth)
|
||||
() => electedInfo && lastEraInfo && totalIssuance && waitingInfo
|
||||
? extractInfo(api, allAccounts, electedInfo, waitingInfo, favorites, totalIssuance, lastEraInfo, historyDepth)
|
||||
: EMPTY_PARTIAL,
|
||||
[api, allAccounts, electedInfo, favorites, historyDepth, lastEraInfo, lastReward, totalIssuance, waitingInfo]
|
||||
[api, allAccounts, electedInfo, favorites, historyDepth, lastEraInfo, totalIssuance, waitingInfo]
|
||||
);
|
||||
|
||||
return { inflation: { inflation: 0, stakedReturn: 0 }, medianComm: 0, ...partial, lastReward };
|
||||
return { inflation: { inflation: 0, stakedReturn: 0 }, medianComm: 0, ...partial };
|
||||
}
|
||||
|
||||
@ -183,7 +183,9 @@ function AccountName ({ children, className = '', defaultName, label, onClick, o
|
||||
}
|
||||
|
||||
export default React.memo(styled(AccountName)(({ theme }: ThemeProps) => `
|
||||
align-items: center;
|
||||
border: 1px dotted transparent;
|
||||
display: inline-flex;
|
||||
vertical-align: middle;
|
||||
white-space: nowrap;
|
||||
|
||||
@ -198,6 +200,8 @@ export default React.memo(styled(AccountName)(({ theme }: ThemeProps) => `
|
||||
width: 100%;
|
||||
|
||||
.name {
|
||||
align-items: center;
|
||||
display: inline-flex;
|
||||
font-weight: 400 !important;
|
||||
filter: grayscale(100%);
|
||||
line-height: 1;
|
||||
|
||||
@ -42,8 +42,7 @@ function AddressSmall ({ children, className = '', defaultName, onClickName, ove
|
||||
export default React.memo(styled(AddressSmall)`
|
||||
white-space: nowrap;
|
||||
|
||||
.ui--IdentityIcon,
|
||||
.ui--AccountName {
|
||||
.ui--IdentityIcon{
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
@ -52,7 +51,6 @@ export default React.memo(styled(AddressSmall)`
|
||||
}
|
||||
|
||||
.ui--AccountName {
|
||||
display: inline-block;
|
||||
max-width: 26rem;
|
||||
overflow: hidden;
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user