Skip to content

Commit

Permalink
fix: incorporate not being selected during the chosen depth
Browse files Browse the repository at this point in the history
  • Loading branch information
Nick-1979 committed Nov 9, 2024
1 parent 8cd346d commit d6cf029
Showing 1 changed file with 37 additions and 11 deletions.
48 changes: 37 additions & 11 deletions packages/extension-polkagate/src/hooks/useValidatorApy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ import { useCallback, useEffect, useState } from 'react';

import { BN, BN_HUNDRED, BN_ZERO } from '@polkadot/util';

interface ValidatorEraInfo {
netReward: BN;
total: BN;
}

export default function useValidatorApy (api: ApiPromise | undefined, validatorAddress: string, isElected?: boolean): string | undefined | null {
const [apy, setApy] = useState<string | null>();

Expand All @@ -20,27 +25,25 @@ export default function useValidatorApy (api: ApiPromise | undefined, validatorA

// Define the number of past eras you want to check (e.g., last 10 eras)
const eraDepth = 10;
let depth = 0;
let totalDepth = 0;
const decimal = new BN(10 ** api.registry.chainDecimals[0]);
let totalRewards = BN_ZERO;
let totalPoints = BN_ZERO;
let validatorPoints = BN_ZERO;
let totalStaked = BN_ZERO;
const validatorEraInfo: ValidatorEraInfo[] = [];

const currentEra = ((await api.query['staking']['activeEra']()) as Option<PalletStakingActiveEraInfo>).unwrap().index.toNumber();
const { commission } = await api.query['staking']['validators'](validatorAddress) as PalletStakingValidatorPrefs;

// Loop over the past eras to calculate rewards for the validator
for (let eraIndex = currentEra - eraDepth; eraIndex <= currentEra; eraIndex++) {
let netReward;
const eraReward = await api.query['staking']['erasValidatorReward'](eraIndex) as Option<u128>;

if (eraReward.isNone) {
continue;
}

depth++;

const eraPoints = await api.query['staking']['erasRewardPoints'](eraIndex) as PalletStakingEraRewardPoints;

let validatorEraPoints;
Expand All @@ -58,7 +61,9 @@ export default function useValidatorApy (api: ApiPromise | undefined, validatorA
totalPoints = totalPoints.add(eraPoints.total);
const _eraReward = eraReward.unwrap();

totalRewards = totalRewards.add(_eraReward.mul(validatorPoints).div(totalPoints).muln(100 - (commission.toNumber() / 1e7)).div(BN_HUNDRED));
netReward = _eraReward.mul(validatorPoints).div(totalPoints).muln(100 - (commission.toNumber() / 1e7)).div(BN_HUNDRED);
} else {
continue;
}

// Fetch the validator's stake in this era
Expand All @@ -72,29 +77,50 @@ export default function useValidatorApy (api: ApiPromise | undefined, validatorA
continue;
}

totalDepth++;
totalStaked = totalStaked.add(totalAsBN);
validatorEraInfo.push(
{
netReward,
total: totalAsBN
});
}
}

// Average the total staked amount over the eras
totalStaked = totalStaked.div(decimal).divn(totalDepth);
if (!validatorEraInfo.length) {
setApy(null);
}

validatorEraInfo.forEach(({ netReward, total }) => {
totalRewards = totalRewards.add(netReward);
totalStaked = totalStaked.add(total);
});

const dailyReward = totalRewards.div(decimal).divn(depth);
const actualDepth = validatorEraInfo.length;

totalStaked = totalStaked.div(decimal).divn(actualDepth);

const dailyReward = totalRewards.div(decimal).divn(actualDepth);

// Calculate daily return as a fraction of the staked amount
const dailyReturn = dailyReward.toNumber() / totalStaked.toNumber();

const APY = (dailyReturn * 365 * 100).toFixed(2);

if (!isFinite(+APY) || isNaN(+APY)) {
setApy(null);
}

setApy(APY);
}, [api]);

useEffect(() => {
if (!api || !isElected) {
if (!api || isElected === undefined) {
return;
}

if (isElected === false) {
return setApy(null);
}

calculateValidatorAPY(validatorAddress).catch(console.error);
}, [api, calculateValidatorAPY, isElected, validatorAddress]);

Expand Down

0 comments on commit d6cf029

Please sign in to comment.