Add insert key functionality (#1683)

This commit is contained in:
Jaco Greeff 2019-10-02 14:24:02 +02:00 committed by GitHub
parent 38faa6adb9
commit 7c1ff04500
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 171 additions and 6 deletions

View File

@ -0,0 +1,138 @@
// Copyright 2017-2019 @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 { I18nProps } from '@polkadot/react-components/types';
import { KeypairType } from '@polkadot/util-crypto/types';
import React, { useContext, useEffect, useState } from 'react';
import { Button, Dropdown, Icon, Input, Modal } from '@polkadot/react-components';
import { QueueContext } from '@polkadot/react-components/Status';
import keyring from '@polkadot/ui-keyring';
import { assert, u8aToHex } from '@polkadot/util';
import { keyExtractSuri, mnemonicValidate } from '@polkadot/util-crypto';
import translate from '../../translate';
interface Props extends I18nProps {
isOpen?: boolean;
onClose: () => void;
}
const CRYPTO_MAP: Record<string, KeypairType[]> = {
aura: ['ed25519', 'sr25519'],
babe: ['sr25519'],
gran: ['ed25519'],
imon: ['ed25519', 'sr25519'],
para: ['sr25519']
};
const EMPTY_KEY = '0x';
function InjectKeys ({ isOpen = true, onClose, t }: Props): React.ReactElement<Props> | null {
const { queueRpc } = useContext(QueueContext);
// this needs to align with what is set as the first value in `type`
const [crypto, setCrypto] = useState<KeypairType>('sr25519');
const [publicKey, setPublicKey] = useState(EMPTY_KEY);
const [suri, setSuri] = useState('');
const [type, setType] = useState('babe');
useEffect((): void => {
setCrypto(CRYPTO_MAP[type][0]);
}, [type]);
useEffect((): void => {
try {
const { phrase } = keyExtractSuri(suri);
assert(mnemonicValidate(phrase), 'Invalid mnemonic phrase');
setPublicKey(u8aToHex(keyring.createFromUri(suri, {}, crypto).publicKey));
} catch (error) {
setPublicKey(EMPTY_KEY);
}
}, [crypto, suri]);
if (!isOpen) {
return null;
}
const _onSubmit = (): void => {
queueRpc({
rpc: { section: 'author', method: 'insertKey' } as any,
values: [type, suri, publicKey]
});
};
const _cryptoOptions = CRYPTO_MAP[type].map((value): { text: string; value: KeypairType } => ({
text: value === 'ed25519'
? t('ed25519, Edwards')
: t('sr15519, Schnorrkel'),
value
}));
return (
<Modal
dimmer='inverted'
open
size='small'
>
<Modal.Header>
{t('Inject Keys')}
</Modal.Header>
<Modal.Content>
<Input
isError={publicKey.length !== 66}
label={t('suri (seed & derivation)')}
onChange={setSuri}
value={suri}
/>
<Dropdown
label={t('key type to set')}
onChange={setType}
options={[
{ text: t('Aura'), value: 'aura' },
{ text: t('Babe'), value: 'babe' },
{ text: t('Grandpa'), value: 'gran' },
{ text: t('I\'m Online'), value: 'imon' },
{ text: t('Parachains'), value: 'para' }
]}
value={type}
/>
<Dropdown
isDisabled={_cryptoOptions.length === 1}
label={t('crypto type to use')}
onChange={setCrypto}
options={_cryptoOptions}
value={crypto}
/>
<Input
isDisabled
label={t('generated public key')}
value={publicKey}
/>
<article className='warning'>
<div><Icon name='warning sign' />{t('This operation will submit the seed via an RPC call. Do not perform this operation on a public RPC node, but ensure that the node is local, connected to your validator and secure.')}</div>
</article>
</Modal.Content>
<Modal.Actions>
<Button.Group>
<Button
icon='cancel'
isNegative
label={t('Cancel')}
onClick={onClose}
/>
<Button.Or />
<Button
icon='sign-in'
isPrimary
label={t('Submit key')}
onClick={_onSubmit}
/>
</Button.Group>
</Modal.Actions>
</Modal>
);
}
export default translate(InjectKeys);

View File

@ -16,6 +16,7 @@ import { AddressCard, AddressInfo, AddressMini, AddressRow, Button, Menu, Online
import { withCalls, withMulti } from '@polkadot/react-api';
import BondExtra from './BondExtra';
import InjectKeys from './InjectKeys';
import Nominate from './Nominate';
import SetControllerAccount from './SetControllerAccount';
import SetRewardDestination from './SetRewardDestination';
@ -42,6 +43,7 @@ interface State {
destination: number;
hexSessionId: string | null;
isBondExtraOpen: boolean;
isInjectOpen: boolean;
isNominateOpen: boolean;
isSetControllerAccountOpen: boolean;
isSetRewardDestinationOpen: boolean;
@ -72,6 +74,7 @@ class Account extends React.PureComponent<Props, State> {
destination: 0,
hexSessionId: null,
isBondExtraOpen: false,
isInjectOpen: false,
isNominateOpen: false,
isSetControllerAccountOpen: false,
isSettingPopupOpen: false,
@ -122,7 +125,7 @@ class Account extends React.PureComponent<Props, State> {
public render (): React.ReactNode {
const { className, isSubstrateV2, t } = this.props;
const { controllerId, hexSessionId, isBondExtraOpen, isStashValidating, isUnbondOpen, nominees, sessionIds, stashId } = this.state;
const { controllerId, hexSessionId, isBondExtraOpen, isInjectOpen, isStashValidating, isUnbondOpen, nominees, sessionIds, stashId } = this.state;
if (!stashId) {
return null;
@ -160,6 +163,9 @@ class Account extends React.PureComponent<Props, State> {
onClose={this.toggleUnbond}
stashId={stashId}
/>
{isInjectOpen && (
<InjectKeys onClose={this.toggleInject} />
)}
{this.renderSetValidatorPrefs()}
{this.renderNominate()}
{this.renderSetControllerAccount()}
@ -418,9 +424,9 @@ class Account extends React.PureComponent<Props, State> {
{t('Change validator preferences')}
</Menu.Item>
}
{(!!sessionIds.length || (isSubstrateV2 && hexSessionId !== '0x')) &&
{!isStashNominating && (!!sessionIds.length || (isSubstrateV2 && hexSessionId !== '0x')) &&
<Menu.Item onClick={this.toggleSetSessionAccount}>
{isSubstrateV2 ? t('Change session keys') : t('Change session account')}
{isSubstrateV2 ? t('Rotate session keys') : t('Change session account')}
</Menu.Item>
}
{isStashNominating &&
@ -428,6 +434,11 @@ class Account extends React.PureComponent<Props, State> {
{t('Change nominee(s)')}
</Menu.Item>
}
{!isStashNominating && isSubstrateV2 &&
<Menu.Item onClick={this.toggleInject}>
{t('Inject session keys (advanced)')}
</Menu.Item>
}
</Menu>
);
}
@ -507,6 +518,12 @@ class Account extends React.PureComponent<Props, State> {
}));
}
private toggleInject = (): void => {
this.setState(({ isInjectOpen }): Pick<State, never> => ({
isInjectOpen: !isInjectOpen
}));
}
private toggleNominate = (): void => {
this.setState(({ isNominateOpen }): Pick<State, never> => ({
isNominateOpen: !isNominateOpen

View File

@ -14,8 +14,11 @@ import Button from '../Button';
import Icon from '../Icon';
import translate from '../translate';
import { classes } from '../util';
import QueueContext from './Context';
import { STATUS_COMPLETE } from './constants';
export { QueueContext };
interface Props extends I18nProps {
stqueue?: QueueStatus[];
txqueue?: QueueTx[];
@ -188,7 +191,7 @@ export default translate(
top: 0.25rem;
width: 20rem;
z-index: 1001;
.dismiss {
margin-bottom: 0.25rem;
}
@ -227,11 +230,11 @@ export default translate(
line-height: 1;
}
}
.padded {
padding: 0.25rem 0 0 0 !important;
}
i.close {
position: absolute;
top: 0.25rem;

View File

@ -60,6 +60,11 @@ export default createGlobalStyle`
padding: 0;
}
&.error,
&.warning {
margin-left: 2.25rem;
}
&.error {
background: #fff6f6;
border-color: #e0b4b4;

View File

@ -486,6 +486,8 @@ class Signer extends React.PureComponent<Props, State> {
const { api } = this.props;
try {
assert(isFunction((api.rpc as any)[section] && (api.rpc as any)[section][method]), `api.rpc.${section}.${method} does not exist`);
const result = await (api.rpc as any)[section][method](...values);
console.log('submitRpc: result ::', format(result));