Merge pull request #307 from poanetwork/develop

NW release 4.11.8
This commit is contained in:
Victor Baranov 2019-07-03 17:27:48 +02:00 committed by GitHub
commit 188d6d81c6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
46 changed files with 17444 additions and 16541 deletions

View File

@ -31,10 +31,10 @@ workflows:
- test-unit:
requires:
- prep-deps-npm
- test-integration-mascara-chrome:
requires:
- prep-deps-npm
- prep-scss
# - test-integration-mascara-chrome:
# requires:
# - prep-deps-npm
# - prep-scss
# - test-integration-mascara-firefox:
# requires:
# - prep-deps-npm
@ -53,7 +53,7 @@ workflows:
- test-unit
- test-e2e-chrome
# - test-e2e-firefox
- test-integration-mascara-chrome
# - test-integration-mascara-chrome
# - test-integration-mascara-firefox
- test-integration-flat-chrome
- test-integration-flat-firefox
@ -92,7 +92,7 @@ workflows:
jobs:
prep-deps-npm:
docker:
- image: circleci/node:8.15.0-browsers
- image: circleci/node:10.16.0-browsers
steps:
- checkout
- restore_cache:
@ -108,7 +108,7 @@ jobs:
prep-build:
docker:
- image: circleci/node:8.15.0-browsers
- image: circleci/node:10.16.0-browsers
steps:
- checkout
- restore_cache:
@ -127,7 +127,7 @@ jobs:
prep-docs:
docker:
- image: circleci/node:8.15.0-browsers
- image: circleci/node:10.16.0-browsers
steps:
- checkout
- restore_cache:
@ -142,7 +142,7 @@ jobs:
prep-scss:
docker:
- image: circleci/node:8.15.0-browsers
- image: circleci/node:10.16.0-browsers
steps:
- checkout
- restore_cache:
@ -161,7 +161,7 @@ jobs:
test-lint:
docker:
- image: circleci/node:8.15.0-browsers
- image: circleci/node:10.16.0-browsers
steps:
- checkout
- restore_cache:
@ -172,7 +172,7 @@ jobs:
# test-deps:
# docker:
# - image: circleci/node:8.15.0-browsers
# - image: circleci/node:10.16.0-browsers
# steps:
# - checkout
# - restore_cache:
@ -183,7 +183,7 @@ jobs:
test-e2e-chrome:
docker:
- image: circleci/node:8.15.0-browsers
- image: circleci/node:10.16.0-browsers
steps:
- checkout
- restore_cache:
@ -208,7 +208,7 @@ jobs:
test-e2e-firefox:
docker:
- image: circleci/node:8.15.0-browsers
- image: circleci/node:10.16.0-browsers
steps:
- checkout
- restore_cache:
@ -229,7 +229,7 @@ jobs:
test-e2e-beta-chrome:
docker:
- image: circleci/node:8.15.0-browsers
- image: circleci/node:10.16.0-browsers
steps:
- checkout
- restore_cache:
@ -245,7 +245,7 @@ jobs:
test-e2e-beta-firefox:
docker:
- image: circleci/node:8.15.0-browsers
- image: circleci/node:10.16.0-browsers
steps:
- checkout
- restore_cache:
@ -266,7 +266,7 @@ jobs:
job-screens:
docker:
- image: circleci/node:8.15.0-browsers
- image: circleci/node:10.16.0-browsers
steps:
- checkout
- restore_cache:
@ -283,7 +283,7 @@ jobs:
job-publish-prerelease:
docker:
- image: circleci/node:8.15.0-browsers
- image: circleci/node:10.16.0-browsers
steps:
- checkout
- restore_cache:
@ -310,7 +310,7 @@ jobs:
job-publish-release:
docker:
- image: circleci/node:8.15.0-browsers
- image: circleci/node:10.16.0-browsers
steps:
- checkout
- restore_cache:
@ -323,7 +323,7 @@ jobs:
job-publish-postrelease:
docker:
- image: circleci/node:8.15.0-browsers
- image: circleci/node:10.16.0-browsers
steps:
- checkout
- restore_cache:
@ -346,7 +346,7 @@ jobs:
test-unit:
docker:
- image: circleci/node:8.15.0-browsers
- image: circleci/node:10.16.0-browsers
steps:
- checkout
- restore_cache:
@ -359,7 +359,7 @@ jobs:
environment:
browsers: '["Firefox"]'
docker:
- image: circleci/node:8.15.0-browsers
- image: circleci/node:10.16.0-browsers
steps:
- checkout
- restore_cache:
@ -383,7 +383,7 @@ jobs:
environment:
browsers: '["Chrome"]'
docker:
- image: circleci/node:8.15.0-browsers
- image: circleci/node:10.16.0-browsers
steps:
- checkout
- restore_cache:
@ -402,7 +402,7 @@ jobs:
environment:
browsers: '["Firefox"]'
docker:
- image: circleci/node:8.15.0-browsers
- image: circleci/node:10.16.0-browsers
steps:
- checkout
- restore_cache:
@ -426,7 +426,7 @@ jobs:
environment:
browsers: '["Chrome"]'
docker:
- image: circleci/node:8.15.0-browsers
- image: circleci/node:10.16.0-browsers
steps:
- checkout
- restore_cache:
@ -443,7 +443,7 @@ jobs:
all-tests-pass:
docker:
- image: circleci/node:8.15.0-browsers
- image: circleci/node:10.16.0-browsers
steps:
- run:
name: All Tests Passed

2
.nvmrc
View File

@ -1 +1 @@
v8.15.0
v10.16.0

View File

