Skip to content

fix: staking payouts claimed with new logic & statuses #1457

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

Closed
wants to merge 94 commits into from
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
94 commits
Select commit Hold shift + click to select a range
b751ca4
fix: duplicate payouts in staking-payouts endpoint (#1439)
Imod7 May 9, 2024
7fb4844
chore(deps): update polkadot-js deps (#1441)
Imod7 May 23, 2024
bb83189
chore(deps): update all non polkadot-js deps (#1442)
Imod7 May 23, 2024
8749062
chore(release): 19.0.1 (#1443)
Imod7 May 24, 2024
1fe1b46
chore(yarn): bump yarn to 4.2.2 (#1444)
TarikGul May 29, 2024
b048648
fix: add nominations in staking-info endpoint (#1448)
Imod7 Jun 6, 2024
edb6049
chore: bump braces from 3.0.2 to 3.0.3 in /docs (#1450)
dependabot[bot] Jun 13, 2024
9fffaff
chore:(deps): bump braces from 3.0.2 to 3.0.3 (#1451)
dependabot[bot] Jun 13, 2024
2b63e9b
chore: bump ws from 8.5.0 to 8.17.1 in /docs (#1455)
dependabot[bot] Jun 18, 2024
92f39d0
chore:(deps): bump ws from 8.16.0 to 8.17.1 (#1456)
dependabot[bot] Jun 18, 2024
8bedde0
claimed new logic in staking payouts
Imod7 Jun 24, 2024
6c23fdf
adjust unclaimedOnly param
Imod7 Jun 25, 2024
2f7a4f1
chore(deps): update polkadot-js deps (#1458)
Imod7 Jun 26, 2024
28ed90d
chore(release): 19.0.2 (#1459)
Imod7 Jun 27, 2024
58bf51d
docs: add maintenance guide (#1460)
Imod7 Jul 3, 2024
a4bbcb8
feat: Add route based metrics across API (#1465)
filvecchiato Aug 8, 2024
250b613
docs: remove old stable version note (#1466)
IkerAlus Aug 13, 2024
386fbb3
feat: add pallets/on-going-referenda endpoint (#1471)
Imod7 Aug 14, 2024
0317ec9
chore(deps): update polkadot-js deps (#1473)
Imod7 Aug 14, 2024
82c61df
chore: bump axios from 1.6.7 to 1.7.4 in /docs (#1474)
dependabot[bot] Aug 14, 2024
c766c1d
chore(deps): update all non polkadot-js deps in root & docs folder (#…
Imod7 Aug 14, 2024
beea4a7
chore(release): 19.1.0 (#1478)
Imod7 Aug 15, 2024
11c0173
feat: Inject metrics registry in route controllers (#1477)
filvecchiato Aug 19, 2024
1ca7f9b
chore: bump micromatch from 4.0.4 to 4.0.8 in /docs (#1480)
dependabot[bot] Aug 26, 2024
85a4cca
feat: add loki functionality to transport logs (#1479)
filvecchiato Aug 26, 2024
6eaca88
fix: Improve performance of blocks service by dependency injection (#…
filvecchiato Aug 27, 2024
373ec9b
chore:(deps): bump micromatch from 4.0.5 to 4.0.8 (#1481)
dependabot[bot] Aug 27, 2024
2e6efc0
fix: dependabot yaml (#1482)
Imod7 Aug 27, 2024
6286442
chore: bump webpack from 5.93.0 to 5.94.0 in /docs (#1484)
dependabot[bot] Aug 29, 2024
02a3797
chore: bump express from 4.19.2 to 4.21.0 in /docs (#1490)
dependabot[bot] Sep 14, 2024
a5b8a36
chore(deps): bump express from 4.19.2 to 4.20.0 (#1491)
dependabot[bot] Sep 16, 2024
890c06b
fix: Moves the LRUcache to Controller level (#1489)
filvecchiato Sep 20, 2024
968f522
chore(deps): update non pjs deps & in docs (#1494)
Imod7 Sep 20, 2024
0115afc
chore(deps): update polkadot-js deps (#1495)
Imod7 Sep 23, 2024
112994e
chore(deps): update polkadot-js deps (#1496)
Imod7 Sep 23, 2024
432d8f0
chore(release): 19.2.0 (#1497)
Imod7 Sep 23, 2024
6aac632
chore(yarn): bump yarn to 4.5.0 (#1498)
Imod7 Sep 24, 2024
cf2b58b
chore(deps): update substrate dev package & types (#1500)
Imod7 Oct 7, 2024
28e039e
chore(deps): update express to v5 & jest deprecations (#1502)
Imod7 Oct 8, 2024
68be48b
fix: queryInfo call in fee-estimate endpoint (#1505)
Imod7 Oct 8, 2024
c365490
test: add test for fee-estimate fix (#1506)
Imod7 Oct 9, 2024
a6e8cf4
chore(release): 19.2.1 (#1507)
Imod7 Oct 9, 2024
f0d662b
fix: access router in getRoutes (#1510)
Imod7 Oct 10, 2024
0d6f123
chore(release): 19.2.2 (#1511)
Imod7 Oct 10, 2024
b67bdcf
fix: filtering in assets endpoint & update guides (#1512)
Imod7 Oct 14, 2024
e35c191
chore(deps): update polkadot-js deps (#1515)
Imod7 Oct 15, 2024
22a143a
chore(deps): bump Swatinem/rust-cache from 2.7.3 to 2.7.5 (#1514)
dependabot[bot] Oct 15, 2024
7422fd2
fix: rococo deprecation changes (#1517)
Imod7 Oct 16, 2024
1a3de02
chore(deps): update non pjs deps in root & docs folder (#1518)
Imod7 Oct 16, 2024
bb00db1
chore(deps): update polkadot-js deps & guides (#1522)
Imod7 Oct 22, 2024
e0ad7c1
feat: improve performance with new version of PJS (#1520)
filvecchiato Oct 22, 2024
aeef4dc
feat: update dry run endpoint to use new runtime api call (#1519)
filvecchiato Oct 22, 2024
f4c2d6c
docs: update docs for dry-run endpoint (#1524)
Imod7 Oct 23, 2024
95dfe4d
fix: dependabot yaml & explicit deps (#1523)
Imod7 Oct 23, 2024
bdf7065
chore(deps-dev): bump @types/argparse from 2.0.16 to 2.0.17 (#1526)
dependabot[bot] Oct 23, 2024
fd3faae
chore(deps): bump http-proxy-middleware from 2.0.6 to 2.0.7 in /docs …
dependabot[bot] Oct 23, 2024
c3fbb5b
chore(release): 19.3.0 (#1527)
Imod7 Oct 23, 2024
67f2806
chore(deps-dev): bump @types/express-serve-static-core (#1529)
dependabot[bot] Oct 28, 2024
991821d
chore(deps-dev): bump @substrate/dev from 0.8.0 to 0.9.0 (#1528)
dependabot[bot] Oct 28, 2024
292cd38
chore(deps): bump lru-cache from 11.0.1 to 11.0.2 (#1535)
dependabot[bot] Nov 4, 2024
4a58326
chore(deps): bump winston from 3.15.0 to 3.16.0 (#1536)
dependabot[bot] Nov 4, 2024
c43a26b
fix: return DispatchError in dry-run endpoint (#1533)
Imod7 Nov 5, 2024
cef2d10
fix(dev): fix tsconfig extends pathing for ts-node-dev (#1537)
TarikGul Nov 6, 2024
87245fd
ci: Move from Gitlab to Github (#1531)
alvicsam Nov 7, 2024
7f161d5
ci: fix deploy (#1539)
alvicsam Nov 7, 2024
45c4b1f
fix: ignore extrinsicIndex in multiBlockMigrations event (#1541)
Imod7 Nov 10, 2024
f7465da
chore(deps): bump docker/build-push-action from 5 to 6 (#1540)
dependabot[bot] Nov 11, 2024
158a1f8
chore: update Dependabot versioning strategy (#1543)
Imod7 Nov 11, 2024
b59928c
chore(deps): bump the pjs group across 1 directory with 7 updates (#1…
dependabot[bot] Nov 11, 2024
fb81a16
chore(deps): bump winston from 3.16.0 to 3.17.0 (#1545)
dependabot[bot] Nov 11, 2024
3ff1e48
chore(deps): update polkadot-js deps (#1547)
Imod7 Nov 18, 2024
80d3b65
chore(deps): bump cross-spawn from 7.0.3 to 7.0.6 (#1549)
dependabot[bot] Nov 18, 2024
c7b3f86
chore(deps): bump cross-spawn from 7.0.3 to 7.0.6 in /docs (#1548)
dependabot[bot] Nov 18, 2024
156ad7a
chore(deps): update non pjs deps (#1550)
Imod7 Nov 19, 2024
bcf03ac
chore(release): 19.3.1 (#1551)
Imod7 Nov 19, 2024
226f656
ci: fix benchmark workflow, move docs to gh-pages (#1552)
alvicsam Nov 20, 2024
bd9cad8
docs: update docs & benchmarks related docs (#1553)
Imod7 Nov 20, 2024
1d75954
chore(deps): bump docker/build-push-action from 6.9.0 to 6.10.0 (#1557)
dependabot[bot] Dec 9, 2024
a6eb6aa
chore(deps): bump the pjs group with 5 updates (#1559)
dependabot[bot] Dec 9, 2024
cdaf3e3
chore(deps): bump nanoid from 3.3.7 to 3.3.8 in /docs (#1560)
dependabot[bot] Dec 17, 2024
fe1e303
chore(deps): bump the pjs group with 5 updates (#1561)
dependabot[bot] Dec 19, 2024
1e519ce
chore(deps): bump Swatinem/rust-cache from 2.7.5 to 2.7.7 (#1564)
dependabot[bot] Jan 1, 2025
98f083d
feat: Add configuration parameter for request body size (#1565)
mjakuszko-punks Jan 6, 2025
3a92196
feat: coretime implementation (#1558)
filvecchiato Jan 7, 2025
c64312f
chore(yarn): bump yarn to 4.6.0 & small guide update (#1569)
Imod7 Jan 7, 2025
7ddd854
chore(deps): update non pjs deps (#1568)
Imod7 Jan 7, 2025
fe2e697
chore(deps): update polkadot-js deps (#1567)
Imod7 Jan 7, 2025
6a36d7c
chore: 2025 (#1570)
TarikGul Jan 7, 2025
afedb82
chore(release): 19.4.0 (#1571)
Imod7 Jan 7, 2025
51ab44b
chore(deps): bump docker/build-push-action from 6.10.0 to 6.11.0 (#1572)
dependabot[bot] Jan 10, 2025
fc95cd0
chore(deps): bump the pjs group with 5 updates (#1573)
dependabot[bot] Jan 14, 2025
194f3e7
chore(deps-dev): bump @types/express-serve-static-core (#1574)
dependabot[bot] Jan 14, 2025
e11955a
fix: claimed in staking info endpoint (#1445)
Imod7 Jan 16, 2025
2fd68e6
merge master & resolve conflicts
Imod7 Jan 20, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/services/accounts/AccountsStakingPayoutsService.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ describe('AccountsStakingPayoutsService', () => {
era: '1039',
payouts: [
{
claimed: true,
claimed: 'claimed',
nominatorExposure: '0',
nominatorStakingPayout: '1043968334900993560134832959396203124',
totalValidatorExposure: '17302617747768368',
Expand Down Expand Up @@ -131,7 +131,7 @@ describe('AccountsStakingPayoutsService', () => {
era: '1039',
payouts: [
{
claimed: true,
claimed: 'claimed',
nominatorExposure: '21133134966048676',
nominatorStakingPayout: '0',
totalValidatorExposure: '21133134966048676',
Expand Down
115 changes: 73 additions & 42 deletions src/services/accounts/AccountsStakingPayoutsService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import { CalcPayout } from '@substrate/calc';
import { BadRequest } from 'http-errors';

import type { IAccountStakingPayouts, IEraPayouts, IPayout } from '../../types/responses';
import { IStatus, IStatusPerEra } from '../../types/responses/AccountStakingPayouts';
import { AbstractService } from '../AbstractService';
import kusamaEarlyErasBlockInfo from './kusamaEarlyErasBlockInfo.json';

Expand Down Expand Up @@ -83,9 +84,10 @@ interface IAdjustedDeriveEraExposure extends DeriveEraExposure {
/**
* Commission and staking ledger of a validator
*/
interface ICommissionAndLedger {
interface ICommissionLedgerAndClaimed {
commission: Perbill;
validatorLedger?: PalletStakingStakingLedger;
claimedRewards?: IStatusPerEra;
}

/**
Expand All @@ -95,7 +97,7 @@ interface IEraData {
deriveEraExposure: IAdjustedDeriveEraExposure;
eraRewardPoints: PalletStakingEraRewardPoints | EraPoints;
erasValidatorRewardOption: Option<BalanceOf>;
exposuresWithCommission?: (ICommissionAndLedger & {
exposuresWithCommission?: (ICommissionLedgerAndClaimed & {
validatorId: string;
})[];
eraIndex: EraIndex;
Expand Down Expand Up @@ -327,7 +329,7 @@ export class AccountsStakingPayoutsService extends AbstractService {
startEra: number,
deriveErasExposures: IAdjustedDeriveEraExposure[],
isKusama: boolean,
): Promise<ICommissionAndLedger[][]> {
): Promise<ICommissionLedgerAndClaimed[][]> {
// Cache StakingLedger to reduce redundant queries to node
const validatorLedgerCache: { [id: string]: PalletStakingStakingLedger } = {};

Expand All @@ -341,7 +343,7 @@ export class AccountsStakingPayoutsService extends AbstractService {
}

const singleEraCommissions = nominatedExposures.map(({ validatorId }) =>
this.fetchCommissionAndLedger(historicApi, validatorId, currEra, validatorLedgerCache, isKusama),
this.fetchCommissionLedgerAndClaimed(historicApi, validatorId, currEra, validatorLedgerCache, isKusama),
);

return Promise.all(singleEraCommissions);
Expand Down Expand Up @@ -382,7 +384,12 @@ export class AccountsStakingPayoutsService extends AbstractService {

// Iterate through validators that this nominator backs and calculate payouts for the era
const payouts: IPayout[] = [];
for (const { validatorId, commission: validatorCommission, validatorLedger } of exposuresWithCommission) {
for (const {
validatorId,
commission: validatorCommission,
validatorLedger,
claimedRewards,
} of exposuresWithCommission) {
const totalValidatorRewardPoints = deriveEraExposure.validatorIndex
? this.extractTotalValidatorRewardPoints(eraRewardPoints, validatorId, deriveEraExposure.validatorIndex)
: this.extractTotalValidatorRewardPoints(eraRewardPoints, validatorId);
Expand All @@ -401,32 +408,16 @@ export class AccountsStakingPayoutsService extends AbstractService {
continue;
}

/**
* Check if the reward has already been claimed.
*
* It is important to note that the following examines types that are both current and historic.
* When going back far enough in certain chains types such as `StakingLedgerTo240` are necessary for grabbing
* any reward data.
*/
let indexOfEra: number;
if (validatorLedger.legacyClaimedRewards) {
indexOfEra = validatorLedger.legacyClaimedRewards.indexOf(eraIndex);
} else if ((validatorLedger as unknown as StakingLedger).claimedRewards) {
indexOfEra = (validatorLedger as unknown as StakingLedger).claimedRewards.indexOf(eraIndex);
} else if ((validatorLedger as unknown as StakingLedgerTo240).lastReward) {
const lastReward = (validatorLedger as unknown as StakingLedgerTo240).lastReward;
if (lastReward.isSome) {
indexOfEra = lastReward.unwrap().toNumber();
} else {
indexOfEra = -1;
}
// Setting the value of `claimed` based on `claimedRewards`
let claimed;
if (claimedRewards && claimedRewards[eraIndex.toNumber()]) {
claimed = claimedRewards[eraIndex.toNumber()];
} else if (eraIndex.toNumber() < 518 && isKusama) {
indexOfEra = eraIndex.toNumber();
claimed = IStatus.claimed;
} else {
continue;
claimed = IStatus.undefined;
}
const claimed: boolean = Number.isInteger(indexOfEra) && indexOfEra !== -1;
if (unclaimedOnly && claimed) {
if (unclaimedOnly && claimed === IStatus.claimed) {
continue;
}

Expand Down Expand Up @@ -465,17 +456,18 @@ export class AccountsStakingPayoutsService extends AbstractService {
* @param era the era to query
* @param validatorLedgerCache object mapping validatorId => StakingLedger to limit redundant queries
*/
private async fetchCommissionAndLedger(
private async fetchCommissionLedgerAndClaimed(
historicApi: ApiDecoration<'promise'>,
validatorId: string,
era: number,
validatorLedgerCache: { [id: string]: PalletStakingStakingLedger },
isKusama: boolean,
): Promise<ICommissionAndLedger> {
): Promise<ICommissionLedgerAndClaimed> {
let commission: Perbill;
let validatorLedger;
let commissionPromise;
const ancient: boolean = era < 518;
const claimedRewards: IStatusPerEra = {};
if (validatorId in validatorLedgerCache) {
validatorLedger = validatorLedgerCache[validatorId];
let prefs: PalletStakingValidatorPrefs | ValidatorPrefsWithCommission;
Expand Down Expand Up @@ -515,22 +507,61 @@ export class AccountsStakingPayoutsService extends AbstractService {
};
} else {
validatorLedger = validatorLedgerOption.unwrap();
if (
historicApi.query.staking.claimedRewards &&
(await historicApi.query.staking.claimedRewards(era, validatorControllerOption.unwrap())).length ===
(await historicApi.query.staking.erasStakersOverview(era, validatorControllerOption.unwrap()))
.unwrap()
.pageCount.toNumber()
) {
const eraVal: u32 = historicApi.registry.createType('u32', era);
validatorLedger.legacyClaimedRewards.push(eraVal);
/**
* Check if the reward has already been claimed.
*
* It is important to note that the following examines types that are both current and historic.
* When going back far enough in certain chains types such as `StakingLedgerTo240` are necessary for grabbing
* any reward data.
*/

let claimedRewardsEras: u32[] = [];
if ((validatorLedger as unknown as StakingLedgerTo240)?.lastReward) {
const lastReward = (validatorLedger as unknown as StakingLedgerTo240).lastReward;
if (lastReward.isSome) {
const e = (validatorLedger as unknown as StakingLedgerTo240)?.lastReward?.unwrap().toNumber();
if (e) {
claimedRewards[e] = IStatus.claimed;
}
}
}
if (validatorLedger?.legacyClaimedRewards) {
claimedRewardsEras = validatorLedger?.legacyClaimedRewards;
} else {
claimedRewardsEras = (validatorLedger as unknown as StakingLedger)?.claimedRewards as Vec<u32>;
}
if (claimedRewardsEras) {
claimedRewardsEras.forEach((era) => {
claimedRewards[era.toNumber()] = IStatus.claimed;
});
}
if (historicApi.query.staking?.claimedRewards) {
const claimedRewardsPerEra = await historicApi.query.staking.claimedRewards(era, validatorId);
const erasStakersOverview = await historicApi.query.staking.erasStakersOverview(era, validatorId);
let erasStakers = null;
if (historicApi.query.staking?.erasStakers) {
erasStakers = await historicApi.query.staking.erasStakers(era, validatorId);
}
if (erasStakersOverview.isSome) {
const pageCount = erasStakersOverview.unwrap().pageCount.toNumber();
const eraStatus =
claimedRewardsPerEra.length === 0
? IStatus.unclaimed
: claimedRewardsPerEra.length === pageCount
? IStatus.claimed
: IStatus.partiallyClaimed;
claimedRewards[era] = eraStatus;
} else if (erasStakers && erasStakers.total.toBigInt() > 0) {
// if erasStakers.total > 0, then the pageCount is always 1
// https://github.com/polkadot-js/api/issues/5859#issuecomment-2077011825
const eraStatus = claimedRewardsPerEra.length === 1 ? IStatus.claimed : IStatus.unclaimed;
claimedRewards[era] = eraStatus;
}
}
}

validatorLedgerCache[validatorId] = validatorLedger;
}

return { commission, validatorLedger };
return { commission, validatorLedger, claimedRewards };
}

/**
Expand Down
13 changes: 12 additions & 1 deletion src/types/responses/AccountStakingPayouts.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2017-2022 Parity Technologies (UK) Ltd.
// Copyright 2017-2024 Parity Technologies (UK) Ltd.
// This file is part of Substrate API Sidecar.
//
// Substrate API Sidecar is free software: you can redistribute it and/or modify
Expand All @@ -16,6 +16,17 @@

import { IAt, IEraPayouts } from '.';

export enum IStatus {
claimed = 'claimed',
partiallyClaimed = 'partially claimed',
unclaimed = 'unclaimed',
undefined = 'undefined',
}

export interface IStatusPerEra {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this needs to be updated in the docs as well!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, good point about the docs.

[era: number]: IStatus;
}

export interface IAccountStakingPayouts {
at: IAt;
erasPayouts: (IEraPayouts | { message: string })[];
Expand Down
4 changes: 3 additions & 1 deletion src/types/responses/Payout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,12 @@

import { Balance, Perbill, RewardPoint } from '@polkadot/types/interfaces';

import { IStatus } from './AccountStakingPayouts';

export interface IPayout {
validatorId: string;
nominatorStakingPayout: string;
claimed: boolean;
claimed: IStatus;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this needs to be updated in the docs as well! as before

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes! I will add it to the Todos in the description.

validatorCommission: Perbill;
totalValidatorRewardPoints: RewardPoint;
totalValidatorExposure: Balance;
Expand Down
Loading