Fixes display of confirm screen token decimals by not relying on confirmTransaction state.

feature/default_network_editable
Dan Miller 6 years ago committed by Mark Stacey
parent 0e108db3cc
commit 789fc8b8ad
  1. 21
      ui/app/helpers/utils/token-util.js
  2. 20
      ui/app/helpers/utils/transactions.util.js
  3. 29
      ui/app/pages/confirm-token-transaction-base/confirm-token-transaction-base.container.js
  4. 9
      ui/app/pages/confirm-transaction/confirm-transaction.component.js
  5. 9
      ui/app/pages/confirm-transaction/confirm-transaction.container.js
  6. 43
      ui/app/store/actions.js

@ -68,6 +68,22 @@ async function getDecimals (tokenAddress) {
return decimals return decimals
} }
export async function fetchSymbolAndDecimals (tokenAddress) {
let symbol, decimals
try {
symbol = await getSymbol(tokenAddress)
decimals = await getDecimals(tokenAddress)
} catch (error) {
log.warn(`symbol() and decimal() calls for token at address ${tokenAddress} resulted in error:`, error)
}
return {
symbol: symbol || DEFAULT_SYMBOL,
decimals: decimals || DEFAULT_DECIMALS,
}
}
export async function getSymbolAndDecimals (tokenAddress, existingTokens = []) { export async function getSymbolAndDecimals (tokenAddress, existingTokens = []) {
const existingToken = existingTokens.find(({ address }) => tokenAddress === address) const existingToken = existingTokens.find(({ address }) => tokenAddress === address)
@ -116,3 +132,8 @@ export function getTokenValue (tokenParams = []) {
const valueData = tokenParams.find(param => param.name === '_value') const valueData = tokenParams.find(param => param.name === '_value')
return valueData && valueData.value return valueData && valueData.value
} }
export function getTokenToAddress (tokenParams = []) {
const toAddressData = tokenParams.find(param => param.name === '_to')
return toAddressData && toAddressData.value
}

@ -102,6 +102,20 @@ export function getFourBytePrefix (data = '') {
return fourBytePrefix return fourBytePrefix
} }
/**
* Given an transaction category, returns a boolean which indicates whether the transaction is calling an erc20 token method
*
* @param {string} transactionCategory - The category of transaction being evaluated
* @returns {boolean} - whether the transaction is calling an erc20 token method
*/
export function isTokenMethodAction (transactionCategory) {
return [
TOKEN_METHOD_TRANSFER,
TOKEN_METHOD_APPROVE,
TOKEN_METHOD_TRANSFER_FROM,
].includes(transactionCategory)
}
/** /**
* Returns the action of a transaction as a key to be passed into the translator. * Returns the action of a transaction as a key to be passed into the translator.
* @param {Object} transaction - txData object * @param {Object} transaction - txData object
@ -122,11 +136,7 @@ export function getTransactionActionKey (transaction) {
return DEPLOY_CONTRACT_ACTION_KEY return DEPLOY_CONTRACT_ACTION_KEY
} }
const isTokenAction = [ const isTokenAction = isTokenMethodAction(transactionCategory)
TOKEN_METHOD_TRANSFER,
TOKEN_METHOD_APPROVE,
TOKEN_METHOD_TRANSFER_FROM,
].find(actionName => actionName === transactionCategory)
const isNonTokenSmartContract = transactionCategory === CONTRACT_INTERACTION_KEY const isNonTokenSmartContract = transactionCategory === CONTRACT_INTERACTION_KEY
if (isTokenAction || isNonTokenSmartContract) { if (isTokenAction || isNonTokenSmartContract) {

@ -1,27 +1,42 @@
import { connect } from 'react-redux' import { connect } from 'react-redux'
import ConfirmTokenTransactionBase from './confirm-token-transaction-base.component' import ConfirmTokenTransactionBase from './confirm-token-transaction-base.component'
import { import {
tokenAmountAndToAddressSelector,
contractExchangeRateSelector, contractExchangeRateSelector,
} from '../../selectors/confirm-transaction' } from '../../selectors/confirm-transaction'
import { tokenSelector } from '../../selectors/tokens'
import {
getTokenData,
} from '../../helpers/utils/transactions.util'
import {
calcTokenAmount,
getTokenToAddress,
getTokenValue,
} from '../../helpers/utils/token-util'
const mapStateToProps = (state, ownProps) => { const mapStateToProps = (state) => {
const { tokenAmount: ownTokenAmount } = ownProps
const { confirmTransaction, metamask: { currentCurrency, conversionRate } } = state const { confirmTransaction, metamask: { currentCurrency, conversionRate } } = state
const { const {
txData: { txParams: { to: tokenAddress } = {} } = {}, txData: { txParams: { to: tokenAddress, data } = {} } = {},
tokenProps: { tokenSymbol } = {},
fiatTransactionTotal, fiatTransactionTotal,
ethTransactionTotal, ethTransactionTotal,
} = confirmTransaction } = confirmTransaction
const { tokenAmount, toAddress } = tokenAmountAndToAddressSelector(state)
const tokens = tokenSelector(state)
const currentToken = tokens && tokens.find(({ address }) => tokenAddress === address)
const { decimals, symbol: tokenSymbol } = currentToken || {}
const tokenData = getTokenData(data)
const tokenValue = tokenData && getTokenValue(tokenData.params)
const toAddress = tokenData && getTokenToAddress(tokenData.params)
const tokenAmount = tokenData && calcTokenAmount(tokenValue, decimals).toString()
const contractExchangeRate = contractExchangeRateSelector(state) const contractExchangeRate = contractExchangeRateSelector(state)
return { return {
toAddress, toAddress,
tokenAddress, tokenAddress,
tokenAmount: typeof ownTokenAmount !== 'undefined' ? ownTokenAmount : tokenAmount, tokenAmount,
tokenSymbol, tokenSymbol,
currentCurrency, currentCurrency,
conversionRate, conversionRate,

@ -37,6 +37,8 @@ export default class ConfirmTransaction extends Component {
getContractMethodData: PropTypes.func, getContractMethodData: PropTypes.func,
transactionId: PropTypes.string, transactionId: PropTypes.string,
paramsTransactionId: PropTypes.string, paramsTransactionId: PropTypes.string,
getTokenParams: PropTypes.func,
isTokenMethodAction: PropTypes.bool,
} }
getParamsTransactionId () { getParamsTransactionId () {
@ -49,11 +51,13 @@ export default class ConfirmTransaction extends Component {
totalUnapprovedCount = 0, totalUnapprovedCount = 0,
send = {}, send = {},
history, history,
transaction: { txParams: { data } = {} } = {}, transaction: { txParams: { data, to } = {} } = {},
fetchBasicGasAndTimeEstimates, fetchBasicGasAndTimeEstimates,
getContractMethodData, getContractMethodData,
transactionId, transactionId,
paramsTransactionId, paramsTransactionId,
getTokenParams,
isTokenMethodAction,
} = this.props } = this.props
if (!totalUnapprovedCount && !send.to) { if (!totalUnapprovedCount && !send.to) {
@ -63,6 +67,9 @@ export default class ConfirmTransaction extends Component {
fetchBasicGasAndTimeEstimates() fetchBasicGasAndTimeEstimates()
getContractMethodData(data) getContractMethodData(data)
if (isTokenMethodAction) {
getTokenParams(to)
}
this.props.setTransactionToConfirm(transactionId || paramsTransactionId) this.props.setTransactionToConfirm(transactionId || paramsTransactionId)
} }

@ -5,12 +5,16 @@ import {
setTransactionToConfirm, setTransactionToConfirm,
clearConfirmTransaction, clearConfirmTransaction,
} from '../../ducks/confirm-transaction/confirm-transaction.duck' } from '../../ducks/confirm-transaction/confirm-transaction.duck'
import {
isTokenMethodAction,
} from '../../helpers/utils/transactions.util'
import { import {
fetchBasicGasAndTimeEstimates, fetchBasicGasAndTimeEstimates,
} from '../../ducks/gas/gas.duck' } from '../../ducks/gas/gas.duck'
import { import {
getContractMethodData, getContractMethodData,
getTokenParams,
} from '../../store/actions' } from '../../store/actions'
import ConfirmTransaction from './confirm-transaction.component' import ConfirmTransaction from './confirm-transaction.component'
import { unconfirmedTransactionsListSelector } from '../../selectors/confirm-transaction' import { unconfirmedTransactionsListSelector } from '../../selectors/confirm-transaction'
@ -25,6 +29,7 @@ const mapStateToProps = (state, ownProps) => {
const transaction = totalUnconfirmed const transaction = totalUnconfirmed
? unapprovedTxs[id] || unconfirmedTransactions[totalUnconfirmed - 1] ? unapprovedTxs[id] || unconfirmedTransactions[totalUnconfirmed - 1]
: {} : {}
const { id: transactionId, transactionCategory } = transaction
return { return {
totalUnapprovedCount: totalUnconfirmed, totalUnapprovedCount: totalUnconfirmed,
@ -33,9 +38,10 @@ const mapStateToProps = (state, ownProps) => {
unapprovedTxs, unapprovedTxs,
id, id,
paramsTransactionId: id && String(id), paramsTransactionId: id && String(id),
transactionId: transaction.id && String(transaction.id), transactionId: transactionId && String(transactionId),
unconfirmedTransactions, unconfirmedTransactions,
transaction, transaction,
isTokenMethodAction: isTokenMethodAction(transactionCategory),
} }
} }
@ -47,6 +53,7 @@ const mapDispatchToProps = dispatch => {
clearConfirmTransaction: () => dispatch(clearConfirmTransaction()), clearConfirmTransaction: () => dispatch(clearConfirmTransaction()),
fetchBasicGasAndTimeEstimates: () => dispatch(fetchBasicGasAndTimeEstimates()), fetchBasicGasAndTimeEstimates: () => dispatch(fetchBasicGasAndTimeEstimates()),
getContractMethodData: (data) => dispatch(getContractMethodData(data)), getContractMethodData: (data) => dispatch(getContractMethodData(data)),
getTokenParams: (tokenAddress) => dispatch(getTokenParams(tokenAddress)),
} }
} }

@ -9,6 +9,7 @@ const {
const ethUtil = require('ethereumjs-util') const ethUtil = require('ethereumjs-util')
const { fetchLocale } = require('../helpers/utils/i18n-helper') const { fetchLocale } = require('../helpers/utils/i18n-helper')
const { getMethodDataAsync } = require('../helpers/utils/transactions.util') const { getMethodDataAsync } = require('../helpers/utils/transactions.util')
const { fetchSymbolAndDecimals } = require('../helpers/utils/token-util')
const log = require('loglevel') const log = require('loglevel')
const { ENVIRONMENT_TYPE_NOTIFICATION } = require('../../../app/scripts/lib/enums') const { ENVIRONMENT_TYPE_NOTIFICATION } = require('../../../app/scripts/lib/enums')
const { hasUnconfirmedTransactions } = require('../helpers/utils/confirm-tx.util') const { hasUnconfirmedTransactions } = require('../helpers/utils/confirm-tx.util')
@ -367,6 +368,12 @@ var actions = {
loadingMethoDataFinished, loadingMethoDataFinished,
LOADING_METHOD_DATA_STARTED: 'LOADING_METHOD_DATA_STARTED', LOADING_METHOD_DATA_STARTED: 'LOADING_METHOD_DATA_STARTED',
LOADING_METHOD_DATA_FINISHED: 'LOADING_METHOD_DATA_FINISHED', LOADING_METHOD_DATA_FINISHED: 'LOADING_METHOD_DATA_FINISHED',
getTokenParams,
loadingTokenParamsStarted,
LOADING_TOKEN_PARAMS_STARTED: 'LOADING_TOKEN_PARAMS_STARTED',
loadingTokenParamsFinished,
LOADING_TOKEN_PARAMS_FINISHED: 'LOADING_TOKEN_PARAMS_FINISHED',
} }
module.exports = actions module.exports = actions
@ -2816,3 +2823,39 @@ function getContractMethodData (data = '') {
}) })
} }
} }
function loadingTokenParamsStarted () {
return {
type: actions.LOADING_TOKEN_PARAMS_STARTED,
}
}
function loadingTokenParamsFinished () {
return {
type: actions.LOADING_TOKEN_PARAMS_FINISHED,
}
}
function getTokenParams (tokenAddress) {
return (dispatch, getState) => {
const existingTokens = getState().metamask.tokens
const existingToken = existingTokens.find(({ address }) => tokenAddress === address)
if (existingToken) {
return Promise.resolve({
symbol: existingToken.symbol,
decimals: existingToken.decimals,
})
}
dispatch(actions.loadingTokenParamsStarted())
log.debug(`loadingTokenParams`)
return fetchSymbolAndDecimals(tokenAddress, existingTokens)
.then(({ symbol, decimals }) => {
dispatch(actions.addToken(tokenAddress, symbol, decimals))
dispatch(actions.loadingTokenParamsFinished())
})
}
}

Loading…
Cancel
Save