Use `send` state for send flow token (#8695)

The chosen token in the `send` flow was set from one of two places:
`metamask.selectedTokenAddress` or `metamask.send.token`. The former is
used most of the time, but the latter is used for the 'Edit' button
shown in the upper-left of the confirmation UI.

The send flow will now exclusively use `metamask.send.token` for the
token state during the send flow. `metamask.selectedTokenAddress` is
now only used for the selected token state on the Home screen. This
simplifies the Redux state, as the send token is now in one place
instead of two, and `metamask.selectedTokenAddress` has only one
purpose.
feature/default_network_editable
Mark Stacey 4 years ago committed by GitHub
parent e481166052
commit ddaa492751
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 18
      ui/app/components/app/gas-customization/gas-modal-page-container/gas-modal-page-container.container.js
  2. 4
      ui/app/components/app/gas-customization/gas-modal-page-container/tests/gas-modal-page-container-container.test.js
  3. 5
      ui/app/components/app/wallet-overview/token-overview.js
  4. 16
      ui/app/hooks/useRetryTransaction.js
  5. 3
      ui/app/pages/confirm-send-token/confirm-send-token.container.js
  6. 4
      ui/app/pages/send/send-content/add-recipient/add-recipient.js
  7. 8
      ui/app/pages/send/send-content/add-recipient/tests/add-recipient-utils.test.js
  8. 6
      ui/app/pages/send/send-content/send-amount-row/amount-max-button/amount-max-button.component.js
  9. 4
      ui/app/pages/send/send-content/send-amount-row/amount-max-button/amount-max-button.container.js
  10. 6
      ui/app/pages/send/send-content/send-amount-row/amount-max-button/amount-max-button.utils.js
  11. 4
      ui/app/pages/send/send-content/send-amount-row/amount-max-button/tests/amount-max-button-component.test.js
  12. 4
      ui/app/pages/send/send-content/send-amount-row/amount-max-button/tests/amount-max-button-container.test.js
  13. 8
      ui/app/pages/send/send-content/send-amount-row/amount-max-button/tests/amount-max-button-utils.test.js
  14. 24
      ui/app/pages/send/send-content/send-amount-row/send-amount-row.component.js
  15. 4
      ui/app/pages/send/send-content/send-amount-row/send-amount-row.container.js
  16. 12
      ui/app/pages/send/send-content/send-amount-row/tests/send-amount-row-component.test.js
  17. 20
      ui/app/pages/send/send-content/send-asset-row/send-asset-row.component.js
  18. 8
      ui/app/pages/send/send-content/send-asset-row/send-asset-row.container.js
  19. 6
      ui/app/pages/send/send-content/send-gas-row/send-gas-row.component.js
  20. 6
      ui/app/pages/send/send-content/send-gas-row/send-gas-row.container.js
  21. 12
      ui/app/pages/send/send-footer/send-footer.component.js
  22. 16
      ui/app/pages/send/send-footer/send-footer.container.js
  23. 10
      ui/app/pages/send/send-footer/send-footer.utils.js
  24. 16
      ui/app/pages/send/send-footer/tests/send-footer-component.test.js
  25. 16
      ui/app/pages/send/send-footer/tests/send-footer-container.test.js
  26. 18
      ui/app/pages/send/send-footer/tests/send-footer-utils.test.js
  27. 36
      ui/app/pages/send/send.component.js
  28. 16
      ui/app/pages/send/send.container.js
  29. 32
      ui/app/pages/send/send.utils.js
  30. 36
      ui/app/pages/send/tests/send-component.test.js
  31. 8
      ui/app/pages/send/tests/send-container.test.js
  32. 35
      ui/app/pages/send/tests/send-utils.test.js
  33. 29
      ui/app/selectors/selectors.js
  34. 25
      ui/app/selectors/send.js
  35. 76
      ui/app/selectors/tests/send.test.js
  36. 8
      ui/app/store/actions.js

@ -28,7 +28,7 @@ import {
getCurrentCurrency,
getCurrentEthBalance,
getIsMainnet,
getSelectedToken,
getSendToken,
isEthereumNetwork,
getPreferences,
getBasicGasEstimateLoadingStatus,
@ -75,7 +75,7 @@ const mapStateToProps = (state, ownProps) => {
const buttonDataLoading = getBasicGasEstimateLoadingStatus(state)
const gasEstimatesLoading = getGasEstimatesLoadingStatus(state)
const selectedToken = getSelectedToken(state)
const sendToken = getSendToken(state)
// a "default" txParams is used during the send flow, since the transaction doesn't exist yet in that case
const txParams = selectedTransaction?.txParams
@ -83,7 +83,7 @@ const mapStateToProps = (state, ownProps) => {
: {
gas: send.gasLimit || '0x5208',
gasPrice: send.gasPrice || getFastPriceEstimateInHexWEI(state, true),
value: selectedToken ? '0x0' : send.amount,
value: sendToken ? '0x0' : send.amount,
}
const { gasPrice: currentGasPrice, gas: currentGasLimit, value } = txParams
@ -112,11 +112,11 @@ const mapStateToProps = (state, ownProps) => {
const isMainnet = getIsMainnet(state)
const showFiat = Boolean(isMainnet || showFiatInTestnets)
const isTokenSelected = Boolean(selectedToken)
const isSendTokenSet = Boolean(sendToken)
const newTotalEth = maxModeOn && !isTokenSelected ? addHexWEIsToRenderableEth(balance, '0x0') : addHexWEIsToRenderableEth(value, customGasTotal)
const newTotalEth = maxModeOn && !isSendTokenSet ? addHexWEIsToRenderableEth(balance, '0x0') : addHexWEIsToRenderableEth(value, customGasTotal)
const sendAmount = maxModeOn && !isTokenSelected ? subtractHexWEIsFromRenderableEth(balance, customGasTotal) : addHexWEIsToRenderableEth(value, '0x0')
const sendAmount = maxModeOn && !isSendTokenSet ? subtractHexWEIsFromRenderableEth(balance, customGasTotal) : addHexWEIsToRenderableEth(value, '0x0')
const insufficientBalance = maxModeOn ? false : !isBalanceSufficient({
amount: value,
@ -167,7 +167,7 @@ const mapStateToProps = (state, ownProps) => {
gasEstimatesLoading,
isMainnet,
isEthereumNetwork: isEthereumNetwork(state),
selectedToken: getSelectedToken(state),
sendToken,
balance,
tokenBalance: getTokenBalance(state),
}
@ -223,7 +223,7 @@ const mergeProps = (stateProps, dispatchProps, ownProps) => {
customGasPrice,
customGasTotal,
balance,
selectedToken,
sendToken,
tokenBalance,
customGasLimit,
transaction,
@ -274,7 +274,7 @@ const mergeProps = (stateProps, dispatchProps, ownProps) => {
dispatchSetAmountToMax({
balance,
gasTotal: customGasTotal,
selectedToken,
sendToken,
tokenBalance,
})
}

@ -40,7 +40,7 @@ proxyquire('../gas-modal-page-container.container.js', {
getRenderableBasicEstimateData: (s) => `mockRenderableBasicEstimateData:${Object.keys(s).length}`,
getDefaultActiveButtonIndex: (a, b) => a + b,
getCurrentEthBalance: (state) => state.metamask.balance || '0x0',
getSelectedToken: () => null,
getSendToken: () => null,
getTokenBalance: (state) => state.metamask.send.tokenBalance || '0x0',
},
'../../../../store/actions': actionSpies,
@ -158,7 +158,7 @@ describe('gas-modal-page-container container', function () {
isEthereumNetwork: true,
isMainnet: true,
maxModeOn: false,
selectedToken: null,
sendToken: null,
tokenBalance: '0x0',
transaction: {
id: 34,

@ -1,6 +1,6 @@
import React, { useContext } from 'react'
import PropTypes from 'prop-types'
import { useSelector } from 'react-redux'
import { useDispatch, useSelector } from 'react-redux'
import { useHistory } from 'react-router-dom'
import Button from '../../ui/button'
@ -11,8 +11,10 @@ import WalletOverview from './wallet-overview'
import { SEND_ROUTE } from '../../../helpers/constants/routes'
import { useMetricEvent } from '../../../hooks/useMetricEvent'
import { getAssetImages } from '../../../selectors/selectors'
import { updateSend } from '../../../store/actions'
const TokenOverview = ({ token }) => {
const dispatch = useDispatch()
const t = useContext(I18nContext)
const sendTokenEvent = useMetricEvent({
eventOpts: {
@ -41,6 +43,7 @@ const TokenOverview = ({ token }) => {
className="token-overview__button"
onClick={() => {
sendTokenEvent()
dispatch(updateSend({ token }))
history.push(SEND_ROUTE)
}}
>

@ -1,16 +1,14 @@
import { useDispatch } from 'react-redux'
import { useCallback } from 'react'
import { setSelectedToken, showSidebar } from '../store/actions'
import { showSidebar } from '../store/actions'
import {
fetchBasicGasAndTimeEstimates,
fetchGasEstimates,
setCustomGasPriceForRetry,
setCustomGasLimit,
} from '../ducks/gas/gas.duck'
import { TOKEN_METHOD_TRANSFER } from '../helpers/constants/transactions'
import { increaseLastGasPrice } from '../helpers/utils/confirm-tx.util'
import { useMetricEvent } from './useMetricEvent'
import { useMethodData } from './useMethodData'
/**
@ -22,7 +20,6 @@ import { useMethodData } from './useMethodData'
export function useRetryTransaction (transactionGroup) {
const { primaryTransaction, initialTransaction } = transactionGroup
const gasPrice = primaryTransaction.txParams.gasPrice
const methodData = useMethodData(primaryTransaction.txParams.data)
const trackMetricsEvent = useMetricEvent(({
eventOpts: {
category: 'Navigation',
@ -32,8 +29,6 @@ export function useRetryTransaction (transactionGroup) {
}))
const dispatch = useDispatch()
const { name: methodName } = methodData || {}
const retryTransaction = useCallback(async (event) => {
event.stopPropagation()
@ -49,14 +44,7 @@ export function useRetryTransaction (transactionGroup) {
type: 'customize-gas',
props: { transaction },
}))
if (
methodName === TOKEN_METHOD_TRANSFER &&
initialTransaction.txParams.to
) {
dispatch(setSelectedToken(initialTransaction.txParams.to))
}
}, [dispatch, methodName, trackMetricsEvent, initialTransaction, gasPrice])
}, [dispatch, trackMetricsEvent, initialTransaction, gasPrice])
return retryTransaction
}

@ -3,7 +3,7 @@ import { compose } from 'redux'
import { withRouter } from 'react-router-dom'
import ConfirmSendToken from './confirm-send-token.component'
import { clearConfirmTransaction } from '../../ducks/confirm-transaction/confirm-transaction.duck'
import { setSelectedToken, updateSend, showSendTokenPage } from '../../store/actions'
import { updateSend, showSendTokenPage } from '../../store/actions'
import { conversionUtil } from '../../helpers/utils/conversion-util'
import { sendTokenTokenAmountAndToAddressSelector } from '../../selectors'
@ -38,7 +38,6 @@ const mapDispatchToProps = (dispatch) => {
toNumericBase: 'hex',
})
dispatch(setSelectedToken(tokenAddress))
dispatch(updateSend({
from,
gasLimit,

@ -24,9 +24,9 @@ export function getToErrorObject (to, hasHexData = false, _, __, network) {
return { to: toError }
}
export function getToWarningObject (to, tokens = [], selectedToken = null) {
export function getToWarningObject (to, tokens = [], sendToken = null) {
let toWarning = null
if (selectedToken && (ethUtil.toChecksumAddress(to) in contractMap || checkExistingAddresses(to, tokens))) {
if (sendToken && (ethUtil.toChecksumAddress(to) in contractMap || checkExistingAddresses(to, tokens))) {
toWarning = KNOWN_RECIPIENT_ADDRESS_ERROR
}
return { to: toWarning }

@ -55,7 +55,7 @@ describe('add-recipient utils', function () {
})
})
it('should null if to is truthy part of tokens but selectedToken falsy', function () {
it('should null if to is truthy part of tokens but sendToken falsy', function () {
assert.deepEqual(getToErrorObject('0xabc123', false, [{ 'address': '0xabc123' }]), {
to: null,
})
@ -66,7 +66,7 @@ describe('add-recipient utils', function () {
to: null,
})
})
it('should null if to is truthy part of contract metadata but selectedToken falsy', function () {
it('should null if to is truthy part of contract metadata but sendToken falsy', function () {
assert.deepEqual(getToErrorObject('0x89d24a6b4ccb1b6faa2625fe562bdd9a23260359', false, [{ 'address': '0xabc123' }], { 'address': '0xabc123' }), {
to: null,
})
@ -80,7 +80,7 @@ describe('add-recipient utils', function () {
})
})
it('should null if to is truthy part of tokens but selectedToken falsy', function () {
it('should null if to is truthy part of tokens but sendToken falsy', function () {
assert.deepEqual(getToWarningObject('0xabc123', [{ 'address': '0xabc123' }]), {
to: null,
})
@ -91,7 +91,7 @@ describe('add-recipient utils', function () {
to: KNOWN_RECIPIENT_ADDRESS_ERROR,
})
})
it('should null if to is truthy part of contract metadata but selectedToken falsy', function () {
it('should null if to is truthy part of contract metadata but sendToken falsy', function () {
assert.deepEqual(getToWarningObject('0x89d24a6b4ccb1b6faa2625fe562bdd9a23260359', [{ 'address': '0xabc123' }], { 'address': '0xabc123' }), {
to: KNOWN_RECIPIENT_ADDRESS_ERROR,
})

@ -11,7 +11,7 @@ export default class AmountMaxButton extends Component {
inError: PropTypes.bool,
gasTotal: PropTypes.string,
maxModeOn: PropTypes.bool,
selectedToken: PropTypes.object,
sendToken: PropTypes.object,
setAmountToMax: PropTypes.func,
setMaxModeTo: PropTypes.func,
tokenBalance: PropTypes.string,
@ -27,7 +27,7 @@ export default class AmountMaxButton extends Component {
const {
balance,
gasTotal,
selectedToken,
sendToken,
setAmountToMax,
tokenBalance,
} = this.props
@ -35,7 +35,7 @@ export default class AmountMaxButton extends Component {
setAmountToMax({
balance,
gasTotal,
selectedToken,
sendToken,
tokenBalance,
})
}

@ -1,7 +1,7 @@
import { connect } from 'react-redux'
import {
getGasTotal,
getSelectedToken,
getSendToken,
getSendFromBalance,
getTokenBalance,
getSendMaxModeState,
@ -26,7 +26,7 @@ function mapStateToProps (state) {
buttonDataLoading: getBasicGasEstimateLoadingStatus(state),
gasTotal: getGasTotal(state),
maxModeOn: getSendMaxModeState(state),
selectedToken: getSelectedToken(state),
sendToken: getSendToken(state),
tokenBalance: getTokenBalance(state),
}
}

@ -1,11 +1,11 @@
import { multiplyCurrencies, subtractCurrencies } from '../../../../../helpers/utils/conversion-util'
import ethUtil from 'ethereumjs-util'
export function calcMaxAmount ({ balance, gasTotal, selectedToken, tokenBalance }) {
const { decimals } = selectedToken || {}
export function calcMaxAmount ({ balance, gasTotal, sendToken, tokenBalance }) {
const { decimals } = sendToken || {}
const multiplier = Math.pow(10, Number(decimals || 0))
return selectedToken
return sendToken
? multiplyCurrencies(
tokenBalance,
multiplier,

@ -25,7 +25,7 @@ describe('AmountMaxButton Component', function () {
balance="mockBalance"
gasTotal="mockGasTotal"
maxModeOn={false}
selectedToken={ { address: 'mockTokenAddress' } }
sendToken={ { address: 'mockTokenAddress' } }
setAmountToMax={propsMethodSpies.setAmountToMax}
setMaxModeTo={propsMethodSpies.setMaxModeTo}
tokenBalance="mockTokenBalance"
@ -60,7 +60,7 @@ describe('AmountMaxButton Component', function () {
[{
balance: 'mockBalance',
gasTotal: 'mockGasTotal',
selectedToken: { address: 'mockTokenAddress' },
sendToken: { address: 'mockTokenAddress' },
tokenBalance: 'mockTokenBalance',
}]
)

@ -23,7 +23,7 @@ proxyquire('../amount-max-button.container.js', {
},
'../../../../../selectors': {
getGasTotal: (s) => `mockGasTotal:${s}`,
getSelectedToken: (s) => `mockSelectedToken:${s}`,
getSendToken: (s) => `mockSendToken:${s}`,
getSendFromBalance: (s) => `mockBalance:${s}`,
getTokenBalance: (s) => `mockTokenBalance:${s}`,
getSendMaxModeState: (s) => `mockMaxModeOn:${s}`,
@ -44,7 +44,7 @@ describe('amount-max-button container', function () {
buttonDataLoading: 'mockButtonDataLoading:mockState',
gasTotal: 'mockGasTotal:mockState',
maxModeOn: 'mockMaxModeOn:mockState',
selectedToken: 'mockSelectedToken:mockState',
sendToken: 'mockSendToken:mockState',
tokenBalance: 'mockTokenBalance:mockState',
})
})

@ -6,17 +6,17 @@ import {
describe('amount-max-button utils', function () {
describe('calcMaxAmount()', function () {
it('should calculate the correct amount when no selectedToken defined', function () {
it('should calculate the correct amount when no sendToken defined', function () {
assert.deepEqual(calcMaxAmount({
balance: 'ffffff',
gasTotal: 'ff',
selectedToken: false,
sendToken: false,
}), 'ffff00')
})
it('should calculate the correct amount when a selectedToken is defined', function () {
it('should calculate the correct amount when a sendToken is defined', function () {
assert.deepEqual(calcMaxAmount({
selectedToken: {
sendToken: {
decimals: 10,
},
tokenBalance: '64',

@ -15,7 +15,7 @@ export default class SendAmountRow extends Component {
gasTotal: PropTypes.string,
inError: PropTypes.bool,
primaryCurrency: PropTypes.string,
selectedToken: PropTypes.object,
sendToken: PropTypes.object,
setMaxModeTo: PropTypes.func,
tokenBalance: PropTypes.string,
updateGasFeeError: PropTypes.func,
@ -31,9 +31,9 @@ export default class SendAmountRow extends Component {
componentDidUpdate (prevProps) {
const { maxModeOn: prevMaxModeOn, gasTotal: prevGasTotal } = prevProps
const { maxModeOn, amount, gasTotal, selectedToken } = this.props
const { maxModeOn, amount, gasTotal, sendToken } = this.props
if (maxModeOn && selectedToken && !prevMaxModeOn) {
if (maxModeOn && sendToken && !prevMaxModeOn) {
this.updateGas(amount)
}
@ -50,7 +50,7 @@ export default class SendAmountRow extends Component {
conversionRate,
gasTotal,
primaryCurrency,
selectedToken,
sendToken,
tokenBalance,
updateGasFeeError,
updateSendAmountError,
@ -62,17 +62,17 @@ export default class SendAmountRow extends Component {
conversionRate,
gasTotal,
primaryCurrency,
selectedToken,
sendToken,
tokenBalance,
})
if (selectedToken) {
if (sendToken) {
updateGasFeeError({
balance,
conversionRate,
gasTotal,
primaryCurrency,
selectedToken,
sendToken,
tokenBalance,
})
}
@ -86,9 +86,9 @@ export default class SendAmountRow extends Component {
}
updateGas (amount) {
const { selectedToken, updateGas } = this.props
const { sendToken, updateGas } = this.props
if (selectedToken) {
if (sendToken) {
updateGas({ amount })
}
}
@ -100,14 +100,14 @@ export default class SendAmountRow extends Component {
}
renderInput () {
const { amount, inError, selectedToken } = this.props
const { amount, inError, sendToken } = this.props
return selectedToken ?
return sendToken ?
(
<UserPreferencedTokenInput
error={inError}
onChange={this.handleChange}
token={selectedToken}
token={sendToken}
value={amount}
/>
)

@ -3,7 +3,7 @@ import {
getConversionRate,
getGasTotal,
getPrimaryCurrency,
getSelectedToken,
getSendToken,
getSendAmount,
getSendFromBalance,
getTokenBalance,
@ -30,7 +30,7 @@ function mapStateToProps (state) {
gasTotal: getGasTotal(state),
inError: sendAmountIsInError(state),
primaryCurrency: getPrimaryCurrency(state),
selectedToken: getSelectedToken(state),
sendToken: getSendToken(state),
tokenBalance: getTokenBalance(state),
maxModeOn: getSendMaxModeState(state),
}

@ -23,12 +23,12 @@ describe('SendAmountRow Component', function () {
conversionRate: 7,
gasTotal: 'mockGasTotal',
primaryCurrency: 'mockPrimaryCurrency',
selectedToken: { address: 'mockTokenAddress' },
sendToken: { address: 'mockTokenAddress' },
tokenBalance: 'mockTokenBalance',
}))
})
it('should call updateGasFeeError if selectedToken is truthy', function () {
it('should call updateGasFeeError if sendToken is truthy', function () {
const { instance, propsMethodSpies: { updateGasFeeError } } = shallowRenderSendAmountRow()
assert.equal(updateGasFeeError.callCount, 0)
@ -40,15 +40,15 @@ describe('SendAmountRow Component', function () {
conversionRate: 7,
gasTotal: 'mockGasTotal',
primaryCurrency: 'mockPrimaryCurrency',
selectedToken: { address: 'mockTokenAddress' },
sendToken: { address: 'mockTokenAddress' },
tokenBalance: 'mockTokenBalance',
}))
})
it('should call not updateGasFeeError if selectedToken is falsey', function () {
it('should call not updateGasFeeError if sendToken is falsey', function () {
const { wrapper, instance, propsMethodSpies: { updateGasFeeError } } = shallowRenderSendAmountRow()
wrapper.setProps({ selectedToken: null })
wrapper.setProps({ sendToken: null })
assert.equal(updateGasFeeError.callCount, 0)
@ -152,7 +152,7 @@ function shallowRenderSendAmountRow () {
gasTotal="mockGasTotal"
inError={false}
primaryCurrency="mockPrimaryCurrency"
selectedToken={ { address: 'mockTokenAddress' } }
sendToken={ { address: 'mockTokenAddress' } }
setMaxModeTo={setMaxModeTo}
tokenBalance="mockTokenBalance"
updateGasFeeError={updateGasFeeError}

@ -17,8 +17,8 @@ export default class SendAssetRow extends Component {
).isRequired,
accounts: PropTypes.object.isRequired,
selectedAddress: PropTypes.string.isRequired,
selectedTokenAddress: PropTypes.string,
setSelectedToken: PropTypes.func.isRequired,
sendTokenAddress: PropTypes.string,
setSendToken: PropTypes.func.isRequired,
}
static contextTypes = {
@ -34,7 +34,7 @@ export default class SendAssetRow extends Component {
closeDropdown = () => this.setState({ isShowingDropdown: false })
selectToken = (address) => {
selectToken = (token) => {
this.setState({
isShowingDropdown: false,
}, () => {
@ -45,10 +45,10 @@ export default class SendAssetRow extends Component {
name: 'User clicks "Assets" dropdown',
},
customVariables: {
assetSelected: address ? 'ERC20' : 'ETH',
assetSelected: token ? 'ERC20' : 'ETH',
},
})
this.props.setSelectedToken(address)
this.props.setSendToken(token)
})
}
@ -58,16 +58,16 @@ export default class SendAssetRow extends Component {
return (
<SendRowWrapper label={`${t('asset')}:`}>
<div className="send-v2__asset-dropdown">
{ this.renderSelectedToken() }
{ this.renderSendToken() }
{ this.props.tokens.length > 0 ? this.renderAssetDropdown() : null }
</div>
</SendRowWrapper>
)
}
renderSelectedToken () {
const { selectedTokenAddress } = this.props
const token = this.props.tokens.find(({ address }) => address === selectedTokenAddress)
renderSendToken () {
const { sendTokenAddress } = this.props
const token = this.props.tokens.find(({ address }) => address === sendTokenAddress)
return (
<div
className="send-v2__asset-dropdown__input-wrapper"
@ -133,7 +133,7 @@ export default class SendAssetRow extends Component {
<div
key={address}
className="send-v2__asset-dropdown__asset"
onClick={() => this.selectToken(address)}
onClick={() => this.selectToken(token)}
>
<div className="send-v2__asset-dropdown__asset-icon">
<Identicon address={address} diameter={36} />

@ -1,20 +1,20 @@
import { connect } from 'react-redux'
import SendAssetRow from './send-asset-row.component'
import { getMetaMaskAccounts } from '../../../../selectors'
import { setSelectedToken } from '../../../../store/actions'
import { getMetaMaskAccounts, getSendTokenAddress } from '../../../../selectors'
import { updateSend } from '../../../../store/actions'
function mapStateToProps (state) {
return {
tokens: state.metamask.tokens,
selectedAddress: state.metamask.selectedAddress,
selectedTokenAddress: state.metamask.selectedTokenAddress,
sendTokenAddress: getSendTokenAddress(state),
accounts: getMetaMaskAccounts(state),
}
}
function mapDispatchToProps (dispatch) {
return {
setSelectedToken: (address) => dispatch(setSelectedToken(address)),
setSendToken: (token) => dispatch(updateSend({ token })),
}
}

@ -14,7 +14,7 @@ export default class SendGasRow extends Component {
gasTotal: PropTypes.string,
maxModeOn: PropTypes.bool,
showCustomizeGasModal: PropTypes.func,
selectedToken: PropTypes.object,
sendToken: PropTypes.object,
setAmountToMax: PropTypes.func,
setGasPrice: PropTypes.func,
setGasLimit: PropTypes.func,
@ -59,7 +59,7 @@ export default class SendGasRow extends Component {
const {
balance,
gasTotal,
selectedToken,
sendToken,
setAmountToMax,
tokenBalance,
} = this.props
@ -67,7 +67,7 @@ export default class SendGasRow extends Component {
setAmountToMax({
balance,
gasTotal,
selectedToken,
sendToken,
tokenBalance,
})
}

@ -13,7 +13,7 @@ import {
getGasButtonGroupShown,
getAdvancedInlineGasShown,
getCurrentEthBalance,
getSelectedToken,
getSendToken,
getBasicGasEstimateLoadingStatus,
getRenderableEstimateDataForSmallButtonsFromGWEI,
getDefaultActiveButtonIndex,
@ -49,7 +49,7 @@ function mapStateToProps (state) {
const balance = getCurrentEthBalance(state)
const insufficientBalance = !isBalanceSufficient({
amount: getSelectedToken(state) ? '0x0' : getSendAmount(state),
amount: getSendToken(state) ? '0x0' : getSendAmount(state),
gasTotal,
balance,
conversionRate,
@ -72,7 +72,7 @@ function mapStateToProps (state) {
gasLimit,
insufficientBalance,
maxModeOn: getSendMaxModeState(state),
selectedToken: getSelectedToken(state),
sendToken: getSendToken(state),
tokenBalance: getTokenBalance(state),
}
}

@ -17,7 +17,7 @@ export default class SendFooter extends Component {
gasTotal: PropTypes.string,
history: PropTypes.object,
inError: PropTypes.bool,
selectedToken: PropTypes.object,
sendToken: PropTypes.object,
sign: PropTypes.func,
to: PropTypes.string,
toAccounts: PropTypes.array,
@ -49,7 +49,7 @@ export default class SendFooter extends Component {
from: { address: from },
gasLimit: gas,
gasPrice,
selectedToken,
sendToken,
sign,
to,
unapprovedTxs,
@ -78,11 +78,11 @@ export default class SendFooter extends Component {
from,
gas,
gasPrice,
selectedToken,
sendToken,
to,
unapprovedTxs,
})
: sign({ data, selectedToken, to, amount, from, gas, gasPrice })
: sign({ data, sendToken, to, amount, from, gas, gasPrice })
Promise.resolve(promise)
.then(() => {
@ -101,8 +101,8 @@ export default class SendFooter extends Component {
}
formShouldBeDisabled () {
const { data, inError, selectedToken, tokenBalance, gasTotal, to, gasLimit, gasIsLoading } = this.props
const missingTokenBalance = selectedToken && !tokenBalance
const { data, inError, sendToken, tokenBalance, gasTotal, to, gasLimit, gasIsLoading } = this.props
const missingTokenBalance = sendToken && !tokenBalance
const gasLimitTooLow = gasLimit < 5208 // 5208 is hex value of 21000, minimum gas limit
const shouldBeDisabled = inError || !gasTotal || missingTokenBalance || !(data || to) || gasLimitTooLow || gasIsLoading
return shouldBeDisabled

@ -11,7 +11,7 @@ import {
getGasLimit,
getGasPrice,
getGasTotal,
getSelectedToken,
getSendToken,
getSendAmount,
getSendEditingTransactionId,
getSendFromObject,
@ -54,7 +54,7 @@ function mapStateToProps (state) {
gasPrice: getGasPrice(state),
gasTotal: getGasTotal(state),
inError: isSendFormInError(state),
selectedToken: getSelectedToken(state),
sendToken: getSendToken(state),
to: getSendTo(state),
toAccounts: getSendToAccounts(state),
tokenBalance: getTokenBalance(state),
@ -68,19 +68,19 @@ function mapStateToProps (state) {
function mapDispatchToProps (dispatch) {
return {
clearSend: () => dispatch(clearSend()),
sign: ({ selectedToken, to, amount, from, gas, gasPrice, data }) => {
sign: ({ sendToken, to, amount, from, gas, gasPrice, data }) => {
const txParams = constructTxParams({
amount,
data,
from,
gas,
gasPrice,
selectedToken,
sendToken,
to,
})
selectedToken
? dispatch(signTokenTx(selectedToken.address, to, amount, txParams))
sendToken
? dispatch(signTokenTx(sendToken.address, to, amount, txParams))
: dispatch(signTx(txParams))
},
update: ({
@ -90,7 +90,7 @@ function mapDispatchToProps (dispatch) {
from,
gas,
gasPrice,
selectedToken,
sendToken,
to,
unapprovedTxs,
}) => {
@ -101,7 +101,7 @@ function mapDispatchToProps (dispatch) {
from,
gas,
gasPrice,
selectedToken,
sendToken,
to,
unapprovedTxs,
})

@ -8,7 +8,7 @@ export function addHexPrefixToObjectValues (obj) {
}, {})
}
export function constructTxParams ({ selectedToken, data, to, amount, from, gas, gasPrice }) {
export function constructTxParams ({ sendToken, data, to, amount, from, gas, gasPrice }) {
const txParams = {
data,
from,
@ -17,7 +17,7 @@ export function constructTxParams ({ selectedToken, data, to, amount, from, gas,
gasPrice,
}
if (!selectedToken) {
if (!sendToken) {
txParams.value = amount
txParams.to = to
}
@ -32,7 +32,7 @@ export function constructUpdatedTx ({
from,
gas,
gasPrice,
selectedToken,
sendToken,
to,
unapprovedTxs,
}) {
@ -54,7 +54,7 @@ export function constructUpdatedTx ({
),
}
if (selectedToken) {
if (sendToken) {
const data = TOKEN_TRANSFER_FUNCTION_SIGNATURE + Array.prototype.map.call(
ethAbi.rawEncode(['address', 'uint256'], [to, ethUtil.addHexPrefix(amount)]),
(x) => ('00' + x.toString(16)).slice(-2)
@ -62,7 +62,7 @@ export function constructUpdatedTx ({
Object.assign(editingTx.txParams, addHexPrefixToObjectValues({
value: '0',
to: selectedToken.address,
to: sendToken.address,
data,
}))
}

@ -40,7 +40,7 @@ describe('SendFooter Component', function () {
gasTotal="mockGasTotal"
history={historySpies}
inError={false}
selectedToken={{ mockProp: 'mockSelectedTokenProp' }}
sendToken={{ mockProp: 'mockSendTokenProp' }}
sign={propsMethodSpies.sign}
to="mockTo"
toAccounts={['mockAccount']}
@ -103,8 +103,8 @@ describe('SendFooter Component', function () {
expectedResult: true,
gasIsLoading: false,
},
'should return true if selectedToken is truthy and tokenBalance is falsy': {
selectedToken: { mockProp: 'mockSelectedTokenProp' },
'should return true if sendToken is truthy and tokenBalance is falsy': {
sendToken: { mockProp: 'mockSendTokenProp' },
tokenBalance: '',
expectedResult: true,
gasIsLoading: false,
@ -112,7 +112,7 @@ describe('SendFooter Component', function () {
'should return true if gasIsLoading is truthy but all other params are falsy': {
inError: false,
gasTotal: '',
selectedToken: null,
sendToken: null,
tokenBalance: '',
expectedResult: true,
gasIsLoading: true,
@ -120,7 +120,7 @@ describe('SendFooter Component', function () {
'should return false if inError is false and all other params are truthy': {
inError: false,
gasTotal: '0x123',
selectedToken: { mockProp: 'mockSelectedTokenProp' },
sendToken: { mockProp: 'mockSendTokenProp' },
tokenBalance: '123',
expectedResult: false,
gasIsLoading: false,
@ -157,7 +157,7 @@ describe('SendFooter Component', function () {
from: 'mockAddress',
gas: 'mockGasLimit',
gasPrice: 'mockGasPrice',
selectedToken: { mockProp: 'mockSelectedTokenProp' },
sendToken: { mockProp: 'mockSendTokenProp' },
to: 'mockTo',
unapprovedTxs: {},
}
@ -180,7 +180,7 @@ describe('SendFooter Component', function () {
from: 'mockAddress',
gas: 'mockGasLimit',
gasPrice: 'mockGasPrice',
selectedToken: { mockProp: 'mockSelectedTokenProp' },
sendToken: { mockProp: 'mockSendTokenProp' },
to: 'mockTo',
}
)
@ -214,7 +214,7 @@ describe('SendFooter Component', function () {
gasTotal="mockGasTotal"
history={historySpies}
inError={false}
selectedToken={{ mockProp: 'mockSelectedTokenProp' }}
sendToken={{ mockProp: 'mockSendTokenProp' }}
sign={propsMethodSpies.sign}
to="mockTo"
toAccounts={['mockAccount']}

@ -31,7 +31,7 @@ proxyquire('../send-footer.container.js', {
getGasLimit: (s) => `mockGasLimit:${s}`,
getGasPrice: (s) => `mockGasPrice:${s}`,
getGasTotal: (s) => `mockGasTotal:${s}`,
getSelectedToken: (s) => `mockSelectedToken:${s}`,
getSendToken: (s) => `mockSendToken:${s}`,
getSendAmount: (s) => `mockAmount:${s}`,
getSendEditingTransactionId: (s) => `mockEditingTransactionId:${s}`,
getSendFromObject: (s) => `mockFromObject:${s}`,
@ -69,9 +69,9 @@ describe('send-footer container', function () {
})
describe('sign()', function () {
it('should dispatch a signTokenTx action if selectedToken is defined', function () {
it('should dispatch a signTokenTx action if sendToken is defined', function () {
mapDispatchToPropsObject.sign({
selectedToken: {
sendToken: {
address: '0xabc',
},
to: 'mockTo',
@ -85,7 +85,7 @@ describe('send-footer container', function () {
utilsStubs.constructTxParams.getCall(0).args[0],
{
data: undefined,
selectedToken: {
sendToken: {
address: '0xabc',
},
to: 'mockTo',
@ -101,7 +101,7 @@ describe('send-footer container', function () {
)
})
it('should dispatch a sign action if selectedToken is not defined', function () {
it('should dispatch a sign action if sendToken is not defined', function () {
utilsStubs.constructTxParams.resetHistory()
mapDispatchToPropsObject.sign({
to: 'mockTo',
@ -115,7 +115,7 @@ describe('send-footer container', function () {
utilsStubs.constructTxParams.getCall(0).args[0],
{
data: undefined,
selectedToken: undefined,
sendToken: undefined,
to: 'mockTo',
amount: 'mockAmount',
from: 'mockFrom',
@ -139,7 +139,7 @@ describe('send-footer container', function () {
gas: 'mockGas',
gasPrice: 'mockGasPrice',
editingTransactionId: 'mockEditingTransactionId',
selectedToken: 'mockSelectedToken',
sendToken: { address: 'mockAddress' },
unapprovedTxs: 'mockUnapprovedTxs',
})
assert(dispatchSpy.calledOnce)
@ -153,7 +153,7 @@ describe('send-footer container', function () {
gas: 'mockGas',
gasPrice: 'mockGasPrice',
editingTransactionId: 'mockEditingTransactionId',
selectedToken: 'mockSelectedToken',
sendToken: { address: 'mockAddress' },
unapprovedTxs: 'mockUnapprovedTxs',
}
)

@ -69,7 +69,7 @@ describe('send-footer utils', function () {
assert.deepEqual(
constructTxParams({
data: 'someData',
selectedToken: false,
sendToken: undefined,
to: 'mockTo',
amount: 'mockAmount',
from: 'mockFrom',
@ -87,10 +87,10 @@ describe('send-footer utils', function () {
)
})
it('should return a new txParams object with value and to properties if there is no selectedToken', function () {
it('should return a new txParams object with value and to properties if there is no sendToken', function () {
assert.deepEqual(
constructTxParams({
selectedToken: false,
sendToken: undefined,
to: 'mockTo',
amount: 'mockAmount',
from: 'mockFrom',
@ -108,10 +108,10 @@ describe('send-footer utils', function () {
)
})
it('should return a new txParams object without a to property and a 0 value if there is a selectedToken', function () {
it('should return a new txParams object without a to property and a 0 value if there is a sendToken', function () {
assert.deepEqual(
constructTxParams({
selectedToken: true,
sendToken: { address: '0x0' },
to: 'mockTo',
amount: 'mockAmount',
from: 'mockFrom',
@ -137,7 +137,7 @@ describe('send-footer utils', function () {
from: 'mockFrom',
gas: 'mockGas',
gasPrice: 'mockGasPrice',
selectedToken: false,
sendToken: false,
to: 'mockTo',
unapprovedTxs: {
'0x123': {},
@ -169,7 +169,7 @@ describe('send-footer utils', function () {
from: 'mockFrom',
gas: 'mockGas',
gasPrice: 'mockGasPrice',
selectedToken: false,
sendToken: false,
to: 'mockTo',
unapprovedTxs: {
'0x123': {},
@ -196,14 +196,14 @@ describe('send-footer utils', function () {
})
})
it('should have token property values if selectedToken is truthy', function () {
it('should have token property values if sendToken is truthy', function () {
const result = constructUpdatedTx({
amount: 'mockAmount',
editingTransactionId: '0x456',
from: 'mockFrom',
gas: 'mockGas',
gasPrice: 'mockGasPrice',
selectedToken: {
sendToken: {
address: 'mockTokenAddress',
},
to: 'mockTo',

@ -34,7 +34,7 @@ export default class SendTransactionScreen extends Component {
primaryCurrency: PropTypes.string,
resetSendState: PropTypes.func.isRequired,
selectedAddress: PropTypes.string,
selectedToken: PropTypes.object,
sendToken: PropTypes.object,
showHexData: PropTypes.bool,
to: PropTypes.string,
toNickname: PropTypes.string,
@ -77,7 +77,7 @@ export default class SendTransactionScreen extends Component {
gasTotal,
network,
primaryCurrency,
selectedToken,
sendToken,
tokenBalance,
updateSendErrors,
updateSendTo,
@ -97,7 +97,7 @@ export default class SendTransactionScreen extends Component {
gasTotal: prevGasTotal,
tokenBalance: prevTokenBalance,
network: prevNetwork,
selectedToken: prevSelectedToken,
sendToken: prevSendToken,
to: prevTo,
} = prevProps
@ -109,7 +109,7 @@ export default class SendTransactionScreen extends Component {
prevBalance,
prevGasTotal,
prevTokenBalance,
selectedToken,
sendToken,
tokenBalance,
})
@ -120,16 +120,16 @@ export default class SendTransactionScreen extends Component {
conversionRate,
gasTotal,
primaryCurrency,
selectedToken,
sendToken,
tokenBalance,
})
const gasFeeErrorObject = selectedToken
const gasFeeErrorObject = sendToken
? getGasFeeErrorObject({
balance,
conversionRate,
gasTotal,
primaryCurrency,
selectedToken,
sendToken,
})
: { gasFee: null }
updateSendErrors(Object.assign(amountErrorObject, gasFeeErrorObject))
@ -139,7 +139,7 @@ export default class SendTransactionScreen extends Component {
if (network !== prevNetwork && network !== 'loading') {
updateSendTokenBalance({
selectedToken,
sendToken,
tokenContract,
address,
})
@ -148,10 +148,10 @@ export default class SendTransactionScreen extends Component {
}
}
const prevTokenAddress = prevSelectedToken && prevSelectedToken.address
const selectedTokenAddress = selectedToken && selectedToken.address
const prevTokenAddress = prevSendToken && prevSendToken.address
const sendTokenAddress = sendToken && sendToken.address
if (selectedTokenAddress && prevTokenAddress !== selectedTokenAddress) {
if (sendTokenAddress && prevTokenAddress !== sendTokenAddress) {
this.updateSendToken()
updateGas = true
}
@ -220,7 +220,7 @@ export default class SendTransactionScreen extends Component {
const {
hasHexData,
tokens,
selectedToken,
sendToken,
network,
} = this.props
@ -228,8 +228,8 @@ export default class SendTransactionScreen extends Component {
return this.setState({ toError: '', toWarning: '' })
}
const toErrorObject = getToErrorObject(query, hasHexData, tokens, selectedToken, network)
const toWarningObject = getToWarningObject(query, tokens, selectedToken)
const toErrorObject = getToErrorObject(query, hasHexData, tokens, sendToken, network)
const toWarningObject = getToWarningObject(query, tokens, sendToken)
this.setState({
toError: toErrorObject.to,
@ -240,13 +240,13 @@ export default class SendTransactionScreen extends Component {
updateSendToken () {
const {
from: { address },
selectedToken,
sendToken,
tokenContract,
updateSendTokenBalance,
} = this.props
updateSendTokenBalance({
selectedToken,
sendToken,
tokenContract,
address,
})
@ -260,7 +260,7 @@ export default class SendTransactionScreen extends Component {
gasLimit,
gasPrice,
selectedAddress,
selectedToken = {},
sendToken = {},
to: currentToAddress,
updateAndSetGasLimit,
} = this.props
@ -271,7 +271,7 @@ export default class SendTransactionScreen extends Component {
gasLimit,
gasPrice,
selectedAddress,
selectedToken,
sendToken,
to: getToAddressForGasUpdate(updatedToAddress, currentToAddress),
value: value || amount,
data,

@ -11,8 +11,8 @@ import {
getGasPrice,
getGasTotal,
getPrimaryCurrency,
getSelectedToken,
getSelectedTokenContract,
getSendToken,
getSendTokenContract,
getSendAmount,
getSendEditingTransactionId,
getSendHexDataFeatureFlagState,
@ -67,13 +67,13 @@ function mapStateToProps (state) {
primaryCurrency: getPrimaryCurrency(state),
qrCodeData: getQrCodeData(state),
selectedAddress: getSelectedAddress(state),
selectedToken: getSelectedToken(state),
sendToken: getSendToken(state),
showHexData: getSendHexDataFeatureFlagState(state),
to: getSendTo(state),
toNickname: getSendToNickname(state),
tokens: getTokens(state),
tokenBalance: getTokenBalance(state),
tokenContract: getSelectedTokenContract(state),
tokenContract: getSendTokenContract(state),
}
}
@ -85,18 +85,18 @@ function mapDispatchToProps (dispatch) {
gasLimit,
gasPrice,
selectedAddress,
selectedToken,
sendToken,
to,
value,
data,
}) => {
!editingTransactionId
? dispatch(updateGasData({ gasPrice, selectedAddress, selectedToken, blockGasLimit, to, value, data }))
? dispatch(updateGasData({ gasPrice, selectedAddress, sendToken, blockGasLimit, to, value, data }))
: dispatch(setGasTotal(calcGasTotal(gasLimit, gasPrice)))
},
updateSendTokenBalance: ({ selectedToken, tokenContract, address }) => {
updateSendTokenBalance: ({ sendToken, tokenContract, address }) => {
dispatch(updateSendTokenBalance({
selectedToken,
sendToken,
tokenContract,
address,
}))

@ -105,11 +105,11 @@ function getAmountErrorObject ({
conversionRate,
gasTotal,
primaryCurrency,
selectedToken,
sendToken,
tokenBalance,
}) {
let insufficientFunds = false
if (gasTotal && conversionRate && !selectedToken) {
if (gasTotal && conversionRate && !sendToken) {
insufficientFunds = !isBalanceSufficient({
amount,
balance,
@ -120,8 +120,8 @@ function getAmountErrorObject ({
}
let inSufficientTokens = false
if (selectedToken && tokenBalance !== null) {
const { decimals } = selectedToken
if (sendToken && tokenBalance !== null) {
const { decimals } = sendToken
inSufficientTokens = !isTokenBalanceSufficient({
tokenBalance,
amount,
@ -172,8 +172,8 @@ function getGasFeeErrorObject ({
return { gasFee: gasFeeError }
}
function calcTokenBalance ({ selectedToken, usersToken }) {
const { decimals } = selectedToken || {}
function calcTokenBalance ({ sendToken, usersToken }) {
const { decimals } = sendToken || {}
return calcTokenAmount(usersToken.balance.toString(), decimals).toString(16)
}
@ -183,12 +183,12 @@ function doesAmountErrorRequireUpdate ({
prevBalance,
prevGasTotal,
prevTokenBalance,
selectedToken,
sendToken,
tokenBalance,
}) {
const balanceHasChanged = balance !== prevBalance
const gasTotalHasChange = gasTotal !== prevGasTotal
const tokenBalanceHasChanged = selectedToken && tokenBalance !== prevTokenBalance
const tokenBalanceHasChanged = sendToken && tokenBalance !== prevTokenBalance
const amountErrorRequiresUpdate = balanceHasChanged || gasTotalHasChange || tokenBalanceHasChanged
return amountErrorRequiresUpdate
@ -196,7 +196,7 @@ function doesAmountErrorRequireUpdate ({
async function estimateGas ({
selectedAddress,
selectedToken,
sendToken,
blockGasLimit = MIN_GAS_LIMIT_HEX,
to,
value,
@ -207,21 +207,21 @@ async function estimateGas ({
const paramsForGasEstimate = { from: selectedAddress, value, gasPrice }
// if recipient has no code, gas is 21k max:
if (!selectedToken && !data) {
if (!sendToken && !data) {
const code = Boolean(to) && await global.eth.getCode(to)
// Geth will return '0x', and ganache-core v2.2.1 will return '0x0'
const codeIsEmpty = !code || code === '0x' || code === '0x0'
if (codeIsEmpty) {
return SIMPLE_GAS_COST
}
} else if (selectedToken && !to) {
} else if (sendToken && !to) {
return BASE_TOKEN_GAS_COST
}
if (selectedToken) {
if (sendToken) {
paramsForGasEstimate.value = '0x0'
paramsForGasEstimate.data = generateTokenTransferData({ toAddress: to, amount: value, selectedToken })
paramsForGasEstimate.to = selectedToken.address
paramsForGasEstimate.data = generateTokenTransferData({ toAddress: to, amount: value, sendToken })
paramsForGasEstimate.to = sendToken.address
} else {
if (data) {
paramsForGasEstimate.data = data
@ -299,8 +299,8 @@ function addGasBuffer (initialGasLimitHex, blockGasLimitHex, bufferMultiplier =
return upperGasLimit
}
function generateTokenTransferData ({ toAddress = '0x0', amount = '0x0', selectedToken }) {
if (!selectedToken) {
function generateTokenTransferData ({ toAddress = '0x0', amount = '0x0', sendToken }) {
if (!sendToken) {
return
}
return TOKEN_TRANSFER_FUNCTION_SIGNATURE + Array.prototype.map.call(

@ -58,7 +58,7 @@ describe('Send Component', function () {
network="3"
primaryCurrency="mockPrimaryCurrency"
selectedAddress="mockSelectedAddress"
selectedToken={{ address: 'mockTokenAddress', decimals: 18, symbol: 'TST' }}
sendToken={{ address: 'mockTokenAddress', decimals: 18, symbol: 'TST' }}
showHexData
tokenBalance="mockTokenBalance"
tokenContract={{ method: 'mockTokenMethod' }}
@ -141,7 +141,7 @@ describe('Send Component', function () {
prevBalance: '',
prevGasTotal: undefined,
prevTokenBalance: undefined,
selectedToken: { address: 'mockTokenAddress', decimals: 18, symbol: 'TST' },
sendToken: { address: 'mockTokenAddress', decimals: 18, symbol: 'TST' },
tokenBalance: 'mockTokenBalance',
}
)
@ -173,13 +173,13 @@ describe('Send Component', function () {
conversionRate: 10,
gasTotal: 'mockGasTotal',
primaryCurrency: 'mockPrimaryCurrency',
selectedToken: { address: 'mockTokenAddress', decimals: 18, symbol: 'TST' },
sendToken: { address: 'mockTokenAddress', decimals: 18, symbol: 'TST' },
tokenBalance: 'mockTokenBalance',
}
)
})
it('should call getGasFeeErrorObject if doesAmountErrorRequireUpdate returns true and selectedToken is truthy', function () {
it('should call getGasFeeErrorObject if doesAmountErrorRequireUpdate returns true and sendToken is truthy', function () {
utilsMethodStubs.getGasFeeErrorObject.resetHistory()
wrapper.instance().componentDidUpdate({
from: {
@ -194,7 +194,7 @@ describe('Send Component', function () {
conversionRate: 10,
gasTotal: 'mockGasTotal',
primaryCurrency: 'mockPrimaryCurrency',
selectedToken: { address: 'mockTokenAddress', decimals: 18, symbol: 'TST' },
sendToken: { address: 'mockTokenAddress', decimals: 18, symbol: 'TST' },
}
)
})
@ -207,9 +207,9 @@ describe('Send Component', function () {
assert.equal(utilsMethodStubs.getGasFeeErrorObject.callCount, 0)
})
it('should not call getGasFeeErrorObject if doesAmountErrorRequireUpdate returns true but selectedToken is falsy', function () {
it('should not call getGasFeeErrorObject if doesAmountErrorRequireUpdate returns true but sendToken is falsy', function () {
utilsMethodStubs.getGasFeeErrorObject.resetHistory()
wrapper.setProps({ selectedToken: null })
wrapper.setProps({ sendToken: null })
wrapper.instance().componentDidUpdate({
from: {
balance: 'balanceChanged',
@ -218,9 +218,9 @@ describe('Send Component', function () {
assert.equal(utilsMethodStubs.getGasFeeErrorObject.callCount, 0)
})
it('should call updateSendErrors with the expected params if selectedToken is falsy', function () {
it('should call updateSendErrors with the expected params if sendToken is falsy', function () {
propsMethodSpies.updateSendErrors.resetHistory()
wrapper.setProps({ selectedToken: null })
wrapper.setProps({ sendToken: null })
wrapper.instance().componentDidUpdate({
from: {
balance: 'balanceChanged',
@ -233,9 +233,9 @@ describe('Send Component', function () {
)
})
it('should call updateSendErrors with the expected params if selectedToken is truthy', function () {
it('should call updateSendErrors with the expected params if sendToken is truthy', function () {
propsMethodSpies.updateSendErrors.resetHistory()
wrapper.setProps({ selectedToken: { address: 'mockTokenAddress', decimals: 18, symbol: 'TST' } })
wrapper.setProps({ sendToken: { address: 'mockTokenAddress', decimals: 18, symbol: 'TST' } })
wrapper.instance().componentDidUpdate({
from: {
balance: 'balanceChanged',
@ -256,7 +256,7 @@ describe('Send Component', function () {
balance: 'balanceChanged',
},
network: '3',
selectedToken: { address: 'mockTokenAddress', decimals: 18, symbol: 'TST' }, // Make sure not to hit updateGas when changing asset
sendToken: { address: 'mockTokenAddress', decimals: 18, symbol: 'TST' }, // Make sure not to hit updateGas when changing asset
})
assert.equal(propsMethodSpies.updateSendTokenBalance.callCount, 0)
assert.equal(SendTransactionScreen.prototype.updateGas.callCount, 0)
@ -271,7 +271,7 @@ describe('Send Component', function () {
balance: 'balanceChanged',
},
network: '3',
selectedToken: { address: 'mockTokenAddress', decimals: 18, symbol: 'TST' }, // Make sure not to hit updateGas when changing asset
sendToken: { address: 'mockTokenAddress', decimals: 18, symbol: 'TST' }, // Make sure not to hit updateGas when changing asset
})
assert.equal(propsMethodSpies.updateSendTokenBalance.callCount, 0)
assert.equal(SendTransactionScreen.prototype.updateGas.callCount, 0)
@ -285,13 +285,13 @@ describe('Send Component', function () {
balance: 'balanceChanged',
},
network: '2',
selectedToken: { address: 'mockTokenAddress', decimals: 18, symbol: 'TST' }, // Make sure not to hit updateGas when changing asset
sendToken: { address: 'mockTokenAddress', decimals: 18, symbol: 'TST' }, // Make sure not to hit updateGas when changing asset
})
assert.equal(propsMethodSpies.updateSendTokenBalance.callCount, 1)
assert.deepEqual(
propsMethodSpies.updateSendTokenBalance.getCall(0).args[0],
{
selectedToken: { address: 'mockTokenAddress', decimals: 18, symbol: 'TST' }, // Make sure not to hit updateGas when changing asset
sendToken: { address: 'mockTokenAddress', decimals: 18, symbol: 'TST' }, // Make sure not to hit updateGas when changing asset
tokenContract: { method: 'mockTokenMethod' },
address: 'mockAddress',
}
@ -303,7 +303,7 @@ describe('Send Component', function () {
)
})
it('should call updateGas when selectedToken.address is changed', function () {
it('should call updateGas when sendToken.address is changed', function () {
SendTransactionScreen.prototype.updateGas.resetHistory()
propsMethodSpies.updateAndSetGasLimit.resetHistory()
wrapper.instance().componentDidUpdate({
@ -311,7 +311,7 @@ describe('Send Component', function () {
balance: 'balancedChanged',
},
network: '3', // Make sure not to hit updateGas when changing network
selectedToken: { address: 'newSelectedToken' },
sendToken: { address: 'newSelectedToken' },
})
assert.equal(propsMethodSpies.updateToNicknameIfNecessary.callCount, 0) // Network did not change
assert.equal(propsMethodSpies.updateAndSetGasLimit.callCount, 1)
@ -331,7 +331,7 @@ describe('Send Component', function () {
gasLimit: 'mockGasLimit',
gasPrice: 'mockGasPrice',
selectedAddress: 'mockSelectedAddress',
selectedToken: { address: 'mockTokenAddress', decimals: 18, symbol: 'TST' },
sendToken: { address: 'mockTokenAddress', decimals: 18, symbol: 'TST' },
to: '',
value: 'mockAmount',
data: undefined,

@ -49,7 +49,7 @@ describe('send container', function () {
gasLimit: '0x3',
gasPrice: '0x4',
selectedAddress: '0x4',
selectedToken: { address: '0x1' },
sendToken: { address: '0x1' },
to: 'mockTo',
value: 'mockValue',
data: undefined,
@ -65,14 +65,14 @@ describe('send container', function () {
})
it('should dispatch an updateGasData action when editingTransactionId is falsy', function () {
const { gasPrice, selectedAddress, selectedToken, blockGasLimit, to, value, data } = mockProps
const { gasPrice, selectedAddress, sendToken, blockGasLimit, to, value, data } = mockProps
mapDispatchToPropsObject.updateAndSetGasLimit(
Object.assign({}, mockProps, { editingTransactionId: false })
)
assert(dispatchSpy.calledOnce)
assert.deepEqual(
actionSpies.updateGasData.getCall(0).args[0],
{ gasPrice, selectedAddress, selectedToken, blockGasLimit, to, value, data }
{ gasPrice, selectedAddress, sendToken, blockGasLimit, to, value, data }
)
})
})
@ -81,7 +81,7 @@ describe('send container', function () {
const mockProps = {
address: '0x10',
tokenContract: '0x00a',
selectedToken: { address: '0x1' },
sendToken: { address: '0x1' },
}
it('should dispatch an action', function () {

@ -89,7 +89,7 @@ describe('send utils', function () {
'should return true if token balances are different': {
tokenBalance: 0,
prevTokenBalance: 1,
selectedToken: 'someToken',
sendToken: { address: '0x0' },
expectedResult: true,
},
'should return false if they are all the same': {
@ -99,7 +99,7 @@ describe('send utils', function () {
prevGasTotal: 1,
tokenBalance: 1,
prevTokenBalance: 1,
selectedToken: 'someToken',
sendToken: { address: '0x0' },
expectedResult: false,
},
}
@ -112,13 +112,13 @@ describe('send utils', function () {
})
describe('generateTokenTransferData()', function () {
it('should return undefined if not passed a selected token', function () {
assert.equal(generateTokenTransferData({ toAddress: 'mockAddress', amount: '0xa', selectedToken: false }), undefined)
it('should return undefined if not passed a send token', function () {
assert.equal(generateTokenTransferData({ toAddress: 'mockAddress', amount: '0xa', sendToken: undefined }), undefined)
})
it('should call abi.rawEncode with the correct params', function () {
stubs.rawEncode.resetHistory()
generateTokenTransferData({ toAddress: 'mockAddress', amount: 'ab', selectedToken: true })
generateTokenTransferData({ toAddress: 'mockAddress', amount: 'ab', sendToken: { address: '0x0' } })
assert.deepEqual(
stubs.rawEncode.getCall(0).args,
[['address', 'uint256'], ['mockAddress', '0xab']]
@ -127,7 +127,7 @@ describe('send utils', function () {
it('should return encoded token transfer data', function () {
assert.equal(
generateTokenTransferData({ toAddress: 'mockAddress', amount: '0xa', selectedToken: true }),
generateTokenTransferData({ toAddress: 'mockAddress', amount: '0xa', sendToken: { address: '0x0' } }),
'0xa9059cbb104c'
)
})
@ -143,13 +143,13 @@ describe('send utils', function () {
primaryCurrency: 'ABC',
expectedResult: { amount: INSUFFICIENT_FUNDS_ERROR },
},
'should not return insufficientFunds error if selectedToken is truthy': {
'should not return insufficientFunds error if sendToken is truthy': {
amount: '0x0',
balance: 1,
conversionRate: 3,
gasTotal: 17,
primaryCurrency: 'ABC',
selectedToken: { symbole: 'DEF', decimals: 0 },
sendToken: { address: '0x0', symbol: 'DEF', decimals: 0 },
decimals: 0,
tokenBalance: 'sometokenbalance',
expectedResult: { amount: null },
@ -161,7 +161,7 @@ describe('send utils', function () {
decimals: 10,
gasTotal: 17,
primaryCurrency: 'ABC',
selectedToken: 'someToken',
sendToken: { address: '0x0' },
tokenBalance: 123,
expectedResult: { amount: INSUFFICIENT_TOKENS_ERROR },
},
@ -200,7 +200,8 @@ describe('send utils', function () {
describe('calcTokenBalance()', function () {
it('should return the calculated token blance', function () {
assert.equal(calcTokenBalance({
selectedToken: {
sendToken: {
address: '0x0',
decimals: 11,
},
usersToken: {
@ -340,8 +341,8 @@ describe('send utils', function () {
assert.equal(result, '0xabc16x1.5')
})
it('should call ethQuery.estimateGas with a value of 0x0 and the expected data and to if passed a selectedToken', async function () {
const result = await estimateGas(Object.assign({ data: 'mockData', selectedToken: { address: 'mockAddress' } }, baseMockParams))
it('should call ethQuery.estimateGas with a value of 0x0 and the expected data and to if passed a sendToken', async function () {
const result = await estimateGas(Object.assign({ data: 'mockData', sendToken: { address: 'mockAddress' } }, baseMockParams))
assert.equal(baseMockParams.estimateGasMethod.callCount, 1)
assert.deepEqual(
baseMockParams.estimateGasMethod.getCall(0).args[0],
@ -373,20 +374,20 @@ describe('send utils', function () {
assert.equal(result, SIMPLE_GAS_COST)
})
it(`should return ${SIMPLE_GAS_COST} if not passed a selectedToken or truthy to address`, async function () {
it(`should return ${SIMPLE_GAS_COST} if not passed a sendToken or truthy to address`, async function () {
assert.equal(baseMockParams.estimateGasMethod.callCount, 0)
const result = await estimateGas(Object.assign({}, baseMockParams, { to: null }))
assert.equal(result, SIMPLE_GAS_COST)
})
it(`should not return ${SIMPLE_GAS_COST} if passed a selectedToken`, async function () {
it(`should not return ${SIMPLE_GAS_COST} if passed a sendToken`, async function () {
assert.equal(baseMockParams.estimateGasMethod.callCount, 0)
const result = await estimateGas(Object.assign({}, baseMockParams, { to: '0x123', selectedToken: { address: '' } }))
const result = await estimateGas(Object.assign({}, baseMockParams, { to: '0x123', sendToken: { address: '0x0' } }))
assert.notEqual(result, SIMPLE_GAS_COST)
})
it(`should return ${BASE_TOKEN_GAS_COST} if passed a selectedToken but no to address`, async function () {
const result = await estimateGas(Object.assign({}, baseMockParams, { to: null, selectedToken: { address: '' } }))
it(`should return ${BASE_TOKEN_GAS_COST} if passed a sendToken but no to address`, async function () {
const result = await estimateGas(Object.assign({}, baseMockParams, { to: null, sendToken: { address: '0x0' } }))
assert.equal(result, BASE_TOKEN_GAS_COST)
})

@ -6,9 +6,18 @@ import {
checksumAddress,
getAccountByAddress,
} from '../helpers/utils/util'
import {
getSelectedToken,
} from '.'
import { getSendToken } from './send'
import { getTokens } from '../ducks/metamask/metamask'
export const getSelectedTokenAddress = (state) => state.metamask.selectedTokenAddress
export const getSelectedToken = createSelector(
getTokens,
getSelectedTokenAddress,
(tokens, selectedTokenAddress) => {
return tokens.find(({ address }) => address === selectedTokenAddress)
}
)
export function getNetworkIdentifier (state) {
const { metamask: { provider: { type, nickname, rpcTarget } } } = state
@ -48,10 +57,14 @@ export function getAccountType (state) {
}
}
export function getSelectedAsset (state) {
const selectedToken = getSelectedToken(state)
return (selectedToken && selectedToken.symbol) || 'ETH'
}
export const getSelectedAsset = createSelector(
getSelectedToken,
getSendToken,
(selectedToken, sendToken) => {
const token = selectedToken || sendToken
return token?.symbol || 'ETH'
}
)
export function getCurrentNetworkId (state) {
return state.metamask.network
@ -314,7 +327,7 @@ export function getTargetDomainMetadata (state, request, defaultOrigin) {
return targetDomainMetadata
}
export function getMetaMetricState (state) {
export const getMetaMetricState = (state) => {
return {
network: getCurrentNetworkId(state),
activeCurrency: getSelectedAsset(state),

@ -37,23 +37,22 @@ export function getGasTotal (state) {
}
export function getPrimaryCurrency (state) {
const selectedToken = getSelectedToken(state)
return selectedToken && selectedToken.symbol
const sendToken = getSendToken(state)
return sendToken?.symbol
}
export function getSelectedToken (state) {
const tokens = state.metamask.tokens || []
const selectedTokenAddress = state.metamask.selectedTokenAddress
const selectedToken = tokens.filter(({ address }) => address === selectedTokenAddress)[0]
const sendToken = state.metamask?.send.token
export function getSendToken (state) {
return state.metamask.send.token
}
return selectedToken || sendToken || null
export function getSendTokenAddress (state) {
return getSendToken(state)?.address
}
export function getSelectedTokenContract (state) {
const selectedToken = getSelectedToken(state)
return selectedToken
? global.eth.contract(abi).at(selectedToken.address)
export function getSendTokenContract (state) {
const sendTokenAddress = getSendTokenAddress(state)
return sendTokenAddress
? global.eth.contract(abi).at(sendTokenAddress)
: null
}
@ -148,7 +147,7 @@ export function getGasButtonGroupShown (state) {
export function getTitleKey (state) {
const isEditing = Boolean(getSendEditingTransactionId(state))
const isToken = Boolean(getSelectedToken(state))
const isToken = Boolean(getSendToken(state))
if (!getSendTo(state)) {
return 'addRecipient'

@ -13,8 +13,8 @@ import {
getGasPrice,
getGasTotal,
getPrimaryCurrency,
getSelectedToken,
getSelectedTokenContract,
getSendToken,
getSendTokenContract,
getSendAmount,
sendAmountIsInError,
getSendEditingTransactionId,
@ -167,18 +167,28 @@ describe('send selectors', function () {
})
describe('getPrimaryCurrency()', function () {
it('should return the symbol of the selected token', function () {
it('should return the symbol of the send token', function () {
assert.equal(
getPrimaryCurrency(mockState),
getPrimaryCurrency({ metamask: { send: { token: { symbol: 'DEF' } } } }),
'DEF'
)
})
})
describe('getSelectedToken()', function () {
it('should return the currently selected token if selected', function () {
describe('getSendToken()', function () {
it('should return the current send token if set', function () {
assert.deepEqual(
getSelectedToken(mockState),
getSendToken({
metamask: {
send: {
token: {
address: '0x8d6b81208414189a58339873ab429b6c47ab92d3',
decimals: 4,
symbol: 'DEF',
},
},
},
}),
{
address: '0x8d6b81208414189a58339873ab429b6c47ab92d3',
decimals: 4,
@ -186,40 +196,30 @@ describe('send selectors', function () {
}
)
})
it('should return the send token if none is currently selected, but a send token exists', function () {
const mockSendToken = {
address: '0x123456708414189a58339873ab429b6c47ab92d3',
decimals: 4,
symbol: 'JKL',
}
const editedMockState = {
metamask: Object.assign({}, mockState.metamask, {
selectedTokenAddress: null,
send: {
token: mockSendToken,
},
}),
}
assert.deepEqual(
getSelectedToken(editedMockState),
Object.assign({}, mockSendToken)
)
})
})
describe('getSelectedTokenContract()', function () {
it('should return the contract at the selected token address', function () {
describe('getSendTokenContract()', function () {
it('should return the contract at the send token address', function () {
assert.equal(
getSelectedTokenContract(mockState),
getSendTokenContract({
metamask: {
send: {
token: {
address: '0x8d6b81208414189a58339873ab429b6c47ab92d3',
decimals: 4,
symbol: 'DEF',
},
},
},
}),
'mockAt:0x8d6b81208414189a58339873ab429b6c47ab92d3'
)
})
it('should return null if no token is selected', function () {
const modifiedMetamaskState = Object.assign({}, mockState.metamask, { selectedTokenAddress: false })
it('should return null if send token is not set', function () {
const modifiedMetamaskState = Object.assign({}, mockState.metamask, { send: {} })
assert.equal(
getSelectedTokenContract(Object.assign({}, mockState, { metamask: modifiedMetamaskState })),
getSendTokenContract(Object.assign({}, mockState, { metamask: modifiedMetamaskState })),
null
)
})
@ -530,29 +530,29 @@ describe('send selectors', function () {
getMetamaskSendMockState({
to: true,
editingTransactionId: true,
token: true, // this can be whatever
token: {},
})
), 'edit')
})
it('should return the correct key when getSendEditingTransactionId is falsy and getSelectedToken is truthy', function () {
it('should return the correct key when getSendEditingTransactionId is falsy and getSendToken is truthy', function () {
assert.equal(
getTitleKey(
getMetamaskSendMockState({
to: true,
editingTransactionId: false,
token: true,
token: {},
})
), 'sendTokens')
})
it('should return the correct key when getSendEditingTransactionId is falsy and getSelectedToken is falsy', function () {
it('should return the correct key when getSendEditingTransactionId is falsy and getSendToken is falsy', function () {
assert.equal(
getTitleKey(
getMetamaskSendMockState({
to: true,
editingTransactionId: false,
token: false,
token: null,
})
), 'sendETH')
})

@ -607,7 +607,7 @@ export function updateGasData ({
gasPrice,
blockGasLimit,
selectedAddress,
selectedToken,
sendToken,
to,
value,
data,
@ -618,7 +618,7 @@ export function updateGasData ({
estimateGasMethod: promisifiedBackground.estimateGas,
blockGasLimit,
selectedAddress,
selectedToken,
sendToken,
to,
value,
estimateGasPrice: gasPrice,
@ -651,7 +651,7 @@ export function gasLoadingFinished () {
}
export function updateSendTokenBalance ({
selectedToken,
sendToken,
tokenContract,
address,
}) {
@ -662,7 +662,7 @@ export function updateSendTokenBalance ({
return tokenBalancePromise
.then((usersToken) => {
if (usersToken) {
const newTokenBalance = calcTokenBalance({ selectedToken, usersToken })
const newTokenBalance = calcTokenBalance({ sendToken, usersToken })
dispatch(setSendTokenBalance(newTokenBalance))
}
})

Loading…
Cancel
Save