Add stakerRewards for available reward calcs (#2028)
This commit is contained in:
@@ -38,8 +38,8 @@ function mapStakers (stakers: [StorageKey, Exposure][]): Mapped {
|
||||
return { nominators, validators };
|
||||
}
|
||||
|
||||
export function erasExposure (api: ApiInterfaceRx): (withActive?: boolean | BN) => Observable<DeriveEraExposure[]> {
|
||||
return memo((withActive?: boolean | BN): Observable<DeriveEraExposure[]> =>
|
||||
export function erasExposure (api: ApiInterfaceRx): (withActive?: boolean | BN | number) => Observable<DeriveEraExposure[]> {
|
||||
return memo((withActive?: boolean | BN | number): Observable<DeriveEraExposure[]> =>
|
||||
api.derive.staking.erasHistoric(withActive).pipe(
|
||||
switchMap((eras): Observable<[EraIndex[], [StorageKey, Exposure][][]]> =>
|
||||
combineLatest([
|
||||
|
||||
@@ -9,12 +9,12 @@ import BN from 'bn.js';
|
||||
import { Observable, of } from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { Option, u32 } from '@polkadot/types';
|
||||
import { isBoolean, isUndefined } from '@polkadot/util';
|
||||
import { isBoolean, isUndefined, bnToBn } from '@polkadot/util';
|
||||
|
||||
import { memo } from '../util';
|
||||
|
||||
export function erasHistoric (api: ApiInterfaceRx): (withActive?: boolean | BN) => Observable<EraIndex[]> {
|
||||
return memo((withActive?: boolean | BN): Observable<EraIndex[]> =>
|
||||
export function erasHistoric (api: ApiInterfaceRx): (withActive?: boolean | BN | number) => Observable<EraIndex[]> {
|
||||
return memo((withActive?: boolean | BN | number): Observable<EraIndex[]> =>
|
||||
api.query.staking?.activeEra
|
||||
? api.queryMulti<[Option<ActiveEraInfo>, u32]>([
|
||||
api.query.staking.activeEra,
|
||||
@@ -36,13 +36,15 @@ export function erasHistoric (api: ApiInterfaceRx): (withActive?: boolean | BN)
|
||||
lastEra = lastEra.subn(1);
|
||||
}
|
||||
|
||||
const startEra = isUndefined(withActive) || isBoolean(withActive)
|
||||
? new BN(0)
|
||||
: bnToBn(withActive);
|
||||
|
||||
// go from oldest to newest
|
||||
return result
|
||||
.filter((era): era is EraIndex =>
|
||||
era
|
||||
? isUndefined(withActive) || isBoolean(withActive)
|
||||
? true
|
||||
: era.gte(withActive)
|
||||
? era.gte(startEra)
|
||||
: false
|
||||
)
|
||||
.reverse();
|
||||
|
||||
@@ -22,8 +22,8 @@ function mapValidators ({ individual }: EraRewardPoints): DeriveEraValPoints {
|
||||
}, {});
|
||||
}
|
||||
|
||||
export function erasPoints (api: ApiInterfaceRx): (withActive?: boolean | BN) => Observable<DeriveEraPoints[]> {
|
||||
return memo((withActive?: boolean): Observable<DeriveEraPoints[]> =>
|
||||
export function erasPoints (api: ApiInterfaceRx): (withActive?: boolean | BN | number) => Observable<DeriveEraPoints[]> {
|
||||
return memo((withActive?: boolean | number): Observable<DeriveEraPoints[]> =>
|
||||
api.derive.staking.erasHistoric(withActive).pipe(
|
||||
switchMap((eras): Observable<[EraIndex[], EraRewardPoints[]]> =>
|
||||
combineLatest([
|
||||
|
||||
@@ -13,8 +13,8 @@ import { Option } from '@polkadot/types';
|
||||
|
||||
import { memo } from '../util';
|
||||
|
||||
export function erasRewards (api: ApiInterfaceRx): (withActive?: boolean | BN) => Observable<DeriveEraRewards[]> {
|
||||
return memo((withActive?: boolean | BN): Observable<DeriveEraRewards[]> =>
|
||||
export function erasRewards (api: ApiInterfaceRx): (withActive?: boolean | BN | number) => Observable<DeriveEraRewards[]> {
|
||||
return memo((withActive?: boolean | BN | number): Observable<DeriveEraRewards[]> =>
|
||||
api.derive.staking.erasHistoric(withActive).pipe(
|
||||
switchMap((eras): Observable<[EraIndex[], Option<Balance>[]]> =>
|
||||
combineLatest([
|
||||
|
||||
@@ -13,4 +13,5 @@ export * from './overview';
|
||||
export * from './query';
|
||||
export * from './stakerExposure';
|
||||
export * from './stakerPoints';
|
||||
export * from './stakerRewards';
|
||||
export * from './validators';
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { ApiInterfaceRx } from '@polkadot/api/types';
|
||||
import { DeriveStakerExpoure, DeriveEraValidatorExposure } from '../types';
|
||||
import { DeriveStakerExposure, DeriveEraValidatorExposure } from '../types';
|
||||
|
||||
import BN from 'bn.js';
|
||||
import { Observable } from 'rxjs';
|
||||
@@ -11,13 +11,13 @@ import { map } from 'rxjs/operators';
|
||||
|
||||
import { memo } from '../util';
|
||||
|
||||
export function stakerExposure (api: ApiInterfaceRx): (accountId: Uint8Array | string, withActive?: boolean | BN) => Observable<DeriveStakerExpoure[]> {
|
||||
return memo((accountId: Uint8Array | string, withActive?: boolean | BN): Observable<DeriveStakerExpoure[]> => {
|
||||
export function stakerExposure (api: ApiInterfaceRx): (accountId: Uint8Array | string, withActive?: boolean | BN | number) => Observable<DeriveStakerExposure[]> {
|
||||
return memo((accountId: Uint8Array | string, withActive?: boolean | BN | number): Observable<DeriveStakerExposure[]> => {
|
||||
const stakerId = api.registry.createType('AccountId', accountId).toString();
|
||||
|
||||
return api.derive.staking.erasExposure(withActive).pipe(
|
||||
map((exposures): DeriveStakerExpoure[] =>
|
||||
exposures.map(({ era, nominators: allNominators, validators: allValidators }): DeriveStakerExpoure => {
|
||||
map((exposures): DeriveStakerExposure[] =>
|
||||
exposures.map(({ era, nominators: allNominators, validators: allValidators }): DeriveStakerExposure => {
|
||||
const isValidator = !!allValidators[stakerId];
|
||||
const validators: DeriveEraValidatorExposure = {};
|
||||
let nominating: [string, number][] = [];
|
||||
|
||||
@@ -11,8 +11,8 @@ import { map } from 'rxjs/operators';
|
||||
|
||||
import { memo } from '../util';
|
||||
|
||||
export function stakerPoints (api: ApiInterfaceRx): (accountId: Uint8Array | string, withActive?: boolean | BN) => Observable<DeriveStakerPoints[]> {
|
||||
return memo((accountId: Uint8Array | string, withActive?: boolean | BN): Observable<DeriveStakerPoints[]> => {
|
||||
export function stakerPoints (api: ApiInterfaceRx): (accountId: Uint8Array | string, withActive?: boolean | BN | number) => Observable<DeriveStakerPoints[]> {
|
||||
return memo((accountId: Uint8Array | string, withActive?: boolean | BN | number): Observable<DeriveStakerPoints[]> => {
|
||||
const stakerId = api.registry.createType('AccountId', accountId).toString();
|
||||
|
||||
return api.derive.staking.erasPoints(withActive).pipe(
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
// Copyright 2017-2020 @polkadot/api-derive 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 { ApiInterfaceRx } from '@polkadot/api/types';
|
||||
import { Balance } from '@polkadot/types/interfaces';
|
||||
import { DeriveEraPoints, DeriveEraRewards, DeriveStakerExposure, DeriveStakerReward } from '../types';
|
||||
|
||||
import BN from 'bn.js';
|
||||
import { Observable, combineLatest } from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
|
||||
import { memo } from '../util';
|
||||
|
||||
type Result = [DeriveEraPoints[], DeriveEraRewards[], DeriveStakerExposure[]];
|
||||
const ZERO = new BN(0);
|
||||
|
||||
function parseRewards (api: ApiInterfaceRx, stakerId: string, [erasPoints, erasRewards, exposures]: Result): DeriveStakerReward[] {
|
||||
return exposures.map(({ era, isEmpty, isValidator, nominating, validators: eraValidators }): DeriveStakerReward => {
|
||||
const { eraPoints, validators: allValPoints } = erasPoints.find((p) => p.era.eq(era)) || { eraPoints: new BN(0), validators: {} };
|
||||
const { eraReward } = erasRewards.find((r) => r.era.eq(era)) || { eraReward: new BN(0) };
|
||||
const validators: Record<string, Balance> = {};
|
||||
let total = ZERO;
|
||||
|
||||
Object.entries(eraValidators).forEach(([validatorId, exposure]): void => {
|
||||
const valPoints = allValPoints[validatorId] || new BN(0);
|
||||
const expTotal = exposure.total.unwrap();
|
||||
let value: BN | undefined;
|
||||
|
||||
if (!expTotal.isZero() && !valPoints.isZero()) {
|
||||
let staked: BN;
|
||||
|
||||
if (validatorId === stakerId) {
|
||||
staked = exposure.own.unwrap();
|
||||
} else {
|
||||
const stakerExp = exposure.others.find(({ who }): boolean => who.eq(stakerId));
|
||||
|
||||
staked = stakerExp
|
||||
? stakerExp.value.unwrap()
|
||||
: ZERO;
|
||||
}
|
||||
|
||||
value = eraReward.mul(valPoints).mul(staked).div(eraPoints).div(expTotal);
|
||||
total = total.add(value);
|
||||
}
|
||||
|
||||
validators[validatorId] = api.registry.createType('Balance', value);
|
||||
});
|
||||
|
||||
return {
|
||||
era,
|
||||
isEmpty,
|
||||
isValidator,
|
||||
nominating,
|
||||
total: api.registry.createType('Balance', total),
|
||||
validators
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
export function stakerRewards (api: ApiInterfaceRx): (accountId: Uint8Array | string, startEra: BN | number) => Observable<DeriveStakerReward[]> {
|
||||
return memo((accountId: Uint8Array | string, startEra: BN | number): Observable<DeriveStakerReward[]> => {
|
||||
const stakerId = api.registry.createType('AccountId', accountId).toString();
|
||||
|
||||
return combineLatest([
|
||||
api.derive.staking.erasPoints(startEra),
|
||||
api.derive.staking.erasRewards(startEra),
|
||||
api.derive.staking.stakerExposure(stakerId, startEra)
|
||||
]).pipe(
|
||||
map((result): DeriveStakerReward[] =>
|
||||
parseRewards(api, stakerId, result)
|
||||
)
|
||||
);
|
||||
});
|
||||
}
|
||||
@@ -34,7 +34,7 @@ export interface DeriveEraExposure {
|
||||
validators: DeriveEraValidatorExposure;
|
||||
}
|
||||
|
||||
export interface DeriveStakerExpoure {
|
||||
export interface DeriveStakerExposure {
|
||||
era: EraIndex;
|
||||
isEmpty: boolean;
|
||||
isValidator: boolean;
|
||||
@@ -42,6 +42,15 @@ export interface DeriveStakerExpoure {
|
||||
validators: DeriveEraValidatorExposure;
|
||||
}
|
||||
|
||||
export interface DeriveStakerReward {
|
||||
era: EraIndex;
|
||||
isEmpty: boolean;
|
||||
isValidator: boolean;
|
||||
nominating: [string, number][];
|
||||
validators: Record<string, Balance>;
|
||||
total: Balance;
|
||||
}
|
||||
|
||||
export interface DerivedStakingElected {
|
||||
nextElected: AccountId[];
|
||||
info: DerivedStakingQuery[];
|
||||
|
||||
Reference in New Issue
Block a user