diff options
author | brunobar79 <brunobar79@gmail.com> | 2018-10-17 02:01:54 +0800 |
---|---|---|
committer | brunobar79 <brunobar79@gmail.com> | 2018-10-17 02:01:54 +0800 |
commit | 13820b6cc1801a420f39cdfecd7ccb5309dc597b (patch) | |
tree | c79832d7077ab03e0afe0c322cb32b204865d8b5 /ui/app/components/send | |
parent | eeecee01540fbad50c4c463a3b1a54142a63f168 (diff) | |
parent | 07ab613d4c647e3fe554bc06eab8cfb833315a88 (diff) | |
download | tangerine-wallet-browser-13820b6cc1801a420f39cdfecd7ccb5309dc597b.tar.gz tangerine-wallet-browser-13820b6cc1801a420f39cdfecd7ccb5309dc597b.tar.zst tangerine-wallet-browser-13820b6cc1801a420f39cdfecd7ccb5309dc597b.zip |
fix conflicts
Diffstat (limited to 'ui/app/components/send')
18 files changed, 202 insertions, 49 deletions
diff --git a/ui/app/components/send/currency-display/tests/currency-display.test.js b/ui/app/components/send/currency-display/tests/currency-display.test.js new file mode 100644 index 000000000..c9560b81c --- /dev/null +++ b/ui/app/components/send/currency-display/tests/currency-display.test.js @@ -0,0 +1,91 @@ +import React from 'react' +import assert from 'assert' +import sinon from 'sinon' +import { shallow, mount } from 'enzyme' +import CurrencyDisplay from '../currency-display' + +describe('', () => { + + const token = { + address: '0xTest', + symbol: 'TST', + decimals: '13', + } + + it('retuns ETH value for wei value', () => { + const wrapper = mount(<CurrencyDisplay />, {context: {t: str => str + '_t'}}) + + const value = wrapper.instance().getValueToRender({ + // 1000000000000000000 + value: 'DE0B6B3A7640000', + }) + + assert.equal(value, 1) + }) + + it('returns value of token based on token decimals', () => { + const wrapper = mount(<CurrencyDisplay />, {context: {t: str => str + '_t'}}) + + const value = wrapper.instance().getValueToRender({ + selectedToken: token, + // 1000000000000000000 + value: 'DE0B6B3A7640000', + }) + + assert.equal(value, 100000) + }) + + it('returns hex value with decimal adjustment', () => { + + const wrapper = mount( + <CurrencyDisplay + selectedToken={token} + />, {context: {t: str => str + '_t'}}) + + const value = wrapper.instance().getAmount(1) + // 10000000000000 + assert.equal(value, '9184e72a000') + }) + + it('#getConvertedValueToRender converts input value based on conversionRate', () => { + + const wrapper = mount( + <CurrencyDisplay + primaryCurrency={'usd'} + convertedCurrency={'ja'} + conversionRate={2} + />, {context: {t: str => str + '_t'}}) + + const value = wrapper.instance().getConvertedValueToRender(32) + + assert.equal(value, 64) + }) + + it('#onlyRenderConversions renders single element for converted currency and value', () => { + const wrapper = mount( + <CurrencyDisplay + convertedCurrency={'test'} + />, {context: {t: str => str + '_t'}}) + + const value = wrapper.instance().onlyRenderConversions(10) + assert.equal(value.props.className, 'currency-display__converted-value') + assert.equal(value.props.children, '10 TEST') + }) + + it('simulates change value in input', () => { + const handleChangeSpy = sinon.spy() + + const wrapper = shallow( + <CurrencyDisplay + onChange={handleChangeSpy} + />, {context: {t: str => str + '_t'}}) + + const input = wrapper.find('input') + input.simulate('focus') + input.simulate('change', { target: { value: '100' } }) + + assert.equal(wrapper.state().valueToRender, '100') + assert.equal(wrapper.find('input').prop('value'), '100') + }) + +}) diff --git a/ui/app/components/send/send-content/send-amount-row/amount-max-button/amount-max-button.component.js b/ui/app/components/send/send-content/send-amount-row/amount-max-button/amount-max-button.component.js index 4d0d36ab4..ceb620941 100644 --- a/ui/app/components/send/send-content/send-amount-row/amount-max-button/amount-max-button.component.js +++ b/ui/app/components/send/send-content/send-amount-row/amount-max-button/amount-max-button.component.js @@ -34,21 +34,27 @@ export default class AmountMaxButton extends Component { }) } + onMaxClick = (event) => { + const { setMaxModeTo } = this.props + + event.preventDefault() + setMaxModeTo(true) + this.setMaxAmount() + } + render () { - const { setMaxModeTo, maxModeOn } = this.props - - return ( - <div - className="send-v2__amount-max" - onClick={(event) => { - event.preventDefault() - setMaxModeTo(true) - this.setMaxAmount() - }} - > - {!maxModeOn ? this.context.t('max') : ''} - </div> - ) + return this.props.maxModeOn + ? null + : ( + <div> + <span + className="send-v2__amount-max" + onClick={this.onMaxClick} + > + {this.context.t('max')} + </span> + </div> + ) } } diff --git a/ui/app/components/send/send-content/send-amount-row/amount-max-button/tests/amount-max-button-component.test.js b/ui/app/components/send/send-content/send-amount-row/amount-max-button/tests/amount-max-button-component.test.js index 86a05ff21..b04d3897f 100644 --- a/ui/app/components/send/send-content/send-amount-row/amount-max-button/tests/amount-max-button-component.test.js +++ b/ui/app/components/send/send-content/send-amount-row/amount-max-button/tests/amount-max-button-component.test.js @@ -56,9 +56,8 @@ describe('AmountMaxButton Component', function () { }) describe('render', () => { - it('should render a div with a send-v2__amount-max class', () => { - assert.equal(wrapper.find('.send-v2__amount-max').length, 1) - assert(wrapper.find('.send-v2__amount-max').is('div')) + it('should render an element with a send-v2__amount-max class', () => { + assert(wrapper.exists('.send-v2__amount-max')) }) it('should call setMaxModeTo and setMaxAmount when the send-v2__amount-max div is clicked', () => { @@ -77,9 +76,9 @@ describe('AmountMaxButton Component', function () { ) }) - it('should not render text when maxModeOn is true', () => { + it('should not render anything when maxModeOn is true', () => { wrapper.setProps({ maxModeOn: true }) - assert.equal(wrapper.find('.send-v2__amount-max').text(), '') + assert.ok(!wrapper.exists('.send-v2__amount-max')) }) it('should render the expected text when maxModeOn is false', () => { diff --git a/ui/app/components/send/send-content/send-content.component.js b/ui/app/components/send/send-content/send-content.component.js index 9e0ce9c23..1b03ffd2b 100644 --- a/ui/app/components/send/send-content/send-content.component.js +++ b/ui/app/components/send/send-content/send-content.component.js @@ -15,18 +15,24 @@ export default class SendContent extends Component { showHexData: PropTypes.bool, }; + updateGas = (updateData) => this.props.updateGas(updateData) + render () { return ( <PageContainerContent> <div className="send-v2__form"> <SendFromRow /> <SendToRow - updateGas={(updateData) => this.props.updateGas(updateData)} + updateGas={this.updateGas} scanQrCode={ _ => this.props.scanQrCode()} /> - <SendAmountRow updateGas={(updateData) => this.props.updateGas(updateData)} /> + <SendAmountRow updateGas={this.updateGas} /> <SendGasRow /> - { this.props.showHexData ? <SendHexDataRow /> : null } + {(this.props.showHexData && ( + <SendHexDataRow + updateGas={this.updateGas} + /> + ))} </div> </PageContainerContent> ) diff --git a/ui/app/components/send/send-content/send-hex-data-row/send-hex-data-row.component.js b/ui/app/components/send/send-content/send-hex-data-row/send-hex-data-row.component.js index 063930db3..62a74a77b 100644 --- a/ui/app/components/send/send-content/send-hex-data-row/send-hex-data-row.component.js +++ b/ui/app/components/send/send-content/send-hex-data-row/send-hex-data-row.component.js @@ -7,6 +7,7 @@ export default class SendHexDataRow extends Component { data: PropTypes.string, inError: PropTypes.bool, updateSendHexData: PropTypes.func.isRequired, + updateGas: PropTypes.func.isRequired, }; static contextTypes = { @@ -14,9 +15,10 @@ export default class SendHexDataRow extends Component { }; onInput = (event) => { - const {updateSendHexData} = this.props - event.target.value = event.target.value.replace(/\n/g, '') - updateSendHexData(event.target.value || null) + const {updateSendHexData, updateGas} = this.props + const data = event.target.value.replace(/\n/g, '') || null + updateSendHexData(data) + updateGas({ data }) } render () { 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 434db81e5..17c75c817 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 @@ -8,6 +8,7 @@ export default class SendToRow extends Component { static propTypes = { closeToDropdown: PropTypes.func, + hasHexData: PropTypes.bool.isRequired, inError: PropTypes.bool, network: PropTypes.string, openToDropdown: PropTypes.func, @@ -25,8 +26,8 @@ export default class SendToRow extends Component { }; handleToChange (to, nickname = '', toError) { - const { updateSendTo, updateSendToError, updateGas } = this.props - const toErrorObject = getToErrorObject(to, toError) + const { hasHexData, updateSendTo, updateSendToError, updateGas } = this.props + const toErrorObject = getToErrorObject(to, toError, hasHexData) updateSendTo(to, nickname) updateSendToError(toErrorObject) if (toErrorObject.to === null) { 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 1c9c9d518..3ee188bad 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 @@ -3,6 +3,7 @@ import { getCurrentNetwork, getSendTo, getSendToAccounts, + getSendHexData, } from '../../send.selectors.js' import { getToDropdownOpen, @@ -22,6 +23,7 @@ export default connect(mapStateToProps, mapDispatchToProps)(SendToRow) function mapStateToProps (state) { return { + hasHexData: Boolean(getSendHexData(state)), inError: sendToIsInError(state), network: getCurrentNetwork(state), to: getSendTo(state), 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 6b90a9f09..0eeaa3a11 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 @@ -4,9 +4,11 @@ const { } = require('../../send.constants') const { isValidAddress } = require('../../../../util') -function getToErrorObject (to, toError = null) { +function getToErrorObject (to, toError = null, hasHexData = false) { if (!to) { - toError = REQUIRED_ERROR + if (!hasHexData) { + toError = REQUIRED_ERROR + } } else if (!isValidAddress(to) && !toError) { toError = INVALID_RECIPIENT_ADDRESS_ERROR } 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 92355c00a..dfce7652f 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 @@ -24,6 +24,7 @@ proxyquire('../send-to-row.container.js', { }, '../../send.selectors.js': { getCurrentNetwork: (s) => `mockNetwork:${s}`, + getSendHexData: (s) => s, getSendTo: (s) => `mockTo:${s}`, getSendToAccounts: (s) => `mockToAccounts:${s}`, }, @@ -41,6 +42,7 @@ describe('send-to-row container', () => { it('should map the correct properties to props', () => { assert.deepEqual(mapStateToProps('mockState'), { + hasHexData: true, inError: 'mockInError:mockState', network: 'mockNetwork:mockState', to: 'mockTo:mockState', 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 4d2447c32..c779aeb76 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 @@ -29,6 +29,12 @@ describe('send-to-row utils', () => { }) }) + it('should return null if to is falsy and hexData is truthy', () => { + assert.deepEqual(getToErrorObject(null, undefined, true), { + to: null, + }) + }) + it('should return an invalid recipient error if to is truthy but invalid', () => { assert.deepEqual(getToErrorObject('mockInvalidTo'), { to: INVALID_RECIPIENT_ADDRESS_ERROR, diff --git a/ui/app/components/send/send-footer/send-footer.component.js b/ui/app/components/send/send-footer/send-footer.component.js index 518cff06e..230bf450f 100644 --- a/ui/app/components/send/send-footer/send-footer.component.js +++ b/ui/app/components/send/send-footer/send-footer.component.js @@ -86,9 +86,9 @@ export default class SendFooter extends Component { } formShouldBeDisabled () { - const { inError, selectedToken, tokenBalance, gasTotal, to } = this.props + const { data, inError, selectedToken, tokenBalance, gasTotal, to } = this.props const missingTokenBalance = selectedToken && !tokenBalance - return inError || !gasTotal || missingTokenBalance || !to + return inError || !gasTotal || missingTokenBalance || !(data || to) } render () { diff --git a/ui/app/components/send/send.component.js b/ui/app/components/send/send.component.js index 0dc973632..fb7beca16 100644 --- a/ui/app/components/send/send.component.js +++ b/ui/app/components/send/send.component.js @@ -62,7 +62,7 @@ export default class SendTransactionScreen extends PersistentForm { } } - updateGas ({ to: updatedToAddress, amount: value } = {}) { + updateGas ({ to: updatedToAddress, amount: value, data } = {}) { const { amount, blockGasLimit, @@ -86,6 +86,7 @@ export default class SendTransactionScreen extends PersistentForm { selectedToken, to: getToAddressForGasUpdate(updatedToAddress, currentToAddress), value: value || amount, + data, }) } diff --git a/ui/app/components/send/send.container.js b/ui/app/components/send/send.container.js index 6ee8de9aa..87056499f 100644 --- a/ui/app/components/send/send.container.js +++ b/ui/app/components/send/send.container.js @@ -86,9 +86,10 @@ function mapDispatchToProps (dispatch) { selectedToken, to, value, + data, }) => { !editingTransactionId - ? dispatch(updateGasData({ recentBlocks, selectedAddress, selectedToken, blockGasLimit, to, value })) + ? dispatch(updateGasData({ recentBlocks, selectedAddress, selectedToken, blockGasLimit, to, value, data })) : dispatch(setGasTotal(calcGasTotal(gasLimit, gasPrice))) }, updateSendTokenBalance: ({ selectedToken, tokenContract, address }) => { diff --git a/ui/app/components/send/send.utils.js b/ui/app/components/send/send.utils.js index aa255c3d4..a18a9e4b3 100644 --- a/ui/app/components/send/send.utils.js +++ b/ui/app/components/send/send.utils.js @@ -200,16 +200,20 @@ function doesAmountErrorRequireUpdate ({ return amountErrorRequiresUpdate } -async function estimateGas ({ selectedAddress, selectedToken, blockGasLimit, to, value, gasPrice, estimateGasMethod }) { +async function estimateGas ({ + selectedAddress, + selectedToken, + blockGasLimit, + to, + value, + data, + gasPrice, + estimateGasMethod, +}) { const paramsForGasEstimate = { from: selectedAddress, value, gasPrice } - if (selectedToken) { - paramsForGasEstimate.value = '0x0' - paramsForGasEstimate.data = generateTokenTransferData({ toAddress: to, amount: value, selectedToken }) - } - // if recipient has no code, gas is 21k max: - if (!selectedToken) { + if (!selectedToken && !data) { const code = Boolean(to) && await global.eth.getCode(to) if (!code || code === '0x') { return SIMPLE_GAS_COST @@ -218,7 +222,19 @@ async function estimateGas ({ selectedAddress, selectedToken, blockGasLimit, to, return BASE_TOKEN_GAS_COST } - paramsForGasEstimate.to = selectedToken ? selectedToken.address : to + if (selectedToken) { + paramsForGasEstimate.value = '0x0' + paramsForGasEstimate.data = generateTokenTransferData({ toAddress: to, amount: value, selectedToken }) + paramsForGasEstimate.to = selectedToken.address + } else { + if (data) { + paramsForGasEstimate.data = data + } + + if (to) { + paramsForGasEstimate.to = to + } + } // if not, fall back to block gasLimit paramsForGasEstimate.gas = ethUtil.addHexPrefix(multiplyCurrencies(blockGasLimit, 0.95, { diff --git a/ui/app/components/send/tests/send-component.test.js b/ui/app/components/send/tests/send-component.test.js index d2c2ee926..f4943e707 100644 --- a/ui/app/components/send/tests/send-component.test.js +++ b/ui/app/components/send/tests/send-component.test.js @@ -289,6 +289,7 @@ describe('Send Component', function () { selectedToken: 'mockSelectedToken', to: '', value: 'mockAmount', + data: undefined, } ) }) diff --git a/ui/app/components/send/tests/send-container.test.js b/ui/app/components/send/tests/send-container.test.js index 85eec6a53..6aa4bf826 100644 --- a/ui/app/components/send/tests/send-container.test.js +++ b/ui/app/components/send/tests/send-container.test.js @@ -105,6 +105,7 @@ describe('send container', () => { selectedToken: { address: '0x1' }, to: 'mockTo', value: 'mockValue', + data: undefined, } it('should dispatch a setGasTotal action when editingTransactionId is truthy', () => { @@ -117,14 +118,14 @@ describe('send container', () => { }) it('should dispatch an updateGasData action when editingTransactionId is falsy', () => { - const { selectedAddress, selectedToken, recentBlocks, blockGasLimit, to, value } = mockProps + const { selectedAddress, selectedToken, recentBlocks, blockGasLimit, to, value, data } = mockProps mapDispatchToPropsObject.updateAndSetGasTotal( Object.assign({}, mockProps, {editingTransactionId: false}) ) assert(dispatchSpy.calledOnce) assert.deepEqual( actionSpies.updateGasData.getCall(0).args[0], - { selectedAddress, selectedToken, recentBlocks, blockGasLimit, to, value } + { selectedAddress, selectedToken, recentBlocks, blockGasLimit, to, value, data } ) }) }) diff --git a/ui/app/components/send/tests/send-utils.test.js b/ui/app/components/send/tests/send-utils.test.js index 18dde495a..b72d87eee 100644 --- a/ui/app/components/send/tests/send-utils.test.js +++ b/ui/app/components/send/tests/send-utils.test.js @@ -304,10 +304,13 @@ describe('send utils', () => { selectedAddress: 'mockAddress', to: '0xisContract', estimateGasMethod: sinon.stub().callsFake( - (data, cb) => cb( - data.to.match(/willFailBecauseOf:/) ? { message: data.to.match(/:(.+)$/)[1] } : null, - { toString: (n) => `0xabc${n}` } - ) + ({to}, cb) => { + const err = typeof to === 'string' && to.match(/willFailBecauseOf:/) + ? new Error(to.match(/:(.+)$/)[1]) + : null + const result = { toString: (n) => `0xabc${n}` } + return cb(err, result) + } ), } const baseExpectedCall = { @@ -364,6 +367,18 @@ describe('send utils', () => { assert.equal(result, '0xabc16') }) + it('should call ethQuery.estimateGas without a recipient if the recipient is empty and data passed', async () => { + const data = 'mockData' + const to = '' + const result = await estimateGas({...baseMockParams, data, to}) + assert.equal(baseMockParams.estimateGasMethod.callCount, 1) + assert.deepEqual( + baseMockParams.estimateGasMethod.getCall(0).args[0], + { gasPrice: undefined, value: undefined, data, from: baseExpectedCall.from, gas: baseExpectedCall.gas}, + ) + assert.equal(result, '0xabc16') + }) + it(`should return ${SIMPLE_GAS_COST} if ethQuery.getCode does not return '0x'`, async () => { assert.equal(baseMockParams.estimateGasMethod.callCount, 0) const result = await estimateGas(Object.assign({}, baseMockParams, { to: '0x123' })) @@ -407,7 +422,7 @@ describe('send utils', () => { to: 'isContract willFailBecauseOf:some other error', })) } catch (err) { - assert.deepEqual(err, { message: 'some other error' }) + assert.equal(err.message, 'some other error') } }) }) diff --git a/ui/app/components/send/to-autocomplete/to-autocomplete.js b/ui/app/components/send/to-autocomplete/to-autocomplete.js index 49ebf49d9..39d15dfa7 100644 --- a/ui/app/components/send/to-autocomplete/to-autocomplete.js +++ b/ui/app/components/send/to-autocomplete/to-autocomplete.js @@ -5,6 +5,7 @@ const inherits = require('util').inherits const AccountListItem = require('../account-list-item/account-list-item.component').default const connect = require('react-redux').connect const Tooltip = require('../../tooltip') +const checksumAddress = require('../../../util').checksumAddress ToAutoComplete.contextTypes = { t: PropTypes.func, @@ -48,7 +49,7 @@ ToAutoComplete.prototype.renderDropdown = function () { account, className: 'account-list-item__dropdown', handleClick: () => { - onChange(account.address) + onChange(checksumAddress(account.address)) closeDropdown() }, icon: this.getListItemIcon(account.address, to), |