diff options
Diffstat (limited to 'ui/app/components/pending-tx.js')
-rw-r--r-- | ui/app/components/pending-tx.js | 569 |
1 files changed, 0 insertions, 569 deletions
diff --git a/ui/app/components/pending-tx.js b/ui/app/components/pending-tx.js deleted file mode 100644 index a8fac4c28..000000000 --- a/ui/app/components/pending-tx.js +++ /dev/null @@ -1,569 +0,0 @@ -const Component = require('react').Component -const { connect } = require('react-redux') -const h = require('react-hyperscript') -const abi = require('human-standard-token-abi') -const abiDecoder = require('abi-decoder') -abiDecoder.addABI(abi) -const inherits = require('util').inherits -const actions = require('../actions') -const clone = require('clone') -const FiatValue = require('./fiat-value') -const Identicon = require('./identicon') - -const ethUtil = require('ethereumjs-util') -const BN = ethUtil.BN -const hexToBn = require('../../../app/scripts/lib/hex-to-bn') -const util = require('../util') -const { conversionUtil, addCurrencies } = require('../conversion-util') - -const MIN_GAS_PRICE_GWEI_BN = new BN(1) -const GWEI_FACTOR = new BN(1e9) -const MIN_GAS_PRICE_BN = MIN_GAS_PRICE_GWEI_BN.mul(GWEI_FACTOR) - -// Next: create separate react components -// roughly 5 components: -// heroIcon -// numericDisplay (contains symbol + currency) -// divider -// contentBox -// actionButtons - -module.exports = connect(mapStateToProps, mapDispatchToProps)(PendingTx) - -function mapStateToProps (state) { - const { - conversionRate, - identities, - } = state.metamask - const accounts = state.metamask.accounts - const selectedAddress = state.metamask.selectedAddress || Object.keys(accounts)[0] - return { - conversionRate, - identities, - selectedAddress, - } -} - -function mapDispatchToProps (dispatch) { - return { - setCurrentCurrencyToUSD: () => dispatch(actions.setCurrentCurrency('USD')), - backToAccountDetail: address => dispatch(actions.backToAccountDetail(address)), - cancelTransaction: ({ id }) => dispatch(actions.cancelTx({ id })), - } -} - -inherits(PendingTx, Component) -function PendingTx () { - Component.call(this) - this.state = { - valid: true, - txData: null, - submitting: false, - } - this.onSubmit = this.onSubmit.bind(this) -} - -PendingTx.prototype.componentWillMount = function () { - this.props.setCurrentCurrencyToUSD() -} - -PendingTx.prototype.getAmount = function () { - const { conversionRate } = this.props - const txMeta = this.gatherTxMeta() - const txParams = txMeta.txParams || {} - const decodedData = txParams.data && abiDecoder.decodeMethod(txParams.data) - const { params = [] } = decodedData || {} - const { name, value } = params[1] || {} - const amountBn = name === '_value' - ? value - : txParams.value - - if (name === '_value') { - const token = util.getContractAtAddress(txParams.to) - token.symbol().then(symbol => console.log({symbol})) - console.log({txParams, txMeta, decodedData, token}) - const USD = conversionUtil(amountBn, { - fromNumericBase: 'hex', - toNumericBase: 'dec', - fromCurrency: 'ETH', - toCurrency: 'USD', - numberOfDecimals: 2, - fromDenomination: 'WEI', - conversionRate, - }) - const ETH = conversionUtil(amountBn, { - fromNumericBase: 'hex', - toNumericBase: 'dec', - fromCurrency: 'ETH', - toCurrency: 'ETH', - fromDenomination: 'WEI', - conversionRate, - numberOfDecimals: 6, - }) - return { - USD, - ETH, - } - } else { - const USD = conversionUtil(amountBn, { - fromNumericBase: 'hex', - toNumericBase: 'dec', - fromCurrency: 'ETH', - toCurrency: 'USD', - numberOfDecimals: 2, - fromDenomination: 'WEI', - conversionRate, - }) - const ETH = conversionUtil(amountBn, { - fromNumericBase: 'hex', - toNumericBase: 'dec', - fromCurrency: 'ETH', - toCurrency: 'ETH', - fromDenomination: 'WEI', - conversionRate, - numberOfDecimals: 6, - }) - - return { - USD, - ETH, - } - } - -} - -PendingTx.prototype.getGasFee = function () { - const { conversionRate } = this.props - const txMeta = this.gatherTxMeta() - const txParams = txMeta.txParams || {} - - // Gas - const gas = txParams.gas - const gasBn = hexToBn(gas) - - // From latest master -// const gasLimit = new BN(parseInt(blockGasLimit)) -// const safeGasLimitBN = this.bnMultiplyByFraction(gasLimit, 19, 20) -// const saferGasLimitBN = this.bnMultiplyByFraction(gasLimit, 18, 20) -// const safeGasLimit = safeGasLimitBN.toString(10) - - // Gas Price - const gasPrice = txParams.gasPrice || MIN_GAS_PRICE_BN.toString(16) - const gasPriceBn = hexToBn(gasPrice) - - const txFeeBn = gasBn.mul(gasPriceBn) - - const USD = conversionUtil(txFeeBn, { - fromNumericBase: 'BN', - toNumericBase: 'dec', - fromDenomination: 'WEI', - fromCurrency: 'ETH', - toCurrency: 'USD', - numberOfDecimals: 2, - conversionRate, - }) - const ETH = conversionUtil(txFeeBn, { - fromNumericBase: 'BN', - toNumericBase: 'dec', - fromDenomination: 'WEI', - fromCurrency: 'ETH', - toCurrency: 'ETH', - numberOfDecimals: 6, - conversionRate, - }) - - return { - USD, - ETH, - } -} - -PendingTx.prototype.getData = function () { - const { identities } = this.props - const txMeta = this.gatherTxMeta() - const txParams = txMeta.txParams || {} - const decodedData = txParams.data && abiDecoder.decodeMethod(txParams.data) - const { name, params = [] } = decodedData || {} - const { type, value } = params[0] || {} - const { USD: gasFeeInUSD, ETH: gasFeeInETH } = this.getGasFee() - const { USD: amountInUSD, ETH: amountInETH } = this.getAmount() - - const totalInUSD = addCurrencies(gasFeeInUSD, amountInUSD, { - toNumericBase: 'dec', - numberOfDecimals: 2, - }) - const totalInETH = addCurrencies(gasFeeInETH, amountInETH, { - toNumericBase: 'dec', - numberOfDecimals: 6, - }) - - if (name === 'transfer' && type === 'address') { - return { - from: { - address: txParams.from, - name: identities[txParams.from].name, - }, - to: { - address: value, - name: identities[value] ? identities[value].name : 'New Recipient', - }, - memo: txParams.memo || '', - gasFeeInUSD, - gasFeeInETH, - amountInUSD, - amountInETH, - } - } else { - return { - from: { - address: txParams.from, - name: identities[txParams.from].name, - }, - to: { - address: txParams.to, - name: identities[txParams.to] ? identities[txParams.to].name : 'New Recipient', - }, - memo: txParams.memo || '', - gasFeeInUSD, - gasFeeInETH, - amountInUSD, - amountInETH, - totalInUSD, - totalInETH, - } - } -} - -PendingTx.prototype.render = function () { - const { backToAccountDetail, selectedAddress } = this.props - const txMeta = this.gatherTxMeta() - const txParams = txMeta.txParams || {} - - // recipient check - // const isValidAddress = !txParams.to || util.isValidAddress(txParams.to) - - const { - from: { - address: fromAddress, - name: fromName, - }, - to: { - address: toAddress, - name: toName, - }, - memo, - gasFeeInUSD, - gasFeeInETH, - amountInUSD, - amountInETH, - totalInUSD, - totalInETH, - } = this.getData() - - // This is from the latest master - // It handles some of the errors that we are not currently handling - // Leaving as comments fo reference - - // const balanceBn = hexToBn(balance) - // const insufficientBalance = balanceBn.lt(maxCost) - // const buyDisabled = insufficientBalance || !this.state.valid || !isValidAddress || this.state.submitting - // const showRejectAll = props.unconfTxListLength > 1 -// const dangerousGasLimit = gasBn.gte(saferGasLimitBN) -// const gasLimitSpecified = txMeta.gasLimitSpecified - - this.inputs = [] - - return ( - h('div.flex-column.flex-grow.confirm-screen-container', { - style: { minWidth: '355px' }, - }, [ - // Main Send token Card - h('div.confirm-screen-wrapper.flex-column.flex-grow', [ - h('h3.flex-center.confirm-screen-header', [ - h('button.confirm-screen-back-button', { - onClick: () => backToAccountDetail(selectedAddress), - }, 'BACK'), - h('div.confirm-screen-title', 'Confirm Transaction'), - ]), - h('div.flex-row.flex-center.confirm-screen-identicons', [ - h('div.confirm-screen-account-wrapper', [ - h( - Identicon, - { - address: fromAddress, - diameter: 100, - }, - ), - h('span.confirm-screen-account-name', fromName), - h('span.confirm-screen-account-number', fromAddress.slice(fromAddress.length - 4)), - ]), - h('i.fa.fa-arrow-right.fa-lg'), - h('div.confirm-screen-account-wrapper', [ - h( - Identicon, - { - address: txParams.to, - diameter: 100, - }, - ), - h('span.confirm-screen-account-name', toName), - h('span.confirm-screen-account-number', toAddress.slice(toAddress.length - 4)), - ]), - ]), - - h('h3.flex-center.confirm-screen-sending-to-message', { - style: { - textAlign: 'center', - fontSize: '16px', - }, - }, [ - `You're sending to Recipient ...${toAddress.slice(toAddress.length - 4)}`, - ]), - - h('h3.flex-center.confirm-screen-send-amount', [`$${amountInUSD}`]), - h('h3.flex-center.confirm-screen-send-amount-currency', [ 'USD' ]), - h('div.flex-center.confirm-memo-wrapper', [ - h('h3.confirm-screen-send-memo', [ memo ]), - ]), - - h('div.confirm-screen-rows', [ - h('section.flex-row.flex-center.confirm-screen-row', [ - h('span.confirm-screen-label.confirm-screen-section-column', [ 'From' ]), - h('div.confirm-screen-section-column', [ - h('div.confirm-screen-row-info', fromName), - h('div.confirm-screen-row-detail', `...${fromAddress.slice(fromAddress.length - 4)}`), - ]), - ]), - - h('section.flex-row.flex-center.confirm-screen-row', [ - h('span.confirm-screen-label.confirm-screen-section-column', [ 'To' ]), - h('div.confirm-screen-section-column', [ - h('div.confirm-screen-row-info', toName), - h('div.confirm-screen-row-detail', `...${toAddress.slice(toAddress.length - 4)}`), - ]), - ]), - - h('section.flex-row.flex-center.confirm-screen-row', [ - h('span.confirm-screen-label.confirm-screen-section-column', [ 'Gas Fee' ]), - h('div.confirm-screen-section-column', [ - h('div.confirm-screen-row-info', `$${gasFeeInUSD} USD`), - - h('div.confirm-screen-row-detail', `${gasFeeInETH} ETH`), - ]), - ]), - - - h('section.flex-row.flex-center.confirm-screen-total-box ', [ - h('div.confirm-screen-section-column', [ - h('span.confirm-screen-label', [ 'Total ' ]), - h('div.confirm-screen-total-box__subtitle', [ 'Amount + Gas' ]), - ]), - - h('div.confirm-screen-section-column', [ - h('div.confirm-screen-row-info', `$${totalInUSD} USD`), - h('div.confirm-screen-row-detail', `${totalInETH} ETH`), - ]), - ]), - ]), - -// These are latest errors handling from master -// Leaving as comments as reference when we start implementing error handling -// h('style', ` -// .conf-buttons button { -// margin-left: 10px; -// text-transform: uppercase; -// } -// `), - -// txMeta.simulationFails ? -// h('.error', { -// style: { -// marginLeft: 50, -// fontSize: '0.9em', -// }, -// }, 'Transaction Error. Exception thrown in contract code.') -// : null, - -// !isValidAddress ? -// h('.error', { -// style: { -// marginLeft: 50, -// fontSize: '0.9em', -// }, -// }, 'Recipient address is invalid. Sending this transaction will result in a loss of ETH.') -// : null, - -// insufficientBalance ? -// h('span.error', { -// style: { -// marginLeft: 50, -// fontSize: '0.9em', -// }, -// }, 'Insufficient balance for transaction') -// : null, - -// // send + cancel -// h('.flex-row.flex-space-around.conf-buttons', { -// style: { -// display: 'flex', -// justifyContent: 'flex-end', -// margin: '14px 25px', -// }, -// }, [ -// h('button', { -// onClick: (event) => { -// this.resetGasFields() -// event.preventDefault() -// }, -// }, 'Reset'), - -// // Accept Button or Buy Button -// insufficientBalance ? h('button.btn-green', { onClick: props.buyEth }, 'Buy Ether') : -// h('input.confirm.btn-green', { -// type: 'submit', -// value: 'SUBMIT', -// style: { marginLeft: '10px' }, -// disabled: buyDisabled, -// }), - -// h('button.cancel.btn-red', { -// onClick: props.cancelTransaction, -// }, 'Reject'), -// ]), -// showRejectAll ? h('.flex-row.flex-space-around.conf-buttons', { -// style: { -// display: 'flex', -// justifyContent: 'flex-end', -// margin: '14px 25px', -// }, -// }, [ -// h('button.cancel.btn-red', { -// onClick: props.cancelAllTransactions, -// }, 'Reject All'), -// ]) : null, -// ]), -// ]) -// ) -// } - ]), - - h('form#pending-tx-form.flex-column.flex-center', { - onSubmit: this.onSubmit, - }, [ - // Reset Button - // h('button', { - // onClick: (event) => { - // this.resetGasFields() - // event.preventDefault() - // }, - // }, 'Reset'), - - // Accept Button - h('button.confirm-screen-confirm-button', ['CONFIRM']), - - // Cancel Button - h('div.cancel.btn-light.confirm-screen-cancel-button', { - onClick: (event) => this.cancel(event, txMeta), - }, 'CANCEL'), - ]), - ]) - ) -} - -// PendingTx.prototype.gasPriceChanged = function (newBN, valid) { -// log.info(`Gas price changed to: ${newBN.toString(10)}`) -// const txMeta = this.gatherTxMeta() -// txMeta.txParams.gasPrice = '0x' + newBN.toString('hex') -// this.setState({ -// txData: clone(txMeta), -// valid, -// }) -// } - -// PendingTx.prototype.gasLimitChanged = function (newBN, valid) { -// log.info(`Gas limit changed to ${newBN.toString(10)}`) -// const txMeta = this.gatherTxMeta() -// txMeta.txParams.gas = '0x' + newBN.toString('hex') -// this.setState({ -// txData: clone(txMeta), -// valid, -// }) -// } - -// PendingTx.prototype.resetGasFields = function () { -// log.debug(`pending-tx resetGasFields`) - -// this.inputs.forEach((hexInput) => { -// if (hexInput) { -// hexInput.setValid() -// } -// }) - -// this.setState({ -// txData: null, -// valid: true, -// }) -// } - -PendingTx.prototype.onSubmit = function (event) { - event.preventDefault() - const txMeta = this.gatherTxMeta() - const valid = this.checkValidity() - this.setState({ valid, submitting: true }) - - if (valid && this.verifyGasParams()) { - this.props.sendTransaction(txMeta, event) - } else { - this.props.dispatch(actions.displayWarning('Invalid Gas Parameters')) - this.setState({ submitting: false }) - } -} - -PendingTx.prototype.cancel = function (event, txMeta) { - event.preventDefault() - this.props.cancelTransaction(txMeta) -} - -PendingTx.prototype.checkValidity = function () { - const form = this.getFormEl() - const valid = form.checkValidity() - return valid -} - -PendingTx.prototype.getFormEl = function () { - const form = document.querySelector('form#pending-tx-form') - // Stub out form for unit tests: - if (!form) { - return { checkValidity () { return true } } - } - return form -} - -// After a customizable state value has been updated, -PendingTx.prototype.gatherTxMeta = function () { - const props = this.props - const state = this.state - const txData = clone(state.txData) || clone(props.txData) - - // log.debug(`UI has defaulted to tx meta ${JSON.stringify(txData)}`) - return txData -} - -PendingTx.prototype.verifyGasParams = function () { - // We call this in case the gas has not been modified at all - if (!this.state) { return true } - return ( - this._notZeroOrEmptyString(this.state.gas) && - this._notZeroOrEmptyString(this.state.gasPrice) - ) -} - -PendingTx.prototype._notZeroOrEmptyString = function (obj) { - return obj !== '' && obj !== '0x0' -} - -PendingTx.prototype.bnMultiplyByFraction = function (targetBN, numerator, denominator) { - const numBN = new BN(numerator) - const denomBN = new BN(denominator) - return targetBN.mul(numBN).div(denomBN) -} |