Add ability to stake (#844)

This commit is contained in:
Jaco Greeff 2019-03-26 11:57:08 +01:00 committed by GitHub
parent b45f1a1ea9
commit 5a50b9ba97
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 103 additions and 47 deletions

View File

@ -7,7 +7,7 @@ import { I18nProps } from '@polkadot/ui-app/types';
import BN from 'bn.js';
import React from 'react';
import { ValidatorPrefs } from '@polkadot/types';
import { Button, InputBalance, InputNumber, Modal } from '@polkadot/ui-app';
import { Button, InputAddress, InputBalance, InputNumber, Modal, TxButton } from '@polkadot/ui-app';
import translate from '../translate';
@ -15,8 +15,7 @@ type Props = I18nProps & {
accountId: string,
isOpen: boolean,
onClose: () => void,
onSetPrefs: (prefs: ValidatorPrefs) => void,
validatorPreferences?: ValidatorPrefs
preferences: ValidatorPrefs
};
type State = {
@ -24,17 +23,17 @@ type State = {
validatorPayment?: BN
};
class Preferences extends React.PureComponent<Props, State> {
class Staking extends React.PureComponent<Props, State> {
state: State = {};
// inject the preferences are returned via RPC once into the state (from this
// point forward it will be entirely managed by the actual inputs)
static getDerivedStateFromProps (props: Props, state: State): State | null {
if (state.unstakeThreshold || !props.validatorPreferences) {
if (state.unstakeThreshold) {
return null;
}
const { unstakeThreshold, validatorPayment } = props.validatorPreferences;
const { unstakeThreshold, validatorPayment } = props.preferences;
return {
unstakeThreshold: unstakeThreshold.toBn(),
@ -51,7 +50,7 @@ class Preferences extends React.PureComponent<Props, State> {
return (
<Modal
className='staking--Preferences'
className='staking--Staking'
dimmer='inverted'
open
size='small'
@ -63,21 +62,28 @@ class Preferences extends React.PureComponent<Props, State> {
}
private renderButtons () {
const { onClose, t } = this.props;
const { accountId, onClose, t } = this.props;
const { unstakeThreshold, validatorPayment } = this.state;
return (
<Modal.Actions>
<Button.Group>
<Button
isNegative
onClick={onClose}
label={t('Cancel')}
onClick={onClose}
/>
<Button.Or />
<Button
<TxButton
accountId={accountId}
isPrimary
onClick={this.setPrefs}
label={t('Set Prefs')}
label={t('Stake')}
onClick={onClose}
params={[{
unstakeThreshold,
validatorPayment
}]}
tx='staking.validate'
/>
</Button.Group>
</Modal.Actions>
@ -85,15 +91,21 @@ class Preferences extends React.PureComponent<Props, State> {
}
private renderContent () {
const { t } = this.props;
const { accountId, t } = this.props;
const { unstakeThreshold, validatorPayment } = this.state;
return (
<>
<Modal.Header>
{t('Validator Preferences')}
{t('Staking')}
</Modal.Header>
<Modal.Content className='ui--signer-Signer-Content'>
<InputAddress
className='medium'
isDisabled
label={t('account')}
value={accountId}
/>
<InputNumber
autoFocus
bitLength={32}
@ -132,16 +144,6 @@ class Preferences extends React.PureComponent<Props, State> {
this.setState({ unstakeThreshold });
}
}
private setPrefs = () => {
const { onSetPrefs } = this.props;
const { unstakeThreshold, validatorPayment } = this.state;
onSetPrefs(new ValidatorPrefs({
unstakeThreshold,
validatorPayment
}));
}
}
export default translate(Preferences);
export default translate(Staking);

View File

@ -14,8 +14,8 @@ import { withCalls } from '@polkadot/ui-api';
import Bonding from './Bonding';
import Controller from './Controller';
import Staking from './Staking';
// import Nominating from './Nominating';
// import Preferences from './Preferences';
// import UnnominateButton from './UnnominateButton';
import translate from '../translate';
@ -25,9 +25,10 @@ type Props = ApiProps & I18nProps & {
balanceArray: (_address: AccountId | string) => Array<Balance> | undefined,
name: string,
session_nextKeyFor?: Option<AccountId>,
staking_bonded?: Option<AccountId>,
staking_nominating?: Option<AccountId>,
staking_nominatorsFor?: Array<string>,
staking_validatorPreferences?: ValidatorPrefs,
staking_validators?: ValidatorPrefs,
intentions: Array<string>,
isValidator: boolean,
queueExtrinsic: QueueTx$ExtrinsicAdd
@ -36,19 +37,31 @@ type Props = ApiProps & I18nProps & {
type State = {
isBondingOpen: boolean,
isControllerOpen: boolean,
nominee: AccountId | null
isStakingOpen: boolean,
bondedId: AccountId | null,
controllerId: AccountId | null,
nomineeId: AccountId | null
};
class Account extends React.PureComponent<Props, State> {
state: State = {
isBondingOpen: false,
isControllerOpen: false,
nominee: null
isStakingOpen: false,
bondedId: null,
controllerId: null,
nomineeId: null
};
static getDerivedStateFromProps ({ staking_nominating }: Props): Partial<State> {
static getDerivedStateFromProps ({ session_nextKeyFor, staking_bonded, staking_nominating }: Props): Partial<State> {
return {
nominee: staking_nominating
bondedId: staking_bonded
? staking_bonded.unwrapOr(null)
: null,
controllerId: session_nextKeyFor
? session_nextKeyFor.unwrapOr(null)
: null,
nomineeId: staking_nominating
? staking_nominating.unwrapOr(null)
: null
};
@ -61,6 +74,7 @@ class Account extends React.PureComponent<Props, State> {
<article className='staking--Account'>
{this.renderBonding()}
{this.renderController()}
{this.renderStaking()}
<AddressSummary
balance={balanceArray(accountId)}
name={name}
@ -78,17 +92,17 @@ class Account extends React.PureComponent<Props, State> {
}
private renderBonding () {
const { accountId, session_nextKeyFor } = this.props;
const { isBondingOpen } = this.state;
const { accountId } = this.props;
const { controllerId, isBondingOpen } = this.state;
if (!session_nextKeyFor || session_nextKeyFor.isNone) {
if (!controllerId) {
return null;
}
return (
<Bonding
accountId={accountId}
controllerId={session_nextKeyFor.unwrap()}
controllerId={controllerId}
isOpen={isBondingOpen}
onClose={this.toggleBonding}
/>
@ -96,11 +110,8 @@ class Account extends React.PureComponent<Props, State> {
}
private renderController () {
const { accountId, session_nextKeyFor } = this.props;
const { isControllerOpen } = this.state;
const controllerId = session_nextKeyFor
? session_nextKeyFor.unwrapOr(null)
: null;
const { accountId } = this.props;
const { controllerId, isControllerOpen } = this.state;
return (
<Controller
@ -112,18 +123,36 @@ class Account extends React.PureComponent<Props, State> {
);
}
private renderStaking () {
const { accountId, staking_validators } = this.props;
const { isStakingOpen } = this.state;
if (!staking_validators || !isStakingOpen) {
return null;
}
return (
<Staking
accountId={accountId}
isOpen
onClose={this.toggleStaking}
preferences={staking_validators}
/>
);
}
private renderNominee () {
const { balanceArray } = this.props;
const { nominee } = this.state;
const { nomineeId } = this.state;
if (!nominee) {
if (!nomineeId) {
return null;
}
return (
<AddressMini
balance={balanceArray(nominee)}
value={nominee}
balance={balanceArray(nomineeId)}
value={nomineeId}
withBalance
/>
);
@ -180,7 +209,8 @@ class Account extends React.PureComponent<Props, State> {
// }
private renderButtons () {
const { session_nextKeyFor, t } = this.props;
const { t } = this.props;
const { bondedId, controllerId } = this.state;
const buttons = [
<Button
isPrimary
@ -190,7 +220,8 @@ class Account extends React.PureComponent<Props, State> {
/>
];
if (session_nextKeyFor && session_nextKeyFor.isSome) {
// only display bonmding if we already have a controller
if (controllerId) {
buttons.push(<Button.Or key='bond.or' />);
buttons.push(
<Button
@ -202,6 +233,19 @@ class Account extends React.PureComponent<Props, State> {
);
}
// only stake/nominate if we already have bonded
if (bondedId) {
buttons.push(<Button.Or key='stake.or' />);
buttons.push(
<Button
isPrimary
key='stake'
onClick={this.toggleStaking}
label={t('Stake')}
/>
);
}
return (
<Button.Group>
{buttons}
@ -262,6 +306,12 @@ class Account extends React.PureComponent<Props, State> {
}));
}
private toggleStaking = () => {
this.setState(({ isStakingOpen }) => ({
isStakingOpen: !isStakingOpen
}));
}
// private toggleNominate = () => {
// this.setState(({ isNominateOpen }: State) => ({
// isNominateOpen: !isNominateOpen
@ -278,8 +328,9 @@ class Account extends React.PureComponent<Props, State> {
export default translate(
withCalls<Props>(
['query.session.nextKeyFor', { paramName: 'accountId' }],
['query.staking.bonded', { paramName: 'accountId' }],
['query.staking.nominatorsFor', { paramName: 'accountId' }],
['query.staking.nominating', { paramName: 'accountId' }],
['query.staking.validatorPreferences', { paramName: 'accountId' }]
['query.staking.validators', { paramName: 'accountId' }]
)(Account)
);

View File

@ -44,6 +44,9 @@ class TxButtonInner extends React.PureComponent<Props & InjectedProps> {
private send = (): void => {
const { accountId, api, onClick, onFailed, onSuccess, onUpdate, params, queueExtrinsic, tx } = this.props;
assert(tx, 'Expected tx param passed to TxButton');
const [section, method] = tx.split('.');
assert(api.tx[section] && api.tx[section][method], `Unable to find api.tx.${section}.${method}`);