Skip to content

Commit

Permalink
[Issue-3000] refactor: refactor validator era reward map
Browse files Browse the repository at this point in the history
  • Loading branch information
bluezdot committed May 6, 2024
1 parent 3231008 commit 34bdb55
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 32 deletions.
25 changes: 18 additions & 7 deletions packages/extension-base/src/koni/api/staking/bonding/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -581,16 +581,14 @@ export function getSupportedDaysByHistoryDepth (erasPerDay: number, maxSupported
}
}

export function getValidatorPointsMap (eraRewardMap: Record<string, PalletStakingEraRewardPoints>) {
export function getRelayValidatorPointsMap (eraRewardMap: Record<string, PalletStakingEraRewardPoints>) {
// mapping store validator and totalPoints
const validatorTotalPointsMap: Record<string, BigNumber> = {};

Object.values(eraRewardMap).forEach((info) => {
const individual = info.individual;

Object.entries(individual).forEach(([validator, rawPoints]) => {
const points = rawPoints.replaceAll(',', '');

Object.entries(individual).forEach(([validator, points]) => {
if (!validatorTotalPointsMap[validator]) {
validatorTotalPointsMap[validator] = new BigNumber(points);
} else {
Expand All @@ -602,7 +600,7 @@ export function getValidatorPointsMap (eraRewardMap: Record<string, PalletStakin
return validatorTotalPointsMap;
}

export function getTopValidatorByPoints (validatorPointsList: Record<string, BigNumber>) {
export function getRelayTopValidatorByPoints (validatorPointsList: Record<string, BigNumber>) {
const sortValidatorPointsList = Object.fromEntries(
Object.entries(validatorPointsList)
.sort(
Expand All @@ -623,11 +621,13 @@ export function getTopValidatorByPoints (validatorPointsList: Record<string, Big
return Object.keys(top50PercentRecord);
}

export function getBlockedValidatorList (validators: any[]) {
export function getRelayBlockedValidatorList (validators: any[]) {
const blockValidatorList: string[] = [];

for (const validator of validators) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-member-access
const validatorAddress = validator[0].toHuman()[0] as string;
// eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-member-access
const validatorPrefs = validator[1].toHuman() as unknown as PalletStakingValidatorPrefs;

const isBlocked = validatorPrefs.blocked;
Expand All @@ -637,7 +637,18 @@ export function getBlockedValidatorList (validators: any[]) {
}
}

return blockValidatorList
return blockValidatorList;
}

export function getRelayEraRewardMap (eraRewardPointArray: Codec[], startEraForPoints: number) {
const eraRewardMap: Record<string, PalletStakingEraRewardPoints> = {};

for (const item of eraRewardPointArray) {
eraRewardMap[startEraForPoints] = item.toPrimitive() as unknown as PalletStakingEraRewardPoints;
startEraForPoints++;
}

return eraRewardMap;
}

export const getMinStakeErrorMessage = (chainInfo: _ChainInfo, bnMinStake: BN): string => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@
import { _ChainInfo } from '@subwallet/chain-list/types';
import { TransactionError } from '@subwallet/extension-base/background/errors/TransactionError';
import { BasicTxErrorType, ExtrinsicType, NominationInfo, StakingTxErrorType, UnstakingInfo } from '@subwallet/extension-base/background/KoniTypes';
import { calculateAlephZeroValidatorReturn, calculateChainStakedReturnV2, calculateInflation, calculateTernoaValidatorReturn, calculateValidatorStakedReturn, getAvgValidatorEraReward, getBlockedValidatorList, getCommission, getMaxValidatorErrorMessage, getMinStakeErrorMessage, getSupportedDaysByHistoryDepth, getTopValidatorByPoints, getValidatorPointsMap } from '@subwallet/extension-base/koni/api/staking/bonding/utils';
import { calculateAlephZeroValidatorReturn, calculateChainStakedReturnV2, calculateInflation, calculateTernoaValidatorReturn, calculateValidatorStakedReturn, getAvgValidatorEraReward, getCommission, getMaxValidatorErrorMessage, getMinStakeErrorMessage, getRelayBlockedValidatorList, getRelayEraRewardMap, getRelayTopValidatorByPoints, getRelayValidatorPointsMap, getSupportedDaysByHistoryDepth } from '@subwallet/extension-base/koni/api/staking/bonding/utils';
import { _STAKING_ERA_LENGTH_MAP } from '@subwallet/extension-base/services/chain-service/constants';
import { _SubstrateApi } from '@subwallet/extension-base/services/chain-service/types';
import { _getChainSubstrateAddressPrefix } from '@subwallet/extension-base/services/chain-service/utils';
import { _STAKING_CHAIN_GROUP, _UPDATED_RUNTIME_STAKING_GROUP, MaxEraRewardPointsEras } from '@subwallet/extension-base/services/earning-service/constants';
import { applyDecimal, parseIdentity } from '@subwallet/extension-base/services/earning-service/utils';
import { BaseYieldPositionInfo, EarningStatus, NativeYieldPoolInfo, OptimalYieldPath, PalletStakingActiveEraInfo, PalletStakingEraRewardPoints, PalletStakingExposure, PalletStakingExposureItem, PalletStakingNominations, PalletStakingStakingLedger, SpStakingExposurePage, SpStakingPagedExposureMetadata, StakeCancelWithdrawalParams, SubmitJoinNativeStaking, SubmitYieldJoinData, TernoaStakingRewardsStakingRewardsData, TransactionData, UnstakingStatus, ValidatorExtraInfo, ValidatorInfo, YieldPoolInfo, YieldPositionInfo, YieldTokenBaseInfo } from '@subwallet/extension-base/types';
import { BaseYieldPositionInfo, EarningStatus, NativeYieldPoolInfo, OptimalYieldPath, PalletStakingActiveEraInfo, PalletStakingExposure, PalletStakingExposureItem, PalletStakingNominations, PalletStakingStakingLedger, SpStakingExposurePage, SpStakingPagedExposureMetadata, StakeCancelWithdrawalParams, SubmitJoinNativeStaking, SubmitYieldJoinData, TernoaStakingRewardsStakingRewardsData, TransactionData, UnstakingStatus, ValidatorExtraInfo, ValidatorInfo, YieldPoolInfo, YieldPositionInfo, YieldTokenBaseInfo } from '@subwallet/extension-base/types';
import { balanceFormatter, formatNumber, reformatAddress } from '@subwallet/extension-base/utils';
import BigN from 'bignumber.js';
import { t } from 'i18next';
Expand Down Expand Up @@ -378,7 +378,7 @@ export default class RelayNativeStakingPoolHandler extends BaseNativeStakingPool

const maxEraRewardPointsEras = MaxEraRewardPointsEras;
const endEraForPoints = parseInt(activeEra) - 1;
let startEraForPoints = Math.max(endEraForPoints - maxEraRewardPointsEras + 1, 0);
const startEraForPoints = Math.max(endEraForPoints - maxEraRewardPointsEras + 1, 0);

let _eraStakersPromise;

Expand All @@ -397,27 +397,20 @@ export default class RelayNativeStakingPoolHandler extends BaseNativeStakingPool
chainApi.api.query.staking.erasRewardPoints.multi([...Array(maxEraRewardPointsEras).keys()].map((i) => i + startEraForPoints))
]);

const eraRewardMap: Record<string, PalletStakingEraRewardPoints> = {};

for (const item of _eraRewardPoints[0]) {
eraRewardMap[startEraForPoints] = item.toHuman() as unknown as PalletStakingEraRewardPoints;
startEraForPoints++;
}

const validatorPointsMap = getValidatorPointsMap(eraRewardMap);
const topValidatorList = getTopValidatorByPoints(validatorPointsMap);
const eraRewardMap = getRelayEraRewardMap(_eraRewardPoints[0], startEraForPoints);
const validatorPointsMap = getRelayValidatorPointsMap(eraRewardMap);
const topValidatorList = getRelayTopValidatorByPoints(validatorPointsMap);

const validators = _validators as any[];
const blockedValidatorList = getBlockedValidatorList(validators);
const blockedValidatorList = getRelayBlockedValidatorList(validators);

const unlimitedNominatorRewarded = chainApi.api.consts.staking.maxExposurePageSize !== undefined;
const maxNominatorRewarded = (chainApi.api.consts.staking.maxNominatorRewardedPerValidator || 0).toString();
const bnTotalEraStake = new BN(_totalEraStake.toString());

const rawMinBond = _minBond.toHuman() as string;
const minBond = rawMinBond.replaceAll(',', '');
const minBond = _minBond.toPrimitive() as number;

const [totalStakeMap, allValidatorAddresses, validatorInfoList] = this.parseEraStakerData(_eraStakers, blockedValidatorList, topValidatorList, validatorPointsMap, minBond, maxNominatorRewarded, unlimitedNominatorRewarded)
const [totalStakeMap, allValidatorAddresses, validatorInfoList] = this.parseEraStakerData(_eraStakers, blockedValidatorList, topValidatorList, validatorPointsMap, minBond, maxNominatorRewarded, unlimitedNominatorRewarded);

const extraInfoMap: Record<string, ValidatorExtraInfo> = {};

Expand Down Expand Up @@ -452,11 +445,10 @@ export default class RelayNativeStakingPoolHandler extends BaseNativeStakingPool
validator.isVerified = extraInfoMap[validator.address].isVerified;
}

console.log('validatorInfo', validatorInfoList);
return validatorInfoList;
}

private getValidatorExpectedReturn(chain: string, validator: ValidatorInfo, totalApy: number, commission: number, _stakingRewards: Codec, allValidatorAddresses: string[], decimals: number, totalStakeMap: Record<string, BN>, bnAvgStake: BN) {
private getValidatorExpectedReturn (chain: string, validator: ValidatorInfo, totalApy: number, commission: number, _stakingRewards: Codec, allValidatorAddresses: string[], decimals: number, totalStakeMap: Record<string, BN>, bnAvgStake: BN) {
if (_STAKING_CHAIN_GROUP.aleph.includes(chain)) {
return calculateAlephZeroValidatorReturn(totalApy, commission);
} else if (_STAKING_CHAIN_GROUP.ternoa.includes(chain)) {
Expand All @@ -467,19 +459,20 @@ export default class RelayNativeStakingPoolHandler extends BaseNativeStakingPool
return calculateTernoaValidatorReturn(rewardPerValidator.toNumber(), validatorStake, commission);
} else {
const bnValidatorStake = applyDecimal(totalStakeMap[validator.address], decimals);

return calculateValidatorStakedReturn(totalApy, bnValidatorStake, bnAvgStake, commission);
}
}

private parseEraStakerData(_eraStakers: unknown, blockedValidatorList: string[], topValidatorList: string[], validatorPointsMap: Record<string, BigN>, minBond: string, maxNominatorRewarded: string, unlimitedNominatorRewarded: boolean): [Record<string, BN>, string[], ValidatorInfo[]] {
private parseEraStakerData (_eraStakers: any[], blockedValidatorList: string[], topValidatorList: string[], validatorPointsMap: Record<string, BigN>, minBond: number, maxNominatorRewarded: string, unlimitedNominatorRewarded: boolean): [Record<string, BN>, string[], ValidatorInfo[]] {
const totalStakeMap: Record<string, BN> = {};
const allValidatorAddresses: string[] = [];
const validatorInfoList: ValidatorInfo[] = [];

const eraStakers = _eraStakers as any[];

for (const item of eraStakers) {
for (const item of _eraStakers) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-member-access
const rawValidatorInfo = item[0].toHuman() as any[];
// eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-member-access
const rawValidatorStat = item[1].toPrimitive() as SpStakingPagedExposureMetadata;
const validatorAddress = rawValidatorInfo[1] as string;

Expand Down Expand Up @@ -522,7 +515,7 @@ export default class RelayNativeStakingPoolHandler extends BaseNativeStakingPool
expectedReturn: 0,
blocked: false,
isVerified: false,
minBond,
minBond: minBond.toString(),
isCrowded: unlimitedNominatorRewarded ? false : nominatorCount > parseInt(maxNominatorRewarded),
eraRewardPoint: (validatorPointsMap[validatorAddress] ?? BN_ZERO).toString(),
topQuartile: isTopQuartile
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@ import { _SubstrateApi } from '@subwallet/extension-base/services/chain-service/
import { _STAKING_CHAIN_GROUP } from '@subwallet/extension-base/services/earning-service/constants';
import { LendingYieldPoolInfo, LiquidYieldPoolInfo, NativeYieldPoolInfo, NominationYieldPoolInfo, YieldAssetExpectedEarning, YieldCompoundingPeriod, YieldPoolInfo, YieldPoolType } from '@subwallet/extension-base/types';

import { hexToString, isHex } from '@polkadot/util';
import { BN } from '@polkadot/util';
import { BN, hexToString, isHex } from '@polkadot/util';

export function calculateReward (apr: number, amount = 0, compoundingPeriod = YieldCompoundingPeriod.YEARLY, isApy = false): YieldAssetExpectedEarning {
if (!apr) {
Expand Down Expand Up @@ -140,5 +139,6 @@ export const isLendingPool = (pool: YieldPoolInfo): pool is LendingYieldPoolInfo

export function applyDecimal (bnNumber: BN, decimals: number) {
const bnDecimals = new BN((10 ** decimals).toString());

return bnNumber.div(bnDecimals);
}

0 comments on commit 34bdb55

Please sign in to comment.