diff --git a/packages/api-derive/src/staking/erasExposure.ts b/packages/api-derive/src/staking/erasExposure.ts index 0fdaba42d2..952afca63d 100644 --- a/packages/api-derive/src/staking/erasExposure.ts +++ b/packages/api-derive/src/staking/erasExposure.ts @@ -3,8 +3,8 @@ // of the Apache-2.0 license. See the LICENSE file for details. import { ApiInterfaceRx } from '@polkadot/api/types'; -import { AccountId, EraIndex, Exposure } from '@polkadot/types/interfaces'; -import { DeriveEraExposure, DeriveEraPointsAll } from '../types'; +import { AccountId, EraIndex, Exposure, RewardPoint } from '@polkadot/types/interfaces'; +import { DeriveEraExposure, DeriveEraExposures, DeriveEraPointsAll } from '../types'; import { Observable, combineLatest, of } from 'rxjs'; import { map, switchMap } from 'rxjs/operators'; @@ -12,13 +12,13 @@ import { StorageKey } from '@polkadot/types'; import { memo } from '../util'; -function queryClipped (api: ApiInterfaceRx): Observable<[EraIndex, [AccountId, Exposure][]][]> { - return api.derive.staking.erasPoints().pipe( +function queryClipped (api: ApiInterfaceRx, withActive?: boolean): Observable<[EraIndex, RewardPoint, [AccountId, Exposure, RewardPoint][]][]> { + return api.derive.staking.erasPoints(withActive).pipe( switchMap((allPoints): Observable<[DeriveEraPointsAll[], [StorageKey, Exposure][][]]> => combineLatest([ of(allPoints), combineLatest( - // we could just do entries over the full set, however the resultset can be quite large - split it into + // we could just do entries over the full set, however the set can be quite large - split it into // batches - may need to re-visit this, or alternatively use pages keys for exceptionally large sets allPoints.map(({ era }): Observable<[StorageKey, Exposure][]> => api.query.staking.erasStakersClipped.entries(era) @@ -26,29 +26,35 @@ function queryClipped (api: ApiInterfaceRx): Observable<[EraIndex, [AccountId, E ) ]) ), - map(([allPoints, erasStakers]): [EraIndex, [AccountId, Exposure][]][] => - allPoints.map(({ era }, index): [EraIndex, [AccountId, Exposure][]] => [ + map(([allPoints, erasStakers]): [EraIndex, RewardPoint, [AccountId, Exposure, RewardPoint][]][] => + allPoints.map(({ all, era, eraPoints }, index): [EraIndex, RewardPoint, [AccountId, Exposure, RewardPoint][]] => [ era, - erasStakers[index].map(([key, exposure]): [AccountId, Exposure] => [ + eraPoints, + erasStakers[index].map(([key, exposure]): [AccountId, Exposure, RewardPoint] => [ key.args[1] as AccountId, - exposure + exposure, + all[key.args[1].toString()] ]) ]) ) ); } -export function erasExposure (api: ApiInterfaceRx): () => Observable { - return memo((): Observable => - queryClipped(api).pipe( +export function erasExposure (api: ApiInterfaceRx): (withActive?: boolean) => Observable { + return memo((withActive?: boolean): Observable => + queryClipped(api, withActive).pipe( map((clipped): DeriveEraExposure[] => - clipped.map(([era, validators]): DeriveEraExposure => ({ - all: validators.reduce((all: Record, [validtorId, exposure]): Record => { - all[validtorId.toString()] = exposure; + clipped.map(([era, eraPoints, validators]): DeriveEraExposure => ({ + all: validators.reduce((all: DeriveEraExposures, [validtorId, exposure, points]): DeriveEraExposures => { + all[validtorId.toString()] = { + exposure, + points + }; return all; }, {}), - era + era, + eraPoints })) ) ) diff --git a/packages/api-derive/src/staking/erasPoints.ts b/packages/api-derive/src/staking/erasPoints.ts index 56e818f0e4..c2721dc9a8 100644 --- a/packages/api-derive/src/staking/erasPoints.ts +++ b/packages/api-derive/src/staking/erasPoints.ts @@ -12,7 +12,7 @@ import { Option, u32 } from '@polkadot/types'; import { memo } from '../util'; -function getAvailableIndexes (api: ApiInterfaceRx): Observable { +function getAvailableIndexes (api: ApiInterfaceRx, withActive?: boolean): Observable { return api.query.staking?.activeEra ? api.queryMulti<[Option, u32]>([ api.query.staking.activeEra, @@ -21,7 +21,7 @@ function getAvailableIndexes (api: ApiInterfaceRx): Observable { map(([activeEraOpt, historyDepth]): EraIndex[] => { const result: EraIndex[] = []; const max = historyDepth.toNumber(); - let lastEra = activeEraOpt.unwrapOrDefault().index.subn(1); + let lastEra = activeEraOpt.unwrapOrDefault().index.subn(withActive ? 0 : 1); while (lastEra.gten(0) && result.length < max) { result.push(api.registry.createType('EraIndex', lastEra)); @@ -36,9 +36,9 @@ function getAvailableIndexes (api: ApiInterfaceRx): Observable { : of([]); } -export function erasPoints (api: ApiInterfaceRx): () => Observable { - return memo((): Observable => - getAvailableIndexes(api).pipe( +export function erasPoints (api: ApiInterfaceRx): (withActive?: boolean) => Observable { + return memo((withActive?: boolean): Observable => + getAvailableIndexes(api, withActive).pipe( switchMap((indexes): Observable<[EraIndex[], EraRewardPoints[]]> => combineLatest([ of(indexes), @@ -57,7 +57,7 @@ export function erasPoints (api: ApiInterfaceRx): () => Observable Observable { - return memo((): Observable => - api.derive.staking.erasExposure().pipe( +export function erasRewards (api: ApiInterfaceRx): (withActive?: boolean) => Observable { + return memo((withActive?: boolean): Observable => + api.derive.staking.erasExposure(withActive).pipe( map((exposures): DeriveEraRewardsAll[] => - exposures.map(({ era, all }): DeriveEraRewardsAll => + exposures.map(({ all, era, eraPoints }): DeriveEraRewardsAll => Object .entries(all) - .reduce((rewards: DeriveEraRewardsAll, [validatorId, exposure]): DeriveEraRewardsAll => { - rewards.validators[validatorId] = exposure; + .reduce((rewards: DeriveEraRewardsAll, [validatorId, data]): DeriveEraRewardsAll => { + rewards.validators[validatorId] = data; - exposure.others.forEach(({ who }, index): void => { + data.exposure.others.forEach(({ who }, index): void => { const nominatorId = who.toString(); rewards.nominators[nominatorId] = rewards.nominators[nominatorId] || []; @@ -28,7 +28,7 @@ export function erasRewards (api: ApiInterfaceRx): () => Observable Observable { - return memo((accountId: Uint8Array | string): Observable => { +export function stakerRewards (api: ApiInterfaceRx): (accountId: Uint8Array | string, withActive?: boolean) => Observable { + return memo((accountId: Uint8Array | string, withActive?: boolean): Observable => { const stakerId = api.registry.createType('AccountId', accountId).toString(); - return api.derive.staking.erasRewards().pipe( + return api.derive.staking.erasRewards(withActive).pipe( map((rewards): DeriveStakerReward[] => - rewards - .map(({ era, nominators: allNominators, validators: allValidators }): DeriveStakerReward => { - const isValidator = !!allValidators[stakerId]; - const validators: Record = {}; - let nominating: [string, number][] = []; + rewards.map(({ era, eraPoints, nominators: allNominators, validators: allValidators }): DeriveStakerReward => { + const isValidator = !!allValidators[stakerId]; + const validators: DeriveEraExposures = {}; + let nominating: [string, number][] = []; - if (isValidator) { - validators[stakerId] = allValidators[stakerId]; - } else if (allNominators[stakerId]) { - nominating = allNominators[stakerId]; + if (isValidator) { + validators[stakerId] = allValidators[stakerId]; + } else if (allNominators[stakerId]) { + nominating = allNominators[stakerId]; - nominating.forEach(([validatorId]): void => { - validators[validatorId] = allValidators[validatorId]; - }); - } + nominating.forEach(([validatorId]): void => { + validators[validatorId] = allValidators[validatorId]; + }); + } - return { era, isValidator, nominating, validators }; - }) - .filter(({ validators }): boolean => Object.keys(validators).length !== 0) + return { era, eraPoints, isEmpty: !Object.keys(validators).length, isValidator, nominating, validators }; + }) ) ); }); diff --git a/packages/api-derive/src/staking/types.ts b/packages/api-derive/src/staking/types.ts index c5dbecd85f..caa9b39b40 100644 --- a/packages/api-derive/src/staking/types.ts +++ b/packages/api-derive/src/staking/types.ts @@ -8,31 +8,40 @@ import { DeriveSessionIndexes } from '../session/types'; export interface DeriveEraPointsAll { all: Record; era: EraIndex; - total: RewardPoint; + eraPoints: RewardPoint; } export interface DeriveEraPoints { era: EraIndex; + eraPoints: RewardPoint; own: RewardPoint; - total: RewardPoint; } +export type DeriveEraExposures = Record; + export interface DeriveEraExposure { - all: Record; + all: DeriveEraExposures; era: EraIndex; + eraPoints: RewardPoint; } export interface DeriveEraRewardsAll { era: EraIndex; + eraPoints: RewardPoint; nominators: Record; - validators: Record; + validators: DeriveEraExposures; } export interface DeriveStakerReward { era: EraIndex; + eraPoints: RewardPoint; + isEmpty: boolean; isValidator: boolean; nominating: [string, number][]; - validators: Record; + validators: DeriveEraExposures; } export interface DerivedStakingElected { diff --git a/packages/api-derive/src/staking/validatorPoints.ts b/packages/api-derive/src/staking/validatorPoints.ts deleted file mode 100644 index 1668b9a9cb..0000000000 --- a/packages/api-derive/src/staking/validatorPoints.ts +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2017-2020 @polkadot/api-derive authors & contributors -// This software may be modified and distributed under the terms -// of the Apache-2.0 license. See the LICENSE file for details. - -import { ApiInterfaceRx } from '@polkadot/api/types'; -import { DeriveEraPoints } from '../types'; - -import { Observable } from 'rxjs'; -import { map } from 'rxjs/operators'; - -import { memo } from '../util'; - -export function validatorPoints (api: ApiInterfaceRx): (accountId: Uint8Array | string) => Observable { - return memo((_accountId: Uint8Array | string): Observable => { - const accountId = api.registry.createType('AccountId', _accountId).toString(); - - return api.derive.staking.erasPoints().pipe( - map((all): DeriveEraPoints[] => - all.map(({ all, era, total }): DeriveEraPoints => ({ - era, - own: all[accountId] || api.registry.createType('RewardPoint'), - total - })) - ) - ); - }); -}