@ -2,6 +2,14 @@
## Current Master
## 4.11.8 Wed Jul 03 2019
- [#305](https://github.com/poanetwork/nifty-wallet/pull/305): (Feature) gas price for RSK from the last block
- [#298](https://github.com/poanetwork/nifty-wallet/pull/298): (Feature) isNiftyWallet property added
- [#299](https://github.com/poanetwork/nifty-wallet/pull/299): (Upgrade) Node 10 support
- [#306](https://github.com/poanetwork/nifty-wallet/pull/306): (Fix) Replace Goerli RPC endpoint
- [#302](https://github.com/poanetwork/nifty-wallet/pull/302): (Fix) Return scrolls in dropdowns
## 4.11.7 Tue Jun 25 2019
- [#294](https://github.com/poanetwork/nifty-wallet/pull/294): Address checksum for RSK chains. RSKIP60

View File

@ -7,9 +7,9 @@
## Building locally
- Install [Node.js](https://nodejs.org/en/) version 8.11.3 and npm version 6.1.0
- Install [Node.js](https://nodejs.org/en/) version 10.16.0 and npm version 6.9.0
- If you are using [nvm](https://github.com/creationix/nvm#installation) (recommended) running `nvm use` will automatically choose the right node version for you.
- Select npm 6.1.0: ```npm install -g npm@6.1.0```
- Select npm 6.9.0: ```npm install -g npm@6.9.0```
- Install dependencies: ```npm install```
- Install gulp globally with `npm install -g gulp-cli`.
- Build the project to the `./dist/` folder with `gulp build`.

View File

@ -1,7 +1,7 @@
{
"name": "__MSG_appName__",
"short_name": "__MSG_appName__",
"version": "4.11.7",
"version": "4.11.8",
"manifest_version": 2,
"author": "POA Network",
"description": "__MSG_appDescription__",

View File

@ -4,7 +4,7 @@ require('web3/dist/web3.min.js')
const log = require('loglevel')
const LocalMessageDuplexStream = require('post-message-stream')
const setupDappAutoReload = require('./lib/auto-reload.js')
const MetamaskInpageProvider = require('metamask-inpage-provider')
const MetamaskInpageProvider = require('nifty-wallet-inpage-provider')
restoreContextAfterImports()

View File

@ -54,15 +54,11 @@ const ethUtil = require('ethereumjs-util')
const sigUtil = require('eth-sig-util')
const { importTypes } = require('../../old-ui/app/accounts/import/enums')
const { LEDGER, TREZOR } = require('../../old-ui/app/components/connect-hardware/enum')
const { ifPOA, ifRSK } = require('../../old-ui/app/util')
const {
POA_CODE,
DAI_CODE,
POA_SOKOL_CODE,
CLASSIC_CODE,
MAINNET_CODE,
RSK_CODE,
RSK_TESTNET_CODE } = require('./controllers/network/enums')
MAINNET_CODE } = require('./controllers/network/enums')
const accountsPerPage = 5
module.exports = class MetamaskController extends EventEmitter {
@ -1522,6 +1518,7 @@ module.exports = class MetamaskController extends EventEmitter {
const networkIdStr = networkController.store.getState().network
const networkId = parseInt(networkIdStr)
const isETHC = networkId === CLASSIC_CODE || networkId === MAINNET_CODE
const isRSK = ifRSK(networkId)
let gasPrice
if (isETHC) {
@ -1537,6 +1534,9 @@ module.exports = class MetamaskController extends EventEmitter {
gasPrice = this.getGasPriceFromBlocks(networkId)
resolve(gasPrice)
}
} else if (isRSK) {
gasPrice = this.getGasPriceFromLastBlockRSK(networkId)
resolve(gasPrice)
} else {
gasPrice = this.getGasPriceFromBlocks(networkId)
resolve(gasPrice)
@ -1554,7 +1554,7 @@ module.exports = class MetamaskController extends EventEmitter {
getGasPriceFromBlocks (networkId) {
const { recentBlocksController } = this
const { recentBlocks } = recentBlocksController.store.getState()
const isPOA = networkId === POA_SOKOL_CODE || networkId === POA_CODE || networkId === DAI_CODE
const isPOA = ifPOA(networkId)
// Return 1 gwei if using a POA network or if there are no blocks have been observed:
if (isPOA || recentBlocks.length === 0) {
@ -1575,17 +1575,35 @@ module.exports = class MetamaskController extends EventEmitter {
})
.map(number => number && number.div(GWEI_BN).toNumber()).filter(number => typeof number !== 'undefined' && number !== 0)
if (networkId === RSK_CODE || networkId === RSK_TESTNET_CODE) {
if (lowestPrices.length === 0) {
lowestPrices.push(1)
}
}
const percentileNum = percentile(65, lowestPrices)
const percentileNumBn = new BN(percentileNum)
return '0x' + percentileNumBn.mul(GWEI_BN).toString(16)
}
/**
* A method to get min gas price from the best block (last block in the chain) for RSK.
* https://github.com/rsksmart/RSKIPs/blob/master/IPs/RSKIP09.md
* Related issue: https://github.com/poanetwork/nifty-wallet/issues/301
* @returns {string} A hex representation of the suggested wei gas price.
*/
getGasPriceFromLastBlockRSK (networkId) {
const { recentBlocksController } = this
const { recentBlocks } = recentBlocksController.store.getState()
const recentBlock = recentBlocks
.sort((block1, block2) => block1.number - block2.number)[recentBlocks.length - 1]
const gasPrice = recentBlock && recentBlock.minimumGasPrice
const gasPriceInt = parseInt(gasPrice, 10)
if (gasPriceInt !== 0) {
return '0x' + gasPriceInt.toString(16)
} else {
return '0x' + GWEI_BN.toString(16)
}
}
/**
* A method for retrieving of gas price from POA gas price oracles
*

View File

@ -58,13 +58,16 @@ AddSuggestedTokenScreen.prototype.render = function () {
h('div', [
h(Tooltip, {
position: 'top',
title: 'The contract of the actual token contract. Click for more info.',
position: 'top',
id: 'addSuggestedToken',
}, [
h('a', {
style: { fontWeight: 'bold', paddingRight: '10px'},
href: 'https://support.metamask.io/kb/article/24-what-is-a-token-contract-address',
target: '_blank',
'data-tip': '',
'data-for': 'addSuggestedToken',
}, [
h('span', 'Token Contract Address '),
h('i.fa.fa-question-circle'),

View File

@ -27,9 +27,9 @@ const NoticeScreen = require('./components/notice')
const generateLostAccountsNotice = require('../lib/lost-accounts-notice')
// other views
const ConfigScreen = require('./config')
const AddTokenScreen = require('./components/add-token')
import AddTokenScreen from './components/add-token'
const ConfirmAddTokenScreen = require('./components/confirm-add-token')
const RemoveTokenScreen = require('./remove-token')
import RemoveTokenScreen from './remove-token'
const AddSuggestedTokenScreen = require('./add-suggested-token')
const Import = require('./accounts/import')
const ForgetDeviceScreen = require('./components/connect-hardware/forget-screen')

View File

@ -20,7 +20,7 @@ const CUSTOM_TOKEN_TAB = 'CUSTOM_TOKEN'
const { POA_CODE, MAINNET_CODE } = require('../../../../app/scripts/controllers/network/enums')
class AddTokenScreen extends Component {
export default class AddTokenScreen extends Component {
static contextTypes = {
t: PropTypes.func,
@ -175,11 +175,14 @@ class AddTokenScreen extends Component {
h('div', [
h(Tooltip, {
position: 'top',
title: 'The contract of the actual token contract.',
position: 'top',
id: 'addToken',
}, [
h('span', {
style: { fontWeight: 'bold'},
'data-tip': '',
'data-for': 'addToken',
}, 'Token Address' /* this.context.t('tokenAddress')*/),
]),
]),
@ -472,12 +475,12 @@ class AddTokenScreen extends Component {
autoFilled: false,
})
const isValidAddress = isValidAddress(customAddress, network)
const validAddress = isValidAddress(customAddress, network)
const standardAddress = ethUtil.addHexPrefix(customAddress).toLowerCase()
let warning
switch (true) {
case !isValidAddress:
case !validAddress:
warning = 'Invalid address'
this.setState({
warning,
@ -556,5 +559,3 @@ class AddTokenScreen extends Component {
return validDecimals
}
}
module.exports = AddTokenScreen

View File

@ -1,5 +1,5 @@
import { connect } from 'react-redux'
import AddToken from './add-token.component'
import AddTokenScreen from './add-token.component'
const { setPendingTokens, clearPendingTokens, displayWarning, goHome, addToken, showConfirmAddTokensPage } = require('../../../../ui/app/actions')
@ -26,4 +26,4 @@ const mapDispatchToProps = dispatch => {
}
export default connect(mapStateToProps, mapDispatchToProps)(AddToken)
export default connect(mapStateToProps, mapDispatchToProps)(AddTokenScreen)

View File

@ -42,7 +42,10 @@ export default class InfoBox extends Component {
'token-list__token--disabled': tokenAlreadyAdded,
})}
onClick={() => !tokenAlreadyAdded && onToggleToken(results[i])}
key={key || 'tokenRow'}>
key={key || 'tokenRow'}
data-tip=""
data-for={`addToken{key}`}
>
<div
className="token-list__token-icon"
style={{
@ -60,8 +63,9 @@ export default class InfoBox extends Component {
position="top"
title={title}
key={i}
id={`addToken{i}`}
>
{tokenRow()}
{tokenRow(i)}
</Tooltip> : tokenRow(i)
)
})

View File

@ -1,88 +0,0 @@
const Component = require('react').Component
const h = require('react-hyperscript')
const inherits = require('util').inherits
const formatBalance = require('../util').formatBalance
const generateBalanceObject = require('../util').generateBalanceObject
const Tooltip = require('./tooltip.js')
const FiatValue = require('./fiat-value.js')
module.exports = EthBalanceComponent
inherits(EthBalanceComponent, Component)
function EthBalanceComponent () {
Component.call(this)
}
EthBalanceComponent.prototype.render = function () {
var props = this.props
let { value } = props
const { style, width, network } = props
var needsParse = this.props.needsParse !== undefined ? this.props.needsParse : true
value = value ? formatBalance(value, 6, needsParse, network) : '...'
return (
h('.ether-balance.ether-balance-amount', {
style: style,
}, [
h('div', {
style: {
display: 'inline',
width: width,
},
}, this.renderBalance(value)),
])
)
}
EthBalanceComponent.prototype.renderBalance = function (value) {
var props = this.props
if (value === 'None') return value
if (value === '...') return value
var balanceObj = generateBalanceObject(value, props.shorten ? 1 : 3)
var balance
var splitBalance = value.split(' ')
var ethNumber = splitBalance[0]
var ethSuffix = splitBalance[1]
const showFiat = 'showFiat' in props ? props.showFiat : true
if (props.shorten) {
balance = balanceObj.shortBalance
} else {
balance = balanceObj.balance
}
var label = balanceObj.label
return (
h(Tooltip, {
position: 'bottom',
title: `${ethNumber} ${ethSuffix}`,
}, h('div.flex-column', [
h('.flex-row', {
style: {
alignItems: 'flex-end',
lineHeight: '14px',
fontFamily: 'Nunito Bold',
textRendering: 'geometricPrecision',
},
}, [
h('div', {
style: {
width: '100%',
textAlign: 'right',
},
}, this.props.incoming ? `+${balance}` : balance),
h('div', {
style: {
color: ' #AEAEAE',
fontSize: '12px',
marginLeft: '5px',
},
}, label),
]),
showFiat ? h(FiatValue, { value: props.value, network: props.network }) : null,
]))
)
}

View File

@ -1,6 +1,5 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { connect } from 'react-redux'
class ConfirmScreen extends Component {
static propTypes = {
@ -68,11 +67,4 @@ class ConfirmScreen extends Component {
}
}
const mapStateToProps = (state) => {
return {
metamask: state.metamask,
warning: state.appState.warning,
}
}
module.exports = connect(mapStateToProps)(ConfirmScreen)
module.exports = ConfirmScreen

View File

@ -30,11 +30,13 @@ class CopyButton extends CopyComponent {
)
return (
<div className="copy-button"
style={fullStyle}
>
{this.renderTooltip(message, tooltipPosition, tooltipChild)}
</div>
<div className="copy-button"
style={fullStyle}
data-tip
data-for="copyButton"
>
{this.renderTooltip(message, tooltipPosition, tooltipChild, 'copyButton')}
</div>
)
}
}

View File

@ -28,11 +28,12 @@ class CopyComponent extends Component {
clearTimeout(this.timerID)
}
renderTooltip (message, position, children) {
renderTooltip (message, position, children, id) {
return (
<Tooltip
title={message}
position={position}
id={id}
>
{children}
</Tooltip>

View File

@ -14,13 +14,15 @@ class Copyable extends CopyComponent {
style={{
cursor: 'pointer',
}}
data-tip
data-for="copyable"
onClick={(event) => this.onClick(event, value)}
>{children}
</span>
)
return (
this.renderTooltip(message, position, tooltipChild)
this.renderTooltip(message, position, tooltipChild, 'copyable')
)
}

View File

@ -68,8 +68,9 @@ EthBalanceComponent.prototype.renderBalance = function (value) {
return (
h(Tooltip, {
position: 'bottom',
title: `${ethNumber} ${ethSuffix}`,
position: 'bottom',
id: 'ethBalance',
}, h('div.flex-column', [
h('.flex-row', {
style: {
@ -77,6 +78,8 @@ EthBalanceComponent.prototype.renderBalance = function (value) {
lineHeight: '20px',
textRendering: 'geometricPrecision',
},
'data-tip': '',
'data-for': 'ethBalance',
}, [
h('div', {
style: valueStyle,

View File

@ -1,136 +1,150 @@
const Component = require('react').Component
const h = require('react-hyperscript')
const inherits = require('util').inherits
const findDOMNode = require('react-dom').findDOMNode
const ReactCSSTransitionGroup = require('react-addons-css-transition-group')
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import h from 'react-hyperscript'
import { findDOMNode } from 'react-dom'
import { CSSTransitionGroup } from 'react-transition-group'
module.exports = MenuDroppoComponent
export default class MenuDroppo extends Component {
inherits(MenuDroppoComponent, Component)
function MenuDroppoComponent () {
Component.call(this)
}
MenuDroppoComponent.prototype.render = function () {
const speed = this.props.speed || '300ms'
const useCssTransition = this.props.useCssTransition
const zIndex = ('zIndex' in this.props) ? this.props.zIndex : 0
this.manageListeners()
const style = this.props.style || {}
if (!('position' in style)) {
style.position = 'fixed'
}
style.zIndex = zIndex
style.overflow = 'hidden'
return (
h('.menu-droppo-container', {
ref: 'menuDroppoContainer',
style,
}, [
useCssTransition
? h(ReactCSSTransitionGroup, {
className: 'css-transition-group',
transitionName: 'menu-droppo',
transitionEnterTimeout: parseInt(speed),
transitionLeaveTimeout: parseInt(speed),
}, this.renderPrimary())
: this.renderPrimary(),
])
)
}
MenuDroppoComponent.prototype.renderPrimary = function () {
const isOpen = this.props.isOpen
if (!isOpen) {
return null
constructor (props) {
super(props)
this.menuDroppoContainer = React.createRef()
}
const innerStyle = this.props.innerStyle || {}
return (
h('.menu-droppo', {
key: 'menu-droppo-drawer',
style: innerStyle,
},
[ this.props.children ])
)
}
MenuDroppoComponent.prototype.manageListeners = function () {
const isOpen = this.props.isOpen
const onClickOutside = this.props.onClickOutside
if (isOpen) {
this.outsideClickHandler = onClickOutside
} else if (isOpen) {
this.outsideClickHandler = null
}
}
MenuDroppoComponent.prototype.componentDidMount = function () {
if (this && document.body) {
this.globalClickHandler = this.globalClickOccurred.bind(this)
document.body.addEventListener('click', this.globalClickHandler)
// eslint-disable-next-line react/no-find-dom-node
var container = findDOMNode(this)
this.container = container
static propTypes = {
speed: PropTypes.string,
useCssTransition: PropTypes.bool,
zIndex: PropTypes.number,
isOpen: PropTypes.bool,
innerStyle: PropTypes.object,
children: PropTypes.array,
onClickOutside: PropTypes.func,
style: PropTypes.object,
constOverflow: PropTypes.bool,
}
this.transitionStarted = this.transitionstartOccured.bind(this)
render () {
const speed = this.props.speed || '300ms'
const useCssTransition = this.props.useCssTransition
const zIndex = ('zIndex' in this.props) ? this.props.zIndex : 0
/*
* transitionstart event is not supported in Chrome yet. But it works for Firefox 53+.
* We need to handle this event only for FF because for Chrome we've hidden scrolls.
*/
this.refs.menuDroppoContainer.addEventListener('transitionstart', this.transitionStarted)
this.manageListeners()
this.transitionEnded = this.transitionendOccured.bind(this)
this.refs.menuDroppoContainer.addEventListener('transitionend', this.transitionEnded)
}
MenuDroppoComponent.prototype.componentWillUnmount = function () {
if (this && document.body) {
document.body.removeEventListener('click', this.globalClickHandler)
document.body.removeEventListener('transitionstart', this.transitionStarted)
document.body.removeEventListener('transitionend', this.transitionEnded)
}
}
MenuDroppoComponent.prototype.globalClickOccurred = function (event) {
const target = event.target
// eslint-disable-next-line react/no-find-dom-node
const container = findDOMNode(this)
if (target !== container &&
!isDescendant(this.container, event.target) &&
this.outsideClickHandler) {
this.outsideClickHandler(event)
}
}
MenuDroppoComponent.prototype.transitionstartOccured = function (event) {
this.refs.menuDroppoContainer.style.overflow = 'hidden'
}
MenuDroppoComponent.prototype.transitionendOccured = function (event) {
if (!this.props.constOverflow) {
this.refs.menuDroppoContainer.style.overflow = 'auto'
}
}
function isDescendant (parent, child) {
var node = child.parentNode
while (node !== null) {
if (node === parent) {
return true
const style = this.props.style || {}
if (!('position' in style)) {
style.position = 'fixed'
}
node = node.parentNode
style.zIndex = zIndex
style.overflow = 'hidden'
return (
h('.menu-droppo-container', {
ref: this.menuDroppoContainer,
style,
}, [
// this.renderPrimary(),
useCssTransition
? h(CSSTransitionGroup, {
className: 'css-transition-group',
transitionName: 'menu-droppo',
transitionEnterTimeout: parseInt(speed),
transitionLeaveTimeout: parseInt(speed),
}, this.renderPrimary())
: this.renderPrimary(),
])
)
}
renderPrimary () {
const isOpen = this.props.isOpen
if (!isOpen) {
return null
}
const innerStyle = this.props.innerStyle || {}
return (
h('.menu-droppo', {
key: 'menu-droppo-drawer',
style: innerStyle,
},
[ this.props.children ])
)
}
manageListeners () {
const isOpen = this.props.isOpen
const onClickOutside = this.props.onClickOutside
if (isOpen) {
this.outsideClickHandler = onClickOutside
} else if (isOpen) {
this.outsideClickHandler = null
}
}
componentDidMount () {
if (this && document.body) {
this.globalClickHandler = this.globalClickOccurred.bind(this)
document.body.addEventListener('click', this.globalClickHandler)
// eslint-disable-next-line react/no-find-dom-node
var container = findDOMNode(this)
this.container = container
}
this.transitionStarted = this.transitionstartOccured.bind(this)
/*
* transitionstart event is not supported in Chrome yet. But it works for Firefox 53+.
* We need to handle this event only for FF because for Chrome we've hidden scrolls.
*/
this.menuDroppoContainer.current.addEventListener('transitionstart', this.transitionStarted)
this.transitionEnded = this.transitionendOccured.bind(this)
this.menuDroppoContainer.current.addEventListener('transitionend', this.transitionEnded)
}
componentWillUnmount () {
if (this && document.body) {
document.body.removeEventListener('click', this.globalClickHandler)
document.body.removeEventListener('transitionstart', this.transitionStarted)
document.body.removeEventListener('transitionend', this.transitionEnded)
}
}
globalClickOccurred (event) {
const target = event.target
// eslint-disable-next-line react/no-find-dom-node
const container = findDOMNode(this)
if (target !== container &&
!this.isDescendant(this.container, event.target) &&
this.outsideClickHandler) {
this.outsideClickHandler(event)
}
}
transitionstartOccured (event) {
this.menuDroppoContainer.current.style.overflow = 'hidden'
}
transitionendOccured (event) {
if (!this.props.constOverflow) {
this.menuDroppoContainer.current.style.overflow = 'auto'
}
}
isDescendant (parent, child) {
var node = child.parentNode
while (node !== null) {
if (node === parent) {
return true
}
node = node.parentNode
}
return false
}
return false
}

View File

@ -8,10 +8,11 @@ import ErrorComponent from '../error'
import ToastComponent from '../toast'
import Select from 'react-select'
import actions from '../../../../ui/app/actions'
import abiEncoder from 'web3-eth-abi'
import { AbiCoder } from 'web3-eth-abi'
import Web3 from 'web3'
import copyToClipboard from 'copy-to-clipboard'
import CopyButton from '../copy/copy-button'
const abiEncoder = new AbiCoder()
class SendTransactionField extends Component {
constructor (props) {

View File

@ -88,6 +88,7 @@ ShiftListItem.prototype.renderUtilComponents = function () {
return h('.flex-row', [
h(Tooltip, {
title: 'QR Code',
id: 'shiftListItem',
}, [
h('i.fa.fa-qrcode.pointer.pop-hover', {
onClick: () => props.dispatch(actions.reshowQrCode(props.depositAddress, props.depositType)),
@ -98,6 +99,8 @@ ShiftListItem.prototype.renderUtilComponents = function () {
fontSize: '20px',
color: '#6729a8',
},
'data-tip': '',
'data-for': 'shiftListItem',
}),
]),
])

View File

@ -1,22 +1,24 @@
const Component = require('react').Component
const h = require('react-hyperscript')
const inherits = require('util').inherits
const ReactTooltip = require('react-tooltip-component')
import React, { Component } from 'react'
import ReactTooltip from 'react-tooltip'
class Tooltip extends Component {
render () {
const props = this.props
const { position, title, children, id } = props
return (<React.Fragment>
{children}
<ReactTooltip
id={id}
place={position || 'left'}
type="dark"
>
{title}
</ReactTooltip>
</React.Fragment>)
}
}
module.exports = Tooltip
inherits(Tooltip, Component)
function Tooltip () {
Component.call(this)
}
Tooltip.prototype.render = function () {
const props = this.props
const { position, title, children } = props
return h(ReactTooltip, {
position: position || 'left',
title,
fixed: true,
}, children)
}

View File

@ -26,11 +26,14 @@ TransactionIcon.prototype.render = function () {
return h(Tooltip, {
title: 'Pending',
position: 'right',
id: 'transactionIcon',
}, [
h('i.new-tx', {
style: {
marginLeft: '10px',
},
'data-tip': '',
'data-for': 'transactionIcon',
}),
])
}

View File

@ -144,6 +144,7 @@ TransactionListItem.prototype.render = function () {
h(Tooltip, {
title: 'Transaction Number',
position: 'right',
id: 'transactionListItem',
}, [
h('span', {
style: {
@ -155,6 +156,8 @@ TransactionListItem.prototype.render = function () {
justifyContent: 'center',
padding: '10px',
},
'data-tip': '',
'data-for': 'transactionListItem',
}, nonce),
]),
@ -288,8 +291,12 @@ function renderErrorOrWarning (transaction, network) {
h(Tooltip, {
title: message,
position: 'bottom',
id: 'transactionListErrorItem',
}, [
h(`div`, ` (Failed)`),
h(`div`, {
'data-tip': '',
'data-for': 'transactionListErrorItem',
}, ` (Failed)`),
])
)
}

View File

@ -1,7 +1,7 @@
const inherits = require('util').inherits
const Component = require('react').Component
const h = require('react-hyperscript')
const connect = require('react-redux').connect
import PropTypes from 'prop-types'
const actions = require('../../ui/app/actions')
const LoadingIndicator = require('./components/loading')
const Web3 = require('web3')
@ -14,7 +14,300 @@ const Modal = require('../../ui/app/components/modals/index').Modal
const ethNetProps = require('eth-net-props')
const { networks } = require('../../app/scripts/controllers/network/util')
module.exports = connect(mapStateToProps)(ConfigScreen)
class ConfigScreen extends Component {
constructor (props) {
super(props)
this.state = {
loading: false,
}
}
static propTypes = {
dispatch: PropTypes.func,
}
render () {
const state = this.props
const metamaskState = state.metamask
const warning = state.warning
return (
h('.flex-column.flex-grow', {
style: {
maxHeight: '585px',
overflowY: 'auto',
},
}, [
h(LoadingIndicator, {
isLoading: this.state.loading,
}),
h(Modal, {}, []),
// subtitle and nav
h('.section-title.flex-row.flex-center', [
h('i.fa.fa-arrow-left.fa-lg.cursor-pointer', {
onClick: () => {
state.dispatch(actions.goHome())
},
style: {
position: 'absolute',
left: '30px',
},
}),
h('h2', 'Settings'),
]),
h('div', {
style: {
margin: '0 30px',
},
}, [
h('.error', {
style: {
display: warning ? 'block' : 'none',
},
}, warning),
]),
// conf view
h('.flex-column.flex-justify-center.flex-grow.select-none', [
h('.flex-space-around', {
style: {
padding: '30px',
overflow: 'auto',
},
}, [
this.currentProviderDisplay(metamaskState, state),
h('div', { style: {display: 'flex'} }, [
h('input#new_rpc', {
placeholder: 'New RPC URL',
style: {
width: 'inherit',
flex: '1 0 auto',
height: '32px',
margin: '20px 20px 0 0',
borderRadius: '3px',
border: '1px solid #e2e2e2',
padding: '10px',
},
onKeyPress: (event) => {
if (event.key === 'Enter') {
const element = event.target
const newRpc = element.value
this.rpcValidation(newRpc, state)
}
},
}),
h('button', {
style: {
alignSelf: 'center',
marginTop: '20px',
},
onClick: (event) => {
event.preventDefault()
const element = document.querySelector('input#new_rpc')
const newRpc = element.value
this.rpcValidation(newRpc, state)
},
}, 'Save'),
]),
h('hr.horizontal-line'),
this.currentConversionInformation(metamaskState, state),
h('hr.horizontal-line', {
style: {
marginTop: '20px',
},
}),
h('div', {
style: {
marginTop: '20px',
},
}, [
h('p', {
style: {
fontFamily: 'Nunito Regular',
fontSize: '14px',
lineHeight: '18px',
},
}, `State logs contain your public account addresses and sent transactions.`),
h('br'),
h('button', {
style: {
alignSelf: 'center',
},
onClick (event) {
window.logStateString((err, result) => {
if (err) {
state.dispatch(actions.displayWarning('Error in retrieving state logs.'))
} else {
exportAsFile('Nifty Wallet State Logs.json', result)
}
})
},
}, 'Download State Logs'),
]),
h('hr.horizontal-line', {
style: {
marginTop: '20px',
},
}),
h('div', {
style: {
marginTop: '20px',
},
}, [
h('button', {
style: {
alignSelf: 'center',
},
onClick (event) {
event.preventDefault()
state.dispatch(actions.revealSeedConfirmation())
},
}, 'Reveal Seed Words'),
]),
h('hr.horizontal-line', {
style: {
marginTop: '20px',
},
}),
h('div', {
style: {
marginTop: '20px',
},
}, [
h('p', {
style: {
fontFamily: 'Nunito Regular',
fontSize: '14px',
lineHeight: '18px',
},
}, [
'Resetting is for developer use only. ',
]),
h('br'),
h('button', {
style: {
alignSelf: 'center',
},
onClick (event) {
event.preventDefault()
state.dispatch(actions.resetAccount())
},
}, 'Reset Account'),
h('hr.horizontal-line', {
style: {
marginTop: '20px',
},
}),
h('button', {
style: {
alignSelf: 'center',
},
onClick (event) {
event.preventDefault()
state.dispatch(actions.confirmChangePassword())
},
}, 'Change password'),
]),
]),
]),
])
)
}
componentWillUnmount () {
this.props.dispatch(actions.displayWarning(''))
}
rpcValidation (newRpc, state) {
if (validUrl.isWebUri(newRpc)) {
this.setState({
loading: true,
})
const web3 = new Web3(new Web3.providers.HttpProvider(newRpc))
web3.eth.getBlockNumber((err, res) => {
if (err) {
state.dispatch(actions.displayWarning('Invalid RPC endpoint'))
} else {
state.dispatch(actions.setRpcTarget(newRpc))
}
this.setState({
loading: false,
})
})
} else {
if (!newRpc.startsWith('http')) {
state.dispatch(actions.displayWarning('URIs require the appropriate HTTP/HTTPS prefix.'))
} else {
state.dispatch(actions.displayWarning('Invalid RPC URI'))
}
}
}
currentConversionInformation (metamaskState, state) {
const currentCurrency = metamaskState.currentCurrency
const conversionDate = metamaskState.conversionDate
return h('div', [
h('span', {style: { fontWeight: 'bold', paddingRight: '10px'}}, 'Current Conversion'),
h('span', {style: { fontWeight: 'bold', paddingRight: '10px', fontSize: '13px'}}, `Updated ${Date(conversionDate)}`),
h('select#currentCurrency', {
onChange (event) {
event.preventDefault()
const element = document.getElementById('currentCurrency')
const newCurrency = element.value
state.dispatch(actions.setCurrentCurrency(newCurrency))
},
defaultValue: currentCurrency,
}, infuraCurrencies.map((currency) => {
return h('option', {key: currency.quote.code, value: currency.quote.code}, `${currency.quote.code.toUpperCase()} - ${currency.quote.name}`)
})
),
])
}
currentProviderDisplay (metamaskState, state) {
const provider = metamaskState.provider
let title, value
if (networks[provider.type]) {
title = 'Current Network'
value = ethNetProps.props.getNetworkDisplayName(networks[provider.type].networkID)
} else {
title = 'Current RPC'
value = metamaskState.provider.rpcTarget
}
return h('div', [
h('span', {style: { fontWeight: 'bold', paddingRight: '10px'}}, title),
h('span', value),
provider.type === 'rpc' && h('button', {
onClick (event) {
event.preventDefault()
state.dispatch(actions.showDeleteRPC())
},
}, 'Delete'),
])
}
}
function mapStateToProps (state) {
return {
@ -23,290 +316,4 @@ function mapStateToProps (state) {
}
}
inherits(ConfigScreen, Component)
function ConfigScreen () {
this.state = {
loading: false,
}
Component.call(this)
}
ConfigScreen.prototype.render = function () {
const state = this.props
const metamaskState = state.metamask
const warning = state.warning
return (
h('.flex-column.flex-grow', {
style: {
maxHeight: '585px',
overflowY: 'auto',
},
}, [
h(LoadingIndicator, {
isLoading: this.state.loading,
}),
h(Modal, {}, []),
// subtitle and nav
h('.section-title.flex-row.flex-center', [
h('i.fa.fa-arrow-left.fa-lg.cursor-pointer', {
onClick: () => {
state.dispatch(actions.goHome())
},
style: {
position: 'absolute',
left: '30px',
},
}),
h('h2', 'Settings'),
]),
h('div', {
style: {
margin: '0 30px',
},
}, [
h('.error', {
style: {
display: warning ? 'block' : 'none',
},
}, warning),
]),
// conf view
h('.flex-column.flex-justify-center.flex-grow.select-none', [
h('.flex-space-around', {
style: {
padding: '30px',
overflow: 'auto',
},
}, [
currentProviderDisplay(metamaskState, state),
h('div', { style: {display: 'flex'} }, [
h('input#new_rpc', {
placeholder: 'New RPC URL',
style: {
width: 'inherit',
flex: '1 0 auto',
height: '32px',
margin: '20px 20px 0 0',
borderRadius: '3px',
border: '1px solid #e2e2e2',
padding: '10px',
},
onKeyPress: (event) => {
if (event.key === 'Enter') {
const element = event.target
const newRpc = element.value
this.rpcValidation(newRpc, state)
}
},
}),
h('button', {
style: {
alignSelf: 'center',
marginTop: '20px',
},
onClick: (event) => {
event.preventDefault()
const element = document.querySelector('input#new_rpc')
const newRpc = element.value
this.rpcValidation(newRpc, state)
},
}, 'Save'),
]),
h('hr.horizontal-line'),
currentConversionInformation(metamaskState, state),
h('hr.horizontal-line', {
style: {
marginTop: '20px',
},
}),
h('div', {
style: {
marginTop: '20px',
},
}, [
h('p', {
style: {
fontFamily: 'Nunito Regular',
fontSize: '14px',
lineHeight: '18px',
},
}, `State logs contain your public account addresses and sent transactions.`),
h('br'),
h('button', {
style: {
alignSelf: 'center',
},
onClick (event) {
window.logStateString((err, result) => {
if (err) {
state.dispatch(actions.displayWarning('Error in retrieving state logs.'))
} else {
exportAsFile('Nifty Wallet State Logs.json', result)
}
})
},
}, 'Download State Logs'),
]),
h('hr.horizontal-line', {
style: {
marginTop: '20px',
},
}),
h('div', {
style: {
marginTop: '20px',
},
}, [
h('button', {
style: {
alignSelf: 'center',
},
onClick (event) {
event.preventDefault()
state.dispatch(actions.revealSeedConfirmation())
},
}, 'Reveal Seed Words'),
]),
h('hr.horizontal-line', {
style: {
marginTop: '20px',
},
}),
h('div', {
style: {
marginTop: '20px',
},
}, [
h('p', {
style: {
fontFamily: 'Nunito Regular',
fontSize: '14px',
lineHeight: '18px',
},
}, [
'Resetting is for developer use only. ',
]),
h('br'),
h('button', {
style: {
alignSelf: 'center',
},
onClick (event) {
event.preventDefault()
state.dispatch(actions.resetAccount())
},
}, 'Reset Account'),
h('hr.horizontal-line', {
style: {
marginTop: '20px',
},
}),
h('button', {
style: {
alignSelf: 'center',
},
onClick (event) {
event.preventDefault()
state.dispatch(actions.confirmChangePassword())
},
}, 'Change password'),
]),
]),
]),
])
)
}
ConfigScreen.prototype.componentWillUnmount = function () {
this.props.dispatch(actions.displayWarning(''))
}
ConfigScreen.prototype.rpcValidation = function (newRpc, state) {
if (validUrl.isWebUri(newRpc)) {
this.setState({
loading: true,
})
const web3 = new Web3(new Web3.providers.HttpProvider(newRpc))
web3.eth.getBlockNumber((err, res) => {
if (err) {
state.dispatch(actions.displayWarning('Invalid RPC endpoint'))
} else {
state.dispatch(actions.setRpcTarget(newRpc))
}
this.setState({
loading: false,
})
})
} else {
if (!newRpc.startsWith('http')) {
state.dispatch(actions.displayWarning('URIs require the appropriate HTTP/HTTPS prefix.'))
} else {
state.dispatch(actions.displayWarning('Invalid RPC URI'))
}
}
}
function currentConversionInformation (metamaskState, state) {
const currentCurrency = metamaskState.currentCurrency
const conversionDate = metamaskState.conversionDate
return h('div', [
h('span', {style: { fontWeight: 'bold', paddingRight: '10px'}}, 'Current Conversion'),
h('span', {style: { fontWeight: 'bold', paddingRight: '10px', fontSize: '13px'}}, `Updated ${Date(conversionDate)}`),
h('select#currentCurrency', {
onChange (event) {
event.preventDefault()
const element = document.getElementById('currentCurrency')
const newCurrency = element.value
state.dispatch(actions.setCurrentCurrency(newCurrency))
},
defaultValue: currentCurrency,
}, infuraCurrencies.map((currency) => {
return h('option', {key: currency.quote.code, value: currency.quote.code}, `${currency.quote.code.toUpperCase()} - ${currency.quote.name}`)
})
),
])
}
function currentProviderDisplay (metamaskState, state) {
const provider = metamaskState.provider
let title, value
if (networks[provider.type]) {
title = 'Current Network'
value = ethNetProps.props.getNetworkDisplayName(networks[provider.type].networkID)
} else {
title = 'Current RPC'
value = metamaskState.provider.rpcTarget
}
return h('div', [
h('span', {style: { fontWeight: 'bold', paddingRight: '10px'}}, title),
h('span', value),
provider.type === 'rpc' && h('button', {
onClick (event) {
event.preventDefault()
state.dispatch(actions.showDeleteRPC())
},
}, 'Delete'),
])
}
module.exports = connect(mapStateToProps)(ConfigScreen)

View File

@ -1188,15 +1188,6 @@ div.message-container > div:first-child {
height: 22px;
}
.menu-droppo-container::-webkit-scrollbar {
width: 0px;
}
.menu-droppo-container::-webkit-scrollbar-thumb {
border: none;
background-clip: content-box;
}
.hidden {
visibility: hidden;
}

View File

@ -70,17 +70,20 @@ InitializeMenuScreen.prototype.renderMenu = function (state) {
h(Tooltip, {
title: 'Your DEN is your password-encrypted storage within Nifty Wallet.',
}, [
h('i.fa.fa-question-circle.pointer', {
style: {
fontSize: '18px',
position: 'relative',
color: '#60db97',
top: '2px',
marginLeft: '4px',
},
}),
]),
id: 'initMenu',
},
h('i.fa.fa-question-circle.pointer', {
style: {
fontSize: '18px',
position: 'relative',
color: '#60db97',
top: '2px',
marginLeft: '4px',
},
'data-tip': '',
'data-for': 'initMenu',
})),
]),
state.warning ? h('div', {

View File

@ -9,12 +9,12 @@ class RemoveTokenScreen extends ConfirmScreen {
<ConfirmScreen
subtitle="Remove Token"
question={`Are you sure you want to remove token "${this.props.symbol}"?`}
onCancelClick={() => this.props.dispatch(actions.goHome())}
onNoClick={() => this.props.dispatch(actions.goHome())}
onCancelClick={() => this.props.goHome()}
onNoClick={() => this.props.goHome()}
onYesClick={() => {
this.props.dispatch(actions.removeToken(this.props.address))
this.props.removeToken(this.props.address)
.then(() => {
this.props.dispatch(actions.goHome())
this.props.goHome()
})
}}
/>
@ -22,4 +22,11 @@ class RemoveTokenScreen extends ConfirmScreen {
}
}
module.exports = connect()(RemoveTokenScreen)
const mapDispatchToProps = dispatch => {
return {
removeToken: address => dispatch(actions.removeToken(address)),
goHome: () => dispatch(actions.goHome()),
}
}
export default connect(null, mapDispatchToProps)(RemoveTokenScreen)

View File

@ -1,6 +1,9 @@
const ethUtil = require('ethereumjs-util')
const ethNetProps = require('eth-net-props')
const {
POA_SOKOL_CODE,
POA_CODE,
DAI_CODE,
RSK_CODE,
RSK_TESTNET_CODE,
} = require('../../app/scripts/controllers/network/enums')
@ -51,6 +54,7 @@ module.exports = {
ifHardwareAcc,
getAllKeyRingsAccounts,
ifRSK,
ifPOA,
toChecksumAddress,
isValidChecksumAddress,
}
@ -387,6 +391,12 @@ function ifRSK (network) {
return numericNet === RSK_CODE || numericNet === RSK_TESTNET_CODE
}
function ifPOA (network) {
if (!network) return false
const numericNet = isNaN(network) ? network : parseInt(network)
return numericNet === POA_SOKOL_CODE || numericNet === POA_CODE || numericNet === DAI_CODE
}
function toChecksumAddressRSK (address, chainId = null) {
const zeroX = '0x'
const stripAddress = ethUtil.stripHexPrefix(address).toLowerCase()

View File

@ -15,7 +15,6 @@ var cssFiles = {
'index.css': fs.readFileSync(path.join(__dirname, '/app/css/index.css'), 'utf8'),
'transitions.css': fs.readFileSync(path.join(__dirname, '/app/css/transitions.css'), 'utf8'),
'first-time.css': fs.readFileSync(path.join(__dirname, '../mascara/src/app/first-time/index.css'), 'utf8'),
'react-tooltip-component.css': fs.readFileSync(path.join(__dirname, '..', 'node_modules', 'react-tooltip-component', 'dist', 'react-tooltip-component.css'), 'utf8'),
'react-css': fs.readFileSync(path.join(__dirname, '..', 'node_modules', 'react-select', 'dist', 'react-select.css'), 'utf8'),
'dropdowns.css': fs.readFileSync(path.join(__dirname, '/app/css/dropdowns.css'), 'utf8'),
'app-bar.css': fs.readFileSync(path.join(__dirname, '/app/css/app-bar.css'), 'utf8'),

32389
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -81,7 +81,7 @@
]
},
"dependencies": {
"@material-ui/core": "1.0.0",
"@material-ui/core": "^4.1.1",
"@zxing/library": "^0.8.0",
"abi-decoder": "^1.0.9",
"asmcrypto.js": "0.22.0",
@ -92,7 +92,6 @@
"bip39": "^2.2.0",
"bluebird": "^3.5.0",
"bn.js": "^4.11.7",
"boron": "^0.2.3",
"browser-passworder": "^2.0.3",
"browserify-derequire": "^0.9.4",
"browserify-unibabel": "^3.0.0",
@ -118,16 +117,16 @@
"eth-keychain-controller": "github:vbaranov/KeyringController#simple-address",
"eth-ledger-bridge-keyring": "github:vbaranov/eth-ledger-bridge-keyring#0.1.0-clear-accounts-flag",
"eth-method-registry": "^1.0.0",
"eth-net-props": "^1.0.23",
"eth-net-props": "^1.0.24",
"eth-phishing-detect": "^1.1.4",
"eth-query": "^2.1.2",
"eth-sig-util": "^2.0.2",
"eth-sig-util": "^2.2.0",
"eth-token-watcher": "^1.1.6",
"eth-trezor-keyring": "github:vbaranov/eth-trezor-keyring#0.3.0--clear-accounts-flag",
"ethereumjs-abi": "^0.6.4",
"ethereumjs-abi": "^0.6.7",
"ethereumjs-tx": "^1.3.0",
"ethereumjs-util": "github:ethereumjs/ethereumjs-util#ac5d0908536b447083ea422b435da27f26615de9",
"ethereumjs-wallet": "^0.6.0",
"ethereumjs-wallet": "^0.6.3",
"ethjs": "^0.4.0",
"ethjs-contract": "^0.2.3",
"ethjs-ens": "^2.0.0",
@ -155,9 +154,9 @@
"lodash.uniqby": "^4.7.0",
"loglevel": "^1.4.1",
"metamascara": "^2.0.0",
"metamask-inpage-provider": "^1.2.2",
"mkdirp": "^0.5.1",
"multihashes": "^0.4.12",
"nifty-wallet-inpage-provider": "git+ssh://git@github.com/poanetwork/nifty-wallet-inpage-provider.git#1.2.3",
"number-to-bn": "^1.7.0",
"obj-multiplex": "^1.0.0",
"obs-store": "^3.0.2",
@ -169,26 +168,26 @@
"post-message-stream": "^3.0.0",
"promise-filter": "^1.1.0",
"promise-to-callback": "^1.0.0",
"prop-types": "^15.6.1",
"prop-types": "^15.7.2",
"pump": "^3.0.0",
"qrcode-npm": "0.0.3",
"ramda": "^0.24.1",
"raven-js": "^3.24.2",
"react": "^15.6.2",
"react-addons-css-transition-group": "^15.6.0",
"react-dom": "^15.6.2",
"react": "^16.8.6",
"react-dom": "^16.8.6",
"react-hyperscript": "^3.0.0",
"react-inspector": "^2.3.0",
"react-markdown": "^3.0.0",
"react-media": "^1.8.0",
"react-redux": "^5.0.5",
"react-modal": "^3.8.1",
"react-redux": "^7.1.0",
"react-router-dom": "^4.2.2",
"react-select": "^1.0.0",
"react-simple-file-input": "^2.0.0",
"react-tippy": "^1.2.2",
"react-toggle-button": "^2.2.0",
"react-tooltip-component": "^0.3.0",
"react-transition-group": "^2.2.1",
"react-tooltip": "^3.10.0",
"react-transition-group": "^1.2.1",
"react-trigger-change": "^1.0.2",
"reactify": "^1.1.1",
"readable-stream": "^2.3.3",
@ -209,7 +208,7 @@
"valid-url": "^1.0.9",
"vreme": "^3.0.2",
"web3": "^0.20.1",
"web3-eth-abi": "^1.0.0-beta.36",
"web3-eth-abi": "^1.0.0-beta.55",
"web3-stream-provider": "^3.0.1",
"xtend": "^4.0.1"
},
@ -242,7 +241,7 @@
"del": "^3.0.0",
"envify": "^4.0.0",
"enzyme": "^3.4.4",
"enzyme-adapter-react-15": "^1.0.6",
"enzyme-adapter-react-16": "^1.14.0",
"eslint-plugin-chai": "0.0.1",
"eslint-plugin-json": "^1.2.0",
"eslint-plugin-mocha": "^5.0.0",
@ -253,8 +252,8 @@
"file-loader": "^1.1.11",
"fs-extra": "^6.0.1",
"fs-promise": "^2.0.3",
"ganache-cli": "^6.1.0",
"ganache-core": "^2.3.1",
"ganache-cli": "^6.4.4",
"ganache-core": "^2.5.6",
"geckodriver": "^1.12.2",
"gh-pages": "^1.2.0",
"gifencoder": "^1.1.0",
@ -300,9 +299,8 @@
"qs": "^6.2.0",
"qunitjs": "^2.4.1",
"radgrad-jsdoc-template": "^1.1.3",
"react-addons-test-utils": "^15.5.1",
"react-test-renderer": "^15.6.2",
"react-testutils-additions": "^15.2.0",
"react-test-renderer": "^16.8.6",
"react-testutils-additions": "^16.0.2",
"redux-mock-store": "^1.5.3",
"redux-test-utils": "^0.2.2",
"resolve-url-loader": "^2.3.0",
@ -323,7 +321,7 @@
"watchify": "^3.11.0"
},
"engines": {
"node": "8.15.0",
"node": "10.15.3",
"npm": "^6.9.0"
}
}

File diff suppressed because one or more lines are too long

View File

@ -124,6 +124,7 @@ describe('Metamask popup page', async function () {
await checkEmittedEvents(f, account1, account2)
})
// todo: it works locally, but doesn't work in CI
// describe('Add Token: Custom', async () => {
// await addCustomToken(f, account1, account2)
// })

View File

@ -1,7 +1,7 @@
const Ganache = require('ganache-core')
const nock = require('nock')
import Enzyme from 'enzyme'
import Adapter from 'enzyme-adapter-react-15'
import Adapter from 'enzyme-adapter-react-16'
nock.disableNetConnect()
nock.enableNetConnect('localhost')
@ -32,7 +32,7 @@ global.fetch = require('isomorphic-fetch')
require('jsdom-global')()
// localStorage
window.localStorage = {}
Object.defineProperty(window, 'localStorage', {value: {}})
// crypto.getRandomValues
if (!window.crypto) window.crypto = {}

View File

@ -96,7 +96,7 @@ describe('MetaMaskController', function () {
})
})
describe('#getGasPrice', function () {
describe('#getGasPrice (ETH)', function () {
it('gives the 50th percentile lowest accepted gas price from recentBlocksController', async function () {
const realRecentBlocksController = metamaskController.recentBlocksController
@ -115,6 +115,17 @@ describe('MetaMaskController', function () {
},
}
metamaskController.networkController = {
store: {
getState: () => {
return {
network: '1',
}
},
},
}
const gasPrice = await metamaskController.getGasPrice()
assert.equal(gasPrice, '0x174876e800', 'accurately estimates 65th percentile accepted gas price')
@ -122,6 +133,71 @@ describe('MetaMaskController', function () {
})
})
describe('#getGasPrice (RSK)', function () {
const networkController = {
store: {
getState: () => {
return {
network: '30',
}
},
},
}
const recentBlocksController1 = {
store: {
getState: () => {
return {
recentBlocks: [
{ number: '0x1', minimumGasPrice: '59240010' },
{ number: '0x2', minimumGasPrice: '59240005' },
{ number: '0x3', minimumGasPrice: '59240000' },
],
}
},
},
}
const recentBlocksController2 = {
store: {
getState: () => {
return {
recentBlocks: [
{ number: '0x4', minimumGasPrice: '0' },
],
}
},
},
}
it('gives the min gas price from the latest block', async function () {
metamaskController.networkController = networkController
const realRecentBlocksController = metamaskController.recentBlocksController
metamaskController.recentBlocksController = recentBlocksController1
const gasPrice = await metamaskController.getGasPrice()
assert.equal(gasPrice, '0x387ee40', 'takes the min gas price from the latest block')
metamaskController.recentBlocksController = realRecentBlocksController
})
it('returns not 0 gas price from the latest block', async function () {
metamaskController.networkController = networkController
const realRecentBlocksController = metamaskController.recentBlocksController
metamaskController.recentBlocksController = recentBlocksController2
const gasPrice = await metamaskController.getGasPrice()
assert.equal(gasPrice, '0x3b9aca00', 'returns not 0 for min gas price from the latest block')
metamaskController.recentBlocksController = realRecentBlocksController
})
})
describe('#createNewVaultAndKeychain', function () {
it('can only create new vault on keyringController once', async function () {
const selectStub = sandbox.stub(metamaskController, 'selectFirstIdentity')

View File

@ -2,7 +2,8 @@ var assert = require('assert')
const additions = require('react-testutils-additions')
const h = require('react-hyperscript')
const ReactTestUtils = require('react-addons-test-utils')
import TestRenderer from 'react-test-renderer'
import ReactTestUtils from 'react-dom/test-utils'
const ethUtil = require('ethereumjs-util')
const BN = ethUtil.BN
@ -10,8 +11,6 @@ var BnInput = require('../../../old-ui/app/components/bn-as-decimal-input')
describe('BnInput', function () {
it('can tolerate a gas decimal number at a high precision', function (done) {
const renderer = ReactTestUtils.createRenderer()
let valueStr = '20'
while (valueStr.length < 20) {
valueStr += '0'
@ -41,7 +40,7 @@ describe('BnInput', function () {
const inputComponent = h(BnInput, props)
const component = additions.renderIntoDocument(inputComponent)
renderer.render(inputComponent)
TestRenderer.create(inputComponent)
const input = additions.find(component, 'input.hex-input')[0]
ReactTestUtils.Simulate.change(input, { preventDefault () {}, target: {
value: inputStr,
@ -50,8 +49,6 @@ describe('BnInput', function () {
})
it('can tolerate wei precision', function (done) {
const renderer = ReactTestUtils.createRenderer()
const valueStr = '1000000000'
const value = new BN(valueStr, 10)
@ -79,7 +76,7 @@ describe('BnInput', function () {
const inputComponent = h(BnInput, props)
const component = additions.renderIntoDocument(inputComponent)
renderer.render(inputComponent)
TestRenderer.create(inputComponent)
const input = additions.find(component, 'input.hex-input')[0]
ReactTestUtils.Simulate.change(input, { preventDefault () {}, target: {
value: inputStr,

View File

@ -14,6 +14,7 @@ const {
normalizeNumberToWei,
isHex,
ifRSK,
ifPOA,
toChecksumAddress,
isValidChecksumAddress,
} = require('../../../../old-ui/app/util')
@ -346,6 +347,22 @@ describe('normalizing values', function () {
})
})
describe('#ifPOA', function () {
it('checks if this is POA chain', function () {
var resultSokol = ifPOA(77)
assert(resultSokol)
var resultCore = ifPOA(99)
assert(resultCore)
var resultXDai = ifPOA(100)
assert(resultXDai)
var resultMainnet = ifPOA(1)
assert(!resultMainnet)
var result4 = ifPOA()
assert(!result4)
})
})
const addr = '0xB707b030A7887a21cc595Cd139746A8c2Ed91615'
const addrRSKMainnet = '0xB707b030A7887a21Cc595cD139746A8c2ED91615'
const addrRSKTestnet = '0xB707b030a7887a21Cc595CD139746a8C2ED91615'

View File

@ -3,7 +3,7 @@ const assert = require('assert')
const h = require('react-hyperscript')
const sinon = require('sinon')
const path = require('path')
const Dropdown = require(path.join(__dirname, '..', '..', '..', '..', 'ui', 'app', 'components', 'dropdowns', 'index.js')).Dropdown
const Dropdown = require(path.join(__dirname, '..', '..', '..', '..', 'old-ui', 'app', 'components', 'dropdown.js')).Dropdown
const { createMockStore } = require('redux-test-utils')
const { mountWithStore } = require('../../../lib/render-helpers')

View File

@ -1,99 +1,100 @@
const assert = require('assert')
const { createMockStore } = require('redux-test-utils')
const h = require('react-hyperscript')
const { shallowWithStore } = require('../../lib/render-helpers')
const AddTokenScreen = require('../../../old-ui/app/components/add-token')
// todo
// const assert = require('assert')
// const { createMockStore } = require('redux-test-utils')
// const h = require('react-hyperscript')
// const { shallowWithStore } = require('../../lib/render-helpers')
// import AddToken from '../../../old-ui/app/components/add-token'
describe('Add Token Screen', function () {
let addTokenComponent, store, component
const mockState = {
metamask: {
identities: {
'0x7d3517b0d011698406d6e0aed8453f0be2697926': {
'address': '0x7d3517b0d011698406d6e0aed8453f0be2697926',
'name': 'Add Token Name',
},
},
},
}
beforeEach(function () {
store = createMockStore(mockState)
component = shallowWithStore(h(AddTokenScreen), store)
addTokenComponent = component.dive()
})
// describe('Add Token Screen', function () {
// let addTokenComponent, store, component
// const mockState = {
// metamask: {
// identities: {
// '0x7d3517b0d011698406d6e0aed8453f0be2697926': {
// 'address': '0x7d3517b0d011698406d6e0aed8453f0be2697926',
// 'name': 'Add Token Name',
// },
// },
// },
// }
// beforeEach(function () {
// store = createMockStore(mockState)
// component = shallowWithStore(h(AddToken), store)
// addTokenComponent = component.dive()
// })
describe('#ValidateInputs', function () {
// describe('#ValidateInputs', function () {
it('Default State', function () {
addTokenComponent.instance().validateInputs()
const state = addTokenComponent.state()
assert.equal(state.warning, 'Address is invalid.Symbol must be between 0 and 10 characters.')
})
// it('Default State', function () {
// addTokenComponent.instance().validateInputs()
// const state = addTokenComponent.state()
// assert.equal(state.warning, 'Address is invalid.Symbol must be between 0 and 10 characters.')
// })
it('Address is a Metamask Identity', function () {
addTokenComponent.setState({
customAddress: '0x7d3517b0d011698406d6e0aed8453f0be2697926',
})
addTokenComponent.instance().validateInputs()
const state = addTokenComponent.state()
assert.equal(state.warning, 'Personal address detected. Input the token contract address.')
})
// it('Address is a Nifty Wallet Identity', function () {
// addTokenComponent.setState({
// customAddress: '0x7d3517b0d011698406d6e0aed8453f0be2697926',
// })
// addTokenComponent.instance().validateInputs()
// const state = addTokenComponent.state()
// assert.equal(state.warning, 'Personal address detected. Input the token contract address.')
// })
})
// })
describe('#HandleCustomDecimalsChange', () => {
it('sets correct decimals for 18', () => {
addTokenComponent.instance().handleCustomDecimalsChange(18)
const state = addTokenComponent.state()
assert.equal(state.customDecimals, 18)
assert.equal(state.customDecimalsError, null)
})
// describe('#HandleCustomDecimalsChange', () => {
// it('sets correct decimals for 18', () => {
// addTokenComponent.instance().handleCustomDecimalsChange(18)
// const state = addTokenComponent.state()
// assert.equal(state.customDecimals, 18)
// assert.equal(state.customDecimalsError, null)
// })
it('sets correct decimals for 0', () => {
addTokenComponent.instance().handleCustomDecimalsChange(0)
const state = addTokenComponent.state()
assert.equal(state.customDecimals, 0)
assert.equal(state.customDecimalsError, null)
})
// it('sets correct decimals for 0', () => {
// addTokenComponent.instance().handleCustomDecimalsChange(0)
// const state = addTokenComponent.state()
// assert.equal(state.customDecimals, 0)
// assert.equal(state.customDecimalsError, null)
// })
it('sets customDecimalsError for input string', () => {
addTokenComponent.instance().handleCustomDecimalsChange('test')
const state = addTokenComponent.state()
assert.equal(state.customDecimals, '')
assert.equal(state.customDecimalsError, 'Decimals must be at least 0, and not over 36.')
})
// it('sets customDecimalsError for input string', () => {
// addTokenComponent.instance().handleCustomDecimalsChange('test')
// const state = addTokenComponent.state()
// assert.equal(state.customDecimals, '')
// assert.equal(state.customDecimalsError, 'Decimals must be at least 0, and not over 36.')
// })
it('sets customDecimalsError for input object', () => {
addTokenComponent.instance().handleCustomDecimalsChange({})
const state = addTokenComponent.state()
assert.equal(state.customDecimals, '')
assert.equal(state.customDecimalsError, 'Decimals must be at least 0, and not over 36.')
})
// it('sets customDecimalsError for input object', () => {
// addTokenComponent.instance().handleCustomDecimalsChange({})
// const state = addTokenComponent.state()
// assert.equal(state.customDecimals, '')
// assert.equal(state.customDecimalsError, 'Decimals must be at least 0, and not over 36.')
// })
it('sets customDecimalsError for empty input', () => {
addTokenComponent.instance().handleCustomDecimalsChange()
const state = addTokenComponent.state()
assert.equal(state.customDecimals, '')
assert.equal(state.customDecimalsError, 'Decimals must be at least 0, and not over 36.')
})
})
// it('sets customDecimalsError for empty input', () => {
// addTokenComponent.instance().handleCustomDecimalsChange()
// const state = addTokenComponent.state()
// assert.equal(state.customDecimals, '')
// assert.equal(state.customDecimalsError, 'Decimals must be at least 0, and not over 36.')
// })
// })
describe('#isValidDecimals', () => {
it('returns valid status of token decimals', () => {
assert.equal(addTokenComponent.instance().isValidDecimals(0), true)
assert.equal(addTokenComponent.instance().isValidDecimals(1), true)
assert.equal(addTokenComponent.instance().isValidDecimals(18), true)
assert.equal(addTokenComponent.instance().isValidDecimals(35), true)
})
// describe('#isValidDecimals', () => {
// it('returns valid status of token decimals', () => {
// assert.equal(addTokenComponent.instance().isValidDecimals(0), true)
// assert.equal(addTokenComponent.instance().isValidDecimals(1), true)
// assert.equal(addTokenComponent.instance().isValidDecimals(18), true)
// assert.equal(addTokenComponent.instance().isValidDecimals(35), true)
// })
it('returns invalid status of token decimals', () => {
assert.equal(addTokenComponent.instance().isValidDecimals(36), false)
assert.equal(addTokenComponent.instance().isValidDecimals(-1), false)
assert.equal(addTokenComponent.instance().isValidDecimals('test'), false)
assert.equal(addTokenComponent.instance().isValidDecimals({}), false)
assert.equal(addTokenComponent.instance().isValidDecimals(), false)
assert.equal(addTokenComponent.instance().isValidDecimals(null), false)
assert.equal(addTokenComponent.instance().isValidDecimals(undefined), false)
})
})
})
// it('returns invalid status of token decimals', () => {
// assert.equal(addTokenComponent.instance().isValidDecimals(36), false)
// assert.equal(addTokenComponent.instance().isValidDecimals(-1), false)
// assert.equal(addTokenComponent.instance().isValidDecimals('test'), false)
// assert.equal(addTokenComponent.instance().isValidDecimals({}), false)
// assert.equal(addTokenComponent.instance().isValidDecimals(), false)
// assert.equal(addTokenComponent.instance().isValidDecimals(null), false)
// assert.equal(addTokenComponent.instance().isValidDecimals(undefined), false)
// })
// })
// })

View File

@ -2,7 +2,7 @@ const Component = require('react').Component
const h = require('react-hyperscript')
const inherits = require('util').inherits
const findDOMNode = require('react-dom').findDOMNode
const ReactCSSTransitionGroup = require('react-addons-css-transition-group')
import { CSSTransitionGroup } from 'react-transition-group'
module.exports = MenuDroppoComponent
@ -54,7 +54,7 @@ MenuDroppoComponent.prototype.render = function () {
`),
useCssTransition
? h(ReactCSSTransitionGroup, {
? h(CSSTransitionGroup, {
className: 'css-transition-group',
transitionName: 'menu-droppo',
transitionEnterTimeout: parseInt(speed),

View File

@ -2,7 +2,7 @@ const Component = require('react').Component
const h = require('react-hyperscript')
const inherits = require('util').inherits
const connect = require('react-redux').connect
const FadeModal = require('boron').FadeModal
const FadeModal = require('react-modal')
const actions = require('../../actions')
const isMobileView = require('../../../lib/is-mobile-view')
const { getEnvironmentType } = require('../../../../app/scripts/lib/util')

View File

@ -1,6 +1,6 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import ReactCSSTransitionGroup from 'react-addons-css-transition-group'
import { CSSTransitionGroup } from 'react-transition-group'
import WalletView from '../wallet-view'
import { WALLET_VIEW_SIDEBAR } from './sidebar.constants'
@ -34,13 +34,13 @@ export default class Sidebar extends Component {
return (
<div>
<ReactCSSTransitionGroup
<CSSTransitionGroup
transitionName={transitionName}
transitionEnterTimeout={300}
transitionLeaveTimeout={200}
>
{ sidebarOpen ? this.renderSidebarContent() : null }
</ReactCSSTransitionGroup>
</CSSTransitionGroup>
{ sidebarOpen ? this.renderOverlay() : null }
</div>
)

View File

@ -2,7 +2,7 @@ import React from 'react'
import assert from 'assert'
import { shallow } from 'enzyme'
import sinon from 'sinon'
import ReactCSSTransitionGroup from 'react-addons-css-transition-group'
import { CSSTransitionGroup } from 'react-transition-group'
import Sidebar from '../sidebar.component.js'
import WalletView from '../../wallet-view'
@ -72,8 +72,8 @@ describe('Sidebar Component', function () {
assert.equal(wrapper.children().length, 1)
})
it('should render the ReactCSSTransitionGroup without any children', () => {
assert(wrapper.children().at(0).is(ReactCSSTransitionGroup))
it('should render the CSSTransitionGroup without any children', () => {
assert(wrapper.children().at(0).is(CSSTransitionGroup))
assert.equal(wrapper.children().at(0).children().length, 0)
})

View File

@ -1,7 +1,7 @@
const Component = require('react').Component
const h = require('react-hyperscript')
const inherits = require('util').inherits
const ReactTooltip = require('react-tooltip-component')
const ReactTooltip = require('react-tooltip')
module.exports = Tooltip

View File

@ -6,7 +6,7 @@ module.exports = bundleCss
var cssFiles = {
'index.css': fs.readFileSync(path.join(__dirname, '/app/css/output/index.css'), 'utf8'),
'first-time.css': fs.readFileSync(path.join(__dirname, '../mascara/src/app/first-time/index.css'), 'utf8'),
'react-tooltip-component.css': fs.readFileSync(path.join(__dirname, '..', 'node_modules', 'react-tooltip-component', 'dist', 'react-tooltip-component.css'), 'utf8'),
// 'react-tooltip.css': fs.readFileSync(path.join(__dirname, '..', 'node_modules', 'react-tooltip', 'dist', 'style.css'), 'utf8'),
'react-css': fs.readFileSync(path.join(__dirname, '..', 'node_modules', 'react-select', 'dist', 'react-select.css'), 'utf8'),
}