Remove support for pre-v2 staking (#2980)
* Remove support for pre-v2 staking * Adjust with util array functions * Remove old enumset support * Empty controller * withController flag
This commit is contained in:
@@ -2,40 +2,16 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import type { ApiInterfaceRx } from '@polkadot/api/types';
|
||||
import type { Option, Vec } from '@polkadot/types';
|
||||
import type { Option } from '@polkadot/types';
|
||||
import type { AccountId, AccountIndex, BalanceOf } from '@polkadot/types/interfaces';
|
||||
import type { ITuple } from '@polkadot/types/types';
|
||||
import type { Observable } from '@polkadot/x-rxjs';
|
||||
|
||||
import { ENUMSET_SIZE } from '@polkadot/types/generic/AccountIndex';
|
||||
import { isFunction } from '@polkadot/util';
|
||||
import { of } from '@polkadot/x-rxjs';
|
||||
import { map, startWith } from '@polkadot/x-rxjs/operators';
|
||||
import { map } from '@polkadot/x-rxjs/operators';
|
||||
|
||||
import { memo } from '../util';
|
||||
|
||||
function queryEnumSet (api: ApiInterfaceRx, _accountIndex: AccountIndex | string): Observable<AccountId | undefined> {
|
||||
const accountIndex = _accountIndex instanceof api.registry.createClass('AccountIndex')
|
||||
? _accountIndex
|
||||
: api.registry.createType('AccountIndex', _accountIndex);
|
||||
|
||||
return api.query.indices.enumSet<Vec<AccountId>>(accountIndex.div(ENUMSET_SIZE)).pipe(
|
||||
startWith([]),
|
||||
map((accounts): AccountId | undefined =>
|
||||
(accounts || [])[accountIndex.mod(ENUMSET_SIZE).toNumber()]
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// current
|
||||
function query (api: ApiInterfaceRx, accountIndex: AccountIndex | string): Observable<AccountId | undefined> {
|
||||
return api.query.indices.accounts<Option<ITuple<[AccountId, BalanceOf]>>>(accountIndex).pipe(
|
||||
map((optResult): AccountId | undefined =>
|
||||
optResult.unwrapOr([])[0]
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @name indexToId
|
||||
* @param {( AccountIndex | string )} accountIndex - An accounts index in different formats.
|
||||
@@ -52,9 +28,11 @@ function query (api: ApiInterfaceRx, accountIndex: AccountIndex | string): Obser
|
||||
export function indexToId (instanceId: string, api: ApiInterfaceRx): (accountIndex: AccountIndex | string) => Observable<AccountId | undefined> {
|
||||
return memo(instanceId, (accountIndex: AccountIndex | string): Observable<AccountId | undefined> =>
|
||||
api.query.indices
|
||||
? isFunction(api.query.indices.accounts)
|
||||
? query(api, accountIndex)
|
||||
: queryEnumSet(api, accountIndex)
|
||||
? api.query.indices.accounts<Option<ITuple<[AccountId, BalanceOf]>>>(accountIndex).pipe(
|
||||
map((optResult): AccountId | undefined =>
|
||||
optResult.unwrapOr([])[0]
|
||||
)
|
||||
)
|
||||
: of(undefined)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2,47 +2,17 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import type { ApiInterfaceRx } from '@polkadot/api/types';
|
||||
import type { Vec } from '@polkadot/types';
|
||||
import type { AccountId, AccountIndex } from '@polkadot/types/interfaces';
|
||||
import type { AccountIndex } from '@polkadot/types/interfaces';
|
||||
import type { Observable } from '@polkadot/x-rxjs';
|
||||
import type { AccountIndexes } from '../types';
|
||||
|
||||
import { ENUMSET_SIZE } from '@polkadot/types/generic/AccountIndex';
|
||||
import { isFunction } from '@polkadot/util';
|
||||
import { of } from '@polkadot/x-rxjs';
|
||||
import { map, startWith, switchMap } from '@polkadot/x-rxjs/operators';
|
||||
import { map, startWith } from '@polkadot/x-rxjs/operators';
|
||||
|
||||
import { memo } from '../util';
|
||||
|
||||
const enumsetSize = ENUMSET_SIZE.toNumber();
|
||||
|
||||
let indicesCache: AccountIndexes | null = null;
|
||||
|
||||
function queryEnumSet (api: ApiInterfaceRx): Observable<AccountIndexes> {
|
||||
return api.query.indices.nextEnumSet<AccountIndex>().pipe(
|
||||
// use the nextEnumSet (which is a counter of the number of sets) to construct
|
||||
// a range of values to query [0, 1, 2, ...]. Retrieve the full enum set for the
|
||||
// specific index - each query can return up to ENUMSET_SIZE (64) records, each
|
||||
// containing an AccountId
|
||||
switchMap((next: AccountIndex): Observable<Vec<AccountId>[]> =>
|
||||
api.query.indices.enumSet.multi<Vec<AccountId>>([...Array(next.toNumber() + 1).keys()])
|
||||
),
|
||||
map((all: AccountId[][]): AccountIndexes =>
|
||||
all.reduce((indexes: AccountIndexes, list, outerIndex): AccountIndexes => {
|
||||
(list || []).forEach((accountId, innerIndex): void => {
|
||||
// re-create the index based on position 0 is [0][0] and likewise
|
||||
// 64 (0..63 in first) is [1][0] (the first index value in set 2)
|
||||
const index = (outerIndex * enumsetSize) + innerIndex;
|
||||
|
||||
indexes[accountId.toString()] = api.registry.createType('AccountIndex', index);
|
||||
});
|
||||
|
||||
return indexes;
|
||||
}, {})
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function queryAccounts (api: ApiInterfaceRx): Observable<AccountIndexes> {
|
||||
return api.query.indices.accounts.entries().pipe(
|
||||
map((entries): AccountIndexes =>
|
||||
@@ -78,9 +48,7 @@ export function indexes (instanceId: string, api: ApiInterfaceRx): () => Observa
|
||||
? of(indicesCache)
|
||||
: (
|
||||
api.query.indices
|
||||
? isFunction(api.query.indices.accounts)
|
||||
? queryAccounts(api).pipe(startWith({}))
|
||||
: queryEnumSet(api).pipe(startWith({}))
|
||||
? queryAccounts(api).pipe(startWith({}))
|
||||
: of({} as AccountIndexes)
|
||||
).pipe(
|
||||
map((indices): AccountIndexes => {
|
||||
|
||||
@@ -7,16 +7,11 @@ import type { ActiveEraInfo, EraIndex, Moment, SessionIndex } from '@polkadot/ty
|
||||
import type { Observable } from '@polkadot/x-rxjs';
|
||||
import type { DeriveSessionIndexes } from '../types';
|
||||
|
||||
import { isFunction } from '@polkadot/util';
|
||||
import { of } from '@polkadot/x-rxjs';
|
||||
import { map } from '@polkadot/x-rxjs/operators';
|
||||
|
||||
import { memo } from '../util';
|
||||
|
||||
function isEraOpt (era: Option<EraIndex> | EraIndex): era is Option<EraIndex> {
|
||||
return isFunction((era as Option<EraIndex>).unwrapOrDefault);
|
||||
}
|
||||
|
||||
// parse into Indexes
|
||||
function parse ([activeEra, activeEraStart, currentEra, currentIndex, validatorCount]: [EraIndex, Option<Moment>, EraIndex, SessionIndex, u32]): DeriveSessionIndexes {
|
||||
return {
|
||||
@@ -28,29 +23,6 @@ function parse ([activeEra, activeEraStart, currentEra, currentIndex, validatorC
|
||||
};
|
||||
}
|
||||
|
||||
// query for previous V2
|
||||
function queryNoActive (api: ApiInterfaceRx): Observable<DeriveSessionIndexes> {
|
||||
return api.queryMulti<[Option<EraIndex> | EraIndex, SessionIndex, u32]>([
|
||||
api.query.staking.currentEra,
|
||||
api.query.session.currentIndex,
|
||||
api.query.staking.validatorCount
|
||||
]).pipe(
|
||||
map(([currentEraOpt, currentIndex, validatorCount]): DeriveSessionIndexes => {
|
||||
const currentEra = isEraOpt(currentEraOpt)
|
||||
? currentEraOpt.unwrapOrDefault()
|
||||
: currentEraOpt;
|
||||
|
||||
return parse([
|
||||
currentEra,
|
||||
api.registry.createType('Option<Moment>'),
|
||||
currentEra,
|
||||
currentIndex,
|
||||
validatorCount
|
||||
]);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
// query based on latest
|
||||
function query (api: ApiInterfaceRx): Observable<DeriveSessionIndexes> {
|
||||
return api.queryMulti<[Option<ActiveEraInfo>, Option<EraIndex>, SessionIndex, u32]>([
|
||||
@@ -87,9 +59,7 @@ function empty (api: ApiInterfaceRx): Observable<DeriveSessionIndexes> {
|
||||
export function indexes (instanceId: string, api: ApiInterfaceRx): () => Observable<DeriveSessionIndexes> {
|
||||
return memo(instanceId, (): Observable<DeriveSessionIndexes> =>
|
||||
api.query.session && api.query.staking
|
||||
? isFunction(api.query.staking.activeEra)
|
||||
? query(api)
|
||||
: queryNoActive(api)
|
||||
? query(api)
|
||||
: empty(api)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ import type { SessionIndex } from '@polkadot/types/interfaces';
|
||||
import type { Observable } from '@polkadot/x-rxjs';
|
||||
import type { DeriveSessionInfo, DeriveSessionProgress } from '../types';
|
||||
|
||||
import { isFunction } from '@polkadot/util';
|
||||
import { combineLatest, of } from '@polkadot/x-rxjs';
|
||||
import { map, switchMap } from '@polkadot/x-rxjs/operators';
|
||||
|
||||
@@ -57,29 +56,13 @@ function queryBabe (api: ApiInterfaceRx): Observable<[DeriveSessionInfo, ResultS
|
||||
);
|
||||
}
|
||||
|
||||
function queryBabeNoHistory (api: ApiInterfaceRx): Observable<[DeriveSessionInfo, ResultSlotsFlat]> {
|
||||
return combineLatest([
|
||||
api.derive.session.info(),
|
||||
api.queryMulti<ResultSlotsFlat>([
|
||||
api.query.babe.currentSlot,
|
||||
api.query.babe.epochIndex,
|
||||
api.query.babe.genesisSlot,
|
||||
api.query.staking.currentEraStartSessionIndex
|
||||
])
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Retrieves all the session and era query and calculates specific values on it as the length of the session and eras
|
||||
*/
|
||||
export function progress (instanceId: string, api: ApiInterfaceRx): () => Observable<DeriveSessionProgress> {
|
||||
return memo(instanceId, (): Observable<DeriveSessionProgress> =>
|
||||
api.consts.babe
|
||||
? (
|
||||
isFunction(api.query.staking.erasStartSessionIndex)
|
||||
? queryBabe(api) // 2.x with Babe
|
||||
: queryBabeNoHistory(api)
|
||||
).pipe(
|
||||
? queryBabe(api).pipe(
|
||||
map(([info, slots]: [DeriveSessionInfo, ResultSlotsFlat]): DeriveSessionProgress =>
|
||||
createDerive(api, info, slots)
|
||||
)
|
||||
|
||||
@@ -2,41 +2,21 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import type { ApiInterfaceRx } from '@polkadot/api/types';
|
||||
import type { AccountId, EraPoints, EraRewardPoints, RewardPoint } from '@polkadot/types/interfaces';
|
||||
import type { EraRewardPoints } from '@polkadot/types/interfaces';
|
||||
import type { Observable } from '@polkadot/x-rxjs';
|
||||
|
||||
import { of } from '@polkadot/x-rxjs';
|
||||
import { map, switchMap } from '@polkadot/x-rxjs/operators';
|
||||
import { switchMap } from '@polkadot/x-rxjs/operators';
|
||||
|
||||
import { memo } from '../util';
|
||||
|
||||
function retrievePointsPrev (api: ApiInterfaceRx, currentElected: AccountId[]): Observable<EraRewardPoints> {
|
||||
return api.query.staking.currentEraPointsEarned<EraPoints>().pipe(
|
||||
map(({ individual, total }): EraRewardPoints =>
|
||||
api.registry.createType('EraRewardPoints', {
|
||||
individual: new Map<AccountId, RewardPoint>(
|
||||
individual
|
||||
.map((points) => api.registry.createType('RewardPoint', points))
|
||||
.map((points, index): [AccountId, RewardPoint] => [currentElected[index], points])
|
||||
),
|
||||
total
|
||||
})
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Retrieve the staking overview, including elected and points earned
|
||||
*/
|
||||
export function currentPoints (instanceId: string, api: ApiInterfaceRx): () => Observable<EraRewardPoints> {
|
||||
return memo(instanceId, (): Observable<EraRewardPoints> =>
|
||||
api.derive.staking.overview().pipe(
|
||||
switchMap(({ activeEra, nextElected }) =>
|
||||
api.query.staking.erasRewardPoints
|
||||
? api.query.staking.erasRewardPoints<EraRewardPoints>(activeEra)
|
||||
: api.query.staking.currentEraPointsEarned
|
||||
? retrievePointsPrev(api, nextElected)
|
||||
: of(api.registry.createType('EraRewardPoints'))
|
||||
api.derive.session.indexes().pipe(
|
||||
switchMap(({ activeEra }) =>
|
||||
api.query.staking.erasRewardPoints<EraRewardPoints>(activeEra)
|
||||
)
|
||||
));
|
||||
}
|
||||
|
||||
@@ -4,21 +4,24 @@
|
||||
import type { ApiInterfaceRx } from '@polkadot/api/types';
|
||||
import type { AccountId } from '@polkadot/types/interfaces';
|
||||
import type { Observable } from '@polkadot/x-rxjs';
|
||||
import type { DeriveStakingElected } from '../types';
|
||||
import type { DeriveStakingElected, StakingQueryFlags } from '../types';
|
||||
|
||||
import { arrayFlatten } from '@polkadot/util';
|
||||
import { map, switchMap } from '@polkadot/x-rxjs/operators';
|
||||
|
||||
import { memo } from '../util';
|
||||
|
||||
const DEFAULT_FLAGS = { withController: true, withExposure: true, withPrefs: true };
|
||||
|
||||
function combineAccounts (nextElected: AccountId[], validators: AccountId[]): AccountId[] {
|
||||
return [...nextElected].concat(...validators.filter((v) => !nextElected.find((n) => n.eq(v))));
|
||||
return arrayFlatten([nextElected, validators.filter((v) => !nextElected.find((n) => n.eq(v)))]);
|
||||
}
|
||||
|
||||
export function electedInfo (instanceId: string, api: ApiInterfaceRx): () => Observable<DeriveStakingElected> {
|
||||
return memo(instanceId, (): Observable<DeriveStakingElected> =>
|
||||
export function electedInfo (instanceId: string, api: ApiInterfaceRx): (flags?: StakingQueryFlags) => Observable<DeriveStakingElected> {
|
||||
return memo(instanceId, (flags: StakingQueryFlags = DEFAULT_FLAGS): Observable<DeriveStakingElected> =>
|
||||
api.derive.staking.validators().pipe(
|
||||
switchMap(({ nextElected, validators }): Observable<DeriveStakingElected> =>
|
||||
api.derive.staking.queryMulti(combineAccounts(nextElected, validators), { withExposure: true, withLedger: true, withPrefs: true }).pipe(
|
||||
api.derive.staking.queryMulti(combineAccounts(nextElected, validators), flags).pipe(
|
||||
map((info): DeriveStakingElected => ({
|
||||
info,
|
||||
nextElected,
|
||||
|
||||
@@ -8,36 +8,33 @@ import type { Observable } from '@polkadot/x-rxjs';
|
||||
|
||||
import BN from 'bn.js';
|
||||
|
||||
import { of } from '@polkadot/x-rxjs';
|
||||
import { map } from '@polkadot/x-rxjs/operators';
|
||||
|
||||
import { memo } from '../util';
|
||||
|
||||
export function erasHistoric (instanceId: string, api: ApiInterfaceRx): (withActive: boolean) => Observable<EraIndex[]> {
|
||||
return memo(instanceId, (withActive: boolean): Observable<EraIndex[]> =>
|
||||
api.query.staking?.activeEra
|
||||
? api.queryMulti<[Option<ActiveEraInfo>, u32]>([
|
||||
api.query.staking.activeEra,
|
||||
api.query.staking.historyDepth
|
||||
]).pipe(
|
||||
map(([activeEraOpt, historyDepth]): EraIndex[] => {
|
||||
const result: EraIndex[] = [];
|
||||
const max = historyDepth.toNumber();
|
||||
const activeEra: BN = activeEraOpt.unwrapOrDefault().index;
|
||||
let lastEra = activeEra;
|
||||
api.queryMulti<[Option<ActiveEraInfo>, u32]>([
|
||||
api.query.staking.activeEra,
|
||||
api.query.staking.historyDepth
|
||||
]).pipe(
|
||||
map(([activeEraOpt, historyDepth]): EraIndex[] => {
|
||||
const result: EraIndex[] = [];
|
||||
const max = historyDepth.toNumber();
|
||||
const activeEra: BN = activeEraOpt.unwrapOrDefault().index;
|
||||
let lastEra = activeEra;
|
||||
|
||||
while (lastEra.gten(0) && (result.length < max)) {
|
||||
if ((lastEra !== activeEra) || (withActive === true)) {
|
||||
result.push(api.registry.createType('EraIndex', lastEra));
|
||||
}
|
||||
|
||||
lastEra = lastEra.subn(1);
|
||||
while (lastEra.gten(0) && (result.length < max)) {
|
||||
if ((lastEra !== activeEra) || (withActive === true)) {
|
||||
result.push(api.registry.createType('EraIndex', lastEra));
|
||||
}
|
||||
|
||||
// go from oldest to newest
|
||||
return result.reverse();
|
||||
})
|
||||
)
|
||||
: of([])
|
||||
lastEra = lastEra.subn(1);
|
||||
}
|
||||
|
||||
// go from oldest to newest
|
||||
return result.reverse();
|
||||
})
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -4,71 +4,63 @@
|
||||
import type { ApiInterfaceRx } from '@polkadot/api/types';
|
||||
import type { Option } from '@polkadot/types';
|
||||
import type { AccountId, EraIndex, Exposure, Nominations, RewardDestination, StakingLedger, ValidatorPrefs } from '@polkadot/types/interfaces';
|
||||
import type { ITuple } from '@polkadot/types/types';
|
||||
import type { Observable } from '@polkadot/x-rxjs';
|
||||
import type { DeriveStakingQuery } from '../types';
|
||||
import type { DeriveStakingQuery, StakingQueryFlags } from '../types';
|
||||
|
||||
import { isFunction } from '@polkadot/util';
|
||||
import { combineLatest, of } from '@polkadot/x-rxjs';
|
||||
import { map, switchMap } from '@polkadot/x-rxjs/operators';
|
||||
|
||||
import { memo } from '../util';
|
||||
|
||||
interface QueryFlags {
|
||||
withDestination?: boolean;
|
||||
withExposure?: boolean;
|
||||
withLedger?: boolean;
|
||||
withNominations?: boolean;
|
||||
withPrefs?: boolean;
|
||||
}
|
||||
|
||||
type MultiResult = [Option<AccountId>, Option<ITuple<[Nominations]> | Nominations>, RewardDestination, ITuple<[ValidatorPrefs]> | ValidatorPrefs, Exposure];
|
||||
|
||||
type MultiResultCombo = [Option<AccountId>, Option<Nominations>, RewardDestination, ValidatorPrefs, Exposure];
|
||||
|
||||
function parseDetails (stashId: AccountId, [controllerIdOpt, nominatorsOpt, rewardDestination, validatorPrefs, exposure]: MultiResult, stakingLedgerOpt: Option<StakingLedger>): DeriveStakingQuery {
|
||||
const nominators = nominatorsOpt && nominatorsOpt.unwrapOr(null);
|
||||
|
||||
function parseDetails (stashId: AccountId, controllerIdOpt: Option<AccountId> | null, nominatorsOpt: Option<Nominations>, rewardDestination: RewardDestination, validatorPrefs: ValidatorPrefs, exposure: Exposure, stakingLedgerOpt: Option<StakingLedger>): DeriveStakingQuery {
|
||||
return {
|
||||
accountId: stashId,
|
||||
controllerId: controllerIdOpt && controllerIdOpt.unwrapOr(null),
|
||||
exposure,
|
||||
nominators: nominators
|
||||
? Array.isArray(nominators)
|
||||
? nominators[0].targets
|
||||
: nominators.targets
|
||||
nominators: nominatorsOpt.isSome
|
||||
? nominatorsOpt.unwrap().targets
|
||||
: [],
|
||||
rewardDestination,
|
||||
stakingLedger: stakingLedgerOpt.unwrapOrDefault(),
|
||||
stashId,
|
||||
validatorPrefs: Array.isArray(validatorPrefs)
|
||||
? validatorPrefs[0]
|
||||
: validatorPrefs
|
||||
validatorPrefs
|
||||
};
|
||||
}
|
||||
|
||||
function retrievePrev (api: ApiInterfaceRx, stashId: AccountId): Observable<MultiResult> {
|
||||
return api.queryMulti<MultiResult>([
|
||||
[api.query.staking.bonded, stashId],
|
||||
[api.query.staking.nominators, stashId],
|
||||
[api.query.staking.payee, stashId],
|
||||
[api.query.staking.validators, stashId],
|
||||
[api.query.staking.stakers, stashId]
|
||||
]);
|
||||
function getLedgers (api: ApiInterfaceRx, optIds: (Option<AccountId> | null)[], { withLedger = false }: StakingQueryFlags): Observable<Option<StakingLedger>[]> {
|
||||
const ids = optIds
|
||||
.filter((opt): opt is Option<AccountId> => withLedger && !!opt && opt.isSome)
|
||||
.map((opt) => opt.unwrap());
|
||||
const emptyLed = api.registry.createType('Option<StakingLedger>');
|
||||
|
||||
return (
|
||||
ids.length
|
||||
? api.query.staking.ledger.multi<Option<StakingLedger>>(ids)
|
||||
: of([])
|
||||
).pipe(
|
||||
map((optLedgers): Option<StakingLedger>[] => {
|
||||
let offset = -1;
|
||||
|
||||
return optIds.map((opt): Option<StakingLedger> =>
|
||||
opt && opt.isSome
|
||||
? optLedgers[++offset] || emptyLed
|
||||
: emptyLed
|
||||
);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
function retrieveCurr (api: ApiInterfaceRx, stashIds: AccountId[], activeEra: EraIndex, { withDestination, withExposure, withLedger, withNominations, withPrefs }: QueryFlags): Observable<MultiResultCombo[]> {
|
||||
const emptyCont = api.registry.createType('Option<AccountId>');
|
||||
function getStashInfo (api: ApiInterfaceRx, stashIds: AccountId[], activeEra: EraIndex, { withController, withDestination, withExposure, withLedger, withNominations, withPrefs }: StakingQueryFlags): Observable<[(Option<AccountId> | null)[], Option<Nominations>[], RewardDestination[], ValidatorPrefs[], Exposure[]]> {
|
||||
const emptyNoms = api.registry.createType('Option<Nominations>');
|
||||
const emptyRewa = api.registry.createType('RewardDestination');
|
||||
const emptyExpo = api.registry.createType('Exposure');
|
||||
const emptyPrefs = api.registry.createType('ValidatorPrefs');
|
||||
|
||||
return combineLatest([
|
||||
withLedger
|
||||
withController || withLedger
|
||||
? api.query.staking.bonded.multi<Option<AccountId>>(stashIds)
|
||||
: of(stashIds.map(() => emptyCont)),
|
||||
withNominations && api.query.staking.nominators
|
||||
: of(stashIds.map(() => null)),
|
||||
withNominations
|
||||
? api.query.staking.nominators.multi<Option<Nominations>>(stashIds)
|
||||
: of(stashIds.map(() => emptyNoms)),
|
||||
withDestination
|
||||
@@ -80,67 +72,43 @@ function retrieveCurr (api: ApiInterfaceRx, stashIds: AccountId[], activeEra: Er
|
||||
withExposure
|
||||
? api.query.staking.erasStakers.multi<Exposure>(stashIds.map((stashId) => [activeEra, stashId]))
|
||||
: of(stashIds.map(() => emptyExpo))
|
||||
]).pipe(
|
||||
map(([controllerIdOpt, nominatorsOpt, rewardDestination, validatorPrefs, exposure]): MultiResultCombo[] =>
|
||||
controllerIdOpt.map((controllerIdOpt, index): MultiResultCombo =>
|
||||
[controllerIdOpt, nominatorsOpt[index], rewardDestination[index], validatorPrefs[index], exposure[index]]
|
||||
]);
|
||||
}
|
||||
|
||||
function getBatch (api: ApiInterfaceRx, activeEra: EraIndex, stashIds: AccountId[], flags: StakingQueryFlags): Observable<DeriveStakingQuery[]> {
|
||||
return getStashInfo(api, stashIds, activeEra, flags).pipe(
|
||||
switchMap(([controllerIdOpt, nominatorsOpt, rewardDestination, validatorPrefs, exposure]): Observable<DeriveStakingQuery[]> =>
|
||||
getLedgers(api, controllerIdOpt, flags).pipe(
|
||||
map((stakingLedgerOpts) =>
|
||||
stashIds.map((stashId, index) =>
|
||||
parseDetails(stashId, controllerIdOpt[index], nominatorsOpt[index], rewardDestination[index], validatorPrefs[index], exposure[index], stakingLedgerOpts[index])
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function retrieveControllers (api: ApiInterfaceRx, optControllerIds: Option<AccountId>[]): Observable<Option<StakingLedger>[]> {
|
||||
const ids = optControllerIds.filter((opt) => opt.isSome).map((opt) => opt.unwrap());
|
||||
const emptyLed = api.registry.createType('Option<StakingLedger>');
|
||||
|
||||
if (!ids.length) {
|
||||
return of(optControllerIds.map(() => emptyLed));
|
||||
}
|
||||
|
||||
return api.query.staking.ledger.multi<Option<StakingLedger>>(ids).pipe(
|
||||
map((optLedgers): Option<StakingLedger>[] => {
|
||||
let offset = -1;
|
||||
|
||||
return optControllerIds.map((opt): Option<StakingLedger> =>
|
||||
opt.isSome
|
||||
? optLedgers[++offset]
|
||||
: emptyLed
|
||||
);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
//
|
||||
/**
|
||||
* @description From a stash, retrieve the controllerId and all relevant details
|
||||
*/
|
||||
export function query (instanceId: string, api: ApiInterfaceRx): (accountId: Uint8Array | string, flags: QueryFlags) => Observable<DeriveStakingQuery> {
|
||||
return memo(instanceId, (accountId: Uint8Array | string, flags: QueryFlags): Observable<DeriveStakingQuery> =>
|
||||
export function query (instanceId: string, api: ApiInterfaceRx): (accountId: Uint8Array | string, flags: StakingQueryFlags) => Observable<DeriveStakingQuery> {
|
||||
return memo(instanceId, (accountId: Uint8Array | string, flags: StakingQueryFlags): Observable<DeriveStakingQuery> =>
|
||||
api.derive.staking.queryMulti([accountId], flags).pipe(
|
||||
map(([first]) => first)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
export function queryMulti (instanceId: string, api: ApiInterfaceRx): (accountIds: (Uint8Array | string)[], flags: QueryFlags) => Observable<DeriveStakingQuery[]> {
|
||||
return memo(instanceId, (accountIds: (Uint8Array | string)[], flags: QueryFlags): Observable<DeriveStakingQuery[]> =>
|
||||
export function queryMulti (instanceId: string, api: ApiInterfaceRx): (accountIds: (Uint8Array | string)[], flags: StakingQueryFlags) => Observable<DeriveStakingQuery[]> {
|
||||
return memo(instanceId, (accountIds: (Uint8Array | string)[], flags: StakingQueryFlags): Observable<DeriveStakingQuery[]> =>
|
||||
accountIds.length
|
||||
? api.derive.session.indexes().pipe(
|
||||
switchMap(({ activeEra }): Observable<DeriveStakingQuery[]> => {
|
||||
const stashIds = accountIds.map((accountId) => api.registry.createType('AccountId', accountId));
|
||||
|
||||
return (
|
||||
isFunction(api.query.staking.erasStakers)
|
||||
? retrieveCurr(api, stashIds, activeEra, flags)
|
||||
: combineLatest(stashIds.map((stashId) => retrievePrev(api, stashId)))
|
||||
).pipe(
|
||||
switchMap((results): Observable<DeriveStakingQuery[]> =>
|
||||
retrieveControllers(api, results.map(([optController]) => optController)).pipe(
|
||||
map((stakingLedgerOpts) =>
|
||||
stashIds.map((stashId, index) => parseDetails(stashId, results[index], stakingLedgerOpts[index]))
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
return getBatch(api, activeEra, stashIds, flags);
|
||||
})
|
||||
)
|
||||
: of([])
|
||||
|
||||
@@ -21,7 +21,6 @@ type ErasResult = [{ unwrapOr: (value: BN) => BN }, DeriveEraPoints[], DeriveEra
|
||||
const ZERO = new BN(0);
|
||||
const MIN_ONE = new BN(-1);
|
||||
const COMM_DIV = new BN(1_000_000_000);
|
||||
const MAX_ERAS = new BN(1_000_000_000);
|
||||
|
||||
function parseRewards (api: ApiInterfaceRx, stashId: AccountId, [, erasPoints, erasPrefs, erasRewards]: ErasResult, exposures: DeriveStakerExposure[]): DeriveStakerReward[] {
|
||||
return exposures.map(({ era, isEmpty, isValidator, nominating, validators: eraValidators }): DeriveStakerReward => {
|
||||
@@ -126,11 +125,7 @@ function filterRewards (api: ApiInterfaceRx, eras: EraIndex[], { migrateEra, rew
|
||||
const validators = uniqValidators(rewards);
|
||||
const filter = filterEras(eras, stakingLedger);
|
||||
|
||||
return (
|
||||
isFunction(api.tx.staking.payoutStakers)
|
||||
? api.derive.staking.queryMulti(validators, { withLedger: true })
|
||||
: of([])
|
||||
).pipe(
|
||||
return api.derive.staking.queryMulti(validators, { withLedger: true }).pipe(
|
||||
map((queryValidators): DeriveStakerReward[] =>
|
||||
rewards
|
||||
.filter(({ isEmpty }) => !isEmpty)
|
||||
@@ -162,7 +157,7 @@ export function _stakerRewardsEras (instanceId: string, api: ApiInterfaceRx): (e
|
||||
combineLatest([
|
||||
isFunction(api.query.staking.migrateEra)
|
||||
? api.query.staking.migrateEra<Option<EraIndex>>()
|
||||
: of({ unwrapOr: () => isFunction(api.tx.staking.payoutStakers) ? ZERO : MAX_ERAS }),
|
||||
: of(api.registry.createType('Option<EraIndex>')),
|
||||
api.derive.staking._erasPoints(eras, withActive),
|
||||
api.derive.staking._erasPrefs(eras, withActive),
|
||||
api.derive.staking._erasRewards(eras, withActive)
|
||||
|
||||
@@ -144,3 +144,12 @@ export interface DeriveStakingOverview extends DeriveSessionIndexes {
|
||||
nextElected: AccountId[];
|
||||
validators: AccountId[];
|
||||
}
|
||||
|
||||
export interface StakingQueryFlags {
|
||||
withController?: boolean;
|
||||
withDestination?: boolean;
|
||||
withExposure?: boolean;
|
||||
withLedger?: boolean;
|
||||
withNominations?: boolean;
|
||||
withPrefs?: boolean;
|
||||
}
|
||||
|
||||
@@ -3,15 +3,17 @@
|
||||
|
||||
import type { ApiInterfaceRx } from '@polkadot/api/types';
|
||||
import type { Observable } from '@polkadot/x-rxjs';
|
||||
import type { DeriveStakingWaiting } from '../types';
|
||||
import type { DeriveStakingWaiting, StakingQueryFlags } from '../types';
|
||||
|
||||
import { combineLatest } from '@polkadot/x-rxjs';
|
||||
import { map, switchMap } from '@polkadot/x-rxjs/operators';
|
||||
|
||||
import { memo } from '../util';
|
||||
|
||||
export function waitingInfo (instanceId: string, api: ApiInterfaceRx): () => Observable<DeriveStakingWaiting> {
|
||||
return memo(instanceId, (): Observable<DeriveStakingWaiting> =>
|
||||
const DEFAULT_FLAGS = { withController: true, withPrefs: true };
|
||||
|
||||
export function waitingInfo (instanceId: string, api: ApiInterfaceRx): (flags?: StakingQueryFlags) => Observable<DeriveStakingWaiting> {
|
||||
return memo(instanceId, (flags: StakingQueryFlags = DEFAULT_FLAGS): Observable<DeriveStakingWaiting> =>
|
||||
combineLatest([
|
||||
api.derive.staking.validators(),
|
||||
api.derive.staking.stashes()
|
||||
@@ -20,7 +22,7 @@ export function waitingInfo (instanceId: string, api: ApiInterfaceRx): () => Obs
|
||||
const elected = nextElected.map((a) => a.toString());
|
||||
const waiting = stashes.filter((v) => !elected.includes(v.toString()));
|
||||
|
||||
return api.derive.staking.queryMulti(waiting, { withLedger: true, withPrefs: true }).pipe(
|
||||
return api.derive.staking.queryMulti(waiting, flags).pipe(
|
||||
map((info): DeriveStakingWaiting => ({
|
||||
info,
|
||||
waiting
|
||||
|
||||
Reference in New Issue
Block a user