diff options
Diffstat (limited to 'ui')
-rw-r--r-- | ui/app/components/dropdowns/account-dropdown-mini.js | 2 | ||||
-rw-r--r-- | ui/app/components/send/account-list-item.js | 74 | ||||
-rw-r--r-- | ui/app/components/send/from-dropdown.js | 72 | ||||
-rw-r--r-- | ui/app/components/send/gas-tooltip.js | 106 | ||||
-rw-r--r-- | ui/app/components/send/memo-textarea.js | 33 | ||||
-rw-r--r-- | ui/app/components/send/send-constants.js | 33 | ||||
-rw-r--r-- | ui/app/components/send/send-utils.js | 78 | ||||
-rw-r--r-- | ui/app/components/send/send-v2-container.js | 95 | ||||
-rw-r--r-- | ui/app/components/send/to-autocomplete.js | 2 | ||||
-rw-r--r-- | ui/app/send-v2.js | 655 |
10 files changed, 2 insertions, 1148 deletions
diff --git a/ui/app/components/dropdowns/account-dropdown-mini.js b/ui/app/components/dropdowns/account-dropdown-mini.js index a3d41af90..a7a908d3b 100644 --- a/ui/app/components/dropdowns/account-dropdown-mini.js +++ b/ui/app/components/dropdowns/account-dropdown-mini.js @@ -1,7 +1,7 @@ const Component = require('react').Component const h = require('react-hyperscript') const inherits = require('util').inherits -const AccountListItem = require('../send/account-list-item') +const AccountListItem = require('../send_/account-list-item/account-list-item.component').default module.exports = AccountDropdownMini diff --git a/ui/app/components/send/account-list-item.js b/ui/app/components/send/account-list-item.js deleted file mode 100644 index b5e604a6e..000000000 --- a/ui/app/components/send/account-list-item.js +++ /dev/null @@ -1,74 +0,0 @@ -const Component = require('react').Component -const h = require('react-hyperscript') -const inherits = require('util').inherits -const connect = require('react-redux').connect -const { checksumAddress } = require('../../util') -const Identicon = require('../identicon') -const CurrencyDisplay = require('./currency-display') -const { conversionRateSelector, getCurrentCurrency } = require('../../selectors') - -inherits(AccountListItem, Component) -function AccountListItem () { - Component.call(this) -} - -function mapStateToProps (state) { - return { - conversionRate: conversionRateSelector(state), - currentCurrency: getCurrentCurrency(state), - } -} - -module.exports = connect(mapStateToProps)(AccountListItem) - -AccountListItem.prototype.render = function () { - const { - className, - account, - handleClick, - icon = null, - conversionRate, - currentCurrency, - displayBalance = true, - displayAddress = false, - } = this.props - - const { name, address, balance } = account || {} - - return h('div.account-list-item', { - className, - onClick: () => handleClick({ name, address, balance }), - }, [ - - h('div.account-list-item__top-row', {}, [ - - h( - Identicon, - { - address, - diameter: 18, - className: 'account-list-item__identicon', - }, - ), - - h('div.account-list-item__account-name', {}, name || address), - - icon && h('div.account-list-item__icon', [icon]), - - ]), - - displayAddress && name && h('div.account-list-item__account-address', checksumAddress(address)), - - displayBalance && h(CurrencyDisplay, { - primaryCurrency: 'ETH', - convertedCurrency: currentCurrency, - value: balance, - conversionRate, - readOnly: true, - className: 'account-list-item__account-balances', - primaryBalanceClassName: 'account-list-item__account-primary-balance', - convertedBalanceClassName: 'account-list-item__account-secondary-balance', - }, name), - - ]) -} diff --git a/ui/app/components/send/from-dropdown.js b/ui/app/components/send/from-dropdown.js deleted file mode 100644 index 0686fbe73..000000000 --- a/ui/app/components/send/from-dropdown.js +++ /dev/null @@ -1,72 +0,0 @@ -const Component = require('react').Component -const h = require('react-hyperscript') -const inherits = require('util').inherits -const AccountListItem = require('./account-list-item') - -module.exports = FromDropdown - -inherits(FromDropdown, Component) -function FromDropdown () { - Component.call(this) -} - -FromDropdown.prototype.getListItemIcon = function (currentAccount, selectedAccount) { - const listItemIcon = h(`i.fa.fa-check.fa-lg`, { style: { color: '#02c9b1' } }) - - return currentAccount.address === selectedAccount.address - ? listItemIcon - : null -} - -FromDropdown.prototype.renderDropdown = function () { - const { - accounts, - selectedAccount, - closeDropdown, - onSelect, - } = this.props - - return h('div', {}, [ - - h('div.send-v2__from-dropdown__close-area', { - onClick: closeDropdown, - }), - - h('div.send-v2__from-dropdown__list', {}, [ - - ...accounts.map(account => h(AccountListItem, { - className: 'account-list-item__dropdown', - account, - handleClick: () => { - onSelect(account) - closeDropdown() - }, - icon: this.getListItemIcon(account, selectedAccount), - })), - - ]), - - ]) -} - -FromDropdown.prototype.render = function () { - const { - selectedAccount, - openDropdown, - dropdownOpen, - } = this.props - - return h('div.send-v2__from-dropdown', {}, [ - - h(AccountListItem, { - account: selectedAccount, - handleClick: openDropdown, - icon: h(`i.fa.fa-caret-down.fa-lg`, { style: { color: '#dedede' } }), - }), - - dropdownOpen && this.renderDropdown(), - - ]) - -} - diff --git a/ui/app/components/send/gas-tooltip.js b/ui/app/components/send/gas-tooltip.js deleted file mode 100644 index 62cdc1cad..000000000 --- a/ui/app/components/send/gas-tooltip.js +++ /dev/null @@ -1,106 +0,0 @@ -const Component = require('react').Component -const PropTypes = require('prop-types') -const h = require('react-hyperscript') -const inherits = require('util').inherits -const InputNumber = require('../input-number.js') -const connect = require('react-redux').connect - -GasTooltip.contextTypes = { - t: PropTypes.func, -} - -module.exports = connect()(GasTooltip) - - -inherits(GasTooltip, Component) -function GasTooltip () { - Component.call(this) - this.state = { - gasLimit: 0, - gasPrice: 0, - } - - this.updateGasPrice = this.updateGasPrice.bind(this) - this.updateGasLimit = this.updateGasLimit.bind(this) - this.onClose = this.onClose.bind(this) -} - -GasTooltip.prototype.componentWillMount = function () { - const { gasPrice = 0, gasLimit = 0} = this.props - - this.setState({ - gasPrice: parseInt(gasPrice, 16) / 1000000000, - gasLimit: parseInt(gasLimit, 16), - }) -} - -GasTooltip.prototype.updateGasPrice = function (newPrice) { - const { onFeeChange } = this.props - const { gasLimit } = this.state - - this.setState({ gasPrice: newPrice }) - onFeeChange({ - gasLimit: gasLimit.toString(16), - gasPrice: (newPrice * 1000000000).toString(16), - }) -} - -GasTooltip.prototype.updateGasLimit = function (newLimit) { - const { onFeeChange } = this.props - const { gasPrice } = this.state - - this.setState({ gasLimit: newLimit }) - onFeeChange({ - gasLimit: newLimit.toString(16), - gasPrice: (gasPrice * 1000000000).toString(16), - }) -} - -GasTooltip.prototype.onClose = function (e) { - e.stopPropagation() - this.props.onClose() -} - -GasTooltip.prototype.render = function () { - const { gasPrice, gasLimit } = this.state - - return h('div.gas-tooltip', {}, [ - h('div.gas-tooltip-close-area', { - onClick: this.onClose, - }), - h('div.customize-gas-tooltip-container', {}, [ - h('div.customize-gas-tooltip', {}, [ - h('div.gas-tooltip-header.gas-tooltip-label', {}, ['Customize Gas']), - h('div.gas-tooltip-input-label', {}, [ - h('span.gas-tooltip-label', {}, ['Gas Price']), - h('i.fa.fa-info-circle'), - ]), - h(InputNumber, { - unitLabel: 'GWEI', - step: 1, - min: 0, - placeholder: '0', - value: gasPrice, - onChange: (newPrice) => this.updateGasPrice(newPrice), - }), - h('div.gas-tooltip-input-label', { - style: { - 'marginTop': '81px', - }, - }, [ - h('span.gas-tooltip-label', {}, [this.context.t('gasLimit')]), - h('i.fa.fa-info-circle'), - ]), - h(InputNumber, { - unitLabel: 'UNITS', - step: 1, - min: 0, - placeholder: '0', - value: gasLimit, - onChange: (newLimit) => this.updateGasLimit(newLimit), - }), - ]), - h('div.gas-tooltip-arrow', {}), - ]), - ]) -} diff --git a/ui/app/components/send/memo-textarea.js b/ui/app/components/send/memo-textarea.js deleted file mode 100644 index f4bb24bf8..000000000 --- a/ui/app/components/send/memo-textarea.js +++ /dev/null @@ -1,33 +0,0 @@ -// const Component = require('react').Component -// const h = require('react-hyperscript') -// const inherits = require('util').inherits -// const Identicon = require('../identicon') - -// module.exports = MemoTextArea - -// inherits(MemoTextArea, Component) -// function MemoTextArea () { -// Component.call(this) -// } - -// MemoTextArea.prototype.render = function () { -// const { memo, identities, onChange } = this.props - -// return h('div.send-v2__memo-text-area', [ - -// h('textarea.send-v2__memo-text-area__input', { -// placeholder: 'Optional', -// value: memo, -// onChange, -// // onBlur: () => { -// // this.setErrorsFor('memo') -// // }, -// onFocus: event => { -// // this.clearErrorsFor('memo') -// }, -// }), - -// ]) - -// } - diff --git a/ui/app/components/send/send-constants.js b/ui/app/components/send/send-constants.js deleted file mode 100644 index b3ee0899a..000000000 --- a/ui/app/components/send/send-constants.js +++ /dev/null @@ -1,33 +0,0 @@ -const ethUtil = require('ethereumjs-util') -const { conversionUtil, multiplyCurrencies } = require('../../conversion-util') - -const MIN_GAS_PRICE_HEX = (100000000).toString(16) -const MIN_GAS_PRICE_DEC = '100000000' -const MIN_GAS_LIMIT_DEC = '21000' -const MIN_GAS_LIMIT_HEX = (parseInt(MIN_GAS_LIMIT_DEC)).toString(16) - -const MIN_GAS_PRICE_GWEI = ethUtil.addHexPrefix(conversionUtil(MIN_GAS_PRICE_HEX, { - fromDenomination: 'WEI', - toDenomination: 'GWEI', - fromNumericBase: 'hex', - toNumericBase: 'hex', - numberOfDecimals: 1, -})) - -const MIN_GAS_TOTAL = multiplyCurrencies(MIN_GAS_LIMIT_HEX, MIN_GAS_PRICE_HEX, { - toNumericBase: 'hex', - multiplicandBase: 16, - multiplierBase: 16, -}) - -const TOKEN_TRANSFER_FUNCTION_SIGNATURE = '0xa9059cbb' - -module.exports = { - MIN_GAS_PRICE_GWEI, - MIN_GAS_PRICE_HEX, - MIN_GAS_PRICE_DEC, - MIN_GAS_LIMIT_HEX, - MIN_GAS_LIMIT_DEC, - MIN_GAS_TOTAL, - TOKEN_TRANSFER_FUNCTION_SIGNATURE, -} diff --git a/ui/app/components/send/send-utils.js b/ui/app/components/send/send-utils.js deleted file mode 100644 index 71bfb2668..000000000 --- a/ui/app/components/send/send-utils.js +++ /dev/null @@ -1,78 +0,0 @@ -const { - addCurrencies, - conversionUtil, - conversionGTE, - multiplyCurrencies, -} = require('../../conversion-util') -const { - calcTokenAmount, -} = require('../../token-util') - -function isBalanceSufficient ({ - amount = '0x0', - gasTotal = '0x0', - balance, - primaryCurrency, - amountConversionRate, - conversionRate, -}) { - const totalAmount = addCurrencies(amount, gasTotal, { - aBase: 16, - bBase: 16, - toNumericBase: 'hex', - }) - - const balanceIsSufficient = conversionGTE( - { - value: balance, - fromNumericBase: 'hex', - fromCurrency: primaryCurrency, - conversionRate, - }, - { - value: totalAmount, - fromNumericBase: 'hex', - conversionRate: amountConversionRate || conversionRate, - fromCurrency: primaryCurrency, - }, - ) - - return balanceIsSufficient -} - -function isTokenBalanceSufficient ({ - amount = '0x0', - tokenBalance, - decimals, -}) { - const amountInDec = conversionUtil(amount, { - fromNumericBase: 'hex', - }) - - const tokenBalanceIsSufficient = conversionGTE( - { - value: tokenBalance, - fromNumericBase: 'dec', - }, - { - value: calcTokenAmount(amountInDec, decimals), - fromNumericBase: 'dec', - }, - ) - - return tokenBalanceIsSufficient -} - -function getGasTotal (gasLimit, gasPrice) { - return multiplyCurrencies(gasLimit, gasPrice, { - toNumericBase: 'hex', - multiplicandBase: 16, - multiplierBase: 16, - }) -} - -module.exports = { - getGasTotal, - isBalanceSufficient, - isTokenBalanceSufficient, -} diff --git a/ui/app/components/send/send-v2-container.js b/ui/app/components/send/send-v2-container.js deleted file mode 100644 index cdbee0cdc..000000000 --- a/ui/app/components/send/send-v2-container.js +++ /dev/null @@ -1,95 +0,0 @@ -const connect = require('react-redux').connect -const actions = require('../../actions') -const abi = require('ethereumjs-abi') -const SendEther = require('../../send-v2') -const { withRouter } = require('react-router-dom') -const { compose } = require('recompose') - -const { - accountsWithSendEtherInfoSelector, - getCurrentAccountWithSendEtherInfo, - conversionRateSelector, - getSelectedToken, - getSelectedAddress, - getAddressBook, - getSendFrom, - getCurrentCurrency, - getSelectedTokenToFiatRate, - getSelectedTokenContract, -} = require('../../selectors') - -import { - updateSendErrors, -} from '../../ducks/send' - -module.exports = compose( - withRouter, - connect(mapStateToProps, mapDispatchToProps) -)(SendEther) - -function mapStateToProps (state) { - const fromAccounts = accountsWithSendEtherInfoSelector(state) - const selectedAddress = getSelectedAddress(state) - const selectedToken = getSelectedToken(state) - const conversionRate = conversionRateSelector(state) - - let data - let primaryCurrency - let tokenToFiatRate - if (selectedToken) { - data = Array.prototype.map.call( - abi.rawEncode(['address', 'uint256'], [selectedAddress, '0x0']), - x => ('00' + x.toString(16)).slice(-2) - ).join('') - - primaryCurrency = selectedToken.symbol - - tokenToFiatRate = getSelectedTokenToFiatRate(state) - } - - return { - ...state.metamask.send, - from: getSendFrom(state) || getCurrentAccountWithSendEtherInfo(state), - fromAccounts, - toAccounts: [...fromAccounts, ...getAddressBook(state)], - conversionRate, - selectedToken, - primaryCurrency, - convertedCurrency: getCurrentCurrency(state), - data, - selectedAddress, - amountConversionRate: selectedToken ? tokenToFiatRate : conversionRate, - tokenContract: getSelectedTokenContract(state), - unapprovedTxs: state.metamask.unapprovedTxs, - network: state.metamask.network, - isToken: Boolean(getSelectedToken(state)), - } -} - -function mapDispatchToProps (dispatch) { - return { - showCustomizeGasModal: () => dispatch(actions.showModal({ name: 'CUSTOMIZE_GAS' })), - estimateGas: params => dispatch(actions.estimateGas(params)), - getGasPrice: () => dispatch(actions.getGasPrice()), - signTokenTx: (tokenAddress, toAddress, amount, txData) => ( - dispatch(actions.signTokenTx(tokenAddress, toAddress, amount, txData)) - ), - signTx: txParams => dispatch(actions.signTx(txParams)), - updateAndApproveTx: txParams => dispatch(actions.updateAndApproveTx(txParams)), - updateTx: txData => dispatch(actions.updateTransaction(txData)), - setSelectedAddress: address => dispatch(actions.setSelectedAddress(address)), - addToAddressBook: (address, nickname) => dispatch(actions.addToAddressBook(address, nickname)), - setGasTotal: newTotal => dispatch(actions.setGasTotal(newTotal)), - updateGasTotal: () => dispatch(actions.updateGasTotal()), - updateGasPrice: newGasPrice => dispatch(actions.updateGasPrice(newGasPrice)), - updateGasLimit: newGasLimit => dispatch(actions.updateGasLimit(newGasLimit)), - updateSendTokenBalance: tokenBalance => dispatch(actions.updateSendTokenBalance(tokenBalance)), - updateSendFrom: newFrom => dispatch(actions.updateSendFrom(newFrom)), - updateSendTo: (newTo, nickname) => dispatch(actions.updateSendTo(newTo, nickname)), - updateSendAmount: newAmount => dispatch(actions.updateSendAmount(newAmount)), - updateSendMemo: newMemo => dispatch(actions.updateSendMemo(newMemo)), - updateSendErrors: newError => dispatch(updateSendErrors(newError)), - clearSend: () => dispatch(actions.clearSend()), - setMaxModeTo: bool => dispatch(actions.setMaxModeTo(bool)), - } -} diff --git a/ui/app/components/send/to-autocomplete.js b/ui/app/components/send/to-autocomplete.js index 5ea17f9a2..df74ef194 100644 --- a/ui/app/components/send/to-autocomplete.js +++ b/ui/app/components/send/to-autocomplete.js @@ -2,7 +2,7 @@ const Component = require('react').Component const PropTypes = require('prop-types') const h = require('react-hyperscript') const inherits = require('util').inherits -const AccountListItem = require('./account-list-item') +const AccountListItem = require('../send_/account-list-item/account-list-item.component').default const connect = require('react-redux').connect ToAutoComplete.contextTypes = { diff --git a/ui/app/send-v2.js b/ui/app/send-v2.js deleted file mode 100644 index 228cb22d0..000000000 --- a/ui/app/send-v2.js +++ /dev/null @@ -1,655 +0,0 @@ -const { inherits } = require('util') -const PropTypes = require('prop-types') -const PersistentForm = require('../lib/persistent-form') -const h = require('react-hyperscript') - -const ethAbi = require('ethereumjs-abi') -const ethUtil = require('ethereumjs-util') - -const FromDropdown = require('./components/send/from-dropdown') -const EnsInput = require('./components/ens-input') -const CurrencyDisplay = require('./components/send/currency-display') -const MemoTextArea = require('./components/send/memo-textarea') -const GasFeeDisplay = require('./components/send/gas-fee-display-v2') - -const { - TOKEN_TRANSFER_FUNCTION_SIGNATURE, -} = require('./components/send/send-constants') - -const { - multiplyCurrencies, - conversionGreaterThan, - subtractCurrencies, -} = require('./conversion-util') -const { - calcTokenAmount, -} = require('./token-util') -const { - isBalanceSufficient, - isTokenBalanceSufficient, - getGasTotal, -} = require('./components/send/send-utils') -const { isValidAddress } = require('./util') - -import PageContainer from './components/page-container' -// import SendHeader from './components/send_/send-header/send-header.container' -// import PageContainerContent from './components/page-container/page-container-content.component' -// import PageContainerFooter from './components/page-container/page-container-footer.component' - -SendTransactionScreen.contextTypes = { - t: PropTypes.func, -} - -module.exports = SendTransactionScreen - -inherits(SendTransactionScreen, PersistentForm) -function SendTransactionScreen () { - PersistentForm.call(this) - - this.state = { - fromDropdownOpen: false, - toDropdownOpen: false, - errors: { - to: null, - amount: null, - }, - gasLoadingError: false, - } - - this.handleToChange = this.handleToChange.bind(this) - this.handleAmountChange = this.handleAmountChange.bind(this) - this.validateAmount = this.validateAmount.bind(this) -} - -const getParamsForGasEstimate = function (selectedAddress, symbol, data) { - const estimatedGasParams = { - from: selectedAddress, - gas: '746a528800', - } - - if (symbol) { - Object.assign(estimatedGasParams, { value: '0x0' }) - } - - if (data) { - Object.assign(estimatedGasParams, { data }) - } - - return estimatedGasParams -} - -SendTransactionScreen.prototype.updateSendTokenBalance = function (usersToken) { - if (!usersToken) return - - const { - selectedToken = {}, - updateSendTokenBalance, - } = this.props - const { decimals } = selectedToken || {} - const tokenBalance = calcTokenAmount(usersToken.balance.toString(), decimals) - - updateSendTokenBalance(tokenBalance) -} - -SendTransactionScreen.prototype.componentWillMount = function () { - const { - updateTokenExchangeRate, - selectedToken = {}, - } = this.props - - const { symbol } = selectedToken || {} - - if (symbol) { - updateTokenExchangeRate(symbol) - } - - this.updateGas() -} - -SendTransactionScreen.prototype.updateGas = function () { - const { - selectedToken = {}, - getGasPrice, - estimateGas, - selectedAddress, - data, - updateGasTotal, - from, - tokenContract, - editingTransactionId, - gasPrice, - gasLimit, - } = this.props - - const { symbol } = selectedToken || {} - - const tokenBalancePromise = tokenContract - ? tokenContract.balanceOf(from.address) - : Promise.resolve() - tokenBalancePromise - .then(usersToken => this.updateSendTokenBalance(usersToken)) - - if (!editingTransactionId) { - const estimateGasParams = getParamsForGasEstimate(selectedAddress, symbol, data) - - Promise - .all([ - getGasPrice(), - estimateGas(estimateGasParams), - ]) - .then(([gasPrice, gas]) => { - const newGasTotal = getGasTotal(gas, gasPrice) - updateGasTotal(newGasTotal) - this.setState({ gasLoadingError: false }) - }) - .catch(err => { - this.setState({ gasLoadingError: true }) - }) - } else { - const newGasTotal = getGasTotal(gasLimit, gasPrice) - updateGasTotal(newGasTotal) - } -} - -SendTransactionScreen.prototype.componentDidUpdate = function (prevProps) { - const { - from: { balance }, - gasTotal, - tokenBalance, - amount, - selectedToken, - network, - } = this.props - - const { - from: { balance: prevBalance }, - gasTotal: prevGasTotal, - tokenBalance: prevTokenBalance, - network: prevNetwork, - } = prevProps - - const uninitialized = [prevBalance, prevGasTotal].every(n => n === null) - - const balanceHasChanged = balance !== prevBalance - const gasTotalHasChange = gasTotal !== prevGasTotal - const tokenBalanceHasChanged = selectedToken && tokenBalance !== prevTokenBalance - const amountValidationChange = balanceHasChanged || gasTotalHasChange || tokenBalanceHasChanged - - if (!uninitialized) { - if (amountValidationChange) { - this.validateAmount(amount) - } - - if (network !== prevNetwork && network !== 'loading') { - this.updateGas() - } - } -} - -SendTransactionScreen.prototype.renderErrorMessage = function (errorType) { - const { errors } = this.props - const errorMessage = errors[errorType] - - return errorMessage - ? h('div.send-v2__error', [ errorMessage ]) - : null -} - -SendTransactionScreen.prototype.handleFromChange = async function (newFrom) { - const { - updateSendFrom, - tokenContract, - } = this.props - - if (tokenContract) { - const usersToken = await tokenContract.balanceOf(newFrom.address) - this.updateSendTokenBalance(usersToken) - } - updateSendFrom(newFrom) -} - -SendTransactionScreen.prototype.renderFromRow = function () { - const { - from, - fromAccounts, - conversionRate, - } = this.props - - const { fromDropdownOpen } = this.state - - return h('div.send-v2__form-row', [ - - h('div.send-v2__form-label', 'From:'), - - h('div.send-v2__form-field', [ - h(FromDropdown, { - dropdownOpen: fromDropdownOpen, - accounts: fromAccounts, - selectedAccount: from, - onSelect: newFrom => this.handleFromChange(newFrom), - openDropdown: () => this.setState({ fromDropdownOpen: true }), - closeDropdown: () => this.setState({ fromDropdownOpen: false }), - conversionRate, - }), - ]), - - ]) -} - -SendTransactionScreen.prototype.handleToChange = function (to, nickname = '') { - const { - updateSendTo, - updateSendErrors, - } = this.props - let toError = null - - if (!to) { - toError = this.context.t('required') - } else if (!isValidAddress(to)) { - toError = this.context.t('invalidAddressRecipient') - } - - updateSendTo(to, nickname) - updateSendErrors({ to: toError }) -} - -SendTransactionScreen.prototype.renderToRow = function () { - const { toAccounts, errors, to, network } = this.props - - const { toDropdownOpen } = this.state - - return h('div.send-v2__form-row', [ - - h('div.send-v2__form-label', [ - - this.context.t('to'), - - this.renderErrorMessage(this.context.t('to')), - - ]), - - h('div.send-v2__form-field', [ - h(EnsInput, { - name: 'address', - placeholder: 'Recipient Address', - network, - to, - accounts: Object.entries(toAccounts).map(([key, account]) => account), - dropdownOpen: toDropdownOpen, - openDropdown: () => this.setState({ toDropdownOpen: true }), - closeDropdown: () => this.setState({ toDropdownOpen: false }), - onChange: this.handleToChange, - inError: Boolean(errors.to), - }), - ]), - - ]) -} - -SendTransactionScreen.prototype.handleAmountChange = function (value) { - const amount = value - const { updateSendAmount, setMaxModeTo } = this.props - - setMaxModeTo(false) - this.validateAmount(amount) - updateSendAmount(amount) -} - -SendTransactionScreen.prototype.setAmountToMax = function () { - const { - from: { balance }, - updateSendAmount, - updateSendErrors, - tokenBalance, - selectedToken, - gasTotal, - } = this.props - const { decimals } = selectedToken || {} - const multiplier = Math.pow(10, Number(decimals || 0)) - - const maxAmount = selectedToken - ? multiplyCurrencies(tokenBalance, multiplier, {toNumericBase: 'hex'}) - : subtractCurrencies( - ethUtil.addHexPrefix(balance), - ethUtil.addHexPrefix(gasTotal), - { toNumericBase: 'hex' } - ) - - updateSendErrors({ amount: null }) - - updateSendAmount(maxAmount) -} - -SendTransactionScreen.prototype.validateAmount = function (value) { - const { - from: { balance }, - updateSendErrors, - amountConversionRate, - conversionRate, - primaryCurrency, - selectedToken, - gasTotal, - tokenBalance, - } = this.props - const { decimals } = selectedToken || {} - const amount = value - - let amountError = null - - let sufficientBalance = true - - if (gasTotal) { - sufficientBalance = isBalanceSufficient({ - amount: selectedToken ? '0x0' : amount, - gasTotal, - balance, - primaryCurrency, - amountConversionRate, - conversionRate, - }) - } - - const verifyTokenBalance = selectedToken && tokenBalance !== null - let sufficientTokens - if (verifyTokenBalance) { - sufficientTokens = isTokenBalanceSufficient({ - tokenBalance, - amount, - decimals, - }) - } - - const amountLessThanZero = conversionGreaterThan( - { value: 0, fromNumericBase: 'dec' }, - { value: amount, fromNumericBase: 'hex' }, - ) - - if (conversionRate && !sufficientBalance) { - amountError = this.context.t('insufficientFunds') - } else if (verifyTokenBalance && !sufficientTokens) { - amountError = this.context.t('insufficientTokens') - } else if (amountLessThanZero) { - amountError = this.context.t('negativeETH') - } - - updateSendErrors({ amount: amountError }) -} - -SendTransactionScreen.prototype.renderAmountRow = function () { - const { - selectedToken, - primaryCurrency = 'ETH', - convertedCurrency, - amountConversionRate, - errors, - amount, - setMaxModeTo, - maxModeOn, - gasTotal, - } = this.props - - return h('div.send-v2__form-row', [ - - h('div.send-v2__form-label', [ - 'Amount:', - this.renderErrorMessage('amount'), - !errors.amount && gasTotal && h('div.send-v2__amount-max', { - onClick: (event) => { - event.preventDefault() - setMaxModeTo(true) - this.setAmountToMax() - }, - }, [ !maxModeOn ? this.context.t('max') : '' ]), - ]), - - h('div.send-v2__form-field', [ - h(CurrencyDisplay, { - inError: Boolean(errors.amount), - primaryCurrency, - convertedCurrency, - selectedToken, - value: amount || '0x0', - conversionRate: amountConversionRate, - handleChange: this.handleAmountChange, - }), - ]), - - ]) -} - -SendTransactionScreen.prototype.renderGasRow = function () { - const { - conversionRate, - convertedCurrency, - showCustomizeGasModal, - gasTotal, - } = this.props - const { gasLoadingError } = this.state - - return h('div.send-v2__form-row', [ - - h('div.send-v2__form-label', this.context.t('gasFee')), - - h('div.send-v2__form-field', [ - - h(GasFeeDisplay, { - gasTotal, - conversionRate, - convertedCurrency, - onClick: showCustomizeGasModal, - gasLoadingError, - }), - - ]), - - ]) -} - -SendTransactionScreen.prototype.renderMemoRow = function () { - const { updateSendMemo, memo } = this.props - - return h('div.send-v2__form-row', [ - - h('div.send-v2__form-label', 'Transaction Memo:'), - - h('div.send-v2__form-field', [ - h(MemoTextArea, { - memo, - onChange: (event) => updateSendMemo(event.target.value), - }), - ]), - - ]) -} - -SendTransactionScreen.prototype.renderForm = function () { - return h(PageContainerContent, [ - h('.send-v2__form', [ - this.renderFromRow(), - - this.renderToRow(), - - this.renderAmountRow(), - - this.renderGasRow(), - ]), - ]) -} - -SendTransactionScreen.prototype.renderFooter = function () { - const { - goHome, - clearSend, - gasTotal, - tokenBalance, - selectedToken, - errors: { amount: amountError, to: toError }, - } = this.props - - const missingTokenBalance = selectedToken && !tokenBalance - const noErrors = !amountError && toError === null - - return h(PageContainerFooter, { - onCancel: () => { - clearSend() - goHome() - }, - onSubmit: e => this.onSubmit(e), - disabled: !noErrors || !gasTotal || missingTokenBalance, - }) -} - -SendTransactionScreen.prototype.render = function () { - const { - isToken, - clearSend, - goHome, - gasTotal, - tokenBalance, - selectedToken, - errors: { amount: amountError, to: toError }, - } = this.props - - const missingTokenBalance = selectedToken && !tokenBalance - const noErrors = !amountError && toError === null - - return ( - - h(PageContainer, { - title: isToken ? this.context.t('sendTokens') : this.context.t('sendETH'), - subtitle: this.context.t('onlySendToEtherAddress'), - onClose: () => { - clearSend() - goHome() - }, - ContentComponent: this.renderForm, - onCancel: () => { - clearSend() - goHome() - }, - onSubmit: e => this.onSubmit(e), - disabled: !noErrors || !gasTotal || missingTokenBalance, - }) - // , [ - - // h(SendHeader), - - // this.renderForm(), - - // this.renderFooter(), - // ]) - - ) -} - -SendTransactionScreen.prototype.addToAddressBookIfNew = function (newAddress, nickname = '') { - const { toAccounts, addToAddressBook } = this.props - if (!toAccounts.find(({ address }) => newAddress === address)) { - // TODO: nickname, i.e. addToAddressBook(recipient, nickname) - addToAddressBook(newAddress, nickname) - } -} - -SendTransactionScreen.prototype.getEditedTx = function () { - const { - from: {address: from}, - to, - amount, - gasLimit: gas, - gasPrice, - selectedToken, - editingTransactionId, - unapprovedTxs, - } = this.props - - const editingTx = { - ...unapprovedTxs[editingTransactionId], - txParams: { - from: ethUtil.addHexPrefix(from), - gas: ethUtil.addHexPrefix(gas), - gasPrice: ethUtil.addHexPrefix(gasPrice), - }, - } - - if (selectedToken) { - 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) - ).join('') - - Object.assign(editingTx.txParams, { - value: ethUtil.addHexPrefix('0'), - to: ethUtil.addHexPrefix(selectedToken.address), - data, - }) - } else { - const { data } = unapprovedTxs[editingTransactionId].txParams - - Object.assign(editingTx.txParams, { - value: ethUtil.addHexPrefix(amount), - to: ethUtil.addHexPrefix(to), - data, - }) - - if (typeof editingTx.txParams.data === 'undefined') { - delete editingTx.txParams.data - } - } - - return editingTx -} - -SendTransactionScreen.prototype.onSubmit = function (event) { - event.preventDefault() - const { - from: {address: from}, - to: _to, - amount, - gasLimit: gas, - gasPrice, - signTokenTx, - signTx, - updateTx, - selectedToken, - editingTransactionId, - toNickname, - errors: { amount: amountError, to: toError }, - } = this.props - - const noErrors = !amountError && toError === null - - if (!noErrors) { - return - } - - const to = ethUtil.addHexPrefix(_to) - - this.addToAddressBookIfNew(to, toNickname) - - if (editingTransactionId) { - const editedTx = this.getEditedTx() - - updateTx(editedTx) - } else { - - const txParams = { - from, - value: '0', - gas, - gasPrice, - } - - if (!selectedToken) { - txParams.value = amount - txParams.to = to - } - - Object.keys(txParams).forEach(key => { - txParams[key] = ethUtil.addHexPrefix(txParams[key]) - }) - - selectedToken - ? signTokenTx(selectedToken.address, to, amount, txParams) - : signTx(txParams) - } -} |