Rework rewards with new staking (#2338)
* Rework rewards with new staking * Bump api * Bump API * Disable buttons on no controller
This commit is contained in:
parent
3d635a1e69
commit
95471f42c4
@ -8,11 +8,10 @@
|
||||
"packages/*"
|
||||
],
|
||||
"resolutions": {
|
||||
"@polkadot/api": "^1.6.0-beta.5",
|
||||
"@polkadot/api-contract": "^1.6.0-beta.5",
|
||||
"@polkadot/api": "^1.6.0-beta.9",
|
||||
"@polkadot/api-contract": "^1.6.0-beta.9",
|
||||
"@polkadot/keyring": "^2.6.1",
|
||||
"@polkadot/typegen": "^1.6.0-beta.5",
|
||||
"@polkadot/types": "^1.6.0-beta.5",
|
||||
"@polkadot/types": "^1.6.0-beta.9",
|
||||
"@polkadot/util": "^2.6.1",
|
||||
"@polkadot/util-crypto": "^2.6.1",
|
||||
"babel-core": "^7.0.0-bridge.0",
|
||||
@ -31,7 +30,7 @@
|
||||
"postinstall": "polkadot-dev-yarn-only",
|
||||
"test": "polkadot-dev-run-test packages/page-claims/src",
|
||||
"vanitygen": "node packages/page-accounts/scripts/vanitygen.js",
|
||||
"start": "cd packages/apps && webpack --config webpack.config.js"
|
||||
"start": "yarn clean && cd packages/apps && webpack --config webpack.config.js"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.8.7",
|
||||
|
||||
@ -12,6 +12,6 @@
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.8.7",
|
||||
"@polkadot/api-contract": "^1.6.0-beta.5"
|
||||
"@polkadot/api-contract": "^1.6.0-beta.9"
|
||||
}
|
||||
}
|
||||
|
||||
@ -140,7 +140,7 @@ function Account ({ allStashes, className, isOwnStash, next, onUpdateType, staki
|
||||
useEffect((): void => {
|
||||
if (stakingRewardsAll && stakingAccount?.stakingLedger?.lastReward) {
|
||||
const lastClaim = stakingAccount.stakingLedger.lastReward.unwrapOr(new BN(-1));
|
||||
const stakingRewards = stakingRewardsAll.filter(({ era }): boolean => era.gt(lastClaim));
|
||||
const stakingRewards = stakingRewardsAll.filter(({ era, isEmpty }): boolean => !isEmpty && era.gt(lastClaim));
|
||||
|
||||
setStakingRewards([
|
||||
stakingRewards,
|
||||
@ -306,6 +306,7 @@ function Account ({ allStashes, className, isOwnStash, next, onUpdateType, staki
|
||||
? (
|
||||
<TxButton
|
||||
accountId={controllerId}
|
||||
isDisabled={!isOwnController}
|
||||
isNegative
|
||||
label={
|
||||
isStashNominating
|
||||
@ -322,6 +323,7 @@ function Account ({ allStashes, className, isOwnStash, next, onUpdateType, staki
|
||||
{(!sessionIds.length || hexSessionIdNext === '0x')
|
||||
? (
|
||||
<Button
|
||||
isDisabled={!isOwnController}
|
||||
isPrimary
|
||||
key='set'
|
||||
onClick={toggleSetSession}
|
||||
@ -331,6 +333,7 @@ function Account ({ allStashes, className, isOwnStash, next, onUpdateType, staki
|
||||
)
|
||||
: (
|
||||
<Button
|
||||
isDisabled={!isOwnController}
|
||||
isPrimary
|
||||
key='validate'
|
||||
onClick={toggleValidate}
|
||||
@ -341,6 +344,7 @@ function Account ({ allStashes, className, isOwnStash, next, onUpdateType, staki
|
||||
}
|
||||
<Button.Or key='nominate.or' />
|
||||
<Button
|
||||
isDisabled={!isOwnController}
|
||||
isPrimary
|
||||
key='nominate'
|
||||
onClick={toggleNominate}
|
||||
|
||||
@ -2,19 +2,16 @@
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { Balance, Hash, Exposure } from '@polkadot/types/interfaces';
|
||||
import { SessionRewards, Slash } from '../types';
|
||||
import { DeriveStakerReward } from '@polkadot/api-derive/types';
|
||||
import { SessionRewards } from '../types';
|
||||
|
||||
import BN from 'bn.js';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import React, { useEffect, useMemo, useState } from 'react';
|
||||
import { Chart, Columar, Column } from '@polkadot/react-components';
|
||||
import { toShortAddress } from '@polkadot/react-components/util';
|
||||
import { getHistoric } from '@polkadot/react-api/util';
|
||||
import { useApi } from '@polkadot/react-hooks';
|
||||
import { formatBalance, formatNumber } from '@polkadot/util';
|
||||
import { useApi, useCall } from '@polkadot/react-hooks';
|
||||
import { formatBalance } from '@polkadot/util';
|
||||
|
||||
import { useTranslation } from '../translate';
|
||||
import useBlockCounts from '../useBlockCounts';
|
||||
|
||||
interface Props {
|
||||
className?: string;
|
||||
@ -26,244 +23,105 @@ type LineDataEntry = (BN | number)[];
|
||||
|
||||
type LineData = LineDataEntry[];
|
||||
|
||||
interface SplitEntry {
|
||||
colors: string[];
|
||||
label: string;
|
||||
tooltip: string;
|
||||
value: number;
|
||||
interface BlockChart {
|
||||
blockChart: LineData;
|
||||
blockLabels: string[];
|
||||
}
|
||||
|
||||
type SplitData = SplitEntry[];
|
||||
interface StakeChart {
|
||||
stakeChart: LineData;
|
||||
stakeLabels: string[];
|
||||
}
|
||||
|
||||
const COLORS_MINE = ['#ff8c00'];
|
||||
const COLORS_OTHER = ['#acacac'];
|
||||
const COLORS_REWARD = ['#8c2200', '#008c22', '#acacac'];
|
||||
// const COLORS_MINE = ['#ff8c00'];
|
||||
// const COLORS_OTHER = ['#acacac'];
|
||||
// const COLORS_REWARD = ['#8c2200', '#008c22', '#acacac'];
|
||||
const COLORS_BLOCKS = [undefined, '#acacac'];
|
||||
|
||||
function balanceToNumber (amount: BN, divisor: BN): number {
|
||||
return amount.muln(1000).div(divisor).toNumber() / 1000;
|
||||
}
|
||||
|
||||
function extractStake (values: [Hash, Exposure][], divisor: BN): LineData {
|
||||
return [
|
||||
values.map(([, { total }]): number =>
|
||||
balanceToNumber(total.unwrap(), divisor))
|
||||
// exposures.map(({ own }): number =>
|
||||
// balanceToNumber(own.unwrap(), divisor)),
|
||||
// exposures.map(({ others }): number =>
|
||||
// balanceToNumber(
|
||||
// others.reduce((total, { value }): number =>
|
||||
// total.add(value.unwrap()), new BN(0)
|
||||
// ), divisor))
|
||||
];
|
||||
function extractBlocks (validatorId: string, rewards: DeriveStakerReward[] = []): BlockChart {
|
||||
const blockLabels: string[] = [];
|
||||
const avgSet: number[] = [];
|
||||
const idxSet: number[] = [];
|
||||
let total = 0;
|
||||
|
||||
rewards.forEach(({ era, validators }, index): void => {
|
||||
const points = validators[validatorId]?.points.toNumber() || 0;
|
||||
|
||||
total += points;
|
||||
|
||||
blockLabels.push(era.toHuman());
|
||||
avgSet.push(Math.ceil(total / (index + 1) * 100) / 100);
|
||||
idxSet.push(points);
|
||||
});
|
||||
|
||||
return {
|
||||
blockChart: [idxSet, avgSet],
|
||||
blockLabels
|
||||
};
|
||||
}
|
||||
|
||||
function extractSplit (values: [Hash, Exposure][], validatorId: string): SplitData | null {
|
||||
if (!values.length) {
|
||||
return null;
|
||||
}
|
||||
function extractStake (validatorId: string, divisor: BN, rewards: DeriveStakerReward[] = []): StakeChart {
|
||||
const stakeLabels: string[] = [];
|
||||
const stakeChart: LineDataEntry = [];
|
||||
|
||||
const last = values[values.length - 1][1];
|
||||
const total = last.total.unwrap();
|
||||
rewards.forEach(({ era, validators }): void => {
|
||||
stakeLabels.push(era.toHuman());
|
||||
stakeChart.push(
|
||||
balanceToNumber(validators[validatorId]?.exposure.total.toBn() || new BN(0), divisor)
|
||||
);
|
||||
});
|
||||
|
||||
if (total.eqn(0)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const currency = formatBalance.getDefaults().unit;
|
||||
|
||||
return [{ accountId: validatorId, isOwn: true, value: last.own.unwrap() }]
|
||||
.concat(last.others.map(({ who, value }): { accountId: string; isOwn: boolean; value: Balance } => ({
|
||||
accountId: who.toString(), isOwn: false, value: value.unwrap()
|
||||
})))
|
||||
.sort((a, b): number => b.value.cmp(a.value))
|
||||
.map(({ accountId, isOwn, value }): SplitEntry => {
|
||||
const label = toShortAddress(accountId);
|
||||
const percentage = value.muln(10000).div(total).toNumber() / 100;
|
||||
const tooltip = `${formatBalance(value, { forceUnit: '-', withSi: false })} ${currency} (${percentage.toFixed(2)}%)`;
|
||||
|
||||
return {
|
||||
colors: isOwn ? COLORS_MINE : COLORS_OTHER,
|
||||
label,
|
||||
tooltip,
|
||||
value: percentage
|
||||
};
|
||||
});
|
||||
return {
|
||||
stakeChart: [stakeChart],
|
||||
stakeLabels
|
||||
};
|
||||
}
|
||||
|
||||
function extractEraSlash (validatorId: string, slashes: Slash[]): BN {
|
||||
return slashes.reduce((total: BN, { accountId, amount }): BN => {
|
||||
return accountId.eq(validatorId)
|
||||
? total.sub(amount)
|
||||
: total;
|
||||
}, new BN(0));
|
||||
}
|
||||
|
||||
export default function Validator ({ className, sessionRewards, validatorId }: Props): React.ReactElement<Props> {
|
||||
export default function Validator ({ className, validatorId }: Props): React.ReactElement<Props> {
|
||||
const { t } = useTranslation();
|
||||
const { api } = useApi();
|
||||
const blockCounts = useBlockCounts(validatorId, sessionRewards);
|
||||
const [blocksLabels, setBlocksLabels] = useState<string[]>([]);
|
||||
const [blocksChart, setBlocksChart] = useState<LineData | null>(null);
|
||||
const [{ currency, divisor }] = useState<{ currency: string; divisor: BN }>({
|
||||
const [{ blockChart, blockLabels }, setBlockChart] = useState<BlockChart>({ blockChart: [], blockLabels: [] });
|
||||
const [{ stakeChart, stakeLabels }, setStakeChart] = useState<StakeChart>({ stakeChart: [], stakeLabels: [] });
|
||||
const stakerRewards = useCall<DeriveStakerReward[]>(api.derive.staking.stakerRewards as any, [validatorId, true]);
|
||||
const { currency, divisor } = useMemo((): { currency: string; divisor: BN } => ({
|
||||
currency: formatBalance.getDefaults().unit,
|
||||
divisor: new BN('1'.padEnd(formatBalance.getDefaults().decimals + 1, '0'))
|
||||
});
|
||||
const [{ rewardsChart, rewardsLabels }, setRewardsInfo] = useState<{ rewardsChart: LineData | null; rewardsLabels: string[] }>({ rewardsChart: null, rewardsLabels: [] });
|
||||
const [{ splitChart, splitMax }, setSplitInfo] = useState<{ splitChart: SplitData | null; splitMax: number }>({ splitChart: null, splitMax: 100 });
|
||||
const [{ stakeChart, stakeLabels }, setStakeInfo] = useState<{ stakeChart: LineData | null; stakeLabels: string[]}>({ stakeChart: null, stakeLabels: [] });
|
||||
}), [formatBalance]);
|
||||
|
||||
useEffect((): void => {
|
||||
if (!splitChart) {
|
||||
const hashes = sessionRewards.map(({ blockHash }): Hash => blockHash);
|
||||
const stakeLabels = sessionRewards.map(({ sessionIndex }): string => formatNumber(sessionIndex));
|
||||
|
||||
api.isReady.then(async (): Promise<void> => {
|
||||
const values = await getHistoric<Exposure>(api.query.staking.stakers.at, [validatorId], hashes);
|
||||
const stakeChart = extractStake(values, divisor);
|
||||
const splitChart = extractSplit(values, validatorId);
|
||||
const splitMax = splitChart ? Math.min(Math.ceil(splitChart[0].value), 100) : 100;
|
||||
|
||||
setStakeInfo({ stakeChart, stakeLabels });
|
||||
setSplitInfo({ splitChart, splitMax });
|
||||
});
|
||||
}
|
||||
}, [sessionRewards, splitChart]);
|
||||
|
||||
useEffect((): void => {
|
||||
if (blockCounts) {
|
||||
const rewardsLabels: string[] = [];
|
||||
const rewardsChart: LineData = [[], [], []];
|
||||
let total = new BN(0);
|
||||
let lastRewardIndex = 0;
|
||||
let rewardCount = 0;
|
||||
|
||||
// we only work from the second position, the first deemed incomplete
|
||||
sessionRewards.forEach(({ blockNumber, reward, sessionIndex, slashes }, index): void => {
|
||||
// we are trying to find the first index where rewards are allocated, this is our start
|
||||
// since we only want complete eras, this means we drop some at the start
|
||||
if (lastRewardIndex === 0) {
|
||||
if (index && reward.gtn(0)) {
|
||||
lastRewardIndex = index;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// slash is extracted from the available slashes
|
||||
const neg = extractEraSlash(validatorId, slashes);
|
||||
|
||||
// start of a new session, use the counts for the previous
|
||||
const totalBlocks = blockCounts
|
||||
.filter((count, countIndex): boolean =>
|
||||
!!count && countIndex >= lastRewardIndex && countIndex < index)
|
||||
.reduce((total, count): BN => total.add(count), new BN(0));
|
||||
|
||||
// calculate the rewards based on our total share
|
||||
const pos = reward
|
||||
.mul(totalBlocks)
|
||||
.div(blockNumber.sub(sessionRewards[lastRewardIndex].blockNumber));
|
||||
|
||||
// add this to the total
|
||||
total = total.add(neg).add(pos);
|
||||
rewardCount++;
|
||||
|
||||
// if we have a reward here, set the reward index for the next iteration
|
||||
if (reward.gtn(0)) {
|
||||
lastRewardIndex = index;
|
||||
}
|
||||
|
||||
// this shows the start of the new era, however rewards are for previous
|
||||
rewardsLabels.push(formatNumber(sessionIndex.subn(1)));
|
||||
|
||||
// calculate and format to 3 decimals
|
||||
rewardsChart[0].push(balanceToNumber(neg, divisor));
|
||||
rewardsChart[1].push(balanceToNumber(pos, divisor));
|
||||
rewardsChart[2].push(balanceToNumber(total.divn(rewardCount), divisor));
|
||||
});
|
||||
|
||||
setRewardsInfo({ rewardsChart, rewardsLabels });
|
||||
}
|
||||
}, [blockCounts, sessionRewards, validatorId]);
|
||||
|
||||
useEffect((): void => {
|
||||
setBlocksLabels(
|
||||
sessionRewards.map(({ sessionIndex }): string => formatNumber(sessionIndex))
|
||||
);
|
||||
}, [sessionRewards]);
|
||||
|
||||
useEffect((): void => {
|
||||
if (blockCounts) {
|
||||
const avgSet: number[] = [];
|
||||
const idxSet: BN[] = [];
|
||||
|
||||
blockCounts.reduce((total: BN, value, index): BN => {
|
||||
total = total.add(value);
|
||||
|
||||
avgSet.push(total.muln(100).divn(index + 1).toNumber() / 100);
|
||||
idxSet.push(value);
|
||||
|
||||
return total;
|
||||
}, new BN(0));
|
||||
|
||||
setBlocksChart([idxSet, avgSet]);
|
||||
}
|
||||
}, [blockCounts]);
|
||||
setBlockChart(extractBlocks(validatorId, stakerRewards));
|
||||
setStakeChart(extractStake(validatorId, divisor, stakerRewards));
|
||||
}, [stakerRewards, validatorId]);
|
||||
|
||||
return (
|
||||
<Columar className={className}>
|
||||
<Column emptyText={t('Loading block data')}>
|
||||
{(rewardsChart || blocksChart) && (
|
||||
<>
|
||||
{blocksChart && (
|
||||
<div className='staking--Chart'>
|
||||
<h1>{t('blocks produced')}</h1>
|
||||
<Chart.Line
|
||||
colors={COLORS_BLOCKS}
|
||||
labels={blocksLabels}
|
||||
legends={[t('blocks'), t('average')]}
|
||||
values={blocksChart}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{rewardsChart && (
|
||||
<div className='staking--Chart'>
|
||||
<h1>{t('rewards & slashes')}</h1>
|
||||
<Chart.Line
|
||||
colors={COLORS_REWARD}
|
||||
labels={rewardsLabels}
|
||||
legends={[t('{{currency}} slashed', { replace: { currency } }), t('{{currency}} rewards (est.)', { replace: { currency } }), t('{{currency}} average', { replace: { currency } })]}
|
||||
values={rewardsChart}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
{!!blockChart.length && (
|
||||
<div className='staking--Chart'>
|
||||
<h1>{t('blocks produced')}</h1>
|
||||
<Chart.Line
|
||||
colors={COLORS_BLOCKS}
|
||||
labels={blockLabels}
|
||||
legends={[t('blocks'), t('average')]}
|
||||
values={blockChart}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</Column>
|
||||
<Column emptyText={t('Loading staker data')}>
|
||||
{(stakeChart || splitChart) && (
|
||||
<>
|
||||
{stakeChart && stakeChart[0].length !== 0 && (
|
||||
<div className='staking--Chart'>
|
||||
<h1>{t('elected stake')}</h1>
|
||||
<Chart.Line
|
||||
labels={stakeLabels}
|
||||
legends={[t('{{currency}} total', { replace: { currency } }), t('{{currency}} own', { replace: { currency } }), t('{{currency}} other', { replace: { currency } })]}
|
||||
values={stakeChart}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{splitChart && (
|
||||
<div className='staking--Chart'>
|
||||
<h1>{t('staker percentages')}</h1>
|
||||
<Chart.HorizBar
|
||||
aspectRatio={2}
|
||||
max={splitMax}
|
||||
values={splitChart}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
{stakeChart && !!stakeChart[0]?.length && (
|
||||
<div className='staking--Chart'>
|
||||
<h1>{t('elected stake')}</h1>
|
||||
<Chart.Line
|
||||
labels={stakeLabels}
|
||||
legends={[t('{{currency}} total', { replace: { currency } }), t('{{currency}} own', { replace: { currency } }), t('{{currency}} other', { replace: { currency } })]}
|
||||
values={stakeChart}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</Column>
|
||||
</Columar>
|
||||
|
||||
271
packages/page-staking/src/Query/ValidatorPrev.tsx
Normal file
271
packages/page-staking/src/Query/ValidatorPrev.tsx
Normal file
@ -0,0 +1,271 @@
|
||||
// Copyright 2017-2020 @polkadot/app-staking 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 { Balance, Hash, Exposure } from '@polkadot/types/interfaces';
|
||||
import { SessionRewards, Slash } from '../types';
|
||||
|
||||
import BN from 'bn.js';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { Chart, Columar, Column } from '@polkadot/react-components';
|
||||
import { toShortAddress } from '@polkadot/react-components/util';
|
||||
import { getHistoric } from '@polkadot/react-api/util';
|
||||
import { useApi } from '@polkadot/react-hooks';
|
||||
import { formatBalance, formatNumber } from '@polkadot/util';
|
||||
|
||||
import { useTranslation } from '../translate';
|
||||
import useBlockCounts from '../useBlockCounts';
|
||||
|
||||
interface Props {
|
||||
className?: string;
|
||||
sessionRewards: SessionRewards[];
|
||||
validatorId: string;
|
||||
}
|
||||
|
||||
type LineDataEntry = (BN | number)[];
|
||||
|
||||
type LineData = LineDataEntry[];
|
||||
|
||||
interface SplitEntry {
|
||||
colors: string[];
|
||||
label: string;
|
||||
tooltip: string;
|
||||
value: number;
|
||||
}
|
||||
|
||||
type SplitData = SplitEntry[];
|
||||
|
||||
const COLORS_MINE = ['#ff8c00'];
|
||||
const COLORS_OTHER = ['#acacac'];
|
||||
const COLORS_REWARD = ['#8c2200', '#008c22', '#acacac'];
|
||||
const COLORS_BLOCKS = [undefined, '#acacac'];
|
||||
|
||||
function balanceToNumber (amount: BN, divisor: BN): number {
|
||||
return amount.muln(1000).div(divisor).toNumber() / 1000;
|
||||
}
|
||||
|
||||
function extractStake (values: [Hash, Exposure][], divisor: BN): LineData {
|
||||
return [
|
||||
values.map(([, { total }]): number =>
|
||||
balanceToNumber(total.unwrap(), divisor))
|
||||
// exposures.map(({ own }): number =>
|
||||
// balanceToNumber(own.unwrap(), divisor)),
|
||||
// exposures.map(({ others }): number =>
|
||||
// balanceToNumber(
|
||||
// others.reduce((total, { value }): number =>
|
||||
// total.add(value.unwrap()), new BN(0)
|
||||
// ), divisor))
|
||||
];
|
||||
}
|
||||
|
||||
function extractSplit (values: [Hash, Exposure][], validatorId: string): SplitData | null {
|
||||
if (!values.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const last = values[values.length - 1][1];
|
||||
const total = last.total.unwrap();
|
||||
|
||||
if (total.eqn(0)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const currency = formatBalance.getDefaults().unit;
|
||||
|
||||
return [{ accountId: validatorId, isOwn: true, value: last.own.unwrap() }]
|
||||
.concat(last.others.map(({ who, value }): { accountId: string; isOwn: boolean; value: Balance } => ({
|
||||
accountId: who.toString(), isOwn: false, value: value.unwrap()
|
||||
})))
|
||||
.sort((a, b): number => b.value.cmp(a.value))
|
||||
.map(({ accountId, isOwn, value }): SplitEntry => {
|
||||
const label = toShortAddress(accountId);
|
||||
const percentage = value.muln(10000).div(total).toNumber() / 100;
|
||||
const tooltip = `${formatBalance(value, { forceUnit: '-', withSi: false })} ${currency} (${percentage.toFixed(2)}%)`;
|
||||
|
||||
return {
|
||||
colors: isOwn ? COLORS_MINE : COLORS_OTHER,
|
||||
label,
|
||||
tooltip,
|
||||
value: percentage
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
function extractEraSlash (validatorId: string, slashes: Slash[]): BN {
|
||||
return slashes.reduce((total: BN, { accountId, amount }): BN => {
|
||||
return accountId.eq(validatorId)
|
||||
? total.sub(amount)
|
||||
: total;
|
||||
}, new BN(0));
|
||||
}
|
||||
|
||||
export default function Validator ({ className, sessionRewards, validatorId }: Props): React.ReactElement<Props> {
|
||||
const { t } = useTranslation();
|
||||
const { api } = useApi();
|
||||
const blockCounts = useBlockCounts(validatorId, sessionRewards);
|
||||
const [blocksLabels, setBlocksLabels] = useState<string[]>([]);
|
||||
const [blocksChart, setBlocksChart] = useState<LineData | null>(null);
|
||||
const [{ currency, divisor }] = useState<{ currency: string; divisor: BN }>({
|
||||
currency: formatBalance.getDefaults().unit,
|
||||
divisor: new BN('1'.padEnd(formatBalance.getDefaults().decimals + 1, '0'))
|
||||
});
|
||||
const [{ rewardsChart, rewardsLabels }, setRewardsInfo] = useState<{ rewardsChart: LineData | null; rewardsLabels: string[] }>({ rewardsChart: null, rewardsLabels: [] });
|
||||
const [{ splitChart, splitMax }, setSplitInfo] = useState<{ splitChart: SplitData | null; splitMax: number }>({ splitChart: null, splitMax: 100 });
|
||||
const [{ stakeChart, stakeLabels }, setStakeInfo] = useState<{ stakeChart: LineData | null; stakeLabels: string[]}>({ stakeChart: null, stakeLabels: [] });
|
||||
|
||||
useEffect((): void => {
|
||||
if (!splitChart) {
|
||||
const hashes = sessionRewards.map(({ blockHash }): Hash => blockHash);
|
||||
const stakeLabels = sessionRewards.map(({ sessionIndex }): string => formatNumber(sessionIndex));
|
||||
|
||||
api.isReady.then(async (): Promise<void> => {
|
||||
const values = await getHistoric<Exposure>(api.query.staking.stakers.at, [validatorId], hashes);
|
||||
const stakeChart = extractStake(values, divisor);
|
||||
const splitChart = extractSplit(values, validatorId);
|
||||
const splitMax = splitChart ? Math.min(Math.ceil(splitChart[0].value), 100) : 100;
|
||||
|
||||
setStakeInfo({ stakeChart, stakeLabels });
|
||||
setSplitInfo({ splitChart, splitMax });
|
||||
});
|
||||
}
|
||||
}, [sessionRewards, splitChart]);
|
||||
|
||||
useEffect((): void => {
|
||||
if (blockCounts) {
|
||||
const rewardsLabels: string[] = [];
|
||||
const rewardsChart: LineData = [[], [], []];
|
||||
let total = new BN(0);
|
||||
let lastRewardIndex = 0;
|
||||
let rewardCount = 0;
|
||||
|
||||
// we only work from the second position, the first deemed incomplete
|
||||
sessionRewards.forEach(({ blockNumber, reward, sessionIndex, slashes }, index): void => {
|
||||
// we are trying to find the first index where rewards are allocated, this is our start
|
||||
// since we only want complete eras, this means we drop some at the start
|
||||
if (lastRewardIndex === 0) {
|
||||
if (index && reward.gtn(0)) {
|
||||
lastRewardIndex = index;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// slash is extracted from the available slashes
|
||||
const neg = extractEraSlash(validatorId, slashes);
|
||||
|
||||
// start of a new session, use the counts for the previous
|
||||
const totalBlocks = blockCounts
|
||||
.filter((count, countIndex): boolean =>
|
||||
!!count && countIndex >= lastRewardIndex && countIndex < index)
|
||||
.reduce((total, count): BN => total.add(count), new BN(0));
|
||||
|
||||
// calculate the rewards based on our total share
|
||||
const pos = reward
|
||||
.mul(totalBlocks)
|
||||
.div(blockNumber.sub(sessionRewards[lastRewardIndex].blockNumber));
|
||||
|
||||
// add this to the total
|
||||
total = total.add(neg).add(pos);
|
||||
rewardCount++;
|
||||
|
||||
// if we have a reward here, set the reward index for the next iteration
|
||||
if (reward.gtn(0)) {
|
||||
lastRewardIndex = index;
|
||||
}
|
||||
|
||||
// this shows the start of the new era, however rewards are for previous
|
||||
rewardsLabels.push(formatNumber(sessionIndex.subn(1)));
|
||||
|
||||
// calculate and format to 3 decimals
|
||||
rewardsChart[0].push(balanceToNumber(neg, divisor));
|
||||
rewardsChart[1].push(balanceToNumber(pos, divisor));
|
||||
rewardsChart[2].push(balanceToNumber(total.divn(rewardCount), divisor));
|
||||
});
|
||||
|
||||
setRewardsInfo({ rewardsChart, rewardsLabels });
|
||||
}
|
||||
}, [blockCounts, sessionRewards, validatorId]);
|
||||
|
||||
useEffect((): void => {
|
||||
setBlocksLabels(
|
||||
sessionRewards.map(({ sessionIndex }): string => formatNumber(sessionIndex))
|
||||
);
|
||||
}, [sessionRewards]);
|
||||
|
||||
useEffect((): void => {
|
||||
if (blockCounts) {
|
||||
const avgSet: number[] = [];
|
||||
const idxSet: BN[] = [];
|
||||
|
||||
blockCounts.reduce((total: BN, value, index): BN => {
|
||||
total = total.add(value);
|
||||
|
||||
avgSet.push(total.muln(100).divn(index + 1).toNumber() / 100);
|
||||
idxSet.push(value);
|
||||
|
||||
return total;
|
||||
}, new BN(0));
|
||||
|
||||
setBlocksChart([idxSet, avgSet]);
|
||||
}
|
||||
}, [blockCounts]);
|
||||
|
||||
return (
|
||||
<Columar className={className}>
|
||||
<Column emptyText={t('Loading block data')}>
|
||||
{(rewardsChart || blocksChart) && (
|
||||
<>
|
||||
{blocksChart && (
|
||||
<div className='staking--Chart'>
|
||||
<h1>{t('blocks produced')}</h1>
|
||||
<Chart.Line
|
||||
colors={COLORS_BLOCKS}
|
||||
labels={blocksLabels}
|
||||
legends={[t('blocks'), t('average')]}
|
||||
values={blocksChart}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{rewardsChart && (
|
||||
<div className='staking--Chart'>
|
||||
<h1>{t('rewards & slashes')}</h1>
|
||||
<Chart.Line
|
||||
colors={COLORS_REWARD}
|
||||
labels={rewardsLabels}
|
||||
legends={[t('{{currency}} slashed', { replace: { currency } }), t('{{currency}} rewards (est.)', { replace: { currency } }), t('{{currency}} average', { replace: { currency } })]}
|
||||
values={rewardsChart}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</Column>
|
||||
<Column emptyText={t('Loading staker data')}>
|
||||
{(stakeChart || splitChart) && (
|
||||
<>
|
||||
{stakeChart && stakeChart[0].length !== 0 && (
|
||||
<div className='staking--Chart'>
|
||||
<h1>{t('elected stake')}</h1>
|
||||
<Chart.Line
|
||||
labels={stakeLabels}
|
||||
legends={[t('{{currency}} total', { replace: { currency } }), t('{{currency}} own', { replace: { currency } }), t('{{currency}} other', { replace: { currency } })]}
|
||||
values={stakeChart}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{splitChart && (
|
||||
<div className='staking--Chart'>
|
||||
<h1>{t('staker percentages')}</h1>
|
||||
<Chart.HorizBar
|
||||
aspectRatio={2}
|
||||
max={splitMax}
|
||||
values={splitChart}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</Column>
|
||||
</Columar>
|
||||
);
|
||||
}
|
||||
@ -42,8 +42,10 @@ function StakingApp ({ basePath, className }: Props): React.ReactElement<Props>
|
||||
const recentlyOnline = useCall<DerivedHeartbeats>(api.derive.imOnline?.receivedHeartbeats, []);
|
||||
const stakingOverview = useCall<DerivedStakingOverview>(api.derive.staking.overview, []);
|
||||
const sessionRewards = useSessionRewards(MAX_SESSIONS);
|
||||
const hasQueries = hasAccounts && !!(api.query.imOnline?.authoredBlocks);
|
||||
const [nominators, dispatchNominators] = useReducer(reduceNominators, [] as string[]);
|
||||
const hasQueries = useMemo((): boolean => {
|
||||
return hasAccounts && !!(api.query.imOnline?.authoredBlocks) && !!(api.query.staking.activeEra);
|
||||
}, [api, hasAccounts]);
|
||||
const items = useMemo(() => [
|
||||
{
|
||||
isRoot: true,
|
||||
@ -68,6 +70,13 @@ function StakingApp ({ basePath, className }: Props): React.ReactElement<Props>
|
||||
text: t('Validator stats')
|
||||
}
|
||||
], [t]);
|
||||
const hiddenTabs = useMemo((): string[] => {
|
||||
return hasAccounts
|
||||
? hasQueries
|
||||
? []
|
||||
: ['query']
|
||||
: ['actions', 'query'];
|
||||
}, [hasAccounts, hasQueries]);
|
||||
|
||||
useEffect((): void => {
|
||||
stakingOverview && setNext(
|
||||
@ -81,13 +90,7 @@ function StakingApp ({ basePath, className }: Props): React.ReactElement<Props>
|
||||
<header>
|
||||
<Tabs
|
||||
basePath={basePath}
|
||||
hidden={
|
||||
hasAccounts
|
||||
? hasQueries
|
||||
? []
|
||||
: ['query']
|
||||
: ['actions', 'query']
|
||||
}
|
||||
hidden={hiddenTabs}
|
||||
items={items}
|
||||
/>
|
||||
</header>
|
||||
|
||||
@ -29,7 +29,7 @@ interface Serialized {
|
||||
treasury: string;
|
||||
}
|
||||
|
||||
const MAX_BLOCKS = 2500;
|
||||
const MAX_BLOCKS = 250;
|
||||
|
||||
function fromJSON (sessions: Serialized[]): SessionRewards[] {
|
||||
let keepAll = false;
|
||||
|
||||
@ -31,7 +31,7 @@
|
||||
"homepage": "https://github.com/polkadot-js/ui/tree/master/packages/ui-reactive#readme",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.8.7",
|
||||
"@polkadot/api": "^1.6.0-beta.5",
|
||||
"@polkadot/api": "^1.6.0-beta.9",
|
||||
"@polkadot/extension-dapp": "^0.22.1",
|
||||
"rxjs-compat": "^6.5.4"
|
||||
}
|
||||
|
||||
@ -42,11 +42,11 @@ const alphaColor = (hexColor: string): string =>
|
||||
ChartJs.helpers.color(hexColor).alpha(0.65).rgbString();
|
||||
|
||||
function calculateOptions (colors: (string | undefined)[] = [], legends: string[], labels: string[], values: (number | BN)[][], jsonValues: string): State {
|
||||
const chartData = values.reduce((config, values, index): Config => {
|
||||
const chartData = values.reduce((chartData, values, index): Config => {
|
||||
const color = colors[index] || alphaColor(COLORS[index]);
|
||||
const data = values.map((value): number => BN.isBN(value) ? value.toNumber() : value);
|
||||
|
||||
config.datasets.push({
|
||||
chartData.datasets.push({
|
||||
data,
|
||||
fill: false,
|
||||
label: legends[index],
|
||||
@ -55,7 +55,7 @@ function calculateOptions (colors: (string | undefined)[] = [], legends: string[
|
||||
hoverBackgroundColor: color
|
||||
});
|
||||
|
||||
return config;
|
||||
return chartData;
|
||||
}, {
|
||||
labels,
|
||||
datasets: [] as Dataset[]
|
||||
|
||||
112
yarn.lock
112
yarn.lock
@ -2765,56 +2765,56 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@polkadot/api-contract@npm:^1.6.0-beta.5":
|
||||
version: 1.6.0-beta.5
|
||||
resolution: "@polkadot/api-contract@npm:1.6.0-beta.5"
|
||||
"@polkadot/api-contract@npm:^1.6.0-beta.9":
|
||||
version: 1.6.0-beta.9
|
||||
resolution: "@polkadot/api-contract@npm:1.6.0-beta.9"
|
||||
dependencies:
|
||||
"@babel/runtime": ^7.8.4
|
||||
"@polkadot/api": 1.6.0-beta.5
|
||||
"@polkadot/rpc-core": 1.6.0-beta.5
|
||||
"@polkadot/types": 1.6.0-beta.5
|
||||
"@polkadot/api": 1.6.0-beta.9
|
||||
"@polkadot/rpc-core": 1.6.0-beta.9
|
||||
"@polkadot/types": 1.6.0-beta.9
|
||||
"@polkadot/util": ^2.6.1
|
||||
bn.js: ^5.1.1
|
||||
rxjs: ^6.5.4
|
||||
checksum: 2/aa349fb472512755aaee16fc9ef7045e2d900c1bc5aeb8598c9baf489be2305161bd1581568b543a2b2fcd2c0ec5431206b242cc5f927cd2a2848a583509aaf9
|
||||
checksum: 2/a0fd7ab797bd736ba381de7df8ba30baa991f3ff319fb3c71e52cd34a1e9b8e4f83d65247e17c43636581825952815b3d85c40016db495c5a31b7c2005a2ab84
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@polkadot/api-derive@npm:1.6.0-beta.5":
|
||||
version: 1.6.0-beta.5
|
||||
resolution: "@polkadot/api-derive@npm:1.6.0-beta.5"
|
||||
"@polkadot/api-derive@npm:1.6.0-beta.9":
|
||||
version: 1.6.0-beta.9
|
||||
resolution: "@polkadot/api-derive@npm:1.6.0-beta.9"
|
||||
dependencies:
|
||||
"@babel/runtime": ^7.8.4
|
||||
"@polkadot/api": 1.6.0-beta.5
|
||||
"@polkadot/rpc-core": 1.6.0-beta.5
|
||||
"@polkadot/rpc-provider": 1.6.0-beta.5
|
||||
"@polkadot/types": 1.6.0-beta.5
|
||||
"@polkadot/api": 1.6.0-beta.9
|
||||
"@polkadot/rpc-core": 1.6.0-beta.9
|
||||
"@polkadot/rpc-provider": 1.6.0-beta.9
|
||||
"@polkadot/types": 1.6.0-beta.9
|
||||
"@polkadot/util": ^2.6.1
|
||||
"@polkadot/util-crypto": ^2.6.1
|
||||
bn.js: ^5.1.1
|
||||
memoizee: ^0.4.14
|
||||
rxjs: ^6.5.4
|
||||
checksum: 2/8a481dc392e28f453ae018507bd5c8b38a58ec6d355bcfb08470028aeb3b68fc30324e73247a13da733088822c8eba5900d78877a75e3222a93d3b5c53556d33
|
||||
checksum: 2/86de96be7ff53fc660ea058f2704abab510425dd0539378984f222e79e06d144a260b9d1564c3d436c94422697d9146d8ffab38e1761a7ae32a570662e3bfa0e
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@polkadot/api@npm:^1.6.0-beta.5":
|
||||
version: 1.6.0-beta.5
|
||||
resolution: "@polkadot/api@npm:1.6.0-beta.5"
|
||||
"@polkadot/api@npm:^1.6.0-beta.9":
|
||||
version: 1.6.0-beta.9
|
||||
resolution: "@polkadot/api@npm:1.6.0-beta.9"
|
||||
dependencies:
|
||||
"@babel/runtime": ^7.8.4
|
||||
"@polkadot/api-derive": 1.6.0-beta.5
|
||||
"@polkadot/api-derive": 1.6.0-beta.9
|
||||
"@polkadot/keyring": ^2.6.1
|
||||
"@polkadot/metadata": 1.6.0-beta.5
|
||||
"@polkadot/rpc-core": 1.6.0-beta.5
|
||||
"@polkadot/rpc-provider": 1.6.0-beta.5
|
||||
"@polkadot/types": 1.6.0-beta.5
|
||||
"@polkadot/metadata": 1.6.0-beta.9
|
||||
"@polkadot/rpc-core": 1.6.0-beta.9
|
||||
"@polkadot/rpc-provider": 1.6.0-beta.9
|
||||
"@polkadot/types": 1.6.0-beta.9
|
||||
"@polkadot/util": ^2.6.1
|
||||
"@polkadot/util-crypto": ^2.6.1
|
||||
bn.js: ^5.1.1
|
||||
eventemitter3: ^4.0.0
|
||||
rxjs: ^6.5.4
|
||||
checksum: 2/fe4c1a1b30c1c861e846bf328f57ff5180c1dceef464e21bb89d80ecdcb29b15833ddfd40874dc24eeee7579bc8b6b5f22b3b095f9d9a2bc75a99f99d85ff175
|
||||
checksum: 2/101414b97ac24417963bd11ea3095664101ecee87a6299beddadf51ff495ae32c7baf0c9cd78b8cc6c2b035f3b3921d1a1cb1826aa5b35a0a8474069ae9ebfaa
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -2864,7 +2864,7 @@ __metadata:
|
||||
resolution: "@polkadot/app-contracts@workspace:packages/page-contracts"
|
||||
dependencies:
|
||||
"@babel/runtime": ^7.8.7
|
||||
"@polkadot/api-contract": ^1.6.0-beta.5
|
||||
"@polkadot/api-contract": ^1.6.0-beta.9
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
@ -3176,14 +3176,14 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@polkadot/jsonrpc@npm:1.6.0-beta.5":
|
||||
version: 1.6.0-beta.5
|
||||
resolution: "@polkadot/jsonrpc@npm:1.6.0-beta.5"
|
||||
"@polkadot/jsonrpc@npm:1.6.0-beta.9":
|
||||
version: 1.6.0-beta.9
|
||||
resolution: "@polkadot/jsonrpc@npm:1.6.0-beta.9"
|
||||
dependencies:
|
||||
"@babel/runtime": ^7.8.4
|
||||
"@polkadot/types": 1.6.0-beta.5
|
||||
"@polkadot/types": 1.6.0-beta.9
|
||||
"@polkadot/util": ^2.6.1
|
||||
checksum: 2/9c43500d6c33f2115ed864a9c4f8a573e5229d5aae864525adbdecd6cfba172f7ce8ec106eef20cb765ba52b87c75da0cf58b689c56c863924d5f4df318c9d8e
|
||||
checksum: 2/ad2117f07fe6ba3d53dc59032ecba1a2b75746c4683e78e9f181111176af5b32eca8cf3e5b336e89a6cf8058536060b0c90beab50759eca96f3a21367927df25
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -3198,16 +3198,16 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@polkadot/metadata@npm:1.6.0-beta.5":
|
||||
version: 1.6.0-beta.5
|
||||
resolution: "@polkadot/metadata@npm:1.6.0-beta.5"
|
||||
"@polkadot/metadata@npm:1.6.0-beta.9":
|
||||
version: 1.6.0-beta.9
|
||||
resolution: "@polkadot/metadata@npm:1.6.0-beta.9"
|
||||
dependencies:
|
||||
"@babel/runtime": ^7.8.4
|
||||
"@polkadot/types": 1.6.0-beta.5
|
||||
"@polkadot/types": 1.6.0-beta.9
|
||||
"@polkadot/util": ^2.6.1
|
||||
"@polkadot/util-crypto": ^2.6.1
|
||||
bn.js: ^5.1.1
|
||||
checksum: 2/c51af8cbe2c509e6631913964e122cb7f5e1a94c754c098a94692fface0611af26e7c2b55f8de834ca1c07532a4ce64a7a151527ca8d5d06415fcadded6c1ebc
|
||||
checksum: 2/d711ea8ae5b484b43b5c837ccf92b676571461f039d521dfc4a57e6ae55e8fb1ee9fa93fcaa9b32b4a713da5ef75af764bb89a01856d4743a511699f10903678
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -3216,7 +3216,7 @@ __metadata:
|
||||
resolution: "@polkadot/react-api@workspace:packages/react-api"
|
||||
dependencies:
|
||||
"@babel/runtime": ^7.8.7
|
||||
"@polkadot/api": ^1.6.0-beta.5
|
||||
"@polkadot/api": ^1.6.0-beta.9
|
||||
"@polkadot/extension-dapp": ^0.22.1
|
||||
rxjs-compat: ^6.5.4
|
||||
languageName: unknown
|
||||
@ -3328,37 +3328,37 @@ __metadata:
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@polkadot/rpc-core@npm:1.6.0-beta.5":
|
||||
version: 1.6.0-beta.5
|
||||
resolution: "@polkadot/rpc-core@npm:1.6.0-beta.5"
|
||||
"@polkadot/rpc-core@npm:1.6.0-beta.9":
|
||||
version: 1.6.0-beta.9
|
||||
resolution: "@polkadot/rpc-core@npm:1.6.0-beta.9"
|
||||
dependencies:
|
||||
"@babel/runtime": ^7.8.4
|
||||
"@polkadot/jsonrpc": 1.6.0-beta.5
|
||||
"@polkadot/metadata": 1.6.0-beta.5
|
||||
"@polkadot/rpc-provider": 1.6.0-beta.5
|
||||
"@polkadot/types": 1.6.0-beta.5
|
||||
"@polkadot/jsonrpc": 1.6.0-beta.9
|
||||
"@polkadot/metadata": 1.6.0-beta.9
|
||||
"@polkadot/rpc-provider": 1.6.0-beta.9
|
||||
"@polkadot/types": 1.6.0-beta.9
|
||||
"@polkadot/util": ^2.6.1
|
||||
memoizee: ^0.4.14
|
||||
rxjs: ^6.5.4
|
||||
checksum: 2/966450e7d01d724139da72d1e01c2713d84f2f315886bbd0b392f481118aee2e74882e4fae1d3820e678ea19f3979997e26a60e88953dc5ad271020882299e56
|
||||
checksum: 2/a51f9a41eb779aee8706e3779bcd5aa594e253210da86da9515f74c4a25ab09b57cf391f5291c90724d1ac414de15d554786999644d1cb639c3aeac4c1cca6ea
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@polkadot/rpc-provider@npm:1.6.0-beta.5":
|
||||
version: 1.6.0-beta.5
|
||||
resolution: "@polkadot/rpc-provider@npm:1.6.0-beta.5"
|
||||
"@polkadot/rpc-provider@npm:1.6.0-beta.9":
|
||||
version: 1.6.0-beta.9
|
||||
resolution: "@polkadot/rpc-provider@npm:1.6.0-beta.9"
|
||||
dependencies:
|
||||
"@babel/runtime": ^7.8.4
|
||||
"@polkadot/jsonrpc": 1.6.0-beta.5
|
||||
"@polkadot/metadata": 1.6.0-beta.5
|
||||
"@polkadot/types": 1.6.0-beta.5
|
||||
"@polkadot/jsonrpc": 1.6.0-beta.9
|
||||
"@polkadot/metadata": 1.6.0-beta.9
|
||||
"@polkadot/types": 1.6.0-beta.9
|
||||
"@polkadot/util": ^2.6.1
|
||||
"@polkadot/util-crypto": ^2.6.1
|
||||
bn.js: ^5.1.1
|
||||
eventemitter3: ^4.0.0
|
||||
isomorphic-fetch: ^2.2.1
|
||||
websocket: ^1.0.31
|
||||
checksum: 2/4a6cc6a6c44191e852ff8ff95c2b395b80cba4ba9345cd506f976afa9e6e772f977d2a62486d66ac31a2df77d75c7401e73f7391f2731b0e5fb755d105fca871
|
||||
checksum: 2/12d670baa6bf60925024a7ffb5b41947e0318c0334fb6ae4e4e3eaa23c611579292014f6c973ff95639917ec9e5b6a4be39cff885b9686a1dc2fffeb6435b009
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -3371,19 +3371,19 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@polkadot/types@npm:^1.6.0-beta.5":
|
||||
version: 1.6.0-beta.5
|
||||
resolution: "@polkadot/types@npm:1.6.0-beta.5"
|
||||
"@polkadot/types@npm:^1.6.0-beta.9":
|
||||
version: 1.6.0-beta.9
|
||||
resolution: "@polkadot/types@npm:1.6.0-beta.9"
|
||||
dependencies:
|
||||
"@babel/runtime": ^7.8.4
|
||||
"@polkadot/metadata": 1.6.0-beta.5
|
||||
"@polkadot/metadata": 1.6.0-beta.9
|
||||
"@polkadot/util": ^2.6.1
|
||||
"@polkadot/util-crypto": ^2.6.1
|
||||
"@types/bn.js": ^4.11.6
|
||||
bn.js: ^5.1.1
|
||||
memoizee: ^0.4.14
|
||||
rxjs: ^6.5.4
|
||||
checksum: 2/99fbf723afe86772c4d61ef1793ef874334979f9653a5c7ef0b8270f70d73dcd9dfdcd95c9884a2130a26a6d696dccdb96da39cbe4a959ed89decb8ebd1c90b7
|
||||
checksum: 2/2adecefd6479d673ad6e731757094d13cd20c1867d254348c5c7ee2a1198caa37fbc32d867816c47371031dbe11277b15ff1b62b9e8e1a5b3e4adc3c9aaaf8d7
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user