Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update api.derive.staking calls with breaking changes #5860

Merged
merged 11 commits into from
Apr 22, 2024
25 changes: 16 additions & 9 deletions packages/api-derive/src/staking/ownExposure.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,39 @@
// SPDX-License-Identifier: Apache-2.0

import type { Observable } from 'rxjs';
import type { Option, u32 } from '@polkadot/types';
import type { EraIndex } from '@polkadot/types/interfaces';
import type { SpStakingExposurePage } from '@polkadot/types/lookup';
import type { AnyNumber } from '@polkadot/types-codec/types';
import type { DeriveApi, DeriveOwnExposure } from '../types.js';

import { combineLatest, map, of } from 'rxjs';

import { firstMemo, memo } from '../util/index.js';
import { erasHistoricApplyAccount } from './util.js';

export function _ownExposures (instanceId: string, api: DeriveApi): (accountId: Uint8Array | string, eras: EraIndex[], withActive: boolean) => Observable<DeriveOwnExposure[]> {
return memo(instanceId, (accountId: Uint8Array | string, eras: EraIndex[], _withActive: boolean): Observable<DeriveOwnExposure[]> =>
eras.length
export function _ownExposures (instanceId: string, api: DeriveApi): (accountId: Uint8Array | string, eras: EraIndex[], withActive: boolean, page: u32 | AnyNumber) => Observable<DeriveOwnExposure[]> {
return memo(instanceId, (accountId: Uint8Array | string, eras: EraIndex[], _withActive: boolean, page: u32 | AnyNumber): Observable<DeriveOwnExposure[]> => {
return eras.length
? combineLatest([
// Backwards and forward compat for historical integrity when using `erasHistoricApplyAccount`
combineLatest(eras.map((e) => api.query.staking.erasStakersClipped(e, accountId))),
combineLatest(eras.map((e) => api.query.staking.erasStakers(e, accountId)))
combineLatest(eras.map((e) => api.query.staking.erasStakers(e, accountId))),
combineLatest(eras.map((e) => api.query.staking.erasStakersPaged<Option<SpStakingExposurePage>>(e, accountId, page))),
combineLatest(eras.map((e) => api.query.staking.erasStakersOverview(e, accountId)))
]).pipe(
map(([clp, exp]): DeriveOwnExposure[] =>
eras.map((era, index) => ({ clipped: clp[index], era, exposure: exp[index] }))
map(([clp, exp, paged, expMeta]): DeriveOwnExposure[] =>
eras.map((era, index) => ({ clipped: clp[index], era, exposure: exp[index], exposureMeta: expMeta[index], exposurePaged: paged[index] }))
)
)
: of([])
: of([]);
}
);
}

export const ownExposure = /*#__PURE__*/ firstMemo(
(api: DeriveApi, accountId: Uint8Array | string, era: EraIndex) =>
api.derive.staking._ownExposures(accountId, [era], true)
(api: DeriveApi, accountId: Uint8Array | string, era: EraIndex, page?: u32 | AnyNumber) =>
api.derive.staking._ownExposures(accountId, [era], true, page || 0)
);

export const ownExposures = /*#__PURE__*/ erasHistoricApplyAccount('_ownExposures');
41 changes: 24 additions & 17 deletions packages/api-derive/src/staking/query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@
// SPDX-License-Identifier: Apache-2.0

import type { Observable } from 'rxjs';
import type { Option } from '@polkadot/types';
import type { Option, u32 } from '@polkadot/types';
import type { AccountId, EraIndex } from '@polkadot/types/interfaces';
import type { PalletStakingNominations, PalletStakingRewardDestination, PalletStakingStakingLedger, PalletStakingValidatorPrefs, SpStakingExposure } from '@polkadot/types/lookup';
import type { PalletStakingNominations, PalletStakingRewardDestination, PalletStakingStakingLedger, PalletStakingValidatorPrefs, SpStakingExposurePage, SpStakingPagedExposureMetadata } from '@polkadot/types/lookup';
import type { AnyNumber } from '@polkadot/types-codec/types';
import type { DeriveApi, DeriveStakingQuery, StakingQueryFlags } from '../types.js';

import { combineLatest, map, of, switchMap } from 'rxjs';
Expand All @@ -19,11 +20,12 @@ function rewardDestinationCompat (rewardDestination: PalletStakingRewardDestinat
: (rewardDestination as PalletStakingRewardDestination);
}

function parseDetails (stashId: AccountId, controllerIdOpt: Option<AccountId> | null, nominatorsOpt: Option<PalletStakingNominations>, rewardDestinationOpts: Option<PalletStakingRewardDestination> | PalletStakingRewardDestination, validatorPrefs: PalletStakingValidatorPrefs, exposure: SpStakingExposure, stakingLedgerOpt: Option<PalletStakingStakingLedger>): DeriveStakingQuery {
function parseDetails (stashId: AccountId, controllerIdOpt: Option<AccountId> | null, nominatorsOpt: Option<PalletStakingNominations>, rewardDestinationOpts: Option<PalletStakingRewardDestination> | PalletStakingRewardDestination, validatorPrefs: PalletStakingValidatorPrefs, exposure: Option<SpStakingExposurePage>, stakingLedgerOpt: Option<PalletStakingStakingLedger>, exposureMeta: Option<SpStakingPagedExposureMetadata>): DeriveStakingQuery {
return {
accountId: stashId,
controllerId: controllerIdOpt?.unwrapOr(null) || null,
exposure,
exposureMeta,
exposurePaged: exposure,
nominators: nominatorsOpt.isSome
? nominatorsOpt.unwrap().targets
: [],
Expand Down Expand Up @@ -57,11 +59,12 @@ function getLedgers (api: DeriveApi, optIds: (Option<AccountId> | null)[], { wit
);
}

function getStashInfo (api: DeriveApi, stashIds: AccountId[], activeEra: EraIndex, { withController, withDestination, withExposure, withLedger, withNominations, withPrefs }: StakingQueryFlags): Observable<[(Option<AccountId> | null)[], Option<PalletStakingNominations>[], Option<PalletStakingRewardDestination>[], PalletStakingValidatorPrefs[], SpStakingExposure[]]> {
function getStashInfo (api: DeriveApi, stashIds: AccountId[], activeEra: EraIndex, { withController, withDestination, withExposure, withExposureMeta, withLedger, withNominations, withPrefs }: StakingQueryFlags, page: u32 | AnyNumber): Observable<[(Option<AccountId> | null)[], Option<PalletStakingNominations>[], Option<PalletStakingRewardDestination>[], PalletStakingValidatorPrefs[], Option<SpStakingExposurePage>[], Option<SpStakingPagedExposureMetadata>[]]> {
const emptyNoms = api.registry.createType<Option<PalletStakingNominations>>('Option<Nominations>');
const emptyRewa = api.registry.createType<Option<PalletStakingRewardDestination>>('RewardDestination');
const emptyExpo = api.registry.createType<SpStakingExposure>('Exposure');
const emptyExpo = api.registry.createType<Option<SpStakingExposurePage>>('Option<SpStakingExposurePage>');
const emptyPrefs = api.registry.createType<PalletStakingValidatorPrefs>('ValidatorPrefs');
const emptyExpoMeta = api.registry.createType<Option<SpStakingPagedExposureMetadata>>('Option<SpStakingPagedExposureMetadata>');

return combineLatest([
withController || withLedger
Expand All @@ -77,18 +80,21 @@ function getStashInfo (api: DeriveApi, stashIds: AccountId[], activeEra: EraInde
? combineLatest(stashIds.map((s) => api.query.staking.validators(s)))
: of(stashIds.map(() => emptyPrefs)),
withExposure
? combineLatest(stashIds.map((s) => api.query.staking.erasStakers(activeEra, s)))
: of(stashIds.map(() => emptyExpo))
? combineLatest(stashIds.map((s) => api.query.staking.erasStakersPaged<Option<SpStakingExposurePage>>(activeEra, s, page)))
: of(stashIds.map(() => emptyExpo)),
withExposureMeta
? combineLatest(stashIds.map((s) => api.query.staking.erasStakersOverview(activeEra, s)))
: of(stashIds.map(() => emptyExpoMeta))
]);
}

function getBatch (api: DeriveApi, activeEra: EraIndex, stashIds: AccountId[], flags: StakingQueryFlags): Observable<DeriveStakingQuery[]> {
return getStashInfo(api, stashIds, activeEra, flags).pipe(
switchMap(([controllerIdOpt, nominatorsOpt, rewardDestination, validatorPrefs, exposure]): Observable<DeriveStakingQuery[]> =>
function getBatch (api: DeriveApi, activeEra: EraIndex, stashIds: AccountId[], flags: StakingQueryFlags, page: u32 | AnyNumber): Observable<DeriveStakingQuery[]> {
return getStashInfo(api, stashIds, activeEra, flags, page).pipe(
switchMap(([controllerIdOpt, nominatorsOpt, rewardDestination, validatorPrefs, exposure, exposureMeta]): 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])
parseDetails(stashId, controllerIdOpt[index], nominatorsOpt[index], rewardDestination[index], validatorPrefs[index], exposure[index], stakingLedgerOpts[index], exposureMeta[index])
)
)
)
Expand All @@ -101,18 +107,19 @@ function getBatch (api: DeriveApi, activeEra: EraIndex, stashIds: AccountId[], f
* @description From a stash, retrieve the controllerId and all relevant details
*/
export const query = /*#__PURE__*/ firstMemo(
(api: DeriveApi, accountId: Uint8Array | string, flags: StakingQueryFlags) =>
api.derive.staking.queryMulti([accountId], flags)
(api: DeriveApi, accountId: Uint8Array | string, flags: StakingQueryFlags, page?: u32) =>
api.derive.staking.queryMulti([accountId], flags, page)
);

export function queryMulti (instanceId: string, api: DeriveApi): (accountIds: (Uint8Array | string)[], flags: StakingQueryFlags) => Observable<DeriveStakingQuery[]> {
return memo(instanceId, (accountIds: (Uint8Array | string)[], flags: StakingQueryFlags): Observable<DeriveStakingQuery[]> =>
export function queryMulti (instanceId: string, api: DeriveApi): (accountIds: (Uint8Array | string)[], flags: StakingQueryFlags, page?: u32 | AnyNumber) => Observable<DeriveStakingQuery[]> {
return memo(instanceId, (accountIds: (Uint8Array | string)[], flags: StakingQueryFlags, page?: u32 | AnyNumber): Observable<DeriveStakingQuery[]> =>
api.derive.session.indexes().pipe(
switchMap(({ activeEra }): Observable<DeriveStakingQuery[]> => {
const stashIds = accountIds.map((a) => api.registry.createType('AccountId', a));
const p = page || 0;

return stashIds.length
? getBatch(api, activeEra, stashIds, flags)
? getBatch(api, activeEra, stashIds, flags, p)
: of([]);
})
)
Expand Down
9 changes: 7 additions & 2 deletions packages/api-derive/src/staking/types.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
// Copyright 2017-2024 @polkadot/api-derive authors & contributors
// SPDX-License-Identifier: Apache-2.0

import type { Option } from '@polkadot/types';
import type { AccountId, Balance, EraIndex, RewardPoint } from '@polkadot/types/interfaces';
import type { PalletStakingRewardDestination, PalletStakingStakingLedger, PalletStakingValidatorPrefs, SpStakingExposure, SpStakingExposurePage } from '@polkadot/types/lookup';
import type { PalletStakingRewardDestination, PalletStakingStakingLedger, PalletStakingValidatorPrefs, SpStakingExposure, SpStakingExposurePage, SpStakingPagedExposureMetadata } from '@polkadot/types/lookup';
import type { BN } from '@polkadot/util';
import type { DeriveSessionIndexes } from '../session/types.js';

Expand Down Expand Up @@ -42,8 +43,10 @@ export interface DeriveStakerPoints {

export interface DeriveOwnExposure {
clipped: SpStakingExposure;
exposurePaged: Option<SpStakingExposurePage>;
era: EraIndex;
exposure: SpStakingExposure;
exposureMeta: Option<SpStakingPagedExposureMetadata>;
}

export interface DeriveEraExposureNominating {
Expand Down Expand Up @@ -115,7 +118,8 @@ export interface DeriveStakingValidators {

export interface DeriveStakingStash {
controllerId: AccountId | null;
exposure: SpStakingExposure;
exposurePaged: Option<SpStakingExposurePage>;
exposureMeta: Option<SpStakingPagedExposureMetadata>;
nominators: AccountId[];
rewardDestination: PalletStakingRewardDestination | null;
stashId: AccountId;
Expand Down Expand Up @@ -160,4 +164,5 @@ export interface StakingQueryFlags {
withLedger?: boolean;
withNominations?: boolean;
withPrefs?: boolean;
withExposureMeta?: boolean;
}
6 changes: 4 additions & 2 deletions packages/api-derive/src/staking/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@

import type { Observable } from 'rxjs';
import type { ObsInnerType } from '@polkadot/api-base/types';
import type { u32 } from '@polkadot/types';
import type { EraIndex } from '@polkadot/types/interfaces';
import type { AnyNumber } from '@polkadot/types-codec/types';
import type { ExactDerive } from '../derive.js';
import type { DeriveApi } from '../types.js';

Expand Down Expand Up @@ -60,9 +62,9 @@ export function erasHistoricApplyAccount <F extends '_ownExposures' | '_ownSlash
return (instanceId: string, api: DeriveApi) =>
// Cannot quite get the typing right, but it is right in the code
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
memo(instanceId, (accountId: string | Uint8Array, withActive = false) =>
memo(instanceId, (accountId: string | Uint8Array, withActive = false, page?: u32 | AnyNumber) =>
api.derive.staking.erasHistoric(withActive).pipe(
switchMap((e) => api.derive.staking[fn](accountId, e, withActive))
switchMap((e) => api.derive.staking[fn](accountId, e, withActive, page || 0))
)
) as any;
}
Expand Down
4 changes: 2 additions & 2 deletions packages/api-derive/src/staking/validators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ import { memo } from '../util/index.js';

export function nextElected (instanceId: string, api: DeriveApi): () => Observable<AccountId[]> {
return memo(instanceId, (): Observable<AccountId[]> =>
api.query.staking.erasStakers
api.query.staking.erasStakersPaged
? api.derive.session.indexes().pipe(
// only populate for next era in the last session, so track both here - entries are not
// subscriptions, so we need a trigger - currentIndex acts as that trigger to refresh
switchMap(({ currentEra }) => api.query.staking.erasStakers.keys(currentEra)),
switchMap(({ currentEra }) => api.query.staking.erasStakersPaged.keys(currentEra)),
map((keys) => keys.map(({ args: [, accountId] }) => accountId))
)
: api.query.staking['currentElected']<AccountId[]>()
Expand Down