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

Add claimedRewardsEra to api.derive.staking.query for compatibility with legacyClaimedRewards #5862

Merged
merged 7 commits into from
Apr 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 3 additions & 3 deletions packages/api-derive/src/staking/electedInfo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ function combineAccounts (nextElected: AccountId[], validators: AccountId[]): Ac
return arrayFlatten([nextElected, validators.filter((v) => !nextElected.find((n) => n.eq(v)))]);
}

export function electedInfo (instanceId: string, api: DeriveApi): (flags?: StakingQueryFlags) => Observable<DeriveStakingElected> {
return memo(instanceId, (flags: StakingQueryFlags = DEFAULT_FLAGS): Observable<DeriveStakingElected> =>
export function electedInfo (instanceId: string, api: DeriveApi): (flags?: StakingQueryFlags, page?: number) => Observable<DeriveStakingElected> {
return memo(instanceId, (flags: StakingQueryFlags = DEFAULT_FLAGS, page = 0): Observable<DeriveStakingElected> =>
api.derive.staking.validators().pipe(
switchMap(({ nextElected, validators }): Observable<DeriveStakingElected> =>
api.derive.staking.queryMulti(combineAccounts(nextElected, validators), flags).pipe(
api.derive.staking.queryMulti(combineAccounts(nextElected, validators), flags, page).pipe(
map((info): DeriveStakingElected => ({
info,
nextElected,
Expand Down
50 changes: 44 additions & 6 deletions packages/api-derive/src/staking/query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// SPDX-License-Identifier: Apache-2.0

import type { Observable } from 'rxjs';
import type { Option, u32 } from '@polkadot/types';
import type { Option, u32, Vec } from '@polkadot/types';
import type { AccountId, EraIndex } from '@polkadot/types/interfaces';
import type { PalletStakingNominations, PalletStakingRewardDestination, PalletStakingStakingLedger, PalletStakingValidatorPrefs, SpStakingExposurePage, SpStakingPagedExposureMetadata } from '@polkadot/types/lookup';
import type { AnyNumber } from '@polkadot/types-codec/types';
Expand All @@ -20,9 +20,14 @@ 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: Option<SpStakingExposurePage>, stakingLedgerOpt: Option<PalletStakingStakingLedger>, exposureMeta: Option<SpStakingPagedExposureMetadata>): DeriveStakingQuery {
function filterClaimedRewards (api: DeriveApi, cl: number[]): Vec<u32> {
return api.registry.createType('Vec<u32>', cl.filter((c) => c !== -1));
}

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

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>[]]> {
function getStashInfo (api: DeriveApi, stashIds: AccountId[], activeEra: EraIndex, { withClaimedRewardsEras, withController, withDestination, withExposure, withExposureMeta, withLedger, withNominations, withPrefs }: StakingQueryFlags, page: u32 | AnyNumber): Observable<[(Option<AccountId> | null)[], Option<PalletStakingNominations>[], Option<PalletStakingRewardDestination>[], PalletStakingValidatorPrefs[], Option<SpStakingExposurePage>[], Option<SpStakingPagedExposureMetadata>[], number[][]]> {
const emptyNoms = api.registry.createType<Option<PalletStakingNominations>>('Option<Nominations>');
const emptyRewa = api.registry.createType<Option<PalletStakingRewardDestination>>('RewardDestination');
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>');
const emptyClaimedRewards = [-1];

const depth = Number(api.consts.staking.historyDepth.toNumber());
const eras = new Array(depth).fill(0).map((_, idx) => {
if (idx === 0) {
return activeEra.toNumber() - 1;
}

return activeEra.toNumber() - idx - 1;
});

return combineLatest([
withController || withLedger
Expand All @@ -84,17 +99,40 @@ function getStashInfo (api: DeriveApi, stashIds: AccountId[], activeEra: EraInde
: of(stashIds.map(() => emptyExpo)),
withExposureMeta
? combineLatest(stashIds.map((s) => api.query.staking.erasStakersOverview(activeEra, s)))
: of(stashIds.map(() => emptyExpoMeta))
: of(stashIds.map(() => emptyExpoMeta)),
withClaimedRewardsEras
? combineLatest(stashIds.map((s) =>
combineLatest([
combineLatest(eras.map((e) => api.query.staking.claimedRewards(e, s))),
combineLatest(eras.map((e) => api.query.staking.erasStakersOverview(e, s)))
]))
).pipe(
map((r) => {
return r.map(([stashClaimedEras, overview]) => {
// stashClaimedEras length will match the length of eras
return stashClaimedEras.map((claimedReward, idx) => {
const o = overview[idx].isSome && overview[idx].unwrap();

if (claimedReward.length === (o && o.pageCount.toNumber())) {
return eras[idx];
}

return -1;
});
});
})
)
: of(stashIds.map(() => emptyClaimedRewards))
]);
}

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[]> =>
switchMap(([controllerIdOpt, nominatorsOpt, rewardDestination, validatorPrefs, exposure, exposureMeta, claimedRewardsEras]): 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], exposureMeta[index])
parseDetails(api, stashId, controllerIdOpt[index], nominatorsOpt[index], rewardDestination[index], validatorPrefs[index], exposure[index], stakingLedgerOpts[index], exposureMeta[index], claimedRewardsEras[index])
)
)
)
Expand Down
31 changes: 17 additions & 14 deletions packages/api-derive/src/staking/stakerRewards.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,15 @@ import { firstMemo, memo } from '../util/index.js';
type ErasResult = [DeriveEraPoints[], DeriveEraPrefs[], DeriveEraRewards[]];

// handle compatibility between generations of structures
function extractCompatRewards (ledger?: PalletStakingStakingLedger): u32[] {
return ledger
function extractCompatRewards (claimedRewardsEras: Vec<u32>, ledger?: PalletStakingStakingLedger): u32[] {
const l = ledger
? (
ledger.legacyClaimedRewards ||
(ledger as PalletStakingStakingLedger & { claimedRewards: Vec<u32> }).claimedRewards
)
: [];
(ledger as PalletStakingStakingLedger & { claimedRewards: Vec<u32> }).claimedRewards
).toArray()
: [] as unknown as Vec<u32>;

return claimedRewardsEras.toArray().concat(l);
}

function parseRewards (api: DeriveApi, stashId: AccountId, [erasPoints, erasPrefs, erasRewards]: ErasResult, exposures: DeriveStakerExposure[]): DeriveStakerReward[] {
Expand Down Expand Up @@ -111,7 +113,7 @@ function allUniqValidators (rewards: DeriveStakerReward[][]): [string[], string[
}, [[], []]);
}

function removeClaimed (validators: string[], queryValidators: DeriveStakingQuery[], reward: DeriveStakerReward): void {
function removeClaimed (validators: string[], queryValidators: DeriveStakingQuery[], reward: DeriveStakerReward, claimedRewardsEras: Vec<u32>): void {
const rm: string[] = [];

Object.keys(reward.validators).forEach((validatorId): void => {
Expand All @@ -120,7 +122,7 @@ function removeClaimed (validators: string[], queryValidators: DeriveStakingQuer
if (index !== -1) {
const valLedger = queryValidators[index].stakingLedger;

if (extractCompatRewards(valLedger).some((e) => reward.era.eq(e))) {
if (extractCompatRewards(claimedRewardsEras, valLedger).some((e) => reward.era.eq(e))) {
rm.push(validatorId);
}
}
Expand All @@ -131,8 +133,8 @@ function removeClaimed (validators: string[], queryValidators: DeriveStakingQuer
});
}

function filterRewards (eras: EraIndex[], valInfo: [string, DeriveStakingQuery][], { rewards, stakingLedger }: { rewards: DeriveStakerReward[]; stakingLedger: PalletStakingStakingLedger }): DeriveStakerReward[] {
const filter = eras.filter((e) => !extractCompatRewards(stakingLedger).some((s) => s.eq(e)));
function filterRewards (eras: EraIndex[], valInfo: [string, DeriveStakingQuery][], { claimedRewardsEras, rewards, stakingLedger }: { rewards: DeriveStakerReward[]; stakingLedger: PalletStakingStakingLedger, claimedRewardsEras: Vec<u32> }): DeriveStakerReward[] {
const filter = eras.filter((e) => !extractCompatRewards(claimedRewardsEras, stakingLedger).some((s) => s.eq(e)));
const validators = valInfo.map(([v]) => v);
const queryValidators = valInfo.map(([, q]) => q);

Expand All @@ -143,7 +145,7 @@ function filterRewards (eras: EraIndex[], valInfo: [string, DeriveStakingQuery][
return false;
}

removeClaimed(validators, queryValidators, reward);
removeClaimed(validators, queryValidators, reward, claimedRewardsEras);

return true;
})
Expand Down Expand Up @@ -173,8 +175,8 @@ export function _stakerRewards (instanceId: string, api: DeriveApi): (accountIds
api.derive.staking._stakerRewardsEras(eras, withActive)
]).pipe(
switchMap(([queries, exposures, erasResult]): Observable<DeriveStakerReward[][]> => {
const allRewards = queries.map(({ stakingLedger, stashId }, index): DeriveStakerReward[] =>
(!stashId || !stakingLedger)
const allRewards = queries.map(({ claimedRewardsEras, stakingLedger, stashId }, index): DeriveStakerReward[] =>
(!stashId || (!stakingLedger && !claimedRewardsEras))
? []
: parseRewards(api, stashId, erasResult, exposures[index])
);
Expand All @@ -185,9 +187,9 @@ export function _stakerRewards (instanceId: string, api: DeriveApi): (accountIds

const [allValidators, stashValidators] = allUniqValidators(allRewards);

return api.derive.staking.queryMulti(allValidators, { withLedger: true }).pipe(
return api.derive.staking.queryMulti(allValidators, { withClaimedRewardsEras: true, withLedger: true }).pipe(
map((queriedVals): DeriveStakerReward[][] =>
queries.map(({ stakingLedger }, index): DeriveStakerReward[] =>
queries.map(({ claimedRewardsEras, stakingLedger }, index): DeriveStakerReward[] =>
filterRewards(
eras,
stashValidators[index]
Expand All @@ -197,6 +199,7 @@ export function _stakerRewards (instanceId: string, api: DeriveApi): (accountIds
])
.filter((v): v is [string, DeriveStakingQuery] => !!v[1]),
{
claimedRewardsEras,
rewards: allRewards[index],
stakingLedger
}
Expand Down
4 changes: 3 additions & 1 deletion packages/api-derive/src/staking/types.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright 2017-2024 @polkadot/api-derive authors & contributors
// SPDX-License-Identifier: Apache-2.0

import type { Option } from '@polkadot/types';
import type { Option, u32, Vec } from '@polkadot/types';
import type { AccountId, Balance, EraIndex, RewardPoint } from '@polkadot/types/interfaces';
import type { PalletStakingRewardDestination, PalletStakingStakingLedger, PalletStakingValidatorPrefs, SpStakingExposure, SpStakingExposurePage, SpStakingPagedExposureMetadata } from '@polkadot/types/lookup';
import type { BN } from '@polkadot/util';
Expand Down Expand Up @@ -124,6 +124,7 @@ export interface DeriveStakingStash {
rewardDestination: PalletStakingRewardDestination | null;
stashId: AccountId;
validatorPrefs: PalletStakingValidatorPrefs;
claimedRewardsEras: Vec<u32>
}

export interface DeriveStakingQuery extends DeriveStakingStash {
Expand Down Expand Up @@ -165,4 +166,5 @@ export interface StakingQueryFlags {
withNominations?: boolean;
withPrefs?: boolean;
withExposureMeta?: boolean;
withClaimedRewardsEras?: boolean;
}