mirror of
https://github.com/status-im/MyCrypto.git
synced 2025-01-23 09:30:38 +00:00
unlock wip
This commit is contained in:
parent
dbb90d0d5c
commit
63e7eb89e4
@ -1,9 +1,7 @@
|
||||
{
|
||||
"extends": ["eslint:recommended", "plugin:react/recommended"],
|
||||
"parser": "babel-eslint",
|
||||
"plugins": [
|
||||
"react"
|
||||
],
|
||||
"plugins": ["react"],
|
||||
"parserOptions": {
|
||||
"ecmaFeatures": {
|
||||
"jsx": true,
|
||||
@ -19,7 +17,7 @@
|
||||
},
|
||||
"rules": {
|
||||
"comma-dangle": 1,
|
||||
"quotes": [ 1, "single" ],
|
||||
"quotes": [1, "single"],
|
||||
"no-undef": 1,
|
||||
"global-strict": 0,
|
||||
"no-extra-semi": 1,
|
||||
@ -32,6 +30,7 @@
|
||||
"react/jsx-uses-react": 1
|
||||
},
|
||||
"globals": {
|
||||
"SyntheticInputEvent": false
|
||||
"SyntheticInputEvent": false,
|
||||
"SyntheticKeyboardEvent": false
|
||||
}
|
||||
}
|
||||
|
29
common/actions/wallet.js
Normal file
29
common/actions/wallet.js
Normal file
@ -0,0 +1,29 @@
|
||||
// @flow
|
||||
import type { PrivateKeyUnlockParams } from 'libs/wallet/privkey';
|
||||
import BaseWallet from 'libs/wallet/base';
|
||||
|
||||
export type UnlockPrivateKeyAction = {
|
||||
type: 'WALLET_UNLOCK_PRIVATE_KEY',
|
||||
payload: PrivateKeyUnlockParams
|
||||
};
|
||||
|
||||
export type SaveWalletAction = {
|
||||
type: 'WALLET_SAVE',
|
||||
payload: BaseWallet
|
||||
};
|
||||
|
||||
export type WalletAction = UnlockPrivateKeyAction | SaveWalletAction;
|
||||
|
||||
export function unlockPrivateKey(value: PrivateKeyUnlockParams): UnlockPrivateKeyAction {
|
||||
return {
|
||||
type: 'WALLET_UNLOCK_PRIVATE_KEY',
|
||||
payload: value
|
||||
};
|
||||
}
|
||||
|
||||
export function saveWallet(value: BaseWallet): SaveWalletAction {
|
||||
return {
|
||||
type: 'WALLET_SAVE',
|
||||
payload: value
|
||||
};
|
||||
}
|
95
common/components/WalletDecrypt/PrivateKey.jsx
Normal file
95
common/components/WalletDecrypt/PrivateKey.jsx
Normal file
@ -0,0 +1,95 @@
|
||||
// @flow
|
||||
import React, { Component } from 'react';
|
||||
import translate from 'translations';
|
||||
import { isValidPrivKey } from 'libs/validators';
|
||||
import type { PrivateKeyUnlockParams } from 'libs/wallet/privkey';
|
||||
|
||||
export type PrivateKeyValue = PrivateKeyUnlockParams & {
|
||||
valid: boolean
|
||||
};
|
||||
|
||||
function fixPkey(key) {
|
||||
if (key.indexOf('0x') === 0) {
|
||||
return key.slice(2);
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
export default class PrivateKeyDecrypt extends Component {
|
||||
props: {
|
||||
value: PrivateKeyUnlockParams,
|
||||
onChange: (value: PrivateKeyUnlockParams) => void,
|
||||
onUnlock: () => void
|
||||
};
|
||||
|
||||
render() {
|
||||
const { key, password } = this.props.value;
|
||||
const fixedPkey = fixPkey(key);
|
||||
const isValid = isValidPrivKey(fixedPkey.length);
|
||||
const isPassRequired = fixedPkey.length > 64;
|
||||
|
||||
return (
|
||||
<section className="col-md-4 col-sm-6">
|
||||
<div id="selectedTypeKey">
|
||||
<h4>
|
||||
{translate('ADD_Radio_3')}
|
||||
</h4>
|
||||
<div className="form-group">
|
||||
<textarea
|
||||
id="aria-private-key"
|
||||
className={`form-control ${isValid ? 'is-valid' : 'is-invalid'}`}
|
||||
value={key}
|
||||
onChange={this.onPkeyChange}
|
||||
onKeyDown={this.onKeyDown}
|
||||
placeholder={translate('x_PrivKey2')}
|
||||
rows="4"
|
||||
/>
|
||||
</div>
|
||||
{isValid &&
|
||||
isPassRequired &&
|
||||
<div className="form-group">
|
||||
<p>
|
||||
{translate('ADD_Label_3')}
|
||||
</p>
|
||||
<input
|
||||
className={`form-control ${password.length > 0
|
||||
? 'is-valid'
|
||||
: 'is-invalid'}`}
|
||||
value={password}
|
||||
onChange={this.onPasswordChange}
|
||||
onKeyDown={this.onKeyDown}
|
||||
placeholder={translate('x_Password')}
|
||||
type="password"
|
||||
/>
|
||||
</div>}
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
onPkeyChange = (e: SyntheticInputEvent) => {
|
||||
const fixedPkey = fixPkey(e.target.value);
|
||||
const isValid = isValidPrivKey(fixedPkey.length);
|
||||
const isPassRequired = fixedPkey.length > 64;
|
||||
const valid = isValid && (isPassRequired ? this.props.value.password.length > 0 : true);
|
||||
|
||||
this.props.onChange({ ...this.props.value, key: e.target.value, valid });
|
||||
};
|
||||
|
||||
onPasswordChange = (e: SyntheticInputEvent) => {
|
||||
const fixedPkey = fixPkey(this.props.value.key);
|
||||
const isValid = isValidPrivKey(fixedPkey.length);
|
||||
const isPassRequired = fixedPkey.length > 64;
|
||||
const valid = isValid && (isPassRequired ? e.target.value.length > 0 : true);
|
||||
|
||||
this.props.onChange({ ...this.props.value, password: e.target.value, valid });
|
||||
};
|
||||
|
||||
onKeyDown = (e: SyntheticKeyboardEvent) => {
|
||||
if (e.keyCode === 13) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
this.props.onUnlock();
|
||||
}
|
||||
};
|
||||
}
|
161
common/components/WalletDecrypt/index.jsx
Normal file
161
common/components/WalletDecrypt/index.jsx
Normal file
@ -0,0 +1,161 @@
|
||||
// @flow
|
||||
import React, { Component } from 'react';
|
||||
import translate from 'translations';
|
||||
import KeystoreDecrypt from './Keystore';
|
||||
import PrivateKeyDecrypt from './PrivateKey';
|
||||
import type { PrivateKeyValue } from './PrivateKey';
|
||||
import MnemonicDecrypt from './Mnemonic';
|
||||
import LedgerNanoSDecrypt from './LedgerNano';
|
||||
import TrezorDecrypt from './Trezor';
|
||||
import ViewOnlyDecrypt from './ViewOnly';
|
||||
import map from 'lodash/map';
|
||||
import { unlockPrivateKey } from 'actions/wallet';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
const WALLETS = {
|
||||
'keystore-file': {
|
||||
lid: 'x_Keystore2',
|
||||
component: KeystoreDecrypt,
|
||||
initialParams: {}
|
||||
},
|
||||
'private-key': {
|
||||
lid: 'x_PrivKey2',
|
||||
component: PrivateKeyDecrypt,
|
||||
initialParams: {
|
||||
key: '',
|
||||
password: ''
|
||||
},
|
||||
unlock: unlockPrivateKey
|
||||
},
|
||||
'mnemonic-phrase': {
|
||||
lid: 'x_Mnemonic',
|
||||
component: MnemonicDecrypt
|
||||
},
|
||||
'ledger-nano-s': {
|
||||
lid: 'x_Ledger',
|
||||
component: LedgerNanoSDecrypt
|
||||
},
|
||||
trezor: {
|
||||
lid: 'x_Trezor',
|
||||
component: TrezorDecrypt
|
||||
},
|
||||
'view-only': {
|
||||
lid: 'View with Address Only',
|
||||
component: ViewOnlyDecrypt
|
||||
}
|
||||
};
|
||||
|
||||
type UnlockParams = {} | PrivateKeyValue;
|
||||
|
||||
type State = {
|
||||
selectedWalletKey: string,
|
||||
value: UnlockParams
|
||||
};
|
||||
|
||||
export class WalletDecrypt extends Component {
|
||||
props: {
|
||||
// FIXME
|
||||
dispatch: (action: any) => void
|
||||
};
|
||||
state: State = {
|
||||
selectedWalletKey: 'keystore-file',
|
||||
value: WALLETS['keystore-file'].initialParams
|
||||
};
|
||||
|
||||
getDecryptionComponent() {
|
||||
const { selectedWalletKey, value } = this.state;
|
||||
const selectedWallet = WALLETS[selectedWalletKey];
|
||||
|
||||
if (!selectedWallet) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<selectedWallet.component
|
||||
value={value}
|
||||
onChange={this.onChange}
|
||||
onUnlock={this.onUnlock}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
buildWalletOptions() {
|
||||
return map(WALLETS, (wallet, key) => {
|
||||
const isSelected = this.state.selectedWalletKey === key;
|
||||
|
||||
return (
|
||||
<label className="radio" key={key}>
|
||||
<input
|
||||
aria-flowto={`aria-${key}`}
|
||||
aria-labelledby={`${key}-label`}
|
||||
type="radio"
|
||||
name="decryption-choice-radio-group"
|
||||
value={key}
|
||||
checked={isSelected}
|
||||
onChange={this.handleDecryptionChoiceChange}
|
||||
/>
|
||||
<span id={`${key}-label`}>
|
||||
{translate(wallet.lid)}
|
||||
</span>
|
||||
</label>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
handleDecryptionChoiceChange = (event: SyntheticInputEvent) => {
|
||||
const wallet = WALLETS[event.target.value];
|
||||
|
||||
if (!wallet) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.setState({
|
||||
selectedWalletKey: event.target.value,
|
||||
value: wallet.initialParams
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const decryptionComponent = this.getDecryptionComponent();
|
||||
|
||||
return (
|
||||
<article className="well decrypt-drtv row">
|
||||
<section className="col-md-4 col-sm-6">
|
||||
<h4>
|
||||
{translate('decrypt_Access')}
|
||||
</h4>
|
||||
|
||||
{this.buildWalletOptions()}
|
||||
</section>
|
||||
|
||||
{decryptionComponent}
|
||||
{!!this.state.value.valid &&
|
||||
<section className="col-md-4 col-sm-6">
|
||||
<h4 id="uploadbtntxt-wallet">
|
||||
{translate('ADD_Label_6')}
|
||||
</h4>
|
||||
<div className="form-group">
|
||||
<a
|
||||
tabIndex="0"
|
||||
role="button"
|
||||
className="btn btn-primary btn-block"
|
||||
onClick={this.onUnlock}
|
||||
>
|
||||
{translate('ADD_Label_6_short')}
|
||||
</a>
|
||||
</div>
|
||||
</section>}
|
||||
</article>
|
||||
);
|
||||
}
|
||||
|
||||
onChange = (value: UnlockParams) => {
|
||||
this.setState({ value });
|
||||
};
|
||||
|
||||
onUnlock = () => {
|
||||
this.props.dispatch(WALLETS[this.state.selectedWalletKey].unlock(this.state.value));
|
||||
};
|
||||
}
|
||||
|
||||
export default connect()(WalletDecrypt);
|
@ -2,11 +2,18 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import translate from 'translations';
|
||||
import WalletDecrypt from 'components/WalletDecrypt';
|
||||
import BaseWallet from 'libs/wallet/base';
|
||||
import { connect } from 'react-redux';
|
||||
import type { State } from 'reducers';
|
||||
|
||||
export default class UnlockHeader extends React.Component {
|
||||
props: {
|
||||
title: string
|
||||
};
|
||||
type Props = {
|
||||
title: string,
|
||||
wallet: BaseWallet
|
||||
};
|
||||
|
||||
export class UnlockHeader extends React.Component {
|
||||
props: Props;
|
||||
static propTypes = {
|
||||
title: PropTypes.string.isRequired
|
||||
};
|
||||
@ -17,17 +24,33 @@ export default class UnlockHeader extends React.Component {
|
||||
expanded: true
|
||||
};
|
||||
|
||||
componentDidUpdate(prevProps: Props) {
|
||||
if (this.props.wallet && this.props.wallet !== prevProps.wallet) {
|
||||
this.setState({ expanded: false });
|
||||
}
|
||||
|
||||
// not sure if could happen
|
||||
if (!this.props.wallet && this.props.wallet !== prevProps.wallet) {
|
||||
this.setState({ expanded: true });
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<article className="collapse-container">
|
||||
<div onClick={this.toggleExpanded}>
|
||||
<a className="collapse-button">
|
||||
<span>{this.state.expanded ? '-' : '+'}</span>
|
||||
<span>
|
||||
{this.state.expanded ? '-' : '+'}
|
||||
</span>
|
||||
</a>
|
||||
<h1>{translate(this.props.title)}</h1>
|
||||
<h1>
|
||||
{translate(this.props.title)}
|
||||
</h1>
|
||||
</div>
|
||||
{this.state.expanded &&
|
||||
<div>
|
||||
<WalletDecrypt />
|
||||
{/* @@if (site === 'cx' ) { <cx-wallet-decrypt-drtv></cx-wallet-decrypt-drtv> }
|
||||
@@if (site === 'mew' ) { <wallet-decrypt-drtv></wallet-decrypt-drtv> } */}
|
||||
</div>}
|
||||
@ -43,3 +66,11 @@ export default class UnlockHeader extends React.Component {
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
function mapStateToProps(state: State) {
|
||||
return {
|
||||
wallet: state.wallet
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(UnlockHeader);
|
||||
|
@ -13,6 +13,9 @@ import {
|
||||
AddressField
|
||||
} from './components';
|
||||
import pickBy from 'lodash/pickBy';
|
||||
import type { State as AppState } from 'reducers';
|
||||
import { connect } from 'react-redux';
|
||||
import BaseWallet from 'libs/wallet/base';
|
||||
// import type { Transaction } from './types';
|
||||
import customMessages from './messages';
|
||||
|
||||
@ -49,7 +52,8 @@ export class SendTransaction extends React.Component {
|
||||
query: {
|
||||
[string]: string
|
||||
}
|
||||
}
|
||||
},
|
||||
wallet: BaseWallet
|
||||
};
|
||||
state: State = {
|
||||
hasQueryString: false,
|
||||
@ -73,7 +77,7 @@ export class SendTransaction extends React.Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
const unlocked = true; //wallet != null
|
||||
const unlocked = !!this.props.wallet;
|
||||
const unitReadable = 'UNITREADABLE';
|
||||
const nodeUnit = 'NODEUNIT';
|
||||
const hasEnoughBalance = false;
|
||||
@ -87,7 +91,6 @@ export class SendTransaction extends React.Component {
|
||||
<section className="container" style={{ minHeight: '50%' }}>
|
||||
<div className="tab-content">
|
||||
<main className="tab-pane active" ng-controller="sendTxCtrl">
|
||||
|
||||
{hasQueryString &&
|
||||
<div className="alert alert-info">
|
||||
<p>
|
||||
@ -116,8 +119,7 @@ export class SendTransaction extends React.Component {
|
||||
<strong>
|
||||
Warning! You do not have enough funds to
|
||||
complete this swap.
|
||||
</strong>
|
||||
{' '}
|
||||
</strong>{' '}
|
||||
<br />
|
||||
Please add more funds or access a different wallet.
|
||||
</div>
|
||||
@ -187,7 +189,6 @@ export class SendTransaction extends React.Component {
|
||||
{' '}Send Transaction{' '}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
</section>
|
||||
{'' /* <!-- / Content --> */}
|
||||
{
|
||||
@ -266,5 +267,11 @@ export class SendTransaction extends React.Component {
|
||||
});
|
||||
};
|
||||
}
|
||||
// export connected version
|
||||
export default SendTransaction;
|
||||
|
||||
function mapStateToProps(state: AppState) {
|
||||
return {
|
||||
wallet: state.wallet
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(SendTransaction);
|
||||
|
26
common/containers/Tabs/ViewWallet/index.jsx
Normal file
26
common/containers/Tabs/ViewWallet/index.jsx
Normal file
@ -0,0 +1,26 @@
|
||||
// @flow
|
||||
import React, { Component } from 'react';
|
||||
import translate from 'translations';
|
||||
|
||||
export default class ViewWallet extends Component {
|
||||
render() {
|
||||
return (
|
||||
<section className="container">
|
||||
<div className="tab-content">
|
||||
<article className="tab-pane active">
|
||||
<article className="collapse-container">
|
||||
<div>
|
||||
<h1>View Wallet Info</h1>
|
||||
</div>
|
||||
<div>
|
||||
<p>
|
||||
{translate('VIEWWALLET_Subtitle')}
|
||||
</p>
|
||||
</div>
|
||||
</article>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
import React, {Component} from 'react';
|
||||
import translate from 'translations';
|
||||
|
||||
|
||||
export default class PrivateKeyDecrypt extends Component {
|
||||
render() {
|
||||
return (
|
||||
<section className="col-md-4 col-sm-6">
|
||||
<div id="selectedUploadKey">
|
||||
<h4>{translate('ADD_Radio_2_alt')}</h4>
|
||||
|
||||
<div className="form-group">
|
||||
<input type="file" id="fselector" />
|
||||
|
||||
<a className="btn-file marg-v-sm" id="aria1" tabIndex="0" role="button">{translate('ADD_Radio_2_short')}</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
}
|
@ -1,129 +0,0 @@
|
||||
import React, {Component} from 'react';
|
||||
import translate from 'translations';
|
||||
import KeystoreDecrypt from './KeystoreDecrypt';
|
||||
import PrivateKeyDecrypt from './PrivateKeyDecrypt';
|
||||
import MnemonicDecrypt from './MnemonicDecrypt';
|
||||
import LedgerNanoSDecrypt from './LedgerNanoSDecrypt';
|
||||
import TrezorDecrypt from './TrezorDecrypt';
|
||||
import ViewOnlyDecrypt from './ViewOnlyDecrypt';
|
||||
|
||||
export default class WalletDecrypt extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.decryptionChoices = [
|
||||
{
|
||||
name: 'keystore-file',
|
||||
lid: 'x_Keystore2',
|
||||
component: KeystoreDecrypt
|
||||
},
|
||||
{
|
||||
name: 'private-key',
|
||||
lid: 'x_PrivKey2',
|
||||
component: PrivateKeyDecrypt
|
||||
},
|
||||
{
|
||||
name: 'mnemonic-phrase',
|
||||
lid: 'x_Mnemonic',
|
||||
component: MnemonicDecrypt
|
||||
},
|
||||
{
|
||||
name: 'ledger-nano-s',
|
||||
lid: 'x_Ledger',
|
||||
component: LedgerNanoSDecrypt
|
||||
},
|
||||
{
|
||||
name: 'trezor',
|
||||
lid: 'x_Trezor',
|
||||
component: TrezorDecrypt
|
||||
},
|
||||
{
|
||||
name: 'view-only',
|
||||
lid: 'View with Address Only',
|
||||
component: ViewOnlyDecrypt
|
||||
}
|
||||
];
|
||||
|
||||
this.state = {
|
||||
decryptionChoice: this.decryptionChoices[0].name // auto-select first option.
|
||||
};
|
||||
}
|
||||
|
||||
getDecryptionComponent() {
|
||||
const selectedDecryptionChoice = this.decryptionChoices.find((decryptionChoice) => {
|
||||
return this.state.decryptionChoice === decryptionChoice.name;
|
||||
});
|
||||
|
||||
if (!selectedDecryptionChoice) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return <selectedDecryptionChoice.component />;
|
||||
}
|
||||
|
||||
buildDecryptionChoices() {
|
||||
return this.decryptionChoices.map((decryptionChoice, idx) => {
|
||||
const isSelected = this.state.decryptionChoice === decryptionChoice.name;
|
||||
|
||||
return (
|
||||
<label className="radio" key={decryptionChoice.name}>
|
||||
<input
|
||||
aria-flowto={`aria${idx}`}
|
||||
aria-labelledby={`${decryptionChoice.name}-label`}
|
||||
type="radio"
|
||||
name="decryption-choice-radio-group"
|
||||
value={decryptionChoice.name}
|
||||
checked={isSelected}
|
||||
onChange={this.handleDecryptionChoiceChange}
|
||||
/>
|
||||
<span id={`${decryptionChoice.name}-label`}>
|
||||
{translate(decryptionChoice.lid)}
|
||||
</span>
|
||||
</label>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
handleDecryptionChoiceChange = (event) => {
|
||||
const choiceObject = this.decryptionChoices.find(decryptionChoice => {
|
||||
return (decryptionChoice.name === event.target.value) ? decryptionChoice.component : false;
|
||||
});
|
||||
|
||||
const decryptionChoice = choiceObject.name;
|
||||
|
||||
this.setState({
|
||||
decryptionChoice
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const decryptionComponent = this.getDecryptionComponent();
|
||||
|
||||
return (
|
||||
<section className="container">
|
||||
<div className="tab-content">
|
||||
<article className="tab-pane active">
|
||||
<article className="collapse-container">
|
||||
<div>
|
||||
<h1>View Wallet Info</h1>
|
||||
</div>
|
||||
<div>
|
||||
<p>{translate('VIEWWALLET_Subtitle')}</p>
|
||||
<article className="well decrypt-drtv row">
|
||||
<section className="col-md-4 col-sm-6">
|
||||
<h4>{translate('decrypt_Access')}</h4>
|
||||
|
||||
{this.buildDecryptionChoices()}
|
||||
|
||||
</section>
|
||||
|
||||
{decryptionComponent}
|
||||
</article>
|
||||
</div>
|
||||
</article>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
}
|
@ -11,31 +11,32 @@ import { createLogger } from 'redux-logger';
|
||||
import createSagaMiddleware from 'redux-saga';
|
||||
import notificationsSaga from './sagas/notifications';
|
||||
import ensSaga from './sagas/ens';
|
||||
import walletSaga from './sagas/wallet';
|
||||
|
||||
// application styles
|
||||
import 'assets/styles/etherwallet-master.less';
|
||||
|
||||
const sagaMiddleware = createSagaMiddleware();
|
||||
|
||||
const configureStore = () => {
|
||||
let sagaApplied = applyMiddleware(sagaMiddleware);
|
||||
const logger = createLogger({
|
||||
collapsed: true
|
||||
});
|
||||
const sagaMiddleware = createSagaMiddleware();
|
||||
let store;
|
||||
let middleware;
|
||||
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
window.Perf = Perf;
|
||||
sagaApplied = composeWithDevTools(sagaApplied);
|
||||
const logger = createLogger({
|
||||
collapsed: true
|
||||
});
|
||||
middleware = applyMiddleware(routerMiddleware(history), logger);
|
||||
middleware = composeWithDevTools(
|
||||
applyMiddleware(sagaMiddleware, logger, routerMiddleware(history))
|
||||
);
|
||||
} else {
|
||||
middleware = applyMiddleware(routerMiddleware(history));
|
||||
middleware = applyMiddleware(sagaMiddleware, routerMiddleware(history));
|
||||
}
|
||||
|
||||
store = createStore(RootReducer, sagaApplied, middleware);
|
||||
store = createStore(RootReducer, void 0, middleware);
|
||||
sagaMiddleware.run(notificationsSaga);
|
||||
sagaMiddleware.run(ensSaga);
|
||||
sagaMiddleware.run(walletSaga);
|
||||
return store;
|
||||
};
|
||||
|
||||
|
@ -65,3 +65,7 @@ function validateEtherAddress(address: string): boolean {
|
||||
return true;
|
||||
else return isChecksumAddress(address);
|
||||
}
|
||||
|
||||
export function isValidPrivKey(length: number): boolean {
|
||||
return length === 64 || length === 128 || length === 132;
|
||||
}
|
||||
|
7
common/libs/wallet/base.js
Normal file
7
common/libs/wallet/base.js
Normal file
@ -0,0 +1,7 @@
|
||||
// @flow
|
||||
|
||||
export default class BaseWallet {
|
||||
getAddress(): string {
|
||||
throw 'Implement me';
|
||||
}
|
||||
}
|
24
common/libs/wallet/privkey.js
Normal file
24
common/libs/wallet/privkey.js
Normal file
@ -0,0 +1,24 @@
|
||||
// @flow
|
||||
import BaseWallet from './base';
|
||||
import { privateToPublic, publicToAddress, toChecksumAddress } from 'ethereumjs-util';
|
||||
|
||||
export type PrivateKeyUnlockParams = {
|
||||
key: string,
|
||||
password: string
|
||||
};
|
||||
|
||||
export default class PrivKeyWallet extends BaseWallet {
|
||||
privKey: Buffer;
|
||||
pubKey: Buffer;
|
||||
address: Buffer;
|
||||
constructor(params: PrivateKeyUnlockParams) {
|
||||
super();
|
||||
this.privKey = Buffer.from(params.key, 'hex');
|
||||
this.pubKey = privateToPublic(this.privKey);
|
||||
this.address = publicToAddress(this.pubKey);
|
||||
}
|
||||
|
||||
getAddress() {
|
||||
return toChecksumAddress(`0x${this.address.toString('hex')}`);
|
||||
}
|
||||
}
|
@ -13,6 +13,9 @@ import type { State as NotificationsState } from './notifications';
|
||||
import * as ens from './ens';
|
||||
import type { State as EnsState } from './ens';
|
||||
|
||||
import * as wallet from './wallet';
|
||||
import type { State as WalletState } from './wallet';
|
||||
|
||||
import { reducer as formReducer } from 'redux-form';
|
||||
import { combineReducers } from 'redux';
|
||||
import { routerReducer } from 'react-router-redux';
|
||||
@ -21,7 +24,8 @@ export type State = {
|
||||
generateWallet: GenerateWalletState,
|
||||
conig: ConfigState,
|
||||
notifications: NotificationsState,
|
||||
ens: EnsState
|
||||
ens: EnsState,
|
||||
wallet: WalletState
|
||||
};
|
||||
|
||||
export default combineReducers({
|
||||
@ -30,6 +34,7 @@ export default combineReducers({
|
||||
...swap,
|
||||
...notifications,
|
||||
...ens,
|
||||
...wallet,
|
||||
form: formReducer,
|
||||
routing: routerReducer
|
||||
});
|
||||
|
20
common/reducers/wallet.js
Normal file
20
common/reducers/wallet.js
Normal file
@ -0,0 +1,20 @@
|
||||
// @flow
|
||||
import type { WalletAction, SaveWalletAction } from 'actions/wallet';
|
||||
import BaseWallet from 'libs/wallet/base';
|
||||
|
||||
export type State = ?BaseWallet;
|
||||
|
||||
const initialState: State = null;
|
||||
|
||||
function saveWallet(state: State, action: SaveWalletAction): State {
|
||||
return action.payload;
|
||||
}
|
||||
|
||||
export function wallet(state: State = initialState, action: WalletAction): State {
|
||||
switch (action.type) {
|
||||
case 'WALLET_SAVE':
|
||||
return saveWallet(state, action);
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
}
|
@ -3,7 +3,6 @@ import { browserHistory, Redirect, Route } from 'react-router';
|
||||
import { useBasename } from 'history';
|
||||
import { App } from 'containers';
|
||||
import GenerateWallet from 'containers/Tabs/GenerateWallet';
|
||||
import WalletDecrypt from 'containers/Tabs/WalletDecrypt';
|
||||
import ViewWallet from 'containers/Tabs/ViewWallet';
|
||||
import Help from 'containers/Tabs/Help';
|
||||
import Swap from 'containers/Tabs/Swap';
|
||||
@ -13,7 +12,7 @@ export const history = getHistory();
|
||||
export const Routing = () =>
|
||||
<Route name="App" path="" component={App}>
|
||||
<Route name="GenerateWallet" path="/" component={GenerateWallet} />
|
||||
<Route name="ViewWallet" path="/view-wallet" component={WalletDecrypt} />
|
||||
<Route name="ViewWallet" path="/view-wallet" component={ViewWallet} />
|
||||
<Route name="Help" path="/help" component={Help} />
|
||||
<Route name="Swap" path="/swap" component={Swap} />
|
||||
<Route name="Send" path="/send-transaction" component={SendTransaction} />
|
||||
|
14
common/sagas/wallet.js
Normal file
14
common/sagas/wallet.js
Normal file
@ -0,0 +1,14 @@
|
||||
// @flow
|
||||
import { takeEvery, call, put, select } from 'redux-saga/effects';
|
||||
import { delay } from 'redux-saga';
|
||||
import { saveWallet } from 'actions/wallet';
|
||||
import type { UnlockPrivateKeyAction } from 'actions/wallet';
|
||||
import PrivKeyWallet from 'libs/wallet/privkey';
|
||||
|
||||
function* unlockPrivateKey(action: UnlockPrivateKeyAction) {
|
||||
yield put(saveWallet(new PrivKeyWallet(action.payload)));
|
||||
}
|
||||
|
||||
export default function* notificationsSaga() {
|
||||
yield takeEvery('WALLET_UNLOCK_PRIVATE_KEY', unlockPrivateKey);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user