diff --git a/packages/app-staking/src/Account/Bond.tsx b/packages/app-staking/src/Account/Bond.tsx index ce5912277f..1c2a95f89a 100644 --- a/packages/app-staking/src/Account/Bond.tsx +++ b/packages/app-staking/src/Account/Bond.tsx @@ -6,7 +6,6 @@ import { I18nProps } from '@polkadot/ui-app/types'; import BN from 'bn.js'; import React from 'react'; -import { AccountId } from '@polkadot/types'; import { Button, InputAddress, InputBalance, Modal, TxButton, Dropdown } from '@polkadot/ui-app'; import translate from '../translate'; @@ -14,7 +13,7 @@ import ValidateController from './ValidateController'; type Props = I18nProps & { accountId: string, - controllerId?: AccountId | null, + controllerId?: string | null, isOpen: boolean, onClose: () => void }; diff --git a/packages/app-staking/src/Account/Nominating.tsx b/packages/app-staking/src/Account/Nominating.tsx index 0fd2fef4cf..2a70f20a31 100644 --- a/packages/app-staking/src/Account/Nominating.tsx +++ b/packages/app-staking/src/Account/Nominating.tsx @@ -6,7 +6,6 @@ import { I18nProps } from '@polkadot/ui-app/types'; import { KeyringSectionOption } from '@polkadot/ui-keyring/options/types'; import React from 'react'; -import { AccountId } from '@polkadot/types'; import { Button, InputAddress, Modal, TxButton } from '@polkadot/ui-app'; import translate from '../translate'; @@ -15,7 +14,7 @@ type Props = I18nProps & { accountId: string, isOpen: boolean, onClose: () => void, - stashId: AccountId, + stashId: string, stashOptions: Array }; diff --git a/packages/app-staking/src/Account/SessionKey.tsx b/packages/app-staking/src/Account/SessionKey.tsx index 5328fad699..37751f319c 100644 --- a/packages/app-staking/src/Account/SessionKey.tsx +++ b/packages/app-staking/src/Account/SessionKey.tsx @@ -7,15 +7,18 @@ import { I18nProps } from '@polkadot/ui-app/types'; import React from 'react'; import { Button, InputAddress, Modal, TxButton } from '@polkadot/ui-app'; +import ValidateSession from './ValidateSession'; import translate from '../translate'; type Props = I18nProps & { accountId: string, isOpen: boolean, - onClose: () => void + onClose: () => void, + stashId: string }; type State = { + sessionError: string | null, sessionId: string }; @@ -26,13 +29,14 @@ class Key extends React.PureComponent { super(props); this.state = { + sessionError: null, sessionId: props.accountId }; } render () { const { accountId, isOpen, onClose, t } = this.props; - const { sessionId } = this.state; + const { sessionError, sessionId } = this.state; if (!isOpen) { return null; @@ -56,7 +60,7 @@ class Key extends React.PureComponent { { } private renderContent () { - const { accountId, t } = this.props; + const { accountId, stashId, t } = this.props; const { sessionId } = this.state; return ( @@ -93,6 +97,12 @@ class Key extends React.PureComponent { value={sessionId} type='account' /> + ); @@ -101,6 +111,10 @@ class Key extends React.PureComponent { private onChangeSession = (sessionId: string) => { this.setState({ sessionId }); } + + private onSessionError = (sessionError: string | null) => { + this.setState({ sessionError }); + } } export default translate(Key); diff --git a/packages/app-staking/src/Account/Unbond.tsx b/packages/app-staking/src/Account/Unbond.tsx index 2968ac3b68..8ebf579970 100644 --- a/packages/app-staking/src/Account/Unbond.tsx +++ b/packages/app-staking/src/Account/Unbond.tsx @@ -2,7 +2,6 @@ // This software may be modified and distributed under the terms // of the Apache-2.0 license. See the LICENSE file for details. -import { AccountId } from '@polkadot/types'; import BN from 'bn.js'; import { Button, InputAddress, InputBalance, Modal, TxButton } from '@polkadot/ui-app'; import { I18nProps } from '@polkadot/ui-app/types'; @@ -11,7 +10,7 @@ import React from 'react'; import translate from '../translate'; type Props = I18nProps & { - controllerId?: AccountId | null, + controllerId?: string | null, isOpen: boolean, onClose: () => void }; @@ -49,7 +48,7 @@ class Unbond extends React.PureComponent { /> { diff --git a/packages/app-staking/src/Account/ValidateSession.tsx b/packages/app-staking/src/Account/ValidateSession.tsx new file mode 100644 index 0000000000..64a9183ce9 --- /dev/null +++ b/packages/app-staking/src/Account/ValidateSession.tsx @@ -0,0 +1,71 @@ +// Copyright 2017-2019 @polkadot/ui-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 { I18nProps } from '@polkadot/ui-app/types'; + +import React from 'react'; +import { Icon } from '@polkadot/ui-app'; +import keyring from '@polkadot/ui-keyring'; + +import translate from '../translate'; + +type Props = I18nProps & { + controllerId: string, + onError: (error: string | null) => void, + sessionId: string, + stashId: string +}; + +type State = { + error: string | null +}; + +class ValidateSession extends React.PureComponent { + state: State = { + error: null + }; + + static getDerivedStateFromProps ({ onError, sessionId, stashId, t }: Props, prevState: State): State | null { + let error = null; + + try { + const pair = keyring.getPair(sessionId); + + if (pair.type !== 'ed25519') { + error = t('The selected account is not an ed25519 (Edwards) account as required for validation'); + } else if (sessionId === stashId) { + error = t('For fund security, your session key should not match your stash key.'); + } else { + error = null; + } + } catch (e) { + // this _should_ never happen... + error = t('The account {{sessionId}} is not a valid account', { replace: { sessionId } }); + } + + if (error === prevState.error) { + return null; + } + + onError(error); + + return { error }; + } + + render () { + const { error } = this.state; + + if (!error) { + return null; + } + + return ( +
+
{error}
+
+ ); + } +} + +export default translate(ValidateSession); diff --git a/packages/app-staking/src/Account/Validating.tsx b/packages/app-staking/src/Account/Validating.tsx index 769d22e193..8d29ea5615 100644 --- a/packages/app-staking/src/Account/Validating.tsx +++ b/packages/app-staking/src/Account/Validating.tsx @@ -6,7 +6,7 @@ import { I18nProps } from '@polkadot/ui-app/types'; import BN from 'bn.js'; import React from 'react'; -import { AccountId, ValidatorPrefs } from '@polkadot/types'; +import { ValidatorPrefs } from '@polkadot/types'; import { Button, InputAddress, InputBalance, InputNumber, Modal, TxButton } from '@polkadot/ui-app'; import translate from '../translate'; @@ -16,7 +16,7 @@ type Props = I18nProps & { isOpen: boolean, onClose: () => void, preferences: ValidatorPrefs, - stashId: AccountId + stashId: string }; type State = { diff --git a/packages/app-staking/src/Account/index.tsx b/packages/app-staking/src/Account/index.tsx index 0df8b44ba0..c42abf9659 100644 --- a/packages/app-staking/src/Account/index.tsx +++ b/packages/app-staking/src/Account/index.tsx @@ -23,13 +23,13 @@ import Validating from './Validating'; type Props = ApiProps & I18nProps & { accountId: string, balances: DerivedBalancesMap, - controllerId?: AccountId | null, + controllerId?: string | null, filter: AccountFilter, isValidator: boolean, name: string, recentlyOffline: RecentlyOfflineMap, - sessionId?: AccountId | null, - stashId?: AccountId | null, + sessionId?: string | null, + stashId?: string | null, freeBalance?: Balance, staking_stakers?: Exposure, staking_nominators?: [Array], @@ -132,11 +132,11 @@ class Account extends React.PureComponent { const { isUnbondOpen } = this.state; return ( - + ); } @@ -160,14 +160,19 @@ class Account extends React.PureComponent { } private renderSessionKey () { - const { accountId } = this.props; + const { accountId, stashId } = this.props; const { isSessionKeyOpen } = this.state; + if (!stashId) { + return null; + } + return ( ); } @@ -209,7 +214,7 @@ class Account extends React.PureComponent { ); @@ -242,7 +247,7 @@ class Account extends React.PureComponent { @@ -404,6 +409,12 @@ class Account extends React.PureComponent { } } +function toIdString (id: AccountId | null): string | null { + return id + ? id.toString() + : null; +} + export default translate( withCalls( 'query.staking.recentlyOffline', @@ -411,19 +422,19 @@ export default translate( paramName: 'accountId', propName: 'sessionId', transform: (session: Option) => - session.unwrapOr(null) + toIdString(session.unwrapOr(null)) }], ['query.staking.bonded', { paramName: 'accountId', propName: 'controllerId', transform: (bonded: Option) => - bonded.unwrapOr(null) + toIdString(bonded.unwrapOr(null)) }], ['query.staking.ledger', { paramName: 'accountId', propName: 'stashId', transform: (ledger: Option) => - ledger.unwrapOr({ stash: null }).stash + toIdString(ledger.unwrapOr({ stash: null }).stash) }], ['query.staking.ledger', { paramName: 'controllerId',