diff --git a/packages/api-derive/src/staking/query.ts b/packages/api-derive/src/staking/query.ts index 6a5799b3f1..b30fc41da4 100644 --- a/packages/api-derive/src/staking/query.ts +++ b/packages/api-derive/src/staking/query.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 import type { Observable } from 'rxjs'; -import type { Option, u32, Vec } from '@polkadot/types'; +import type { Option, StorageKey, u32, Vec } from '@polkadot/types'; import type { AccountId, EraIndex } from '@polkadot/types/interfaces'; import type { PalletStakingNominations, PalletStakingRewardDestination, PalletStakingStakingLedger, PalletStakingValidatorPrefs, SpStakingExposure, SpStakingExposurePage, SpStakingPagedExposureMetadata } from '@polkadot/types/lookup'; import type { AnyNumber } from '@polkadot/types-codec/types'; @@ -24,6 +24,58 @@ function filterClaimedRewards (api: DeriveApi, cl: number[]): Vec { return api.registry.createType('Vec', cl.filter((c) => c !== -1)); } +function filterRewards (stashIds: AccountId[], eras: number[], claimedRewards: [StorageKey<[u32, AccountId]>, Vec][], stakersOverview: [StorageKey<[u32, AccountId]>, Option][]): number[][] { + const claimedData: Record> = {}; + const overviewData: Record> = {}; + const ids = stashIds.map((i) => i.toString()); + + claimedRewards.forEach(([keys, rewards]) => { + const id = keys.args[1].toString(); + const era = keys.args[0].toNumber(); + + if (ids.includes(id)) { + if (claimedData[id]) { + claimedData[id].set(era, rewards.toArray()); + } else { + claimedData[id] = new Map(); + claimedData[id].set(era, rewards.toArray()); + } + } + }); + + stakersOverview.forEach(([keys, overview]) => { + const id = keys.args[1].toString(); + const era = keys.args[0].toNumber(); + + if (ids.includes(id) && overview.isSome) { + if (overviewData[id]) { + overviewData[id].set(era, overview.unwrap().pageCount); + } else { + overviewData[id] = new Map(); + overviewData[id].set(era, overview.unwrap().pageCount); + } + } + }); + + return stashIds.map((id) => { + const rewardsPerEra = claimedData[id.toString()]; + const overviewPerEra = overviewData[id.toString()]; + + return eras.map((era) => { + if (rewardsPerEra && rewardsPerEra.has(era) && overviewPerEra && overviewPerEra.has(era)) { + const rewards = rewardsPerEra.get(era) as unknown as u32[]; + const pageCount = overviewPerEra.get(era) as unknown as u32; + + return rewards.length === pageCount.toNumber() + ? era + : -1; + } + + return -1; + }); + }); +} + function parseDetails (api: DeriveApi, stashId: AccountId, controllerIdOpt: Option | null, nominatorsOpt: Option, rewardDestinationOpts: Option | PalletStakingRewardDestination, validatorPrefs: PalletStakingValidatorPrefs, exposure: Option, stakingLedgerOpt: Option, exposureMeta: Option, claimedRewards: number[], exposureEraStakers: SpStakingExposure): DeriveStakingQuery { return { accountId: stashId, @@ -105,26 +157,11 @@ function getStashInfo (api: DeriveApi, stashIds: AccountId[], activeEra: EraInde ? combineLatest(stashIds.map((s) => api.query.staking.erasStakersOverview(activeEra, s))) : of(stashIds.map(() => emptyExpoMeta)), withClaimedRewardsEras && api.query.staking.claimedRewards - ? 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; - }); - }); - }) + ? combineLatest([ + api.query.staking.claimedRewards.entries>(), + api.query.staking.erasStakersOverview.entries>() + ]).pipe( + map(([rewardsStorageVec, overviewStorageVec]) => filterRewards(stashIds, eras, rewardsStorageVec, overviewStorageVec)) ) : of(stashIds.map(() => emptyClaimedRewards)), withExposureErasStakersLegacy && api.query.staking.erasStakers diff --git a/packages/api-derive/src/staking/stakerRewards.ts b/packages/api-derive/src/staking/stakerRewards.ts index a223c0fcab..c9ad0217d2 100644 --- a/packages/api-derive/src/staking/stakerRewards.ts +++ b/packages/api-derive/src/staking/stakerRewards.ts @@ -170,7 +170,7 @@ export function _stakerRewardsEras (instanceId: string, api: DeriveApi): (eras: export function _stakerRewards (instanceId: string, api: DeriveApi): (accountIds: (Uint8Array | string)[], eras: EraIndex[], withActive?: boolean) => Observable { return memo(instanceId, (accountIds: (Uint8Array | string)[], eras: EraIndex[], withActive = false): Observable => combineLatest([ - api.derive.staking.queryMulti(accountIds, { withLedger: true }), + api.derive.staking.queryMulti(accountIds, { withClaimedRewardsEras: true, withLedger: true }), api.derive.staking._stakerExposures(accountIds, eras, withActive), api.derive.staking._stakerRewardsEras(eras, withActive) ]).pipe(