mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-23 09:52:26 +01:00
Merge pull request #2157 from danjm/MM-57-use-gas-estimator
[NewUI] Estimate gasPrice and gasLimit in send screen.
This commit is contained in:
commit
d1737777f0
@ -129,6 +129,9 @@ var actions = {
|
||||
cancelAllTx: cancelAllTx,
|
||||
viewPendingTx: viewPendingTx,
|
||||
VIEW_PENDING_TX: 'VIEW_PENDING_TX',
|
||||
// send screen
|
||||
estimateGas,
|
||||
getGasPrice,
|
||||
// app messages
|
||||
confirmSeedWords: confirmSeedWords,
|
||||
showAccountDetail: showAccountDetail,
|
||||
@ -449,6 +452,36 @@ function signTx (txData) {
|
||||
}
|
||||
}
|
||||
|
||||
function estimateGas ({ to, amount }) {
|
||||
return (dispatch) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
global.ethQuery.estimateGas({ to, amount }, (err, data) => {
|
||||
if (err) {
|
||||
dispatch(actions.displayWarning(err.message))
|
||||
return reject(err)
|
||||
}
|
||||
dispatch(actions.hideWarning())
|
||||
return resolve(data)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function getGasPrice () {
|
||||
return (dispatch) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
global.ethQuery.gasPrice((err, data) => {
|
||||
if (err) {
|
||||
dispatch(actions.displayWarning(err.message))
|
||||
return reject(err)
|
||||
}
|
||||
dispatch(actions.hideWarning())
|
||||
return resolve(data)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function sendTx (txData) {
|
||||
log.info(`actions - sendTx: ${JSON.stringify(txData.txParams)}`)
|
||||
return (dispatch) => {
|
||||
|
@ -5,7 +5,7 @@ const classnames = require('classnames')
|
||||
const inherits = require('util').inherits
|
||||
const actions = require('../../actions')
|
||||
const selectors = require('../../selectors')
|
||||
const { isValidAddress } = require('../../util')
|
||||
const { isValidAddress, allNull } = require('../../util')
|
||||
|
||||
// const BalanceComponent = require('./balance-component')
|
||||
const Identicon = require('../identicon')
|
||||
@ -57,6 +57,9 @@ function mapDispatchToProps (dispatch) {
|
||||
dispatch(actions.signTokenTx(tokenAddress, toAddress, amount, txData))
|
||||
),
|
||||
updateTokenExchangeRate: token => dispatch(actions.updateTokenExchangeRate(token)),
|
||||
estimateGas: ({ to, amount }) => dispatch(actions.estimateGas({ to, amount })),
|
||||
getGasPrice: () => dispatch(actions.getGasPrice()),
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -65,11 +68,12 @@ function SendTokenScreen () {
|
||||
Component.call(this)
|
||||
this.state = {
|
||||
to: '',
|
||||
amount: '',
|
||||
amount: '0x0',
|
||||
amountToSend: '0x0',
|
||||
selectedCurrency: 'USD',
|
||||
isGasTooltipOpen: false,
|
||||
gasPrice: '0x5d21dba00',
|
||||
gasLimit: '0x7b0d',
|
||||
gasPrice: null,
|
||||
gasLimit: null,
|
||||
errors: {},
|
||||
}
|
||||
}
|
||||
@ -83,6 +87,24 @@ SendTokenScreen.prototype.componentWillMount = function () {
|
||||
updateTokenExchangeRate(symbol)
|
||||
}
|
||||
|
||||
SendTokenScreen.prototype.estimateGasAndPrice = function () {
|
||||
const { selectedToken } = this.props
|
||||
const { errors, amount, to } = this.state
|
||||
|
||||
if (!errors.to && !errors.amount && amount > 0) {
|
||||
Promise.all([
|
||||
this.props.getGasPrice(),
|
||||
this.props.estimateGas({ to, amount: this.getAmountToSend(amount, selectedToken) }),
|
||||
])
|
||||
.then(([blockGasPrice, estimatedGas]) => {
|
||||
this.setState({
|
||||
blockGasPrice,
|
||||
estimatedGas,
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
SendTokenScreen.prototype.validate = function () {
|
||||
const {
|
||||
to,
|
||||
@ -113,6 +135,46 @@ SendTokenScreen.prototype.validate = function () {
|
||||
}
|
||||
}
|
||||
|
||||
SendTokenScreen.prototype.setErrorsFor = function (field) {
|
||||
const { balance, selectedToken } = this.props
|
||||
const { errors: previousErrors } = this.state
|
||||
|
||||
const {
|
||||
isValid,
|
||||
errors: newErrors
|
||||
} = this.validate()
|
||||
|
||||
const nextErrors = Object.assign({}, previousErrors, {
|
||||
[field]: newErrors[field] || null
|
||||
})
|
||||
|
||||
if (!isValid) {
|
||||
this.setState({
|
||||
errors: nextErrors,
|
||||
isValid,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
SendTokenScreen.prototype.clearErrorsFor = function (field) {
|
||||
const { errors: previousErrors } = this.state
|
||||
const nextErrors = Object.assign({}, previousErrors, {
|
||||
[field]: null
|
||||
})
|
||||
|
||||
this.setState({
|
||||
errors: nextErrors,
|
||||
isValid: allNull(nextErrors),
|
||||
})
|
||||
}
|
||||
|
||||
SendTokenScreen.prototype.getAmountToSend = function (amount, selectedToken) {
|
||||
const { decimals } = selectedToken || {}
|
||||
const multiplier = Math.pow(10, Number(decimals || 0))
|
||||
const sendAmount = Number(amount * multiplier).toString(16)
|
||||
return sendAmount
|
||||
}
|
||||
|
||||
SendTokenScreen.prototype.submit = function () {
|
||||
const {
|
||||
to,
|
||||
@ -132,11 +194,6 @@ SendTokenScreen.prototype.submit = function () {
|
||||
} = this.props
|
||||
|
||||
const { nickname = ' ' } = identities[to] || {}
|
||||
const { isValid, errors } = this.validate()
|
||||
|
||||
if (!isValid) {
|
||||
return this.setState({ errors })
|
||||
}
|
||||
|
||||
hideWarning()
|
||||
addToAddressBook(to, nickname)
|
||||
@ -148,9 +205,7 @@ SendTokenScreen.prototype.submit = function () {
|
||||
gasPrice: gasPrice,
|
||||
}
|
||||
|
||||
const { decimals } = selectedToken || {}
|
||||
const multiplier = Math.pow(10, Number(decimals || 0))
|
||||
const sendAmount = Number(amount * multiplier).toString(16)
|
||||
const sendAmount = this.getAmountToSend(amount, selectedToken)
|
||||
|
||||
signTokenTx(selectedTokenAddress, to, sendAmount, txParams)
|
||||
}
|
||||
@ -181,7 +236,14 @@ SendTokenScreen.prototype.renderToAddressInput = function () {
|
||||
to: e.target.value,
|
||||
errors: {},
|
||||
}),
|
||||
onFocus: event => to && event.target.select(),
|
||||
onBlur: () => {
|
||||
this.setErrorsFor('to')
|
||||
this.estimateGasAndPrice()
|
||||
},
|
||||
onFocus: event => {
|
||||
if (to) event.target.select()
|
||||
this.clearErrorsFor('to')
|
||||
},
|
||||
}),
|
||||
h('datalist#addresses', [
|
||||
// Corresponds to the addresses owned.
|
||||
@ -235,8 +297,12 @@ SendTokenScreen.prototype.renderAmountInput = function () {
|
||||
value: amount,
|
||||
onChange: e => this.setState({
|
||||
amount: e.target.value,
|
||||
errors: {},
|
||||
}),
|
||||
onBlur: () => {
|
||||
this.setErrorsFor('amount')
|
||||
this.estimateGasAndPrice()
|
||||
},
|
||||
onFocus: () => this.clearErrorsFor('amount'),
|
||||
}),
|
||||
h('div.send-screen-input-wrapper__error-message', [ errorMessage ]),
|
||||
])
|
||||
@ -247,6 +313,8 @@ SendTokenScreen.prototype.renderGasInput = function () {
|
||||
isGasTooltipOpen,
|
||||
gasPrice,
|
||||
gasLimit,
|
||||
blockGasPrice,
|
||||
estimatedGas,
|
||||
selectedCurrency,
|
||||
errors: {
|
||||
gasPrice: gasPriceErrorMessage,
|
||||
@ -267,12 +335,20 @@ SendTokenScreen.prototype.renderGasInput = function () {
|
||||
}, [
|
||||
isGasTooltipOpen && h(GasTooltip, {
|
||||
className: 'send-tooltip',
|
||||
gasPrice,
|
||||
gasLimit,
|
||||
gasPrice: gasPrice || blockGasPrice || '0x0',
|
||||
gasLimit: gasLimit || estimatedGas || '0x0',
|
||||
onClose: () => this.setState({ isGasTooltipOpen: false }),
|
||||
onFeeChange: ({ gasLimit, gasPrice }) => {
|
||||
this.setState({ gasLimit, gasPrice, errors: {} })
|
||||
},
|
||||
onBlur: () => {
|
||||
this.setErrorsFor('gasLimit')
|
||||
this.setErrorsFor('gasPrice')
|
||||
},
|
||||
onFocus: () => {
|
||||
this.clearErrorsFor('gasLimit')
|
||||
this.clearErrorsFor('gasPrice')
|
||||
},
|
||||
}),
|
||||
|
||||
h('div.send-screen-gas-labels', {}, [
|
||||
@ -283,9 +359,9 @@ SendTokenScreen.prototype.renderGasInput = function () {
|
||||
h(GasFeeDisplay, {
|
||||
conversionRate,
|
||||
tokenExchangeRate,
|
||||
gasPrice,
|
||||
gasPrice: gasPrice || blockGasPrice || '0x0',
|
||||
activeCurrency: selectedCurrency,
|
||||
gas: gasLimit,
|
||||
gas: gasLimit || estimatedGas || '0x0',
|
||||
blockGasLimit: currentBlockGasLimit,
|
||||
}),
|
||||
h(
|
||||
@ -312,10 +388,12 @@ SendTokenScreen.prototype.renderMemoInput = function () {
|
||||
|
||||
SendTokenScreen.prototype.renderButtons = function () {
|
||||
const { selectedAddress, backToAccountDetail } = this.props
|
||||
const { isValid } = this.validate()
|
||||
|
||||
return h('div.send-token__button-group', [
|
||||
h('button.send-token__button-next.btn-secondary', {
|
||||
onClick: () => this.submit(),
|
||||
className: !isValid && 'send-screen__send-button__disabled',
|
||||
onClick: () => isValid && this.submit(),
|
||||
}, ['Next']),
|
||||
h('button.send-token__button-cancel.btn-tertiary', {
|
||||
onClick: () => backToAccountDetail(selectedAddress),
|
||||
@ -347,7 +425,7 @@ SendTokenScreen.prototype.render = function () {
|
||||
this.renderAmountInput(),
|
||||
this.renderGasInput(),
|
||||
this.renderMemoInput(),
|
||||
warning && h('div.send-screen-input-wrapper--error',
|
||||
warning && h('div.send-screen-input-wrapper--error', {},
|
||||
h('div.send-screen-input-wrapper__error-message', [
|
||||
warning,
|
||||
])
|
||||
|
@ -16,6 +16,8 @@ const {
|
||||
hideWarning,
|
||||
addToAddressBook,
|
||||
signTx,
|
||||
estimateGas,
|
||||
getGasPrice,
|
||||
} = require('./actions')
|
||||
const { stripHexPrefix, addHexPrefix } = require('ethereumjs-util')
|
||||
const { isHex, numericBalance, isValidAddress, allNull } = require('./util')
|
||||
@ -33,6 +35,8 @@ function mapStateToProps (state) {
|
||||
addressBook,
|
||||
conversionRate,
|
||||
currentBlockGasLimit: blockGasLimit,
|
||||
estimatedGas,
|
||||
blockGasPrice,
|
||||
} = state.metamask
|
||||
const { warning } = state.appState
|
||||
const selectedIdentity = getSelectedIdentity(state)
|
||||
@ -65,13 +69,15 @@ function SendTransactionScreen () {
|
||||
newTx: {
|
||||
from: '',
|
||||
to: '',
|
||||
amount: 0,
|
||||
amountToSend: '0x0',
|
||||
gasPrice: '0x5d21dba00',
|
||||
gas: '0x7b0d',
|
||||
gasPrice: null,
|
||||
gas: null,
|
||||
amount: '0x0',
|
||||
txData: null,
|
||||
memo: '',
|
||||
},
|
||||
blockGasPrice: null,
|
||||
estimatedGas: null,
|
||||
activeCurrency: 'USD',
|
||||
tooltipIsOpen: false,
|
||||
errors: {},
|
||||
@ -87,6 +93,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)
|
||||
@ -162,7 +169,10 @@ SendTransactionScreen.prototype.renderToInput = function (to, identities, addres
|
||||
},
|
||||
})
|
||||
},
|
||||
onBlur: () => this.setErrorsFor('to'),
|
||||
onBlur: () => {
|
||||
this.setErrorsFor('to')
|
||||
this.estimateGasAndPrice()
|
||||
},
|
||||
onFocus: event => {
|
||||
this.clearErrorsFor('to')
|
||||
this.state.newTx.to && event.target.select()
|
||||
@ -218,7 +228,10 @@ SendTransactionScreen.prototype.renderAmountInput = function (activeCurrency) {
|
||||
),
|
||||
})
|
||||
},
|
||||
onBlur: () => this.setErrorsFor('amount'),
|
||||
onBlur: () => {
|
||||
this.setErrorsFor('amount')
|
||||
this.estimateGasAndPrice()
|
||||
},
|
||||
onFocus: () => this.clearErrorsFor('amount'),
|
||||
}),
|
||||
|
||||
@ -301,7 +314,14 @@ SendTransactionScreen.prototype.render = function () {
|
||||
conversionRate,
|
||||
} = props
|
||||
|
||||
const { blockGasLimit, newTx, activeCurrency, isValid } = this.state
|
||||
const {
|
||||
blockGasLimit,
|
||||
newTx,
|
||||
activeCurrency,
|
||||
isValid,
|
||||
blockGasPrice,
|
||||
estimatedGas,
|
||||
} = this.state
|
||||
const { gas, gasPrice } = newTx
|
||||
|
||||
return (
|
||||
@ -322,7 +342,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(),
|
||||
|
||||
@ -357,6 +383,23 @@ 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) {
|
||||
Promise.all([
|
||||
this.props.dispatch(getGasPrice()),
|
||||
this.props.dispatch(estimateGas({ to: newTx.to, amount: sendAmount })),
|
||||
])
|
||||
.then(([blockGasPrice, estimatedGas]) => {
|
||||
this.setState({
|
||||
blockGasPrice,
|
||||
estimatedGas,
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
SendTransactionScreen.prototype.back = function () {
|
||||
var address = this.props.address
|
||||
this.props.dispatch(backToAccountDetail(address))
|
||||
@ -477,7 +520,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
|
||||
@ -495,7 +538,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,
|
||||
|
Loading…
Reference in New Issue
Block a user