William O'Beirne e7633c6d2f MyEtherWallet -> MyCrypto (#977)
* Replace all mentions of MyEtherWallet in translations with MyCrypto

* Replace all translation mentions of kvhnuke/etherwallet repo with MyCryptoHQ/MyCrypto repo.

* Replace all instances of MEW with MyCrypto in translations.

* Replace all instances of myetherwallet.com with mycrypto.com

* First pass of myetherwallet -> mycrypto in codebase.

* Replace most MEWs and mews with MyCrypto or MyC or myc

* Update all assets, clean out unused old assets.

* Adjust v3 url

* Convert all links to help articles to a help link component to make future changes easier.

* Rework onboarding images

* Adjust logo colors due to CMY issue.

* Update donation address, remove mentions of mewtopia.eth

* Update license

* Update sosh meed and referral links.

* Fix more translations strings.

* Tscheck fix.

* Update shapeshift api key.
2018-02-06 22:28:28 -06:00

469 lines
14 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React, { Component } from 'react';
import { connect } from 'react-redux';
import { Link } from 'react-router-dom';
import isEmpty from 'lodash/isEmpty';
import { TransitionGroup, CSSTransition } from 'react-transition-group';
import {
setWallet,
TSetWallet,
unlockKeystore,
TUnlockKeystore,
unlockMnemonic,
TUnlockMnemonic,
unlockPrivateKey,
TUnlockPrivateKey,
unlockWeb3,
TUnlockWeb3,
resetWallet,
TResetWallet
} from 'actions/wallet';
import { reset, TReset } from 'actions/transaction';
import translate from 'translations';
import {
KeystoreDecrypt,
LedgerNanoSDecrypt,
MnemonicDecrypt,
PrivateKeyDecrypt,
PrivateKeyValue,
TrezorDecrypt,
ViewOnlyDecrypt,
Web3Decrypt,
WalletButton,
InsecureWalletWarning
} from './components';
import { AppState } from 'reducers';
import { showNotification, TShowNotification } from 'actions/notifications';
import { getDisabledWallets } from 'selectors/wallet';
import { DisabledWallets } from './disables';
import {
SecureWalletName,
InsecureWalletName,
MiscWalletName,
WalletName,
isWeb3NodeAvailable,
knowledgeBaseURL,
donationAddressMap
} from 'config';
import LedgerIcon from 'assets/images/wallets/ledger.svg';
import MetamaskIcon from 'assets/images/wallets/metamask.svg';
import MistIcon from 'assets/images/wallets/mist.svg';
import TrezorIcon from 'assets/images/wallets/trezor.svg';
import './WalletDecrypt.scss';
interface OwnProps {
hidden?: boolean;
disabledWallets?: DisabledWallets;
showGenerateLink?: boolean;
}
interface DispatchProps {
unlockKeystore: TUnlockKeystore;
unlockMnemonic: TUnlockMnemonic;
unlockPrivateKey: TUnlockPrivateKey;
unlockWeb3: TUnlockWeb3;
setWallet: TSetWallet;
resetWallet: TResetWallet;
resetTransactionState: TReset;
showNotification: TShowNotification;
}
interface StateProps {
computedDisabledWallets: DisabledWallets;
isWalletPending: AppState['wallet']['isWalletPending'];
isPasswordPending: AppState['wallet']['isPasswordPending'];
}
type Props = OwnProps & StateProps & DispatchProps;
type UnlockParams = {} | PrivateKeyValue;
interface State {
selectedWalletKey: WalletName | null;
value: UnlockParams | null;
hasAcknowledgedInsecure: boolean;
}
interface BaseWalletInfo {
lid: string;
component: any;
initialParams: object;
unlock: any;
helpLink: string;
isReadOnly?: boolean;
attemptUnlock?: boolean;
}
export interface SecureWalletInfo extends BaseWalletInfo {
icon?: string;
description: string;
}
export interface InsecureWalletInfo extends BaseWalletInfo {
example: string;
}
// tslint:disable-next-line:no-empty-interface
interface MiscWalletInfo extends InsecureWalletInfo {}
const WEB3_TYPES = {
MetamaskInpageProvider: {
lid: 'x_MetaMask',
icon: MetamaskIcon
},
EthereumProvider: {
lid: 'x_Mist',
icon: MistIcon
}
};
type SecureWallets = { [key in SecureWalletName]: SecureWalletInfo };
type InsecureWallets = { [key in InsecureWalletName]: InsecureWalletInfo };
type MiscWallet = { [key in MiscWalletName]: MiscWalletInfo };
type Wallets = SecureWallets & InsecureWallets & MiscWallet;
const WEB3_TYPE: string | false =
(window as any).web3 && (window as any).web3.currentProvider.constructor.name;
const SECURE_WALLETS = Object.values(SecureWalletName);
const INSECURE_WALLETS = Object.values(InsecureWalletName);
const MISC_WALLETS = Object.values(MiscWalletName);
export class WalletDecrypt extends Component<Props, State> {
// https://github.com/Microsoft/TypeScript/issues/13042
// index signature should become [key: Wallets] (from config) once typescript bug is fixed
public WALLETS: Wallets = {
[SecureWalletName.WEB3]: {
lid: WEB3_TYPE ? WEB3_TYPES[WEB3_TYPE].lid : 'x_Web3',
icon: WEB3_TYPE && WEB3_TYPES[WEB3_TYPE].icon,
description: 'ADD_Web3Desc',
component: Web3Decrypt,
initialParams: {},
unlock: this.props.unlockWeb3,
attemptUnlock: true,
helpLink: `${knowledgeBaseURL}/migration/moving-from-private-key-to-metamask`
},
[SecureWalletName.LEDGER_NANO_S]: {
lid: 'x_Ledger',
icon: LedgerIcon,
description: 'ADD_HardwareDesc',
component: LedgerNanoSDecrypt,
initialParams: {},
unlock: this.props.setWallet,
helpLink:
'https://ledger.zendesk.com/hc/en-us/articles/115005200009-How-to-use-MyEtherWallet-with-Ledger'
},
[SecureWalletName.TREZOR]: {
lid: 'x_Trezor',
icon: TrezorIcon,
description: 'ADD_HardwareDesc',
component: TrezorDecrypt,
initialParams: {},
unlock: this.props.setWallet,
helpLink: 'https://doc.satoshilabs.com/trezor-apps/mew.html'
},
[InsecureWalletName.KEYSTORE_FILE]: {
lid: 'x_Keystore2',
example: 'UTC--2017-12-15T17-35-22.547Z--6be6e49e82425a5aa56396db03512f2cc10e95e8',
component: KeystoreDecrypt,
initialParams: {
file: '',
password: ''
},
unlock: this.props.unlockKeystore,
helpLink: `${knowledgeBaseURL}/private-keys-passwords/difference-beween-private-key-and-keystore-file.html`
},
[InsecureWalletName.MNEMONIC_PHRASE]: {
lid: 'x_Mnemonic',
example: 'brain surround have swap horror cheese file distinct',
component: MnemonicDecrypt,
initialParams: {},
unlock: this.props.unlockMnemonic,
helpLink: `${knowledgeBaseURL}/private-keys-passwords/difference-beween-private-key-and-keystore-file.html`
},
[InsecureWalletName.PRIVATE_KEY]: {
lid: 'x_PrivKey2',
example: 'f1d0e0789c6d40f399ca90cc674b7858de4c719e0d5752a60d5d2f6baa45d4c9',
component: PrivateKeyDecrypt,
initialParams: {
key: '',
password: ''
},
unlock: this.props.unlockPrivateKey,
helpLink: `${knowledgeBaseURL}/private-keys-passwords/difference-beween-private-key-and-keystore-file.html`
},
[MiscWalletName.VIEW_ONLY]: {
lid: 'View Address',
example: donationAddressMap.ETH,
component: ViewOnlyDecrypt,
initialParams: {},
unlock: this.props.setWallet,
helpLink: '',
isReadOnly: true
}
};
public state: State = {
selectedWalletKey: null,
value: null,
hasAcknowledgedInsecure: false
};
public componentWillReceiveProps(nextProps: Props) {
// Reset state when unlock is hidden / revealed
if (nextProps.hidden !== this.props.hidden) {
this.setState({
value: null,
selectedWalletKey: null
});
}
}
public getSelectedWallet() {
const { selectedWalletKey } = this.state;
if (!selectedWalletKey) {
return null;
}
return this.WALLETS[selectedWalletKey];
}
public getDecryptionComponent() {
const { selectedWalletKey, hasAcknowledgedInsecure } = this.state;
const selectedWallet = this.getSelectedWallet();
if (!selectedWalletKey || !selectedWallet) {
return null;
}
if (INSECURE_WALLETS.includes(selectedWalletKey) && !hasAcknowledgedInsecure) {
return (
<div className="WalletDecrypt-decrypt">
<InsecureWalletWarning
walletType={translate(selectedWallet.lid)}
onContinue={this.handleAcknowledgeInsecure}
onCancel={this.clearWalletChoice}
/>
</div>
);
}
return (
<div className="WalletDecrypt-decrypt">
<button className="WalletDecrypt-decrypt-back" onClick={this.clearWalletChoice}>
<i className="fa fa-arrow-left" /> {translate('Change Wallet')}
</button>
<h2 className="WalletDecrypt-decrypt-title">
{!selectedWallet.isReadOnly && 'Unlock your'} {translate(selectedWallet.lid)}
</h2>
<section className="WalletDecrypt-decrypt-form">
<selectedWallet.component
value={this.state.value}
onChange={this.onChange}
onUnlock={this.onUnlock}
showNotification={this.props.showNotification}
isWalletPending={
this.state.selectedWalletKey === InsecureWalletName.KEYSTORE_FILE
? this.props.isWalletPending
: undefined
}
isPasswordPending={
this.state.selectedWalletKey === InsecureWalletName.KEYSTORE_FILE
? this.props.isPasswordPending
: undefined
}
/>
</section>
</div>
);
}
public handleAcknowledgeInsecure = () => {
this.setState({ hasAcknowledgedInsecure: true });
};
public buildWalletOptions() {
const { computedDisabledWallets } = this.props;
const { reasons } = computedDisabledWallets;
return (
<div className="WalletDecrypt-wallets">
<h2 className="WalletDecrypt-wallets-title">{translate('decrypt_Access')}</h2>
<div className="WalletDecrypt-wallets-row">
{SECURE_WALLETS.map((walletType: SecureWalletName) => {
const wallet = this.WALLETS[walletType];
return (
<WalletButton
key={walletType}
name={translate(wallet.lid)}
description={translate(wallet.description)}
icon={wallet.icon}
helpLink={wallet.helpLink}
walletType={walletType}
isSecure={true}
isDisabled={this.isWalletDisabled(walletType)}
disableReason={reasons[walletType]}
onClick={this.handleWalletChoice}
/>
);
})}
</div>
<div className="WalletDecrypt-wallets-row">
{INSECURE_WALLETS.map((walletType: InsecureWalletName) => {
const wallet = this.WALLETS[walletType];
return (
<WalletButton
key={walletType}
name={translate(wallet.lid)}
example={wallet.example}
helpLink={wallet.helpLink}
walletType={walletType}
isSecure={false}
isDisabled={this.isWalletDisabled(walletType)}
disableReason={reasons[walletType]}
onClick={this.handleWalletChoice}
/>
);
})}
{MISC_WALLETS.map((walletType: MiscWalletName) => {
const wallet = this.WALLETS[walletType];
return (
<WalletButton
key={walletType}
name={translate(wallet.lid)}
example={wallet.example}
helpLink={wallet.helpLink}
walletType={walletType}
isReadOnly={true}
isDisabled={this.isWalletDisabled(walletType)}
disableReason={reasons[walletType]}
onClick={this.handleWalletChoice}
/>
);
})}
</div>
{this.props.showGenerateLink && (
<div className="WalletDecrypt-wallets-generate">
Dont have a wallet? <Link to="/generate">Click here to get one</Link>.
</div>
)}
</div>
);
}
public handleWalletChoice = async (walletType: WalletName) => {
const wallet = this.WALLETS[walletType];
if (!wallet) {
return;
}
let timeout = 0;
const web3Available = await isWeb3NodeAvailable();
if (wallet.attemptUnlock && web3Available) {
// timeout is only the maximum wait time before secondary view is shown
// send view will be shown immediately on web3 resolve
timeout = 1000;
wallet.unlock();
}
window.setTimeout(() => {
this.setState({
selectedWalletKey: walletType,
value: wallet.initialParams,
hasAcknowledgedInsecure: false
});
}, timeout);
};
public clearWalletChoice = () => {
this.setState({
selectedWalletKey: null,
value: null,
hasAcknowledgedInsecure: false
});
};
public render() {
const { hidden } = this.props;
const selectedWallet = this.getSelectedWallet();
const decryptionComponent = this.getDecryptionComponent();
return (
<div>
{!hidden && (
<article className="Tab-content-pane">
<div className="WalletDecrypt">
<TransitionGroup>
{decryptionComponent && selectedWallet ? (
<CSSTransition classNames="DecryptContent" timeout={500} key="decrypt">
{decryptionComponent}
</CSSTransition>
) : (
<CSSTransition classNames="DecryptContent" timeout={500} key="wallets">
{this.buildWalletOptions()}
</CSSTransition>
)}
</TransitionGroup>
</div>
</article>
)}
</div>
);
}
public onChange = (value: UnlockParams) => {
this.setState({ value });
};
public onUnlock = (payload: any) => {
const { value, selectedWalletKey } = this.state;
if (!selectedWalletKey) {
return;
}
// some components (TrezorDecrypt) don't take an onChange prop, and thus
// this.state.value will remain unpopulated. in this case, we can expect
// the payload to contain the unlocked wallet info.
const unlockValue = value && !isEmpty(value) ? value : payload;
this.WALLETS[selectedWalletKey].unlock(unlockValue);
this.props.resetTransactionState();
};
private isWalletDisabled = (walletKey: WalletName) => {
return this.props.computedDisabledWallets.wallets.indexOf(walletKey) !== -1;
};
}
function mapStateToProps(state: AppState, ownProps: Props) {
const { disabledWallets } = ownProps;
let computedDisabledWallets = getDisabledWallets(state);
if (disabledWallets) {
computedDisabledWallets = {
wallets: [...computedDisabledWallets.wallets, ...disabledWallets.wallets],
reasons: {
...computedDisabledWallets.reasons,
...disabledWallets.reasons
}
};
}
return {
computedDisabledWallets,
isWalletPending: state.wallet.isWalletPending,
isPasswordPending: state.wallet.isPasswordPending
};
}
export default connect<StateProps, DispatchProps>(mapStateToProps, {
unlockKeystore,
unlockMnemonic,
unlockPrivateKey,
unlockWeb3,
setWallet,
resetWallet,
resetTransactionState: reset,
showNotification
})(WalletDecrypt);