Merge remote-tracking branch 'origin/develop' into token-menu

This commit is contained in:
Victor Baranov 2018-10-02 17:59:33 +03:00
commit c9efcd45b0
14 changed files with 210 additions and 61 deletions

View File

@ -70,6 +70,10 @@ createCopyTasks('contractImages', {
source: './node_modules/eth-contract-metadata/images/',
destinations: commonPlatforms.map(platform => `./dist/${platform}/images/contract`),
})
createCopyTasks('contractImagesPOA', {
source: './node_modules/poa-contract-metadata/images/',
destinations: commonPlatforms.map(platform => `./dist/${platform}/images/contractPOA`),
})
createCopyTasks('fonts', {
source: './app/fonts/',
destinations: commonPlatforms.map(platform => `./dist/${platform}/fonts`),

View File

@ -3,7 +3,7 @@ const { Component } = React
const h = require('react-hyperscript')
const Tooltip = require('../tooltip.js')
const TabBar = require('../tab-bar')
const { checkExistingAddresses } = require('../../../../ui/app/components/pages/add-token/util')
const { checkExistingAddresses } = require('./util')
const TokenList = require('./token-list')
const TokenSearch = require('./token-search')
const { tokenInfoGetter } = require('../../../../ui/app/token-util')
@ -24,6 +24,7 @@ class AddTokenScreen extends Component {
}
static propTypes = {
goHome: PropTypes.func,
setPendingTokens: PropTypes.func,
pendingTokens: PropTypes.object,
clearPendingTokens: PropTypes.func,
@ -90,7 +91,8 @@ class AddTokenScreen extends Component {
const { network } = this.props
const networkID = parseInt(network)
let views = []
networkID === 1 ? views = [h(TabBar, {
const isProdNetwork = networkID === 1 || networkID === 99
isProdNetwork ? views = [h(TabBar, {
style: {
paddingTop: '0px',
},
@ -258,15 +260,14 @@ class AddTokenScreen extends Component {
}
renderTabBar () {
const props = this.props
const state = this.state
const { tokenSelectorError, selectedTokens, searchResults } = state
const { clearPendingTokens, goHome } = props
const { tokenSelectorError, selectedTokens, searchResults } = this.state
const { clearPendingTokens, goHome, network } = this.props
return h('div', [
h('.add-token__search-token', [
h(TokenSearch, {
onSearch: ({ results = [] }) => this.setState({ searchResults: results }),
error: tokenSelectorError,
network: network,
}),
h('.add-token__token-list', {
style: {
@ -278,6 +279,7 @@ class AddTokenScreen extends Component {
h(TokenList, {
results: searchResults,
selectedTokens: selectedTokens,
network: network,
onToggleToken: token => this.handleToggleToken(token),
}),
]),
@ -312,6 +314,22 @@ class AddTokenScreen extends Component {
displayWarning('')
}
componentWillUpdate (nextProps) {
const {
network: oldNet,
} = this.props
const {
network: newNet,
} = nextProps
if (oldNet !== newNet) {
this.setState({
selectedTokens: {},
searchResults: [],
})
}
}
validateInputs () {
let msg = ''
const state = this.state

View File

@ -11,6 +11,7 @@ export default class InfoBox extends Component {
}
static propTypes = {
network: PropTypes.string,
tokens: PropTypes.array,
results: PropTypes.array,
selectedTokens: PropTypes.object,
@ -18,7 +19,9 @@ export default class InfoBox extends Component {
}
render () {
const { results = [], selectedTokens = {}, onToggleToken, tokens = [] } = this.props
const { results = [], selectedTokens = {}, onToggleToken, tokens = [], network } = this.props
const networkID = parseInt(network)
const imagesFolder = networkID === 1 ? 'images/contract' : 'images/contractPOA'
return results.length === 0
? <TokenListPlaceholder />
@ -43,7 +46,7 @@ export default class InfoBox extends Component {
<div
className="token-list__token-icon"
style={{
'backgroundImage': logo && `url(images/contract/${logo})`,
'backgroundImage': logo && `url(${imagesFolder}/${logo})`,
}}
>
</div>

View File

@ -1,2 +1,2 @@
import TokenSearch from './token-search.component'
import TokenSearch from './token-search.container'
module.exports = TokenSearch

View File

@ -1,26 +1,14 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import contractMap from 'eth-contract-metadata'
import contractMapETH from 'eth-contract-metadata'
import contractMapPOA from 'poa-contract-metadata'
import Fuse from 'fuse.js'
import InputAdornment from '@material-ui/core/InputAdornment'
import TextField from '../../../../../ui/app/components/text-field'
const contractList = Object.entries(contractMap)
.map(([ _, tokenData]) => tokenData)
.filter(tokenData => Boolean(tokenData.erc20))
let contractList
const fuse = new Fuse(contractList, {
shouldSort: true,
threshold: 0.45,
location: 0,
distance: 100,
maxPatternLength: 32,
minMatchCharLength: 1,
keys: [
{ name: 'name', weight: 0.5 },
{ name: 'symbol', weight: 0.5 },
],
})
let fuse
export default class TokenSearch extends Component {
static contextTypes = {
@ -32,6 +20,7 @@ export default class TokenSearch extends Component {
}
static propTypes = {
network: PropTypes.string,
onSearch: PropTypes.func,
error: PropTypes.string,
}
@ -42,6 +31,9 @@ export default class TokenSearch extends Component {
this.state = {
searchQuery: '',
}
const networkID = parseInt(props.network)
this.updateContractList(networkID)
}
handleSearch (searchQuery) {
@ -54,6 +46,42 @@ export default class TokenSearch extends Component {
this.props.onSearch({ searchQuery, results })
}
componentWillUpdate (nextProps) {
const {
network: oldNet,
} = this.props
const {
network: newNet,
} = nextProps
if (oldNet !== newNet) {
const newNetworkID = parseInt(newNet)
this.updateContractList(newNetworkID)
this.setState({ searchQuery: '' })
this.props.onSearch({ searchQuery: '', results: [] })
}
}
updateContractList (newNetworkID) {
const contractMap = newNetworkID === 1 ? contractMapETH : contractMapPOA
contractList = Object.entries(contractMap)
.map(([ _, tokenData]) => tokenData)
.filter(tokenData => Boolean(tokenData.erc20))
fuse = new Fuse(contractList, {
shouldSort: true,
threshold: 0.45,
location: 0,
distance: 100,
maxPatternLength: 32,
minMatchCharLength: 1,
keys: [
{ name: 'name', weight: 0.5 },
{ name: 'symbol', weight: 0.5 },
],
})
}
renderAdornment () {
return (
<InputAdornment

View File

@ -0,0 +1,20 @@
import { connect } from 'react-redux'
import TokenSearch from './token-search.component'
const { clearPendingTokens } = require('../../../../../ui/app/actions')
const mapStateToProps = ({ metamask }) => {
const { network } = metamask
return {
network,
}
}
const mapDispatchToProps = dispatch => {
return {
clearPendingTokens: () => dispatch(clearPendingTokens()),
}
}
export default connect(mapStateToProps, mapDispatchToProps)(TokenSearch)

View File

@ -10,6 +10,7 @@ export default class ConfirmAddToken extends Component {
}
static propTypes = {
network: PropTypes.string,
clearPendingTokens: PropTypes.func,
addTokens: PropTypes.func,
pendingTokens: PropTypes.object,
@ -31,9 +32,25 @@ export default class ConfirmAddToken extends Component {
: `${name} (${symbol})`
}
componentWillUpdate (nextProps) {
const { clearPendingTokens, showAddTokenPage } = this.props
const {
network: oldNet,
} = this.props
const {
network: newNet,
} = nextProps
if (oldNet !== newNet) {
clearPendingTokens()
showAddTokenPage()
}
}
render () {
const { addTokens, clearPendingTokens, pendingTokens, goHome, showAddTokenPage } = this.props
const { addTokens, clearPendingTokens, pendingTokens, goHome, showAddTokenPage, network } = this.props
const areMultipleTokens = pendingTokens && Object.keys(pendingTokens).length > 1
const likeToAddTokensText = areMultipleTokens ? 'Would you like to add these tokens?' : 'Would you like to add this token?'
return (
<div className="page-container">
@ -42,7 +59,7 @@ export default class ConfirmAddToken extends Component {
{ 'Add Tokens' /* this.context.t('addTokens')*/ }
</h2>
<p className="confirm-label">
{ areMultipleTokens ? 'Would you like to add these tokens?' : 'Would you like to add this token?' /* this.context.t('likeToAddTokens')*/ }
{ likeToAddTokensText /* this.context.t('likeToAddTokens')*/ }
</p>
</div>
<div className="page-container__content">
@ -71,6 +88,7 @@ export default class ConfirmAddToken extends Component {
className="confirm-add-token__token-icon"
diameter={48}
address={address}
network={network}
/>
<div className="confirm-add-token__name">
{ this.getTokenName(name, symbol) }

View File

@ -4,9 +4,10 @@ import ConfirmAddToken from './confirm-add-token.component'
const { addTokens, clearPendingTokens, goHome, showAddTokenPage } = require('../../../../ui/app/actions')
const mapStateToProps = ({ metamask }) => {
const { pendingTokens } = metamask
const { pendingTokens, network } = metamask
return {
pendingTokens,
network,
}
}

View File

@ -37,7 +37,7 @@ IdenticonComponent.prototype.render = function () {
IdenticonComponent.prototype.componentDidMount = function () {
var props = this.props
const { address } = props
const { address, network } = props
if (!address) return
@ -46,14 +46,14 @@ IdenticonComponent.prototype.componentDidMount = function () {
var diameter = props.diameter || this.defaultDiameter
if (!isNode) {
var img = iconFactory.iconForAddress(address, diameter)
var img = iconFactory.iconForAddress(address, diameter, network)
container.appendChild(img)
}
}
IdenticonComponent.prototype.componentDidUpdate = function () {
var props = this.props
const { address } = props
const { address, network } = props
if (!address) return
@ -67,7 +67,7 @@ IdenticonComponent.prototype.componentDidUpdate = function () {
var diameter = props.diameter || this.defaultDiameter
if (!isNode) {
var img = iconFactory.iconForAddress(address, diameter)
var img = iconFactory.iconForAddress(address, diameter, network)
container.appendChild(img)
}
}

View File

@ -3,9 +3,38 @@ const h = require('react-hyperscript')
const inherits = require('util').inherits
const TokenTracker = require('eth-token-watcher')
const TokenCell = require('./token-cell.js')
const connect = require('react-redux').connect
const selectors = require('../../../ui/app/selectors')
const log = require('loglevel')
module.exports = TokenList
function mapStateToProps (state) {
return {
network: state.metamask.network,
tokens: state.metamask.tokens,
userAddress: selectors.getSelectedAddress(state),
}
}
const defaultTokens = []
const contractsETH = require('eth-contract-metadata')
const contractsPOA = require('poa-contract-metadata')
for (const address in contractsETH) {
const contract = contractsETH[address]
if (contract.erc20) {
contract.address = address
defaultTokens.push(contract)
}
}
for (const address in contractsPOA) {
const contract = contractsPOA[address]
if (contract.erc20) {
contract.address = address
defaultTokens.push(contract)
}
}
module.exports = connect(mapStateToProps)(TokenList)
inherits(TokenList, Component)
function TokenList () {
@ -155,7 +184,7 @@ TokenList.prototype.componentDidMount = function () {
this.createFreshTokenTracker()
}
TokenList.prototype.createFreshTokenTracker = function (userAddress) {
TokenList.prototype.createFreshTokenTracker = function () {
if (this.tracker) {
// Clean up old trackers when refreshing:
this.tracker.stop()
@ -164,8 +193,10 @@ TokenList.prototype.createFreshTokenTracker = function (userAddress) {
}
if (!global.ethereumProvider) return
const { userAddress } = this.props
this.tracker = new TokenTracker({
userAddress: userAddress || this.props.userAddress,
userAddress,
provider: global.ethereumProvider,
tokens: this.props.tokens,
pollingInterval: 8000,
@ -190,26 +221,42 @@ TokenList.prototype.createFreshTokenTracker = function (userAddress) {
})
}
TokenList.prototype.componentWillUpdate = function (nextProps) {
if (nextProps.network === 'loading') return
const oldNet = this.props.network
const newNet = nextProps.network
TokenList.prototype.componentDidUpdate = function (nextProps) {
const {
network: oldNet,
userAddress: oldAddress,
tokens,
} = this.props
const {
network: newNet,
userAddress: newAddress,
tokens: newTokens,
} = nextProps
const oldAddress = this.props.userAddress
const newAddress = nextProps.userAddress
const isLoading = newNet === 'loading'
const missingInfo = !oldNet || !newNet || !oldAddress || !newAddress
const sameUserAndNetwork = oldAddress === newAddress && oldNet === newNet
const shouldUpdateTokens = isLoading || missingInfo || sameUserAndNetwork
if (oldNet && newNet && (newNet !== oldNet || newAddress !== oldAddress)) {
this.setState({ isLoading: true })
this.createFreshTokenTracker(newAddress)
}
const oldTokensLength = tokens ? tokens.length : 0
const tokensLengthUnchanged = oldTokensLength === newTokens.length
if (tokensLengthUnchanged && shouldUpdateTokens) return
this.setState({ isLoading: true })
this.createFreshTokenTracker()
}
TokenList.prototype.updateBalances = function (tokens) {
this.setState({ tokens, error: null, isLoading: false })
if (!this.tracker.running) {
return
}
this.setState({ tokens, isLoading: false })
}
TokenList.prototype.componentWillUnmount = function () {
if (!this.tracker) return
this.tracker.stop()
this.tracker.removeListener('update', this.balanceUpdater)
this.tracker.removeListener('error', this.showError)
}

View File

@ -1,26 +1,28 @@
var iconFactory
const isValidAddress = require('ethereumjs-util').isValidAddress
const toChecksumAddress = require('ethereumjs-util').toChecksumAddress
const contractMap = require('eth-contract-metadata')
const contractMapETH = require('eth-contract-metadata')
const contractMapPOA = require('poa-contract-metadata')
const colors = require('../../colors')
module.exports = function (jazzicon) {
module.exports = function (rockicon) {
if (!iconFactory) {
iconFactory = new IconFactory(jazzicon)
iconFactory = new IconFactory(rockicon)
}
return iconFactory
}
function IconFactory (jazzicon) {
jazzicon.setColorsPalette(colors)
this.jazzicon = jazzicon
function IconFactory (rockicon) {
rockicon.setColorsPalette(colors)
this.rockicon = rockicon
this.cache = {}
}
IconFactory.prototype.iconForAddress = function (address, diameter) {
IconFactory.prototype.iconForAddress = function (address, diameter, network) {
const networkID = parseInt(network)
const addr = toChecksumAddress(address)
if (iconExistsFor(addr)) {
return imageElFor(addr)
if (iconExistsFor(addr, networkID)) {
return imageElFor(addr, networkID)
}
return this.generateIdenticonSvg(address, diameter)
@ -39,20 +41,24 @@ IconFactory.prototype.generateIdenticonSvg = function (address, diameter) {
// creates a new identicon
IconFactory.prototype.generateNewIdenticon = function (address, diameter) {
var numericRepresentation = jsNumberForAddress(address)
var identicon = this.jazzicon.generateIdenticon(diameter, numericRepresentation)
var identicon = this.rockicon.generateIdenticon(diameter, numericRepresentation)
return identicon
}
// util
function iconExistsFor (address) {
function iconExistsFor (address, networkID) {
const contractMap = networkID === 1 ? contractMapETH : contractMapPOA
return contractMap[address] && isValidAddress(address) && contractMap[address].logo
}
function imageElFor (address) {
function imageElFor (address, networkID) {
const contractMap = networkID === 1 ? contractMapETH : contractMapPOA
console.log(contractMap)
const contract = contractMap[address]
const fileName = contract.logo
const path = `images/contract/${fileName}`
const imagesFolder = networkID === 1 ? 'images/contract' : 'images/contractPOA'
const path = `${imagesFolder}/${fileName}`
const img = document.createElement('img')
img.src = path
img.style.width = '75%'

4
package-lock.json generated
View File

@ -23820,6 +23820,10 @@
"integrity": "sha1-HMfCEjA6yr50Jj7DrHgAlYAkLZM=",
"dev": true
},
"poa-contract-metadata": {
"version": "github:poanetwork/poa-contract-metadata#daee2eab58db1cb2aad50cd58c45374f614f029e",
"from": "github:poanetwork/poa-contract-metadata#master"
},
"pojo-migrator": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/pojo-migrator/-/pojo-migrator-2.1.0.tgz",

View File

@ -161,6 +161,7 @@
"percentile": "^1.2.0",
"pify": "^3.0.0",
"ping-pong-stream": "^1.0.0",
"poa-contract-metadata": "github:poanetwork/poa-contract-metadata#master",
"pojo-migrator": "^2.1.0",
"polyfill-crypto.getrandomvalues": "^1.0.0",
"post-message-stream": "^3.0.0",

View File

@ -64,4 +64,3 @@ function jsNumberForAddress (address) {
var seed = parseInt(addr, 16)
return seed
}