diff options
author | Esteban MiƱo <efmino@uc.cl> | 2019-01-24 02:09:56 +0800 |
---|---|---|
committer | Whymarrh Whitby <whymarrh.whitby@gmail.com> | 2019-01-24 02:09:56 +0800 |
commit | 2d7c9b3dacc08c3d308100894b14d8c9f971e775 (patch) | |
tree | ddb6de9b5d8e42a5a2bcaf7cde3bdcd62f4a666a /ui/app/components/send/send-content | |
parent | fba17d77de9e60de0e02e90dc6dbcbbf7454158a (diff) | |
download | tangerine-wallet-browser-2d7c9b3dacc08c3d308100894b14d8c9f971e775.tar.gz tangerine-wallet-browser-2d7c9b3dacc08c3d308100894b14d8c9f971e775.tar.zst tangerine-wallet-browser-2d7c9b3dacc08c3d308100894b14d8c9f971e775.zip |
Prevent send to token warning (#6058)
Diffstat (limited to 'ui/app/components/send/send-content')
14 files changed, 194 insertions, 10 deletions
diff --git a/ui/app/components/send/send-content/send-row-wrapper/send-row-warning-message/index.js b/ui/app/components/send/send-content/send-row-wrapper/send-row-warning-message/index.js new file mode 100644 index 000000000..fd4d19ef7 --- /dev/null +++ b/ui/app/components/send/send-content/send-row-wrapper/send-row-warning-message/index.js @@ -0,0 +1 @@ +export { default } from './send-row-warning-message.container' diff --git a/ui/app/components/send/send-content/send-row-wrapper/send-row-warning-message/send-row-warning-message.component.js b/ui/app/components/send/send-content/send-row-wrapper/send-row-warning-message/send-row-warning-message.component.js new file mode 100644 index 000000000..f1caa8f99 --- /dev/null +++ b/ui/app/components/send/send-content/send-row-wrapper/send-row-warning-message/send-row-warning-message.component.js @@ -0,0 +1,27 @@ +import React, { Component } from 'react' +import PropTypes from 'prop-types' + +export default class SendRowWarningMessage extends Component { + + static propTypes = { + warnings: PropTypes.object, + warningType: PropTypes.string, + }; + + static contextTypes = { + t: PropTypes.func, + }; + + render () { + const { warnings, warningType } = this.props + + const warningMessage = warningType in warnings && warnings[warningType] + + return ( + warningMessage + ? <div className="send-v2__warning">{this.context.t(warningMessage)}</div> + : null + ) + } + +} diff --git a/ui/app/components/send/send-content/send-row-wrapper/send-row-warning-message/send-row-warning-message.container.js b/ui/app/components/send/send-content/send-row-wrapper/send-row-warning-message/send-row-warning-message.container.js new file mode 100644 index 000000000..7df14fd96 --- /dev/null +++ b/ui/app/components/send/send-content/send-row-wrapper/send-row-warning-message/send-row-warning-message.container.js @@ -0,0 +1,12 @@ +import { connect } from 'react-redux' +import { getSendWarnings } from '../../../send.selectors' +import SendRowWarningMessage from './send-row-warning-message.component' + +export default connect(mapStateToProps)(SendRowWarningMessage) + +function mapStateToProps (state, ownProps) { + return { + warnings: getSendWarnings(state), + warningType: ownProps.warningType, + } +} diff --git a/ui/app/components/send/send-content/send-row-wrapper/send-row-warning-message/send-row-warning-message.scss b/ui/app/components/send/send-content/send-row-wrapper/send-row-warning-message/send-row-warning-message.scss new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/ui/app/components/send/send-content/send-row-wrapper/send-row-warning-message/send-row-warning-message.scss diff --git a/ui/app/components/send/send-content/send-row-wrapper/send-row-warning-message/tests/send-row-warning-message-component.test.js b/ui/app/components/send/send-content/send-row-wrapper/send-row-warning-message/tests/send-row-warning-message-component.test.js new file mode 100644 index 000000000..bd803d833 --- /dev/null +++ b/ui/app/components/send/send-content/send-row-wrapper/send-row-warning-message/tests/send-row-warning-message-component.test.js @@ -0,0 +1,28 @@ +import React from 'react' +import assert from 'assert' +import { shallow } from 'enzyme' +import SendRowWarningMessage from '../send-row-warning-message.component.js' + +describe('SendRowWarningMessage Component', function () { + let wrapper + + beforeEach(() => { + wrapper = shallow(<SendRowWarningMessage + warnings={{ warning1: 'abc', warning2: 'def' }} + warningType={'warning3'} + />, { context: { t: str => str + '_t' } }) + }) + + describe('render', () => { + it('should render null if the passed warnings do not contain a warning of warningType', () => { + assert.equal(wrapper.find('.send-v2__warning').length, 0) + assert.equal(wrapper.html(), null) + }) + + it('should render a warning message if the passed warnings contain a warning of warningType', () => { + wrapper.setProps({ warnings: { warning1: 'abc', warning2: 'def', warning3: 'xyz' } }) + assert.equal(wrapper.find('.send-v2__warning').length, 1) + assert.equal(wrapper.find('.send-v2__warning').text(), 'xyz_t') + }) + }) +}) diff --git a/ui/app/components/send/send-content/send-row-wrapper/send-row-warning-message/tests/send-row-warning-message-container.test.js b/ui/app/components/send/send-content/send-row-wrapper/send-row-warning-message/tests/send-row-warning-message-container.test.js new file mode 100644 index 000000000..225bf056c --- /dev/null +++ b/ui/app/components/send/send-content/send-row-wrapper/send-row-warning-message/tests/send-row-warning-message-container.test.js @@ -0,0 +1,28 @@ +import assert from 'assert' +import proxyquire from 'proxyquire' + +let mapStateToProps + +proxyquire('../send-row-warning-message.container.js', { + 'react-redux': { + connect: (ms, md) => { + mapStateToProps = ms + return () => ({}) + }, + }, + '../../../send.selectors': { getSendWarnings: (s) => `mockWarnings:${s}` }, +}) + +describe('send-row-warning-message container', () => { + + describe('mapStateToProps()', () => { + + it('should map the correct properties to props', () => { + assert.deepEqual(mapStateToProps('mockState', { warningType: 'someType' }), { + warnings: 'mockWarnings:mockState', + warningType: 'someType' }) + }) + + }) + +}) diff --git a/ui/app/components/send/send-content/send-row-wrapper/send-row-wrapper.component.js b/ui/app/components/send/send-content/send-row-wrapper/send-row-wrapper.component.js index 04f4f8a15..0146ce645 100644 --- a/ui/app/components/send/send-content/send-row-wrapper/send-row-wrapper.component.js +++ b/ui/app/components/send/send-content/send-row-wrapper/send-row-wrapper.component.js @@ -1,6 +1,7 @@ import React, { Component } from 'react' import PropTypes from 'prop-types' import SendRowErrorMessage from './send-row-error-message/' +import SendRowWarningMessage from './send-row-warning-message/' export default class SendRowWrapper extends Component { @@ -9,6 +10,8 @@ export default class SendRowWrapper extends Component { errorType: PropTypes.string, label: PropTypes.string, showError: PropTypes.bool, + showWarning: PropTypes.bool, + warningType: PropTypes.string, }; static contextTypes = { @@ -21,8 +24,9 @@ export default class SendRowWrapper extends Component { errorType = '', label, showError = false, + showWarning = false, + warningType = '', } = this.props - const formField = Array.isArray(children) ? children[1] || children[0] : children const customLabelContent = children.length > 1 ? children[0] : null @@ -31,6 +35,7 @@ export default class SendRowWrapper extends Component { <div className="send-v2__form-label"> {label} {showError && <SendRowErrorMessage errorType={errorType}/>} + {!showError && showWarning && <SendRowWarningMessage warningType={warningType} />} {customLabelContent} </div> <div className="send-v2__form-field"> diff --git a/ui/app/components/send/send-content/send-to-row/send-to-row.component.js b/ui/app/components/send/send-content/send-to-row/send-to-row.component.js index dbcc4ecd6..0f26dd55c 100644 --- a/ui/app/components/send/send-content/send-to-row/send-to-row.component.js +++ b/ui/app/components/send/send-content/send-to-row/send-to-row.component.js @@ -2,7 +2,7 @@ import React, { Component } from 'react' import PropTypes from 'prop-types' import SendRowWrapper from '../send-row-wrapper/' import EnsInput from '../../../ens-input' -import { getToErrorObject } from './send-to-row.utils.js' +import { getToErrorObject, getToWarningObject } from './send-to-row.utils.js' export default class SendToRow extends Component { @@ -10,6 +10,7 @@ export default class SendToRow extends Component { closeToDropdown: PropTypes.func, hasHexData: PropTypes.bool.isRequired, inError: PropTypes.bool, + inWarning: PropTypes.bool, network: PropTypes.string, openToDropdown: PropTypes.func, selectedToken: PropTypes.object, @@ -20,6 +21,7 @@ export default class SendToRow extends Component { updateGas: PropTypes.func, updateSendTo: PropTypes.func, updateSendToError: PropTypes.func, + updateSendToWarning: PropTypes.func, scanQrCode: PropTypes.func, } @@ -27,11 +29,13 @@ export default class SendToRow extends Component { t: PropTypes.func, } - handleToChange (to, nickname = '', toError) { - const { hasHexData, updateSendTo, updateSendToError, updateGas, tokens, selectedToken } = this.props - const toErrorObject = getToErrorObject(to, toError, hasHexData, tokens, selectedToken) + handleToChange (to, nickname = '', toError, toWarning) { + const { hasHexData, updateSendTo, updateSendToError, updateGas, tokens, selectedToken, updateSendToWarning } = this.props + const toErrorObject = getToErrorObject(to, toError, hasHexData) + const toWarningObject = getToWarningObject(to, toWarning, tokens, selectedToken) updateSendTo(to, nickname) updateSendToError(toErrorObject) + updateSendToWarning(toWarningObject) if (toErrorObject.to === null) { updateGas({ to }) } @@ -41,6 +45,7 @@ export default class SendToRow extends Component { const { closeToDropdown, inError, + inWarning, network, openToDropdown, to, @@ -53,7 +58,9 @@ export default class SendToRow extends Component { errorType={'to'} label={`${this.context.t('to')}: `} showError={inError} - > + showWarning={inWarning} + warningType={'to'} + > <EnsInput scanQrCode={_ => this.props.scanQrCode()} accounts={toAccounts} @@ -62,7 +69,7 @@ export default class SendToRow extends Component { inError={inError} name={'address'} network={network} - onChange={({ toAddress, nickname, toError }) => this.handleToChange(toAddress, nickname, toError)} + onChange={({ toAddress, nickname, toError, toWarning }) => this.handleToChange(toAddress, nickname, toError, toWarning)} openDropdown={() => openToDropdown()} placeholder={this.context.t('recipientAddress')} to={to} diff --git a/ui/app/components/send/send-content/send-to-row/send-to-row.container.js b/ui/app/components/send/send-content/send-to-row/send-to-row.container.js index 945cdbaeb..fc6742df0 100644 --- a/ui/app/components/send/send-content/send-to-row/send-to-row.container.js +++ b/ui/app/components/send/send-content/send-to-row/send-to-row.container.js @@ -10,12 +10,14 @@ import { getToDropdownOpen, getTokens, sendToIsInError, + sendToIsInWarning, } from './send-to-row.selectors.js' import { updateSendTo, } from '../../../../actions' import { updateSendErrors, + updateSendWarnings, openToDropdown, closeToDropdown, } from '../../../../ducks/send.duck' @@ -27,6 +29,7 @@ function mapStateToProps (state) { return { hasHexData: Boolean(getSendHexData(state)), inError: sendToIsInError(state), + inWarning: sendToIsInWarning(state), network: getCurrentNetwork(state), selectedToken: getSelectedToken(state), to: getSendTo(state), @@ -44,5 +47,8 @@ function mapDispatchToProps (dispatch) { updateSendToError: (toErrorObject) => { dispatch(updateSendErrors(toErrorObject)) }, + updateSendToWarning: (toWarningObject) => { + dispatch(updateSendWarnings(toWarningObject)) + }, } } diff --git a/ui/app/components/send/send-content/send-to-row/send-to-row.selectors.js b/ui/app/components/send/send-content/send-to-row/send-to-row.selectors.js index 982fd2e46..a6160d335 100644 --- a/ui/app/components/send/send-content/send-to-row/send-to-row.selectors.js +++ b/ui/app/components/send/send-content/send-to-row/send-to-row.selectors.js @@ -2,6 +2,7 @@ const selectors = { getToDropdownOpen, getTokens, sendToIsInError, + sendToIsInWarning, } module.exports = selectors @@ -14,6 +15,10 @@ function sendToIsInError (state) { return Boolean(state.send.errors.to) } +function sendToIsInWarning (state) { + return Boolean(state.send.warnings.to) +} + function getTokens (state) { return state.metamask.tokens } diff --git a/ui/app/components/send/send-content/send-to-row/send-to-row.utils.js b/ui/app/components/send/send-content/send-to-row/send-to-row.utils.js index 7efd2a772..4a8add42e 100644 --- a/ui/app/components/send/send-content/send-to-row/send-to-row.utils.js +++ b/ui/app/components/send/send-content/send-to-row/send-to-row.utils.js @@ -19,10 +19,17 @@ function getToErrorObject (to, toError = null, hasHexData = false, tokens = [], } else if (selectedToken && (ethUtil.toChecksumAddress(to) in contractMap || checkExistingAddresses(to, tokens))) { toError = KNOWN_RECIPIENT_ADDRESS_ERROR } - return { to: toError } } +function getToWarningObject (to, toWarning = null, tokens = [], selectedToken = null) { + if (selectedToken && (ethUtil.toChecksumAddress(to) in contractMap || checkExistingAddresses(to, tokens))) { + toWarning = KNOWN_RECIPIENT_ADDRESS_ERROR + } + return { to: toWarning } +} + module.exports = { getToErrorObject, + getToWarningObject, } diff --git a/ui/app/components/send/send-content/send-to-row/tests/send-to-row-component.test.js b/ui/app/components/send/send-content/send-to-row/tests/send-to-row-component.test.js index 591229deb..d3732307f 100644 --- a/ui/app/components/send/send-content/send-to-row/tests/send-to-row-component.test.js +++ b/ui/app/components/send/send-content/send-to-row/tests/send-to-row-component.test.js @@ -9,6 +9,9 @@ const SendToRow = proxyquire('../send-to-row.component.js', { getToErrorObject: (to, toError) => ({ to: to === false ? null : `mockToErrorObject:${to}${toError}`, }), + getToWarningObject: (to, toWarning) => ({ + to: to === false ? null : `mockToWarningObject:${to}${toWarning}`, + }), }, }).default @@ -21,6 +24,7 @@ const propsMethodSpies = { updateGas: sinon.spy(), updateSendTo: sinon.spy(), updateSendToError: sinon.spy(), + updateSendToWarning: sinon.spy(), } sinon.spy(SendToRow.prototype, 'handleToChange') @@ -33,6 +37,7 @@ describe('SendToRow Component', function () { wrapper = shallow(<SendToRow closeToDropdown={propsMethodSpies.closeToDropdown} inError={false} + inWarning={false} network={'mockNetwork'} openToDropdown={propsMethodSpies.openToDropdown} to={'mockTo'} @@ -41,6 +46,7 @@ describe('SendToRow Component', function () { updateGas={propsMethodSpies.updateGas} updateSendTo={propsMethodSpies.updateSendTo} updateSendToError={propsMethodSpies.updateSendToError} + updateSendToWarning={propsMethodSpies.updateSendToWarning} />, { context: { t: str => str + '_t' } }) instance = wrapper.instance() }) @@ -50,6 +56,7 @@ describe('SendToRow Component', function () { propsMethodSpies.openToDropdown.resetHistory() propsMethodSpies.updateSendTo.resetHistory() propsMethodSpies.updateSendToError.resetHistory() + propsMethodSpies.updateSendToWarning.resetHistory() SendToRow.prototype.handleToChange.resetHistory() }) @@ -75,6 +82,16 @@ describe('SendToRow Component', function () { ) }) + it('should call updateSendToWarning', () => { + assert.equal(propsMethodSpies.updateSendToWarning.callCount, 0) + instance.handleToChange('mockTo2', '', '', 'mockToWarning') + assert.equal(propsMethodSpies.updateSendToWarning.callCount, 1) + assert.deepEqual( + propsMethodSpies.updateSendToWarning.getCall(0).args, + [{ to: 'mockToWarningObject:mockTo2mockToWarning' }] + ) + }) + it('should not call updateGas if there is a to error', () => { assert.equal(propsMethodSpies.updateGas.callCount, 0) instance.handleToChange('mockTo2') @@ -138,11 +155,11 @@ describe('SendToRow Component', function () { openDropdown() assert.equal(propsMethodSpies.openToDropdown.callCount, 1) assert.equal(SendToRow.prototype.handleToChange.callCount, 0) - onChange({ toAddress: 'mockNewTo', nickname: 'mockNewNickname', toError: 'mockToError' }) + onChange({ toAddress: 'mockNewTo', nickname: 'mockNewNickname', toError: 'mockToError', toWarning: 'mockToWarning' }) assert.equal(SendToRow.prototype.handleToChange.callCount, 1) assert.deepEqual( SendToRow.prototype.handleToChange.getCall(0).args, - ['mockNewTo', 'mockNewNickname', 'mockToError'] + ['mockNewTo', 'mockNewNickname', 'mockToError', 'mockToWarning'] ) }) }) diff --git a/ui/app/components/send/send-content/send-to-row/tests/send-to-row-container.test.js b/ui/app/components/send/send-content/send-to-row/tests/send-to-row-container.test.js index 95efdd7cc..aa09f01a9 100644 --- a/ui/app/components/send/send-content/send-to-row/tests/send-to-row-container.test.js +++ b/ui/app/components/send/send-content/send-to-row/tests/send-to-row-container.test.js @@ -12,6 +12,7 @@ const duckActionSpies = { closeToDropdown: sinon.spy(), openToDropdown: sinon.spy(), updateSendErrors: sinon.spy(), + updateSendWarnings: sinon.spy(), } proxyquire('../send-to-row.container.js', { @@ -32,6 +33,7 @@ proxyquire('../send-to-row.container.js', { './send-to-row.selectors.js': { getToDropdownOpen: (s) => `mockToDropdownOpen:${s}`, sendToIsInError: (s) => `mockInError:${s}`, + sendToIsInWarning: (s) => `mockInWarning:${s}`, getTokens: (s) => `mockTokens:${s}`, }, '../../../../actions': actionSpies, @@ -46,6 +48,7 @@ describe('send-to-row container', () => { assert.deepEqual(mapStateToProps('mockState'), { hasHexData: true, inError: 'mockInError:mockState', + inWarning: 'mockInWarning:mockState', network: 'mockNetwork:mockState', selectedToken: 'mockSelectedToken:mockState', to: 'mockTo:mockState', @@ -114,6 +117,18 @@ describe('send-to-row container', () => { }) }) + describe('updateSendToWarning()', () => { + it('should dispatch an action', () => { + mapDispatchToPropsObject.updateSendToWarning('mockToWarningObject') + assert(dispatchSpy.calledOnce) + assert(duckActionSpies.updateSendWarnings.calledOnce) + assert.equal( + duckActionSpies.updateSendWarnings.getCall(0).args[0], + 'mockToWarningObject' + ) + }) + }) + }) }) diff --git a/ui/app/components/send/send-content/send-to-row/tests/send-to-row-utils.test.js b/ui/app/components/send/send-content/send-to-row/tests/send-to-row-utils.test.js index 8d4f26e15..f6abb26e6 100644 --- a/ui/app/components/send/send-content/send-to-row/tests/send-to-row-utils.test.js +++ b/ui/app/components/send/send-content/send-to-row/tests/send-to-row-utils.test.js @@ -19,6 +19,7 @@ const toRowUtils = proxyquire('../send-to-row.utils.js', { }) const { getToErrorObject, + getToWarningObject, } = toRowUtils describe('send-to-row utils', () => { @@ -78,4 +79,29 @@ describe('send-to-row utils', () => { }) }) + describe('getToWarningObject()', () => { + it('should return a known address recipient if to is truthy but part of state tokens', () => { + assert.deepEqual(getToWarningObject('0xabc123', undefined, [{'address': '0xabc123'}], {'address': '0xabc123'}), { + to: KNOWN_RECIPIENT_ADDRESS_ERROR, + }) + }) + + it('should null if to is truthy part of tokens but selectedToken falsy', () => { + assert.deepEqual(getToWarningObject('0xabc123', undefined, [{'address': '0xabc123'}]), { + to: null, + }) + }) + + it('should return a known address recipient if to is truthy but part of contract metadata', () => { + assert.deepEqual(getToWarningObject('0x89d24a6b4ccb1b6faa2625fe562bdd9a23260359', undefined, [{'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(getToWarningObject('0x89d24a6b4ccb1b6faa2625fe562bdd9a23260359', undefined, [{'address': '0xabc123'}], {'address': '0xabc123'}), { + to: KNOWN_RECIPIENT_ADDRESS_ERROR, + }) + }) + }) + }) |