diff --git a/ui/app/actions.js b/ui/app/actions.js index 0a2b4a636..a43809fc0 100644 --- a/ui/app/actions.js +++ b/ui/app/actions.js @@ -129,6 +129,17 @@ var actions = { cancelAllTx: cancelAllTx, viewPendingTx: viewPendingTx, VIEW_PENDING_TX: 'VIEW_PENDING_TX', + // send screen + estimateGas, + updateGasEstimate, + UPDATE_GAS_ESTIMATE: 'UPDATE_GAS_ESTIMATE', + updateGasPrice, + UPDATE_GAS_PRICE: 'UPDATE_GAS_PRICE', + getGasPrice, + CLEAR_GAS_ESTIMATE: 'CLEAR_GAS_ESTIMATE', + CLEAR_GAS_PRICE: 'CLEAR_GAS_PRICE', + clearGasEstimate, + clearGasPrice, // app messages confirmSeedWords: confirmSeedWords, showAccountDetail: showAccountDetail, @@ -449,6 +460,26 @@ function signTx (txData) { } } +function estimateGas ({ to, amount }) { + return (dispatch) => { + global.ethQuery.estimateGas({ to, amount }, (err, data) => { + if (err) return dispatch(actions.displayWarning(err.message)) + dispatch(actions.hideWarning()) + dispatch(actions.updateGasEstimate(data)) + }) + } +} + +function getGasPrice () { + return (dispatch) => { + global.ethQuery.gasPrice((err, data) => { + if (err) return dispatch(actions.displayWarning(err.message)) + dispatch(actions.hideWarning()) + dispatch(actions.updateGasPrice(data)) + }) + } +} + function sendTx (txData) { log.info(`actions - sendTx: ${JSON.stringify(txData.txParams)}`) return (dispatch) => { @@ -506,6 +537,32 @@ function txError (err) { } } +function updateGasEstimate (gas) { + return { + type: actions.UPDATE_GAS_ESTIMATE, + value: gas, + } +} + +function clearGasEstimate () { + return { + type: actions.CLEAR_GAS_ESTIMATE, + } +} + +function updateGasPrice (gasPrice) { + return { + type: actions.UPDATE_GAS_PRICE, + value: gasPrice, + } +} + +function clearGasPrice () { + return { + type: actions.CLEAR_GAS_PRICE, + } +} + function cancelMsg (msgData) { log.debug(`background.cancelMessage`) background.cancelMessage(msgData.id) diff --git a/ui/app/reducers/metamask.js b/ui/app/reducers/metamask.js index cdc98d05e..e78f51f3a 100644 --- a/ui/app/reducers/metamask.js +++ b/ui/app/reducers/metamask.js @@ -19,6 +19,8 @@ function reduceMetamask (state, action) { addressBook: [], selectedTokenAddress: null, tokenExchangeRates: {}, + estimatedGas: null, + blockGasPrice: null, }, state.metamask) switch (action.type) { @@ -74,6 +76,26 @@ function reduceMetamask (state, action) { }, }) + case actions.UPDATE_GAS_ESTIMATE: + return extend(metamaskState, { + estimatedGas: action.value, + }) + + case actions.UPDATE_GAS_PRICE: + return extend(metamaskState, { + blockGasPrice: action.value, + }) + + case actions.CLEAR_GAS_ESTIMATE: + return extend(metamaskState, { + estimatedGas: null, + }) + + case actions.CLEAR_GAS_PRICE: + return extend(metamaskState, { + blockGasPrice: null, + }) + case actions.COMPLETED_TX: var stringId = String(action.id) newState = extend(metamaskState, { diff --git a/ui/app/send.js b/ui/app/send.js index 16fe470be..4ce7fc475 100644 --- a/ui/app/send.js +++ b/ui/app/send.js @@ -16,6 +16,10 @@ const { hideWarning, addToAddressBook, signTx, + estimateGas, + getGasPrice, + clearGasEstimate, + clearGasPrice, } = require('./actions') const { stripHexPrefix, addHexPrefix } = require('ethereumjs-util') const { isHex, numericBalance, isValidAddress, allNull } = require('./util') @@ -33,6 +37,8 @@ function mapStateToProps (state) { addressBook, conversionRate, currentBlockGasLimit: blockGasLimit, + estimatedGas, + blockGasPrice, } = state.metamask const { warning } = state.appState const selectedIdentity = getSelectedIdentity(state) @@ -46,6 +52,8 @@ function mapStateToProps (state) { addressBook, conversionRate, blockGasLimit, + blockGasPrice, + estimatedGas, warning, selectedIdentity, error: warning && warning.split('.')[0], @@ -67,8 +75,11 @@ function SendTransactionScreen () { to: '', amount: 0, amountToSend: '0x0', - gasPrice: '0x5d21dba00', - gas: '0x7b0d', + gasPrice: null, + gas: null, + amount: '0x0', + gasPrice: null, + gas: null, txData: null, memo: '', }, @@ -87,6 +98,7 @@ function SendTransactionScreen () { this.getAmountToSend = this.getAmountToSend.bind(this) this.setErrorsFor = this.setErrorsFor.bind(this) this.clearErrorsFor = this.clearErrorsFor.bind(this) + this.estimateGasAndPrice = this.estimateGasAndPrice.bind(this) this.renderFromInput = this.renderFromInput.bind(this) this.renderToInput = this.renderToInput.bind(this) @@ -96,6 +108,11 @@ function SendTransactionScreen () { this.renderErrorMessage = this.renderErrorMessage.bind(this) } +SendTransactionScreen.prototype.componentWillMount = function() { + this.props.dispatch(clearGasEstimate()) + this.props.dispatch(clearGasPrice()) +} + SendTransactionScreen.prototype.renderErrorMessage = function(errorType, warning) { const { errors } = this.state const errorMessage = errors[errorType]; @@ -159,7 +176,10 @@ SendTransactionScreen.prototype.renderToInput = function (to, identities, addres }, }) }, - onBlur: () => this.setErrorsFor('to'), + onBlur: () => { + this.setErrorsFor('to') + this.estimateGasAndPrice() + }, onFocus: () => this.clearErrorsFor('to'), }), @@ -212,7 +232,10 @@ SendTransactionScreen.prototype.renderAmountInput = function (activeCurrency) { ), }) }, - onBlur: () => this.setErrorsFor('amount'), + onBlur: () => { + this.setErrorsFor('amount') + this.estimateGasAndPrice() + }, onFocus: () => this.clearErrorsFor('amount'), }), @@ -293,6 +316,8 @@ SendTransactionScreen.prototype.render = function () { identities, addressBook, conversionRate, + estimatedGas, + blockGasPrice, } = props const { blockGasLimit, newTx, activeCurrency, isValid } = this.state @@ -316,7 +341,13 @@ SendTransactionScreen.prototype.render = function () { this.renderAmountInput(activeCurrency), - this.renderGasInput(gasPrice, gas, activeCurrency, conversionRate, blockGasLimit), + this.renderGasInput( + gasPrice || blockGasPrice || '0x0', + gas || estimatedGas || '0x0', + activeCurrency, + conversionRate, + blockGasLimit + ), this.renderMemoInput(), @@ -351,6 +382,15 @@ SendTransactionScreen.prototype.setActiveCurrency = function (newCurrency) { this.setState({ activeCurrency: newCurrency }) } +SendTransactionScreen.prototype.estimateGasAndPrice = function () { + const { errors, sendAmount, newTx } = this.state + + if (!errors.to && !errors.amount && newTx.amount > 0) { + this.props.dispatch(getGasPrice()) + this.props.dispatch(estimateGas({ to: newTx.to, amount: sendAmount })) + } +} + SendTransactionScreen.prototype.back = function () { var address = this.props.address this.props.dispatch(backToAccountDetail(address)) @@ -471,7 +511,7 @@ SendTransactionScreen.prototype.clearErrorsFor = function (field) { SendTransactionScreen.prototype.onSubmit = function (event) { event.preventDefault() - const { warning, balance, amountToSend } = this.props + const { warning, balance } = this.props const state = this.state || {} const recipient = state.newTx.to @@ -489,7 +529,7 @@ SendTransactionScreen.prototype.onSubmit = function (event) { from: this.state.newTx.from, to: this.state.newTx.to, - value: amountToSend, + value: this.state.newTx.amountToSend, gas: this.state.newTx.gas, gasPrice: this.state.newTx.gasPrice,