Skip to content

Commit b4ebdc2

Browse files
authored
Add claimedRewardsEra to api.derive.staking.query for compatibility with legacyClaimedRewards (#5862)
* Fix ClaimedRewards breaking change * fix some naming * remove consoles * Fix logic * fix output type * Fix StakerRewards * Fix electedInfo
1 parent 6e4dc0b commit b4ebdc2

File tree

4 files changed

+67
-24
lines changed

4 files changed

+67
-24
lines changed

packages/api-derive/src/staking/electedInfo.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,11 @@ function combineAccounts (nextElected: AccountId[], validators: AccountId[]): Ac
1717
return arrayFlatten([nextElected, validators.filter((v) => !nextElected.find((n) => n.eq(v)))]);
1818
}
1919

20-
export function electedInfo (instanceId: string, api: DeriveApi): (flags?: StakingQueryFlags) => Observable<DeriveStakingElected> {
21-
return memo(instanceId, (flags: StakingQueryFlags = DEFAULT_FLAGS): Observable<DeriveStakingElected> =>
20+
export function electedInfo (instanceId: string, api: DeriveApi): (flags?: StakingQueryFlags, page?: number) => Observable<DeriveStakingElected> {
21+
return memo(instanceId, (flags: StakingQueryFlags = DEFAULT_FLAGS, page = 0): Observable<DeriveStakingElected> =>
2222
api.derive.staking.validators().pipe(
2323
switchMap(({ nextElected, validators }): Observable<DeriveStakingElected> =>
24-
api.derive.staking.queryMulti(combineAccounts(nextElected, validators), flags).pipe(
24+
api.derive.staking.queryMulti(combineAccounts(nextElected, validators), flags, page).pipe(
2525
map((info): DeriveStakingElected => ({
2626
info,
2727
nextElected,

packages/api-derive/src/staking/query.ts

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// SPDX-License-Identifier: Apache-2.0
33

44
import type { Observable } from 'rxjs';
5-
import type { Option, u32 } from '@polkadot/types';
5+
import type { Option, u32, Vec } from '@polkadot/types';
66
import type { AccountId, EraIndex } from '@polkadot/types/interfaces';
77
import type { PalletStakingNominations, PalletStakingRewardDestination, PalletStakingStakingLedger, PalletStakingValidatorPrefs, SpStakingExposurePage, SpStakingPagedExposureMetadata } from '@polkadot/types/lookup';
88
import type { AnyNumber } from '@polkadot/types-codec/types';
@@ -20,9 +20,14 @@ function rewardDestinationCompat (rewardDestination: PalletStakingRewardDestinat
2020
: (rewardDestination as PalletStakingRewardDestination);
2121
}
2222

23-
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 {
23+
function filterClaimedRewards (api: DeriveApi, cl: number[]): Vec<u32> {
24+
return api.registry.createType('Vec<u32>', cl.filter((c) => c !== -1));
25+
}
26+
27+
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 {
2428
return {
2529
accountId: stashId,
30+
claimedRewardsEras: filterClaimedRewards(api, claimedRewards),
2631
controllerId: controllerIdOpt?.unwrapOr(null) || null,
2732
exposureMeta,
2833
exposurePaged: exposure,
@@ -59,12 +64,22 @@ function getLedgers (api: DeriveApi, optIds: (Option<AccountId> | null)[], { wit
5964
);
6065
}
6166

62-
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>[]]> {
67+
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[][]]> {
6368
const emptyNoms = api.registry.createType<Option<PalletStakingNominations>>('Option<Nominations>');
6469
const emptyRewa = api.registry.createType<Option<PalletStakingRewardDestination>>('RewardDestination');
6570
const emptyExpo = api.registry.createType<Option<SpStakingExposurePage>>('Option<SpStakingExposurePage>');
6671
const emptyPrefs = api.registry.createType<PalletStakingValidatorPrefs>('ValidatorPrefs');
6772
const emptyExpoMeta = api.registry.createType<Option<SpStakingPagedExposureMetadata>>('Option<SpStakingPagedExposureMetadata>');
73+
const emptyClaimedRewards = [-1];
74+
75+
const depth = Number(api.consts.staking.historyDepth.toNumber());
76+
const eras = new Array(depth).fill(0).map((_, idx) => {
77+
if (idx === 0) {
78+
return activeEra.toNumber() - 1;
79+
}
80+
81+
return activeEra.toNumber() - idx - 1;
82+
});
6883

6984
return combineLatest([
7085
withController || withLedger
@@ -84,17 +99,40 @@ function getStashInfo (api: DeriveApi, stashIds: AccountId[], activeEra: EraInde
8499
: of(stashIds.map(() => emptyExpo)),
85100
withExposureMeta
86101
? combineLatest(stashIds.map((s) => api.query.staking.erasStakersOverview(activeEra, s)))
87-
: of(stashIds.map(() => emptyExpoMeta))
102+
: of(stashIds.map(() => emptyExpoMeta)),
103+
withClaimedRewardsEras
104+
? combineLatest(stashIds.map((s) =>
105+
combineLatest([
106+
combineLatest(eras.map((e) => api.query.staking.claimedRewards(e, s))),
107+
combineLatest(eras.map((e) => api.query.staking.erasStakersOverview(e, s)))
108+
]))
109+
).pipe(
110+
map((r) => {
111+
return r.map(([stashClaimedEras, overview]) => {
112+
// stashClaimedEras length will match the length of eras
113+
return stashClaimedEras.map((claimedReward, idx) => {
114+
const o = overview[idx].isSome && overview[idx].unwrap();
115+
116+
if (claimedReward.length === (o && o.pageCount.toNumber())) {
117+
return eras[idx];
118+
}
119+
120+
return -1;
121+
});
122+
});
123+
})
124+
)
125+
: of(stashIds.map(() => emptyClaimedRewards))
88126
]);
89127
}
90128

91129
function getBatch (api: DeriveApi, activeEra: EraIndex, stashIds: AccountId[], flags: StakingQueryFlags, page: u32 | AnyNumber): Observable<DeriveStakingQuery[]> {
92130
return getStashInfo(api, stashIds, activeEra, flags, page).pipe(
93-
switchMap(([controllerIdOpt, nominatorsOpt, rewardDestination, validatorPrefs, exposure, exposureMeta]): Observable<DeriveStakingQuery[]> =>
131+
switchMap(([controllerIdOpt, nominatorsOpt, rewardDestination, validatorPrefs, exposure, exposureMeta, claimedRewardsEras]): Observable<DeriveStakingQuery[]> =>
94132
getLedgers(api, controllerIdOpt, flags).pipe(
95133
map((stakingLedgerOpts) =>
96134
stashIds.map((stashId, index) =>
97-
parseDetails(stashId, controllerIdOpt[index], nominatorsOpt[index], rewardDestination[index], validatorPrefs[index], exposure[index], stakingLedgerOpts[index], exposureMeta[index])
135+
parseDetails(api, stashId, controllerIdOpt[index], nominatorsOpt[index], rewardDestination[index], validatorPrefs[index], exposure[index], stakingLedgerOpts[index], exposureMeta[index], claimedRewardsEras[index])
98136
)
99137
)
100138
)

packages/api-derive/src/staking/stakerRewards.ts

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,15 @@ import { firstMemo, memo } from '../util/index.js';
1818
type ErasResult = [DeriveEraPoints[], DeriveEraPrefs[], DeriveEraRewards[]];
1919

2020
// handle compatibility between generations of structures
21-
function extractCompatRewards (ledger?: PalletStakingStakingLedger): u32[] {
22-
return ledger
21+
function extractCompatRewards (claimedRewardsEras: Vec<u32>, ledger?: PalletStakingStakingLedger): u32[] {
22+
const l = ledger
2323
? (
2424
ledger.legacyClaimedRewards ||
25-
(ledger as PalletStakingStakingLedger & { claimedRewards: Vec<u32> }).claimedRewards
26-
)
27-
: [];
25+
(ledger as PalletStakingStakingLedger & { claimedRewards: Vec<u32> }).claimedRewards
26+
).toArray()
27+
: [] as unknown as Vec<u32>;
28+
29+
return claimedRewardsEras.toArray().concat(l);
2830
}
2931

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

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

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

123-
if (extractCompatRewards(valLedger).some((e) => reward.era.eq(e))) {
125+
if (extractCompatRewards(claimedRewardsEras, valLedger).some((e) => reward.era.eq(e))) {
124126
rm.push(validatorId);
125127
}
126128
}
@@ -131,8 +133,8 @@ function removeClaimed (validators: string[], queryValidators: DeriveStakingQuer
131133
});
132134
}
133135

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

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

146-
removeClaimed(validators, queryValidators, reward);
148+
removeClaimed(validators, queryValidators, reward, claimedRewardsEras);
147149

148150
return true;
149151
})
@@ -173,8 +175,8 @@ export function _stakerRewards (instanceId: string, api: DeriveApi): (accountIds
173175
api.derive.staking._stakerRewardsEras(eras, withActive)
174176
]).pipe(
175177
switchMap(([queries, exposures, erasResult]): Observable<DeriveStakerReward[][]> => {
176-
const allRewards = queries.map(({ stakingLedger, stashId }, index): DeriveStakerReward[] =>
177-
(!stashId || !stakingLedger)
178+
const allRewards = queries.map(({ claimedRewardsEras, stakingLedger, stashId }, index): DeriveStakerReward[] =>
179+
(!stashId || (!stakingLedger && !claimedRewardsEras))
178180
? []
179181
: parseRewards(api, stashId, erasResult, exposures[index])
180182
);
@@ -185,9 +187,9 @@ export function _stakerRewards (instanceId: string, api: DeriveApi): (accountIds
185187

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

188-
return api.derive.staking.queryMulti(allValidators, { withLedger: true }).pipe(
190+
return api.derive.staking.queryMulti(allValidators, { withClaimedRewardsEras: true, withLedger: true }).pipe(
189191
map((queriedVals): DeriveStakerReward[][] =>
190-
queries.map(({ stakingLedger }, index): DeriveStakerReward[] =>
192+
queries.map(({ claimedRewardsEras, stakingLedger }, index): DeriveStakerReward[] =>
191193
filterRewards(
192194
eras,
193195
stashValidators[index]
@@ -197,6 +199,7 @@ export function _stakerRewards (instanceId: string, api: DeriveApi): (accountIds
197199
])
198200
.filter((v): v is [string, DeriveStakingQuery] => !!v[1]),
199201
{
202+
claimedRewardsEras,
200203
rewards: allRewards[index],
201204
stakingLedger
202205
}

packages/api-derive/src/staking/types.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Copyright 2017-2024 @polkadot/api-derive authors & contributors
22
// SPDX-License-Identifier: Apache-2.0
33

4-
import type { Option } from '@polkadot/types';
4+
import type { Option, u32, Vec } from '@polkadot/types';
55
import type { AccountId, Balance, EraIndex, RewardPoint } from '@polkadot/types/interfaces';
66
import type { PalletStakingRewardDestination, PalletStakingStakingLedger, PalletStakingValidatorPrefs, SpStakingExposure, SpStakingExposurePage, SpStakingPagedExposureMetadata } from '@polkadot/types/lookup';
77
import type { BN } from '@polkadot/util';
@@ -124,6 +124,7 @@ export interface DeriveStakingStash {
124124
rewardDestination: PalletStakingRewardDestination | null;
125125
stashId: AccountId;
126126
validatorPrefs: PalletStakingValidatorPrefs;
127+
claimedRewardsEras: Vec<u32>
127128
}
128129

129130
export interface DeriveStakingQuery extends DeriveStakingStash {
@@ -165,4 +166,5 @@ export interface StakingQueryFlags {
165166
withNominations?: boolean;
166167
withPrefs?: boolean;
167168
withExposureMeta?: boolean;
169+
withClaimedRewardsEras?: boolean;
168170
}

0 commit comments

Comments
 (0)