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

feat(refactor): Remove pre-paged rewards code (part 1) #2101

Merged
merged 1 commit into from
Apr 30, 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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
106 changes: 27 additions & 79 deletions src/contexts/Payouts/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import { rmCommas, setStateWithRef } from '@w3ux/utils';
import BigNumber from 'bignumber.js';
import { useNetwork } from 'contexts/Network';
import { useActiveAccounts } from 'contexts/ActiveAccounts';
import { NetworksWithPagedRewards } from 'config/networks';
import { MaxSupportedPayoutEras, defaultPayoutsContext } from './defaults';
import type {
LocalValidatorExposure,
Expand All @@ -35,9 +34,9 @@ export const usePayouts = () => useContext(PayoutsContext);

export const PayoutsProvider = ({ children }: { children: ReactNode }) => {
const { network } = useNetwork();
const { api, consts, activeEra } = useApi();
const { activeAccount } = useActiveAccounts();
const { isNominating, fetchEraStakers } = useStaking();
const { api, consts, activeEra, isPagedRewardsActive } = useApi();
const { maxExposurePageSize } = consts;

// Store active accont's payout state.
Expand Down Expand Up @@ -162,21 +161,6 @@ export const PayoutsProvider = ({ children }: { children: ReactNode }) => {
new BigNumber(b).minus(a).toNumber()
);

// Helper function to check which eras a validator was exposed in.
const validatorExposedEras = (validator: string) => {
const exposedEras: string[] = [];
for (const era of erasToCheck) {
if (
Object.values(
Object.keys(getLocalEraExposure(network, era, activeAccount))
)?.[0] === validator
) {
exposedEras.push(era);
}
}
return exposedEras;
};

// Fetch controllers in order to query ledgers.
const bondedResults =
await api.query.staking.bonded.multi<AnyApi>(uniqueValidators);
Expand All @@ -193,70 +177,34 @@ export const PayoutsProvider = ({ children }: { children: ReactNode }) => {

// Refer to new `ClaimedRewards` storage item and calculate unclaimed rewards from that and
// `exposedPage` stored locally in exposure data.
if (isPagedRewardsActive(activeEra.index)) {
// Accumulate calls to fetch unclaimed rewards for each era for all validators.
const unclaimedRewardsEntries = erasToCheck
.map((era) => uniqueValidators.map((v) => [era, v]))
.flat();

const results = await Promise.all(
unclaimedRewardsEntries.map(([era, v]) =>
api.query.staking.claimedRewards<AnyApi>(era, v)
)
);

for (let i = 0; i < results.length; i++) {
const pages = results[i].toHuman() || [];
const era = unclaimedRewardsEntries[i][0];
const validator = unclaimedRewardsEntries[i][1];
const exposure = getLocalEraExposure(network, era, activeAccount);
const exposedPage =
exposure?.[validator]?.exposedPage !== undefined
? String(exposure[validator].exposedPage)
: undefined;

// Add to `unclaimedRewards` if payout page has not yet been claimed.
if (!pages.includes(exposedPage)) {
if (unclaimedRewards?.[validator]) {
unclaimedRewards[validator].push(era);
} else {
unclaimedRewards[validator] = [era];
}
}
}
} else {
// DEPRECATION: Paged Rewards
//
// Use `staking.ledger` to get unclaimed reward eras. Read `legacyClaimedRewards`
// if paged rewards are active, otherwise use `claimedRewards`.
const ledgerResults = await api.query.staking.ledger.multi<AnyApi>(
Object.values(validatorControllers)
);
// Accumulate calls to fetch unclaimed rewards for each era for all validators.
const unclaimedRewardsEntries = erasToCheck
.map((era) => uniqueValidators.map((v) => [era, v]))
.flat();

const results = await Promise.all(
unclaimedRewardsEntries.map(([era, v]) =>
api.query.staking.claimedRewards<AnyApi>(era, v)
)
);

// Fetch ledgers to determine which eras have not yet been claimed per validator. Only
// includes eras that are in `erasToCheck`.
for (const ledgerResult of ledgerResults) {
const ledger = ledgerResult.unwrapOr(null)?.toHuman();
if (ledger) {
// get claimed eras within `erasToCheck`.
const erasClaimed = ledger[
NetworksWithPagedRewards.includes(network)
? 'legacyClaimedRewards'
: 'claimedRewards'
]
.map((e: string) => rmCommas(e))
.filter(
(e: string) =>
new BigNumber(e).isLessThanOrEqualTo(startEra) &&
new BigNumber(e).isGreaterThanOrEqualTo(endEra)
);

// filter eras yet to be claimed
unclaimedRewards[ledger.stash] = erasToCheck.filter(
(era) =>
validatorExposedEras(ledger.stash).includes(era) &&
!erasClaimed.includes(era)
);
for (let i = 0; i < results.length; i++) {
const pages = results[i].toHuman() || [];
const era = unclaimedRewardsEntries[i][0];
const validator = unclaimedRewardsEntries[i][1];
const exposure = getLocalEraExposure(network, era, activeAccount);
const exposedPage =
exposure?.[validator]?.exposedPage !== undefined
? String(exposure[validator].exposedPage)
: undefined;

// Add to `unclaimedRewards` if payout page has not yet been claimed.
if (!pages.includes(exposedPage)) {
if (unclaimedRewards?.[validator]) {
unclaimedRewards[validator].push(era);
} else {
unclaimedRewards[validator] = [era];
}
}
}
Expand Down
15 changes: 4 additions & 11 deletions src/modals/ClaimPayouts/Forms.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export const Forms = forwardRef(
ref: ForwardedRef<HTMLDivElement>
) => {
const { t } = useTranslation('modals');
const { api, isPagedRewardsActive } = useApi();
const { api } = useApi();
const {
networkData: { units, unit },
} = useNetwork();
Expand Down Expand Up @@ -68,16 +68,9 @@ export const Forms = forwardRef(
if (!paginatedValidators) {
return [];
}

return paginatedValidators.forEach(([page, v]) => {
if (isPagedRewardsActive(new BigNumber(era))) {
return calls.push(api.tx.staking.payoutStakersByPage(v, era, page));
}
// DEPRECATION: Paged Rewards
//
// Fall back to deprecated `payoutStakers` if not on paged reward era.
return calls.push(api.tx.staking.payoutStakers(v, era));
});
return paginatedValidators.forEach(([page, v]) =>
calls.push(api.tx.staking.payoutStakersByPage(v, era, page))
);
});
return calls;
};
Expand Down
15 changes: 2 additions & 13 deletions src/model/Api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import type {
} from 'contexts/Api/types';
import { SyncController } from 'controllers/SyncController';
import type { AnyApi, NetworkName } from 'types';
import { NetworkList, NetworksWithPagedRewards } from 'config/networks';
import { NetworkList } from 'config/networks';
import { makeCancelable, rmCommas, stringToBigNumber } from '@w3ux/utils';
import { WellKnownChain } from '@substrate/connect';
import type { BlockNumber } from '@polkadot/types/interfaces';
Expand Down Expand Up @@ -245,20 +245,9 @@ export class Api {
this.api.consts.staking.historyDepth,
this.api.consts.fastUnstake.deposit,
this.api.consts.nominationPools.palletId,
this.api.consts.staking.maxExposurePageSize,
];

// DEPRECATION: Paged Rewards
//
// Fetch `maxExposurePageSize` instead of `maxNominatorRewardedPerValidator` for networks that
// have paged rewards.
if (NetworksWithPagedRewards.includes(this.network)) {
allPromises.push(this.api.consts.staking.maxExposurePageSize);
} else {
allPromises.push(
this.api.consts.staking.maxNominatorRewardedPerValidator
);
}

const consts = await Promise.all(allPromises);

// Fetch the active era. Needed for previous era and for queries below.
Expand Down
Loading