@@ -48,6 +48,7 @@ import { CalcPayout } from '@substrate/calc';
4848import { BadRequest } from 'http-errors' ;
4949
5050import type { IAccountStakingPayouts , IEraPayouts , IPayout } from '../../types/responses' ;
51+ import { IStatus , IStatusPerEra } from '../../types/responses/AccountStakingPayouts' ;
5152import { AbstractService } from '../AbstractService' ;
5253import kusamaEarlyErasBlockInfo from './kusamaEarlyErasBlockInfo.json' ;
5354
@@ -82,11 +83,12 @@ interface IAdjustedDeriveEraExposure extends DeriveEraExposure {
8283}
8384
8485/**
85- * Commission and staking ledger of a validator
86+ * Commission, staking ledger & claimed information of a validator
8687 */
87- interface ICommissionAndLedger {
88+ interface ICommissionLedgerAndClaimed {
8889 commission : Perbill ;
8990 validatorLedger ?: PalletStakingStakingLedger ;
91+ claimedRewards ?: IStatusPerEra ;
9092}
9193
9294/**
@@ -96,7 +98,7 @@ interface IEraData {
9698 deriveEraExposure : IAdjustedDeriveEraExposure ;
9799 eraRewardPoints : PalletStakingEraRewardPoints | EraPoints ;
98100 erasValidatorRewardOption : Option < BalanceOf > ;
99- exposuresWithCommission ?: ( ICommissionAndLedger & {
101+ exposuresWithCommission ?: ( ICommissionLedgerAndClaimed & {
100102 validatorId : string ;
101103 nominatorIndex : number ;
102104 } ) [ ] ;
@@ -264,7 +266,7 @@ export class AccountsStakingPayoutsService extends AbstractService {
264266 blockNumber : IBlockInfo ,
265267 isKusama : boolean ,
266268 ) : Promise < IErasGeneral [ ] > {
267- const allDeriveQuerys : Promise < IErasGeneral > [ ] = [ ] ;
269+ const allDeriveQueries : Promise < IErasGeneral > [ ] = [ ] ;
268270 let nextEraStartBlock : number = Number ( blockNumber . height ) ;
269271 let eraDurationInBlocks : number = 0 ;
270272 const earlyErasBlockInfo : IEarlyErasBlockInfo = kusamaEarlyErasBlockInfo ;
@@ -277,7 +279,7 @@ export class AccountsStakingPayoutsService extends AbstractService {
277279 historicApi . query . staking . erasRewardPoints ( eraIndex ) ,
278280 historicApi . query . staking . erasValidatorReward ( eraIndex ) ,
279281 ] ) ;
280- allDeriveQuerys . push ( eraGeneralTuple ) ;
282+ allDeriveQueries . push ( eraGeneralTuple ) ;
281283 } else {
282284 // We check if we are in the Kusama chain since currently we have
283285 // the block info for the early eras only for Kusama.
@@ -290,6 +292,7 @@ export class AccountsStakingPayoutsService extends AbstractService {
290292 const epochDuration = historicApi . consts . babe . epochDuration . toNumber ( ) ;
291293 eraDurationInBlocks = sessionDuration * epochDuration ;
292294 }
295+
293296 const nextEraStartBlockHash : BlockHash = await this . api . rpc . chain . getBlockHash ( nextEraStartBlock ) ;
294297 const currentEraEndBlockHash : BlockHash =
295298 era === 0
@@ -323,10 +326,10 @@ export class AccountsStakingPayoutsService extends AbstractService {
323326
324327 const eraGeneralTuple = Promise . all ( [ this . deriveEraExposure ( historicApi , eraIndex ) , points , rewardPromise ] ) ;
325328
326- allDeriveQuerys . push ( eraGeneralTuple ) ;
329+ allDeriveQueries . push ( eraGeneralTuple ) ;
327330 }
328331 }
329- return Promise . all ( allDeriveQuerys ) ;
332+ return Promise . all ( allDeriveQueries ) ;
330333 }
331334
332335 private async fetchHistoricRewardPoints ( hash : BlockHash ) : Promise < EraPoints > {
@@ -348,7 +351,7 @@ export class AccountsStakingPayoutsService extends AbstractService {
348351 startEra : number ,
349352 deriveErasExposures : IAdjustedDeriveEraExposure [ ] ,
350353 isKusama : boolean ,
351- ) : Promise < ICommissionAndLedger [ ] [ ] > {
354+ ) : Promise < ICommissionLedgerAndClaimed [ ] [ ] > {
352355 // Cache StakingLedger to reduce redundant queries to node
353356 const validatorLedgerCache : { [ id : string ] : PalletStakingStakingLedger } = { } ;
354357
@@ -362,7 +365,7 @@ export class AccountsStakingPayoutsService extends AbstractService {
362365 }
363366
364367 const singleEraCommissions = nominatedExposures . map ( ( { validatorId } ) =>
365- this . fetchCommissionAndLedger ( historicApi , validatorId , currEra , validatorLedgerCache , isKusama ) ,
368+ this . fetchCommissionLedgerAndClaimed ( historicApi , validatorId , currEra , validatorLedgerCache , isKusama ) ,
366369 ) ;
367370
368371 return Promise . all ( singleEraCommissions ) ;
@@ -408,6 +411,7 @@ export class AccountsStakingPayoutsService extends AbstractService {
408411 commission : validatorCommission ,
409412 validatorLedger,
410413 nominatorIndex,
414+ claimedRewards,
411415 } of exposuresWithCommission ) {
412416 const totalValidatorRewardPoints = deriveEraExposure . validatorIndex
413417 ? this . extractTotalValidatorRewardPoints ( eraRewardPoints , validatorId , deriveEraExposure . validatorIndex )
@@ -432,32 +436,16 @@ export class AccountsStakingPayoutsService extends AbstractService {
432436 continue ;
433437 }
434438
435- /**
436- * Check if the reward has already been claimed.
437- *
438- * It is important to note that the following examines types that are both current and historic.
439- * When going back far enough in certain chains types such as `StakingLedgerTo240` are necessary for grabbing
440- * any reward data.
441- */
442- let indexOfEra : number ;
443- if ( validatorLedger . legacyClaimedRewards ) {
444- indexOfEra = validatorLedger . legacyClaimedRewards . indexOf ( eraIndex ) ;
445- } else if ( ( validatorLedger as unknown as StakingLedger ) . claimedRewards ) {
446- indexOfEra = ( validatorLedger as unknown as StakingLedger ) . claimedRewards . indexOf ( eraIndex ) ;
447- } else if ( ( validatorLedger as unknown as StakingLedgerTo240 ) . lastReward ) {
448- const lastReward = ( validatorLedger as unknown as StakingLedgerTo240 ) . lastReward ;
449- if ( lastReward . isSome ) {
450- indexOfEra = lastReward . unwrap ( ) . toNumber ( ) ;
451- } else {
452- indexOfEra = - 1 ;
453- }
439+ // Setting the value of `claimed` based on `claimedRewards`
440+ let claimed ;
441+ if ( claimedRewards && claimedRewards [ eraIndex . toNumber ( ) ] ) {
442+ claimed = claimedRewards [ eraIndex . toNumber ( ) ] ;
454443 } else if ( eraIndex . toNumber ( ) < 518 && isKusama ) {
455- indexOfEra = eraIndex . toNumber ( ) ;
444+ claimed = IStatus . claimed ;
456445 } else {
457- continue ;
446+ claimed = IStatus . undefined ;
458447 }
459- const claimed : boolean = Number . isInteger ( indexOfEra ) && indexOfEra !== - 1 ;
460- if ( unclaimedOnly && claimed ) {
448+ if ( unclaimedOnly && claimed === IStatus . claimed ) {
461449 continue ;
462450 }
463451
@@ -496,17 +484,18 @@ export class AccountsStakingPayoutsService extends AbstractService {
496484 * @param era the era to query
497485 * @param validatorLedgerCache object mapping validatorId => StakingLedger to limit redundant queries
498486 */
499- private async fetchCommissionAndLedger (
487+ private async fetchCommissionLedgerAndClaimed (
500488 historicApi : ApiDecoration < 'promise' > ,
501489 validatorId : string ,
502490 era : number ,
503491 validatorLedgerCache : { [ id : string ] : PalletStakingStakingLedger } ,
504492 isKusama : boolean ,
505- ) : Promise < ICommissionAndLedger > {
493+ ) : Promise < ICommissionLedgerAndClaimed > {
506494 let commission : Perbill ;
507495 let validatorLedger ;
508496 let commissionPromise ;
509497 const ancient : boolean = era < 518 ;
498+ const claimedRewards : IStatusPerEra = { } ;
510499 if ( validatorId in validatorLedgerCache ) {
511500 validatorLedger = validatorLedgerCache [ validatorId ] ;
512501 let prefs : PalletStakingValidatorPrefs | ValidatorPrefsWithCommission ;
@@ -544,13 +533,62 @@ export class AccountsStakingPayoutsService extends AbstractService {
544533 return {
545534 commission,
546535 } ;
536+ } else {
537+ validatorLedger = validatorLedgerOption . unwrap ( ) ;
538+ /**
539+ * Check if the reward has already been claimed.
540+ *
541+ * It is important to note that the following examines types that are both current and historic.
542+ * When going back far enough in certain chains types such as `StakingLedgerTo240` are necessary for grabbing
543+ * any reward data.
544+ */
545+ let claimedRewardsEras : u32 [ ] = [ ] ;
546+ if ( ( validatorLedger as unknown as StakingLedgerTo240 ) ?. lastReward ) {
547+ const lastReward = ( validatorLedger as unknown as StakingLedgerTo240 ) . lastReward ;
548+ if ( lastReward . isSome ) {
549+ const e = ( validatorLedger as unknown as StakingLedgerTo240 ) ?. lastReward ?. unwrap ( ) . toNumber ( ) ;
550+ if ( e ) {
551+ claimedRewards [ e ] = IStatus . claimed ;
552+ }
553+ }
554+ }
555+ if ( validatorLedger ?. legacyClaimedRewards ) {
556+ claimedRewardsEras = validatorLedger ?. legacyClaimedRewards ;
557+ } else {
558+ claimedRewardsEras = ( validatorLedger as unknown as StakingLedger ) ?. claimedRewards as Vec < u32 > ;
559+ }
560+ if ( claimedRewardsEras ) {
561+ claimedRewardsEras . forEach ( ( era ) => {
562+ claimedRewards [ era . toNumber ( ) ] = IStatus . claimed ;
563+ } ) ;
564+ }
565+ if ( historicApi . query . staking ?. claimedRewards ) {
566+ const claimedRewardsPerEra = await historicApi . query . staking . claimedRewards ( era , validatorId ) ;
567+ const erasStakersOverview = await historicApi . query . staking . erasStakersOverview ( era , validatorId ) ;
568+ let erasStakers = null ;
569+ if ( historicApi . query . staking ?. erasStakers ) {
570+ erasStakers = await historicApi . query . staking . erasStakers ( era , validatorId ) ;
571+ }
572+ if ( erasStakersOverview . isSome ) {
573+ const pageCount = erasStakersOverview . unwrap ( ) . pageCount . toNumber ( ) ;
574+ const eraStatus =
575+ claimedRewardsPerEra . length === 0
576+ ? IStatus . unclaimed
577+ : claimedRewardsPerEra . length === pageCount
578+ ? IStatus . claimed
579+ : IStatus . partiallyClaimed ;
580+ claimedRewards [ era ] = eraStatus ;
581+ } else if ( erasStakers && erasStakers . total . toBigInt ( ) > 0 ) {
582+ // if erasStakers.total > 0, then the pageCount is always 1
583+ // https://github.com/polkadot-js/api/issues/5859#issuecomment-2077011825
584+ const eraStatus = claimedRewardsPerEra . length === 1 ? IStatus . claimed : IStatus . unclaimed ;
585+ claimedRewards [ era ] = eraStatus ;
586+ }
587+ }
547588 }
548-
549- validatorLedger = validatorLedgerOption . unwrap ( ) ;
550- validatorLedgerCache [ validatorId ] = validatorLedger ;
551589 }
552590
553- return { commission, validatorLedger } ;
591+ return { commission, validatorLedger, claimedRewards } ;
554592 }
555593
556594 /**
@@ -576,7 +614,6 @@ export class AccountsStakingPayoutsService extends AbstractService {
576614 const nominators : DeriveEraNominatorExposure = { } ;
577615 const validators : DeriveEraValidatorExposure = { } ;
578616 const validatorsOverview : Record < string , Option < SpStakingPagedExposureMetadata > > = { } ;
579-
580617 stakers . forEach ( ( [ key , exposure ] ) : void => {
581618 const validatorId = key . args [ 1 ] . toString ( ) ;
582619
0 commit comments