From 4aed2c0a7b07cc0159b64ee96190fbfbcf252537 Mon Sep 17 00:00:00 2001 From: Esteban MIno Date: Wed, 13 Feb 2019 23:15:39 -0300 Subject: [PATCH 1/9] decode transfer data ERC721 --- app/util/transactions.js | 22 +++++++++++++++++----- app/util/transactions.test.js | 12 +++++++++++- 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/app/util/transactions.js b/app/util/transactions.js index e197bfa43e4..620a4dbc040 100644 --- a/app/util/transactions.js +++ b/app/util/transactions.js @@ -85,13 +85,25 @@ export function generateTransferData(assetType, opts) { * @returns {Object} - Object containing the decoded transfer data */ export function decodeTransferData(assetType, data) { - let encodedAddress, encodedAmount, bufferEncodedAddress; switch (assetType) { - case 'ERC20': - encodedAddress = data.substr(10, 64); - encodedAmount = data.substr(74, 138); - bufferEncodedAddress = rawEncode(['address'], [addHexPrefix(encodedAddress)]); + case 'ERC20': { + const encodedAddress = data.substr(10, 64); + const encodedAmount = data.substr(74, 138); + const bufferEncodedAddress = rawEncode(['address'], [addHexPrefix(encodedAddress)]); return [addHexPrefix(rawDecode(['address'], bufferEncodedAddress)[0]), hexToBN(encodedAmount)]; + } + case 'ERC721': { + const encodedFromAddress = data.substr(10, 64); + const encodedToAddress = data.substr(74, 64); + const encodedTokenId = data.substr(138, 64); + const bufferEncodedFromAddress = rawEncode(['address'], [addHexPrefix(encodedFromAddress)]); + const bufferEncodedToAddress = rawEncode(['address'], [addHexPrefix(encodedToAddress)]); + return [ + addHexPrefix(rawDecode(['address'], bufferEncodedFromAddress)[0]), + addHexPrefix(rawDecode(['address'], bufferEncodedToAddress)[0]), + parseInt(encodedTokenId, 16).toString() + ]; + } } } diff --git a/app/util/transactions.test.js b/app/util/transactions.test.js index 7470269aecd..f0cc0ba1f7e 100644 --- a/app/util/transactions.test.js +++ b/app/util/transactions.test.js @@ -48,7 +48,7 @@ describe('Transactions utils :: generateTransferData', () => { }); describe('Transactions utils :: decodeTransferData', () => { - it('decodeTransferData', () => { + it('decodeTransferData ERC20', () => { const [address, amount] = decodeTransferData( 'ERC20', '0xa9059cbb00000000000000000000000056ced0d816c668d7c0bcc3fbf0ab2c6896f589a00000000000000000000000000000000000000000000000000000000000000001' @@ -56,6 +56,16 @@ describe('Transactions utils :: decodeTransferData', () => { expect(address).toEqual('0x56ced0d816c668d7c0bcc3fbf0ab2c6896f589a0'); expect(amount.toNumber()).toEqual(1); }); + + it('decodeTransferData ERC721', () => { + const [fromAddress, toAddress, tokenId] = decodeTransferData( + 'ERC721', + '0x23b872dd00000000000000000000000056ced0d816c668d7c0bcc3fbf0ab2c6896f589c900000000000000000000000056ced0d816c668d7c0bcc3fbf0ab2c6896f589b400000000000000000000000000000000000000000000000000000000000004f1' + ); + expect(fromAddress).toEqual('0x56ced0d816c668d7c0bcc3fbf0ab2c6896f589c9'); + expect(toAddress).toEqual('0x56ced0d816c668d7c0bcc3fbf0ab2c6896f589b4'); + expect(tokenId).toEqual('1265'); + }); }); describe('Transactions utils :: getMethodData', () => { From 810ca5f1c7e20ee3537e93f1c835cc38822d2e49 Mon Sep 17 00:00:00 2001 From: Esteban Mino Date: Thu, 14 Feb 2019 20:24:36 -0300 Subject: [PATCH 2/9] render tx element --- app/components/TransactionElement/index.js | 93 +++++++++------------- 1 file changed, 36 insertions(+), 57 deletions(-) diff --git a/app/components/TransactionElement/index.js b/app/components/TransactionElement/index.js index 99c4b44dd59..723dedd2f5c 100644 --- a/app/components/TransactionElement/index.js +++ b/app/components/TransactionElement/index.js @@ -1,6 +1,6 @@ import React, { PureComponent } from 'react'; import PropTypes from 'prop-types'; -import { TouchableOpacity, StyleSheet, Text, View, Image } from 'react-native'; +import { TouchableOpacity, StyleSheet, Text, View } from 'react-native'; import { colors, fontStyles } from '../../styles/common'; import { strings } from '../../../locales/i18n'; import { toLocaleDateTime } from '../../util/date'; @@ -88,15 +88,9 @@ const styles = StyleSheet.create({ statusFailed: { backgroundColor: colors.lightRed, color: colors.error - }, - ethLogo: { - width: 24, - height: 24 } }); -const ethLogo = require('../../images/eth-logo.png'); // eslint-disable-line - /** * View that renders a transaction item part of transactions list */ @@ -210,6 +204,32 @@ export default class TransactionElement extends PureComponent { /> ) : null; + /** + * Renders an horizontal bar with basic tx information + * + * @param {string} addressTo - Transaction to address + * @param {string} actionKey - Transaction action key + * @param {string} status - Transaction status + * @param {string} value - Transaction crypto value (ETH, assets ERC20 and ERC721) + * @param {string} fiatValue - transaction fiat crypto value, if available + */ + renderTxElement = (addressTo, actionKey, status, value, fiatValue) => ( + + {this.renderTxTime()} + + + + {actionKey} + {status.toUpperCase()} + + + {value} + {fiatValue} + + + + ); + renderTransferElement = () => { const { tx, @@ -253,24 +273,13 @@ export default class TransactionElement extends PureComponent { }; return ( - - {this.renderTxTime()} - - - - {renderActionKey} - - {tx.status.toUpperCase()} - - - - - {!renderTokenAmount ? strings('transaction.value_not_available') : renderTokenAmount} - - {renderTokenFiatAmount} - - - + {this.renderTxElement( + addressTo, + renderActionKey, + tx.status, + !renderTokenAmount ? strings('transaction.value_not_available') : renderTokenAmount, + renderTokenFiatAmount + )} {this.renderTxDetails( selected, { ...tx, ...{ transfer } }, @@ -301,22 +310,7 @@ export default class TransactionElement extends PureComponent { const renderTotalEthFiat = weiToFiat(totalETh, conversionRate, currentCurrency).toUpperCase(); return ( - - {this.renderTxTime()} - - - - {actionKey} - - {tx.status.toUpperCase()} - - - - {renderTotalEth} - {renderTotalEthFiat} - - - + {this.renderTxElement(tx.transaction.to, actionKey, tx.status, renderTotalEth, renderTotalEthFiat)} {this.renderTxDetails(selected, tx, blockExplorer, showAlert, currentCurrency, conversionRate)} ); @@ -329,22 +323,7 @@ export default class TransactionElement extends PureComponent { const renderTotalEthFiat = weiToFiat(totalGas, conversionRate, currentCurrency).toUpperCase(); return ( - - {this.renderTxTime()} - - - - {actionKey} - - {tx.status.toUpperCase()} - - - - {renderTotalEth} - {renderTotalEthFiat} - - - + {this.renderTxElement(tx.transaction.to, actionKey, tx.status, renderTotalEth, renderTotalEthFiat)} {this.renderTxDetails(selected, tx, blockExplorer, showAlert, currentCurrency, conversionRate)} ); From 42a0338e36d4f9138100e38598a22e278799c877 Mon Sep 17 00:00:00 2001 From: Esteban Mino Date: Thu, 14 Feb 2019 23:58:18 -0300 Subject: [PATCH 3/9] tx details refactor --- .../TransactionDetails/index.js | 91 ++----- app/components/TransactionElement/index.js | 247 +++++++++++++++--- app/components/Transactions/index.js | 6 + app/util/transactions.js | 2 + locales/en.json | 1 + 5 files changed, 255 insertions(+), 92 deletions(-) diff --git a/app/components/TransactionElement/TransactionDetails/index.js b/app/components/TransactionElement/TransactionDetails/index.js index 3a93cb07eb3..384efecd3c5 100644 --- a/app/components/TransactionElement/TransactionDetails/index.js +++ b/app/components/TransactionElement/TransactionDetails/index.js @@ -3,9 +3,7 @@ import PropTypes from 'prop-types'; import { Clipboard, TouchableOpacity, StyleSheet, Text, View } from 'react-native'; import { colors, fontStyles } from '../../../styles/common'; import { strings } from '../../../../locales/i18n'; -import { renderFromWei, weiToFiat, hexToBN, isBN, toBN, toGwei, weiToFiatNumber } from '../../../util/number'; import Icon from 'react-native-vector-icons/FontAwesome'; -import { renderFullAddress } from '../../../util/address'; const styles = StyleSheet.create({ detailRowWrapper: { @@ -81,14 +79,6 @@ const styles = StyleSheet.create({ */ export default class TransactionDetails extends PureComponent { static propTypes = { - /** - * ETH to current currency conversion rate - */ - conversionRate: PropTypes.number, - /** - * Currency code of the currently-active currency - */ - currentCurrency: PropTypes.string, /** * Object corresponding to a transaction, containing transaction object, networkId and transaction hash string */ @@ -104,7 +94,16 @@ export default class TransactionDetails extends PureComponent { /** * Action that shows the global alert */ - viewOnEtherscan: PropTypes.func.isRequired + viewOnEtherscan: PropTypes.func.isRequired, + renderFrom: PropTypes.string, + renderTo: PropTypes.string, + transactionHash: PropTypes.string, + valueLabel: PropTypes.string, + renderValue: PropTypes.string, + renderGas: PropTypes.string, + renderGasPrice: PropTypes.string, + renderTotalValue: PropTypes.string, + renderTotalValueFiat: PropTypes.string }; renderTxHash = transactionHash => { @@ -124,10 +123,7 @@ export default class TransactionDetails extends PureComponent { }; copy = async () => { - const { - transactionObject: { transactionHash } - } = this.props; - await Clipboard.setString(transactionHash); + await Clipboard.setString(this.props.transactionHash); this.props.showAlert({ isVisible: true, autodismiss: 2000, @@ -144,87 +140,58 @@ export default class TransactionDetails extends PureComponent { viewOnEtherscan = () => { const { - transactionObject: { transactionHash, networkID } + transactionObject: { networkID } } = this.props; - this.props.viewOnEtherscan(networkID, transactionHash); + this.props.viewOnEtherscan(networkID, this.props.transactionHash); }; render = () => { - const { - transactionObject: { - transaction: { gas, gasPrice, value, to, from }, - transactionHash, - transfer - }, - blockExplorer - } = this.props; - const gasBN = hexToBN(gas); - const gasPriceBN = hexToBN(gasPrice); - const amount = hexToBN(value); - const { conversionRate, currentCurrency } = this.props; - const totalGas = isBN(gasBN) && isBN(gasPriceBN) ? gasBN.mul(gasPriceBN) : toBN('0x0'); - const totalEth = isBN(amount) ? amount.add(totalGas) : totalGas; - const renderAmount = transfer - ? !transfer.amount - ? strings('transaction.value_not_available') - : transfer.amount - : renderFromWei(value) + ' ' + strings('unit.eth'); - const renderTotalEth = renderFromWei(totalEth) + ' ' + strings('unit.eth'); - const renderTotal = transfer - ? transfer.amount - ? transfer.amount + ' ' + strings('unit.divisor') + ' ' + renderTotalEth - : strings('transaction.value_not_available') - : renderTotalEth; - - const renderTotalEthFiat = weiToFiat(totalEth, conversionRate, currentCurrency).toUpperCase(); - const totalEthFiatAmount = weiToFiatNumber(totalEth, conversionRate); - const renderTotalFiat = transfer - ? transfer.amountFiat - ? totalEthFiatAmount + transfer.amountFiat + ' ' + currentCurrency.toUpperCase() - : undefined - : renderTotalEthFiat; - const renderTo = transfer ? transfer.to : !to ? strings('transactions.to_contract') : renderFullAddress(to); + const { blockExplorer } = this.props; return ( - {this.renderTxHash(transactionHash)} + {this.renderTxHash(this.props.transactionHash)} {strings('transactions.from')} - {renderFullAddress(from)} + {this.props.renderFrom} {strings('transactions.to')} - {renderTo} + {this.props.renderTo} {strings('transactions.details')} - {strings('transactions.amount')} - {renderAmount} + + {this.props.valueLabel || strings('transactions.amount')} + + {this.props.renderValue} {strings('transactions.gas_limit')} - {hexToBN(gas).toNumber()} + {this.props.renderGas} {strings('transactions.gas_price')} - {toGwei(gasPrice)} + {this.props.renderGasPrice} {strings('transactions.total')} - {renderTotal} + {this.props.renderTotalValue} - {renderTotalFiat && ( + {this.props.renderTotalValueFiat && ( - {renderTotalFiat} + + {this.props.renderTotalValueFiat} + )} - {transactionHash && + {this.props.transactionHash && blockExplorer && ( - selected ? ( + renderTxDetails = ( + selected, + tx, + renderFrom, + renderTo, + transactionHash, + renderValue, + renderGas, + renderGasPrice, + renderTotalValue, + renderTotalValueFiat, + valueLabel = undefined + ) => { + const { showAlert, blockExplorer } = this.props; + return selected ? ( ) : null; + }; /** * Renders an horizontal bar with basic tx information @@ -212,12 +245,17 @@ export default class TransactionElement extends PureComponent { * @param {string} status - Transaction status * @param {string} value - Transaction crypto value (ETH, assets ERC20 and ERC721) * @param {string} fiatValue - transaction fiat crypto value, if available + * @param {bool} contractDeployment - Whether the transaction corresponds to a contract deployment */ - renderTxElement = (addressTo, actionKey, status, value, fiatValue) => ( + renderTxElement = (addressTo, actionKey, status, value, fiatValue, contractDeployment = false) => ( {this.renderTxTime()} - + {contractDeployment ? ( + + ) : ( + + )} {actionKey} {status.toUpperCase()} @@ -233,13 +271,14 @@ export default class TransactionElement extends PureComponent { renderTransferElement = () => { const { tx, + tx: { + transaction: { gas, gasPrice } + }, conversionRate, currentCurrency, tokens, contractExchangeRates, - selected, - blockExplorer, - showAlert + selected } = this.props; const { actionKey } = this.state; const [addressTo, amount] = decodeTransferData('ERC20', tx.transaction.data); @@ -266,11 +305,25 @@ export default class TransactionElement extends PureComponent { exchangeRate ); } - const transfer = { - to: addressTo, - amount: renderTokenAmount, - amountFiat: renderTokenFiatNumber - }; + const renderFrom = tx.transaction.from; + const renderTo = addressTo; + const transactionHash = tx.transaction.hash; + const renderValue = token + ? renderFromTokenMinimalUnit(amount, token.decimals) + ' ' + token.symbol + : strings('transaction.value_not_available'); + const gasBN = hexToBN(gas); + const gasPriceBN = hexToBN(gasPrice); + const totalGas = isBN(gasBN) && isBN(gasPriceBN) ? gasBN.mul(gasPriceBN) : toBN('0x0'); + const renderTotalValue = token + ? renderValue + ' ' + strings('unit.divisor') + ' ' + renderFromWei(totalGas) + : renderFromWei(totalGas); + const renderTotalValueFiat = token + ? weiToFiatNumber(totalGas, conversionRate) + renderTokenFiatNumber + +' ' + currentCurrency.toUpperCase() + : weiToFiatNumber(totalGas, conversionRate); + + const renderGas = parseInt(gas, 16).toString(); + const renderGasPrice = toGwei(gasPrice); + return ( {this.renderTxElement( @@ -282,11 +335,77 @@ export default class TransactionElement extends PureComponent { )} {this.renderTxDetails( selected, - { ...tx, ...{ transfer } }, - blockExplorer, - showAlert, - currentCurrency, - conversionRate + tx, + renderFrom, + renderTo, + transactionHash, + renderValue, + renderGas, + renderGasPrice, + renderTotalValue, + renderTotalValueFiat + )} + + ); + }; + + renderTransferFromElement = () => { + const { + tx, + tx: { + transaction: { gas, gasPrice } + }, + selected, + collectibleContracts, + conversionRate, + currentCurrency + } = this.props; + let { actionKey } = this.state; + const [addressFrom, addressTo, tokenId] = decodeTransferData('ERC721', tx.transaction.data); + const collectible = collectibleContracts.find( + collectible => collectible.address.toLowerCase() === tx.transaction.to.toLowerCase() + ); + if (collectible) { + actionKey = strings('transactions.sent') + ' ' + collectible.name; + } + + const gasBN = hexToBN(gas); + const gasPriceBN = hexToBN(gasPrice); + const totalGas = isBN(gasBN) && isBN(gasPriceBN) ? gasBN.mul(gasPriceBN) : toBN('0x0'); + + const renderFrom = addressFrom; + const renderTo = addressTo; + const transactionHash = tx.transaction.hash; + const renderValue = '#' + tokenId + ' ' + (collectible ? collectible.symbol : undefined); + const renderGas = parseInt(gas, 16).toString(); + const renderGasPrice = toGwei(gasPrice); + + const renderTotalValue = collectible + ? renderValue + ' ' + strings('unit.divisor') + ' ' + renderFromWei(totalGas) + : renderFromWei(totalGas); + const renderTotalValueFiat = weiToFiat(totalGas, conversionRate, currentCurrency).toUpperCase(); + + return ( + + {this.renderTxElement( + addressTo, + actionKey, + tx.status, + `#${tokenId}`, + collectible ? collectible.symbol : undefined + )} + {this.renderTxDetails( + selected, + tx, + renderFrom, + renderTo, + transactionHash, + renderValue, + renderGas, + renderGasPrice, + renderTotalValue, + renderTotalValueFiat, + 'Collectible' )} ); @@ -296,35 +415,100 @@ export default class TransactionElement extends PureComponent { const { tx, tx: { - transaction: { value } + transaction: { value, gas, gasPrice } }, conversionRate, currentCurrency, - selected, - blockExplorer, - showAlert + selected } = this.props; const { actionKey } = this.state; const totalETh = hexToBN(value); const renderTotalEth = renderFromWei(totalETh) + ' ' + strings('unit.eth'); const renderTotalEthFiat = weiToFiat(totalETh, conversionRate, currentCurrency).toUpperCase(); + + const gasBN = hexToBN(gas); + const gasPriceBN = hexToBN(gasPrice); + const totalGas = isBN(gasBN) && isBN(gasPriceBN) ? gasBN.mul(gasPriceBN) : toBN('0x0'); + + const renderFrom = tx.transaction.from; + const renderTo = tx.transaction.to; + const transactionHash = tx.transaction.hash; + const renderValue = renderFromWei(value) + ' ' + strings('unit.eth'); + const renderGas = parseInt(gas, 16).toString(); + const renderGasPrice = toGwei(gasPrice); + const totalEth = isBN(value) ? value.add(totalGas) : totalGas; + const renderTotalValue = renderFromWei(totalEth) + ' ' + strings('unit.eth'); + const renderTotalValueFiat = weiToFiat(totalEth, conversionRate, currentCurrency).toUpperCase(); + return ( {this.renderTxElement(tx.transaction.to, actionKey, tx.status, renderTotalEth, renderTotalEthFiat)} - {this.renderTxDetails(selected, tx, blockExplorer, showAlert, currentCurrency, conversionRate)} + {this.renderTxDetails( + selected, + tx, + renderFrom, + renderTo, + transactionHash, + renderValue, + renderGas, + renderGasPrice, + renderTotalValue, + renderTotalValueFiat + )} ); }; - renderDeploymentElement = totalGas => { - const { tx, selected, blockExplorer, conversionRate, currentCurrency, showAlert } = this.props; + renderDeploymentElement = () => { + const { + tx, + tx: { + transaction: { value, gas, gasPrice } + }, + selected, + conversionRate, + currentCurrency + } = this.props; const { actionKey } = this.state; + const gasBN = hexToBN(gas); + const gasPriceBN = hexToBN(gasPrice); + const totalGas = isBN(gasBN) && isBN(gasPriceBN) ? gasBN.mul(gasPriceBN) : toBN('0x0'); + const renderTotalEth = renderFromWei(totalGas) + ' ' + strings('unit.eth'); const renderTotalEthFiat = weiToFiat(totalGas, conversionRate, currentCurrency).toUpperCase(); + + const renderFrom = tx.transaction.from; + const renderTo = strings('transactions.to_contract'); + const transactionHash = tx.transaction.hash; + const renderValue = renderFromWei(value) + ' ' + strings('unit.eth'); + const renderGas = parseInt(gas, 16).toString(); + const renderGasPrice = toGwei(gasPrice); + const totalEth = isBN(value) ? value.add(totalGas) : totalGas; + const renderTotalValue = renderFromWei(totalEth) + ' ' + strings('unit.eth'); + const renderTotalValueFiat = weiToFiat(totalEth, conversionRate, currentCurrency).toUpperCase(); + return ( - {this.renderTxElement(tx.transaction.to, actionKey, tx.status, renderTotalEth, renderTotalEthFiat)} - {this.renderTxDetails(selected, tx, blockExplorer, showAlert, currentCurrency, conversionRate)} + {this.renderTxElement( + tx.transaction.to, + actionKey, + tx.status, + renderTotalEth, + renderTotalEthFiat, + true + )} + {this.renderTxDetails( + selected, + tx, + renderFrom, + renderTo, + transactionHash, + renderValue, + renderGas, + renderGasPrice, + renderTotalValue, + renderTotalValueFiat + )} ); }; @@ -345,6 +529,9 @@ export default class TransactionElement extends PureComponent { case strings('transactions.sent_tokens'): transactionElement = this.renderTransferElement(totalGas); break; + case strings('transactions.sent_collectible'): + transactionElement = this.renderTransferFromElement(totalGas); + break; case strings('transactions.contract_deploy'): transactionElement = this.renderDeploymentElement(totalGas); break; diff --git a/app/components/Transactions/index.js b/app/components/Transactions/index.js index d878cf879e0..8ec6c6c88ae 100644 --- a/app/components/Transactions/index.js +++ b/app/components/Transactions/index.js @@ -54,6 +54,10 @@ class Transactions extends PureComponent { /* navigation object required to push new views */ navigation: PropTypes.object, + /** + * An array that represents the user collectible contracts + */ + collectibleContracts: PropTypes.object, /** * An array that represents the user tokens */ @@ -186,6 +190,7 @@ class Transactions extends PureComponent { onPressItem={this.toggleDetailsView} blockExplorer tokens={this.props.tokens} + collectibleContracts={this.props.collectibleContracts} contractExchangeRates={this.props.contractExchangeRates} conversionRate={this.props.conversionRate} currentCurrency={this.props.currentCurrency} @@ -230,6 +235,7 @@ const mapStateToProps = state => ({ tokens[token.address] = token; return tokens; }, {}), + collectibleContracts: state.engine.backgroundState.AssetsController.collectibleContracts, contractExchangeRates: state.engine.backgroundState.TokenRatesController.contractExchangeRates, conversionRate: state.engine.backgroundState.CurrencyRateController.conversionRate, currentCurrency: state.engine.backgroundState.CurrencyRateController.currentCurrency diff --git a/app/util/transactions.js b/app/util/transactions.js index 620a4dbc040..b37a53c6939 100644 --- a/app/util/transactions.js +++ b/app/util/transactions.js @@ -210,6 +210,8 @@ export async function getActionKey(tx, selectedAddress) { switch (actionKey) { case SEND_TOKEN_ACTION_KEY: return strings('transactions.sent_tokens'); + case TRANSFER_FROM_ACTION_KEY: + return strings('transactions.sent_collectible'); case SEND_ETHER_ACTION_KEY: return incoming ? selfSent diff --git a/locales/en.json b/locales/en.json index fe619743924..b6a525acabf 100644 --- a/locales/en.json +++ b/locales/en.json @@ -358,6 +358,7 @@ "self_sent_ether": "Sent Yourself Ether", "received_ether": "Received Ether", "sent_tokens": "Sent Tokens", + "sent_collectible": "Sent Collectible", "sent": "Sent", "contract_deploy": "Contract Deployment", "to_contract": "New Contract", From 89fdec1c2319a645df985aa72f2f1ddc389583c2 Mon Sep 17 00:00:00 2001 From: Esteban MIno Date: Fri, 15 Feb 2019 18:51:47 -0300 Subject: [PATCH 4/9] stable --- .../TransactionDetails/index.js | 44 ++-- app/components/TransactionElement/index.js | 243 +++++++----------- package-lock.json | 235 +++++++++-------- 3 files changed, 245 insertions(+), 277 deletions(-) diff --git a/app/components/TransactionElement/TransactionDetails/index.js b/app/components/TransactionElement/TransactionDetails/index.js index 384efecd3c5..9ac2d005f7b 100644 --- a/app/components/TransactionElement/TransactionDetails/index.js +++ b/app/components/TransactionElement/TransactionDetails/index.js @@ -95,15 +95,7 @@ export default class TransactionDetails extends PureComponent { * Action that shows the global alert */ viewOnEtherscan: PropTypes.func.isRequired, - renderFrom: PropTypes.string, - renderTo: PropTypes.string, - transactionHash: PropTypes.string, - valueLabel: PropTypes.string, - renderValue: PropTypes.string, - renderGas: PropTypes.string, - renderGasPrice: PropTypes.string, - renderTotalValue: PropTypes.string, - renderTotalValueFiat: PropTypes.string + transactionDetails: PropTypes.object }; renderTxHash = transactionHash => { @@ -123,7 +115,7 @@ export default class TransactionDetails extends PureComponent { }; copy = async () => { - await Clipboard.setString(this.props.transactionHash); + await Clipboard.setString(this.props.transactionDetails.transactionHash); this.props.showAlert({ isVisible: true, autodismiss: 2000, @@ -142,7 +134,7 @@ export default class TransactionDetails extends PureComponent { const { transactionObject: { networkID } } = this.props; - this.props.viewOnEtherscan(networkID, this.props.transactionHash); + this.props.viewOnEtherscan(networkID, this.props.transactionDetails.transactionHash); }; render = () => { @@ -150,48 +142,56 @@ export default class TransactionDetails extends PureComponent { return ( - {this.renderTxHash(this.props.transactionHash)} + {this.renderTxHash(this.props.transactionDetails.transactionHash)} {strings('transactions.from')} - {this.props.renderFrom} + {this.props.transactionDetails.renderFrom} {strings('transactions.to')} - {this.props.renderTo} + {this.props.transactionDetails.renderTo} {strings('transactions.details')} - {this.props.valueLabel || strings('transactions.amount')} + {this.props.transactionDetails.valueLabel || strings('transactions.amount')} + + + {this.props.transactionDetails.renderValue} - {this.props.renderValue} {strings('transactions.gas_limit')} - {this.props.renderGas} + + {this.props.transactionDetails.renderGas} + {strings('transactions.gas_price')} - {this.props.renderGasPrice} + + {this.props.transactionDetails.renderGasPrice} + {strings('transactions.total')} - {this.props.renderTotalValue} + + {this.props.transactionDetails.renderTotalValue} + - {this.props.renderTotalValueFiat && ( + {this.props.transactionDetails.renderTotalValueFiat && ( - {this.props.renderTotalValueFiat} + {this.props.transactionDetails.renderTotalValueFiat} )} - {this.props.transactionHash && + {this.props.transactionDetails.transactionHash && blockExplorer && ( { + renderTxDetails = (selected, tx, transactionDetails) => { const { showAlert, blockExplorer } = this.props; return selected ? ( ) : null; }; @@ -242,31 +222,35 @@ export default class TransactionElement extends PureComponent { * * @param {string} addressTo - Transaction to address * @param {string} actionKey - Transaction action key - * @param {string} status - Transaction status * @param {string} value - Transaction crypto value (ETH, assets ERC20 and ERC721) * @param {string} fiatValue - transaction fiat crypto value, if available * @param {bool} contractDeployment - Whether the transaction corresponds to a contract deployment */ - renderTxElement = (addressTo, actionKey, status, value, fiatValue, contractDeployment = false) => ( - - {this.renderTxTime()} - - {contractDeployment ? ( - - ) : ( - - )} - - {actionKey} - {status.toUpperCase()} - - - {value} - {fiatValue} + renderTxElement = (addressTo, actionKey, value, fiatValue, contractDeployment = false) => { + const { + tx: { status } + } = this.props; + return ( + + {this.renderTxTime()} + + {contractDeployment ? ( + + ) : ( + + )} + + {actionKey} + {status.toUpperCase()} + + + {value} + {fiatValue} + - - ); + ); + }; renderTransferElement = () => { const { @@ -305,46 +289,36 @@ export default class TransactionElement extends PureComponent { exchangeRate ); } - const renderFrom = tx.transaction.from; - const renderTo = addressTo; - const transactionHash = tx.transaction.hash; - const renderValue = token - ? renderFromTokenMinimalUnit(amount, token.decimals) + ' ' + token.symbol - : strings('transaction.value_not_available'); const gasBN = hexToBN(gas); const gasPriceBN = hexToBN(gasPrice); const totalGas = isBN(gasBN) && isBN(gasPriceBN) ? gasBN.mul(gasPriceBN) : toBN('0x0'); - const renderTotalValue = token - ? renderValue + ' ' + strings('unit.divisor') + ' ' + renderFromWei(totalGas) - : renderFromWei(totalGas); - const renderTotalValueFiat = token - ? weiToFiatNumber(totalGas, conversionRate) + renderTokenFiatNumber + +' ' + currentCurrency.toUpperCase() - : weiToFiatNumber(totalGas, conversionRate); - - const renderGas = parseInt(gas, 16).toString(); - const renderGasPrice = toGwei(gasPrice); + const renderToken = token + ? renderFromTokenMinimalUnit(amount, token.decimals) + ' ' + token.symbol + : strings('transaction.value_not_available'); + const totalFiatNumber = renderTokenFiatNumber + ? weiToFiatNumber(totalGas, conversionRate) + renderTokenFiatNumber + : undefined; + const transactionDetails = { + renderFrom: tx.transaction.from, + renderTo: addressTo, + transactionHash: tx.transaction.hash, + renderValue: renderToken, + renderGas: parseInt(gas, 16).toString(), + renderGasPrice: toGwei(gasPrice), + renderTotalValue: + renderToken + ' ' + strings('unit.divisor') + ' ' + renderFromWei(totalGas) + ' ' + strings('unit.eth'), + renderTotalValueFiat: totalFiatNumber ? totalFiatNumber + ' ' + currentCurrency.toUpperCase() : undefined + }; return ( {this.renderTxElement( addressTo, renderActionKey, - tx.status, !renderTokenAmount ? strings('transaction.value_not_available') : renderTokenAmount, renderTokenFiatAmount )} - {this.renderTxDetails( - selected, - tx, - renderFrom, - renderTo, - transactionHash, - renderValue, - renderGas, - renderGasPrice, - renderTotalValue, - renderTotalValueFiat - )} + {this.renderTxDetails(selected, tx, transactionDetails)} ); }; @@ -356,9 +330,7 @@ export default class TransactionElement extends PureComponent { transaction: { gas, gasPrice } }, selected, - collectibleContracts, - conversionRate, - currentCurrency + collectibleContracts } = this.props; let { actionKey } = this.state; const [addressFrom, addressTo, tokenId] = decodeTransferData('ERC721', tx.transaction.data); @@ -372,41 +344,35 @@ export default class TransactionElement extends PureComponent { const gasBN = hexToBN(gas); const gasPriceBN = hexToBN(gasPrice); const totalGas = isBN(gasBN) && isBN(gasPriceBN) ? gasBN.mul(gasPriceBN) : toBN('0x0'); + const renderCollectible = '#' + tokenId + ' ' + (collectible ? collectible.symbol : undefined); - const renderFrom = addressFrom; - const renderTo = addressTo; - const transactionHash = tx.transaction.hash; - const renderValue = '#' + tokenId + ' ' + (collectible ? collectible.symbol : undefined); - const renderGas = parseInt(gas, 16).toString(); - const renderGasPrice = toGwei(gasPrice); - - const renderTotalValue = collectible - ? renderValue + ' ' + strings('unit.divisor') + ' ' + renderFromWei(totalGas) - : renderFromWei(totalGas); - const renderTotalValueFiat = weiToFiat(totalGas, conversionRate, currentCurrency).toUpperCase(); + const transactionDetails = { + renderFrom: addressFrom, + renderTo: addressTo, + transactionHash: tx.transaction.hash, + renderValue: renderCollectible, + renderGas: parseInt(gas, 16).toString(), + renderGasPrice: toGwei(gasPrice), + renderTotalValue: + renderCollectible + + ' ' + + strings('unit.divisor') + + ' ' + + renderFromWei(totalGas) + + ' ' + + strings('unit.eth'), + renderTotalValueFiat: undefined + }; return ( {this.renderTxElement( addressTo, actionKey, - tx.status, `#${tokenId}`, collectible ? collectible.symbol : undefined )} - {this.renderTxDetails( - selected, - tx, - renderFrom, - renderTo, - transactionHash, - renderValue, - renderGas, - renderGasPrice, - renderTotalValue, - renderTotalValueFiat, - 'Collectible' - )} + {this.renderTxDetails(selected, tx, transactionDetails)} ); }; @@ -422,39 +388,30 @@ export default class TransactionElement extends PureComponent { selected } = this.props; const { actionKey } = this.state; - const totalETh = hexToBN(value); - const renderTotalEth = renderFromWei(totalETh) + ' ' + strings('unit.eth'); - const renderTotalEthFiat = weiToFiat(totalETh, conversionRate, currentCurrency).toUpperCase(); + const totalEth = hexToBN(value); + const renderTotalEth = renderFromWei(totalEth) + ' ' + strings('unit.eth'); + const renderTotalEthFiat = weiToFiat(totalEth, conversionRate, currentCurrency).toUpperCase(); const gasBN = hexToBN(gas); const gasPriceBN = hexToBN(gasPrice); const totalGas = isBN(gasBN) && isBN(gasPriceBN) ? gasBN.mul(gasPriceBN) : toBN('0x0'); + const totalValue = isBN(totalEth) ? totalEth.add(totalGas) : totalGas; - const renderFrom = tx.transaction.from; - const renderTo = tx.transaction.to; - const transactionHash = tx.transaction.hash; - const renderValue = renderFromWei(value) + ' ' + strings('unit.eth'); - const renderGas = parseInt(gas, 16).toString(); - const renderGasPrice = toGwei(gasPrice); - const totalEth = isBN(value) ? value.add(totalGas) : totalGas; - const renderTotalValue = renderFromWei(totalEth) + ' ' + strings('unit.eth'); - const renderTotalValueFiat = weiToFiat(totalEth, conversionRate, currentCurrency).toUpperCase(); + const transactionDetails = { + renderFrom: tx.transaction.from, + renderTo: tx.transaction.to, + transactionHash: tx.transaction.hash, + renderValue: renderFromWei(value) + ' ' + strings('unit.eth'), + renderGas: parseInt(gas, 16).toString(), + renderGasPrice: toGwei(gasPrice), + renderTotalValue: renderFromWei(totalValue) + ' ' + strings('unit.eth'), + renderTotalValueFiat: weiToFiat(totalValue, conversionRate, currentCurrency).toUpperCase() + }; return ( - {this.renderTxElement(tx.transaction.to, actionKey, tx.status, renderTotalEth, renderTotalEthFiat)} - {this.renderTxDetails( - selected, - tx, - renderFrom, - renderTo, - transactionHash, - renderValue, - renderGas, - renderGasPrice, - renderTotalValue, - renderTotalValueFiat - )} + {this.renderTxElement(tx.transaction.to, actionKey, renderTotalEth, renderTotalEthFiat)} + {this.renderTxDetails(selected, tx, transactionDetails)} ); }; @@ -476,39 +433,23 @@ export default class TransactionElement extends PureComponent { const renderTotalEth = renderFromWei(totalGas) + ' ' + strings('unit.eth'); const renderTotalEthFiat = weiToFiat(totalGas, conversionRate, currentCurrency).toUpperCase(); - - const renderFrom = tx.transaction.from; - const renderTo = strings('transactions.to_contract'); - const transactionHash = tx.transaction.hash; - const renderValue = renderFromWei(value) + ' ' + strings('unit.eth'); - const renderGas = parseInt(gas, 16).toString(); - const renderGasPrice = toGwei(gasPrice); const totalEth = isBN(value) ? value.add(totalGas) : totalGas; - const renderTotalValue = renderFromWei(totalEth) + ' ' + strings('unit.eth'); - const renderTotalValueFiat = weiToFiat(totalEth, conversionRate, currentCurrency).toUpperCase(); + + const transactionDetails = { + renderFrom: tx.transaction.from, + renderTo: strings('transactions.to_contract'), + transactionHash: tx.transaction.hash, + renderValue: renderFromWei(value) + ' ' + strings('unit.eth'), + renderGas: parseInt(gas, 16).toString(), + renderGasPrice: toGwei(gasPrice), + renderTotalValue: renderFromWei(totalEth) + ' ' + strings('unit.eth'), + renderTotalValueFiat: weiToFiat(totalEth, conversionRate, currentCurrency).toUpperCase() + }; return ( - {this.renderTxElement( - tx.transaction.to, - actionKey, - tx.status, - renderTotalEth, - renderTotalEthFiat, - true - )} - {this.renderTxDetails( - selected, - tx, - renderFrom, - renderTo, - transactionHash, - renderValue, - renderGas, - renderGasPrice, - renderTotalValue, - renderTotalValueFiat - )} + {this.renderTxElement(tx.transaction.to, actionKey, renderTotalEth, renderTotalEthFiat, true)} + {this.renderTxDetails(selected, tx, transactionDetails)} ); }; diff --git a/package-lock.json b/package-lock.json index b2031e0541c..eacd1625eb9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2408,14 +2408,6 @@ "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==" }, - "backoff": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/backoff/-/backoff-2.5.0.tgz", - "integrity": "sha1-9hbtqdPktmuMp/ynn2lXIsX44m8=", - "requires": { - "precond": "0.2" - } - }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", @@ -5108,8 +5100,17 @@ "resolved": "https://registry.npmjs.org/eth-sig-util/-/eth-sig-util-1.4.2.tgz", "integrity": "sha1-jZWCAsftuq6Dlwf7pvCf8ydgYhA=", "requires": { - "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git#d84a96796079c8595a0c78accd1e7709f2277215", "ethereumjs-util": "^5.1.1" + }, + "dependencies": { + "ethereumjs-abi": { + "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#d84a96796079c8595a0c78accd1e7709f2277215", + "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git#d84a96796079c8595a0c78accd1e7709f2277215", + "requires": { + "bn.js": "^4.10.0", + "ethereumjs-util": "^5.0.0" + } + } } }, "ethereumjs-abi": { @@ -5237,8 +5238,17 @@ "resolved": "https://registry.npmjs.org/eth-sig-util/-/eth-sig-util-1.4.2.tgz", "integrity": "sha1-jZWCAsftuq6Dlwf7pvCf8ydgYhA=", "requires": { - "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git#d84a96796079c8595a0c78accd1e7709f2277215", "ethereumjs-util": "^5.1.1" + }, + "dependencies": { + "ethereumjs-abi": { + "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#d84a96796079c8595a0c78accd1e7709f2277215", + "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git#d84a96796079c8595a0c78accd1e7709f2277215", + "requires": { + "bn.js": "^4.10.0", + "ethereumjs-util": "^5.0.0" + } + } } }, "ethereumjs-abi": { @@ -6074,7 +6084,8 @@ }, "ansi-regex": { "version": "2.1.1", - "bundled": true + "bundled": true, + "optional": true }, "aproba": { "version": "1.2.0", @@ -6092,11 +6103,13 @@ }, "balanced-match": { "version": "1.0.0", - "bundled": true + "bundled": true, + "optional": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, + "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -6109,15 +6122,18 @@ }, "code-point-at": { "version": "1.1.0", - "bundled": true + "bundled": true, + "optional": true }, "concat-map": { "version": "0.0.1", - "bundled": true + "bundled": true, + "optional": true }, "console-control-strings": { "version": "1.1.0", - "bundled": true + "bundled": true, + "optional": true }, "core-util-is": { "version": "1.0.2", @@ -6220,7 +6236,8 @@ }, "inherits": { "version": "2.0.3", - "bundled": true + "bundled": true, + "optional": true }, "ini": { "version": "1.3.5", @@ -6230,6 +6247,7 @@ "is-fullwidth-code-point": { "version": "1.0.0", "bundled": true, + "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -6242,17 +6260,20 @@ "minimatch": { "version": "3.0.4", "bundled": true, + "optional": true, "requires": { "brace-expansion": "^1.1.7" } }, "minimist": { "version": "0.0.8", - "bundled": true + "bundled": true, + "optional": true }, "minipass": { "version": "2.3.5", "bundled": true, + "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -6269,6 +6290,7 @@ "mkdirp": { "version": "0.5.1", "bundled": true, + "optional": true, "requires": { "minimist": "0.0.8" } @@ -6341,7 +6363,8 @@ }, "number-is-nan": { "version": "1.0.1", - "bundled": true + "bundled": true, + "optional": true }, "object-assign": { "version": "4.1.1", @@ -6351,6 +6374,7 @@ "once": { "version": "1.4.0", "bundled": true, + "optional": true, "requires": { "wrappy": "1" } @@ -6426,7 +6450,8 @@ }, "safe-buffer": { "version": "5.1.2", - "bundled": true + "bundled": true, + "optional": true }, "safer-buffer": { "version": "2.1.2", @@ -6456,6 +6481,7 @@ "string-width": { "version": "1.0.2", "bundled": true, + "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -6473,6 +6499,7 @@ "strip-ansi": { "version": "3.0.1", "bundled": true, + "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -6511,11 +6538,13 @@ }, "wrappy": { "version": "1.0.2", - "bundled": true + "bundled": true, + "optional": true }, "yallist": { "version": "3.0.3", - "bundled": true + "bundled": true, + "optional": true } } }, @@ -6561,7 +6590,6 @@ "requires": { "await-semaphore": "^0.1.3", "eth-block-tracker": "^4.1.0", - "eth-contract-metadata": "github:estebanmino/eth-contract-metadata#e307359ca9ea6be4ded6ac58ac7e16f192ae4e2a", "eth-json-rpc-infura": "^3.1.2", "eth-keyring-controller": "^4.0.0", "eth-phishing-detect": "^1.1.13", @@ -6577,8 +6605,86 @@ "percentile": "^1.2.1", "single-call-balance-checker-abi": "^1.0.0", "uuid": "^3.3.2", - "web3": "^0.20.7", - "web3-provider-engine": "github:metamask/provider-engine#e91367bc2c2535fbf7add06244d9d4ec98620042" + "web3": "^0.20.7" + }, + "dependencies": { + "eth-contract-metadata": { + "version": "github:estebanmino/eth-contract-metadata#e307359ca9ea6be4ded6ac58ac7e16f192ae4e2a", + "from": "github:estebanmino/eth-contract-metadata#e307359ca9ea6be4ded6ac58ac7e16f192ae4e2a" + }, + "ethereumjs-abi": { + "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#d84a96796079c8595a0c78accd1e7709f2277215", + "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git", + "requires": { + "bn.js": "^4.10.0", + "ethereumjs-util": "^5.0.0" + } + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "web3-provider-engine": { + "version": "github:metamask/provider-engine#e91367bc2c2535fbf7add06244d9d4ec98620042", + "from": "github:metamask/provider-engine#e91367bc2c2535fbf7add06244d9d4ec98620042", + "requires": { + "async": "^2.5.0", + "backoff": "^2.5.0", + "clone": "^2.0.0", + "cross-fetch": "^2.1.0", + "eth-block-tracker": "^3.0.0", + "eth-json-rpc-infura": "^3.1.0", + "eth-sig-util": "^1.4.2", + "ethereumjs-block": "^1.2.2", + "ethereumjs-tx": "^1.2.0", + "ethereumjs-util": "^5.1.5", + "ethereumjs-vm": "^2.3.4", + "json-rpc-error": "^2.0.0", + "json-stable-stringify": "^1.0.1", + "promise-to-callback": "^1.0.0", + "readable-stream": "^2.2.9", + "request": "^2.85.0", + "semaphore": "^1.0.3", + "ws": "^5.1.1", + "xhr": "^2.2.0", + "xtend": "^4.0.1" + }, + "dependencies": { + "eth-block-tracker": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/eth-block-tracker/-/eth-block-tracker-3.0.1.tgz", + "integrity": "sha512-WUVxWLuhMmsfenfZvFO5sbl1qFY2IqUlw/FPVmjjdElpqLsZtSG+wPe9Dz7W/sB6e80HgFKknOmKk2eNlznHug==", + "requires": { + "eth-query": "^2.1.0", + "ethereumjs-tx": "^1.3.3", + "ethereumjs-util": "^5.1.3", + "ethjs-util": "^0.1.3", + "json-rpc-engine": "^3.6.0", + "pify": "^2.3.0", + "tape": "^4.6.3" + } + }, + "eth-sig-util": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/eth-sig-util/-/eth-sig-util-1.4.2.tgz", + "integrity": "sha1-jZWCAsftuq6Dlwf7pvCf8ydgYhA=", + "requires": { + "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git", + "ethereumjs-util": "^5.1.1" + } + } + } + } } }, "gauge": { @@ -11869,11 +11975,6 @@ "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=" }, - "precond": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/precond/-/precond-0.2.3.tgz", - "integrity": "sha1-qpWRvKokkj8eD0hJ0kD0fvwQdaw=" - }, "prelude-ls": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", @@ -15582,7 +15683,6 @@ "resolved": "https://registry.npmjs.org/web3/-/web3-0.20.7.tgz", "integrity": "sha512-VU6/DSUX93d1fCzBz7WP/SGCQizO1rKZi4Px9j/3yRyfssHyFcZamMw2/sj4E8TlfMXONvZLoforR8B4bRoyTQ==", "requires": { - "bignumber.js": "git+https://github.com/frozeman/bignumber.js-nolookahead.git#57692b3ecfc98bbdd6b3a516cb2353652ea49934", "crypto-js": "^3.1.4", "utf8": "^2.1.1", "xhr2-cookies": "^1.1.0", @@ -15591,80 +15691,7 @@ "dependencies": { "bignumber.js": { "version": "git+https://github.com/frozeman/bignumber.js-nolookahead.git#57692b3ecfc98bbdd6b3a516cb2353652ea49934", - "from": "git+https://github.com/frozeman/bignumber.js-nolookahead.git" - } - } - }, - "web3-provider-engine": { - "version": "github:metamask/provider-engine#e91367bc2c2535fbf7add06244d9d4ec98620042", - "from": "github:metamask/provider-engine#feature/getaccounts-payload", - "requires": { - "async": "^2.5.0", - "backoff": "^2.5.0", - "clone": "^2.0.0", - "cross-fetch": "^2.1.0", - "eth-block-tracker": "^3.0.0", - "eth-json-rpc-infura": "^3.1.0", - "eth-sig-util": "^1.4.2", - "ethereumjs-block": "^1.2.2", - "ethereumjs-tx": "^1.2.0", - "ethereumjs-util": "^5.1.5", - "ethereumjs-vm": "^2.3.4", - "json-rpc-error": "^2.0.0", - "json-stable-stringify": "^1.0.1", - "promise-to-callback": "^1.0.0", - "readable-stream": "^2.2.9", - "request": "^2.85.0", - "semaphore": "^1.0.3", - "ws": "^5.1.1", - "xhr": "^2.2.0", - "xtend": "^4.0.1" - }, - "dependencies": { - "eth-block-tracker": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/eth-block-tracker/-/eth-block-tracker-3.0.1.tgz", - "integrity": "sha512-WUVxWLuhMmsfenfZvFO5sbl1qFY2IqUlw/FPVmjjdElpqLsZtSG+wPe9Dz7W/sB6e80HgFKknOmKk2eNlznHug==", - "requires": { - "eth-query": "^2.1.0", - "ethereumjs-tx": "^1.3.3", - "ethereumjs-util": "^5.1.3", - "ethjs-util": "^0.1.3", - "json-rpc-engine": "^3.6.0", - "pify": "^2.3.0", - "tape": "^4.6.3" - } - }, - "eth-sig-util": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/eth-sig-util/-/eth-sig-util-1.4.2.tgz", - "integrity": "sha1-jZWCAsftuq6Dlwf7pvCf8ydgYhA=", - "requires": { - "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git#d84a96796079c8595a0c78accd1e7709f2277215", - "ethereumjs-util": "^5.1.1" - } - }, - "ethereumjs-abi": { - "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#d84a96796079c8595a0c78accd1e7709f2277215", - "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git", - "requires": { - "bn.js": "^4.10.0", - "ethereumjs-util": "^5.0.0" - } - }, - "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } + "from": "git+https://github.com/frozeman/bignumber.js-nolookahead.git#57692b3ecfc98bbdd6b3a516cb2353652ea49934" } } }, From 6ecc9b7bedf4e2c252fd7f3cfe5e2804e5534c26 Mon Sep 17 00:00:00 2001 From: Esteban MIno Date: Fri, 15 Feb 2019 19:31:34 -0300 Subject: [PATCH 5/9] more refactor --- app/components/TransactionElement/index.js | 149 ++++++++++----------- app/components/Transactions/index.js | 2 +- 2 files changed, 72 insertions(+), 79 deletions(-) diff --git a/app/components/TransactionElement/index.js b/app/components/TransactionElement/index.js index 0b4c7ea888e..9f3ce4bc673 100644 --- a/app/components/TransactionElement/index.js +++ b/app/components/TransactionElement/index.js @@ -21,6 +21,7 @@ import { toChecksumAddress } from 'ethereumjs-util'; import Identicon from '../Identicon'; import { getActionKey, decodeTransferData } from '../../util/transactions'; import TransactionDetails from './TransactionDetails'; +import { renderFullAddress } from '../../util/address'; const styles = StyleSheet.create({ row: { @@ -220,16 +221,13 @@ export default class TransactionElement extends PureComponent { /** * Renders an horizontal bar with basic tx information * - * @param {string} addressTo - Transaction to address - * @param {string} actionKey - Transaction action key - * @param {string} value - Transaction crypto value (ETH, assets ERC20 and ERC721) - * @param {string} fiatValue - transaction fiat crypto value, if available - * @param {bool} contractDeployment - Whether the transaction corresponds to a contract deployment + * @param {object} transactionElement - Transaction information to render, containing addressTo, actionKey, value, fiatValue, contractDeployment */ - renderTxElement = (addressTo, actionKey, value, fiatValue, contractDeployment = false) => { + renderTxElement = transactionElement => { const { tx: { status } } = this.props; + const { addressTo, actionKey, value, fiatValue, contractDeployment = false } = transactionElement; return ( {this.renderTxTime()} @@ -254,20 +252,18 @@ export default class TransactionElement extends PureComponent { renderTransferElement = () => { const { - tx, tx: { - transaction: { gas, gasPrice } + transaction: { gas, gasPrice, to, data, hash, from } }, conversionRate, currentCurrency, tokens, - contractExchangeRates, - selected + contractExchangeRates } = this.props; const { actionKey } = this.state; - const [addressTo, amount] = decodeTransferData('ERC20', tx.transaction.data); - const userHasToken = toChecksumAddress(tx.transaction.to) in tokens; - const token = userHasToken ? tokens[toChecksumAddress(tx.transaction.to)] : null; + const [addressTo, amount] = decodeTransferData('ERC20', data); + const userHasToken = toChecksumAddress(to) in tokens; + const token = userHasToken ? tokens[toChecksumAddress(to)] : null; const renderActionKey = token ? strings('transactions.sent') + ' ' + token.symbol : actionKey; const renderTokenAmount = token ? renderFromTokenMinimalUnit(amount, token.decimals) + ' ' + token.symbol @@ -298,10 +294,11 @@ export default class TransactionElement extends PureComponent { const totalFiatNumber = renderTokenFiatNumber ? weiToFiatNumber(totalGas, conversionRate) + renderTokenFiatNumber : undefined; + const transactionDetails = { - renderFrom: tx.transaction.from, - renderTo: addressTo, - transactionHash: tx.transaction.hash, + renderFrom: renderFullAddress(from), + renderTo: renderFullAddress(addressTo), + transactionHash: hash, renderValue: renderToken, renderGas: parseInt(gas, 16).toString(), renderGasPrice: toGwei(gasPrice), @@ -310,32 +307,27 @@ export default class TransactionElement extends PureComponent { renderTotalValueFiat: totalFiatNumber ? totalFiatNumber + ' ' + currentCurrency.toUpperCase() : undefined }; - return ( - - {this.renderTxElement( - addressTo, - renderActionKey, - !renderTokenAmount ? strings('transaction.value_not_available') : renderTokenAmount, - renderTokenFiatAmount - )} - {this.renderTxDetails(selected, tx, transactionDetails)} - - ); + const transactionElement = { + addressTo, + actionKey: renderActionKey, + value: !renderTokenAmount ? strings('transaction.value_not_available') : renderTokenAmount, + fiatValue: renderTokenFiatAmount + }; + + return [transactionElement, transactionDetails]; }; renderTransferFromElement = () => { const { - tx, tx: { - transaction: { gas, gasPrice } + transaction: { gas, gasPrice, data, to, hash } }, - selected, collectibleContracts } = this.props; let { actionKey } = this.state; - const [addressFrom, addressTo, tokenId] = decodeTransferData('ERC721', tx.transaction.data); + const [addressFrom, addressTo, tokenId] = decodeTransferData('ERC721', data); const collectible = collectibleContracts.find( - collectible => collectible.address.toLowerCase() === tx.transaction.to.toLowerCase() + collectible => collectible.address.toLowerCase() === to.toLowerCase() ); if (collectible) { actionKey = strings('transactions.sent') + ' ' + collectible.name; @@ -347,9 +339,9 @@ export default class TransactionElement extends PureComponent { const renderCollectible = '#' + tokenId + ' ' + (collectible ? collectible.symbol : undefined); const transactionDetails = { - renderFrom: addressFrom, - renderTo: addressTo, - transactionHash: tx.transaction.hash, + renderFrom: renderFullAddress(addressFrom), + renderTo: renderFullAddress(addressTo), + transactionHash: hash, renderValue: renderCollectible, renderGas: parseInt(gas, 16).toString(), renderGasPrice: toGwei(gasPrice), @@ -364,28 +356,23 @@ export default class TransactionElement extends PureComponent { renderTotalValueFiat: undefined }; - return ( - - {this.renderTxElement( - addressTo, - actionKey, - `#${tokenId}`, - collectible ? collectible.symbol : undefined - )} - {this.renderTxDetails(selected, tx, transactionDetails)} - - ); + const transactionElement = { + addressTo, + actionKey, + value: `#${tokenId}`, + fiatValue: collectible ? collectible.symbol : undefined + }; + + return [transactionElement, transactionDetails]; }; renderConfirmElement = () => { const { - tx, tx: { - transaction: { value, gas, gasPrice } + transaction: { value, gas, gasPrice, from, to, hash } }, conversionRate, - currentCurrency, - selected + currentCurrency } = this.props; const { actionKey } = this.state; const totalEth = hexToBN(value); @@ -398,9 +385,9 @@ export default class TransactionElement extends PureComponent { const totalValue = isBN(totalEth) ? totalEth.add(totalGas) : totalGas; const transactionDetails = { - renderFrom: tx.transaction.from, - renderTo: tx.transaction.to, - transactionHash: tx.transaction.hash, + renderFrom: renderFullAddress(from), + renderTo: renderFullAddress(to), + transactionHash: hash, renderValue: renderFromWei(value) + ' ' + strings('unit.eth'), renderGas: parseInt(gas, 16).toString(), renderGasPrice: toGwei(gasPrice), @@ -408,21 +395,21 @@ export default class TransactionElement extends PureComponent { renderTotalValueFiat: weiToFiat(totalValue, conversionRate, currentCurrency).toUpperCase() }; - return ( - - {this.renderTxElement(tx.transaction.to, actionKey, renderTotalEth, renderTotalEthFiat)} - {this.renderTxDetails(selected, tx, transactionDetails)} - - ); + const transactionElement = { + addressTo: to, + actionKey, + value: renderTotalEth, + fiatValue: renderTotalEthFiat + }; + + return [transactionElement, transactionDetails]; }; renderDeploymentElement = () => { const { - tx, tx: { - transaction: { value, gas, gasPrice } + transaction: { value, gas, gasPrice, to, from, hash } }, - selected, conversionRate, currentCurrency } = this.props; @@ -435,10 +422,17 @@ export default class TransactionElement extends PureComponent { const renderTotalEthFiat = weiToFiat(totalGas, conversionRate, currentCurrency).toUpperCase(); const totalEth = isBN(value) ? value.add(totalGas) : totalGas; + const transactionElement = { + addressTo: to, + actionKey, + value: renderTotalEth, + fiatValue: renderTotalEthFiat, + contractDeployment: true + }; const transactionDetails = { - renderFrom: tx.transaction.from, + renderFrom: renderFullAddress(from), renderTo: strings('transactions.to_contract'), - transactionHash: tx.transaction.hash, + transactionHash: hash, renderValue: renderFromWei(value) + ' ' + strings('unit.eth'), renderGas: parseInt(gas, 16).toString(), renderGasPrice: toGwei(gasPrice), @@ -446,38 +440,34 @@ export default class TransactionElement extends PureComponent { renderTotalValueFiat: weiToFiat(totalEth, conversionRate, currentCurrency).toUpperCase() }; - return ( - - {this.renderTxElement(tx.transaction.to, actionKey, renderTotalEth, renderTotalEthFiat, true)} - {this.renderTxDetails(selected, tx, transactionDetails)} - - ); + return [transactionElement, transactionDetails]; }; render = () => { const { tx: { transaction: { gas, gasPrice } - } + }, + selected, + tx } = this.props; const { actionKey } = this.state; - let transactionElement; const gasBN = hexToBN(gas); const gasPriceBN = hexToBN(gasPrice); const totalGas = isBN(gasBN) && isBN(gasPriceBN) ? gasBN.mul(gasPriceBN) : toBN('0x0'); - + let transactionElement, transactionDetails; switch (actionKey) { case strings('transactions.sent_tokens'): - transactionElement = this.renderTransferElement(totalGas); + [transactionElement, transactionDetails] = this.renderTransferElement(totalGas); break; case strings('transactions.sent_collectible'): - transactionElement = this.renderTransferFromElement(totalGas); + [transactionElement, transactionDetails] = this.renderTransferFromElement(totalGas); break; case strings('transactions.contract_deploy'): - transactionElement = this.renderDeploymentElement(totalGas); + [transactionElement, transactionDetails] = this.renderDeploymentElement(totalGas); break; default: - transactionElement = this.renderConfirmElement(totalGas); + [transactionElement, transactionDetails] = this.renderConfirmElement(totalGas); } return ( @@ -485,7 +475,10 @@ export default class TransactionElement extends PureComponent { style={styles.row} onPress={this.onPressItem} // eslint-disable-line react/jsx-no-bind > - {transactionElement} + + {this.renderTxElement(transactionElement)} + {this.renderTxDetails(selected, tx, transactionDetails)} + ); }; diff --git a/app/components/Transactions/index.js b/app/components/Transactions/index.js index 8ec6c6c88ae..e653fa98bcc 100644 --- a/app/components/Transactions/index.js +++ b/app/components/Transactions/index.js @@ -57,7 +57,7 @@ class Transactions extends PureComponent { /** * An array that represents the user collectible contracts */ - collectibleContracts: PropTypes.object, + collectibleContracts: PropTypes.array, /** * An array that represents the user tokens */ From 2c6f429fff477496c9e79cfc2eaf663a59331fa6 Mon Sep 17 00:00:00 2001 From: Esteban MIno Date: Fri, 15 Feb 2019 21:07:06 -0300 Subject: [PATCH 6/9] renderable gasprice --- app/components/TransactionElement/index.js | 10 +++++----- app/util/number.js | 14 ++++++++++++++ 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/app/components/TransactionElement/index.js b/app/components/TransactionElement/index.js index 9f3ce4bc673..e0427543f9d 100644 --- a/app/components/TransactionElement/index.js +++ b/app/components/TransactionElement/index.js @@ -14,7 +14,7 @@ import { toBN, isBN, balanceToFiatNumber, - toGwei, + renderToGwei, weiToFiatNumber } from '../../util/number'; import { toChecksumAddress } from 'ethereumjs-util'; @@ -301,7 +301,7 @@ export default class TransactionElement extends PureComponent { transactionHash: hash, renderValue: renderToken, renderGas: parseInt(gas, 16).toString(), - renderGasPrice: toGwei(gasPrice), + renderGasPrice: renderToGwei(gasPrice), renderTotalValue: renderToken + ' ' + strings('unit.divisor') + ' ' + renderFromWei(totalGas) + ' ' + strings('unit.eth'), renderTotalValueFiat: totalFiatNumber ? totalFiatNumber + ' ' + currentCurrency.toUpperCase() : undefined @@ -344,7 +344,7 @@ export default class TransactionElement extends PureComponent { transactionHash: hash, renderValue: renderCollectible, renderGas: parseInt(gas, 16).toString(), - renderGasPrice: toGwei(gasPrice), + renderGasPrice: renderToGwei(gasPrice), renderTotalValue: renderCollectible + ' ' + @@ -390,7 +390,7 @@ export default class TransactionElement extends PureComponent { transactionHash: hash, renderValue: renderFromWei(value) + ' ' + strings('unit.eth'), renderGas: parseInt(gas, 16).toString(), - renderGasPrice: toGwei(gasPrice), + renderGasPrice: renderToGwei(gasPrice), renderTotalValue: renderFromWei(totalValue) + ' ' + strings('unit.eth'), renderTotalValueFiat: weiToFiat(totalValue, conversionRate, currentCurrency).toUpperCase() }; @@ -435,7 +435,7 @@ export default class TransactionElement extends PureComponent { transactionHash: hash, renderValue: renderFromWei(value) + ' ' + strings('unit.eth'), renderGas: parseInt(gas, 16).toString(), - renderGasPrice: toGwei(gasPrice), + renderGasPrice: renderToGwei(gasPrice), renderTotalValue: renderFromWei(totalEth) + ' ' + strings('unit.eth'), renderTotalValueFiat: weiToFiat(totalEth, conversionRate, currentCurrency).toUpperCase() }; diff --git a/app/util/number.js b/app/util/number.js index ab6dd2feb01..30d57372794 100644 --- a/app/util/number.js +++ b/app/util/number.js @@ -205,6 +205,20 @@ export function toGwei(value, unit = 'ether') { return fromWei(value, unit) * 1000000000; } +/** + * Converts some unit to Gwei and return it in render format + * + * @param {number|string|BN} value - Value to convert + * @param {string} unit - Unit to convert from, ether by default + * @returns {string} - String instance containing the renderable number + */ +export function renderToGwei(value, unit = 'ether') { + const gwei = fromWei(value, unit) * 1000000000; + let gweiFixed = parseFloat(Math.round(gwei)); + gweiFixed = isNaN(gweiFixed) ? 0 : gweiFixed; + return gweiFixed; +} + /** * Converts wei expressed as a BN instance into a human-readable fiat string * From 47b12bdaee2c1b9804b62f3524ed446666cbe87c Mon Sep 17 00:00:00 2001 From: Esteban MIno Date: Fri, 15 Feb 2019 21:16:56 -0300 Subject: [PATCH 7/9] render hash --- app/components/TransactionElement/index.js | 26 +++++++++++++--------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/app/components/TransactionElement/index.js b/app/components/TransactionElement/index.js index e0427543f9d..3c083ab53b6 100644 --- a/app/components/TransactionElement/index.js +++ b/app/components/TransactionElement/index.js @@ -253,7 +253,8 @@ export default class TransactionElement extends PureComponent { renderTransferElement = () => { const { tx: { - transaction: { gas, gasPrice, to, data, hash, from } + transaction: { gas, gasPrice, to, data, from }, + transactionHash }, conversionRate, currentCurrency, @@ -298,7 +299,7 @@ export default class TransactionElement extends PureComponent { const transactionDetails = { renderFrom: renderFullAddress(from), renderTo: renderFullAddress(addressTo), - transactionHash: hash, + transactionHash, renderValue: renderToken, renderGas: parseInt(gas, 16).toString(), renderGasPrice: renderToGwei(gasPrice), @@ -320,7 +321,8 @@ export default class TransactionElement extends PureComponent { renderTransferFromElement = () => { const { tx: { - transaction: { gas, gasPrice, data, to, hash } + transaction: { gas, gasPrice, data, to }, + transactionHash }, collectibleContracts } = this.props; @@ -336,12 +338,13 @@ export default class TransactionElement extends PureComponent { const gasBN = hexToBN(gas); const gasPriceBN = hexToBN(gasPrice); const totalGas = isBN(gasBN) && isBN(gasPriceBN) ? gasBN.mul(gasPriceBN) : toBN('0x0'); - const renderCollectible = '#' + tokenId + ' ' + (collectible ? collectible.symbol : undefined); + const renderCollectible = + strings('unit.token_id') + tokenId + ' ' + (collectible ? collectible.symbol : undefined); const transactionDetails = { renderFrom: renderFullAddress(addressFrom), renderTo: renderFullAddress(addressTo), - transactionHash: hash, + transactionHash, renderValue: renderCollectible, renderGas: parseInt(gas, 16).toString(), renderGasPrice: renderToGwei(gasPrice), @@ -359,7 +362,7 @@ export default class TransactionElement extends PureComponent { const transactionElement = { addressTo, actionKey, - value: `#${tokenId}`, + value: `${strings('unit.token_id')}${tokenId}`, fiatValue: collectible ? collectible.symbol : undefined }; @@ -369,7 +372,8 @@ export default class TransactionElement extends PureComponent { renderConfirmElement = () => { const { tx: { - transaction: { value, gas, gasPrice, from, to, hash } + transaction: { value, gas, gasPrice, from, to }, + transactionHash }, conversionRate, currentCurrency @@ -387,7 +391,7 @@ export default class TransactionElement extends PureComponent { const transactionDetails = { renderFrom: renderFullAddress(from), renderTo: renderFullAddress(to), - transactionHash: hash, + transactionHash, renderValue: renderFromWei(value) + ' ' + strings('unit.eth'), renderGas: parseInt(gas, 16).toString(), renderGasPrice: renderToGwei(gasPrice), @@ -408,7 +412,8 @@ export default class TransactionElement extends PureComponent { renderDeploymentElement = () => { const { tx: { - transaction: { value, gas, gasPrice, to, from, hash } + transaction: { value, gas, gasPrice, to, from }, + transactionHash }, conversionRate, currentCurrency @@ -432,7 +437,7 @@ export default class TransactionElement extends PureComponent { const transactionDetails = { renderFrom: renderFullAddress(from), renderTo: strings('transactions.to_contract'), - transactionHash: hash, + transactionHash, renderValue: renderFromWei(value) + ' ' + strings('unit.eth'), renderGas: parseInt(gas, 16).toString(), renderGasPrice: renderToGwei(gasPrice), @@ -469,7 +474,6 @@ export default class TransactionElement extends PureComponent { default: [transactionElement, transactionDetails] = this.renderConfirmElement(totalGas); } - return ( Date: Fri, 15 Feb 2019 21:25:31 -0300 Subject: [PATCH 8/9] snapshots --- .../TransactionElement/TransactionDetails/index.js | 3 +++ .../TransactionDetails/index.test.js | 11 ++++++++++- app/components/TransactionElement/index.js | 5 +++-- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/app/components/TransactionElement/TransactionDetails/index.js b/app/components/TransactionElement/TransactionDetails/index.js index 9ac2d005f7b..745301e1dc2 100644 --- a/app/components/TransactionElement/TransactionDetails/index.js +++ b/app/components/TransactionElement/TransactionDetails/index.js @@ -95,6 +95,9 @@ export default class TransactionDetails extends PureComponent { * Action that shows the global alert */ viewOnEtherscan: PropTypes.func.isRequired, + /** + * Object with information to render + */ transactionDetails: PropTypes.object }; diff --git a/app/components/TransactionElement/TransactionDetails/index.test.js b/app/components/TransactionElement/TransactionDetails/index.test.js index 8ba2484667c..9adb426bbdc 100644 --- a/app/components/TransactionElement/TransactionDetails/index.test.js +++ b/app/components/TransactionElement/TransactionDetails/index.test.js @@ -21,9 +21,18 @@ describe('TransactionDetails', () => { const wrapper = shallow( , { context: { store: mockStore(initialState) } diff --git a/app/components/TransactionElement/index.js b/app/components/TransactionElement/index.js index 3c083ab53b6..1b5f4f7735f 100644 --- a/app/components/TransactionElement/index.js +++ b/app/components/TransactionElement/index.js @@ -338,8 +338,9 @@ export default class TransactionElement extends PureComponent { const gasBN = hexToBN(gas); const gasPriceBN = hexToBN(gasPrice); const totalGas = isBN(gasBN) && isBN(gasPriceBN) ? gasBN.mul(gasPriceBN) : toBN('0x0'); - const renderCollectible = - strings('unit.token_id') + tokenId + ' ' + (collectible ? collectible.symbol : undefined); + const renderCollectible = collectible + ? strings('unit.token_id') + tokenId + ' ' + collectible.symbol + : strings('unit.token_id') + tokenId; const transactionDetails = { renderFrom: renderFullAddress(addressFrom), From a1a05b1bc1210b3713194c117ced794888519eba Mon Sep 17 00:00:00 2001 From: Esteban MIno Date: Fri, 15 Feb 2019 22:31:19 -0300 Subject: [PATCH 9/9] fadein --- app/components/TransactionElement/index.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/components/TransactionElement/index.js b/app/components/TransactionElement/index.js index 1b5f4f7735f..bbd254ccf46 100644 --- a/app/components/TransactionElement/index.js +++ b/app/components/TransactionElement/index.js @@ -22,6 +22,7 @@ import Identicon from '../Identicon'; import { getActionKey, decodeTransferData } from '../../util/transactions'; import TransactionDetails from './TransactionDetails'; import { renderFullAddress } from '../../util/address'; +import FadeIn from 'react-native-fade-in-image'; const styles = StyleSheet.create({ row: { @@ -233,7 +234,9 @@ export default class TransactionElement extends PureComponent { {this.renderTxTime()} {contractDeployment ? ( - + + + ) : ( )}