Merge branch 'develop' into feature/monero-swap

This commit is contained in:
Daniel Ternyak 2018-07-02 16:53:34 -05:00 committed by GitHub
commit 534c1b8419
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 167 additions and 52 deletions

View File

@ -0,0 +1,9 @@
// use dates as vars so they're not stripped out by minification
let letCheck = new Date();
const constCheck = new Date();
const arrowCheck = (() => new Date())();
if (letCheck && constCheck && arrowCheck) {
window.localStorage.setItem('goodBrowser', 'true');
}

View File

@ -0,0 +1,33 @@
var badBrowser = false;
try {
// Local storage
window.localStorage.setItem('test', 'test');
window.localStorage.removeItem('test');
// Flexbox
var elTest = document.createElement('div');
elTest.style.display = 'flex';
if (elTest.style.display !== 'flex') {
badBrowser = true;
}
// const and let check from badBrowserCheckA.js
if (window.localStorage.goodBrowser !== 'true') {
badBrowser = true;
}
window.localStorage.removeItem('goodBrowser');
} catch (err) {
badBrowser = true;
}
if (badBrowser) {
var el = document.getElementsByClassName('BadBrowser')[0];
el.className += ' is-open';
// Dumb check for known mobile OS's. Not important to catch all, just
// displays more appropriate information.
if (/iPhone|iPad|iPod|Android/i.test(navigator.userAgent)) {
el.className += ' is-mobile';
}
}

View File

