1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-12-23 09:52:26 +01:00

Prevent send to token (#6051)

* check contact metadata

* check for tokens in state

* tests

* update tests

* validation only if sending tokens

* container test
This commit is contained in:
Esteban Miño 2019-01-22 16:05:59 -03:00 committed by Dan Finlay
parent 2cfea0b788
commit 1d93d9a385
9 changed files with 66 additions and 3 deletions

View File

@ -648,6 +648,9 @@
"invalidAddressRecipient": {
"message": "Recipient address is invalid"
},
"knownAddressRecipient": {
"message": "Known contract address."
},
"invalidGasParams": {
"message": "Invalid Gas Parameters"
},

View File

@ -12,9 +12,11 @@ export default class SendToRow extends Component {
inError: PropTypes.bool,
network: PropTypes.string,
openToDropdown: PropTypes.func,
selectedToken: PropTypes.object,
to: PropTypes.string,
toAccounts: PropTypes.array,
toDropdownOpen: PropTypes.bool,
tokens: PropTypes.array,
updateGas: PropTypes.func,
updateSendTo: PropTypes.func,
updateSendToError: PropTypes.func,
@ -26,8 +28,8 @@ export default class SendToRow extends Component {
}
handleToChange (to, nickname = '', toError) {
const { hasHexData, updateSendTo, updateSendToError, updateGas } = this.props
const toErrorObject = getToErrorObject(to, toError, hasHexData)
const { hasHexData, updateSendTo, updateSendToError, updateGas, tokens, selectedToken } = this.props
const toErrorObject = getToErrorObject(to, toError, hasHexData, tokens, selectedToken)
updateSendTo(to, nickname)
updateSendToError(toErrorObject)
if (toErrorObject.to === null) {

View File

@ -1,12 +1,14 @@
import { connect } from 'react-redux'
import {
getCurrentNetwork,
getSelectedToken,
getSendTo,
getSendToAccounts,
getSendHexData,
} from '../../send.selectors.js'
import {
getToDropdownOpen,
getTokens,
sendToIsInError,
} from './send-to-row.selectors.js'
import {
@ -26,9 +28,11 @@ function mapStateToProps (state) {
hasHexData: Boolean(getSendHexData(state)),
inError: sendToIsInError(state),
network: getCurrentNetwork(state),
selectedToken: getSelectedToken(state),
to: getSendTo(state),
toAccounts: getSendToAccounts(state),
toDropdownOpen: getToDropdownOpen(state),
tokens: getTokens(state),
}
}

View File

@ -1,5 +1,6 @@
const selectors = {
getToDropdownOpen,
getTokens,
sendToIsInError,
}
@ -12,3 +13,7 @@ function getToDropdownOpen (state) {
function sendToIsInError (state) {
return Boolean(state.send.errors.to)
}
function getTokens (state) {
return state.metamask.tokens
}

View File

@ -1,16 +1,23 @@
const {
REQUIRED_ERROR,
INVALID_RECIPIENT_ADDRESS_ERROR,
KNOWN_RECIPIENT_ADDRESS_ERROR,
} = require('../../send.constants')
const { isValidAddress } = require('../../../../util')
import { checkExistingAddresses } from '../../../pages/add-token/util'
function getToErrorObject (to, toError = null, hasHexData = false) {
const ethUtil = require('ethereumjs-util')
const contractMap = require('eth-contract-metadata')
function getToErrorObject (to, toError = null, hasHexData = false, tokens = [], selectedToken = null) {
if (!to) {
if (!hasHexData) {
toError = REQUIRED_ERROR
}
} else if (!isValidAddress(to) && !toError) {
toError = INVALID_RECIPIENT_ADDRESS_ERROR
} else if (selectedToken && (ethUtil.toChecksumAddress(to) in contractMap || checkExistingAddresses(to, tokens))) {
toError = KNOWN_RECIPIENT_ADDRESS_ERROR
}
return { to: toError }

View File

@ -24,6 +24,7 @@ proxyquire('../send-to-row.container.js', {
},
'../../send.selectors.js': {
getCurrentNetwork: (s) => `mockNetwork:${s}`,
getSelectedToken: (s) => `mockSelectedToken:${s}`,
getSendHexData: (s) => s,
getSendTo: (s) => `mockTo:${s}`,
getSendToAccounts: (s) => `mockToAccounts:${s}`,
@ -31,6 +32,7 @@ proxyquire('../send-to-row.container.js', {
'./send-to-row.selectors.js': {
getToDropdownOpen: (s) => `mockToDropdownOpen:${s}`,
sendToIsInError: (s) => `mockInError:${s}`,
getTokens: (s) => `mockTokens:${s}`,
},
'../../../../actions': actionSpies,
'../../../../ducks/send.duck': duckActionSpies,
@ -45,9 +47,11 @@ describe('send-to-row container', () => {
hasHexData: true,
inError: 'mockInError:mockState',
network: 'mockNetwork:mockState',
selectedToken: 'mockSelectedToken:mockState',
to: 'mockTo:mockState',
toAccounts: 'mockToAccounts:mockState',
toDropdownOpen: 'mockToDropdownOpen:mockState',
tokens: 'mockTokens:mockState',
})
})

View File

@ -1,6 +1,7 @@
import assert from 'assert'
import {
getToDropdownOpen,
getTokens,
sendToIsInError,
} from '../send-to-row.selectors.js'
@ -44,4 +45,15 @@ describe('send-to-row selectors', () => {
})
})
describe('getTokens()', () => {
it('should return empty array if no tokens in state', () => {
const state = {
metamask: {
tokens: [],
},
}
assert.deepStrictEqual(getTokens(state), [])
})
})
})

View File

@ -5,6 +5,7 @@ import sinon from 'sinon'
import {
REQUIRED_ERROR,
INVALID_RECIPIENT_ADDRESS_ERROR,
KNOWN_RECIPIENT_ADDRESS_ERROR,
} from '../../../send.constants'
const stubs = {
@ -52,6 +53,29 @@ describe('send-to-row utils', () => {
to: 'someExplicitError',
})
})
it('should return a known address recipient if to is truthy but part of state tokens', () => {
assert.deepEqual(getToErrorObject('0xabc123', undefined, false, [{'address': '0xabc123'}], {'address': '0xabc123'}), {
to: KNOWN_RECIPIENT_ADDRESS_ERROR,
})
})
it('should null if to is truthy part of tokens but selectedToken falsy', () => {
assert.deepEqual(getToErrorObject('0xabc123', undefined, false, [{'address': '0xabc123'}]), {
to: null,
})
})
it('should return a known address recipient if to is truthy but part of contract metadata', () => {
assert.deepEqual(getToErrorObject('0x89d24a6b4ccb1b6faa2625fe562bdd9a23260359', undefined, false, [{'address': '0xabc123'}], {'address': '0xabc123'}), {
to: KNOWN_RECIPIENT_ADDRESS_ERROR,
})
})
it('should null if to is truthy part of contract metadata but selectedToken falsy', () => {
assert.deepEqual(getToErrorObject('0x89d24a6b4ccb1b6faa2625fe562bdd9a23260359', undefined, false, [{'address': '0xabc123'}], {'address': '0xabc123'}), {
to: KNOWN_RECIPIENT_ADDRESS_ERROR,
})
})
})
})

View File

@ -27,6 +27,7 @@ const INSUFFICIENT_TOKENS_ERROR = 'insufficientTokens'
const NEGATIVE_ETH_ERROR = 'negativeETH'
const INVALID_RECIPIENT_ADDRESS_ERROR = 'invalidAddressRecipient'
const REQUIRED_ERROR = 'required'
const KNOWN_RECIPIENT_ADDRESS_ERROR = 'knownAddressRecipient'
const ONE_GWEI_IN_WEI_HEX = ethUtil.addHexPrefix(conversionUtil('0x1', {
fromDenomination: 'GWEI',
@ -42,6 +43,7 @@ module.exports = {
INSUFFICIENT_FUNDS_ERROR,
INSUFFICIENT_TOKENS_ERROR,
INVALID_RECIPIENT_ADDRESS_ERROR,
KNOWN_RECIPIENT_ADDRESS_ERROR,
MIN_GAS_LIMIT_DEC,
MIN_GAS_LIMIT_HEX,
MIN_GAS_PRICE_DEC,