Format stakingBalance as votingBalance + nominatingBalance (#204)
* Format stakingBalance as votingBalance + nominatingBalance * Fix version number change (revert) * Bump api 0.15.x: rxjs 6 & class-ified providers * API bump * Type cleanup * Update version of packages * RxJs 6 style Observable imports * Remove ZERO const
This commit is contained in:
parent
ab26caa399
commit
fb9c0f7f0b
@ -11,6 +11,7 @@
|
||||
],
|
||||
"resolutions": {
|
||||
"babel-core": "^7.0.0-bridge.0",
|
||||
"rxjs": "^6.2.2",
|
||||
"typescript": "^2.9.2"
|
||||
},
|
||||
"scripts": {
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
import { Header } from '@polkadot/primitives/header';
|
||||
import { I18nProps } from '@polkadot/ui-app/types';
|
||||
import { ApiProps } from '@polkadot/ui-react-rx/types';
|
||||
import { Balance, BalanceMap } from './observables/types';
|
||||
|
||||
import BN from 'bn.js';
|
||||
import React from 'react';
|
||||
@ -14,7 +15,9 @@ import classes from '@polkadot/ui-app/util/classes';
|
||||
import withApiCall from '@polkadot/ui-react-rx/with/apiCall';
|
||||
import withMulti from '@polkadot/ui-react-rx/with/multi';
|
||||
import withStorage from '@polkadot/ui-react-rx/with/storage';
|
||||
import numberFormat from '@polkadot/ui-react-rx/util/numberFormat';
|
||||
|
||||
import validatingBalances from './observables/validatingBalances';
|
||||
import translate from './translate';
|
||||
|
||||
type Props = ApiProps & I18nProps & {
|
||||
@ -25,16 +28,11 @@ type Props = ApiProps & I18nProps & {
|
||||
validators: Array<string>
|
||||
};
|
||||
|
||||
type StateBalances = {
|
||||
[index: string]: BN
|
||||
};
|
||||
|
||||
type State = {
|
||||
balances: StateBalances,
|
||||
subscriptions: Array<any>
|
||||
balances: BalanceMap,
|
||||
subBalances: any
|
||||
};
|
||||
|
||||
const DEFAULT_BALANCE = new BN(0);
|
||||
const DEFAULT_BLOCKNUMBER = new BN(0);
|
||||
const DEFAULT_SESSION_CHANGE = new BN(0);
|
||||
const DEFAULT_SESSION_LENGTH = new BN(60);
|
||||
@ -45,7 +43,7 @@ class Summary extends React.PureComponent<Props, State> {
|
||||
|
||||
this.state = {
|
||||
balances: {},
|
||||
subscriptions: []
|
||||
subBalances: null
|
||||
};
|
||||
}
|
||||
|
||||
@ -57,46 +55,31 @@ class Summary extends React.PureComponent<Props, State> {
|
||||
}
|
||||
}
|
||||
|
||||
private subscribeBalances (accounts: string[]) {
|
||||
private unsubscribeBalances () {
|
||||
const { subBalances } = this.state;
|
||||
|
||||
if (subBalances) {
|
||||
subBalances.unsubscribe();
|
||||
}
|
||||
}
|
||||
|
||||
private subscribeBalances (accounts: string[] = []) {
|
||||
const { api } = this.props;
|
||||
const { balances, subscriptions } = this.state;
|
||||
const newBalances = { ...balances };
|
||||
|
||||
accounts.forEach((account) => {
|
||||
if (newBalances[account]) {
|
||||
return;
|
||||
} else {
|
||||
newBalances[account] = DEFAULT_BALANCE;
|
||||
}
|
||||
this.unsubscribeBalances();
|
||||
|
||||
subscriptions.push(
|
||||
api.state
|
||||
// Here we pass a parameter to the key generator, so it points to the correct storage entry
|
||||
.getStorage(storage.staking.public.freeBalanceOf, account)
|
||||
.subscribe((balance: BN) => {
|
||||
this.setState(({ balances }: State) => {
|
||||
const newBalances = { ...balances };
|
||||
|
||||
newBalances[account] = balance;
|
||||
|
||||
return {
|
||||
balances: newBalances
|
||||
} as State;
|
||||
});
|
||||
})
|
||||
);
|
||||
// FIXME: We want these as a HOC on the class
|
||||
const subBalances = validatingBalances(api, accounts).subscribe((balances: BalanceMap) => {
|
||||
this.setState({ balances });
|
||||
});
|
||||
|
||||
this.setState({
|
||||
balances: newBalances,
|
||||
subscriptions
|
||||
subBalances
|
||||
} as State);
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
const { subscriptions } = this.state;
|
||||
|
||||
subscriptions.forEach((sub) => sub.unsubscribe());
|
||||
this.unsubscribeBalances();
|
||||
}
|
||||
|
||||
render () {
|
||||
@ -122,19 +105,23 @@ class Summary extends React.PureComponent<Props, State> {
|
||||
<div>{t('summary.balance.validator', {
|
||||
defaultValue: 'lowest validator balance is {{validatorLow}}',
|
||||
replace: {
|
||||
validatorLow: validatorLow ? validatorLow.toString() : 'unknown'
|
||||
validatorLow: validatorLow && validatorLow.stakingBalance
|
||||
? `${numberFormat(validatorLow.stakingBalance)} (+${numberFormat(validatorLow.nominatedBalance)})`
|
||||
: 'unknown'
|
||||
}
|
||||
})}</div>
|
||||
<div>{t('summary.balance.stake', {
|
||||
defaultValue: ' highest balance intending to stake is {{intentionHigh}}',
|
||||
replace: {
|
||||
intentionHigh: intentionHigh ? intentionHigh.toString() : 'unknown'
|
||||
intentionHigh: intentionHigh
|
||||
? `${numberFormat(intentionHigh.stakingBalance)} (+${numberFormat(intentionHigh.nominatedBalance)})`
|
||||
: 'unknown'
|
||||
}
|
||||
})}</div>
|
||||
<div>{t('summary.countdown', {
|
||||
defaultValue: 'session block {{remainder}} / {{length}} at #{{blockNumber}}',
|
||||
replace: {
|
||||
blockNumber: blockNumber.toString(),
|
||||
blockNumber: numberFormat(blockNumber),
|
||||
remainder: Math.max(1, blockNumber.sub(lastLengthChange).mod(sessionLength).addn(1).toNumber()).toString(),
|
||||
length: sessionLength.toString()
|
||||
}
|
||||
@ -143,16 +130,16 @@ class Summary extends React.PureComponent<Props, State> {
|
||||
);
|
||||
}
|
||||
|
||||
private calcIntentionsHigh (): BN | null {
|
||||
private calcIntentionsHigh (): Balance | null {
|
||||
const { intentions, validators } = this.props;
|
||||
const { balances } = this.state;
|
||||
|
||||
return intentions.reduce((high: BN | null, addr) => {
|
||||
const balance = validators.includes(addr)
|
||||
return intentions.reduce((high: Balance | null, addr) => {
|
||||
const balance = validators.includes(addr) || !balances[addr]
|
||||
? null
|
||||
: balances[addr] || null;
|
||||
: balances[addr];
|
||||
|
||||
if (high === null || (balance && high.lt(balance))) {
|
||||
if (high === null || (balance && high.stakingBalance.lt(balance.stakingBalance))) {
|
||||
return balance;
|
||||
}
|
||||
|
||||
@ -160,14 +147,14 @@ class Summary extends React.PureComponent<Props, State> {
|
||||
}, null);
|
||||
}
|
||||
|
||||
private calcValidatorLow (): BN | null {
|
||||
private calcValidatorLow (): Balance | null {
|
||||
const { validators } = this.props;
|
||||
const { balances } = this.state;
|
||||
|
||||
return validators.reduce((low: BN | null, addr) => {
|
||||
return validators.reduce((low: Balance | null, addr) => {
|
||||
const balance = balances[addr] || null;
|
||||
|
||||
if (low === null || (balance && low.gt(balance))) {
|
||||
if (low === null || (balance && low.stakingBalance.gt(balance.stakingBalance))) {
|
||||
return balance;
|
||||
}
|
||||
|
||||
|
||||
19
packages/app-staking/src/observables/types.d.ts
vendored
Normal file
19
packages/app-staking/src/observables/types.d.ts
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
// Copyright 2017-2018 @polkadot/app-staking authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the ISC license. See the LICENSE file for details.
|
||||
|
||||
import BN from 'bn.js';
|
||||
|
||||
export type Balance = {
|
||||
address: string,
|
||||
freeBalance: BN,
|
||||
nominatedBalance: BN,
|
||||
reservedBalance: BN,
|
||||
votingBalance: BN,
|
||||
stakingBalance: BN,
|
||||
nominators?: Array<Balance>
|
||||
}
|
||||
|
||||
export type BalanceMap = {
|
||||
[index: string]: Balance
|
||||
}
|
||||
45
packages/app-staking/src/observables/validatingBalance.ts
Normal file
45
packages/app-staking/src/observables/validatingBalance.ts
Normal file
@ -0,0 +1,45 @@
|
||||
// Copyright 2017-2018 @polkadot/app-staking authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the ISC license. See the LICENSE file for details.
|
||||
|
||||
import { RxApiInterface } from '@polkadot/api-rx/types';
|
||||
import { Balance } from './types';
|
||||
|
||||
import BN from 'bn.js';
|
||||
import { Observable, combineLatest } from 'rxjs';
|
||||
import { map, switchMap, toArray } from 'rxjs/operators';
|
||||
import storage from '@polkadot/storage';
|
||||
import encodeAddress from '@polkadot/util-keyring/address/encode';
|
||||
|
||||
import votingBalance from './votingBalance';
|
||||
import votingBalances from './/votingBalances';
|
||||
|
||||
type Result = [Balance, [Array<Balance>]];
|
||||
|
||||
export default function validatingBalance (api: RxApiInterface, address: string): Observable<Balance> {
|
||||
return combineLatest(
|
||||
votingBalance(api, address),
|
||||
api.state
|
||||
.getStorage(storage.staking.public.nominatorsFor, address)
|
||||
.pipe(
|
||||
switchMap((nominators = []) =>
|
||||
// FIXME: Will not be needed after https://github.com/polkadot-js/apps/issues/128
|
||||
votingBalances(api, nominators.map(encodeAddress))
|
||||
),
|
||||
toArray()
|
||||
)
|
||||
).pipe(
|
||||
map(([balance, [nominators = []]]: Result): Balance => {
|
||||
const nominatedBalance = nominators.reduce((total, nominator: Balance) => {
|
||||
return total.add(nominator.votingBalance);
|
||||
}, new BN(0));
|
||||
|
||||
return {
|
||||
...balance,
|
||||
nominators,
|
||||
nominatedBalance,
|
||||
stakingBalance: nominatedBalance.add(balance.votingBalance)
|
||||
};
|
||||
})
|
||||
);
|
||||
}
|
||||
27
packages/app-staking/src/observables/validatingBalances.ts
Normal file
27
packages/app-staking/src/observables/validatingBalances.ts
Normal file
@ -0,0 +1,27 @@
|
||||
// Copyright 2017-2018 @polkadot/app-staking authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the ISC license. See the LICENSE file for details.
|
||||
|
||||
import { RxApiInterface } from '@polkadot/api-rx/types';
|
||||
import { Balance, BalanceMap } from './types';
|
||||
|
||||
import { Observable, combineLatest } from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
|
||||
import validatingBalance from './validatingBalance';
|
||||
|
||||
export default function validatingBalances (api: RxApiInterface, addresses: Array<string>): Observable<BalanceMap> {
|
||||
return combineLatest(
|
||||
addresses.map((address) =>
|
||||
validatingBalance(api, address)
|
||||
)
|
||||
).pipe(
|
||||
map((result: Array<Balance>): BalanceMap => {
|
||||
return result.reduce((balances, balance) => {
|
||||
balances[balance.address] = balance;
|
||||
|
||||
return balances;
|
||||
}, {} as BalanceMap);
|
||||
})
|
||||
);
|
||||
}
|
||||
27
packages/app-staking/src/observables/votingBalance.ts
Normal file
27
packages/app-staking/src/observables/votingBalance.ts
Normal file
@ -0,0 +1,27 @@
|
||||
// Copyright 2017-2018 @polkadot/app-staking authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the ISC license. See the LICENSE file for details.
|
||||
|
||||
import { RxApiInterface } from '@polkadot/api-rx/types';
|
||||
import { Balance } from './types';
|
||||
|
||||
import BN from 'bn.js';
|
||||
import { Observable, combineLatest } from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
import storage from '@polkadot/storage';
|
||||
|
||||
export default function votingBalance (api: RxApiInterface, address: string): Observable<Balance> {
|
||||
return combineLatest(
|
||||
api.state.getStorage(storage.staking.public.freeBalanceOf, address),
|
||||
api.state.getStorage(storage.staking.public.reservedBalanceOf, address)
|
||||
).pipe(
|
||||
map(([freeBalance = new BN(0), reservedBalance = new BN(0)]): Balance => ({
|
||||
address,
|
||||
freeBalance,
|
||||
nominatedBalance: new BN(0),
|
||||
reservedBalance,
|
||||
stakingBalance: new BN(0),
|
||||
votingBalance: freeBalance.add(reservedBalance)
|
||||
}))
|
||||
);
|
||||
}
|
||||
18
packages/app-staking/src/observables/votingBalances.ts
Normal file
18
packages/app-staking/src/observables/votingBalances.ts
Normal file
@ -0,0 +1,18 @@
|
||||
// Copyright 2017-2018 @polkadot/app-staking authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the ISC license. See the LICENSE file for details.
|
||||
|
||||
import { RxApiInterface } from '@polkadot/api-rx/types';
|
||||
import { Balance } from './types';
|
||||
|
||||
import { Observable, combineLatest } from 'rxjs';
|
||||
|
||||
import votingBalance from './votingBalance';
|
||||
|
||||
export default function votingBalances (api: RxApiInterface, addresses: Array<string>): Observable<Balance[]> {
|
||||
return combineLatest(
|
||||
addresses.map((address) =>
|
||||
votingBalance(api, address)
|
||||
)
|
||||
);
|
||||
}
|
||||
@ -36,9 +36,10 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.0.0-beta.51",
|
||||
"@polkadot/api-rx": "^0.14.29",
|
||||
"@polkadot/api-rx": "^0.15.6",
|
||||
"@polkadot/extrinsics": "^0.27.9",
|
||||
"@polkadot/storage": "^0.27.9"
|
||||
"@polkadot/storage": "^0.27.9",
|
||||
"rxjs-compat": "^6.2.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-loader": "^8.0.0-beta.2",
|
||||
|
||||
@ -10,7 +10,7 @@ import { ApiProps } from '../types';
|
||||
import React from 'react';
|
||||
|
||||
import shouldUseLatestChain from '@polkadot/ui-react-rx/util/shouldUseLatestChain';
|
||||
import createWsProvider from '@polkadot/api-provider/ws';
|
||||
import WsProvider from '@polkadot/api-provider/ws';
|
||||
import createApi from '@polkadot/api-rx';
|
||||
import defaults from '@polkadot/api-rx/defaults';
|
||||
|
||||
@ -40,7 +40,7 @@ export default class Api extends React.PureComponent<Props, State> {
|
||||
const { provider, url = '' } = props;
|
||||
const api = props.api || createApi(
|
||||
url && url.length
|
||||
? createWsProvider(url)
|
||||
? new WsProvider(url)
|
||||
: provider
|
||||
);
|
||||
const setApi = (api: RxApiInterface): void => {
|
||||
@ -51,7 +51,7 @@ export default class Api extends React.PureComponent<Props, State> {
|
||||
const setApiProvider = (provider?: ProviderInterface): void =>
|
||||
setApi(createApi(provider));
|
||||
const setApiWsUrl = (url: string = defaults.WS_URL): void =>
|
||||
setApiProvider(createWsProvider(url));
|
||||
setApiProvider(new WsProvider(url));
|
||||
|
||||
this.state = {
|
||||
api,
|
||||
|
||||
52
yarn.lock
52
yarn.lock
@ -765,9 +765,9 @@
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-1.1.0.tgz#50c1e2260ac0ed9439a181de3725a0168d59c48a"
|
||||
|
||||
"@polkadot/api-format@^0.14.29":
|
||||
version "0.14.29"
|
||||
resolved "https://registry.yarnpkg.com/@polkadot/api-format/-/api-format-0.14.29.tgz#02b1cc84d19219909d4dc82ab9ecd57f07aa888c"
|
||||
"@polkadot/api-format@^0.15.6":
|
||||
version "0.15.6"
|
||||
resolved "https://registry.yarnpkg.com/@polkadot/api-format/-/api-format-0.15.6.tgz#9d50258df3fcd9e11ad591d43a3f25db3647ff7a"
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.0.0-beta.51"
|
||||
"@polkadot/jsonrpc" "^0.27.9"
|
||||
@ -775,9 +775,9 @@
|
||||
"@polkadot/util" "^0.27.9"
|
||||
"@polkadot/util-keyring" "^0.27.9"
|
||||
|
||||
"@polkadot/api-provider@^0.14.29":
|
||||
version "0.14.29"
|
||||
resolved "https://registry.yarnpkg.com/@polkadot/api-provider/-/api-provider-0.14.29.tgz#d1bb7e8e879e62f868e0149e25a55995e600536e"
|
||||
"@polkadot/api-provider@^0.15.6":
|
||||
version "0.15.6"
|
||||
resolved "https://registry.yarnpkg.com/@polkadot/api-provider/-/api-provider-0.15.6.tgz#e3c664687d9d82d59d16e9b5a8e3d10fd285a7a0"
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.0.0-beta.51"
|
||||
"@polkadot/storage" "^0.27.9"
|
||||
@ -789,23 +789,23 @@
|
||||
isomorphic-fetch "^2.2.1"
|
||||
websocket "^1.0.25"
|
||||
|
||||
"@polkadot/api-rx@^0.14.29":
|
||||
version "0.14.29"
|
||||
resolved "https://registry.yarnpkg.com/@polkadot/api-rx/-/api-rx-0.14.29.tgz#e71c3b2dec8dd0e7cbc391024bd17b9616c8b453"
|
||||
"@polkadot/api-rx@^0.15.6":
|
||||
version "0.15.6"
|
||||
resolved "https://registry.yarnpkg.com/@polkadot/api-rx/-/api-rx-0.15.6.tgz#849adc73d129d87eaf3c9463f9eb7201b8d6bfa7"
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.0.0-beta.51"
|
||||
"@polkadot/api" "^0.14.29"
|
||||
"@polkadot/api-provider" "^0.14.29"
|
||||
"@polkadot/api" "^0.15.6"
|
||||
"@polkadot/api-provider" "^0.15.6"
|
||||
"@types/rx" "^4.1.1"
|
||||
rxjs "^5.5.10"
|
||||
rxjs "^6.2.2"
|
||||
|
||||
"@polkadot/api@^0.14.29":
|
||||
version "0.14.29"
|
||||
resolved "https://registry.yarnpkg.com/@polkadot/api/-/api-0.14.29.tgz#6a3f08ee1bd98e5ee96d85361f195496ebab65b7"
|
||||
"@polkadot/api@^0.15.6":
|
||||
version "0.15.6"
|
||||
resolved "https://registry.yarnpkg.com/@polkadot/api/-/api-0.15.6.tgz#6bf02708c5ef77d71ca0b00bdbbf6154abe80f6f"
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.0.0-beta.51"
|
||||
"@polkadot/api-format" "^0.14.29"
|
||||
"@polkadot/api-provider" "^0.14.29"
|
||||
"@polkadot/api-format" "^0.15.6"
|
||||
"@polkadot/api-provider" "^0.15.6"
|
||||
"@polkadot/jsonrpc" "^0.27.9"
|
||||
"@polkadot/params" "^0.27.9"
|
||||
"@polkadot/util" "^0.27.9"
|
||||
@ -9865,15 +9865,13 @@ rx-lite@*, rx-lite@^4.0.8:
|
||||
version "4.0.8"
|
||||
resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-4.0.8.tgz#0b1e11af8bc44836f04a6407e92da42467b79444"
|
||||
|
||||
rxjs@^5.5.10, rxjs@^5.5.2:
|
||||
version "5.5.11"
|
||||
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-5.5.11.tgz#f733027ca43e3bec6b994473be4ab98ad43ced87"
|
||||
dependencies:
|
||||
symbol-observable "1.0.1"
|
||||
rxjs-compat@^6.2.2:
|
||||
version "6.2.2"
|
||||
resolved "https://registry.yarnpkg.com/rxjs-compat/-/rxjs-compat-6.2.2.tgz#3c0fcdb46130cc70aa55412c2b1147905ab4680a"
|
||||
|
||||
rxjs@^6.1.0:
|
||||
version "6.2.1"
|
||||
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.2.1.tgz#246cebec189a6cbc143a3ef9f62d6f4c91813ca1"
|
||||
rxjs@^5.5.2, rxjs@^6.1.0, rxjs@^6.2.2:
|
||||
version "6.2.2"
|
||||
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.2.2.tgz#eb75fa3c186ff5289907d06483a77884586e1cf9"
|
||||
dependencies:
|
||||
tslib "^1.9.0"
|
||||
|
||||
@ -10521,10 +10519,6 @@ svgo@^0.7.0:
|
||||
sax "~1.2.1"
|
||||
whet.extend "~0.9.9"
|
||||
|
||||
symbol-observable@1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.0.1.tgz#8340fc4702c3122df5d22288f88283f513d3fdd4"
|
||||
|
||||
symbol-observable@1.0.4:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.0.4.tgz#29bf615d4aa7121bdd898b22d4b3f9bc4e2aa03d"
|
||||
|
||||
Loading…
Reference in New Issue
Block a user