@ -9,6 +9,7 @@ interface Props {
hasUnitDropdown?: boolean;
hasSendEverything?: boolean;
showAllTokens?: boolean;
showInvalidWithoutValue?: boolean;
customValidator?(rawAmount: string): boolean;
}
@ -16,7 +17,8 @@ export const AmountField: React.SFC<Props> = ({
hasUnitDropdown,
hasSendEverything,
showAllTokens,
customValidator
customValidator,
showInvalidWithoutValue
}) => (
<AmountFieldFactory
withProps={({ currentValue: { raw }, isValid, onChange, readOnly }) => (
@ -30,6 +32,7 @@ export const AmountField: React.SFC<Props> = ({
value={raw}
readOnly={!!readOnly}
onChange={onChange}
showInvalidWithoutValue={showInvalidWithoutValue}
/>
{hasSendEverything && <SendEverything />}
{hasUnitDropdown && <UnitDropDown showAllTokens={showAllTokens} />}

View File

@ -100,6 +100,7 @@ class ConfirmationModalTemplateClass extends React.Component<Props, State> {
buttons={buttons}
handleClose={onClose}
disableButtons={transactionBroadcasting}
hideButtons={transactionBroadcasting}
isOpen={isOpen}
>
{transactionBroadcasting ? (

View File

@ -12,6 +12,7 @@ import './NonceField.scss';
interface OwnProps {
alwaysDisplay: boolean;
showInvalidBeforeBlur?: boolean;
}
interface StateProps {
@ -27,7 +28,13 @@ type Props = OwnProps & DispatchProps & StateProps;
class NonceField extends React.Component<Props> {
public render() {
const { alwaysDisplay, requestNonce, noncePending, isOffline } = this.props;
const {
alwaysDisplay,
showInvalidBeforeBlur,
requestNonce,
noncePending,
isOffline
} = this.props;
return (
<NonceFieldFactory
withProps={({ nonce: { raw, value }, onChange, readOnly, shouldDisplay }) => {
@ -51,6 +58,7 @@ class NonceField extends React.Component<Props> {
onChange={onChange}
disabled={noncePending}
showInvalidWithoutValue={true}
showInvalidBeforeBlur={showInvalidBeforeBlur}
/>
{noncePending ? (
<div className="Nonce-spinner">

View File

@ -106,7 +106,7 @@ class AdvancedGas extends React.Component<Props, State> {
)}
{nonceField && (
<div className="AdvancedGas-nonce">
<NonceField alwaysDisplay={true} />
<NonceField alwaysDisplay={true} showInvalidBeforeBlur={true} />
</div>
)}
</div>

View File

@ -49,7 +49,7 @@ class Input extends React.Component<Props, State> {
} else if (!hasBlurred && !showInvalidBeforeBlur) {
validClass = '';
}
if (!hasValue && showInvalidWithoutValue) {
if ((!isStateless || showInvalidBeforeBlur) && !hasValue && showInvalidWithoutValue) {
validClass = 'invalid';
}

View File

@ -9,7 +9,8 @@ interface Props {
modalStyle?: CSSProperties;
hasButtons?: number;
buttons?: IButton[];
disableButtons?: any;
disableButtons?: boolean;
hideButtons?: boolean;
handleClose(): void;
}
@ -45,7 +46,7 @@ export default class ModalBody extends React.Component<Props> {
};
public render() {
const { title, children, modalStyle, hasButtons, handleClose } = this.props;
const { title, children, modalStyle, hasButtons, hideButtons, handleClose } = this.props;
return (
<div
className="Modal"
@ -68,9 +69,9 @@ export default class ModalBody extends React.Component<Props> {
<div className="Modal-content" ref={div => (this.modalContent = div as HTMLElement)}>
{children}
<div className={`Modal-fade ${!hasButtons ? 'has-no-footer' : ''}`} />
<div className={`Modal-fade ${!hasButtons || hideButtons ? 'has-no-footer' : ''}`} />
</div>
{hasButtons && <div className="Modal-footer">{this.renderButtons()}</div>}
{hasButtons && !hideButtons && <div className="Modal-footer">{this.renderButtons()}</div>}
</div>
);
}

View File

@ -15,6 +15,7 @@ interface Props {
isOpen?: boolean;
title?: React.ReactNode;
disableButtons?: boolean;
hideButtons?: boolean;
children: React.ReactNode;
buttons?: IButton[];
maxWidth?: number;
@ -56,7 +57,16 @@ export default class Modal extends PureComponent<Props, {}> {
}
public render() {
const { isOpen, title, children, buttons, handleClose, maxWidth } = this.props;
const {
isOpen,
title,
children,
buttons,
disableButtons,
hideButtons,
handleClose,
maxWidth
} = this.props;
const hasButtons = buttons && buttons.length;
const modalStyle: ModalStyle = {};
@ -65,7 +75,16 @@ export default class Modal extends PureComponent<Props, {}> {
modalStyle.maxWidth = `${maxWidth}px`;
}
const modalBodyProps = { title, children, modalStyle, hasButtons, buttons, handleClose };
const modalBodyProps = {
title,
children,
modalStyle,
hasButtons,
buttons,
disableButtons,
hideButtons,
handleClose
};
const modal = (
<TransitionGroup>

View File

@ -0,0 +1,8 @@
[
{
"name": "Bridge",
"address": "0x0000000000000000000000000000000001000006",
"abi":
"[{ \"name\": \"getFederationAddress\", \"type\": \"function\", \"constant\": true, \"inputs\": [], \"outputs\": [{ \"name\": \"\", \"type\": \"string\" }] }]"
}
]

View File

@ -83,6 +83,11 @@ export const RSK_TESTNET: DPath = {
value: "m/44'/37310'/0'/0"
};
export const RSK_MAINNET: DPath = {
label: 'Mainnet (RSK)',
value: "m/44'/137'/0'/0"
};
export const GO_DEFAULT: DPath = {
label: 'Default (GO)',
value: "m/44'/6060'/0'/0"
@ -114,6 +119,7 @@ export const DPaths: DPath[] = [
ETSC_DEFAULT,
EGEM_DEFAULT,
CLO_DEFAULT,
RSK_MAINNET,
RSK_TESTNET,
GO_DEFAULT,
EOSC_DEFAULT,

View File

@ -0,0 +1 @@
[]

View File

@ -54,7 +54,11 @@ class FieldsClass extends Component<StateProps> {
<div
className={schedulingAvailable ? 'col-sm-9 col-md-10' : 'col-sm-12 col-md-12'}
>
<AmountField hasUnitDropdown={true} hasSendEverything={true} />
<AmountField
hasUnitDropdown={true}
hasSendEverything={true}
showInvalidWithoutValue={true}
/>
</div>
{schedulingAvailable && (
<div className="col-sm-3 col-md-2">

View File

@ -102,6 +102,7 @@ class RequestPayment extends React.Component<Props, {}> {
hasUnitDropdown={true}
showAllTokens={true}
customValidator={isValidAmount(decimal)}
showInvalidWithoutValue={true}
/>
</div>
</div>

View File

@ -21,6 +21,7 @@ import {
ETSC_DEFAULT,
EGEM_DEFAULT,
CLO_DEFAULT,
RSK_MAINNET,
RSK_TESTNET,
GO_DEFAULT,
EOSC_DEFAULT,
@ -205,7 +206,7 @@ export const STATIC_NETWORKS_INITIAL_STATE: StaticNetworksState = {
isCustom: false,
color: '#6d2eae',
blockExplorer: makeExplorer({
name: 'Etherchain Light',
name: 'POA Explorer',
origin: 'https://poaexplorer.com',
addressPath: 'address/search',
blockPath: 'blocks/block'
@ -369,6 +370,32 @@ export const STATIC_NETWORKS_INITIAL_STATE: StaticNetworksState = {
}
},
RSK: {
id: 'RSK',
name: 'RSK',
unit: 'SBTC',
chainId: 30,
color: '#58A052',
isCustom: false,
blockExplorer: makeExplorer({
name: 'RSK Explorer',
origin: 'https://explorer.rsk.co'
}),
tokens: require('config/tokens/rsk.json'),
contracts: require('config/contracts/rsk.json'),
isTestnet: false,
dPathFormats: {
[SecureWalletName.TREZOR]: RSK_MAINNET,
[SecureWalletName.LEDGER_NANO_S]: RSK_MAINNET,
[InsecureWalletName.MNEMONIC_PHRASE]: RSK_MAINNET
},
gasPriceSettings: {
min: 0.183,
max: 1.5,
initial: 0.183
}
},
RSK_TESTNET: {
id: 'RSK_TESTNET',
name: 'RSK',
@ -380,8 +407,8 @@ export const STATIC_NETWORKS_INITIAL_STATE: StaticNetworksState = {
name: 'RSK Testnet Explorer',
origin: 'https://explorer.testnet.rsk.co'
}),
tokens: require('config/tokens/rsk.json'),
contracts: require('config/contracts/rsk.json'),
tokens: require('config/tokens/rsk_testnet.json'),
contracts: require('config/contracts/rsk_testnet.json'),
isTestnet: true,
dPathFormats: {
[SecureWalletName.TREZOR]: RSK_TESTNET,

View File

@ -71,40 +71,6 @@
</div>
</div>
<script>
(function () {
var badBrowser = false;
try {
// Let and const
eval('let a = 1;');
eval('const b = 1');
// Local storage
window.localStorage.setItem('test', 'test');
window.localStorage.removeItem('test');
// Flexbox
var el = document.createElement('div');
el.style.display = 'flex';
if (el.style.display !== 'flex') {
badBrowser = false;
}
} catch (err) {
badBrowser = true;
}
if (badBrowser) {
var el = document.getElementsByClassName('BadBrowser')[0];
el.className += ' is-open';
// Dumb check for known mobile OS's. Not important to catch all, just
// displays more appropriate information.
if (/iPhone|iPad|iPod|Android/i.test(navigator.userAgent)) {
el.className += ' is-mobile';
}
}
})();
</script>
</body>
</html>

View File

@ -108,9 +108,9 @@ export const NODE_CONFIGS: { [key in StaticNetworkIds]: RawNodeConfig[] } = {
POA: [
{
name: makeNodeName('POA', 'core'),
type: 'rpc',
service: 'poa.network',
url: 'https://core.poa.network'
type: 'infura',
service: 'poa.infura.io',
url: 'https://poa.infura.io'
}
],
@ -168,6 +168,15 @@ export const NODE_CONFIGS: { [key in StaticNetworkIds]: RawNodeConfig[] } = {
}
],
RSK: [
{
name: makeNodeName('RSK', 'rsk_mainnet'),
type: 'rpc',
service: 'mycrypto.rsk.co',
url: 'https://mycrypto.rsk.co/'
}
],
RSK_TESTNET: [
{
name: makeNodeName('RSK_TESTNET', 'rsk_testnet'),

View File

@ -139,11 +139,20 @@ export const validPositiveNumber = (num: number) => validNumber(num) && num !==
export const validDecimal = (input: string, decimal: number) => {
const arr = input.split('.');
// Only a single decimal can exist.
if (arr.length > 2) {
return false;
}
const fractionPortion = arr[1];
if (!fractionPortion || fractionPortion.length === 0) {
return true;
}
const decimalLength = fractionPortion.length;
return decimalLength <= decimal;
};

View File

@ -13,6 +13,7 @@ type StaticNetworkIds =
| 'ETSC'
| 'EGEM'
| 'CLO'
| 'RSK'
| 'RSK_TESTNET'
| 'GO'
| 'EOSC'

View File

@ -16,6 +16,7 @@ configuredStore.getState();
const VALID_BTC_ADDRESS = '1MEWT2SGbqtz6mPCgFcnea8XmWV5Z4Wc6';
const VALID_ETH_ADDRESS = '0x7cB57B5A97eAbe94205C07890BE4c1aD31E486A8';
const VALID_RSK_TESTNET_ADDRESS = '0x5aAeb6053F3e94c9b9A09F33669435E7EF1BEaEd';
const VALID_RSK_MAINNET_ADDRESS = '0x5aaEB6053f3e94c9b9a09f33669435E7ef1bEAeD';
const VALID_ETH_PRIVATE_KEY = '3f4fd89ea4970cc77bfd2d07a95786575ea62e183857afe6301578e1a3c5c782';
const INVALID_ETH_PRIVATE_KEY = '3f4fd89ea4970cc77bfd2d07a95786575ea62e183857afe6301578e1a3c5ZZZZ';
const VALID_ETH_PRIVATE_BUFFER = Buffer.from(VALID_ETH_PRIVATE_KEY, 'hex');
@ -50,6 +51,12 @@ describe('Validator', () => {
it('should validate correct RSK address in RSK mainnet network as false', () => {
expect(isValidAddress(VALID_RSK_TESTNET_ADDRESS, RSK_MAINNET_CHAIN_ID)).toBeFalsy();
});
it('should validate correct RSK address in RSK mainnet network as true', () => {
expect(isValidAddress(VALID_RSK_MAINNET_ADDRESS, RSK_MAINNET_CHAIN_ID)).toBeTruthy();
});
it('should validate correct RSK mainnet address in RSK testnet network as false', () => {
expect(isValidAddress(VALID_RSK_MAINNET_ADDRESS, RSK_TESTNET_CHAIN_ID)).toBeFalsy();
});
it('should validate an incorrect DPath as false', () => {
expect(isValidPath('m/44/60/0/0')).toBeFalsy();
});

View File

@ -32,6 +32,8 @@ module.exports = function(opts = {}) {
// ====== Entry =======
// ====================
const entry = {
badBrowserCheckA: './common/badBrowserCheckA.js',
badBrowserCheckB: './common/badBrowserCheckB.js',
client: './common/index.tsx'
};