From a59972dcabc56c3d92f09ba1b88a2ded70ce8c34 Mon Sep 17 00:00:00 2001 From: Alexander Tseung Date: Fri, 13 Oct 2017 17:14:48 -0400 Subject: [PATCH] Prevent adding already added tokens (#2362) --- ui/app/add-token.js | 28 +++++++++++++++++++--- ui/app/css/itcss/components/add-token.scss | 15 +++++++++++- 2 files changed, 39 insertions(+), 4 deletions(-) diff --git a/ui/app/add-token.js b/ui/app/add-token.js index f723ff07c..90edc8de1 100644 --- a/ui/app/add-token.js +++ b/ui/app/add-token.js @@ -22,14 +22,17 @@ const ethUtil = require('ethereumjs-util') const abi = require('human-standard-token-abi') const Eth = require('ethjs-query') const EthContract = require('ethjs-contract') +const R = require('ramda') const emptyAddr = '0x0000000000000000000000000000000000000000' module.exports = connect(mapStateToProps, mapDispatchToProps)(AddTokenScreen) function mapStateToProps (state) { + const { identities, tokens } = state.metamask return { - identities: state.metamask.identities, + identities, + tokens, } } @@ -101,6 +104,15 @@ AddTokenScreen.prototype.tokenAddressDidChange = function (e) { } } +AddTokenScreen.prototype.checkExistingAddresses = function (address) { + const tokensList = this.props.tokens + const matchesAddress = existingToken => { + return existingToken.address.toLowerCase() === address.toLowerCase() + } + + return R.any(matchesAddress)(tokensList) +} + AddTokenScreen.prototype.validate = function () { const errors = {} const identitiesList = Object.keys(this.props.identities) @@ -128,6 +140,11 @@ AddTokenScreen.prototype.validate = function () { if (ownAddress) { errors.customAddress = 'Personal address detected. Input the token contract address.' } + + const tokenAlreadyAdded = this.checkExistingAddresses(customAddress) + if (tokenAlreadyAdded) { + errors.customAddress = 'Token has already been added.' + } } else if ( Object.entries(selectedTokens) .reduce((isEmpty, [ symbol, isSelected ]) => ( @@ -217,12 +234,14 @@ AddTokenScreen.prototype.renderTokenList = function () { return Array(6).fill(undefined) .map((_, i) => { const { logo, symbol, name, address } = results[i] || {} + const tokenAlreadyAdded = this.checkExistingAddresses(address) return Boolean(logo || symbol || name) && ( h('div.add-token__token-wrapper', { - className: classnames('add-token__token-wrapper', { + className: classnames({ 'add-token__token-wrapper--selected': selectedTokens[address], + 'add-token__token-wrapper--disabled': tokenAlreadyAdded, }), - onClick: () => this.toggleToken(address, results[i]), + onClick: () => !tokenAlreadyAdded && this.toggleToken(address, results[i]), }, [ h('div.add-token__token-icon', { style: { @@ -233,6 +252,9 @@ AddTokenScreen.prototype.renderTokenList = function () { h('div.add-token__token-symbol', symbol), h('div.add-token__token-name', name), ]), + tokenAlreadyAdded && ( + h('div.add-token__token-message', 'Already added') + ), ]) ) }) diff --git a/ui/app/css/itcss/components/add-token.scss b/ui/app/css/itcss/components/add-token.scss index d5d1aab71..aa8221c9a 100644 --- a/ui/app/css/itcss/components/add-token.scss +++ b/ui/app/css/itcss/components/add-token.scss @@ -4,7 +4,6 @@ flex-flow: column nowrap; align-items: center; position: relative; - top: -36px; z-index: 12; font-family: 'DIN Next Light'; @@ -189,6 +188,7 @@ border-radius: 10px; cursor: pointer; border: 2px solid transparent; + position: relative; &:hover { border: 2px solid rgba($malibu-blue, .5); @@ -197,6 +197,11 @@ &--selected { border: 2px solid $malibu-blue !important; } + + &--disabled { + opacity: .4; + pointer-events: none; + } } &__token-name { @@ -223,6 +228,14 @@ flex: 0 0 auto; } + &__token-message { + position: absolute; + color: $caribbean-green; + font-size: 11px; + bottom: 0; + left: 85px; + } + &__confirmation-token-list { display: flex; flex-flow: column nowrap;