aboutsummaryrefslogtreecommitdiffstats
path: root/ui/app/send.js
diff options
context:
space:
mode:
Diffstat (limited to 'ui/app/send.js')
-rw-r--r--ui/app/send.js856
1 files changed, 547 insertions, 309 deletions
diff --git a/ui/app/send.js b/ui/app/send.js
index 09c9e03d4..517b7690d 100644
--- a/ui/app/send.js
+++ b/ui/app/send.js
@@ -1,309 +1,547 @@
-const inherits = require('util').inherits
-const PersistentForm = require('../lib/persistent-form')
-const h = require('react-hyperscript')
-const connect = require('react-redux').connect
-const Identicon = require('./components/identicon')
-const actions = require('./actions')
-const util = require('./util')
-const numericBalance = require('./util').numericBalance
-const addressSummary = require('./util').addressSummary
-const isHex = require('./util').isHex
-const EthBalance = require('./components/eth-balance')
-const EnsInput = require('./components/ens-input')
-const ethUtil = require('ethereumjs-util')
-module.exports = connect(mapStateToProps)(SendTransactionScreen)
-
-function mapStateToProps (state) {
- var result = {
- address: state.metamask.selectedAddress,
- accounts: state.metamask.accounts,
- identities: state.metamask.identities,
- warning: state.appState.warning,
- network: state.metamask.network,
- addressBook: state.metamask.addressBook,
- conversionRate: state.metamask.conversionRate,
- currentCurrency: state.metamask.currentCurrency,
- }
-
- result.error = result.warning && result.warning.split('.')[0]
-
- result.account = result.accounts[result.address]
- result.identity = result.identities[result.address]
- result.balance = result.account ? numericBalance(result.account.balance) : null
-
- return result
-}
-
-inherits(SendTransactionScreen, PersistentForm)
-function SendTransactionScreen () {
- PersistentForm.call(this)
-}
-
-SendTransactionScreen.prototype.render = function () {
- this.persistentFormParentId = 'send-tx-form'
-
- const props = this.props
- const {
- address,
- account,
- identity,
- network,
- identities,
- addressBook,
- conversionRate,
- currentCurrency,
- } = props
-
- return (
-
- h('.send-screen.flex-column.flex-grow', [
-
- //
- // Sender Profile
- //
-
- h('.account-data-subsection.flex-row.flex-grow', {
- style: {
- margin: '0 20px',
- },
- }, [
-
- // header - identicon + nav
- h('.flex-row.flex-space-between', {
- style: {
- marginTop: '15px',
- },
- }, [
- // back button
- h('i.fa.fa-arrow-left.fa-lg.cursor-pointer.color-orange', {
- onClick: this.back.bind(this),
- }),
-
- // large identicon
- h('.identicon-wrapper.flex-column.flex-center.select-none', [
- h(Identicon, {
- diameter: 62,
- address: address,
- }),
- ]),
-
- // invisible place holder
- h('i.fa.fa-users.fa-lg.invisible', {
- style: {
- marginTop: '28px',
- },
- }),
-
- ]),
-
- // account label
-
- h('.flex-column', {
- style: {
- marginTop: '10px',
- alignItems: 'flex-start',
- },
- }, [
- h('h2.font-medium.color-forest.flex-center', {
- style: {
- paddingTop: '8px',
- marginBottom: '8px',
- },
- }, identity && identity.name),
-
- // address and getter actions
- h('.flex-row.flex-center', {
- style: {
- marginBottom: '8px',
- },
- }, [
-
- h('div', {
- style: {
- lineHeight: '16px',
- },
- }, addressSummary(address)),
-
- ]),
-
- // balance
- h('.flex-row.flex-center', [
-
- h(EthBalance, {
- value: account && account.balance,
- conversionRate,
- currentCurrency,
- }),
-
- ]),
- ]),
- ]),
-
- //
- // Required Fields
- //
-
- h('h3.flex-center.text-transform-uppercase', {
- style: {
- background: '#EBEBEB',
- color: '#AEAEAE',
- marginTop: '15px',
- marginBottom: '16px',
- },
- }, [
- 'Send Transaction',
- ]),
-
- // error message
- props.error && h('span.error.flex-center', props.error),
-
- // 'to' field
- h('section.flex-row.flex-center', [
- h(EnsInput, {
- name: 'address',
- placeholder: 'Recipient Address',
- onChange: this.recipientDidChange.bind(this),
- network,
- identities,
- addressBook,
- }),
- ]),
-
- // 'amount' and send button
- h('section.flex-row.flex-center', [
-
- h('input.large-input', {
- name: 'amount',
- placeholder: 'Amount',
- type: 'number',
- style: {
- marginRight: '6px',
- },
- dataset: {
- persistentFormId: 'tx-amount',
- },
- }),
-
- h('button.primary', {
- onClick: this.onSubmit.bind(this),
- style: {
- textTransform: 'uppercase',
- },
- }, 'Next'),
-
- ]),
-
- //
- // Optional Fields
- //
- h('h3.flex-center.text-transform-uppercase', {
- style: {
- background: '#EBEBEB',
- color: '#AEAEAE',
- marginTop: '16px',
- marginBottom: '16px',
- },
- }, [
- 'Transaction Data (optional)',
- ]),
-
- // 'data' field
- h('section.flex-column.flex-center', [
- h('input.large-input', {
- name: 'txData',
- placeholder: '0x01234',
- style: {
- width: '100%',
- resize: 'none',
- },
- dataset: {
- persistentFormId: 'tx-data',
- },
- }),
- ]),
- ])
- )
-}
-
-SendTransactionScreen.prototype.navigateToAccounts = function (event) {
- event.stopPropagation()
- this.props.dispatch(actions.showAccountsPage())
-}
-
-SendTransactionScreen.prototype.back = function () {
- var address = this.props.address
- this.props.dispatch(actions.backToAccountDetail(address))
-}
-
-SendTransactionScreen.prototype.recipientDidChange = function (recipient, nickname) {
- this.setState({
- recipient: recipient,
- nickname: nickname,
- })
-}
-
-SendTransactionScreen.prototype.onSubmit = function () {
- const state = this.state || {}
- const recipient = state.recipient || document.querySelector('input[name="address"]').value.replace(/^[.\s]+|[.\s]+$/g, '')
- const nickname = state.nickname || ' '
- const input = document.querySelector('input[name="amount"]').value
- const parts = input.split('')
-
- let message
-
- if (isNaN(input) || input === '') {
- message = 'Invalid ether value.'
- return this.props.dispatch(actions.displayWarning(message))
- }
-
- if (parts[1]) {
- var decimal = parts[1]
- if (decimal.length > 18) {
- message = 'Ether amount is too precise.'
- return this.props.dispatch(actions.displayWarning(message))
- }
- }
-
- const value = util.normalizeEthStringToWei(input)
- const txData = document.querySelector('input[name="txData"]').value
- const balance = this.props.balance
-
- if (value.gt(balance)) {
- message = 'Insufficient funds.'
- return this.props.dispatch(actions.displayWarning(message))
- }
-
- if (input < 0) {
- message = 'Can not send negative amounts of ETH.'
- return this.props.dispatch(actions.displayWarning(message))
- }
-
- if ((util.isInvalidChecksumAddress(recipient))) {
- message = 'Recipient address checksum is invalid.'
- return this.props.dispatch(actions.displayWarning(message))
- }
-
- if ((!util.isValidAddress(recipient) && !txData) || (!recipient && !txData)) {
- message = 'Recipient address is invalid.'
- return this.props.dispatch(actions.displayWarning(message))
- }
-
- if (!isHex(ethUtil.stripHexPrefix(txData)) && txData) {
- message = 'Transaction data must be hex string.'
- return this.props.dispatch(actions.displayWarning(message))
- }
-
- this.props.dispatch(actions.hideWarning())
-
- this.props.dispatch(actions.addToAddressBook(recipient, nickname))
-
- var txParams = {
- from: this.props.address,
- value: '0x' + value.toString(16),
- }
-
- if (recipient) txParams.to = ethUtil.addHexPrefix(recipient)
- if (txData) txParams.data = txData
-
- this.props.dispatch(actions.signTx(txParams))
-}
+// const { inherits } = require('util')
+// const PersistentForm = require('../lib/persistent-form')
+// const h = require('react-hyperscript')
+// const connect = require('react-redux').connect
+// const Identicon = require('./components/identicon')
+// const EnsInput = require('./components/ens-input')
+// const GasTooltip = require('./components/send/gas-tooltip')
+// const CurrencyToggle = require('./components/send/currency-toggle')
+// const GasFeeDisplay = require('./components/send/gas-fee-display')
+// const { getSelectedIdentity } = require('./selectors')
+
+// const {
+// showAccountsPage,
+// backToAccountDetail,
+// displayWarning,
+// hideWarning,
+// addToAddressBook,
+// signTx,
+// estimateGas,
+// getGasPrice,
+// } = require('./actions')
+// const { stripHexPrefix, addHexPrefix } = require('ethereumjs-util')
+// const { isHex, numericBalance, isValidAddress, allNull } = require('./util')
+// const { conversionUtil, conversionGreaterThan } = require('./conversion-util')
+
+// module.exports = connect(mapStateToProps)(SendTransactionScreen)
+
+// function mapStateToProps (state) {
+// const {
+// selectedAddress: address,
+// accounts,
+// identities,
+// network,
+// addressBook,
+// conversionRate,
+// currentBlockGasLimit: blockGasLimit,
+// } = state.metamask
+// const { warning } = state.appState
+// const selectedIdentity = getSelectedIdentity(state)
+// const account = accounts[address]
+
+// return {
+// address,
+// accounts,
+// identities,
+// network,
+// addressBook,
+// conversionRate,
+// blockGasLimit,
+// warning,
+// selectedIdentity,
+// error: warning && warning.split('.')[0],
+// account,
+// identity: identities[address],
+// balance: account ? account.balance : null,
+// }
+// }
+
+// inherits(SendTransactionScreen, PersistentForm)
+// function SendTransactionScreen () {
+// PersistentForm.call(this)
+
+// // [WIP] These are the bare minimum of tx props needed to sign a transaction
+// // We will need a few more for contract-related interactions
+// this.state = {
+// newTx: {
+// from: '',
+// to: '',
+// amountToSend: '0x0',
+// gasPrice: null,
+// gas: null,
+// amount: '0x0',
+// txData: null,
+// memo: '',
+// },
+// activeCurrency: 'USD',
+// tooltipIsOpen: false,
+// errors: {},
+// isValid: false,
+// }
+
+// this.back = this.back.bind(this)
+// this.closeTooltip = this.closeTooltip.bind(this)
+// this.onSubmit = this.onSubmit.bind(this)
+// this.setActiveCurrency = this.setActiveCurrency.bind(this)
+// this.toggleTooltip = this.toggleTooltip.bind(this)
+// this.validate = this.validate.bind(this)
+// this.getAmountToSend = this.getAmountToSend.bind(this)
+// this.setErrorsFor = this.setErrorsFor.bind(this)
+// this.clearErrorsFor = this.clearErrorsFor.bind(this)
+
+// this.renderFromInput = this.renderFromInput.bind(this)
+// this.renderToInput = this.renderToInput.bind(this)
+// this.renderAmountInput = this.renderAmountInput.bind(this)
+// this.renderGasInput = this.renderGasInput.bind(this)
+// this.renderMemoInput = this.renderMemoInput.bind(this)
+// this.renderErrorMessage = this.renderErrorMessage.bind(this)
+// }
+
+// SendTransactionScreen.prototype.componentWillMount = function () {
+// const { newTx } = this.state
+// const { address } = this.props
+
+// Promise.all([
+// this.props.dispatch(getGasPrice()),
+// this.props.dispatch(estimateGas({
+// from: address,
+// gas: '746a528800',
+// })),
+// ])
+// .then(([blockGasPrice, estimatedGas]) => {
+// console.log({ blockGasPrice, estimatedGas})
+// this.setState({
+// newTx: {
+// ...newTx,
+// gasPrice: blockGasPrice,
+// gas: estimatedGas,
+// },
+// })
+// })
+// }
+
+// SendTransactionScreen.prototype.renderErrorMessage = function(errorType, warning) {
+// const { errors } = this.state
+// const errorMessage = errors[errorType];
+
+// return errorMessage || warning
+// ? h('div.send-screen-input-wrapper__error-message', [ errorMessage || warning ])
+// : null
+// }
+
+// SendTransactionScreen.prototype.renderFromInput = function (from, identities) {
+// return h('div.send-screen-input-wrapper', [
+
+// h('div', 'From:'),
+
+// h('input.large-input.send-screen-input', {
+// list: 'accounts',
+// placeholder: 'Account',
+// value: from,
+// onChange: (event) => {
+// this.setState({
+// newTx: {
+// ...this.state.newTx,
+// from: event.target.value,
+// },
+// })
+// },
+// onBlur: () => this.setErrorsFor('from'),
+// onFocus: event => {
+// this.clearErrorsFor('from')
+// this.state.newTx.from && event.target.select()
+// },
+// }),
+
+// h('datalist#accounts', [
+// Object.entries(identities).map(([key, { address, name }]) => {
+// return h('option', {
+// value: address,
+// label: name,
+// key: address,
+// })
+// }),
+// ]),
+
+// this.renderErrorMessage('from'),
+
+// ])
+// }
+
+// SendTransactionScreen.prototype.renderToInput = function (to, identities, addressBook) {
+// return h('div.send-screen-input-wrapper', [
+
+// h('div', 'To:'),
+
+// h('input.large-input.send-screen-input', {
+// name: 'address',
+// list: 'addresses',
+// placeholder: 'Address',
+// value: to,
+// onChange: (event) => {
+// this.setState({
+// newTx: {
+// ...this.state.newTx,
+// to: event.target.value,
+// },
+// })
+// },
+// onBlur: () => {
+// this.setErrorsFor('to')
+// },
+// onFocus: event => {
+// this.clearErrorsFor('to')
+// this.state.newTx.to && event.target.select()
+// },
+// }),
+
+// h('datalist#addresses', [
+// // Corresponds to the addresses owned.
+// ...Object.entries(identities).map(([key, { address, name }]) => {
+// return h('option', {
+// value: address,
+// label: name,
+// key: address,
+// })
+// }),
+// // Corresponds to previously sent-to addresses.
+// ...addressBook.map(({ address, name }) => {
+// return h('option', {
+// value: address,
+// label: name,
+// key: address,
+// })
+// }),
+// ]),
+
+// this.renderErrorMessage('to'),
+
+// ])
+// }
+
+// SendTransactionScreen.prototype.renderAmountInput = function (activeCurrency) {
+// return h('div.send-screen-input-wrapper', [
+
+// h('div.send-screen-amount-labels', [
+// h('span', 'Amount'),
+// h(CurrencyToggle, {
+// activeCurrency,
+// onClick: (newCurrency) => this.setActiveCurrency(newCurrency),
+// }), // holding on icon from design
+// ]),
+
+// h('input.large-input.send-screen-input', {
+// placeholder: `0 ${activeCurrency}`,
+// type: 'number',
+// onChange: (event) => {
+// const amountToSend = event.target.value
+// ? this.getAmountToSend(event.target.value)
+// : '0x0'
+
+// this.setState({
+// newTx: Object.assign(
+// this.state.newTx,
+// {
+// amount: event.target.value,
+// amountToSend: amountToSend,
+// }
+// ),
+// })
+// },
+// onBlur: () => {
+// this.setErrorsFor('amount')
+// },
+// onFocus: () => this.clearErrorsFor('amount'),
+// }),
+
+// this.renderErrorMessage('amount'),
+
+// ])
+// }
+
+// SendTransactionScreen.prototype.renderGasInput = function (gasPrice, gas, activeCurrency, conversionRate, blockGasLimit) {
+// return h('div.send-screen-input-wrapper', [
+// this.state.tooltipIsOpen && h(GasTooltip, {
+// className: 'send-tooltip',
+// gasPrice,
+// gasLimit: gas,
+// onClose: this.closeTooltip,
+// onFeeChange: ({gasLimit, gasPrice}) => {
+// this.setState({
+// newTx: {
+// ...this.state.newTx,
+// gas: gasLimit,
+// gasPrice,
+// },
+// })
+// },
+// }),
+
+// h('div.send-screen-gas-labels', [
+// h('span', [
+// h('i.fa.fa-bolt'),
+// 'Gas fee:',
+// ]),
+// h('span', 'What\'s this?'),
+// ]),
+
+// // TODO: handle loading time when switching to USD
+// h('div.large-input.send-screen-gas-input', {}, [
+// h(GasFeeDisplay, {
+// activeCurrency,
+// conversionRate,
+// gas,
+// gasPrice,
+// blockGasLimit,
+// }),
+// h('div.send-screen-gas-input-customize', {
+// onClick: this.toggleTooltip,
+// }, [
+// 'Customize',
+// ]),
+// ]),
+
+// ])
+// }
+
+// SendTransactionScreen.prototype.renderMemoInput = function () {
+// return h('div.send-screen-input-wrapper', [
+// h('div', 'Transaction memo (optional)'),
+// h('input.large-input.send-screen-input', {
+// onChange: () => {
+// this.setState({
+// newTx: Object.assign(
+// this.state.newTx,
+// {
+// memo: event.target.value,
+// }
+// ),
+// })
+// },
+// }),
+// ])
+// }
+
+// SendTransactionScreen.prototype.render = function () {
+// this.persistentFormParentId = 'send-tx-form'
+
+// const props = this.props
+// const {
+// warning,
+// identities,
+// addressBook,
+// conversionRate,
+// } = props
+
+// const {
+// blockGasLimit,
+// newTx,
+// activeCurrency,
+// isValid,
+// } = this.state
+// const { gas, gasPrice } = newTx
+
+// return (
+
+// h('div.send-screen-wrapper', [
+// // Main Send token Card
+// h('div.send-screen-card', [
+
+// h('img.send-eth-icon', { src: '../images/eth_logo.svg' }),
+
+// h('div.send-screen__title', 'Send'),
+
+// h('div.send-screen__subtitle', 'Send Ethereum to anyone with an Ethereum account'),
+
+// this.renderFromInput(this.state.newTx.from, identities),
+
+// this.renderToInput(this.state.newTx.to, identities, addressBook),
+
+// this.renderAmountInput(activeCurrency),
+
+// this.renderGasInput(
+// gasPrice || '0x0',
+// gas || '0x0',
+// activeCurrency,
+// conversionRate,
+// blockGasLimit
+// ),
+
+// this.renderMemoInput(),
+
+// this.renderErrorMessage(null, warning),
+
+// ]),
+
+// // Buttons underneath card
+// h('section.flex-column.flex-center', [
+// h('button.btn-secondary.send-screen__send-button', {
+// className: !isValid && 'send-screen__send-button__disabled',
+// onClick: (event) => isValid && this.onSubmit(event),
+// }, 'Next'),
+// h('button.btn-tertiary.send-screen__cancel-button', {
+// onClick: this.back,
+// }, 'Cancel'),
+// ]),
+// ])
+
+// )
+// }
+
+// SendTransactionScreen.prototype.toggleTooltip = function () {
+// this.setState({ tooltipIsOpen: !this.state.tooltipIsOpen })
+// }
+
+// SendTransactionScreen.prototype.closeTooltip = function () {
+// this.setState({ tooltipIsOpen: false })
+// }
+
+// SendTransactionScreen.prototype.setActiveCurrency = function (newCurrency) {
+// this.setState({ activeCurrency: newCurrency })
+// }
+
+// SendTransactionScreen.prototype.back = function () {
+// var address = this.props.address
+// this.props.dispatch(backToAccountDetail(address))
+// }
+
+// SendTransactionScreen.prototype.validate = function (balance, amountToSend, { to, from }) {
+// const sufficientBalance = conversionGreaterThan(
+// {
+// value: balance,
+// fromNumericBase: 'hex',
+// },
+// {
+// value: amountToSend,
+// fromNumericBase: 'hex',
+// },
+// )
+
+// const amountLessThanZero = conversionGreaterThan(
+// {
+// value: 0,
+// fromNumericBase: 'dec',
+// },
+// {
+// value: amountToSend,
+// fromNumericBase: 'hex',
+// },
+// )
+
+// const errors = {}
+
+// if (!sufficientBalance) {
+// errors.amount = 'Insufficient funds.'
+// }
+
+// if (amountLessThanZero) {
+// errors.amount = 'Can not send negative amounts of ETH.'
+// }
+
+// if (!from) {
+// errors.from = 'Required'
+// }
+
+// if (from && !isValidAddress(from)) {
+// errors.from = 'Sender address is invalid.'
+// }
+
+// if (!to) {
+// errors.to = 'Required'
+// }
+
+// if (to && !isValidAddress(to)) {
+// errors.to = 'Recipient address is invalid.'
+// }
+
+// // if (txData && !isHex(stripHexPrefix(txData))) {
+// // message = 'Transaction data must be hex string.'
+// // return this.props.dispatch(displayWarning(message))
+// // }
+
+// return {
+// isValid: allNull(errors),
+// errors,
+// }
+// }
+
+// SendTransactionScreen.prototype.getAmountToSend = function (amount) {
+// const { activeCurrency } = this.state
+// const { conversionRate } = this.props
+
+// return conversionUtil(amount, {
+// fromNumericBase: 'dec',
+// toNumericBase: 'hex',
+// fromCurrency: activeCurrency,
+// toCurrency: 'ETH',
+// toDenomination: 'WEI',
+// conversionRate,
+// invertConversionRate: activeCurrency !== 'ETH',
+// })
+// }
+
+// SendTransactionScreen.prototype.setErrorsFor = function (field) {
+// const { balance } = this.props
+// const { newTx, errors: previousErrors } = this.state
+// const { amountToSend } = newTx
+
+// const {
+// isValid,
+// errors: newErrors
+// } = this.validate(balance, amountToSend, newTx)
+
+// const nextErrors = Object.assign({}, previousErrors, {
+// [field]: newErrors[field] || null
+// })
+
+// if (!isValid) {
+// this.setState({
+// errors: nextErrors,
+// isValid,
+// })
+// }
+// }
+
+// SendTransactionScreen.prototype.clearErrorsFor = function (field) {
+// const { errors: previousErrors } = this.state
+// const nextErrors = Object.assign({}, previousErrors, {
+// [field]: null
+// })
+
+// this.setState({
+// errors: nextErrors,
+// isValid: allNull(nextErrors),
+// })
+// }
+
+// SendTransactionScreen.prototype.onSubmit = function (event) {
+// event.preventDefault()
+// const { warning, balance } = this.props
+// const state = this.state || {}
+
+// const recipient = state.newTx.to
+// const sender = state.newTx.from
+// const nickname = state.nickname || ' '
+
+// // TODO: convert this to hex when created and include it in send
+// const txData = state.newTx.memo
+
+// this.props.dispatch(hideWarning())
+
+// this.props.dispatch(addToAddressBook(recipient, nickname))
+
+// var txParams = {
+// from: this.state.newTx.from,
+// to: this.state.newTx.to,
+
+// value: this.state.newTx.amountToSend,
+
+// gas: this.state.newTx.gas,
+// gasPrice: this.state.newTx.gasPrice,
+// }
+
+// if (recipient) txParams.to = addHexPrefix(recipient)
+// if (txData) txParams.data = txData
+
+// this.props.dispatch(signTx(txParams))
+// }