mirror of
https://github.com/status-im/MyCrypto.git
synced 2025-01-24 01:49:06 +00:00
commit
16232d6afd
@ -1,8 +1,11 @@
|
||||
# MyCrypto Beta RC (VISIT [MyCryptoHQ/mycrypto.com](https://github.com/MyCryptoHQ/mycrypto.com) for the current site)<br/>Just looking to download? Grab our [latest release](https://github.com/MyCryptoHQ/MyCrypto/releases)
|
||||
# MyCrypto Web & Desktop Apps
|
||||
|
||||
[![Greenkeeper badge](https://badges.greenkeeper.io/MyCryptoHq/MyCrypto.svg)](https://greenkeeper.io/)
|
||||
[![Coverage Status](https://coveralls.io/repos/github/MyCryptoHQ/MyCrypto/badge.svg?branch=develop)](https://coveralls.io/github/MyCryptoHQ/MyCrypto?branch=develop)
|
||||
|
||||
* **Just looking to download?** Grab our [latest release](https://github.com/MyCryptoHQ/MyCrypto/releases).
|
||||
* **Looking for the old site?** Check out [https://legacy.mycrypto.com](https://legacy.mycrypto.com) or the source at [MyCryptoHQ/mycrypto.com](https://github.com/MyCryptoHQ/mycrypto.com)
|
||||
|
||||
## Running the App
|
||||
|
||||
This codebase targets Node 8.9.4 (LTS). After `npm install`ing all dependencies (You may be required to install additional system dependencies, due to some node modules relying on them) you can run various commands depending on what you want to do:
|
||||
@ -132,3 +135,4 @@ npm run test:int
|
||||
</a>
|
||||
|
||||
Cross browser testing and debugging provided by the very lovely team at BrowserStack.
|
||||
|
||||
|
@ -15,8 +15,9 @@ import ErrorScreen from 'components/ErrorScreen';
|
||||
import PageNotFound from 'components/PageNotFound';
|
||||
import LogOutPrompt from 'components/LogOutPrompt';
|
||||
import QrSignerModal from 'containers/QrSignerModal';
|
||||
import OnboardModal from 'containers/OnboardModal';
|
||||
import WelcomeModal from 'components/WelcomeModal';
|
||||
import NewAppReleaseModal from 'components/NewAppReleaseModal';
|
||||
import { TitleBar } from 'components/ui';
|
||||
import { Store } from 'redux';
|
||||
import { pollOfflineStatus, TPollOfflineStatus } from 'actions/config';
|
||||
import { AppState } from 'reducers';
|
||||
@ -104,12 +105,17 @@ class RootClass extends Component<Props, State> {
|
||||
<Provider store={store} key={Math.random()}>
|
||||
<Router key={Math.random()}>
|
||||
<React.Fragment>
|
||||
{process.env.BUILD_ELECTRON && <TitleBar />}
|
||||
{routes}
|
||||
<LegacyRoutes />
|
||||
<LogOutPrompt />
|
||||
<QrSignerModal />
|
||||
{process.env.BUILD_ELECTRON && <NewAppReleaseModal />}
|
||||
{!process.env.DOWNLOADABLE_BUILD && (
|
||||
<React.Fragment>
|
||||
<OnboardModal />
|
||||
{!process.env.BUILD_ELECTRON && <WelcomeModal />}
|
||||
</React.Fragment>
|
||||
)}
|
||||
</React.Fragment>
|
||||
</Router>
|
||||
</Provider>
|
||||
|
BIN
common/assets/images/link-preview.png
Normal file
BIN
common/assets/images/link-preview.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 60 KiB |
@ -21,7 +21,7 @@ export const AddressField: React.SFC<Props> = ({ isReadOnly, isSelfAddress, isCh
|
||||
{translate(isSelfAddress ? 'X_ADDRESS' : 'SEND_ADDR')}
|
||||
</div>
|
||||
<Input
|
||||
className={`input-group-input ${isValid ? '' : 'invalid'}`}
|
||||
isValid={isValid}
|
||||
type="text"
|
||||
value={isCheckSummed ? toChecksumAddress(currentTo.raw) : currentTo.raw}
|
||||
placeholder={donationAddressMap.ETH}
|
||||
|
@ -23,9 +23,7 @@ export const AmountField: React.SFC<Props> = ({
|
||||
<label className="AmountField-group input-group input-group-inline">
|
||||
<div className="input-group-header">{translate('SEND_AMOUNT_SHORT')}</div>
|
||||
<Input
|
||||
className={`input-group-input ${
|
||||
isAmountValid(raw, customValidator, isValid) ? '' : 'invalid'
|
||||
}`}
|
||||
isValid={isAmountValid(raw, customValidator, isValid)}
|
||||
type="number"
|
||||
placeholder="1"
|
||||
value={raw}
|
||||
|
@ -88,7 +88,7 @@ class EquivalentValues extends React.Component<Props, State> {
|
||||
};
|
||||
}
|
||||
|
||||
public componentWillReceiveProps(nextProps: Props) {
|
||||
public UNSAFE_componentWillReceiveProps(nextProps: Props) {
|
||||
const { balance, tokenBalances, isOffline, network } = this.props;
|
||||
if (
|
||||
nextProps.balance !== balance ||
|
||||
|
@ -16,8 +16,13 @@ interface IGenerateSymbolLookup {
|
||||
[tokenSymbol: string]: boolean;
|
||||
}
|
||||
|
||||
interface IGenerateAddressLookup {
|
||||
[address: string]: boolean;
|
||||
}
|
||||
|
||||
interface State {
|
||||
tokenSymbolLookup: IGenerateSymbolLookup;
|
||||
tokenAddressLookup: IGenerateAddressLookup;
|
||||
address: string;
|
||||
symbol: string;
|
||||
decimal: string;
|
||||
@ -25,20 +30,13 @@ interface State {
|
||||
|
||||
export default class AddCustomTokenForm extends React.PureComponent<Props, State> {
|
||||
public state: State = {
|
||||
tokenSymbolLookup: {},
|
||||
tokenSymbolLookup: this.generateSymbolLookup(),
|
||||
tokenAddressLookup: this.generateAddressMap(),
|
||||
address: '',
|
||||
symbol: '',
|
||||
decimal: ''
|
||||
};
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
...this.state,
|
||||
tokenSymbolLookup: this.generateSymbolLookup(props.allTokens)
|
||||
};
|
||||
}
|
||||
|
||||
public render() {
|
||||
const { address, symbol, decimal } = this.state;
|
||||
const errors = this.getErrors();
|
||||
@ -68,15 +66,14 @@ export default class AddCustomTokenForm extends React.PureComponent<Props, State
|
||||
<label className="AddCustom-field form-group" key={field.name}>
|
||||
<div className="input-group-header">{field.label}</div>
|
||||
<Input
|
||||
className={`${
|
||||
errors[field.name] ? 'invalid' : field.value ? 'valid' : ''
|
||||
} input-group-input-small`}
|
||||
isValid={!errors[field.name]}
|
||||
className="input-group-input-small"
|
||||
type="text"
|
||||
name={field.name}
|
||||
value={field.value}
|
||||
onChange={this.onFieldChange}
|
||||
/>
|
||||
{typeof errors[field.name] === 'string' && (
|
||||
{errors[field.name] && (
|
||||
<div className="AddCustom-field-error">{errors[field.name]}</div>
|
||||
)}
|
||||
</label>
|
||||
@ -106,14 +103,19 @@ export default class AddCustomTokenForm extends React.PureComponent<Props, State
|
||||
|
||||
public getErrors() {
|
||||
const { address, symbol, decimal } = this.state;
|
||||
const errors: { [key: string]: boolean | string } = {};
|
||||
const errors: { [key: string]: string } = {};
|
||||
|
||||
// Formatting errors
|
||||
if (decimal && !isPositiveIntegerOrZero(parseInt(decimal, 10))) {
|
||||
errors.decimal = true;
|
||||
if (decimal && !isPositiveIntegerOrZero(Number(decimal))) {
|
||||
errors.decimal = 'Invalid decimal';
|
||||
}
|
||||
if (address && !isValidETHAddress(address)) {
|
||||
errors.address = true;
|
||||
if (address) {
|
||||
if (!isValidETHAddress(address)) {
|
||||
errors.address = 'Not a valid address';
|
||||
}
|
||||
if (this.state.tokenAddressLookup[address]) {
|
||||
errors.address = 'A token with this address already exists';
|
||||
}
|
||||
}
|
||||
|
||||
// Message errors
|
||||
@ -146,13 +148,19 @@ export default class AddCustomTokenForm extends React.PureComponent<Props, State
|
||||
this.props.onSave({ address, symbol, decimal: parseInt(decimal, 10) });
|
||||
};
|
||||
|
||||
private generateSymbolLookup(tokens: Token[]) {
|
||||
return tokens.reduce(
|
||||
(prev, tk) => {
|
||||
prev[tk.symbol] = true;
|
||||
return prev;
|
||||
},
|
||||
{} as IGenerateSymbolLookup
|
||||
);
|
||||
private generateSymbolLookup() {
|
||||
return this.tknArrToMap('symbol');
|
||||
}
|
||||
|
||||
private generateAddressMap() {
|
||||
return this.tknArrToMap('address');
|
||||
}
|
||||
|
||||
private tknArrToMap(key: Exclude<keyof Token, 'error'>) {
|
||||
const tokens = this.props.allTokens;
|
||||
return tokens.reduce<{ [k: string]: boolean }>((prev, tk) => {
|
||||
prev[tk[key]] = true;
|
||||
return prev;
|
||||
}, {});
|
||||
}
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ interface TrackedTokens {
|
||||
}
|
||||
|
||||
interface State {
|
||||
trackedTokens: { [symbol: string]: boolean };
|
||||
trackedTokens: TrackedTokens;
|
||||
showCustomTokenForm: boolean;
|
||||
}
|
||||
export default class TokenBalances extends React.PureComponent<Props, State> {
|
||||
@ -29,10 +29,10 @@ export default class TokenBalances extends React.PureComponent<Props, State> {
|
||||
showCustomTokenForm: false
|
||||
};
|
||||
|
||||
public componentWillReceiveProps(nextProps: Props) {
|
||||
public UNSAFE_componentWillReceiveProps(nextProps: Props) {
|
||||
if (nextProps.tokenBalances !== this.props.tokenBalances) {
|
||||
const trackedTokens = nextProps.tokenBalances.reduce<TrackedTokens>((prev, t) => {
|
||||
prev[t.symbol] = !t.balance.isZero();
|
||||
prev[t.symbol] = !t.balance.isZero() || t.custom;
|
||||
return prev;
|
||||
}, {});
|
||||
this.setState({ trackedTokens });
|
||||
@ -45,7 +45,7 @@ export default class TokenBalances extends React.PureComponent<Props, State> {
|
||||
|
||||
let bottom;
|
||||
let help;
|
||||
if (tokenBalances.length && !hasSavedWalletTokens) {
|
||||
if (tokenBalances.length && !hasSavedWalletTokens && !this.onlyCustomTokens()) {
|
||||
help = 'Select which tokens you would like to keep track of';
|
||||
bottom = (
|
||||
<div className="TokenBalances-buttons">
|
||||
@ -134,6 +134,24 @@ export default class TokenBalances extends React.PureComponent<Props, State> {
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @description Checks if all currently tracked tokens are custom
|
||||
* @private
|
||||
* @returns
|
||||
* @memberof TokenBalances
|
||||
*/
|
||||
private onlyCustomTokens() {
|
||||
const tokenMap = this.props.tokenBalances.reduce<{ [key: string]: TokenBalance }>(
|
||||
(acc, cur) => ({ ...acc, [cur.symbol]: cur }),
|
||||
{}
|
||||
);
|
||||
|
||||
return Object.keys(this.state.trackedTokens).reduce(
|
||||
(prev, tokenName) => tokenMap[tokenName].custom && prev,
|
||||
true
|
||||
);
|
||||
}
|
||||
private addCustomToken = (token: Token) => {
|
||||
this.props.onAddCustomToken(token);
|
||||
this.setState({ showCustomTokenForm: false });
|
||||
|
@ -30,11 +30,14 @@ export default class TokenRow extends React.PureComponent<Props, State> {
|
||||
|
||||
return (
|
||||
<tr className="TokenRow" onClick={this.handleToggleTracked}>
|
||||
{this.props.toggleTracked && (
|
||||
<td className="TokenRow-toggled">
|
||||
<input type="checkbox" checked={tracked} />
|
||||
</td>
|
||||
)}
|
||||
{/* Only allow to toggle tracking on non custom tokens
|
||||
because the user can just remove the custom token instead */}
|
||||
{!this.props.custom &&
|
||||
this.props.toggleTracked && (
|
||||
<td className="TokenRow-toggled">
|
||||
<input type="checkbox" checked={tracked} />
|
||||
</td>
|
||||
)}
|
||||
<td
|
||||
className="TokenRow-balance"
|
||||
title={`${balance.toString()} (Double-Click)`}
|
||||
|
@ -1,66 +0,0 @@
|
||||
@import 'common/sass/variables';
|
||||
@import 'common/sass/mixins';
|
||||
|
||||
.BetaAgreement {
|
||||
@include cover-message;
|
||||
background: $brand-info;
|
||||
|
||||
&-content {
|
||||
h2 {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
&-buttons {
|
||||
padding-top: 20px;
|
||||
|
||||
&-btn {
|
||||
display: block;
|
||||
width: 100%;
|
||||
max-width: 280px;
|
||||
margin: 0 auto;
|
||||
border: none;
|
||||
padding: 0;
|
||||
transition: $transition;
|
||||
|
||||
&.is-continue {
|
||||
height: 60px;
|
||||
line-height: 60px;
|
||||
font-size: 22px;
|
||||
background: rgba(#fff, 0.96);
|
||||
color: $gray-dark;
|
||||
border-radius: 4px;
|
||||
margin-bottom: 20px;
|
||||
|
||||
&:hover {
|
||||
background: #fff;
|
||||
color: $gray-darker;
|
||||
}
|
||||
}
|
||||
|
||||
&.is-reject {
|
||||
background: none;
|
||||
color: #fff;
|
||||
opacity: 0.7;
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fade out
|
||||
&.is-fading {
|
||||
pointer-events: none;
|
||||
opacity: 0;
|
||||
background: #fff;
|
||||
transition: all 500ms ease 400ms;
|
||||
|
||||
.BetaAgreement-content {
|
||||
opacity: 0;
|
||||
transform: translateY(15px);
|
||||
transition: all 500ms ease;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,73 +0,0 @@
|
||||
import React from 'react';
|
||||
import { NewTabLink } from 'components/ui';
|
||||
import { discordURL } from 'config';
|
||||
import './index.scss';
|
||||
|
||||
const LS_KEY = 'acknowledged-beta';
|
||||
|
||||
interface State {
|
||||
isFading: boolean;
|
||||
hasAcknowledged: boolean;
|
||||
}
|
||||
export default class BetaAgreement extends React.PureComponent<{}, State> {
|
||||
public state = {
|
||||
hasAcknowledged: !!localStorage.getItem(LS_KEY),
|
||||
isFading: false
|
||||
};
|
||||
|
||||
public render() {
|
||||
if (this.state.hasAcknowledged) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const isFading = this.state.isFading ? 'is-fading' : '';
|
||||
|
||||
return (
|
||||
<div className={`BetaAgreement ${isFading}`}>
|
||||
<div className="BetaAgreement-content">
|
||||
<h2>Welcome to the New MyCrypto Beta Release Candidate!</h2>
|
||||
<p>
|
||||
You are about to use the new MyCrypto Beta Release Candidate. Although this is a release
|
||||
candidate for production, we encourage caution while using this unreleased version of
|
||||
MyCrypto.
|
||||
</p>
|
||||
<p>We hope to move this version of MyCrypto into production in the near future!</p>
|
||||
<p>
|
||||
Feedback and bug reports are greatly appreciated. You can file issues on our{' '}
|
||||
<NewTabLink href="https://github.com/MyCryptoHQ/MyCrypto/issues">
|
||||
GitHub repository
|
||||
</NewTabLink>{' '}
|
||||
or join our <NewTabLink href={discordURL}>Discord server</NewTabLink> to discuss the
|
||||
beta.
|
||||
</p>
|
||||
<p>Are you sure you would like to continue?</p>
|
||||
|
||||
<div className="BetaAgreement-content-buttons">
|
||||
<button
|
||||
className="BetaAgreement-content-buttons-btn is-continue"
|
||||
onClick={this.doContinue}
|
||||
>
|
||||
Yes, continue to the Beta RC
|
||||
</button>
|
||||
<button className="BetaAgreement-content-buttons-btn is-reject" onClick={this.reject}>
|
||||
No, take me to the production site
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
private doContinue = () => {
|
||||
localStorage.setItem(LS_KEY, 'true');
|
||||
this.setState({ isFading: true });
|
||||
|
||||
setTimeout(() => {
|
||||
this.setState({ hasAcknowledged: true });
|
||||
}, 1000);
|
||||
};
|
||||
|
||||
private reject = () => {
|
||||
window.location.assign('https://mycrypto.com');
|
||||
};
|
||||
}
|
@ -20,7 +20,12 @@ class DetailsClass extends Component<StateProps> {
|
||||
<div className="tx-modal-details">
|
||||
<label className="input-group">
|
||||
<div className="input-group-header">Network</div>
|
||||
<Input readOnly={true} value={`${network} network - provided by ${service}`} />
|
||||
<Input
|
||||
isValid={true}
|
||||
showValidAsPlain={true}
|
||||
readOnly={true}
|
||||
value={`${network} network - provided by ${service}`}
|
||||
/>
|
||||
</label>
|
||||
|
||||
<SerializedTransaction
|
||||
|
@ -29,7 +29,7 @@ class CurrentCustomMessageClass extends PureComponent<Props, State> {
|
||||
this.setAddressState(this.props);
|
||||
}
|
||||
|
||||
public componentWillReceiveProps(nextProps: Props) {
|
||||
public UNSAFE_componentWillReceiveProps(nextProps: Props) {
|
||||
if (this.props.wallet !== nextProps.wallet) {
|
||||
this.setAddressState(nextProps);
|
||||
}
|
||||
|
@ -117,7 +117,7 @@ class CustomNodeModal extends React.Component<Props, State> {
|
||||
<label className="col-sm-9 input-group flex-grow-1">
|
||||
<div className="input-group-header">{translate('CUSTOM_NODE_NAME')}</div>
|
||||
<Input
|
||||
className={`input-group-input ${this.state.name && invalids.name ? 'invalid' : ''}`}
|
||||
isValid={!(this.state.name && invalids.name)}
|
||||
type="text"
|
||||
placeholder="My Node"
|
||||
value={this.state.name}
|
||||
@ -142,9 +142,7 @@ class CustomNodeModal extends React.Component<Props, State> {
|
||||
<label className="col-sm-6 input-group input-group-inline">
|
||||
<div className="input-group-header">{translate('CUSTOM_NETWORK_NAME')}</div>
|
||||
<Input
|
||||
className={`input-group-input ${
|
||||
this.state.customNetworkId && invalids.customNetworkId ? 'invalid' : ''
|
||||
}`}
|
||||
isValid={!(this.state.customNetworkId && invalids.customNetworkId)}
|
||||
type="text"
|
||||
placeholder="My Custom Network"
|
||||
value={this.state.customNetworkId}
|
||||
@ -154,9 +152,7 @@ class CustomNodeModal extends React.Component<Props, State> {
|
||||
<label className="col-sm-3 input-group input-group-inline">
|
||||
<div className="input-group-header">{translate('CUSTOM_NETWORK_CURRENCY')}</div>
|
||||
<Input
|
||||
className={`input-group-input ${
|
||||
this.state.customNetworkUnit && invalids.customNetworkUnit ? 'invalid' : ''
|
||||
}`}
|
||||
isValid={!(this.state.customNetworkUnit && invalids.customNetworkUnit)}
|
||||
type="text"
|
||||
placeholder="ETH"
|
||||
value={this.state.customNetworkUnit}
|
||||
@ -166,11 +162,7 @@ class CustomNodeModal extends React.Component<Props, State> {
|
||||
<label className="col-sm-3 input-group input-group-inline">
|
||||
<div className="input-group-header">{translate('CUSTOM_NETWORK_CHAIN_ID')}</div>
|
||||
<Input
|
||||
className={`input-group-input ${
|
||||
this.state.customNetworkChainId && invalids.customNetworkChainId
|
||||
? 'invalid'
|
||||
: ''
|
||||
}`}
|
||||
isValid={!(this.state.customNetworkChainId && invalids.customNetworkChainId)}
|
||||
type="text"
|
||||
placeholder="1"
|
||||
value={this.state.customNetworkChainId}
|
||||
@ -183,7 +175,7 @@ class CustomNodeModal extends React.Component<Props, State> {
|
||||
<label className="input-group input-group-inline">
|
||||
<div className="input-group-header">{translate('CUSTOM_NETWORK_URL')}</div>
|
||||
<Input
|
||||
className={`input-group-input ${this.state.url && invalids.url ? 'invalid' : ''}`}
|
||||
isValid={!(this.state.url && invalids.url)}
|
||||
type="text"
|
||||
placeholder="https://127.0.0.1:8545/"
|
||||
value={this.state.url}
|
||||
@ -207,9 +199,7 @@ class CustomNodeModal extends React.Component<Props, State> {
|
||||
<label className="col-sm-6 input-group input-group-inline">
|
||||
<div className="input-group-header">{translate('INPUT_USERNAME_LABEL')}</div>
|
||||
<Input
|
||||
className={`input-group-input ${
|
||||
this.state.username && invalids.username ? 'invalid' : ''
|
||||
}`}
|
||||
isValid={!(this.state.username && invalids.username)}
|
||||
type="text"
|
||||
value={this.state.username}
|
||||
onChange={e => this.setState({ username: e.currentTarget.value })}
|
||||
@ -218,9 +208,7 @@ class CustomNodeModal extends React.Component<Props, State> {
|
||||
<label className="col-sm-6 input-group input-group-inline">
|
||||
<div className="input-group-header">{translate('INPUT_PASSWORD_LABEL')}</div>
|
||||
<Input
|
||||
className={`input-group-input ${
|
||||
this.state.password && invalids.password ? 'invalid' : ''
|
||||
}`}
|
||||
isValid={!(this.state.password && invalids.password)}
|
||||
type="password"
|
||||
value={this.state.password}
|
||||
onChange={e => this.setState({ password: e.currentTarget.value })}
|
||||
|
@ -6,12 +6,12 @@ import { Input } from 'components/ui';
|
||||
|
||||
export const DataField: React.SFC<{}> = () => (
|
||||
<DataFieldFactory
|
||||
withProps={({ data: { raw }, dataExists, onChange, readOnly }) => (
|
||||
withProps={({ data: { raw }, validData, onChange, readOnly }) => (
|
||||
<div className="input-group-wrapper">
|
||||
<label className="input-group">
|
||||
<div className="input-group-header">{translate('OFFLINE_STEP2_LABEL_6')}</div>
|
||||
<Input
|
||||
className={dataExists ? 'is-valid' : 'is-invalid'}
|
||||
isValid={validData}
|
||||
type="text"
|
||||
placeholder={donationAddressMap.ETH}
|
||||
value={raw}
|
||||
|
@ -7,7 +7,7 @@ import { isEtherTransaction } from 'selectors/transaction';
|
||||
import { AppState } from 'reducers';
|
||||
export interface CallBackProps {
|
||||
data: AppState['transaction']['fields']['data'];
|
||||
dataExists: boolean;
|
||||
validData: boolean;
|
||||
readOnly: boolean;
|
||||
onChange(ev: React.FormEvent<HTMLInputElement | HTMLTextAreaElement>): void;
|
||||
}
|
||||
|
@ -1,9 +1,10 @@
|
||||
import React, { Component } from 'react';
|
||||
import { Query } from 'components/renderCbs';
|
||||
import { getData, getDataExists } from 'selectors/transaction';
|
||||
import { getData } from 'selectors/transaction';
|
||||
import { connect } from 'react-redux';
|
||||
import { AppState } from 'reducers';
|
||||
import { CallBackProps } from 'components/DataFieldFactory';
|
||||
import { isHexString } from 'ethereumjs-util';
|
||||
|
||||
interface OwnProps {
|
||||
withProps(props: CallBackProps): React.ReactElement<any> | null;
|
||||
@ -11,19 +12,19 @@ interface OwnProps {
|
||||
}
|
||||
interface StateProps {
|
||||
data: AppState['transaction']['fields']['data'];
|
||||
dataExists: boolean;
|
||||
validData: boolean;
|
||||
}
|
||||
|
||||
type Props = OwnProps & StateProps;
|
||||
|
||||
class DataInputClass extends Component<Props> {
|
||||
public render() {
|
||||
const { data, onChange, dataExists } = this.props;
|
||||
const { data, onChange, validData } = this.props;
|
||||
return (
|
||||
<Query
|
||||
params={['readOnly']}
|
||||
withQuery={({ readOnly }) =>
|
||||
this.props.withProps({ data, onChange, readOnly: !!readOnly, dataExists })
|
||||
this.props.withProps({ data, onChange, readOnly: !!readOnly, validData })
|
||||
}
|
||||
/>
|
||||
);
|
||||
@ -32,5 +33,5 @@ class DataInputClass extends Component<Props> {
|
||||
|
||||
export const DataInput = connect((state: AppState) => ({
|
||||
data: getData(state),
|
||||
dataExists: getDataExists(state)
|
||||
validData: getData(state).raw === '' || isHexString(getData(state).raw)
|
||||
}))(DataInputClass);
|
||||
|
@ -12,7 +12,6 @@ import React from 'react';
|
||||
import PreFooter from './PreFooter';
|
||||
import DisclaimerModal from 'components/DisclaimerModal';
|
||||
import { NewTabLink } from 'components/ui';
|
||||
import OnboardModal from 'containers/OnboardModal';
|
||||
import './index.scss';
|
||||
import { translateRaw } from 'translations';
|
||||
|
||||
@ -82,6 +81,9 @@ export default class Footer extends React.PureComponent<Props, State> {
|
||||
<NewTabLink href="https://about.mycrypto.com">
|
||||
{translateRaw('FOOTER_TEAM')}
|
||||
</NewTabLink>
|
||||
<NewTabLink href="https://about.mycrypto.com/privacy/">
|
||||
{translateRaw('FOOTER_PRIVACY_POLICY')}
|
||||
</NewTabLink>
|
||||
</div>
|
||||
|
||||
<p className="Footer-about-text">{translateRaw('FOOTER_ABOUT')}</p>
|
||||
@ -130,8 +132,6 @@ export default class Footer extends React.PureComponent<Props, State> {
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<OnboardModal />
|
||||
<DisclaimerModal isOpen={this.state.isDisclaimerOpen} handleClose={this.toggleModal} />
|
||||
</div>
|
||||
);
|
||||
|
@ -30,7 +30,7 @@ export const GasLimitField: React.SFC<Props> = ({
|
||||
/>
|
||||
</div>
|
||||
<Input
|
||||
className={gasLimitValidator(raw) ? 'is-valid' : 'is-invalid'}
|
||||
isValid={gasLimitValidator(raw)}
|
||||
type="number"
|
||||
placeholder="21000"
|
||||
readOnly={!!readOnly}
|
||||
|
@ -41,7 +41,7 @@ export default class GenerateKeystoreModal extends React.Component<Props, State>
|
||||
}
|
||||
}
|
||||
|
||||
public componentWillReceiveProps(nextProps: Props) {
|
||||
public UNSAFE_componentWillReceiveProps(nextProps: Props) {
|
||||
if (nextProps.privateKey !== this.props.privateKey) {
|
||||
this.setState({ privateKey: nextProps.privateKey || '' });
|
||||
}
|
||||
|
@ -12,7 +12,6 @@
|
||||
|
||||
.OnlineStatus {
|
||||
position: relative;
|
||||
top: -2px;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
text-align: center;
|
||||
|
@ -7,8 +7,8 @@ interface Props {
|
||||
}
|
||||
|
||||
const OnlineStatus: React.SFC<Props> = ({ isOffline }) => (
|
||||
<div className={`OnlineStatus fa-stack ${isOffline ? 'is-offline' : 'is-online'}`}>
|
||||
<Tooltip>{isOffline ? 'Offline' : 'Online'}</Tooltip>
|
||||
<div className={`OnlineStatus ${isOffline ? 'is-offline' : 'is-online'}`}>
|
||||
<Tooltip direction="left">{isOffline ? 'Offline' : 'Online'}</Tooltip>
|
||||
</div>
|
||||
);
|
||||
|
||||
|
@ -1,27 +1,12 @@
|
||||
import React from 'react';
|
||||
import translate, { translateRaw } from 'translations';
|
||||
import Modal, { IButton } from 'components/ui/Modal';
|
||||
import { VERSION_RC } from 'config';
|
||||
import { isNewerVersion } from 'utils/helpers';
|
||||
|
||||
interface IGitHubRelease {
|
||||
tag_name: string;
|
||||
}
|
||||
|
||||
function getLatestGitHubRelease(): Promise<IGitHubRelease> {
|
||||
return fetch('https://api.github.com/repos/MyCryptoHQ/MyCrypto/releases/latest', {
|
||||
method: 'GET',
|
||||
mode: 'cors',
|
||||
headers: {
|
||||
'content-type': 'application/json; charset=utf-8'
|
||||
}
|
||||
})
|
||||
.then(res => res.json())
|
||||
.then(data => data as IGitHubRelease);
|
||||
}
|
||||
import { getLatestElectronRelease } from 'utils/versioning';
|
||||
import { VERSION } from 'config/data';
|
||||
|
||||
interface State {
|
||||
isOpen: boolean;
|
||||
newRelease?: string;
|
||||
}
|
||||
|
||||
export default class NewAppReleaseModal extends React.Component<{}, State> {
|
||||
@ -31,10 +16,9 @@ export default class NewAppReleaseModal extends React.Component<{}, State> {
|
||||
|
||||
public async componentDidMount() {
|
||||
try {
|
||||
const release = await getLatestGitHubRelease();
|
||||
// TODO: Use VERSION once done with release candidates
|
||||
if (isNewerVersion(VERSION_RC, release.tag_name)) {
|
||||
this.setState({ isOpen: true });
|
||||
const newRelease = await getLatestElectronRelease();
|
||||
if (newRelease) {
|
||||
this.setState({ isOpen: true, newRelease });
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('Failed to fetch latest release from GitHub:', err);
|
||||
@ -64,11 +48,22 @@ export default class NewAppReleaseModal extends React.Component<{}, State> {
|
||||
handleClose={this.close}
|
||||
maxWidth={520}
|
||||
>
|
||||
<h5>{translateRaw('APP_UPDATE_BODY')}</h5>
|
||||
<h4>
|
||||
{translateRaw('APP_UPDATE_BODY')} {this.versionCompareStr()}
|
||||
</h4>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
private versionCompareStr() {
|
||||
return (
|
||||
<>
|
||||
<h5>Current Version: {VERSION}</h5>
|
||||
<h5>New Version: {this.state.newRelease}</h5>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
private close = () => {
|
||||
this.setState({ isOpen: false });
|
||||
};
|
||||
|
@ -42,7 +42,8 @@ class NonceField extends React.Component<Props> {
|
||||
/>
|
||||
</div>
|
||||
<Input
|
||||
className={`Nonce-field-input ${!!value ? 'is-valid' : 'is-invalid'}`}
|
||||
isValid={!!value}
|
||||
className="Nonce-field-input"
|
||||
type="number"
|
||||
placeholder="7"
|
||||
value={raw}
|
||||
|
@ -64,7 +64,7 @@ class OnlineSendClass extends Component<Props, State> {
|
||||
);
|
||||
}
|
||||
|
||||
public componentWillReceiveProps(nextProps: Props) {
|
||||
public UNSAFE_componentWillReceiveProps(nextProps: Props) {
|
||||
if (nextProps.transactionBroadcasted && this.state.showModal) {
|
||||
this.closeModal();
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ export default class SubTabs extends React.PureComponent<Props, State> {
|
||||
window.removeEventListener('resize', this.handleResize);
|
||||
}
|
||||
|
||||
public componentWillReceiveProps(nextProps: Props) {
|
||||
public UNSAFE_componentWillReceiveProps(nextProps: Props) {
|
||||
// When new tabs come in, we'll need to uncollapse so that they can
|
||||
// be measured and collapsed again, if needed.
|
||||
if (this.props.tabs !== nextProps.tabs) {
|
||||
|
@ -76,7 +76,7 @@ class TXMetaDataPanel extends React.Component<Props, State> {
|
||||
}
|
||||
}
|
||||
|
||||
public componentWillReceiveProps(nextProps: Props) {
|
||||
public UNSAFE_componentWillReceiveProps(nextProps: Props) {
|
||||
if (
|
||||
(this.props.offline && !nextProps.offline) ||
|
||||
this.props.network.unit !== nextProps.network.unit
|
||||
|
@ -9,7 +9,6 @@ import { NonceField, GasLimitField, DataField } from 'components';
|
||||
import { connect } from 'react-redux';
|
||||
import { getAutoGasLimitEnabled } from 'selectors/config';
|
||||
import { isValidGasPrice } from 'selectors/transaction';
|
||||
import { sanitizeNumericalInput } from 'libs/values';
|
||||
import { Input } from 'components/ui';
|
||||
import { EAC_SCHEDULING_CONFIG } from 'libs/scheduling';
|
||||
import { getScheduleGasPrice, getTimeBounty } from 'selectors/schedule';
|
||||
@ -83,9 +82,11 @@ class AdvancedGas extends React.Component<Props, State> {
|
||||
<div className="input-group-header">
|
||||
{translateRaw('OFFLINE_STEP2_LABEL_3')} (gwei)
|
||||
</div>
|
||||
{/*We leave type as string instead of number, because things such as multiple decimals
|
||||
or invalid exponent notation does not fire the onchange handler
|
||||
so the component will not display as invalid for such things */}
|
||||
<Input
|
||||
className={!!gasPrice.raw && !validGasPrice ? 'invalid' : ''}
|
||||
type="number"
|
||||
isValid={validGasPrice}
|
||||
placeholder="40"
|
||||
value={gasPrice.raw}
|
||||
onChange={this.handleGasPriceChange}
|
||||
@ -173,7 +174,7 @@ class AdvancedGas extends React.Component<Props, State> {
|
||||
|
||||
private handleGasPriceChange = (ev: React.FormEvent<HTMLInputElement>) => {
|
||||
const { value } = ev.currentTarget;
|
||||
this.props.inputGasPrice(sanitizeNumericalInput(value));
|
||||
this.props.inputGasPrice(value);
|
||||
};
|
||||
|
||||
private handleToggleAutoGasLimit = (_: React.FormEvent<HTMLInputElement>) => {
|
||||
|
@ -54,6 +54,9 @@ class FeeSummary extends React.Component<Props> {
|
||||
scheduleGasLimit
|
||||
} = this.props;
|
||||
|
||||
if (!gasPrice.value || gasPrice.value.eqn(0) || !gasLimit.value || gasLimit.value.eqn(0)) {
|
||||
return null;
|
||||
}
|
||||
if (isGasEstimating) {
|
||||
return (
|
||||
<div className="FeeSummary is-loading">
|
||||
|
@ -57,7 +57,7 @@ class SimpleGas extends React.Component<Props> {
|
||||
this.props.fetchGasEstimates();
|
||||
}
|
||||
|
||||
public componentWillReceiveProps(nextProps: Props) {
|
||||
public UNSAFE_componentWillReceiveProps(nextProps: Props) {
|
||||
if (!this.state.hasSetRecommendedGasPrice && nextProps.gasEstimates) {
|
||||
this.setState({ hasSetRecommendedGasPrice: true });
|
||||
this.props.setGasPrice(nextProps.gasEstimates.fast.toString());
|
||||
|
@ -40,7 +40,7 @@ export default class TogglablePassword extends React.PureComponent<Props, State>
|
||||
isVisible: !!this.props.isVisible
|
||||
};
|
||||
|
||||
public componentWillReceiveProps(nextProps: Props) {
|
||||
public UNSAFE_componentWillReceiveProps(nextProps: Props) {
|
||||
if (this.props.isVisible !== nextProps.isVisible) {
|
||||
this.setState({ isVisible: !!nextProps.isVisible });
|
||||
}
|
||||
@ -69,7 +69,8 @@ export default class TogglablePassword extends React.PureComponent<Props, State>
|
||||
<div className={`TogglablePassword input-group input-group-inline`}>
|
||||
{isTextareaWhenVisible && isVisible ? (
|
||||
<TextArea
|
||||
className={`${className} ${!isValid ? 'invalid' : ''}`}
|
||||
isValid={!!isValid}
|
||||
className={className}
|
||||
value={value}
|
||||
name={name}
|
||||
disabled={disabled}
|
||||
@ -84,11 +85,12 @@ export default class TogglablePassword extends React.PureComponent<Props, State>
|
||||
/>
|
||||
) : (
|
||||
<Input
|
||||
isValid={!!isValid}
|
||||
value={value}
|
||||
name={name}
|
||||
disabled={disabled}
|
||||
type={isVisible ? 'text' : 'password'}
|
||||
className={`${className} ${!isValid ? 'invalid' : ''} border-rad-right-0`}
|
||||
className={`${className} border-rad-right-0`}
|
||||
placeholder={placeholder}
|
||||
onChange={onChange}
|
||||
onFocus={onFocus}
|
||||
|
@ -31,7 +31,7 @@ class TransactionStatus extends React.Component<Props> {
|
||||
this.props.fetchTransactionData(this.props.txHash);
|
||||
}
|
||||
|
||||
public componentWillReceiveProps(nextProps: Props) {
|
||||
public UNSAFE_componentWillReceiveProps(nextProps: Props) {
|
||||
if (this.props.txHash !== nextProps.txHash) {
|
||||
this.props.fetchTransactionData(nextProps.txHash);
|
||||
}
|
||||
|
@ -226,7 +226,7 @@ const WalletDecrypt = withRouter<Props>(
|
||||
hasAcknowledgedInsecure: false
|
||||
};
|
||||
|
||||
public componentWillReceiveProps(nextProps: Props) {
|
||||
public UNSAFE_componentWillReceiveProps(nextProps: Props) {
|
||||
// Reset state when unlock is hidden / revealed
|
||||
if (nextProps.hidden !== this.props.hidden) {
|
||||
this.setState({
|
||||
|
@ -37,12 +37,6 @@
|
||||
padding-right: $space;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.form-control {
|
||||
display: inline-block;
|
||||
width: auto;
|
||||
margin: 0 0 0 10px;
|
||||
}
|
||||
}
|
||||
|
||||
&-addresses {
|
||||
|
@ -73,7 +73,7 @@ class DeterministicWalletsModalClass extends React.PureComponent<Props, State> {
|
||||
this.getAddresses();
|
||||
}
|
||||
|
||||
public componentWillReceiveProps(nextProps: Props) {
|
||||
public UNSAFE_componentWillReceiveProps(nextProps: Props) {
|
||||
const { publicKey, chainCode, seed, dPath } = this.props;
|
||||
if (
|
||||
nextProps.publicKey !== publicKey ||
|
||||
@ -132,7 +132,7 @@ class DeterministicWalletsModalClass extends React.PureComponent<Props, State> {
|
||||
<React.Fragment>
|
||||
<div className="DWModal-path-custom">
|
||||
<Input
|
||||
className={customPath ? (isValidPath(customPath) ? 'valid' : 'invalid') : ''}
|
||||
isValid={customPath ? isValidPath(customPath) : true}
|
||||
value={customPath}
|
||||
placeholder="m/44'/60'/0'/0"
|
||||
onChange={this.handleChangeCustomPath}
|
||||
|
@ -65,9 +65,8 @@ export class KeystoreDecrypt extends PureComponent {
|
||||
|
||||
{isWalletPending ? <Spinner /> : ''}
|
||||
<Input
|
||||
className={`${password.length > 0 ? 'is-valid' : 'is-invalid'} ${
|
||||
file.length && isWalletPending ? 'hidden' : ''
|
||||
}`}
|
||||
isValid={password.length > 0}
|
||||
className={`${file.length && isWalletPending ? 'hidden' : ''}`}
|
||||
disabled={!file}
|
||||
value={password}
|
||||
onChange={this.onPasswordChange}
|
||||
|
@ -50,7 +50,7 @@ class LedgerNanoSDecryptClass extends PureComponent<Props, State> {
|
||||
});
|
||||
};
|
||||
|
||||
public componentWillReceiveProps(nextProps: Props) {
|
||||
public UNSAFE_componentWillReceiveProps(nextProps: Props) {
|
||||
if (this.props.dPath !== nextProps.dPath && nextProps.dPath) {
|
||||
this.setState({ dPath: nextProps.dPath });
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ class MnemonicDecryptClass extends PureComponent<Props, State> {
|
||||
dPath: this.props.dPath
|
||||
};
|
||||
|
||||
public componentWillReceiveProps(nextProps: Props) {
|
||||
public UNSAFE_componentWillReceiveProps(nextProps: Props) {
|
||||
if (this.props.dPath !== nextProps.dPath) {
|
||||
this.setState({ dPath: nextProps.dPath });
|
||||
}
|
||||
@ -67,6 +67,8 @@ class MnemonicDecryptClass extends PureComponent<Props, State> {
|
||||
<div className="form-group">
|
||||
<p>{translate('ADD_LABEL_8')}</p>
|
||||
<Input
|
||||
isValid={true}
|
||||
showValidAsPlain={true}
|
||||
value={pass}
|
||||
onChange={this.onPasswordChange}
|
||||
placeholder={translateRaw('INPUT_PASSWORD_LABEL')}
|
||||
|
@ -74,7 +74,7 @@ export class PrivateKeyDecrypt extends PureComponent<Props> {
|
||||
<label className="input-group">
|
||||
<div className="input-group-header">{translate('ADD_LABEL_3')}</div>
|
||||
<Input
|
||||
className={`form-control ${password.length > 0 ? 'is-valid' : 'is-invalid'}`}
|
||||
isValid={password.length > 0}
|
||||
value={password}
|
||||
onChange={this.onPasswordChange}
|
||||
onKeyDown={this.onKeyDown}
|
||||
|
@ -41,7 +41,7 @@ class TrezorDecryptClass extends PureComponent<Props, State> {
|
||||
isLoading: false
|
||||
};
|
||||
|
||||
public componentWillReceiveProps(nextProps: Props) {
|
||||
public UNSAFE_componentWillReceiveProps(nextProps: Props) {
|
||||
if (this.props.dPath !== nextProps.dPath && nextProps.dPath) {
|
||||
this.setState({ dPath: nextProps.dPath });
|
||||
}
|
||||
|
@ -60,7 +60,8 @@ class ViewOnlyDecryptClass extends PureComponent<Props, State> {
|
||||
)}
|
||||
|
||||
<Input
|
||||
className={`ViewOnly-input ${isValid ? 'is-valid' : 'is-invalid'}`}
|
||||
isValid={isValid}
|
||||
className="ViewOnly-input"
|
||||
value={address}
|
||||
onChange={this.changeAddress}
|
||||
placeholder={translateRaw('VIEW_ONLY_ENTER')}
|
||||
|
26
common/components/WelcomeModal.scss
Normal file
26
common/components/WelcomeModal.scss
Normal file
@ -0,0 +1,26 @@
|
||||
@import 'common/sass/variables';
|
||||
|
||||
.WelcomeModal {
|
||||
font-size: $font-size-bump-more;
|
||||
|
||||
&-logo {
|
||||
display: block;
|
||||
max-width: 380px;
|
||||
margin: $space auto $space * 2;
|
||||
}
|
||||
|
||||
&-beta {
|
||||
margin-top: -$space-md;
|
||||
font-size: $font-size-base;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
&-continue {
|
||||
display: block;
|
||||
margin: $space * 2 auto 0;
|
||||
}
|
||||
|
||||
p, ul {
|
||||
margin-bottom: $space;
|
||||
}
|
||||
}
|
62
common/components/WelcomeModal.tsx
Normal file
62
common/components/WelcomeModal.tsx
Normal file
@ -0,0 +1,62 @@
|
||||
import React from 'react';
|
||||
import translate from 'translations';
|
||||
import { Modal, NewTabLink } from 'components/ui';
|
||||
import { isLegacyUser, isBetaUser } from 'utils/localStorage';
|
||||
import Logo from 'assets/images/logo-mycrypto-transparent.svg';
|
||||
import './WelcomeModal.scss';
|
||||
|
||||
const LS_KEY = 'acknowledged-welcome';
|
||||
|
||||
interface State {
|
||||
isOpen: boolean;
|
||||
}
|
||||
|
||||
export default class WelcomeModal extends React.Component<{}, State> {
|
||||
public state: State = {
|
||||
isOpen: false
|
||||
};
|
||||
|
||||
public componentDidMount() {
|
||||
if (isLegacyUser() && !localStorage.getItem(LS_KEY)) {
|
||||
this.setState({ isOpen: true });
|
||||
}
|
||||
}
|
||||
|
||||
public render() {
|
||||
return (
|
||||
<Modal isOpen={this.state.isOpen} handleClose={this.close} maxWidth={660}>
|
||||
<div className="WelcomeModal">
|
||||
<img className="WelcomeModal-logo" src={Logo} />
|
||||
{isBetaUser() && (
|
||||
<p className="WelcomeModal-beta alert alert-success">
|
||||
💖 {translate('WELCOME_MODAL_BETA')} 🚀
|
||||
</p>
|
||||
)}
|
||||
<p>{translate('WELCOME_MODAL_INTRO')}</p>
|
||||
<ul>
|
||||
<li>{translate('WELCOME_MODAL_FEATURE_1')}</li>
|
||||
<li>{translate('WELCOME_MODAL_FEATURE_2')}</li>
|
||||
<li>{translate('WELCOME_MODAL_FEATURE_3')}</li>
|
||||
<li>{translate('WELCOME_MODAL_FEATURE_4')}</li>
|
||||
<li>
|
||||
<NewTabLink href="https://download.mycrypto.com/">
|
||||
{translate('WELCOME_MODAL_FEATURE_5')}
|
||||
</NewTabLink>
|
||||
</li>
|
||||
<li>{translate('WELCOME_MODAL_FEATURE_MORE')}</li>
|
||||
</ul>
|
||||
<p>{translate('WELCOME_MODAL_LINKS')}</p>
|
||||
|
||||
<button className="WelcomeModal-continue btn btn-lg btn-primary" onClick={this.close}>
|
||||
{translate('WELCOME_MODAL_CONTINUE')}
|
||||
</button>
|
||||
</div>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
private close = () => {
|
||||
this.setState({ isOpen: false });
|
||||
localStorage.setItem(LS_KEY, 'true');
|
||||
};
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
import React, { Component } from 'react';
|
||||
|
||||
interface RequiredProps {
|
||||
condition: boolean;
|
||||
conditionalProps: {
|
||||
[key: string]: any;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Optional
|
||||
*/
|
||||
export const withConditional = <WrappedComponentProps extends {}>(
|
||||
PassedComponent: React.ComponentType<WrappedComponentProps>
|
||||
) =>
|
||||
class extends Component<WrappedComponentProps & RequiredProps, {}> {
|
||||
public render() {
|
||||
const { condition, conditionalProps, ...passedProps } = this.props as any;
|
||||
return condition ? (
|
||||
<PassedComponent {...{ ...passedProps, ...(conditionalProps as object) }} />
|
||||
) : (
|
||||
<PassedComponent {...passedProps} />
|
||||
);
|
||||
}
|
||||
};
|
@ -1 +0,0 @@
|
||||
export * from './Conditional';
|
@ -14,7 +14,6 @@ export { default as Header } from './Header';
|
||||
export { default as Footer } from './Footer';
|
||||
export { default as BalanceSidebar } from './BalanceSidebar';
|
||||
export { default as PaperWallet } from './PaperWallet';
|
||||
export { default as BetaAgreement } from './BetaAgreement';
|
||||
export { default as TXMetaDataPanel } from './TXMetaDataPanel';
|
||||
export { default as WalletDecrypt } from './WalletDecrypt';
|
||||
export { default as TogglablePassword } from './TogglablePassword';
|
||||
|
@ -29,7 +29,7 @@ const initialState = { userInput: '' };
|
||||
class UnitConverterClass extends Component<Props, State> {
|
||||
public state: State = initialState;
|
||||
|
||||
public componentWillReceiveProps(nextProps: Props) {
|
||||
public UNSAFE_componentWillReceiveProps(nextProps: Props) {
|
||||
const { userInput } = this.state;
|
||||
|
||||
if (this.props.decimal !== nextProps.decimal) {
|
||||
|
@ -1,6 +0,0 @@
|
||||
import React from 'react';
|
||||
import { withConditional } from 'components/hocs';
|
||||
import { Input } from 'components/ui';
|
||||
|
||||
const inpt: React.SFC<React.InputHTMLAttributes<any>> = props => <Input {...props} />;
|
||||
export const ConditionalInput = withConditional(inpt);
|
@ -85,13 +85,13 @@
|
||||
border-color: $brand-danger;
|
||||
box-shadow: inset 0px 0px 0px 1px $brand-danger;
|
||||
}
|
||||
&.valid.has-value {
|
||||
border-color: #8dd17b;
|
||||
box-shadow: inset 0px 0px 0px 1px #8dd17b;
|
||||
}
|
||||
&:focus {
|
||||
border-color: #4295bc;
|
||||
box-shadow: inset 0px 0px 0px 1px #4295bc;
|
||||
&.valid {
|
||||
border-color: #8dd17b;
|
||||
box-shadow: inset 0px 0px 0px 1px #8dd17b;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,33 +1,62 @@
|
||||
import React, { HTMLProps } from 'react';
|
||||
import classnames from 'classnames';
|
||||
import './Input.scss';
|
||||
|
||||
interface State {
|
||||
hasBlurred: boolean;
|
||||
/**
|
||||
* @description when the input has not had any values inputted yet
|
||||
* e.g. "Pristine" condition
|
||||
*/
|
||||
isStateless: boolean;
|
||||
}
|
||||
|
||||
class Input extends React.Component<HTMLProps<HTMLInputElement>, State> {
|
||||
interface OwnProps extends HTMLProps<HTMLInputElement> {
|
||||
isValid: boolean;
|
||||
showValidAsPlain?: boolean;
|
||||
}
|
||||
|
||||
class Input extends React.Component<OwnProps, State> {
|
||||
public state: State = {
|
||||
hasBlurred: false
|
||||
hasBlurred: false,
|
||||
isStateless: true
|
||||
};
|
||||
|
||||
public render() {
|
||||
const { showValidAsPlain, isValid, ...htmlProps } = this.props;
|
||||
const hasValue = !!this.props.value && this.props.value.toString().length > 0;
|
||||
const classname = classnames(
|
||||
this.props.className,
|
||||
'input-group-input',
|
||||
this.state.isStateless ? '' : isValid ? (showValidAsPlain ? '' : '') : `invalid`,
|
||||
this.state.hasBlurred && 'has-blurred',
|
||||
hasValue && 'has-value'
|
||||
);
|
||||
|
||||
return (
|
||||
<input
|
||||
{...this.props}
|
||||
{...htmlProps}
|
||||
onBlur={e => {
|
||||
this.setState({ hasBlurred: true });
|
||||
if (this.props && this.props.onBlur) {
|
||||
this.props.onBlur(e);
|
||||
}
|
||||
}}
|
||||
onChange={this.handleOnChange}
|
||||
onWheel={this.props.type === 'number' ? this.preventNumberScroll : undefined}
|
||||
className={`input-group-input ${this.props.className} ${
|
||||
this.state.hasBlurred ? 'has-blurred' : ''
|
||||
} ${!!this.props.value && this.props.value.toString().length > 0 ? 'has-value' : ''}`}
|
||||
className={classname}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
private handleOnChange = (args: React.FormEvent<HTMLInputElement>) => {
|
||||
if (this.state.isStateless) {
|
||||
this.setState({ isStateless: false });
|
||||
}
|
||||
if (this.props.onChange) {
|
||||
this.props.onChange(args);
|
||||
}
|
||||
};
|
||||
// When number inputs are scrolled on while in focus, the number changes. So we blur
|
||||
// it if it's focused to prevent that behavior, without preventing the scroll.
|
||||
private preventNumberScroll(ev: React.WheelEvent<HTMLInputElement>) {
|
||||
|
@ -3,8 +3,8 @@ import closeIcon from 'assets/images/close.svg';
|
||||
import { IButton } from 'components/ui/Modal';
|
||||
|
||||
interface Props {
|
||||
title?: string;
|
||||
children: any;
|
||||
title?: React.ReactNode;
|
||||
children: React.ReactNode;
|
||||
modalStyle?: CSSProperties;
|
||||
hasButtons?: number;
|
||||
buttons?: IButton[];
|
||||
@ -67,7 +67,7 @@ export default class ModalBody extends React.Component<Props> {
|
||||
|
||||
<div className="Modal-content" ref={div => (this.modalContent = div as HTMLElement)}>
|
||||
{children}
|
||||
<div className="Modal-fade" />
|
||||
<div className={`Modal-fade ${!hasButtons ? 'has-no-footer' : ''}`} />
|
||||
</div>
|
||||
{hasButtons && <div className="Modal-footer">{this.renderButtons()}</div>}
|
||||
</div>
|
||||
|
@ -53,6 +53,10 @@ $m-anim-speed: 400ms;
|
||||
bottom: 4.5rem;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
|
||||
&.has-no-footer {
|
||||
bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&-header {
|
||||
|
@ -12,9 +12,9 @@ export interface IButton {
|
||||
}
|
||||
interface Props {
|
||||
isOpen?: boolean;
|
||||
title?: string;
|
||||
title?: React.ReactNode;
|
||||
disableButtons?: boolean;
|
||||
children: any;
|
||||
children: React.ReactNode;
|
||||
buttons?: IButton[];
|
||||
maxWidth?: number;
|
||||
handleClose(): void;
|
||||
|
@ -70,14 +70,7 @@ export default class DropdownComponent<T> extends PureComponent<Props<T>, State>
|
||||
|
||||
return (
|
||||
<ul className={menuClass} style={searchable ? searchableStyle : undefined}>
|
||||
{searchable && (
|
||||
<input
|
||||
className="form-control"
|
||||
placeholder={'Search'}
|
||||
onChange={onSearchChange}
|
||||
value={search}
|
||||
/>
|
||||
)}
|
||||
{searchable && <input placeholder={'Search'} onChange={onSearchChange} value={search} />}
|
||||
|
||||
{options
|
||||
.filter(option => {
|
||||
|
@ -15,12 +15,12 @@ interface State {
|
||||
|
||||
export default class QRCode extends React.PureComponent<Props, State> {
|
||||
public state: State = {};
|
||||
public componentWillMount() {
|
||||
public UNSAFE_componentWillMount() {
|
||||
// Start generating QR codes immediately
|
||||
this.generateQrCode(this.props.data);
|
||||
}
|
||||
|
||||
public componentWillReceiveProps(nextProps: Props) {
|
||||
public UNSAFE_componentWillReceiveProps(nextProps: Props) {
|
||||
// Regenerate QR codes if props change
|
||||
if (nextProps.data !== this.props.data) {
|
||||
this.generateQrCode(nextProps.data);
|
||||
|
@ -1,27 +0,0 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
|
||||
interface Props {
|
||||
value?: string;
|
||||
options: string[];
|
||||
onChange(event: React.FormEvent<HTMLSpanElement>): void;
|
||||
}
|
||||
|
||||
export default class SimpleSelect extends PureComponent<Props, {}> {
|
||||
public render() {
|
||||
return (
|
||||
<select
|
||||
value={this.props.value || this.props.options[0]}
|
||||
className={'form-control'}
|
||||
onChange={this.props.onChange}
|
||||
>
|
||||
{this.props.options.map((obj, i) => {
|
||||
return (
|
||||
<option value={obj} key={i}>
|
||||
{obj}
|
||||
</option>
|
||||
);
|
||||
})}
|
||||
</select>
|
||||
);
|
||||
}
|
||||
}
|
@ -34,7 +34,7 @@ class SwapDropdown extends PureComponent<Props, State> {
|
||||
|
||||
public dropdown: HTMLDivElement | null;
|
||||
|
||||
public componentWillMount() {
|
||||
public UNSAFE_componentWillMount() {
|
||||
this.buildOptions(this.props.options);
|
||||
document.addEventListener('click', this.handleBodyClick);
|
||||
}
|
||||
@ -43,7 +43,7 @@ class SwapDropdown extends PureComponent<Props, State> {
|
||||
document.removeEventListener('click', this.handleBodyClick);
|
||||
}
|
||||
|
||||
public componentWillReceiveProps(nextProps: Props) {
|
||||
public UNSAFE_componentWillReceiveProps(nextProps: Props) {
|
||||
if (this.props.options !== nextProps.options) {
|
||||
this.buildOptions(nextProps.options);
|
||||
}
|
||||
|
@ -1,30 +1,59 @@
|
||||
import React, { HTMLProps } from 'react';
|
||||
import classnames from 'classnames';
|
||||
import './Input.scss';
|
||||
|
||||
interface State {
|
||||
hasBlurred: boolean;
|
||||
/**
|
||||
* @description when the input has not had any values inputted yet
|
||||
* e.g. "Pristine" condition
|
||||
*/
|
||||
isStateless: boolean;
|
||||
}
|
||||
|
||||
class TextArea extends React.Component<HTMLProps<HTMLTextAreaElement>, State> {
|
||||
interface OwnProps extends HTMLProps<HTMLTextAreaElement> {
|
||||
isValid: boolean;
|
||||
showValidAsPlain?: boolean;
|
||||
}
|
||||
|
||||
class TextArea extends React.Component<OwnProps, State> {
|
||||
public state: State = {
|
||||
hasBlurred: false
|
||||
hasBlurred: false,
|
||||
isStateless: true
|
||||
};
|
||||
|
||||
public render() {
|
||||
const { showValidAsPlain, isValid, ...htmlProps } = this.props;
|
||||
const classname = classnames(
|
||||
this.props.className,
|
||||
'input-group-input',
|
||||
this.state.isStateless ? '' : isValid ? (showValidAsPlain ? '' : '') : `invalid`,
|
||||
this.state.hasBlurred && 'has-blurred'
|
||||
);
|
||||
|
||||
return (
|
||||
<textarea
|
||||
{...this.props}
|
||||
{...htmlProps}
|
||||
onBlur={e => {
|
||||
this.setState({ hasBlurred: true });
|
||||
if (this.props && this.props.onBlur) {
|
||||
this.props.onBlur(e);
|
||||
}
|
||||
}}
|
||||
className={`input-group-input ${this.props.className} ${
|
||||
this.state.hasBlurred ? 'has-blurred' : ''
|
||||
}`}
|
||||
onChange={this.handleOnChange}
|
||||
className={classname}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
private handleOnChange = (args: React.FormEvent<HTMLTextAreaElement>) => {
|
||||
if (this.state.isStateless) {
|
||||
this.setState({ isStateless: false });
|
||||
}
|
||||
if (this.props.onChange) {
|
||||
this.props.onChange(args);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export default TextArea;
|
||||
|
@ -1,27 +0,0 @@
|
||||
@import 'common/sass/variables';
|
||||
|
||||
$height: 22px;
|
||||
|
||||
// TODO - Implement styles for custom title bar on all platforms
|
||||
.TitleBar,
|
||||
.TitleBarPlaceholder {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.TitleBar {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: $height;
|
||||
line-height: $height;
|
||||
-webkit-user-select: none;
|
||||
-webkit-app-region: drag;
|
||||
background: $body-bg;
|
||||
z-index: $zindex-top;
|
||||
box-shadow: 0 1px 1px rgba(#000, 0.08);
|
||||
}
|
||||
|
||||
.TitleBarPlaceholder {
|
||||
height: $height;
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
import React from 'react';
|
||||
import './TitleBar.scss';
|
||||
|
||||
const TitleBar: React.SFC<{}> = () => (
|
||||
<React.Fragment>
|
||||
<div className="TitleBar" />
|
||||
<div className="TitleBarPlaceholder" />
|
||||
</React.Fragment>
|
||||
);
|
||||
|
||||
export default TitleBar;
|
@ -1,9 +1,9 @@
|
||||
@import 'common/sass/variables';
|
||||
@import 'common/sass/mixins';
|
||||
|
||||
$tooltip-bg: rgba(#222, 0.95);
|
||||
|
||||
.Tooltip {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 50%;
|
||||
@ -14,7 +14,7 @@ $tooltip-bg: rgba(#222, 0.95);
|
||||
pointer-events: none;
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
transform: translate(-50%, -100%) translateY(-5px);
|
||||
transform: translate(-50%, -100%) translateY(-$tooltip-start-distance);
|
||||
transition-property: opacity, transform, visibility;
|
||||
transition-duration: 100ms, 100ms, 0ms;
|
||||
transition-delay: 0ms, 0ms, 100ms;
|
||||
@ -32,7 +32,7 @@ $tooltip-bg: rgba(#222, 0.95);
|
||||
bottom: 0;
|
||||
left: 50%;
|
||||
transform: translate(-50%, 100%);
|
||||
@include triangle(10px, $tooltip-bg, down);
|
||||
@include triangle($tooltip-arrow-size * 2, $tooltip-bg, down);
|
||||
}
|
||||
}
|
||||
|
||||
@ -46,7 +46,7 @@ $tooltip-bg: rgba(#222, 0.95);
|
||||
border-radius: 2px;
|
||||
|
||||
&:after {
|
||||
@include triangle(8px, $tooltip-bg, down);
|
||||
border-width: $tooltip-arrow-size - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -60,8 +60,55 @@ $tooltip-bg: rgba(#222, 0.95);
|
||||
border-radius: 4px;
|
||||
|
||||
&:after {
|
||||
@include triangle(12px, $tooltip-bg, down);
|
||||
border-width: $tooltip-arrow-size + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Direction, top is default
|
||||
&.is-direction-left {
|
||||
left: 0;
|
||||
top: 50%;
|
||||
justify-content: flex-end;
|
||||
transform: translate(-100%, -50%) translateX(-$tooltip-start-distance);
|
||||
|
||||
> span:after {
|
||||
bottom: 50%;
|
||||
right: 0;
|
||||
left: auto;
|
||||
transform: translate(100%, 50%);
|
||||
border-top-color: transparent;
|
||||
border-left-color: $tooltip-bg;
|
||||
}
|
||||
}
|
||||
|
||||
&.is-direction-right {
|
||||
left: auto;
|
||||
right: 0;
|
||||
top: 50%;
|
||||
justify-content: flex-start;
|
||||
transform: translate(100%, -50%) translateX($tooltip-start-distance);
|
||||
|
||||
> span:after {
|
||||
bottom: 50%;
|
||||
left: 0;
|
||||
transform: translate(-100%, 50%);
|
||||
border-top-color: transparent;
|
||||
border-right-color: $tooltip-bg;
|
||||
}
|
||||
}
|
||||
|
||||
&.is-direction-bottom {
|
||||
top: auto;
|
||||
bottom: 0;
|
||||
transform: translate(-50%, 100%) translateY($tooltip-start-distance);
|
||||
|
||||
> span:after {
|
||||
bottom: auto;
|
||||
top: 0;
|
||||
transform: translate(-50%, -100%);
|
||||
border-top-color: transparent;
|
||||
border-bottom-color: $tooltip-bg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,13 +5,15 @@ import './Tooltip.scss';
|
||||
interface Props {
|
||||
children: React.ReactElement<string> | string;
|
||||
size?: 'sm' | 'md' | 'lg';
|
||||
direction?: 'top' | 'bottom' | 'left' | 'right';
|
||||
}
|
||||
|
||||
const Tooltip: React.SFC<Props> = ({ size, children }) => (
|
||||
const Tooltip: React.SFC<Props> = ({ size, direction, children }) => (
|
||||
<div
|
||||
className={classnames({
|
||||
Tooltip: true,
|
||||
[`is-size-${size}`]: !!size
|
||||
[`is-size-${size}`]: !!size,
|
||||
[`is-direction-${direction}`]: !!direction
|
||||
})}
|
||||
>
|
||||
<span className="Tooltip-text">{children}</span>
|
||||
|
@ -11,13 +11,11 @@ export { default as UnitDisplay } from './UnitDisplay';
|
||||
export { default as Spinner } from './Spinner';
|
||||
export { default as SwapDropdown } from './SwapDropdown';
|
||||
export { default as Tooltip } from './Tooltip';
|
||||
export { default as TitleBar } from './TitleBar';
|
||||
export { default as HelpLink } from './HelpLink';
|
||||
export { default as Input } from './Input';
|
||||
export { default as TextArea } from './TextArea';
|
||||
export { default as Address } from './Address';
|
||||
export { default as CodeBlock } from './CodeBlock';
|
||||
export { default as Toggle } from './Toggle';
|
||||
export * from './ConditionalInput';
|
||||
export * from './Expandable';
|
||||
export * from './InlineSpinner';
|
||||
|
@ -1,16 +1,17 @@
|
||||
import React from 'react'; // For ANNOUNCEMENT_MESSAGE jsx
|
||||
import NewTabLink from 'components/ui/NewTabLink';
|
||||
import { getValues } from '../utils/helpers';
|
||||
import packageJson from '../../package.json';
|
||||
import { GasPriceSetting } from 'types/network';
|
||||
import { makeExplorer } from 'utils/helpers';
|
||||
import NewTabLink from 'components/ui/NewTabLink';
|
||||
|
||||
export const languages = require('./languages.json');
|
||||
export const discordURL = 'https://discord.gg/VSaTXEA';
|
||||
|
||||
// Displays in the footer
|
||||
export const VERSION_RAW = packageJson.version;
|
||||
export const VERSION = `${VERSION_RAW} (Release Candidate 2)`;
|
||||
const VERSION_ELECTRON = packageJson['electron-version'];
|
||||
const VERSION_WEB = packageJson.version;
|
||||
export const VERSION = process.env.BUILD_ELECTRON ? VERSION_ELECTRON : VERSION_WEB;
|
||||
export const N_FACTOR = 8192;
|
||||
|
||||
// Bricks the app once this date has been exceeded. Remember to update these 2
|
||||
@ -18,7 +19,6 @@ export const N_FACTOR = 8192;
|
||||
// It is currently set to: 05/25/2018 @ 12:00am (UTC)
|
||||
// TODO: Remove me once app alpha / release candidates are done
|
||||
export const APP_ALPHA_EXPIRATION = 1527206400000;
|
||||
export const VERSION_RC = `${packageJson.version}-RC.0`;
|
||||
|
||||
// Displays at the top of the site, make message empty string to remove.
|
||||
// Type can be primary, warning, danger, success, info, or blank for grey.
|
||||
@ -26,10 +26,8 @@ export const VERSION_RC = `${packageJson.version}-RC.0`;
|
||||
export const ANNOUNCEMENT_TYPE = '';
|
||||
export const ANNOUNCEMENT_MESSAGE = (
|
||||
<React.Fragment>
|
||||
This is a Beta Release Candidate of the new MyCrypto. Please submit any bug reports to our{' '}
|
||||
<NewTabLink href="https://github.com/MyCryptoHQ/MyCrypto/issues">GitHub</NewTabLink> and use{' '}
|
||||
<NewTabLink href="https://hackerone.com/mycrypto">HackerOne</NewTabLink> for critical
|
||||
vulnerabilities. Join the discussion on <NewTabLink href={discordURL}>Discord</NewTabLink>.
|
||||
Welcome to the new MyCrypto. We hope you like it! If it's urgent and you need the old site, you
|
||||
can still use <NewTabLink href="https://legacy.mycrypto.com">MyCrypto Legacy</NewTabLink>
|
||||
</React.Fragment>
|
||||
);
|
||||
|
||||
|
@ -47,6 +47,10 @@ export const socialMediaLinks: Link[] = [
|
||||
];
|
||||
|
||||
export const productLinks: Link[] = [
|
||||
{
|
||||
link: 'https://legacy.mycrypto.com/',
|
||||
text: translateRaw('OLD_MYCRYPTO')
|
||||
},
|
||||
{
|
||||
link:
|
||||
'https://chrome.google.com/webstore/detail/etheraddresslookup/pdknmigbbbhmllnmgdfalmedcmcefdfn',
|
||||
@ -62,8 +66,12 @@ export const productLinks: Link[] = [
|
||||
text: translateRaw('ETHERSCAMDB')
|
||||
},
|
||||
{
|
||||
link: 'https://www.mycrypto.com/helpers.html',
|
||||
link: 'https://legacy.mycrypto.com/helpers.html',
|
||||
text: translateRaw('FOOTER_HELP_AND_DEBUGGING')
|
||||
},
|
||||
{
|
||||
link: 'https://hackerone.com/mycrypto',
|
||||
text: translateRaw('FOOTER_HACKERONE')
|
||||
}
|
||||
];
|
||||
|
||||
|
@ -24,6 +24,16 @@
|
||||
"symbol": "REN",
|
||||
"decimal": 18
|
||||
},
|
||||
{
|
||||
"address": "0x37427576324fE1f3625c9102674772d7CF71377d",
|
||||
"symbol": "SGT (SelfieYo Gold Token)",
|
||||
"decimal": 18
|
||||
},
|
||||
{
|
||||
"address": "0xd248B0D48E44aaF9c49aea0312be7E13a6dc1468",
|
||||
"symbol": "SGT (SGT)",
|
||||
"decimal": 1
|
||||
},
|
||||
{
|
||||
"address": "0x78B7FADA55A64dD895D8c8c35779DD8b67fA8a05",
|
||||
"symbol": "ATL",
|
||||
@ -49,6 +59,11 @@
|
||||
"symbol": "SNGLS",
|
||||
"decimal": 0
|
||||
},
|
||||
{
|
||||
"address": "0x515669d308f887Fd83a471C7764F5d084886D34D",
|
||||
"symbol": "MUXE",
|
||||
"decimal": 18
|
||||
},
|
||||
{
|
||||
"address": "0x025abAD9e518516fdaAFBDcdB9701b37fb7eF0FA",
|
||||
"symbol": "GTKT",
|
||||
@ -64,6 +79,11 @@
|
||||
"symbol": "STRC",
|
||||
"decimal": 8
|
||||
},
|
||||
{
|
||||
"address": "0x2a8E98e256f32259b5E5Cb55Dd63C8e891950666",
|
||||
"symbol": "PTC",
|
||||
"decimal": 18
|
||||
},
|
||||
{
|
||||
"address": "0x41e5560054824eA6B0732E656E3Ad64E20e94E45",
|
||||
"symbol": "CVC",
|
||||
@ -139,6 +159,11 @@
|
||||
"symbol": "FAM",
|
||||
"decimal": 12
|
||||
},
|
||||
{
|
||||
"address": "0x105d97ef2E723f1cfb24519Bc6fF15a6D091a3F1",
|
||||
"symbol": "UMKA",
|
||||
"decimal": 4
|
||||
},
|
||||
{
|
||||
"address": "0x694404595e3075A942397F466AAcD462FF1a7BD0",
|
||||
"symbol": "PATENTS",
|
||||
@ -184,6 +209,11 @@
|
||||
"symbol": "GANA",
|
||||
"decimal": 18
|
||||
},
|
||||
{
|
||||
"address": "0xC5bBaE50781Be1669306b9e001EFF57a2957b09d",
|
||||
"symbol": "GTO",
|
||||
"decimal": 5
|
||||
},
|
||||
{
|
||||
"address": "0x9e88613418cF03dCa54D6a2cf6Ad934A78C7A17A",
|
||||
"symbol": "SWM",
|
||||
@ -199,6 +229,31 @@
|
||||
"symbol": "OMG",
|
||||
"decimal": 18
|
||||
},
|
||||
{
|
||||
"address": "0xf9F7c29CFdf19FCf1f2AA6B84aA367Bcf1bD1676",
|
||||
"symbol": "DTT",
|
||||
"decimal": 18
|
||||
},
|
||||
{
|
||||
"address": "0x78Eb8DC641077F049f910659b6d580E80dC4d237",
|
||||
"symbol": "SMT (Social Media Market)",
|
||||
"decimal": 8
|
||||
},
|
||||
{
|
||||
"address": "0x55F93985431Fc9304077687a35A1BA103dC1e081",
|
||||
"symbol": "SMT (SmartMesh)",
|
||||
"decimal": 18
|
||||
},
|
||||
{
|
||||
"address": "0x2dCFAAc11c9EebD8C6C42103Fe9e2a6AD237aF27",
|
||||
"symbol": "SMT (Smart Node)",
|
||||
"decimal": 18
|
||||
},
|
||||
{
|
||||
"address": "0x82125AFe01819Dff1535D0D6276d57045291B6c0",
|
||||
"symbol": "MRL",
|
||||
"decimal": 18
|
||||
},
|
||||
{
|
||||
"address": "0x7DD7F56D697Cc0f2b52bD55C057f378F1fE6Ab4b",
|
||||
"symbol": "$TEAK",
|
||||
@ -219,11 +274,26 @@
|
||||
"symbol": "ARN",
|
||||
"decimal": 8
|
||||
},
|
||||
{
|
||||
"address": "0x464eBE77c293E473B48cFe96dDCf88fcF7bFDAC0",
|
||||
"symbol": "KRL",
|
||||
"decimal": 18
|
||||
},
|
||||
{
|
||||
"address": "0x1014613E2B3CBc4d575054D4982E580d9b99d7B1",
|
||||
"symbol": "BCV",
|
||||
"decimal": 8
|
||||
},
|
||||
{
|
||||
"address": "0xd94F2778e2B3913C53637Ae60647598bE588c570",
|
||||
"symbol": "PRPS (1)",
|
||||
"decimal": 18
|
||||
},
|
||||
{
|
||||
"address": "0x7641b2Ca9DDD58adDf6e3381c1F994Aac5f1A32f",
|
||||
"symbol": "PRPS (2)",
|
||||
"decimal": 18
|
||||
},
|
||||
{
|
||||
"address": "0xdd94De9cFE063577051A5eb7465D08317d8808B6",
|
||||
"symbol": "Devcon2 Token",
|
||||
@ -284,6 +354,16 @@
|
||||
"symbol": "DIVX",
|
||||
"decimal": 18
|
||||
},
|
||||
{
|
||||
"address": "0xe25bCec5D3801cE3a794079BF94adF1B8cCD802D",
|
||||
"symbol": "MAN",
|
||||
"decimal": 18
|
||||
},
|
||||
{
|
||||
"address": "0x5adc961D6AC3f7062D2eA45FEFB8D8167d44b190",
|
||||
"symbol": "DTH",
|
||||
"decimal": 18
|
||||
},
|
||||
{
|
||||
"address": "0x86Fa049857E0209aa7D9e616F7eb3b3B78ECfdb0",
|
||||
"symbol": "EOS",
|
||||
@ -405,13 +485,8 @@
|
||||
"decimal": 18
|
||||
},
|
||||
{
|
||||
"address": "0x55F93985431Fc9304077687a35A1BA103dC1e081",
|
||||
"symbol": "SMT (SmartMesh)",
|
||||
"decimal": 18
|
||||
},
|
||||
{
|
||||
"address": "0x2dCFAAc11c9EebD8C6C42103Fe9e2a6AD237aF27",
|
||||
"symbol": "SMT (Smart Node)",
|
||||
"address": "0x38c87AA89B2B8cD9B95b736e1Fa7b612EA972169",
|
||||
"symbol": "AMO",
|
||||
"decimal": 18
|
||||
},
|
||||
{
|
||||
@ -479,6 +554,11 @@
|
||||
"symbol": "XID",
|
||||
"decimal": 8
|
||||
},
|
||||
{
|
||||
"address": "0xCd4b4b0F3284a33AC49C67961EC6e111708318Cf",
|
||||
"symbol": "AX1",
|
||||
"decimal": 5
|
||||
},
|
||||
{
|
||||
"address": "0xdAC17F958D2ee523a2206206994597C13D831ec7",
|
||||
"symbol": "USDT",
|
||||
@ -524,6 +604,21 @@
|
||||
"symbol": "BTT",
|
||||
"decimal": 0
|
||||
},
|
||||
{
|
||||
"address": "0x9fC0583220eB44fAeE9e2dc1E63F39204DDD9090",
|
||||
"symbol": "2DC",
|
||||
"decimal": 18
|
||||
},
|
||||
{
|
||||
"address": "0x0E8d6b471e332F140e7d9dbB99E5E3822F728DA6",
|
||||
"symbol": "ABYSS",
|
||||
"decimal": 18
|
||||
},
|
||||
{
|
||||
"address": "0xC87c5dD86A3d567fF28701886fB0745aaa898da4",
|
||||
"symbol": "CTG",
|
||||
"decimal": 18
|
||||
},
|
||||
{
|
||||
"address": "0xfbd0d1c77B501796A35D86cF91d65D9778EeE695",
|
||||
"symbol": "TWNKL",
|
||||
@ -626,7 +721,12 @@
|
||||
},
|
||||
{
|
||||
"address": "0xD4CffeeF10F60eCA581b5E1146B5Aca4194a4C3b",
|
||||
"symbol": "DUBI",
|
||||
"symbol": "DUBI (1)",
|
||||
"decimal": 18
|
||||
},
|
||||
{
|
||||
"address": "0x9c6Fa42209169bCeA032e401188a6fc3e9C9f59c",
|
||||
"symbol": "DUBI (2)",
|
||||
"decimal": 18
|
||||
},
|
||||
{
|
||||
@ -709,6 +809,11 @@
|
||||
"symbol": "DCN",
|
||||
"decimal": 0
|
||||
},
|
||||
{
|
||||
"address": "0x6e2050CBFB3eD8A4d39b64cC9f47E711a03a5a89",
|
||||
"symbol": "SSH",
|
||||
"decimal": 18
|
||||
},
|
||||
{
|
||||
"address": "0x59416A25628A76b4730eC51486114c32E0B582A1",
|
||||
"symbol": "PLASMA",
|
||||
@ -729,6 +834,11 @@
|
||||
"symbol": "CCC (ICONOMI)",
|
||||
"decimal": 18
|
||||
},
|
||||
{
|
||||
"address": "0x075c60EE2cD308ff47873b38Bd9A0Fa5853382c4",
|
||||
"symbol": "DEEZ",
|
||||
"decimal": 18
|
||||
},
|
||||
{
|
||||
"address": "0x638AC149eA8EF9a1286C41B977017AA7359E6Cfa",
|
||||
"symbol": "ALTS",
|
||||
@ -739,6 +849,11 @@
|
||||
"symbol": "WCN",
|
||||
"decimal": 18
|
||||
},
|
||||
{
|
||||
"address": "0xFA1a856Cfa3409CFa145Fa4e20Eb270dF3EB21ab",
|
||||
"symbol": "IOST",
|
||||
"decimal": 18
|
||||
},
|
||||
{
|
||||
"address": "0x5BC7e5f0Ab8b2E10D2D0a3F21739FCe62459aeF3",
|
||||
"symbol": "ENTRP",
|
||||
@ -824,6 +939,11 @@
|
||||
"symbol": "NBAI",
|
||||
"decimal": 18
|
||||
},
|
||||
{
|
||||
"address": "0x6710c63432A2De02954fc0f851db07146a6c0312",
|
||||
"symbol": "MFG",
|
||||
"decimal": 18
|
||||
},
|
||||
{
|
||||
"address": "0x65A15014964F2102Ff58647e16a16a6B9E14bCF6",
|
||||
"symbol": "Ox Fina",
|
||||
@ -914,6 +1034,11 @@
|
||||
"symbol": "LA",
|
||||
"decimal": 18
|
||||
},
|
||||
{
|
||||
"address": "0x7e9e431a0B8c4D532C745B1043c7FA29a48D4fBa",
|
||||
"symbol": "eosDAC",
|
||||
"decimal": 18
|
||||
},
|
||||
{
|
||||
"address": "0xb5C33F965C8899D255c34CDD2A3efA8AbCbB3DeA",
|
||||
"symbol": "KPR",
|
||||
@ -1069,6 +1194,11 @@
|
||||
"symbol": "SIG",
|
||||
"decimal": 18
|
||||
},
|
||||
{
|
||||
"address": "0xDF347911910b6c9A4286bA8E2EE5ea4a39eB2134",
|
||||
"symbol": "BOB",
|
||||
"decimal": 18
|
||||
},
|
||||
{
|
||||
"address": "0x4F4f0Db4de903B88f2B1a2847971E231D54F8fd3",
|
||||
"symbol": "GEE",
|
||||
@ -1089,6 +1219,11 @@
|
||||
"symbol": "BTL (Bitlle)",
|
||||
"decimal": 4
|
||||
},
|
||||
{
|
||||
"address": "0xdD41fBd1Ae95C5D9B198174A28e04Be6b3d1aa27",
|
||||
"symbol": "LYS",
|
||||
"decimal": 8
|
||||
},
|
||||
{
|
||||
"address": "0xf3Db5Fa2C66B7aF3Eb0C0b782510816cbe4813b8",
|
||||
"symbol": "EVX",
|
||||
@ -1134,6 +1269,11 @@
|
||||
"symbol": "LGO",
|
||||
"decimal": 8
|
||||
},
|
||||
{
|
||||
"address": "0xAd8DD4c725dE1D31b9E8F8D146089e9DC6882093",
|
||||
"symbol": "MIT (Mychatcoin)",
|
||||
"decimal": 6
|
||||
},
|
||||
{
|
||||
"address": "0xA89b5934863447f6E4Fc53B315a93e873bdA69a3",
|
||||
"symbol": "LUM",
|
||||
@ -1174,6 +1314,11 @@
|
||||
"symbol": "FLX",
|
||||
"decimal": 18
|
||||
},
|
||||
{
|
||||
"address": "0x554FFc77F4251a9fB3c0E3590a6a205f8d4e067D",
|
||||
"symbol": "ZMN",
|
||||
"decimal": 18
|
||||
},
|
||||
{
|
||||
"address": "0x888666CA69E0f178DED6D75b5726Cee99A87D698",
|
||||
"symbol": "ICN",
|
||||
@ -1239,6 +1384,11 @@
|
||||
"symbol": "EDC",
|
||||
"decimal": 6
|
||||
},
|
||||
{
|
||||
"address": "0xDDe12a12A6f67156e0DA672be05c374e1B0a3e57",
|
||||
"symbol": "JOY",
|
||||
"decimal": 6
|
||||
},
|
||||
{
|
||||
"address": "0xEF68e7C694F40c8202821eDF525dE3782458639f",
|
||||
"symbol": "LRC",
|
||||
@ -1259,6 +1409,11 @@
|
||||
"symbol": "RVL",
|
||||
"decimal": 18
|
||||
},
|
||||
{
|
||||
"address": "0x7f6715c3FC4740A02F70De85B9FD50ac6001fEd9",
|
||||
"symbol": "FANX",
|
||||
"decimal": 18
|
||||
},
|
||||
{
|
||||
"address": "0xa74476443119A942dE498590Fe1f2454d7D4aC0d",
|
||||
"symbol": "GNT",
|
||||
@ -1339,6 +1494,11 @@
|
||||
"symbol": "CC3",
|
||||
"decimal": 18
|
||||
},
|
||||
{
|
||||
"address": "0x0C91B015AbA6f7B4738dcD36E7410138b29ADC29",
|
||||
"symbol": "COIL",
|
||||
"decimal": 8
|
||||
},
|
||||
{
|
||||
"address": "0x85e076361cc813A908Ff672F9BAd1541474402b2",
|
||||
"symbol": "TEL",
|
||||
@ -1369,6 +1529,16 @@
|
||||
"symbol": "AIX",
|
||||
"decimal": 18
|
||||
},
|
||||
{
|
||||
"address": "0x6c6EE5e31d828De241282B9606C8e98Ea48526E2",
|
||||
"symbol": "HOT (HoloToken)",
|
||||
"decimal": 18
|
||||
},
|
||||
{
|
||||
"address": "0x9AF839687F6C94542ac5ece2e317dAAE355493A1",
|
||||
"symbol": "HOT (Hydro Protocol)",
|
||||
"decimal": 18
|
||||
},
|
||||
{
|
||||
"address": "0x6927C69fb4daf2043fbB1Cb7b86c5661416bea29",
|
||||
"symbol": "ETR",
|
||||
@ -1414,6 +1584,11 @@
|
||||
"symbol": "CTX",
|
||||
"decimal": 18
|
||||
},
|
||||
{
|
||||
"address": "0xf0Ee6b27b759C9893Ce4f094b49ad28fd15A23e4",
|
||||
"symbol": "ENG",
|
||||
"decimal": 8
|
||||
},
|
||||
{
|
||||
"address": "0x1844b21593262668B7248d0f57a220CaaBA46ab9",
|
||||
"symbol": "PRL",
|
||||
@ -1444,6 +1619,11 @@
|
||||
"symbol": "S-A-PAT",
|
||||
"decimal": 18
|
||||
},
|
||||
{
|
||||
"address": "0xf6b6AA0Ef0f5Edc2C1c5d925477F97eAF66303e7",
|
||||
"symbol": "XGG",
|
||||
"decimal": 8
|
||||
},
|
||||
{
|
||||
"address": "0x3618516F45CD3c913F81F9987AF41077932Bc40d",
|
||||
"symbol": "PCL",
|
||||
@ -1474,6 +1654,11 @@
|
||||
"symbol": "onG",
|
||||
"decimal": 18
|
||||
},
|
||||
{
|
||||
"address": "0x0a9A9ce600D08BF9b76F49FA4e7b38A67EBEB1E6",
|
||||
"symbol": "GROW",
|
||||
"decimal": 8
|
||||
},
|
||||
{
|
||||
"address": "0xF26ef5E0545384b7Dcc0f297F2674189586830DF",
|
||||
"symbol": "BSDC",
|
||||
@ -1549,6 +1734,11 @@
|
||||
"symbol": "REBL",
|
||||
"decimal": 18
|
||||
},
|
||||
{
|
||||
"address": "0xC64500DD7B0f1794807e67802F8Abbf5F8Ffb054",
|
||||
"symbol": "LOCUS",
|
||||
"decimal": 18
|
||||
},
|
||||
{
|
||||
"address": "0x83eEA00D838f92dEC4D1475697B9f4D3537b56E3",
|
||||
"symbol": "VOISE",
|
||||
@ -1594,6 +1784,11 @@
|
||||
"symbol": "DCA",
|
||||
"decimal": 18
|
||||
},
|
||||
{
|
||||
"address": "0x8a77e40936BbC27e80E9a3F526368C967869c86D",
|
||||
"symbol": "MVP",
|
||||
"decimal": 18
|
||||
},
|
||||
{
|
||||
"address": "0x9E46A38F5DaaBe8683E10793b06749EEF7D733d1",
|
||||
"symbol": "NCT",
|
||||
@ -1645,9 +1840,14 @@
|
||||
"decimal": 18
|
||||
},
|
||||
{
|
||||
"address": "0xd248B0D48E44aaF9c49aea0312be7E13a6dc1468",
|
||||
"symbol": "SGT",
|
||||
"decimal": 1
|
||||
"address": "0xFcD862985628b254061F7A918035B80340D045d3",
|
||||
"symbol": "GIF",
|
||||
"decimal": 18
|
||||
},
|
||||
{
|
||||
"address": "0x922aC473A3cC241fD3a0049Ed14536452D58D73c",
|
||||
"symbol": "VLD",
|
||||
"decimal": 18
|
||||
},
|
||||
{
|
||||
"address": "0xfeDAE5642668f8636A11987Ff386bfd215F942EE",
|
||||
@ -1689,6 +1889,11 @@
|
||||
"symbol": "DAXT",
|
||||
"decimal": 18
|
||||
},
|
||||
{
|
||||
"address": "0x523630976eB6147621B5c31c781eBe2Ec2a806E0",
|
||||
"symbol": "eUSD",
|
||||
"decimal": 18
|
||||
},
|
||||
{
|
||||
"address": "0xF433089366899D83a9f26A773D59ec7eCF30355e",
|
||||
"symbol": "MTL",
|
||||
@ -1739,6 +1944,11 @@
|
||||
"symbol": "HKY",
|
||||
"decimal": 18
|
||||
},
|
||||
{
|
||||
"address": "0x2467AA6B5A2351416fD4C3DeF8462d841feeecEC",
|
||||
"symbol": "QBX",
|
||||
"decimal": 18
|
||||
},
|
||||
{
|
||||
"address": "0x5dbe296F97B23C4A6AA6183D73e574D02bA5c719",
|
||||
"symbol": "LUC",
|
||||
@ -1819,6 +2029,11 @@
|
||||
"symbol": "CK",
|
||||
"decimal": 0
|
||||
},
|
||||
{
|
||||
"address": "0x48e5413b73add2434e47504E2a22d14940dBFe78",
|
||||
"symbol": "INRM",
|
||||
"decimal": 3
|
||||
},
|
||||
{
|
||||
"address": "0x1e49fF77c355A3e38D6651ce8404AF0E48c5395f",
|
||||
"symbol": "MTRc",
|
||||
@ -1844,16 +2059,21 @@
|
||||
"symbol": "DICE",
|
||||
"decimal": 16
|
||||
},
|
||||
{
|
||||
"address": "0x9AF839687F6C94542ac5ece2e317dAAE355493A1",
|
||||
"symbol": "HOT",
|
||||
"decimal": 18
|
||||
},
|
||||
{
|
||||
"address": "0x744d70FDBE2Ba4CF95131626614a1763DF805B9E",
|
||||
"symbol": "SNT",
|
||||
"decimal": 18
|
||||
},
|
||||
{
|
||||
"address": "0x69c4BB240cF05D51eeab6985Bab35527d04a8C64",
|
||||
"symbol": "OPEN (1)",
|
||||
"decimal": 8
|
||||
},
|
||||
{
|
||||
"address": "0xe9dE1C630753A15d7021Cc563429c21d4887506F",
|
||||
"symbol": "OPEN (2)",
|
||||
"decimal": 8
|
||||
},
|
||||
{
|
||||
"address": "0x1a7a8BD9106F2B8D977E08582DC7d24c723ab0DB",
|
||||
"symbol": "APPC",
|
||||
@ -1929,6 +2149,11 @@
|
||||
"symbol": "SAN",
|
||||
"decimal": 18
|
||||
},
|
||||
{
|
||||
"address": "0x82fdedfB7635441aA5A92791D001fA7388da8025",
|
||||
"symbol": "DTx",
|
||||
"decimal": 18
|
||||
},
|
||||
{
|
||||
"address": "0x8eFFd494eB698cc399AF6231fCcd39E08fd20B15",
|
||||
"symbol": "PIX",
|
||||
@ -2024,6 +2249,11 @@
|
||||
"symbol": "GXVC",
|
||||
"decimal": 10
|
||||
},
|
||||
{
|
||||
"address": "0x8a854288a5976036A725879164Ca3e91d30c6A1B",
|
||||
"symbol": "GET",
|
||||
"decimal": 18
|
||||
},
|
||||
{
|
||||
"address": "0x4c382F8E09615AC86E08CE58266CC227e7d4D913",
|
||||
"symbol": "SKR",
|
||||
@ -2109,6 +2339,11 @@
|
||||
"symbol": "STAC",
|
||||
"decimal": 18
|
||||
},
|
||||
{
|
||||
"address": "0xfe7B915A0bAA0E79f85c5553266513F7C1c03Ed0",
|
||||
"symbol": "THUG",
|
||||
"decimal": 18
|
||||
},
|
||||
{
|
||||
"address": "0xC0Eb85285d83217CD7c891702bcbC0FC401E2D9D",
|
||||
"symbol": "HVN",
|
||||
@ -2209,11 +2444,6 @@
|
||||
"symbol": "GELD",
|
||||
"decimal": 18
|
||||
},
|
||||
{
|
||||
"address": "0x7641b2Ca9DDD58adDf6e3381c1F994Aac5f1A32f",
|
||||
"symbol": "PRPS",
|
||||
"decimal": 18
|
||||
},
|
||||
{
|
||||
"address": "0x0AfFa06e7Fbe5bC9a764C979aA66E8256A631f02",
|
||||
"symbol": "PLBT",
|
||||
@ -2269,6 +2499,11 @@
|
||||
"symbol": "YUPIE",
|
||||
"decimal": 18
|
||||
},
|
||||
{
|
||||
"address": "0x558EC3152e2eb2174905cd19AeA4e34A23DE9aD6",
|
||||
"symbol": "BRD",
|
||||
"decimal": 18
|
||||
},
|
||||
{
|
||||
"address": "0xaAAf91D9b90dF800Df4F55c205fd6989c977E73a",
|
||||
"symbol": "TKN",
|
||||
@ -2284,6 +2519,11 @@
|
||||
"symbol": "BCPT",
|
||||
"decimal": 18
|
||||
},
|
||||
{
|
||||
"address": "0x9aeFBE0b3C3ba9Eab262CB9856E8157AB7648e09",
|
||||
"symbol": "FLR",
|
||||
"decimal": 18
|
||||
},
|
||||
{
|
||||
"address": "0x0AF44e2784637218dD1D32A322D44e603A8f0c6A",
|
||||
"symbol": "MTX",
|
||||
@ -2399,6 +2639,11 @@
|
||||
"symbol": "DROP",
|
||||
"decimal": 0
|
||||
},
|
||||
{
|
||||
"address": "0xF03f8D65BaFA598611C3495124093c56e8F638f0",
|
||||
"symbol": "VIEW",
|
||||
"decimal": 18
|
||||
},
|
||||
{
|
||||
"address": "0x43F6a1BE992deE408721748490772B15143CE0a7",
|
||||
"symbol": "POIN",
|
||||
@ -2604,6 +2849,16 @@
|
||||
"symbol": "WPR",
|
||||
"decimal": 18
|
||||
},
|
||||
{
|
||||
"address": "0x543Ff227F64Aa17eA132Bf9886cAb5DB55DCAddf",
|
||||
"symbol": "GEN",
|
||||
"decimal": 18
|
||||
},
|
||||
{
|
||||
"address": "0xD760ADdFb24D9C01Fe4Bfea7475C5e3636684058",
|
||||
"symbol": "USDM",
|
||||
"decimal": 2
|
||||
},
|
||||
{
|
||||
"address": "0xF4134146AF2d511Dd5EA8cDB1C4AC88C57D60404",
|
||||
"symbol": "SNC",
|
||||
@ -2644,11 +2899,6 @@
|
||||
"symbol": "EMONT",
|
||||
"decimal": 8
|
||||
},
|
||||
{
|
||||
"address": "0xe9dE1C630753A15d7021Cc563429c21d4887506F",
|
||||
"symbol": "OPEN",
|
||||
"decimal": 8
|
||||
},
|
||||
{
|
||||
"address": "0x514910771AF9Ca656af840dff83E8264EcF986CA",
|
||||
"symbol": "LINK (Chainlink)",
|
||||
@ -2899,6 +3149,11 @@
|
||||
"symbol": "AIR",
|
||||
"decimal": 8
|
||||
},
|
||||
{
|
||||
"address": "0xF244176246168F24e3187f7288EdbCA29267739b",
|
||||
"symbol": "HAV",
|
||||
"decimal": 18
|
||||
},
|
||||
{
|
||||
"address": "0xc8C6A31A4A806d3710A7B38b7B296D2fABCCDBA8",
|
||||
"symbol": "ELIX",
|
||||
|
@ -28,9 +28,7 @@ import {
|
||||
SecureSlideThree,
|
||||
FinalSlide
|
||||
} from './components';
|
||||
|
||||
const ONBOARD_LOCAL_STORAGE_KEY = 'onboardStatus';
|
||||
const NUMBER_OF_SLIDES = 10;
|
||||
import { ONBOARD_LOCAL_STORAGE_KEY, NUMBER_OF_ONBOARD_SLIDES } from 'utils/localStorage';
|
||||
|
||||
interface State {
|
||||
isOpen: boolean;
|
||||
@ -58,7 +56,6 @@ class OnboardModal extends React.Component<Props, State> {
|
||||
|
||||
public componentDidMount() {
|
||||
const { sessionStarted } = this.props;
|
||||
|
||||
const currentSlide = Number(localStorage.getItem(ONBOARD_LOCAL_STORAGE_KEY)) || 0;
|
||||
|
||||
if (!sessionStarted) {
|
||||
@ -68,7 +65,7 @@ class OnboardModal extends React.Component<Props, State> {
|
||||
isOpen: true
|
||||
});
|
||||
}
|
||||
if (currentSlide > 0 && currentSlide < NUMBER_OF_SLIDES) {
|
||||
if (currentSlide > 0 && currentSlide < NUMBER_OF_ONBOARD_SLIDES) {
|
||||
this.props.resumeSlide(currentSlide);
|
||||
this.setState({
|
||||
isOpen: true
|
||||
@ -90,7 +87,7 @@ class OnboardModal extends React.Component<Props, State> {
|
||||
|
||||
const firstButtons: IButton[] = [
|
||||
{
|
||||
disabled: slideNumber === NUMBER_OF_SLIDES,
|
||||
disabled: slideNumber === NUMBER_OF_ONBOARD_SLIDES,
|
||||
text: translate('ACTION_6'),
|
||||
type: 'primary',
|
||||
onClick: this.handleNextSlide
|
||||
@ -115,8 +112,8 @@ class OnboardModal extends React.Component<Props, State> {
|
||||
}
|
||||
];
|
||||
|
||||
const buttons = slideNumber === NUMBER_OF_SLIDES ? lastButtons : firstButtons;
|
||||
const steps = new Array(NUMBER_OF_SLIDES).fill({});
|
||||
const buttons = slideNumber === NUMBER_OF_ONBOARD_SLIDES ? lastButtons : firstButtons;
|
||||
const steps = new Array(NUMBER_OF_ONBOARD_SLIDES).fill({});
|
||||
|
||||
return (
|
||||
<div className="OnboardModal">
|
||||
@ -158,8 +155,8 @@ class OnboardModal extends React.Component<Props, State> {
|
||||
<FinalSlide key={10} closeModal={this.closeModal} />
|
||||
];
|
||||
|
||||
if (slides.length !== NUMBER_OF_SLIDES) {
|
||||
console.log('Slides length do not match const NUMBER_OF_SLIDES');
|
||||
if (slides.length !== NUMBER_OF_ONBOARD_SLIDES) {
|
||||
console.log('Slides length do not match const NUMBER_OF_ONBOARD_SLIDES');
|
||||
}
|
||||
const currentSlideIndex = this.props.slideNumber - 1;
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React, { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { BetaAgreement, Footer, Header } from 'components';
|
||||
import { Footer, Header } from 'components';
|
||||
import { AppState } from 'reducers';
|
||||
import Notifications from './Notifications';
|
||||
import OfflineTab from './OfflineTab';
|
||||
@ -38,7 +38,6 @@ class WebTemplate extends Component<Props, {}> {
|
||||
<div className="WebTemplate-spacer" />
|
||||
<Footer latestBlock={latestBlock} />
|
||||
<Notifications />
|
||||
<BetaAgreement />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -65,7 +65,7 @@ class BroadcastTx extends Component<Props> {
|
||||
<Input
|
||||
type="text"
|
||||
placeholder="0xf86b0284ee6b2800825208944bbeeb066ed09b7aed07bf39eee0460dfa26152088016345785d8a00008029a03ba7a0cc6d1756cd771f2119cf688b6d4dc9d37096089f0331fe0de0d1cc1254a02f7bcd19854c8d46f8de09e457aec25b127ab4328e1c0d24bfbff8702ee1f474"
|
||||
className={stateTransaction ? '' : 'invalid'}
|
||||
isValid={!!stateTransaction}
|
||||
value={userInput}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
|
@ -33,7 +33,7 @@ class TxHashInput extends React.Component<Props, State> {
|
||||
this.state = { hash: props.hash || '' };
|
||||
}
|
||||
|
||||
public componentWillReceiveProps(nextProps: Props) {
|
||||
public UNSAFE_componentWillReceiveProps(nextProps: Props) {
|
||||
if (this.props.hash !== nextProps.hash && nextProps.hash) {
|
||||
this.setState({ hash: nextProps.hash });
|
||||
}
|
||||
@ -42,7 +42,7 @@ class TxHashInput extends React.Component<Props, State> {
|
||||
public render() {
|
||||
const { recentTxs } = this.props;
|
||||
const { hash } = this.state;
|
||||
const validClass = hash ? (isValidTxHash(hash) ? 'is-valid' : 'is-invalid') : '';
|
||||
|
||||
let selectOptions: Option[] = [];
|
||||
|
||||
if (recentTxs && recentTxs.length) {
|
||||
@ -75,8 +75,9 @@ class TxHashInput extends React.Component<Props, State> {
|
||||
|
||||
<Input
|
||||
value={hash}
|
||||
isValid={hash ? isValidTxHash(hash) : true}
|
||||
placeholder="0x16e521..."
|
||||
className={`TxHashInput-field ${validClass}`}
|
||||
className="TxHashInput-field"
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
|
||||
|
@ -34,7 +34,7 @@ class CheckTransaction extends React.Component<Props, State> {
|
||||
}
|
||||
}
|
||||
|
||||
public componentWillReceiveProps(nextProps: Props) {
|
||||
public UNSAFE_componentWillReceiveProps(nextProps: Props) {
|
||||
const { network } = this.props;
|
||||
if (network.chainId !== nextProps.network.chainId) {
|
||||
this.setState({ hash: '' });
|
||||
|
@ -1,5 +1,4 @@
|
||||
import translate from 'translations';
|
||||
import classnames from 'classnames';
|
||||
import { DataFieldFactory } from 'components/DataFieldFactory';
|
||||
import { SendButtonFactory } from 'components/SendButtonFactory';
|
||||
import WalletDecrypt, { DISABLE_WALLETS } from 'components/WalletDecrypt';
|
||||
@ -31,16 +30,15 @@ class DeployClass extends Component<DispatchProps> {
|
||||
<label className="input-group">
|
||||
<div className="input-group-header">{translate('CONTRACT_BYTECODE')}</div>
|
||||
<DataFieldFactory
|
||||
withProps={({ data: { raw, value }, onChange, readOnly }) => (
|
||||
withProps={({ data: { raw }, onChange, readOnly, validData }) => (
|
||||
<TextArea
|
||||
isValid={validData && !!raw}
|
||||
name="byteCode"
|
||||
placeholder="0x8f87a973e..."
|
||||
rows={6}
|
||||
onChange={onChange}
|
||||
disabled={readOnly}
|
||||
className={classnames('Deploy-field-input', {
|
||||
'is-valid': value && value.length > 0
|
||||
})}
|
||||
className="Deploy-field-input"
|
||||
value={raw}
|
||||
/>
|
||||
)}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { AmountFieldFactory } from 'components/AmountFieldFactory';
|
||||
import React from 'react';
|
||||
import classnames from 'classnames';
|
||||
|
||||
import { Input } from 'components/ui';
|
||||
|
||||
export const AmountField: React.SFC = () => (
|
||||
@ -12,11 +12,10 @@ export const AmountField: React.SFC = () => (
|
||||
<Input
|
||||
name="value"
|
||||
value={raw}
|
||||
isValid={isValid || raw === ''}
|
||||
onChange={onChange}
|
||||
readOnly={readOnly}
|
||||
className={classnames('InteractExplorer-field-input', 'form-control', {
|
||||
'is-invalid': !(isValid || raw === '')
|
||||
})}
|
||||
className="InteractExplorer-field-input"
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
|
@ -116,6 +116,7 @@ class InteractExplorerClass extends Component<Props, State> {
|
||||
<div className="input-group-header">{name + ' ' + type}</div>
|
||||
<Input
|
||||
className="InteractExplorer-func-in-input"
|
||||
isValid={!!(inputs[name] && inputs[name].rawData)}
|
||||
name={name}
|
||||
value={(inputs[name] && inputs[name].rawData) || ''}
|
||||
onChange={this.handleInputChange}
|
||||
@ -138,7 +139,8 @@ class InteractExplorerClass extends Component<Props, State> {
|
||||
<label className="input-group">
|
||||
<div className="input-group-header"> ↳ {name + ' ' + type}</div>
|
||||
<Input
|
||||
className="InteractExplorer-func-out-input "
|
||||
className="InteractExplorer-func-out-input"
|
||||
isValid={!!decodedFieldValue}
|
||||
value={decodedFieldValue}
|
||||
disabled={true}
|
||||
/>
|
||||
|
@ -4,7 +4,6 @@ import { getNetworkContracts } from 'selectors/config';
|
||||
import { connect } from 'react-redux';
|
||||
import { AppState } from 'reducers';
|
||||
import { isValidETHAddress, isValidAbiJson } from 'libs/validators';
|
||||
import classnames from 'classnames';
|
||||
import { NetworkContract } from 'types/network';
|
||||
import { donationAddressMap } from 'config';
|
||||
import { Input, TextArea, CodeBlock, Dropdown } from 'components/ui';
|
||||
@ -63,7 +62,7 @@ class InteractForm extends Component<Props, State> {
|
||||
};
|
||||
}
|
||||
|
||||
public componentWillReceiveProps(nextProps: Props) {
|
||||
public UNSAFE_componentWillReceiveProps(nextProps: Props) {
|
||||
const prevProps = this.props;
|
||||
if (nextProps.currentTo.raw !== prevProps.currentTo.raw) {
|
||||
nextProps.resetState();
|
||||
@ -126,9 +125,8 @@ class InteractForm extends Component<Props, State> {
|
||||
name="contract_address"
|
||||
autoComplete="off"
|
||||
value={currentTo.raw}
|
||||
className={classnames('InteractForm-address-field-input', {
|
||||
invalid: !isValid
|
||||
})}
|
||||
isValid={isValid}
|
||||
className="InteractForm-address-field-input"
|
||||
spellCheck={false}
|
||||
onChange={onChange}
|
||||
/>
|
||||
@ -144,7 +142,8 @@ class InteractForm extends Component<Props, State> {
|
||||
contract.name === 'Custom' ? (
|
||||
<TextArea
|
||||
placeholder={this.abiJsonPlaceholder}
|
||||
className={`InteractForm-interface-field-input ${validAbiJson ? '' : 'invalid'}`}
|
||||
isValid={!!validAbiJson}
|
||||
className="InteractForm-interface-field-input"
|
||||
onChange={this.handleInput('abiJson')}
|
||||
value={abiJson}
|
||||
rows={6}
|
||||
@ -155,7 +154,8 @@ class InteractForm extends Component<Props, State> {
|
||||
) : (
|
||||
<TextArea
|
||||
placeholder={this.abiJsonPlaceholder}
|
||||
className={`InteractForm-interface-field-input ${validAbiJson ? '' : 'invalid'}`}
|
||||
isValid={!!validAbiJson}
|
||||
className="InteractForm-interface-field-input"
|
||||
onChange={this.handleInput('abiJson')}
|
||||
value={abiJson}
|
||||
rows={6}
|
||||
|
@ -37,9 +37,8 @@ class NameInput extends Component<Props, State> {
|
||||
<label className="input-group input-group-inline ENSInput-name">
|
||||
<Input
|
||||
value={domainToCheck}
|
||||
className={`${
|
||||
!domainToCheck ? '' : isValidDomain ? '' : 'invalid'
|
||||
} border-rad-right-0`}
|
||||
isValid={!!domainToCheck && isValidDomain}
|
||||
className="border-rad-right-0"
|
||||
type="text"
|
||||
placeholder="mycrypto"
|
||||
onChange={this.onChange}
|
||||
|
@ -21,6 +21,8 @@ const PaperWallet: React.SFC<Props> = props => (
|
||||
<h1 className="GenPaper-title">{translate('GEN_LABEL_5')}</h1>
|
||||
<Input
|
||||
value={stripHexPrefix(props.privateKey)}
|
||||
showValidAsPlain={true}
|
||||
isValid={true}
|
||||
aria-label={translateRaw('X_PRIVKEY')}
|
||||
aria-describedby="x_PrivKeyDesc"
|
||||
type="text"
|
||||
|
@ -61,7 +61,13 @@ export default class MnemonicWord extends React.Component<Props, State> {
|
||||
{word}
|
||||
</button>
|
||||
) : (
|
||||
<Input className="MnemonicWord-word-input" value={word} readOnly={true} />
|
||||
<Input
|
||||
className="MnemonicWord-word-input"
|
||||
value={word}
|
||||
readOnly={true}
|
||||
showValidAsPlain={true}
|
||||
isValid={true}
|
||||
/>
|
||||
)}
|
||||
</label>
|
||||
</div>
|
||||
|
@ -38,7 +38,7 @@ class ScheduleDepositFieldClass extends Component<Props> {
|
||||
</span>
|
||||
</div>
|
||||
<Input
|
||||
className={!!scheduleDeposit.raw && !validScheduleDeposit ? 'invalid' : ''}
|
||||
isValid={scheduleDeposit.raw && validScheduleDeposit}
|
||||
type="number"
|
||||
placeholder="0.00001"
|
||||
value={scheduleDeposit.raw}
|
||||
|
@ -34,7 +34,7 @@ class ScheduleGasLimitFieldClass extends React.Component<Props> {
|
||||
<InlineSpinner active={gasEstimationPending} text="Calculating" />
|
||||
</div>
|
||||
<Input
|
||||
className={!!scheduleGasLimit.raw && !validScheduleGasLimit ? 'invalid' : ''}
|
||||
isValid={scheduleGasLimit.raw && validScheduleGasLimit}
|
||||
type="number"
|
||||
placeholder={EAC_SCHEDULING_CONFIG.SCHEDULE_GAS_LIMIT_FALLBACK.toString()}
|
||||
value={scheduleGasLimit.raw}
|
||||
|
@ -27,7 +27,7 @@ class ScheduleGasPriceFieldClass extends React.Component<Props> {
|
||||
<label className="input-group">
|
||||
<div className="input-group-header">{translateRaw('SCHEDULE_GAS_PRICE')} (gwei)</div>
|
||||
<Input
|
||||
className={!!scheduleGasPrice.raw && !validScheduleGasPrice ? 'invalid' : ''}
|
||||
isValid={scheduleGasPrice.raw && validScheduleGasPrice}
|
||||
type="number"
|
||||
placeholder="40"
|
||||
value={scheduleGasPrice.raw}
|
||||
|
@ -25,7 +25,7 @@ export const TimeBountyField: React.SFC<Props> = ({ isReadOnly }) => (
|
||||
</span>
|
||||
</div>
|
||||
<Input
|
||||
className={`input-group-input ${isValid ? '' : 'invalid'}`}
|
||||
isValid={isValid}
|
||||
type="text"
|
||||
value={currentTimeBounty.raw}
|
||||
placeholder={translateRaw('SCHEDULE_TIMEBOUNTY_PLACEHOLDER')}
|
||||
|
@ -32,7 +32,7 @@ export const WindowSizeField: React.SFC<Props> = ({ isReadOnly }) => (
|
||||
</span>
|
||||
</div>
|
||||
<Input
|
||||
className={`input-group-input ${isValid ? '' : 'invalid'}`}
|
||||
isValid={isValid}
|
||||
type="text"
|
||||
value={currentWindowSize.raw}
|
||||
placeholder={
|
||||
|
@ -14,7 +14,7 @@ export const WindowStartField: React.SFC<Props> = ({ isReadOnly }) => (
|
||||
<label className="input-group">
|
||||
<div className="input-group-header">{translate('SCHEDULE_BLOCK')}</div>
|
||||
<Input
|
||||
className={`input-group-input ${isValid ? '' : 'invalid'}`}
|
||||
isValid={isValid}
|
||||
type="text"
|
||||
value={currentWindowStart.raw}
|
||||
placeholder={translateRaw('SCHEDULE_BLOCK_PLACEHOLDER')}
|
||||
|
@ -68,7 +68,7 @@ class RequestPayment extends React.Component<Props, {}> {
|
||||
this.props.resetTransactionRequested();
|
||||
}
|
||||
|
||||
public componentWillReceiveProps(nextProps: Props) {
|
||||
public UNSAFE_componentWillReceiveProps(nextProps: Props) {
|
||||
if (nextProps.wallet && this.props.wallet !== nextProps.wallet) {
|
||||
this.setWalletAsyncState(nextProps.wallet);
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ export default class WalletInfo extends React.PureComponent<Props, State> {
|
||||
this.setStateFromWallet(this.props.wallet);
|
||||
}
|
||||
|
||||
public componentWillReceiveProps(nextProps: Props) {
|
||||
public UNSAFE_componentWillReceiveProps(nextProps: Props) {
|
||||
if (this.props.wallet !== nextProps.wallet) {
|
||||
this.setStateFromWallet(nextProps.wallet);
|
||||
}
|
||||
|
@ -57,7 +57,8 @@ export class SignMessage extends Component<Props, State> {
|
||||
<label className="input-group">
|
||||
<div className="input-group-header">{translate('MSG_MESSAGE')}</div>
|
||||
<TextArea
|
||||
className={`SignMessage-inputBox ${message ? 'is-valid' : 'is-invalid'}`}
|
||||
isValid={!!message}
|
||||
className="SignMessage-inputBox"
|
||||
placeholder={messagePlaceholder}
|
||||
value={message}
|
||||
onChange={this.handleMessageChange}
|
||||
|
@ -41,7 +41,8 @@ export class VerifyMessage extends Component<Props, State> {
|
||||
<label className="input-group">
|
||||
<div className="input-group-header">{translate('MSG_SIGNATURE')}</div>
|
||||
<TextArea
|
||||
className={`VerifyMessage-inputBox ${signature ? 'is-valid' : 'is-invalid'}`}
|
||||
isValid={!!signature}
|
||||
className="VerifyMessage-inputBox"
|
||||
placeholder={signaturePlaceholder}
|
||||
value={signature}
|
||||
onChange={this.handleSignatureChange}
|
||||
|
@ -2,7 +2,13 @@ import React from 'react';
|
||||
import translate from 'translations';
|
||||
import TabSection from 'containers/TabSection';
|
||||
import logo from 'assets/images/logo-mycrypto-transparent.svg';
|
||||
import { donationAddressMap, socialMediaLinks, productLinks, affiliateLinks } from 'config';
|
||||
import {
|
||||
donationAddressMap,
|
||||
socialMediaLinks,
|
||||
productLinks,
|
||||
affiliateLinks,
|
||||
VERSION
|
||||
} from 'config';
|
||||
import DisclaimerModal from 'components/DisclaimerModal';
|
||||
import { NewTabLink } from 'components/ui';
|
||||
import './index.scss';
|
||||
@ -47,6 +53,7 @@ export default class SupportPage extends React.Component<{}, State> {
|
||||
<div className="SupportPage-mycrypto-legal-text">
|
||||
<a onClick={this.openDisclaimer}>{translate('DISCLAIMER')}</a>
|
||||
</div>
|
||||
<div className="SupportPage-mycrypto-legal-text">v{VERSION}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -117,7 +117,7 @@ export default class CurrencySwap extends PureComponent<Props, State> {
|
||||
}
|
||||
}
|
||||
|
||||
public componentWillReceiveProps(nextProps: Props) {
|
||||
public UNSAFE_componentWillReceiveProps(nextProps: Props) {
|
||||
if (nextProps.options !== this.props.options) {
|
||||
this.setState({ options: Object.values(nextProps.options.byId) });
|
||||
}
|
||||
@ -316,12 +316,7 @@ export default class CurrencySwap extends PureComponent<Props, State> {
|
||||
<div className="input-group input-group-inline">
|
||||
<Input
|
||||
id="origin-swap-input"
|
||||
className={`input-group-input ${
|
||||
!!origin.amount &&
|
||||
this.isMinMaxValid(origin.amount, origin.label, destination.label)
|
||||
? ''
|
||||
: 'invalid'
|
||||
}`}
|
||||
isValid={!originErr}
|
||||
type="number"
|
||||
placeholder={translateRaw('SEND_AMOUNT_SHORT')}
|
||||
value={isNaN(origin.amount) ? '' : origin.amount}
|
||||
@ -341,12 +336,7 @@ export default class CurrencySwap extends PureComponent<Props, State> {
|
||||
<div className="input-group-header">{translate('SWAP_RECEIVE_INPUT_LABEL')}</div>
|
||||
<Input
|
||||
id="destination-swap-input"
|
||||
className={`${
|
||||
!!destination.amount &&
|
||||
this.isMinMaxValid(origin.amount, origin.label, destination.label)
|
||||
? ''
|
||||
: 'invalid'
|
||||
}`}
|
||||
isValid={!destinationErr}
|
||||
type="number"
|
||||
placeholder={translateRaw('SEND_AMOUNT_SHORT')}
|
||||
value={isNaN(destination.amount) ? '' : destination.amount}
|
||||
|
@ -49,7 +49,7 @@ class CurrentRates extends PureComponent<Props> {
|
||||
}
|
||||
}
|
||||
|
||||
public componentWillReceiveProps(nextProps: Props) {
|
||||
public UNSAFE_componentWillReceiveProps(nextProps: Props) {
|
||||
if (this.props.isOffline && !nextProps.isOffline) {
|
||||
this.loadRates();
|
||||
}
|
||||
|
@ -37,7 +37,12 @@ class FieldsClass extends Component<Props> {
|
||||
<div className="col-xs-12">
|
||||
<AddressFieldFactory
|
||||
withProps={({ currentTo }) => (
|
||||
<Input type="text" value={currentTo.raw} readOnly={true} />
|
||||
<Input
|
||||
type="text"
|
||||
value={currentTo.raw}
|
||||
readOnly={true}
|
||||
isValid={!!currentTo.raw}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
@ -60,6 +65,8 @@ class FieldsClass extends Component<Props> {
|
||||
)}
|
||||
{isValid && (
|
||||
<Input
|
||||
isValid={true}
|
||||
showValidAsPlain={true}
|
||||
type="text"
|
||||
value={`${currentValue.raw} ${this.props.unit}`}
|
||||
readOnly={true}
|
||||
|
@ -21,6 +21,7 @@ export default class PaymentInfo extends PureComponent<Props, {}> {
|
||||
})}
|
||||
<Input
|
||||
className="SwapPayment-address"
|
||||
isValid={!!this.props.paymentAddress}
|
||||
value={this.props.paymentAddress || undefined}
|
||||
disabled={true}
|
||||
/>
|
||||
|
@ -79,7 +79,8 @@ export default class ReceivingAddress extends PureComponent<StateProps & ActionP
|
||||
</h4>
|
||||
|
||||
<Input
|
||||
className={`SwapAddress-address-input ${!validAddress ? 'invalid' : ''}`}
|
||||
isValid={validAddress}
|
||||
className="SwapAddress-address-input"
|
||||
type="text"
|
||||
value={destinationAddress}
|
||||
onChange={this.onChangeDestinationAddress}
|
||||
|
@ -83,7 +83,13 @@ Rate: ${rates[pair].rate} ${origin.label}/${destination.label}`;
|
||||
<small>{translate('SWAP_SUPPORT_LINK_BROKEN')}</small>
|
||||
</p>
|
||||
{open ? (
|
||||
<TextArea defaultValue={fallbackBody} className="form-control input-sm" rows={9} />
|
||||
<TextArea
|
||||
isValid={true}
|
||||
showValidAsPlain={true}
|
||||
defaultValue={fallbackBody}
|
||||
className="input-sm"
|
||||
rows={9}
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
</section>
|
||||
|
@ -5,8 +5,16 @@
|
||||
<meta charset="utf-8">
|
||||
<title>MyCrypto</title>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||
<meta name="description" content="">
|
||||
<meta name="description" content="MyCrypto is a free, open-source interface for interacting with the blockchain.">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0">
|
||||
<meta property="og:title" content="<%= htmlWebpackPlugin.options.title %>">
|
||||
<meta property="og:url" content="<%= htmlWebpackPlugin.options.appUrl %>">
|
||||
<meta property="og:description" content="<%= htmlWebpackPlugin.options.appDescription %>">
|
||||
<meta property="og:site_name" content="<%= htmlWebpackPlugin.options.title %>">
|
||||
<meta property="og:type" content="<%= htmlWebpackPlugin.options.type %>">
|
||||
<meta property="og:image" content="<%= htmlWebpackPlugin.options.image %>">
|
||||
<meta name="twitter:site" content="<%= htmlWebpackPlugin.options.twitter.site %>">
|
||||
<meta name="twitter:creator" content="<%= htmlWebpackPlugin.options.twitter.creator %>">
|
||||
<link rel="manifest" href="/manifest.json">
|
||||
</head>
|
||||
|
||||
@ -32,16 +40,17 @@
|
||||
<div class="BadBrowser-content">
|
||||
<h2>Your Browser is Out of Date</h2>
|
||||
<p class="is-desktop">
|
||||
MyCrypto requires certain features that your browser doesn't offer. Your browser may also be missing security updates
|
||||
that could open you up to vulnerabilities. Please update your browser, or switch to one of the following browsers
|
||||
to continue using MyCrypto.
|
||||
MyCrypto requires certain features that your browser doesn't offer. Your browser may also be missing security updates that
|
||||
could open you up to vulnerabilities. Please update your browser, or switch to one of the following browsers to continue
|
||||
using MyCrypto.
|
||||
</p>
|
||||
<p class="is-mobile">
|
||||
MyCrypto requires certain features that your browser doesn't offer. Please use your device's default browser, or switch
|
||||
to a laptop or desktop computer to continue using MyCrypto.
|
||||
MyCrypto requires certain features that your browser doesn't offer. Please use your device's default browser, or switch to
|
||||
a laptop or desktop computer to continue using MyCrypto.
|
||||
</p>
|
||||
<div class="BadBrowser-content-browsers is-desktop">
|
||||
<a class="BadBrowser-content-browsers-browser firefox" href="https://www.mozilla.org/en-US/firefox/new/" rel="noopener noreferrer" target="_blank">
|
||||
<a class="BadBrowser-content-browsers-browser firefox" href="https://www.mozilla.org/en-US/firefox/new/" rel="noopener noreferrer"
|
||||
target="_blank">
|
||||
<span class="BadBrowser-content-browsers-browser-name">
|
||||
Firefox
|
||||
</span>
|
||||
@ -97,4 +106,4 @@
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
</html>
|
@ -95,8 +95,12 @@ export default class AbiFunction {
|
||||
return mapppedType ? mapppedType(value) : BN.isBN(value) ? value.toString() : value;
|
||||
};
|
||||
|
||||
private parsePreEncodedValue = (_: string, value: any) =>
|
||||
BN.isBN(value) ? value.toString() : value;
|
||||
private parsePreEncodedValue = (type: string, value: any) => {
|
||||
if (type === 'bytes') {
|
||||
return Buffer.from(value, 'hex');
|
||||
}
|
||||
return BN.isBN(value) ? value.toString() : value;
|
||||
};
|
||||
|
||||
private makeFuncParams = () =>
|
||||
this.inputs.reduce((accumulator, currInput) => {
|
||||
|
@ -11,7 +11,7 @@ export const makeProviderConfig = (options: DeepPartial<IProviderConfig> = {}):
|
||||
const defaultConfig: IProviderConfig = {
|
||||
concurrency: 2,
|
||||
network: 'ETH',
|
||||
requestFailureThreshold: 3,
|
||||
requestFailureThreshold: 10,
|
||||
supportedMethods: {
|
||||
getNetVersion: true,
|
||||
ping: true,
|
||||
@ -30,7 +30,7 @@ export const makeProviderConfig = (options: DeepPartial<IProviderConfig> = {}):
|
||||
signMessage: true,
|
||||
sendTransaction: true
|
||||
},
|
||||
timeoutThresholdMs: 5000
|
||||
timeoutThresholdMs: 10000
|
||||
};
|
||||
|
||||
return {
|
||||
@ -45,7 +45,7 @@ export const makeProviderConfig = (options: DeepPartial<IProviderConfig> = {}):
|
||||
|
||||
let shepherdProvider: INode;
|
||||
shepherd
|
||||
.init()
|
||||
.init({ queueTimeout: 10000 })
|
||||
.then(
|
||||
provider => (shepherdProvider = (new Proxy(provider, tokenBalanceHandler) as any) as INode)
|
||||
);
|
||||
|
@ -8,11 +8,10 @@ interface ABIFunc<T, K = void> {
|
||||
|
||||
type address = any;
|
||||
type uint256 = any;
|
||||
type bytes = any;
|
||||
|
||||
interface IRequestFactory {
|
||||
validateRequestParams: ABIFunc<
|
||||
{ _addressArgs: address[]; _uintArgs: uint256[]; _callData: bytes; _endowment: uint256 },
|
||||
{ _addressArgs: address[]; _uintArgs: uint256[]; _endowment: uint256 },
|
||||
{ paramsValidity: boolean[] }
|
||||
>;
|
||||
}
|
||||
@ -29,10 +28,6 @@ const requestFactoryAbi = [
|
||||
name: '_uintArgs',
|
||||
type: 'uint256[12]'
|
||||
},
|
||||
{
|
||||
name: '_callData',
|
||||
type: 'bytes'
|
||||
},
|
||||
{
|
||||
name: '_endowment',
|
||||
type: 'uint256'
|
||||
|
@ -26,9 +26,9 @@ export const EAC_SCHEDULING_CONFIG = {
|
||||
|
||||
export const EAC_ADDRESSES = {
|
||||
KOVAN: {
|
||||
blockScheduler: '0x1afc19a7e642761ba2b55d2a45b32c7ef08269d1',
|
||||
requestFactory: '0x496e2b6089bde77293a994469b08e9f266d87adb',
|
||||
timestampScheduler: '0xc6370807f0164bdf10a66c08d0dab1028dbe80a3'
|
||||
blockScheduler: '0x394ce9fe06c72f18e5a845842974f0c1224b1ff5',
|
||||
requestFactory: '0x98c128b3d8a0ac240f7b7dd4969ea0ad54f9d330',
|
||||
timestampScheduler: '0x31bbbf5180f2bd9c213e2e1d91a439677243268a'
|
||||
}
|
||||
};
|
||||
|
||||
@ -163,7 +163,6 @@ export const parseSchedulingParametersValidity = (isValid: boolean[]) => {
|
||||
|
||||
export const getValidateRequestParamsData = (
|
||||
toAddress: string,
|
||||
callData = '',
|
||||
callGas: Wei,
|
||||
callValue: ICurrentValue['value'],
|
||||
windowSize: BN | null,
|
||||
@ -200,7 +199,6 @@ export const getValidateRequestParamsData = (
|
||||
gasPrice,
|
||||
requiredDeposit
|
||||
],
|
||||
_callData: callData,
|
||||
_endowment: endowment
|
||||
});
|
||||
};
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user