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:
parent
2cfea0b788
commit
1d93d9a385
@ -648,6 +648,9 @@
|
||||
"invalidAddressRecipient": {
|
||||
"message": "Recipient address is invalid"
|
||||
},
|
||||
"knownAddressRecipient": {
|
||||
"message": "Known contract address."
|
||||
},
|
||||
"invalidGasParams": {
|
||||
"message": "Invalid Gas Parameters"
|
||||
},
|
||||
|
@ -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) {
|
||||
|
@ -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),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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 }
|
||||
|
@ -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',
|
||||
})
|
||||
})
|
||||
|
||||
|
@ -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), [])
|
||||
})
|
||||
})
|
||||
})
|
||||
|
@ -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,
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user