From c8c918d44e26e9541beead982ef0ed79a56d6e6f Mon Sep 17 00:00:00 2001 From: Dan Date: Fri, 27 Oct 2017 15:09:40 -0230 Subject: [PATCH] Add utility for getting token data; get token data in tx-list even if token has been removed. --- ui/app/add-token.js | 23 +++----------- ui/app/components/tx-list-item.js | 53 ++++++++++++++++++++++++------- ui/app/components/tx-list.js | 6 ++++ ui/app/token-util.js | 36 +++++++++++++++++++++ 4 files changed, 89 insertions(+), 29 deletions(-) create mode 100644 ui/app/token-util.js diff --git a/ui/app/add-token.js b/ui/app/add-token.js index 518701a1d..10aaae103 100644 --- a/ui/app/add-token.js +++ b/ui/app/add-token.js @@ -21,9 +21,7 @@ const fuse = new Fuse(contractList, { }) const actions = require('./actions') const ethUtil = require('ethereumjs-util') -const abi = require('human-standard-token-abi') -const Eth = require('ethjs-query') -const EthContract = require('ethjs-contract') +const { tokenInfoGetter } = require('./token-util') const R = require('ramda') const emptyAddr = '0x0000000000000000000000000000000000000000' @@ -63,11 +61,7 @@ function AddTokenScreen () { } AddTokenScreen.prototype.componentWillMount = function () { - if (typeof global.ethereumProvider === 'undefined') return - - this.eth = new Eth(global.ethereumProvider) - this.contract = new EthContract(this.eth) - this.TokenContract = this.contract(abi) + this.tokenInfoGetter = tokenInfoGetter() } AddTokenScreen.prototype.toggleToken = function (address, token) { @@ -164,18 +158,11 @@ AddTokenScreen.prototype.validate = function () { } AddTokenScreen.prototype.attemptToAutoFillTokenParams = async function (address) { - const contract = this.TokenContract.at(address) - - const results = await Promise.all([ - contract.symbol(), - contract.decimals(), - ]) - - const [ symbol, decimals ] = results + const { symbol, decimals } = await this.tokenInfoGetter(address) if (symbol && decimals) { this.setState({ - customSymbol: symbol[0], - customDecimals: decimals[0].toString(), + customSymbol: symbol, + customDecimals: decimals.toString(), }) } } diff --git a/ui/app/components/tx-list-item.js b/ui/app/components/tx-list-item.js index 84026700b..a59b6509b 100644 --- a/ui/app/components/tx-list-item.js +++ b/ui/app/components/tx-list-item.js @@ -8,6 +8,7 @@ const abiDecoder = require('abi-decoder') abiDecoder.addABI(abi) const prefixForNetwork = require('../../lib/etherscan-prefix-for-network') const Identicon = require('./identicon') +const contractMap = require('eth-contract-metadata') const { conversionUtil, multiplyCurrencies } = require('../conversion-util') @@ -26,6 +27,24 @@ function mapStateToProps (state) { inherits(TxListItem, Component) function TxListItem () { Component.call(this) + + this.state = { + total: null, + fiatTotal: null, + } +} + +TxListItem.prototype.componentDidMount = async function () { + const { txParams = {} } = this.props + + const decodedData = txParams.data && abiDecoder.decodeMethod(txParams.data) + const { name: txDataName } = decodedData || {} + + const { total, fiatTotal } = txDataName === 'transfer' + ? await this.getSendTokenTotal() + : this.getSendEtherTotal() + + this.setState({ total, fiatTotal }) } TxListItem.prototype.getAddressText = function () { @@ -85,7 +104,27 @@ TxListItem.prototype.getSendEtherTotal = function () { } } -TxListItem.prototype.getSendTokenTotal = function () { +TxListItem.prototype.getTokenInfo = async function () { + const { txParams = {}, tokenInfoGetter, tokens } = this.props + const toAddress = txParams.to + + let decimals + let symbol + + ({ decimals, symbol } = tokens.filter(({ address }) => address === toAddress)[0] || {}) + + if (!decimals && !symbol) { + ({ decimals, symbol } = contractMap[toAddress] || {}) + } + + if (!decimals && !symbol) { + ({ decimals, symbol } = await tokenInfoGetter(toAddress)) + } + + return { decimals, symbol } +} + +TxListItem.prototype.getSendTokenTotal = async function () { const { txParams = {}, tokens, @@ -94,11 +133,10 @@ TxListItem.prototype.getSendTokenTotal = function () { currentCurrency, } = this.props - const toAddress = txParams.to const decodedData = txParams.data && abiDecoder.decodeMethod(txParams.data) const { params = [] } = decodedData || {} const { value } = params[1] || {} - const { decimals, symbol } = tokens.filter(({ address }) => address === toAddress)[0] || {} + const { decimals, symbol } = await this.getTokenInfo() const multiplier = Math.pow(10, Number(decimals || 0)) const total = Number(value / multiplier) @@ -139,15 +177,8 @@ TxListItem.prototype.render = function () { dateString, address, className, - txParams = {}, } = this.props - - const decodedData = txParams.data && abiDecoder.decodeMethod(txParams.data) - const { name: txDataName } = decodedData || {} - - const { total, fiatTotal } = txDataName === 'transfer' - ? this.getSendTokenTotal() - : this.getSendEtherTotal() + const { total, fiatTotal } = this.state return h(`div${className || ''}`, { key: transActionId, diff --git a/ui/app/components/tx-list.js b/ui/app/components/tx-list.js index a02849d0e..2f6c1fee8 100644 --- a/ui/app/components/tx-list.js +++ b/ui/app/components/tx-list.js @@ -9,6 +9,7 @@ const ShiftListItem = require('./shift-list-item') const { formatBalance, formatDate } = require('../util') const { showConfTxPage } = require('../actions') const classnames = require('classnames') +const { tokenInfoGetter } = require('../token-util') module.exports = connect(mapStateToProps, mapDispatchToProps)(TxList) @@ -30,6 +31,10 @@ function TxList () { Component.call(this) } +TxList.prototype.componentWillMount = function () { + this.tokenInfoGetter = tokenInfoGetter() +} + TxList.prototype.render = function () { const { txsToRender, showConfTxPage } = this.props @@ -99,6 +104,7 @@ TxList.prototype.renderTransactionListItem = function (transaction, conversionRa transactionAmount, transactionHash, conversionRate, + tokenInfoGetter: this.tokenInfoGetter, } const isUnapproved = transactionStatus === 'unapproved'; diff --git a/ui/app/token-util.js b/ui/app/token-util.js new file mode 100644 index 000000000..eec518556 --- /dev/null +++ b/ui/app/token-util.js @@ -0,0 +1,36 @@ +const abi = require('human-standard-token-abi') +const Eth = require('ethjs-query') +const EthContract = require('ethjs-contract') + +const tokenInfoGetter = function () { + if (typeof global.ethereumProvider === 'undefined') return + + const eth = new Eth(global.ethereumProvider) + const contract = new EthContract(eth) + const TokenContract = contract(abi) + + const tokens = {} + + return async (address) => { + if (tokens[address]) { + return tokens[address] + } + + const contract = TokenContract.at(address) + + const result = await Promise.all([ + contract.symbol(), + contract.decimals(), + ]) + + const [ symbol = [], decimals = [] ] = result + + tokens[address] = { symbol: symbol[0], decimals: decimals[0] } + + return tokens[address] + } +} + +module.exports = { + tokenInfoGetter, +}