ghost-portal/packages/react-hooks/src/useOwnEraRewards.ts
Jaco Greeff ebad8635f7
Adjust useCall options (#3430)
* Adjust useCall options

* Extract useCall options

* typo

* Apply suggestions from code review

* Adjust param creation in calls
2020-08-17 12:24:51 +02:00

141 lines
4.9 KiB
TypeScript

// Copyright 2017-2020 @polkadot/react-hooks authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { DeriveEraPoints, DeriveEraRewards, DeriveStakerReward } from '@polkadot/api-derive/types';
import { EraIndex } from '@polkadot/types/interfaces';
import { StakerState } from './types';
import { useEffect, useState } from 'react';
import { registry } from '@polkadot/react-api';
import { BN_ZERO } from '@polkadot/util';
import useApi from './useApi';
import useCall from './useCall';
import useIsMountedRef from './useIsMountedRef';
import { useOwnStashIds } from './useOwnStashes';
interface OwnRewards {
allRewards?: Record<string, DeriveStakerReward[]> | null;
isLoadingRewards: boolean;
rewardCount: number;
}
interface ValidatorWithEras {
eras: EraIndex[];
stashId: string;
}
interface Filtered {
filteredEras: EraIndex[];
validatorEras: ValidatorWithEras[];
}
function getRewards ([[stashIds], available]: [[string[]], DeriveStakerReward[][]]): OwnRewards {
const allRewards: Record<string, DeriveStakerReward[]> = {};
stashIds.forEach((stashId, index): void => {
allRewards[stashId] = available[index].filter(({ eraReward }) => !eraReward.isZero());
});
return {
allRewards,
isLoadingRewards: false,
rewardCount: Object.values(allRewards).filter((rewards) => rewards.length !== 0).length
};
}
function getValRewards (validatorEras: ValidatorWithEras[], erasPoints: DeriveEraPoints[], erasRewards: DeriveEraRewards[]): OwnRewards {
const allRewards: Record<string, DeriveStakerReward[]> = {};
validatorEras.forEach(({ eras, stashId }): void => {
eras.forEach((era): void => {
const eraPoints = erasPoints.find((p) => p.era.eq(era));
const eraRewards = erasRewards.find((r) => r.era.eq(era));
if (eraPoints?.eraPoints.gt(BN_ZERO) && eraPoints?.validators[stashId] && eraRewards) {
const reward = eraPoints.validators[stashId].mul(eraRewards.eraReward).div(eraPoints.eraPoints);
if (!reward.isZero()) {
const total = registry.createType('Balance', reward);
if (!allRewards[stashId]) {
allRewards[stashId] = [];
}
allRewards[stashId].push({
era,
eraReward: eraRewards.eraReward,
isEmpty: false,
isValidator: true,
nominating: [],
validators: {
[stashId]: {
total,
value: total
}
}
});
}
}
});
});
return {
allRewards,
isLoadingRewards: false,
rewardCount: Object.values(allRewards).filter((rewards) => rewards.length !== 0).length
};
}
export default function useOwnEraRewards (maxEras?: number, ownValidators?: StakerState[]): OwnRewards {
const { api } = useApi();
const mountedRef = useIsMountedRef();
const stashIds = useOwnStashIds();
const allEras = useCall<EraIndex[]>(api.derive.staking?.erasHistoric);
const [{ filteredEras, validatorEras }, setFiltered] = useState<Filtered>({ filteredEras: [], validatorEras: [] });
const [state, setState] = useState<OwnRewards>({ isLoadingRewards: true, rewardCount: 0 });
const stakerRewards = useCall<[[string[]], DeriveStakerReward[][]]>(!ownValidators?.length && !!filteredEras.length && stashIds && api.derive.staking?.stakerRewardsMultiEras, [stashIds, filteredEras], { withParams: true });
const erasPoints = useCall<DeriveEraPoints[]>(!!validatorEras.length && !!filteredEras.length && api.derive.staking._erasPoints, [filteredEras, false]);
const erasRewards = useCall<DeriveEraRewards[]>(!!validatorEras.length && !!filteredEras.length && api.derive.staking._erasRewards, [filteredEras, false]);
useEffect((): void => {
setState({ allRewards: null, isLoadingRewards: true, rewardCount: 0 });
}, [maxEras, ownValidators]);
useEffect((): void => {
if (allEras && maxEras) {
const filteredEras = allEras.slice(-1 * maxEras);
const validatorEras: ValidatorWithEras[] = [];
if (ownValidators?.length) {
ownValidators.forEach(({ stakingLedger, stashId }): void => {
if (stakingLedger) {
const eras = filteredEras.filter((era) => !stakingLedger.claimedRewards.some((c) => era.eq(c)));
if (eras.length) {
validatorEras.push({ eras, stashId });
}
}
});
}
setFiltered({ filteredEras, validatorEras });
}
}, [allEras, maxEras, ownValidators]);
useEffect((): void => {
mountedRef.current && stakerRewards && !ownValidators && setState(
getRewards(stakerRewards)
);
}, [mountedRef, ownValidators, stakerRewards]);
useEffect((): void => {
mountedRef && erasPoints && erasRewards && ownValidators && setState(
getValRewards(validatorEras, erasPoints, erasRewards)
);
}, [erasPoints, erasRewards, mountedRef, ownValidators, validatorEras]);
return state;
}