aboutsummaryrefslogtreecommitdiffstats
path: root/ui/app
diff options
context:
space:
mode:
Diffstat (limited to 'ui/app')
-rw-r--r--ui/app/components/app/gas-customization/advanced-gas-inputs/advanced-gas-inputs.component.js63
-rw-r--r--ui/app/components/app/gas-customization/gas-modal-page-container/gas-modal-page-container.container.js41
-rw-r--r--ui/app/components/app/gas-customization/gas-modal-page-container/tests/gas-modal-page-container-container.test.js23
-rw-r--r--ui/app/components/app/modals/account-details-modal.js107
-rw-r--r--ui/app/components/app/modals/account-details-modal/account-details-modal.component.js87
-rw-r--r--ui/app/components/app/modals/account-details-modal/account-details-modal.container.js27
-rw-r--r--ui/app/components/app/modals/account-details-modal/index.js1
-rw-r--r--ui/app/components/app/modals/deposit-ether-modal.js36
-rw-r--r--ui/app/components/app/modals/modal.js10
-rw-r--r--ui/app/components/app/modals/shapeshift-deposit-tx-modal.js40
-rw-r--r--ui/app/components/app/shapeshift-form.js256
-rw-r--r--ui/app/pages/confirm-token-transaction-base/confirm-token-transaction-base.container.js24
-rw-r--r--ui/app/pages/confirm-transaction-base/confirm-transaction-base.container.js81
-rw-r--r--ui/app/pages/first-time-flow/create-password/import-with-seed-phrase/import-with-seed-phrase.component.js19
-rw-r--r--ui/app/pages/first-time-flow/create-password/import-with-seed-phrase/tests/import-with-seed-phrase.component.test.js78
-rw-r--r--ui/app/pages/first-time-flow/first-time-flow.component.js2
-rw-r--r--ui/app/pages/keychains/restore-vault.js1
-rw-r--r--ui/app/selectors/confirm-transaction.js60
-rw-r--r--ui/app/store/actions.js4
19 files changed, 428 insertions, 532 deletions
diff --git a/ui/app/components/app/gas-customization/advanced-gas-inputs/advanced-gas-inputs.component.js b/ui/app/components/app/gas-customization/advanced-gas-inputs/advanced-gas-inputs.component.js
index d6c259033..d942fd150 100644
--- a/ui/app/components/app/gas-customization/advanced-gas-inputs/advanced-gas-inputs.component.js
+++ b/ui/app/components/app/gas-customization/advanced-gas-inputs/advanced-gas-inputs.component.js
@@ -8,6 +8,17 @@ export default class AdvancedTabContent extends Component {
t: PropTypes.func,
}
+ constructor (props) {
+ super(props)
+ this.state = {
+ gasPrice: this.props.customGasPrice,
+ gasLimit: this.props.customGasLimit,
+ }
+ this.changeGasPrice = debounce(this.changeGasPrice, 500)
+ this.changeGasLimit = debounce(this.changeGasLimit, 500)
+ }
+
+
static propTypes = {
updateCustomGasPrice: PropTypes.func,
updateCustomGasLimit: PropTypes.func,
@@ -20,15 +31,40 @@ export default class AdvancedTabContent extends Component {
showGasLimitInfoModal: PropTypes.func,
}
- debouncedGasLimitReset = debounce((dVal) => {
- if (dVal < 21000) {
+ componentDidUpdate (prevProps) {
+ const { customGasPrice: prevCustomGasPrice, customGasLimit: prevCustomGasLimit } = prevProps
+ const { customGasPrice, customGasLimit } = this.props
+ const { gasPrice, gasLimit } = this.state
+
+ if (customGasPrice !== prevCustomGasPrice && customGasPrice !== gasPrice) {
+ this.setState({ gasPrice: customGasPrice })
+ }
+ if (customGasLimit !== prevCustomGasLimit && customGasLimit !== gasLimit) {
+ this.setState({ gasLimit: customGasLimit })
+ }
+ }
+
+ onChangeGasLimit = (e) => {
+ this.setState({ gasLimit: e.target.value })
+ this.changeGasLimit({ target: { value: e.target.value } })
+ }
+
+ changeGasLimit = (e) => {
+ if (e.target.value < 21000) {
+ this.setState({ gasLimit: 21000 })
this.props.updateCustomGasLimit(21000)
+ } else {
+ this.props.updateCustomGasLimit(Number(e.target.value))
}
- }, 1000, { trailing: true })
+ }
+
+ onChangeGasPrice = (e) => {
+ this.setState({ gasPrice: e.target.value })
+ this.changeGasPrice({ target: { value: e.target.value } })
+ }
- onChangeGasLimit = (val) => {
- this.props.updateCustomGasLimit(val)
- this.debouncedGasLimitReset(val)
+ changeGasPrice = (e) => {
+ this.props.updateCustomGasPrice(Number(e.target.value))
}
gasInputError ({ labelKey, insufficientBalance, customPriceIsSafe, isSpeedUp, value }) {
@@ -74,7 +110,7 @@ export default class AdvancedTabContent extends Component {
})}
type="number"
value={value}
- onChange={event => onChange(Number(event.target.value))}
+ onChange={onChange}
/>
<div className={classnames('advanced-gas-inputs__gas-edit-row__input-arrows', {
'advanced-gas-inputs__gas-edit-row__input--error': isInError && errorType === 'error',
@@ -82,13 +118,13 @@ export default class AdvancedTabContent extends Component {
})}>
<div
className="advanced-gas-inputs__gas-edit-row__input-arrows__i-wrap"
- onClick={() => onChange(value + 1)}
+ onClick={() => onChange({ target: { value: value + 1 } })}
>
<i className="fa fa-sm fa-angle-up" />
</div>
<div
className="advanced-gas-inputs__gas-edit-row__input-arrows__i-wrap"
- onClick={() => onChange(Math.max(value - 1, 0))}
+ onClick={() => onChange({ target: { value: Math.max(value - 1, 0) } })}
>
<i className="fa fa-sm fa-angle-down" />
</div>
@@ -120,9 +156,6 @@ export default class AdvancedTabContent extends Component {
render () {
const {
- customGasPrice,
- updateCustomGasPrice,
- customGasLimit,
insufficientBalance,
customPriceIsSafe,
isSpeedUp,
@@ -134,8 +167,8 @@ export default class AdvancedTabContent extends Component {
<div className="advanced-gas-inputs__gas-edit-rows">
{ this.renderGasEditRow({
labelKey: 'gasPrice',
- value: customGasPrice,
- onChange: updateCustomGasPrice,
+ value: this.state.gasPrice,
+ onChange: this.onChangeGasPrice,
insufficientBalance,
customPriceIsSafe,
showGWEI: true,
@@ -144,7 +177,7 @@ export default class AdvancedTabContent extends Component {
}) }
{ this.renderGasEditRow({
labelKey: 'gasLimit',
- value: customGasLimit,
+ value: this.state.gasLimit,
onChange: this.onChangeGasLimit,
insufficientBalance,
customPriceIsSafe,
diff --git a/ui/app/components/app/gas-customization/gas-modal-page-container/gas-modal-page-container.container.js b/ui/app/components/app/gas-customization/gas-modal-page-container/gas-modal-page-container.container.js
index 9da9a2ef6..c260d6798 100644
--- a/ui/app/components/app/gas-customization/gas-modal-page-container/gas-modal-page-container.container.js
+++ b/ui/app/components/app/gas-customization/gas-modal-page-container/gas-modal-page-container.container.js
@@ -9,6 +9,7 @@ import {
hideSidebar,
updateSendAmount,
setGasTotal,
+ updateTransaction,
} from '../../../../store/actions'
import {
setCustomGasPrice,
@@ -23,9 +24,6 @@ import {
updateSendErrors,
} from '../../../../ducks/send/send.duck'
import {
- updateGasAndCalculate,
-} from '../../../../ducks/confirm-transaction/confirm-transaction.duck'
-import {
conversionRateSelector as getConversionRate,
getCurrentCurrency,
getCurrentEthBalance,
@@ -52,9 +50,6 @@ import {
getTokenBalance,
} from '../../../../pages/send/send.selectors'
import {
- submittedPendingTransactionsSelector,
-} from '../../../../selectors/transactions'
-import {
formatCurrency,
} from '../../../../helpers/utils/confirm-tx.util'
import {
@@ -77,11 +72,16 @@ import { getMaxModeOn } from '../../../../pages/send/send-content/send-amount-ro
import { calcMaxAmount } from '../../../../pages/send/send-content/send-amount-row/amount-max-button/amount-max-button.utils'
const mapStateToProps = (state, ownProps) => {
+ const { selectedAddressTxList } = state.metamask
+ const { modalState: { props: modalProps } = {} } = state.appState.modal || {}
+ const { txData = {} } = modalProps || {}
const { transaction = {} } = ownProps
+ const selectedTransaction = selectedAddressTxList.find(({ id }) => id === (transaction.id || txData.id))
+
const buttonDataLoading = getBasicGasEstimateLoadingStatus(state)
const gasEstimatesLoading = getGasEstimatesLoadingStatus(state)
- const { gasPrice: currentGasPrice, gas: currentGasLimit, value } = getTxParams(state, transaction.id)
+ const { gasPrice: currentGasPrice, gas: currentGasLimit, value } = getTxParams(state, selectedTransaction)
const customModalGasPriceInHex = getCustomGasPrice(state) || currentGasPrice
const customModalGasLimitInHex = getCustomGasLimit(state) || currentGasLimit
const customGasTotal = calcGasTotal(customModalGasLimitInHex, customModalGasPriceInHex)
@@ -118,6 +118,7 @@ const mapStateToProps = (state, ownProps) => {
conversionRate,
})
+
return {
hideBasic,
isConfirm: isConfirm(state),
@@ -151,6 +152,7 @@ const mapStateToProps = (state, ownProps) => {
transactionFee: addHexWEIsToRenderableEth('0x0', customGasTotal),
sendAmount,
},
+ transaction: txData || transaction,
isSpeedUp: transaction.status === 'submitted',
txId: transaction.id,
insufficientBalance,
@@ -179,10 +181,10 @@ const mapDispatchToProps = dispatch => {
dispatch(setGasLimit(newLimit))
dispatch(setGasPrice(newPrice))
},
- updateConfirmTxGasAndCalculate: (gasLimit, gasPrice) => {
+ updateConfirmTxGasAndCalculate: (gasLimit, gasPrice, updatedTx) => {
updateCustomGasPrice(gasPrice)
dispatch(setCustomGasLimit(addHexPrefix(gasLimit.toString(16))))
- return dispatch(updateGasAndCalculate({ gasLimit, gasPrice }))
+ return dispatch(updateTransaction(updatedTx))
},
createSpeedUpTransaction: (txId, gasPrice) => {
return dispatch(createSpeedUpTransaction(txId, gasPrice))
@@ -214,6 +216,7 @@ const mergeProps = (stateProps, dispatchProps, ownProps) => {
selectedToken,
tokenBalance,
customGasLimit,
+ transaction,
} = stateProps
const {
updateCustomGasPrice: dispatchUpdateCustomGasPrice,
@@ -234,7 +237,15 @@ const mergeProps = (stateProps, dispatchProps, ownProps) => {
...ownProps,
onSubmit: (gasLimit, gasPrice) => {
if (isConfirm) {
- dispatchUpdateConfirmTxGasAndCalculate(gasLimit, gasPrice)
+ const updatedTx = {
+ ...transaction,
+ txParams: {
+ ...transaction.txParams,
+ gas: gasLimit,
+ gasPrice,
+ },
+ }
+ dispatchUpdateConfirmTxGasAndCalculate(gasLimit, gasPrice, updatedTx)
dispatchHideModal()
} else if (isSpeedUp) {
dispatchCreateSpeedUpTransaction(txId, gasPrice)
@@ -282,12 +293,10 @@ function calcCustomGasLimit (customGasLimitInHex) {
return parseInt(customGasLimitInHex, 16)
}
-function getTxParams (state, transactionId) {
- const { confirmTransaction: { txData }, metamask: { send } } = state
- const pendingTransactions = submittedPendingTransactionsSelector(state)
- const pendingTransaction = pendingTransactions.find(({ id }) => id === transactionId)
- const { txParams: pendingTxParams } = pendingTransaction || {}
- return txData.txParams || pendingTxParams || {
+function getTxParams (state, selectedTransaction = {}) {
+ const { metamask: { send } } = state
+ const { txParams } = selectedTransaction
+ return txParams || {
from: send.from,
gas: send.gasLimit || '0x5208',
gasPrice: send.gasPrice || getFastPriceEstimateInHexWEI(state, true),
diff --git a/ui/app/components/app/gas-customization/gas-modal-page-container/tests/gas-modal-page-container-container.test.js b/ui/app/components/app/gas-customization/gas-modal-page-container/tests/gas-modal-page-container-container.test.js
index dbe61d5cf..03d254eee 100644
--- a/ui/app/components/app/gas-customization/gas-modal-page-container/tests/gas-modal-page-container-container.test.js
+++ b/ui/app/components/app/gas-customization/gas-modal-page-container/tests/gas-modal-page-container-container.test.js
@@ -63,6 +63,9 @@ describe('gas-modal-page-container container', () => {
modalState: {
props: {
hideBasic: true,
+ txData: {
+ id: 34,
+ },
},
},
},
@@ -82,6 +85,14 @@ describe('gas-modal-page-container container', () => {
provider: {
type: 'mainnet',
},
+ selectedAddressTxList: [{
+ id: 34,
+ txParams: {
+ gas: '0x1600000',
+ gasPrice: '0x3200000',
+ value: '0x640000000000000',
+ },
+ }],
},
gas: {
basicEstimates: {
@@ -152,6 +163,9 @@ describe('gas-modal-page-container container', () => {
maxModeOn: false,
selectedToken: null,
tokenBalance: '0x0',
+ transaction: {
+ id: 34,
+ },
}
const baseMockOwnProps = { transaction: { id: 34 } }
const tests = [
@@ -168,7 +182,7 @@ describe('gas-modal-page-container container', () => {
mockOwnProps: Object.assign({}, baseMockOwnProps, {
transaction: { id: 34, status: 'submitted' },
}),
- expectedResult: Object.assign({}, baseExpectedResult, { isSpeedUp: true }),
+ expectedResult: Object.assign({}, baseExpectedResult, { isSpeedUp: true, transaction: { id: 34 } }),
},
{
mockState: Object.assign({}, baseMockState, {
@@ -317,8 +331,10 @@ describe('gas-modal-page-container container', () => {
it('should dispatch a updateGasAndCalculate action with the correct props', () => {
mapDispatchToPropsObject.updateConfirmTxGasAndCalculate('ffff', 'aaaa')
assert.equal(dispatchSpy.callCount, 3)
- assert(confirmTransactionActionSpies.updateGasAndCalculate.calledOnce)
- assert.deepEqual(confirmTransactionActionSpies.updateGasAndCalculate.getCall(0).args[0], { gasLimit: 'ffff', gasPrice: 'aaaa' })
+ assert(actionSpies.setGasPrice.calledOnce)
+ assert(actionSpies.setGasLimit.calledOnce)
+ assert.equal(actionSpies.setGasLimit.getCall(0).args[0], 'ffff')
+ assert.equal(actionSpies.setGasPrice.getCall(0).args[0], 'aaaa')
})
})
@@ -337,6 +353,7 @@ describe('gas-modal-page-container container', () => {
},
isConfirm: true,
someOtherStateProp: 'baz',
+ transaction: {},
}
dispatchProps = {
updateCustomGasPrice: sinon.spy(),
diff --git a/ui/app/components/app/modals/account-details-modal.js b/ui/app/components/app/modals/account-details-modal.js
deleted file mode 100644
index 6cffc918b..000000000
--- a/ui/app/components/app/modals/account-details-modal.js
+++ /dev/null
@@ -1,107 +0,0 @@
-const Component = require('react').Component
-const PropTypes = require('prop-types')
-const h = require('react-hyperscript')
-const inherits = require('util').inherits
-const connect = require('react-redux').connect
-const actions = require('../../../store/actions')
-const AccountModalContainer = require('./account-modal-container')
-const { getSelectedIdentity, getRpcPrefsForCurrentProvider } = require('../../../selectors/selectors')
-const genAccountLink = require('../../../../lib/account-link.js')
-const QrView = require('../../ui/qr-code')
-const EditableLabel = require('../../ui/editable-label')
-
-import Button from '../../ui/button'
-
-function mapStateToProps (state) {
- return {
- network: state.metamask.network,
- selectedIdentity: getSelectedIdentity(state),
- keyrings: state.metamask.keyrings,
- rpcPrefs: getRpcPrefsForCurrentProvider(state),
- }
-}
-
-function mapDispatchToProps (dispatch) {
- return {
- // Is this supposed to be used somewhere?
- showQrView: (selected, identity) => dispatch(actions.showQrView(selected, identity)),
- showExportPrivateKeyModal: () => {
- dispatch(actions.showModal({ name: 'EXPORT_PRIVATE_KEY' }))
- },
- hideModal: () => dispatch(actions.hideModal()),
- setAccountLabel: (address, label) => dispatch(actions.setAccountLabel(address, label)),
- }
-}
-
-inherits(AccountDetailsModal, Component)
-function AccountDetailsModal () {
- Component.call(this)
-}
-
-AccountDetailsModal.contextTypes = {
- t: PropTypes.func,
-}
-
-module.exports = connect(mapStateToProps, mapDispatchToProps)(AccountDetailsModal)
-
-
-// Not yet pixel perfect todos:
- // fonts of qr-header
-
-AccountDetailsModal.prototype.render = function () {
- const {
- selectedIdentity,
- network,
- showExportPrivateKeyModal,
- setAccountLabel,
- keyrings,
- rpcPrefs,
- } = this.props
- const { name, address } = selectedIdentity
-
- const keyring = keyrings.find((kr) => {
- return kr.accounts.includes(address)
- })
-
- let exportPrivateKeyFeatureEnabled = true
- // This feature is disabled for hardware wallets
- if (keyring && keyring.type.search('Hardware') !== -1) {
- exportPrivateKeyFeatureEnabled = false
- }
-
- return h(AccountModalContainer, {}, [
- h(EditableLabel, {
- className: 'account-modal__name',
- defaultValue: name,
- onSubmit: label => setAccountLabel(address, label),
- }),
-
- h(QrView, {
- Qr: {
- data: address,
- network: network,
- },
- }),
-
- h('div.account-modal-divider'),
-
- h(Button, {
- type: 'secondary',
- className: 'account-modal__button',
- onClick: () => {
- global.platform.openWindow({ url: genAccountLink(address, network, rpcPrefs) })
- },
- }, (rpcPrefs.blockExplorerUrl
- ? this.context.t('blockExplorerView', [rpcPrefs.blockExplorerUrl.match(/^https?:\/\/(.+)/)[1]])
- : this.context.t('viewOnEtherscan'))),
-
- // Holding on redesign for Export Private Key functionality
-
- exportPrivateKeyFeatureEnabled ? h(Button, {
- type: 'secondary',
- className: 'account-modal__button',
- onClick: () => showExportPrivateKeyModal(),
- }, this.context.t('exportPrivateKey')) : null,
-
- ])
-}
diff --git a/ui/app/components/app/modals/account-details-modal/account-details-modal.component.js b/ui/app/components/app/modals/account-details-modal/account-details-modal.component.js
new file mode 100644
index 000000000..e3919edcf
--- /dev/null
+++ b/ui/app/components/app/modals/account-details-modal/account-details-modal.component.js
@@ -0,0 +1,87 @@
+import React, { Component} from 'react'
+import PropTypes from 'prop-types'
+import AccountModalContainer from '../account-modal-container'
+import genAccountLink from '../../../../../lib/account-link.js'
+import QrView from '../../../ui/qr-code'
+import EditableLabel from '../../../ui/editable-label'
+import Button from '../../../ui/button'
+
+export default class AccountDetailsModal extends Component {
+ static propTypes = {
+ selectedIdentity: PropTypes.object,
+ network: PropTypes.string,
+ showExportPrivateKeyModal: PropTypes.func,
+ setAccountLabel: PropTypes.func,
+ keyrings: PropTypes.array,
+ rpcPrefs: PropTypes.object,
+ }
+
+ static contextTypes = {
+ t: PropTypes.func,
+ }
+
+ render () {
+ const {
+ selectedIdentity,
+ network,
+ showExportPrivateKeyModal,
+ setAccountLabel,
+ keyrings,
+ rpcPrefs,
+ } = this.props
+ const { name, address } = selectedIdentity
+
+ const keyring = keyrings.find((kr) => {
+ return kr.accounts.includes(address)
+ })
+
+ let exportPrivateKeyFeatureEnabled = true
+ // This feature is disabled for hardware wallets
+ if (keyring && keyring.type.search('Hardware') !== -1) {
+ exportPrivateKeyFeatureEnabled = false
+ }
+
+ return (
+ <AccountModalContainer>
+ <EditableLabel
+ className="account-modal__name"
+ defaultValue={name}
+ onSubmit={label => setAccountLabel(address, label)}
+ />
+
+ <QrView
+ Qr={{
+ data: address,
+ network: network,
+ }}
+ />
+
+ <div className="account-modal-divider"/>
+
+ <Button
+ type="secondary"
+ className="account-modal__button"
+ onClick={() => {
+ global.platform.openWindow({ url: genAccountLink(address, network, rpcPrefs) })
+ }}
+ >
+ {rpcPrefs.blockExplorerUrl
+ ? this.context.t('blockExplorerView', [rpcPrefs.blockExplorerUrl.match(/^https?:\/\/(.+)/)[1]])
+ : this.context.t('viewOnEtherscan')
+ }
+ </Button>
+
+ {exportPrivateKeyFeatureEnabled
+ ? <Button
+ type="secondary"
+ className="account-modal__button"
+ onClick={() => showExportPrivateKeyModal()}
+ >
+ {this.context.t('exportPrivateKey')}
+ </Button>
+ : null
+ }
+ </AccountModalContainer>
+ )
+ }
+}
diff --git a/ui/app/components/app/modals/account-details-modal/account-details-modal.container.js b/ui/app/components/app/modals/account-details-modal/account-details-modal.container.js
new file mode 100644
index 000000000..4b2283ced
--- /dev/null
+++ b/ui/app/components/app/modals/account-details-modal/account-details-modal.container.js
@@ -0,0 +1,27 @@
+import { connect } from 'react-redux'
+import actions from '../../../../store/actions'
+import { getSelectedIdentity, getRpcPrefsForCurrentProvider } from '../../../../selectors/selectors'
+import AccountDetailsModal from './account-details-modal.component'
+
+const mapStateToProps = (state) => {
+ return {
+ network: state.metamask.network,
+ selectedIdentity: getSelectedIdentity(state),
+ keyrings: state.metamask.keyrings,
+ rpcPrefs: getRpcPrefsForCurrentProvider(state),
+ }
+}
+
+const mapDispatchToProps = (dispatch) => {
+ return {
+ // Is this supposed to be used somewhere?
+ showQrView: (selected, identity) => dispatch(actions.showQrView(selected, identity)),
+ showExportPrivateKeyModal: () => {
+ dispatch(actions.showModal({ name: 'EXPORT_PRIVATE_KEY' }))
+ },
+ hideModal: () => dispatch(actions.hideModal()),
+ setAccountLabel: (address, label) => dispatch(actions.setAccountLabel(address, label)),
+ }
+}
+
+export default connect(mapStateToProps, mapDispatchToProps)(AccountDetailsModal)
diff --git a/ui/app/components/app/modals/account-details-modal/index.js b/ui/app/components/app/modals/account-details-modal/index.js
new file mode 100644
index 000000000..433f4d170
--- /dev/null
+++ b/ui/app/components/app/modals/account-details-modal/index.js
@@ -0,0 +1 @@
+export { default } from './account-details-modal.container'
diff --git a/ui/app/components/app/modals/deposit-ether-modal.js b/ui/app/components/app/modals/deposit-ether-modal.js
index f56069d65..20c4d018c 100644
--- a/ui/app/components/app/modals/deposit-ether-modal.js
+++ b/ui/app/components/app/modals/deposit-ether-modal.js
@@ -5,7 +5,6 @@ const inherits = require('util').inherits
const connect = require('react-redux').connect
const actions = require('../../../store/actions')
const { getNetworkDisplayName } = require('../../../../../app/scripts/controllers/network/util')
-const ShapeshiftForm = require('../shapeshift-form')
import Button from '../../ui/button'
@@ -13,8 +12,6 @@ let DIRECT_DEPOSIT_ROW_TITLE
let DIRECT_DEPOSIT_ROW_TEXT
let WYRE_ROW_TITLE
let WYRE_ROW_TEXT
-let SHAPESHIFT_ROW_TITLE
-let SHAPESHIFT_ROW_TEXT
let FAUCET_ROW_TITLE
let COINSWITCH_ROW_TITLE
let COINSWITCH_ROW_TEXT
@@ -56,15 +53,9 @@ function DepositEtherModal (_, context) {
DIRECT_DEPOSIT_ROW_TEXT = context.t('directDepositEtherExplainer')
WYRE_ROW_TITLE = context.t('buyWithWyre')
WYRE_ROW_TEXT = context.t('buyWithWyreDescription')
- SHAPESHIFT_ROW_TITLE = context.t('depositShapeShift')
- SHAPESHIFT_ROW_TEXT = context.t('depositShapeShiftExplainer')
FAUCET_ROW_TITLE = context.t('testFaucet')
COINSWITCH_ROW_TITLE = context.t('buyCoinSwitch')
COINSWITCH_ROW_TEXT = context.t('buyCoinSwitchExplainer')
-
- this.state = {
- buyingWithShapeshift: false,
- }
}
DepositEtherModal.contextTypes = {
@@ -131,7 +122,6 @@ DepositEtherModal.prototype.renderRow = function ({
DepositEtherModal.prototype.render = function () {
const { network, toWyre, toCoinSwitch, address, toFaucet } = this.props
- const { buyingWithShapeshift } = this.state
const isTestNetwork = ['3', '4', '5', '42'].find(n => n === network)
const networkName = getNetworkDisplayName(network)
@@ -148,7 +138,6 @@ DepositEtherModal.prototype.render = function () {
h('div.page-container__header-close', {
onClick: () => {
- this.setState({ buyingWithShapeshift: false })
this.props.hideWarning()
this.props.hideModal()
},
@@ -168,7 +157,6 @@ DepositEtherModal.prototype.render = function () {
text: DIRECT_DEPOSIT_ROW_TEXT,
buttonLabel: this.context.t('viewAccount'),
onButtonClick: () => this.goToAccountDetailsModal(),
- hide: buyingWithShapeshift,
}),
this.renderRow({
@@ -177,7 +165,7 @@ DepositEtherModal.prototype.render = function () {
text: this.facuetRowText(networkName),
buttonLabel: this.context.t('getEther'),
onButtonClick: () => toFaucet(network),
- hide: !isTestNetwork || buyingWithShapeshift,
+ hide: !isTestNetwork,
}),
this.renderRow({
@@ -191,7 +179,7 @@ DepositEtherModal.prototype.render = function () {
text: WYRE_ROW_TEXT,
buttonLabel: this.context.t('continueToWyre'),
onButtonClick: () => toWyre(address),
- hide: isTestNetwork || buyingWithShapeshift,
+ hide: isTestNetwork,
}),
this.renderRow({
@@ -205,29 +193,9 @@ DepositEtherModal.prototype.render = function () {
text: COINSWITCH_ROW_TEXT,
buttonLabel: this.context.t('continueToCoinSwitch'),
onButtonClick: () => toCoinSwitch(address),
- hide: isTestNetwork || buyingWithShapeshift,
- }),
-
- this.renderRow({
- logo: h('div.deposit-ether-modal__logo', {
- style: {
- backgroundImage: 'url(\'./images/shapeshift logo.png\')',
- },
- }),
- title: SHAPESHIFT_ROW_TITLE,
- text: SHAPESHIFT_ROW_TEXT,
- buttonLabel: this.context.t('shapeshiftBuy'),
- onButtonClick: () => this.setState({ buyingWithShapeshift: true }),
hide: isTestNetwork,
- hideButton: buyingWithShapeshift,
- hideTitle: buyingWithShapeshift,
- onBackClick: () => this.setState({ buyingWithShapeshift: false }),
- showBackButton: this.state.buyingWithShapeshift,
- className: buyingWithShapeshift && 'deposit-ether-modal__buy-row__shapeshift-buy',
}),
- buyingWithShapeshift && h(ShapeshiftForm),
-
]),
]),
diff --git a/ui/app/components/app/modals/modal.js b/ui/app/components/app/modals/modal.js
index 717f623af..394367c46 100644
--- a/ui/app/components/app/modals/modal.js
+++ b/ui/app/components/app/modals/modal.js
@@ -12,11 +12,10 @@ const { ENVIRONMENT_TYPE_POPUP } = require('../../../../../app/scripts/lib/enums
// Modal Components
const BuyOptions = require('./buy-options-modal')
const DepositEtherModal = require('./deposit-ether-modal')
-const AccountDetailsModal = require('./account-details-modal')
+import AccountDetailsModal from './account-details-modal'
const EditAccountNameModal = require('./edit-account-name-modal')
const ExportPrivateKeyModal = require('./export-private-key-modal')
const NewAccountModal = require('./new-account-modal')
-const ShapeshiftDepositTxModal = require('./shapeshift-deposit-tx-modal.js')
const HideTokenConfirmationModal = require('./hide-token-confirmation-modal')
const NotifcationModal = require('./notification-modal')
const QRScanner = require('./qr-scanner')
@@ -181,13 +180,6 @@ const MODALS = {
...accountModalStyle,
},
- SHAPESHIFT_DEPOSIT_TX: {
- contents: [
- h(ShapeshiftDepositTxModal),
- ],
- ...accountModalStyle,
- },
-
HIDE_TOKEN_CONFIRMATION: {
contents: [
h(HideTokenConfirmationModal, {}, []),
diff --git a/ui/app/components/app/modals/shapeshift-deposit-tx-modal.js b/ui/app/components/app/modals/shapeshift-deposit-tx-modal.js
deleted file mode 100644
index ada9430f7..000000000
--- a/ui/app/components/app/modals/shapeshift-deposit-tx-modal.js
+++ /dev/null
@@ -1,40 +0,0 @@
-const Component = require('react').Component
-const h = require('react-hyperscript')
-const inherits = require('util').inherits
-const connect = require('react-redux').connect
-const actions = require('../../../store/actions')
-const QrView = require('../../ui/qr-code')
-const AccountModalContainer = require('./account-modal-container')
-
-function mapStateToProps (state) {
- return {
- Qr: state.appState.modal.modalState.props.Qr,
- }
-}
-
-function mapDispatchToProps (dispatch) {
- return {
- hideModal: () => {
- dispatch(actions.hideModal())
- },
- }
-}
-
-inherits(ShapeshiftDepositTxModal, Component)
-function ShapeshiftDepositTxModal () {
- Component.call(this)
-
-}
-
-module.exports = connect(mapStateToProps, mapDispatchToProps)(ShapeshiftDepositTxModal)
-
-ShapeshiftDepositTxModal.prototype.render = function () {
- const { Qr } = this.props
-
- return h(AccountModalContainer, {
- }, [
- h('div', {}, [
- h(QrView, {key: 'qr', Qr}),
- ]),
- ])
-}
diff --git a/ui/app/components/app/shapeshift-form.js b/ui/app/components/app/shapeshift-form.js
deleted file mode 100644
index 34a6f3acd..000000000
--- a/ui/app/components/app/shapeshift-form.js
+++ /dev/null
@@ -1,256 +0,0 @@
-const h = require('react-hyperscript')
-const inherits = require('util').inherits
-const PropTypes = require('prop-types')
-const Component = require('react').Component
-const connect = require('react-redux').connect
-const classnames = require('classnames')
-const qrcode = require('qrcode-generator')
-const { shapeShiftSubview, pairUpdate, buyWithShapeShift } = require('../../store/actions')
-const { isValidAddress } = require('../../helpers/utils/util')
-const SimpleDropdown = require('./dropdowns/simple-dropdown')
-
-import Button from '../ui/button'
-
-function mapStateToProps (state) {
- const {
- coinOptions,
- tokenExchangeRates,
- selectedAddress,
- } = state.metamask
- const { warning } = state.appState
-
- return {
- coinOptions,
- tokenExchangeRates,
- selectedAddress,
- warning,
- }
-}
-
-function mapDispatchToProps (dispatch) {
- return {
- shapeShiftSubview: () => dispatch(shapeShiftSubview()),
- pairUpdate: coin => dispatch(pairUpdate(coin)),
- buyWithShapeShift: data => dispatch(buyWithShapeShift(data)),
- }
-}
-
-ShapeshiftForm.contextTypes = {
- t: PropTypes.func,
-}
-
-module.exports = connect(mapStateToProps, mapDispatchToProps)(ShapeshiftForm)
-
-
-inherits(ShapeshiftForm, Component)
-function ShapeshiftForm () {
- Component.call(this)
-
- this.state = {
- depositCoin: 'btc',
- refundAddress: '',
- showQrCode: false,
- depositAddress: '',
- errorMessage: '',
- isLoading: false,
- bought: false,
- }
-}
-
-ShapeshiftForm.prototype.getCoinPair = function () {
- return `${this.state.depositCoin.toUpperCase()}_ETH`
-}
-
-ShapeshiftForm.prototype.componentWillMount = function () {
- this.props.shapeShiftSubview()
-}
-
-ShapeshiftForm.prototype.onCoinChange = function (coin) {
- this.setState({
- depositCoin: coin,
- errorMessage: '',
- })
- this.props.pairUpdate(coin)
-}
-
-ShapeshiftForm.prototype.onBuyWithShapeShift = function () {
- this.setState({
- isLoading: true,
- showQrCode: true,
- })
-
- const {
- buyWithShapeShift,
- selectedAddress: withdrawal,
- } = this.props
- const {
- refundAddress: returnAddress,
- depositCoin,
- } = this.state
- const pair = `${depositCoin}_eth`
- const data = {
- withdrawal,
- pair,
- returnAddress,
- // Public api key
- 'apiKey': '803d1f5df2ed1b1476e4b9e6bcd089e34d8874595dda6a23b67d93c56ea9cc2445e98a6748b219b2b6ad654d9f075f1f1db139abfa93158c04e825db122c14b6',
- }
-
- if (isValidAddress(withdrawal)) {
- buyWithShapeShift(data)
- .then(d => this.setState({
- showQrCode: true,
- depositAddress: d.deposit,
- isLoading: false,
- }))
- .catch(() => this.setState({
- showQrCode: false,
- errorMessage: this.context.t('invalidRequest'),
- isLoading: false,
- }))
- }
-}
-
-ShapeshiftForm.prototype.renderMetadata = function (label, value) {
- return h('div', {className: 'shapeshift-form__metadata-wrapper'}, [
-
- h('div.shapeshift-form__metadata-label', {}, [
- h('span', `${label}:`),
- ]),
-
- h('div.shapeshift-form__metadata-value', {}, [
- h('span', value),
- ]),
-
- ])
-}
-
-ShapeshiftForm.prototype.renderMarketInfo = function () {
- const { tokenExchangeRates } = this.props
- const {
- limit,
- rate,
- minimum,
- } = tokenExchangeRates[this.getCoinPair()] || {}
-
- return h('div.shapeshift-form__metadata', {}, [
-
- this.renderMetadata(this.context.t('status'), limit ? this.context.t('available') : this.context.t('unavailable')),
- this.renderMetadata(this.context.t('limit'), limit),
- this.renderMetadata(this.context.t('exchangeRate'), rate),
- this.renderMetadata(this.context.t('min'), minimum),
-
- ])
-}
-
-ShapeshiftForm.prototype.renderQrCode = function () {
- const { depositAddress, isLoading, depositCoin } = this.state
- const qrImage = qrcode(4, 'M')
- qrImage.addData(depositAddress)
- qrImage.make()
-
- return h('div.shapeshift-form', {}, [
-
- h('div.shapeshift-form__deposit-instruction', [
- this.context.t('depositCoin', [depositCoin.toUpperCase()]),
- ]),
-
- h('div', depositAddress),
-
- h('div.shapeshift-form__qr-code', [
- isLoading
- ? h('img', {
- src: 'images/loading.svg',
- style: { width: '60px'},
- })
- : h('div', {
- dangerouslySetInnerHTML: { __html: qrImage.createTableTag(4) },
- }),
- ]),
-
- this.renderMarketInfo(),
-
- ])
-}
-
-
-ShapeshiftForm.prototype.render = function () {
- const { coinOptions, btnClass, warning } = this.props
- const { errorMessage, showQrCode, depositAddress } = this.state
- const { tokenExchangeRates } = this.props
- const token = tokenExchangeRates[this.getCoinPair()]
-
- return h('div.shapeshift-form-wrapper', [
- showQrCode
- ? this.renderQrCode()
- : h('div.modal-shapeshift-form', [
- h('div.shapeshift-form__selectors', [
-
- h('div.shapeshift-form__selector', [
-
- h('div.shapeshift-form__selector-label', this.context.t('deposit')),
-
- h(SimpleDropdown, {
- selectedOption: this.state.depositCoin,
- onSelect: (coin) => this.onCoinChange(coin),
- options: Object.entries(coinOptions).map(([coin]) => ({
- value: coin.toLowerCase(),
- displayValue: coin,
- })),
- }),
-
- ]),
-
- h('div.icon.shapeshift-form__caret', {
- style: { backgroundImage: 'url(images/caret-right.svg)'},
- }),
-
- h('div.shapeshift-form__selector', [
-
- h('div.shapeshift-form__selector-label', [
- this.context.t('receive'),
- ]),
-
- h('div.shapeshift-form__selector-input', ['ETH']),
-
- ]),
-
- ]),
-
- warning && h('div.shapeshift-form__address-input-label', warning),
-
- !warning && h('div', {
- className: classnames('shapeshift-form__address-input-wrapper', {
- 'shapeshift-form__address-input-wrapper--error': errorMessage,
- }),
- }, [
-
- h('div.shapeshift-form__address-input-label', [
- this.context.t('refundAddress'),
- ]),
-
- h('input.shapeshift-form__address-input', {
- type: 'text',
- onChange: e => this.setState({
- refundAddress: e.target.value,
- errorMessage: '',
- }),
- }),
-
- h('divshapeshift-form__address-input-error-message', [errorMessage]),
- ]),
-
- !warning && this.renderMarketInfo(),
-
- ]),
-
- !depositAddress && h(Button, {
- type: 'secondary',
- large: true,
- className: `${btnClass} shapeshift-form__shapeshift-buy-btn`,
- disabled: !token,
- onClick: () => this.onBuyWithShapeShift(),
- }, [this.context.t('buy')]),
-
- ])
-}
diff --git a/ui/app/pages/confirm-token-transaction-base/confirm-token-transaction-base.container.js b/ui/app/pages/confirm-token-transaction-base/confirm-token-transaction-base.container.js
index fc5e2f90d..5d2ccb083 100644
--- a/ui/app/pages/confirm-token-transaction-base/confirm-token-transaction-base.container.js
+++ b/ui/app/pages/confirm-token-transaction-base/confirm-token-transaction-base.container.js
@@ -1,7 +1,10 @@
import { connect } from 'react-redux'
+import { compose } from 'recompose'
+import { withRouter } from 'react-router-dom'
import ConfirmTokenTransactionBase from './confirm-token-transaction-base.component'
import {
contractExchangeRateSelector,
+ transactionFeeSelector,
} from '../../selectors/confirm-transaction'
import { tokenSelector } from '../../selectors/tokens'
import {
@@ -14,15 +17,21 @@ import {
} from '../../helpers/utils/token-util'
-const mapStateToProps = (state) => {
- const { confirmTransaction, metamask: { currentCurrency, conversionRate } } = state
+const mapStateToProps = (state, ownProps) => {
+ const { match: { params = {} } } = ownProps
+ const { id: paramsTransactionId } = params
+ const { confirmTransaction, metamask: { currentCurrency, conversionRate, selectedAddressTxList } } = state
+
const {
- txData: { txParams: { to: tokenAddress, data } = {} } = {},
- fiatTransactionTotal,
- ethTransactionTotal,
+ txData: { id: transactionId, txParams: { to: tokenAddress, data } = {} } = {},
} = confirmTransaction
+ const transaction = selectedAddressTxList.find(({ id }) => id === (Number(paramsTransactionId) || transactionId)) || {}
+ const {
+ ethTransactionTotal,
+ fiatTransactionTotal,
+ } = transactionFeeSelector(state, transaction)
const tokens = tokenSelector(state)
const currentToken = tokens && tokens.find(({ address }) => tokenAddress === address)
const { decimals, symbol: tokenSymbol } = currentToken || {}
@@ -46,4 +55,7 @@ const mapStateToProps = (state) => {
}
}
-export default connect(mapStateToProps)(ConfirmTokenTransactionBase)
+export default compose(
+ withRouter,
+ connect(mapStateToProps)
+)(ConfirmTokenTransactionBase)
diff --git a/ui/app/pages/confirm-transaction-base/confirm-transaction-base.container.js b/ui/app/pages/confirm-transaction-base/confirm-transaction-base.container.js
index e769d8974..2a1b78a8e 100644
--- a/ui/app/pages/confirm-transaction-base/confirm-transaction-base.container.js
+++ b/ui/app/pages/confirm-transaction-base/confirm-transaction-base.container.js
@@ -6,9 +6,9 @@ import contractMap from 'eth-contract-metadata'
import ConfirmTransactionBase from './confirm-transaction-base.component'
import {
clearConfirmTransaction,
- updateGasAndCalculate,
} from '../../ducks/confirm-transaction/confirm-transaction.duck'
-import { clearSend, cancelTx, cancelTxs, updateAndApproveTx, showModal, setMetaMetricsSendCount } from '../../store/actions'
+
+import { clearSend, cancelTx, cancelTxs, updateAndApproveTx, showModal, setMetaMetricsSendCount, updateTransaction } from '../../store/actions'
import {
INSUFFICIENT_FUNDS_ERROR_KEY,
GAS_LIMIT_TOO_LOW_ERROR_KEY,
@@ -19,6 +19,7 @@ import { conversionGreaterThan } from '../../helpers/utils/conversion-util'
import { MIN_GAS_LIMIT_DEC } from '../send/send.constants'
import { checksumAddress, addressSlicer, valuesFor } from '../../helpers/utils/util'
import { getMetaMaskAccounts, getAdvancedInlineGasShown, preferencesSelector, getIsMainnet, getKnownMethodData } from '../../selectors/selectors'
+import { transactionFeeSelector } from '../../selectors/confirm-transaction'
const casedContractMap = Object.keys(contractMap).reduce((acc, base) => {
return {
@@ -32,23 +33,26 @@ const mapStateToProps = (state, ownProps) => {
const { id: paramsTransactionId } = params
const { showFiatInTestnets } = preferencesSelector(state)
const isMainnet = getIsMainnet(state)
- const { confirmTransaction, metamask, gas } = state
+ const { confirmTransaction, metamask } = state
+ const {
+ conversionRate,
+ identities,
+ currentCurrency,
+ selectedAddress,
+ selectedAddressTxList,
+ assetImages,
+ network,
+ unapprovedTxs,
+ metaMetricsSendCount,
+ } = metamask
const {
- ethTransactionAmount,
- ethTransactionFee,
- ethTransactionTotal,
- fiatTransactionAmount,
- fiatTransactionFee,
- fiatTransactionTotal,
- hexTransactionAmount,
- hexTransactionFee,
- hexTransactionTotal,
tokenData,
txData,
tokenProps,
nonce,
} = confirmTransaction
const { txParams = {}, lastGasPrice, id: transactionId, transactionCategory } = txData
+ const transaction = R.find(({ id }) => id === (transactionId || Number(paramsTransactionId)))(selectedAddressTxList) || {}
const {
from: fromAddress,
to: txParamsToAddress,
@@ -56,26 +60,10 @@ const mapStateToProps = (state, ownProps) => {
gas: gasLimit,
value: amount,
data,
- } = txParams
+ } = transaction && transaction.txParams || txParams
const accounts = getMetaMaskAccounts(state)
- const {
- conversionRate,
- identities,
- currentCurrency,
- selectedAddress,
- selectedAddressTxList,
- assetImages,
- network,
- unapprovedTxs,
- metaMetricsSendCount,
- } = metamask
const assetImage = assetImages[txParamsToAddress]
- const {
- customGasLimit,
- customGasPrice,
- } = gas
-
const { balance } = accounts[selectedAddress]
const { name: fromName } = identities[selectedAddress]
const toAddress = propsToAddress || txParamsToAddress
@@ -88,9 +76,20 @@ const mapStateToProps = (state, ownProps) => {
)
const isTxReprice = Boolean(lastGasPrice)
- const transaction = R.find(({ id }) => id === (transactionId || Number(paramsTransactionId)))(selectedAddressTxList)
const transactionStatus = transaction ? transaction.status : ''
+ const {
+ ethTransactionAmount,
+ ethTransactionFee,
+ ethTransactionTotal,
+ fiatTransactionAmount,
+ fiatTransactionFee,
+ fiatTransactionTotal,
+ hexTransactionAmount,
+ hexTransactionFee,
+ hexTransactionTotal,
+ } = transactionFeeSelector(state, transaction)
+
if (transaction && transaction.simulationFails) {
txData.simulationFails = transaction.simulationFails
}
@@ -125,7 +124,7 @@ const mapStateToProps = (state, ownProps) => {
hexTransactionAmount,
hexTransactionFee,
hexTransactionTotal,
- txData: Object.keys(txData).length ? txData : transaction || {},
+ txData: { ...txData, ...transaction },
tokenData,
methodData,
tokenProps,
@@ -139,8 +138,8 @@ const mapStateToProps = (state, ownProps) => {
unapprovedTxCount,
currentNetworkUnapprovedTxs,
customGas: {
- gasLimit: customGasLimit || gasLimit,
- gasPrice: customGasPrice || gasPrice,
+ gasLimit,
+ gasPrice,
},
advancedInlineGasShown: getAdvancedInlineGasShown(state),
insufficientBalance,
@@ -161,8 +160,8 @@ const mapDispatchToProps = dispatch => {
showCustomizeGasModal: ({ txData, onSubmit, validate }) => {
return dispatch(showModal({ name: 'CUSTOMIZE_GAS', txData, onSubmit, validate }))
},
- updateGasAndCalculate: ({ gasLimit, gasPrice }) => {
- return dispatch(updateGasAndCalculate({ gasLimit, gasPrice }))
+ updateGasAndCalculate: (updatedTx) => {
+ return dispatch(updateTransaction(updatedTx))
},
showRejectTransactionsConfirmationModal: ({ onSubmit, unapprovedTxCount }) => {
return dispatch(showModal({ name: 'REJECT_TRANSACTIONS', onSubmit, unapprovedTxCount }))
@@ -239,7 +238,17 @@ const mergeProps = (stateProps, dispatchProps, ownProps) => {
validate: validateEditGas,
}),
cancelAllTransactions: () => dispatchCancelAllTransactions(valuesFor(unapprovedTxs)),
- updateGasAndCalculate: dispatchUpdateGasAndCalculate,
+ updateGasAndCalculate: ({ gasLimit, gasPrice }) => {
+ const updatedTx = {
+ ...txData,
+ txParams: {
+ ...txData.txParams,
+ gas: gasLimit,
+ gasPrice,
+ },
+ }
+ dispatchUpdateGasAndCalculate(updatedTx)
+ },
}
}
diff --git a/ui/app/pages/first-time-flow/create-password/import-with-seed-phrase/import-with-seed-phrase.component.js b/ui/app/pages/first-time-flow/create-password/import-with-seed-phrase/import-with-seed-phrase.component.js
index 5092d277e..a2fb5a3bf 100644
--- a/ui/app/pages/first-time-flow/create-password/import-with-seed-phrase/import-with-seed-phrase.component.js
+++ b/ui/app/pages/first-time-flow/create-password/import-with-seed-phrase/import-with-seed-phrase.component.js
@@ -30,10 +30,21 @@ export default class ImportWithSeedPhrase extends PureComponent {
}
parseSeedPhrase = (seedPhrase) => {
- return seedPhrase
- .trim()
- .match(/\w+/g)
- .join(' ')
+ if (!seedPhrase) {
+ return ''
+ }
+
+ const trimmed = seedPhrase.trim()
+ if (!trimmed) {
+ return ''
+ }
+
+ const words = trimmed.match(/\w+/g)
+ if (!words) {
+ return ''
+ }
+
+ return words.join(' ')
}
componentWillMount () {
diff --git a/ui/app/pages/first-time-flow/create-password/import-with-seed-phrase/tests/import-with-seed-phrase.component.test.js b/ui/app/pages/first-time-flow/create-password/import-with-seed-phrase/tests/import-with-seed-phrase.component.test.js
new file mode 100644
index 000000000..7960d17b2
--- /dev/null
+++ b/ui/app/pages/first-time-flow/create-password/import-with-seed-phrase/tests/import-with-seed-phrase.component.test.js
@@ -0,0 +1,78 @@
+import React from 'react'
+import assert from 'assert'
+import { shallow } from 'enzyme'
+import sinon from 'sinon'
+import ImportWithSeedPhrase from '../import-with-seed-phrase.component'
+
+function shallowRender (props = {}, context = {}) {
+ return shallow(<ImportWithSeedPhrase {...props} />, {
+ context: {
+ t: str => str + '_t',
+ metricsEvent: sinon.spy(),
+ ...context,
+ },
+ })
+}
+
+describe('ImportWithSeedPhrase Component', () => {
+ it('should render without error', () => {
+ const root = shallowRender({
+ onSubmit: sinon.spy(),
+ })
+ const textareaCount = root.find('.first-time-flow__textarea').length
+ assert.equal(textareaCount, 1, 'should render 12 seed phrases')
+ })
+
+ describe('parseSeedPhrase', () => {
+ it('should handle a regular seed phrase', () => {
+ const root = shallowRender({
+ onSubmit: sinon.spy(),
+ })
+
+ const {parseSeedPhrase} = root.instance()
+
+ assert.deepEqual(parseSeedPhrase('foo bar baz'), 'foo bar baz')
+ })
+
+ it('should trim extraneous whitespace from the given seed phrase', () => {
+ const root = shallowRender({
+ onSubmit: sinon.spy(),
+ })
+
+ const {parseSeedPhrase} = root.instance()
+
+ assert.deepEqual(parseSeedPhrase(' foo bar baz '), 'foo bar baz')
+ })
+
+ it('should return an empty string when given a whitespace-only string', () => {
+ const root = shallowRender({
+ onSubmit: sinon.spy(),
+ })
+
+ const {parseSeedPhrase} = root.instance()
+
+ assert.deepEqual(parseSeedPhrase(' '), '')
+ })
+
+ it('should return an empty string when given a string with only symbols', () => {
+ const root = shallowRender({
+ onSubmit: sinon.spy(),
+ })
+
+ const {parseSeedPhrase} = root.instance()
+
+ assert.deepEqual(parseSeedPhrase('$'), '')
+ })
+
+ it('should return an empty string for both null and undefined', () => {
+ const root = shallowRender({
+ onSubmit: sinon.spy(),
+ })
+
+ const {parseSeedPhrase} = root.instance()
+
+ assert.deepEqual(parseSeedPhrase(undefined), '')
+ assert.deepEqual(parseSeedPhrase(null), '')
+ })
+ })
+})
diff --git a/ui/app/pages/first-time-flow/first-time-flow.component.js b/ui/app/pages/first-time-flow/first-time-flow.component.js
index bf6e80ca9..0d206bf42 100644
--- a/ui/app/pages/first-time-flow/first-time-flow.component.js
+++ b/ui/app/pages/first-time-flow/first-time-flow.component.js
@@ -29,7 +29,7 @@ export default class FirstTimeFlow extends PureComponent {
isInitialized: PropTypes.bool,
isUnlocked: PropTypes.bool,
unlockAccount: PropTypes.func,
- nextRoute: PropTypes.func,
+ nextRoute: PropTypes.string,
}
state = {
diff --git a/ui/app/pages/keychains/restore-vault.js b/ui/app/pages/keychains/restore-vault.js
index 574949258..08164fd9f 100644
--- a/ui/app/pages/keychains/restore-vault.js
+++ b/ui/app/pages/keychains/restore-vault.js
@@ -123,6 +123,7 @@ class RestoreVaultPage extends Component {
className="import-account__back-button"
onClick={e => {
e.preventDefault()
+ this.props.leaveImportSeedScreenState()
this.props.history.goBack()
}}
href="#"
diff --git a/ui/app/selectors/confirm-transaction.js b/ui/app/selectors/confirm-transaction.js
index 9b5eda82f..82df4e776 100644
--- a/ui/app/selectors/confirm-transaction.js
+++ b/ui/app/selectors/confirm-transaction.js
@@ -1,7 +1,17 @@
import { createSelector } from 'reselect'
import txHelper from '../../lib/tx-helper'
import { calcTokenAmount } from '../helpers/utils/token-util'
-import { roundExponential } from '../helpers/utils/confirm-tx.util'
+import {
+ roundExponential,
+ getValueFromWeiHex,
+ getHexGasTotal,
+ getTransactionFee,
+ addFiat,
+ addEth,
+} from '../helpers/utils/confirm-tx.util'
+import {
+ sumHexes,
+} from '../helpers/utils/transactions.util'
const unapprovedTxsSelector = state => state.metamask.unapprovedTxs
const unapprovedMsgsSelector = state => state.metamask.unapprovedMsgs
@@ -207,3 +217,51 @@ export const contractExchangeRateSelector = createSelector(
tokenAddressSelector,
(contractExchangeRates, tokenAddress) => contractExchangeRates[tokenAddress]
)
+
+export const transactionFeeSelector = function (state, txData) {
+ const currentCurrency = currentCurrencySelector(state)
+ const conversionRate = conversionRateSelector(state)
+ const nativeCurrency = getNativeCurrency(state)
+
+ const { txParams: { value = '0x0', gas: gasLimit = '0x0', gasPrice = '0x0' } = {} } = txData
+
+ const fiatTransactionAmount = getValueFromWeiHex({
+ value, fromCurrency: nativeCurrency, toCurrency: currentCurrency, conversionRate, numberOfDecimals: 2,
+ })
+ const ethTransactionAmount = getValueFromWeiHex({
+ value, fromCurrency: nativeCurrency, toCurrency: nativeCurrency, conversionRate, numberOfDecimals: 6,
+ })
+
+ const hexTransactionFee = getHexGasTotal({ gasLimit, gasPrice })
+
+ const fiatTransactionFee = getTransactionFee({
+ value: hexTransactionFee,
+ fromCurrency: nativeCurrency,
+ toCurrency: currentCurrency,
+ numberOfDecimals: 2,
+ conversionRate,
+ })
+ const ethTransactionFee = getTransactionFee({
+ value: hexTransactionFee,
+ fromCurrency: nativeCurrency,
+ toCurrency: nativeCurrency,
+ numberOfDecimals: 6,
+ conversionRate,
+ })
+
+ const fiatTransactionTotal = addFiat(fiatTransactionFee, fiatTransactionAmount)
+ const ethTransactionTotal = addEth(ethTransactionFee, ethTransactionAmount)
+ const hexTransactionTotal = sumHexes(value, hexTransactionFee)
+
+ return {
+ hexTransactionAmount: value,
+ fiatTransactionAmount,
+ ethTransactionAmount,
+ hexTransactionFee,
+ fiatTransactionFee,
+ ethTransactionFee,
+ fiatTransactionTotal,
+ ethTransactionTotal,
+ hexTransactionTotal,
+ }
+}
diff --git a/ui/app/store/actions.js b/ui/app/store/actions.js
index d3cc7efca..3ed82044d 100644
--- a/ui/app/store/actions.js
+++ b/ui/app/store/actions.js
@@ -2391,10 +2391,6 @@ function reshowQrCode (data, coin) {
dispatch(actions.hideLoadingIndication())
return dispatch(actions.showQrView(data, message))
- // return dispatch(actions.showModal({
- // name: 'SHAPESHIFT_DEPOSIT_TX',
- // Qr: { data, message },
- // }))
})
}
}