From 0e74acd19fc570932e5fe7cd989cee6f9734200b Mon Sep 17 00:00:00 2001 From: Jaco Greeff Date: Mon, 27 Apr 2020 23:02:46 +0200 Subject: [PATCH] Add hook for targets (#2642) --- packages/page-staking/src/Targets/Summary.tsx | 12 +- packages/page-staking/src/Targets/index.tsx | 227 +++--------------- packages/page-staking/src/Targets/types.ts | 8 + .../src/Targets/useSortedTargets.ts | 167 +++++++++++++ packages/page-staking/src/index.tsx | 7 +- 5 files changed, 226 insertions(+), 195 deletions(-) create mode 100644 packages/page-staking/src/Targets/useSortedTargets.ts diff --git a/packages/page-staking/src/Targets/Summary.tsx b/packages/page-staking/src/Targets/Summary.tsx index cda7416609..61a6527f0f 100644 --- a/packages/page-staking/src/Targets/Summary.tsx +++ b/packages/page-staking/src/Targets/Summary.tsx @@ -14,8 +14,8 @@ import { useTranslation } from '../translate'; interface Props { lastReward?: BN; - numNominators: number; - numValidators: number; + numNominators?: number; + numValidators?: number; totalStaked?: BN; } @@ -59,9 +59,11 @@ function Summary ({ lastReward, numNominators, numValidators, totalStaked }: Pro {percentage} )} - - {numValidators}/{numNominators} - + {numValidators && numNominators && ( + + {numValidators}/{numNominators} + + )} {lastReward?.gtn(0) && ( a.bondTotal.gtn(0)) - .sort((a, b): number => b.commissionPer - a.commissionPer) - .map((info, index): ValidatorInfo => { - info.rankComm = index + 1; - - return info; - }) - .sort((a, b): number => b.bondOther.cmp(a.bondOther)) - .map((info, index): ValidatorInfo => { - info.rankBondOther = index + 1; - - return info; - }) - .sort((a, b): number => b.bondOwn.cmp(a.bondOwn)) - .map((info, index): ValidatorInfo => { - info.rankBondOwn = index + 1; - - return info; - }) - .sort((a, b): number => b.bondTotal.cmp(a.bondTotal)) - .map((info, index): ValidatorInfo => { - info.rankBondTotal = index + 1; - - return info; - }) - .sort((a, b): number => b.validatorPayment.cmp(a.validatorPayment)) - .map((info, index): ValidatorInfo => { - info.rankPayment = index + 1; - - return info; - }) - .sort((a, b): number => a.rewardSplit.cmp(b.rewardSplit)) - .map((info, index): ValidatorInfo => { - info.rankReward = index + 1; - - return info; - }) - .sort((a, b): number => { - const cmp = b.rewardPayout.cmp(a.rewardPayout); - - return cmp !== 0 - ? cmp - : a.rankReward === b.rankReward - ? a.rankPayment === b.rankPayment - ? b.rankBondTotal - a.rankBondTotal - : b.rankPayment - a.rankPayment - : b.rankReward - a.rankReward; - }) - .map((info, index): ValidatorInfo => { - info.rankOverall = index + 1; - - return info; - }) - .sort((a, b): number => a.isFavorite === b.isFavorite - ? 0 - : (a.isFavorite ? -1 : 1) - ); -} - -function extractInfo (allAccounts: string[], amount: BN = new BN(0), electedInfo: DeriveStakingElected, favorites: string[], lastReward = new BN(1)): AllInfo { - const nominators: string[] = []; - let totalStaked = new BN(0); - const perValidatorReward = lastReward.divn(electedInfo.info.length); - const validators = sortValidators( - electedInfo.info.map(({ accountId, exposure: _exposure, validatorPrefs }): ValidatorInfo => { - const exposure = _exposure || { - others: registry.createType('Vec'), - own: registry.createType('Compact'), - total: registry.createType('Compact') - }; - const prefs = (validatorPrefs as (ValidatorPrefs | ValidatorPrefsTo196)) || { - commission: registry.createType('Compact') - }; - const bondOwn = exposure.own.unwrap(); - const bondTotal = exposure.total.unwrap(); - const validatorPayment = (prefs as ValidatorPrefsTo196).validatorPayment - ? (prefs as ValidatorPrefsTo196).validatorPayment.unwrap() as BN - : (prefs as ValidatorPrefs).commission.unwrap().mul(perValidatorReward).div(PERBILL); - const key = accountId.toString(); - const rewardSplit = perValidatorReward.sub(validatorPayment); - const rewardPayout = rewardSplit.gtn(0) - ? amount.mul(rewardSplit).div(amount.add(bondTotal)) - : new BN(0); - const isNominating = exposure.others.reduce((isNominating, indv): boolean => { - const nominator = indv.who.toString(); - - if (!nominators.includes(nominator)) { - nominators.push(nominator); - } - - return isNominating || allAccounts.includes(nominator); - }, allAccounts.includes(key)); - - totalStaked = totalStaked.add(bondTotal); - - return { - accountId, - bondOther: bondTotal.sub(bondOwn), - bondOwn, - bondShare: 0, - bondTotal, - commissionPer: (((prefs as ValidatorPrefs).commission?.unwrap() || new BN(0)).toNumber() / 10_000_000), - isCommission: !!(prefs as ValidatorPrefs).commission, - isFavorite: favorites.includes(key), - isNominating, - key, - numNominators: exposure.others.length, - rankBondOther: 0, - rankBondOwn: 0, - rankBondTotal: 0, - rankComm: 0, - rankOverall: 0, - rankPayment: 0, - rankReward: 0, - rewardPayout, - rewardSplit, - validatorPayment - }; - }) - ); - - return { nominators, totalStaked, validators }; -} - -function sort (sortBy: SortBy, sortFromMax: boolean, validators: ValidatorInfo[]): ValidatorInfo[] { - return [...validators] - .sort((a, b): number => sortFromMax - ? a[sortBy] - b[sortBy] - : b[sortBy] - a[sortBy] +function sort (sortBy: SortBy, sortFromMax: boolean, validators: ValidatorInfo[]): number[] { + return [...Array(validators.length).keys()] + .sort((a, b) => + sortFromMax + ? validators[a][sortBy] - validators[b][sortBy] + : validators[b][sortBy] - validators[a][sortBy] ) - .sort((a, b): number => a.isFavorite === b.isFavorite - ? 0 - : (a.isFavorite ? -1 : 1) + .sort((a, b) => + validators[a].isFavorite === validators[b].isFavorite + ? 0 + : (validators[a].isFavorite ? -1 : 1) ); } function Targets ({ className, ownStashes }: Props): React.ReactElement { const { t } = useTranslation(); - const { api } = useApi(); - const { allAccounts } = useAccounts(); const ownNominators = useOwnNominators(ownStashes); - const lastEra = useCall(api.derive.session.indexes, [], { - transform: ({ activeEra }: DeriveSessionIndexes) => activeEra.gtn(0) ? activeEra.subn(1) : new BN(0) - }) || new BN(0); - const lastReward = useCall(api.query.staking.erasValidatorReward, [lastEra], { - transform: (optBalance: Option) => optBalance.unwrapOrDefault() - }); const [_amount, setAmount] = useState(new BN(1_000)); - const electedInfo = useCall(api.derive.staking.electedInfo, []); - const [favorites, toggleFavorite] = useFavorites(STORE_FAVS_BASE); - const [selected, setSelected] = useState([]); - const [{ nominators, sorted, totalStaked, validators }, setWorkable] = useState({ nominators: [], validators: [] }); - const [{ sortBy, sortFromMax }, setSortBy] = useState<{ sortBy: SortBy; sortFromMax: boolean }>({ sortBy: 'rankOverall', sortFromMax: true }); const amount = useDebounce(_amount); - const labels = useMemo( - (): Record => ({ - rankBondOther: t('other stake'), - rankBondOwn: t('own stake'), - rankBondTotal: t('total stake'), - rankComm: t('commission'), - rankOverall: t('profit/era est') - }), - [t] - ); + const { lastReward, nominators, toggleFavorite, totalStaked, validators } = useSortedTargets(amount); + const [selected, setSelected] = useState([]); + const [sorted, setSorted] = useState(); + const [{ sortBy, sortFromMax }, setSortBy] = useState<{ sortBy: SortBy; sortFromMax: boolean }>({ sortBy: 'rankOverall', sortFromMax: true }); + + useEffect((): void => { + validators && setSorted( + sort(sortBy, sortFromMax, validators) + ); + }, [sortBy, sortFromMax, validators]); const _sort = useCallback( (newSortBy: SortBy) => setSortBy(({ sortBy, sortFromMax }) => ({ @@ -227,21 +78,23 @@ function Targets ({ className, ownStashes }: Props): React.ReactElement { const _selectProfitable = useCallback( () => setSelected( - validators + (validators || []) .filter((_, index) => index < MAX_NOMINATIONS) .map(({ key }) => key) ), [validators] ); - useEffect((): void => { - if (electedInfo) { - const { nominators, totalStaked, validators } = extractInfo(allAccounts, amount, electedInfo, favorites, lastReward); - const sorted = sort(sortBy, sortFromMax, validators); - - setWorkable({ nominators, sorted, totalStaked, validators }); - } - }, [allAccounts, amount, electedInfo, favorites, lastReward, sortBy, sortFromMax]); + const labels = useMemo( + (): Record => ({ + rankBondOther: t('other stake'), + rankBondOwn: t('own stake'), + rankBondTotal: t('total stake'), + rankComm: t('commission'), + rankOverall: t('profit/era est') + }), + [t] + ); const header = useMemo(() => [ [t('validators'), 'start', 3], @@ -269,14 +122,14 @@ function Targets ({ className, ownStashes }: Props): React.ReactElement {