1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-12-22 17:33:23 +01:00

Improve customize gas modal error handling

This commit is contained in:
Dan 2017-10-22 17:44:03 -02:30 committed by Chi Kei Chan
parent a7069acf2e
commit e737a9565a
8 changed files with 234 additions and 63 deletions

View File

@ -6,23 +6,46 @@ const actions = require('../../actions')
const GasModalCard = require('./gas-modal-card')
const {
MIN_GAS_PRICE,
MIN_GAS_LIMIT,
MIN_GAS_PRICE_DEC,
MIN_GAS_LIMIT_DEC,
MIN_GAS_PRICE_GWEI,
} = require('../send/send-constants')
const { conversionUtil, multiplyCurrencies } = require('../../conversion-util')
const {
isBalanceSufficient,
} = require('../send/send-utils')
const {
conversionUtil,
multiplyCurrencies,
conversionGreaterThan,
} = require('../../conversion-util')
const {
getGasPrice,
getGasLimit,
conversionRateSelector,
getSendAmount,
getSelectedToken,
getSendFrom,
getCurrentAccountWithSendEtherInfo,
getSelectedTokenToFiatRate,
} = require('../../selectors')
function mapStateToProps (state) {
const selectedToken = getSelectedToken(state)
const currentAccount = getSendFrom(state) || getCurrentAccountWithSendEtherInfo(state)
const conversionRate = conversionRateSelector(state)
return {
gasPrice: getGasPrice(state),
gasLimit: getGasLimit(state),
conversionRate: conversionRateSelector(state),
conversionRate,
amount: getSendAmount(state),
balance: currentAccount.balance,
primaryCurrency: selectedToken && selectedToken.symbol,
selectedToken,
amountConversionRate: selectedToken ? getSelectedTokenToFiatRate(state) : conversionRate,
}
}
@ -39,15 +62,26 @@ inherits(CustomizeGasModal, Component)
function CustomizeGasModal (props) {
Component.call(this)
const gasPrice = props.gasPrice || MIN_GAS_PRICE_DEC
const gasLimit = props.gasLimit || MIN_GAS_LIMIT_DEC
const gasTotal = multiplyCurrencies(gasLimit, gasPrice, {
toNumericBase: 'hex',
multiplicandBase: 16,
multiplierBase: 16,
})
this.state = {
gasPrice: props.gasPrice || MIN_GAS_PRICE,
gasLimit: props.gasLimit || MIN_GAS_LIMIT,
gasPrice,
gasLimit,
gasTotal,
error: null,
}
}
module.exports = connect(mapStateToProps, mapDispatchToProps)(CustomizeGasModal)
CustomizeGasModal.prototype.save = function (gasPrice, gasLimit) {
CustomizeGasModal.prototype.save = function (gasPrice, gasLimit, gasTotal) {
const {
updateGasPrice,
updateGasLimit,
@ -55,41 +89,101 @@ CustomizeGasModal.prototype.save = function (gasPrice, gasLimit) {
updateGasTotal
} = this.props
const newGasTotal = multiplyCurrencies(gasLimit, gasPrice, {
updateGasPrice(gasPrice)
updateGasLimit(gasLimit)
updateGasTotal(gasTotal)
hideModal()
}
CustomizeGasModal.prototype.validate = function ({ gasTotal, gasLimit }) {
const {
amount,
balance,
primaryCurrency,
selectedToken,
amountConversionRate,
conversionRate,
} = this.props
let error = null
const balanceIsSufficient = isBalanceSufficient({
amount,
gasTotal,
balance,
primaryCurrency,
selectedToken,
amountConversionRate,
conversionRate,
})
if (!balanceIsSufficient) {
error = 'Insufficient balance for current gas total'
}
const gasLimitTooLow = gasLimit && conversionGreaterThan(
{
value: MIN_GAS_LIMIT_DEC,
fromNumericBase: 'dec',
conversionRate,
},
{
value: gasLimit,
fromNumericBase: 'hex',
},
)
if (gasLimitTooLow) {
error = 'Gas limit must be at least 21000'
}
this.setState({ error })
return error
}
CustomizeGasModal.prototype.convertAndSetGasLimit = function (newGasLimit) {
const { gasPrice } = this.state
const gasLimit = conversionUtil(newGasLimit, {
fromNumericBase: 'dec',
toNumericBase: 'hex',
})
const gasTotal = multiplyCurrencies(gasLimit, gasPrice, {
toNumericBase: 'hex',
multiplicandBase: 16,
multiplierBase: 16,
})
updateGasPrice(gasPrice)
updateGasLimit(gasLimit)
updateGasTotal(newGasTotal)
hideModal()
}
this.validate({ gasTotal, gasLimit })
CustomizeGasModal.prototype.convertAndSetGasLimit = function (newGasLimit) {
const convertedGasLimit = conversionUtil(newGasLimit, {
fromNumericBase: 'dec',
toNumericBase: 'hex',
})
this.setState({ gasLimit: convertedGasLimit })
this.setState({ gasTotal, gasLimit })
}
CustomizeGasModal.prototype.convertAndSetGasPrice = function (newGasPrice) {
const convertedGasPrice = conversionUtil(newGasPrice, {
const { gasLimit } = this.state
const gasPrice = conversionUtil(newGasPrice, {
fromNumericBase: 'dec',
toNumericBase: 'hex',
fromDenomination: 'GWEI',
toDenomination: 'WEI',
})
this.setState({ gasPrice: convertedGasPrice })
const gasTotal = multiplyCurrencies(gasLimit, gasPrice, {
toNumericBase: 'hex',
multiplicandBase: 16,
multiplierBase: 16,
})
this.validate({ gasTotal })
this.setState({ gasTotal, gasPrice })
}
CustomizeGasModal.prototype.render = function () {
const { hideModal, conversionRate } = this.props
const { gasPrice, gasLimit } = this.state
const { gasPrice, gasLimit, gasTotal, error } = this.state
const convertedGasPrice = conversionUtil(gasPrice, {
fromNumericBase: 'hex',
@ -120,7 +214,7 @@ CustomizeGasModal.prototype.render = function () {
h(GasModalCard, {
value: convertedGasPrice,
min: MIN_GAS_PRICE,
min: MIN_GAS_PRICE_GWEI,
// max: 1000,
step: 1,
onChange: value => this.convertAndSetGasPrice(value),
@ -130,7 +224,7 @@ CustomizeGasModal.prototype.render = function () {
h(GasModalCard, {
value: convertedGasLimit,
min: MIN_GAS_LIMIT,
min: 1,
// max: 100000,
step: 1,
onChange: value => this.convertAndSetGasLimit(value),
@ -141,6 +235,10 @@ CustomizeGasModal.prototype.render = function () {
]),
h('div.send-v2__customize-gas__footer', {}, [
error && h('div.send-v2__customize-gas__error-message', [
error,
]),
h('div.send-v2__customize-gas__revert', {
onClick: () => console.log('Revert'),
@ -151,8 +249,8 @@ CustomizeGasModal.prototype.render = function () {
onClick: this.props.hideModal,
}, ['CANCEL']),
h('div.send-v2__customize-gas__save', {
onClick: () => this.save(gasPrice, gasLimit),
h(`div.send-v2__customize-gas__save${error ? '__error' : ''}`, {
onClick: () => !error && this.save(gasPrice, gasLimit, gasTotal),
}, ['SAVE']),
])

View File

@ -50,7 +50,7 @@ ConfirmSendEther.prototype.getAmount = function () {
const { conversionRate, currentCurrency } = this.props
const txMeta = this.gatherTxMeta()
const txParams = txMeta.txParams || {}
console.log(`conversionRate, currentCurrency`, conversionRate, currentCurrency);
const FIAT = conversionUtil(txParams.value, {
fromNumericBase: 'hex',
toNumericBase: 'dec',

View File

@ -3,12 +3,19 @@ const { multiplyCurrencies } = require('../../conversion-util')
const MIN_GAS_PRICE_GWEI = '1'
const GWEI_FACTOR = '1e9'
const MIN_GAS_PRICE = multiplyCurrencies(GWEI_FACTOR, MIN_GAS_PRICE_GWEI, {
const MIN_GAS_PRICE_HEX = multiplyCurrencies(GWEI_FACTOR, MIN_GAS_PRICE_GWEI, {
multiplicandBase: 16,
multiplierBase: 16,
toNumericBase: 'hex',
})
const MIN_GAS_LIMIT = (21000).toString(16)
const MIN_GAS_TOTAL = multiplyCurrencies(MIN_GAS_LIMIT, MIN_GAS_PRICE, {
const MIN_GAS_PRICE_DEC = multiplyCurrencies(GWEI_FACTOR, MIN_GAS_PRICE_GWEI, {
multiplicandBase: 16,
multiplierBase: 16,
toNumericBase: 'dec',
})
const MIN_GAS_LIMIT_HEX = (21000).toString(16)
const MIN_GAS_LIMIT_DEC = 21000
const MIN_GAS_TOTAL = multiplyCurrencies(MIN_GAS_LIMIT_HEX, MIN_GAS_PRICE_HEX, {
toNumericBase: 'hex',
multiplicandBase: 16,
multiplierBase: 16,
@ -16,8 +23,9 @@ const MIN_GAS_TOTAL = multiplyCurrencies(MIN_GAS_LIMIT, MIN_GAS_PRICE, {
module.exports = {
MIN_GAS_PRICE_GWEI,
GWEI_FACTOR,
MIN_GAS_PRICE,
MIN_GAS_LIMIT,
MIN_GAS_PRICE_HEX,
MIN_GAS_PRICE_DEC,
MIN_GAS_LIMIT_HEX,
MIN_GAS_LIMIT_DEC,
MIN_GAS_TOTAL,
}

View File

@ -0,0 +1,39 @@
const { addCurrencies, conversionGreaterThan } = require('../../conversion-util')
function isBalanceSufficient({
amount,
gasTotal,
balance,
primaryCurrency,
selectedToken,
amountConversionRate,
conversionRate,
}) {
const totalAmount = addCurrencies(amount, gasTotal, {
aBase: 16,
bBase: 16,
toNumericBase: 'hex',
})
const balanceIsSufficient = conversionGreaterThan(
{
value: balance,
fromNumericBase: 'hex',
fromCurrency: primaryCurrency,
conversionRate,
},
{
value: totalAmount,
fromNumericBase: 'hex',
conversionRate: amountConversionRate,
fromCurrency: selectedToken || primaryCurrency,
conversionRate: amountConversionRate,
},
)
return balanceIsSufficient
}
module.exports = {
isBalanceSufficient,
}

View File

@ -17,6 +17,7 @@ const {
getAddressBook,
getSendFrom,
getCurrentCurrency,
getSelectedTokenToFiatRate,
} = require('../../selectors')
module.exports = connect(mapStateToProps, mapDispatchToProps)(SendEther)
@ -26,7 +27,6 @@ function mapStateToProps (state) {
const selectedAddress = getSelectedAddress(state)
const selectedToken = getSelectedToken(state)
const tokenExchangeRates = state.metamask.tokenExchangeRates
const selectedTokenExchangeRate = getSelectedTokenExchangeRate(state)
const conversionRate = conversionRateSelector(state)
let data;
@ -40,11 +40,7 @@ function mapStateToProps (state) {
primaryCurrency = selectedToken.symbol
tokenToFiatRate = multiplyCurrencies(
conversionRate,
selectedTokenExchangeRate,
{ toNumericBase: 'dec' }
)
tokenToFiatRate = getSelectedTokenToFiatRate(state)
}
return {

View File

@ -738,6 +738,7 @@
align-items: center;
justify-content: space-between;
font-size: 22px;
position: relative;
}
&__buttons {
@ -747,7 +748,7 @@
margin-right: 21.25px;
}
&__revert, &__cancel, &__save {
&__revert, &__cancel, &__save, &__save__error {
display: flex;
justify-content: center;
align-items: center;
@ -760,7 +761,7 @@
margin-left: 21.25px;
}
&__cancel, &__save {
&__cancel, &__save, &__save__error {
height: 34.64px;
width: 85.74px;
border: 1px solid $dusty-gray;
@ -769,6 +770,21 @@
font-size: 12px;
color: $dusty-gray;
}
&__save__error {
opacity: 0.5;
cursor: auto;
}
&__error-message {
display: block;
position: absolute;
top: 4px;
right: 4px;
font-size: 12px;
line-height: 12px;
color: $red;
}
}
&__gas-modal-card {

View File

@ -1,5 +1,9 @@
const valuesFor = require('./util').valuesFor
const {
multiplyCurrencies,
} = require('./conversion-util')
const selectors = {
getSelectedAddress,
getSelectedIdentity,
@ -16,6 +20,8 @@ const selectors = {
getAddressBook,
getSendFrom,
getCurrentCurrency,
getSendAmount,
getSelectedTokenToFiatRate,
}
module.exports = selectors
@ -123,6 +129,23 @@ function getSendFrom (state) {
return state.metamask.send.from
}
function getSendAmount (state) {
return state.metamask.send.amount
}
function getCurrentCurrency (state) {
return state.metamask.currentCurrency
}
function getSelectedTokenToFiatRate (state) {
const selectedTokenExchangeRate = getSelectedTokenExchangeRate(state)
const conversionRate = conversionRateSelector(state)
const tokenToFiatRate = multiplyCurrencies(
conversionRate,
selectedTokenExchangeRate,
{ toNumericBase: 'dec' }
)
return tokenToFiatRate
}

View File

@ -19,6 +19,9 @@ const {
conversionGreaterThan,
addCurrencies,
} = require('./conversion-util')
const {
isBalanceSufficient,
} = require('./components/send/send-utils.js')
const { isValidAddress } = require('./util')
module.exports = SendTransactionScreen
@ -237,28 +240,16 @@ SendTransactionScreen.prototype.validateAmount = function (value) {
let amountError = null
const totalAmount = addCurrencies(amount, gasTotal, {
aBase: 16,
bBase: 16,
toNumericBase: 'hex',
const sufficientBalance = isBalanceSufficient({
amount,
gasTotal,
balance,
primaryCurrency,
selectedToken,
amountConversionRate,
conversionRate,
})
const sufficientBalance = conversionGreaterThan(
{
value: balance,
fromNumericBase: 'hex',
fromCurrency: primaryCurrency,
conversionRate,
},
{
value: totalAmount,
fromNumericBase: 'hex',
conversionRate: amountConversionRate,
fromCurrency: selectedToken || primaryCurrency,
conversionRate: amountConversionRate,
},
)
const amountLessThanZero = conversionGreaterThan(
{ value: 0, fromNumericBase: 'dec' },
{ value: amount, fromNumericBase: 'hex' },
@ -387,7 +378,7 @@ SendTransactionScreen.prototype.renderFooter = function () {
clearSend,
errors: { amount: amountError, to: toError }
} = this.props
const noErrors = amountError === null && toError === null
const errorClass = noErrors ? '' : '__disabled'