1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-12-23 09:52:26 +01:00
metamask-extension/ui/app/selectors/custom-gas.js
Dan J Miller 3191d9e014
Help users avoid insufficient gas prices in swaps (#9624)
* Don't show average (slowest) button in custom gas modal while in swaps

* In swaps, show warning in custom gas modal if price set below average price

* Update ui/app/selectors/custom-gas.js

Co-authored-by: Erik Marks <25517051+rekmarks@users.noreply.github.com>

* Fix typo

Co-authored-by: Erik Marks <25517051+rekmarks@users.noreply.github.com>
2020-10-17 06:43:51 -02:30

324 lines
9.4 KiB
JavaScript

import { addHexPrefix } from 'ethereumjs-util'
import {
conversionUtil,
multiplyCurrencies,
conversionGreaterThan,
} from '../helpers/utils/conversion-util'
import {
formatCurrency,
} from '../helpers/utils/confirm-tx.util'
import {
decEthToConvertedCurrency as ethTotalToConvertedCurrency,
} from '../helpers/utils/conversions.util'
import {
formatETHFee,
} from '../helpers/utils/formatters'
import {
calcGasTotal,
} from '../pages/send/send.utils'
import { GAS_ESTIMATE_TYPES } from '../helpers/constants/common'
import {
getCurrentCurrency, getIsMainnet, getPreferences,
} from '.'
const NUMBER_OF_DECIMALS_SM_BTNS = 5
export function getCustomGasErrors (state) {
return state.gas.errors
}
export function getCustomGasLimit (state) {
return state.gas.customData.limit
}
export function getCustomGasPrice (state) {
return state.gas.customData.price
}
export function getCustomGasTotal (state) {
return state.gas.customData.total
}
export function getBasicGasEstimateLoadingStatus (state) {
return state.gas.basicEstimateIsLoading
}
export function getGasEstimatesLoadingStatus (state) {
return state.gas.gasEstimatesLoading
}
export function getPriceAndTimeEstimates (state) {
return state.gas.priceAndTimeEstimates
}
export function getEstimatedGasPrices (state) {
return getPriceAndTimeEstimates(state).map(({ gasprice }) => gasprice)
}
export function getEstimatedGasTimes (state) {
return getPriceAndTimeEstimates(state).map(({ expectedTime }) => expectedTime)
}
export function getAveragePriceEstimateInHexWEI (state) {
const averagePriceEstimate = state.gas.basicEstimates.average
return getGasPriceInHexWei(averagePriceEstimate || '0x0')
}
export function getFastPriceEstimateInHexWEI (state) {
const fastPriceEstimate = state.gas.basicEstimates.fast
return getGasPriceInHexWei(fastPriceEstimate || '0x0')
}
export function getDefaultActiveButtonIndex (gasButtonInfo, customGasPriceInHex, gasPrice) {
return gasButtonInfo
.map(({ priceInHexWei }) => priceInHexWei)
.lastIndexOf(addHexPrefix(customGasPriceInHex || gasPrice))
}
export function getSafeLowEstimate (state) {
const {
gas: {
basicEstimates: {
safeLow,
},
},
} = state
return safeLow
}
export function getAverageEstimate (state) {
const {
gas: {
basicEstimates: {
average,
},
},
} = state
return average
}
export function isCustomPriceSafe (state, averageIsSafe) {
const safeLow = getSafeLowEstimate(state)
const average = getAverageEstimate(state)
const safeMinimumPrice = averageIsSafe ? average : safeLow
const customGasPrice = getCustomGasPrice(state)
if (!customGasPrice) {
return true
}
if (safeMinimumPrice === null) {
return false
}
const customPriceSafe = conversionGreaterThan(
{
value: customGasPrice,
fromNumericBase: 'hex',
fromDenomination: 'WEI',
toDenomination: 'GWEI',
},
{ value: safeMinimumPrice, fromNumericBase: 'dec' },
)
return customPriceSafe
}
export function getBasicGasEstimateBlockTime (state) {
return state.gas.basicEstimates.blockTime
}
export function basicPriceEstimateToETHTotal (estimate, gasLimit, numberOfDecimals = 9) {
return conversionUtil(calcGasTotal(gasLimit, estimate), {
fromNumericBase: 'hex',
toNumericBase: 'dec',
fromDenomination: 'GWEI',
numberOfDecimals,
})
}
export function getRenderableEthFee (estimate, gasLimit, numberOfDecimals = 9) {
const value = conversionUtil(estimate, { fromNumericBase: 'dec', toNumericBase: 'hex' })
const fee = basicPriceEstimateToETHTotal(value, gasLimit, numberOfDecimals)
return formatETHFee(fee)
}
export function getRenderableConvertedCurrencyFee (estimate, gasLimit, convertedCurrency, conversionRate) {
const value = conversionUtil(estimate, { fromNumericBase: 'dec', toNumericBase: 'hex' })
const fee = basicPriceEstimateToETHTotal(value, gasLimit)
const feeInCurrency = ethTotalToConvertedCurrency(fee, convertedCurrency, conversionRate)
return formatCurrency(feeInCurrency, convertedCurrency)
}
export function getTimeEstimateInSeconds (blockWaitEstimate) {
return multiplyCurrencies(blockWaitEstimate, 60, {
toNumericBase: 'dec',
multiplicandBase: 10,
multiplierBase: 10,
numberOfDecimals: 1,
})
}
export function formatTimeEstimate (totalSeconds, greaterThanMax, lessThanMin) {
const minutes = Math.floor(totalSeconds / 60)
const seconds = Math.floor(totalSeconds % 60)
if (!minutes && !seconds) {
return '...'
}
let symbol = '~'
if (greaterThanMax) {
symbol = '< '
} else if (lessThanMin) {
symbol = '> '
}
const formattedMin = `${minutes ? `${minutes} min` : ''}`
const formattedSec = `${seconds ? `${seconds} sec` : ''}`
const formattedCombined = formattedMin && formattedSec
? `${symbol}${formattedMin} ${formattedSec}`
: symbol + [formattedMin, formattedSec].find((t) => t)
return formattedCombined
}
export function getRenderableTimeEstimate (blockWaitEstimate) {
return formatTimeEstimate(getTimeEstimateInSeconds(blockWaitEstimate))
}
export function priceEstimateToWei (priceEstimate) {
return conversionUtil(priceEstimate, {
fromNumericBase: 'hex',
toNumericBase: 'hex',
fromDenomination: 'GWEI',
toDenomination: 'WEI',
numberOfDecimals: 9,
})
}
export function getGasPriceInHexWei (price) {
const value = conversionUtil(price, { fromNumericBase: 'dec', toNumericBase: 'hex' })
return addHexPrefix(priceEstimateToWei(value))
}
export function getRenderableBasicEstimateData (state, gasLimit, useFastestButtons) {
if (getBasicGasEstimateLoadingStatus(state)) {
return []
}
const { showFiatInTestnets } = getPreferences(state)
const isMainnet = getIsMainnet(state)
const showFiat = (isMainnet || Boolean(showFiatInTestnets))
const { conversionRate } = state.metamask
const currentCurrency = getCurrentCurrency(state)
const {
gas: {
basicEstimates: {
safeLow,
average,
fast,
safeLowWait,
avgWait,
fastWait,
fastest,
fastestWait,
},
},
} = state
const slowEstimateData = {
gasEstimateType: GAS_ESTIMATE_TYPES.SLOW,
feeInPrimaryCurrency: getRenderableEthFee(safeLow, gasLimit),
feeInSecondaryCurrency: showFiat
? getRenderableConvertedCurrencyFee(safeLow, gasLimit, currentCurrency, conversionRate)
: '',
timeEstimate: safeLowWait && getRenderableTimeEstimate(safeLowWait),
priceInHexWei: getGasPriceInHexWei(safeLow),
}
const averageEstimateData = {
gasEstimateType: GAS_ESTIMATE_TYPES.AVERAGE,
feeInPrimaryCurrency: getRenderableEthFee(average, gasLimit),
feeInSecondaryCurrency: showFiat
? getRenderableConvertedCurrencyFee(average, gasLimit, currentCurrency, conversionRate)
: '',
timeEstimate: avgWait && getRenderableTimeEstimate(avgWait),
priceInHexWei: getGasPriceInHexWei(average),
}
const fastEstimateData = {
gasEstimateType: GAS_ESTIMATE_TYPES.FAST,
feeInPrimaryCurrency: getRenderableEthFee(fast, gasLimit),
feeInSecondaryCurrency: showFiat
? getRenderableConvertedCurrencyFee(fast, gasLimit, currentCurrency, conversionRate)
: '',
timeEstimate: fastWait && getRenderableTimeEstimate(fastWait),
priceInHexWei: getGasPriceInHexWei(fast),
}
const fastestEstimateData = {
gasEstimateType: GAS_ESTIMATE_TYPES.FASTEST,
feeInPrimaryCurrency: getRenderableEthFee(fastest, gasLimit),
feeInSecondaryCurrency: showFiat
? getRenderableConvertedCurrencyFee(fastest, gasLimit, currentCurrency, conversionRate)
: '',
timeEstimate: fastestWait && getRenderableTimeEstimate(fastestWait),
priceInHexWei: getGasPriceInHexWei(fastest),
}
return useFastestButtons
? [fastEstimateData, fastestEstimateData]
: [slowEstimateData, averageEstimateData, fastEstimateData]
}
export function getRenderableEstimateDataForSmallButtonsFromGWEI (state) {
if (getBasicGasEstimateLoadingStatus(state)) {
return []
}
const { showFiatInTestnets } = getPreferences(state)
const isMainnet = getIsMainnet(state)
const showFiat = (isMainnet || Boolean(showFiatInTestnets))
const gasLimit = state.metamask.send.gasLimit || getCustomGasLimit(state) || '0x5208'
const { conversionRate } = state.metamask
const currentCurrency = getCurrentCurrency(state)
const {
gas: {
basicEstimates: {
safeLow,
average,
fast,
},
},
} = state
return [
{
gasEstimateType: GAS_ESTIMATE_TYPES.SLOW,
feeInSecondaryCurrency: showFiat
? getRenderableConvertedCurrencyFee(safeLow, gasLimit, currentCurrency, conversionRate)
: '',
feeInPrimaryCurrency: getRenderableEthFee(safeLow, gasLimit, NUMBER_OF_DECIMALS_SM_BTNS, true),
priceInHexWei: getGasPriceInHexWei(safeLow, true),
},
{
gasEstimateType: GAS_ESTIMATE_TYPES.AVERAGE,
feeInSecondaryCurrency: showFiat
? getRenderableConvertedCurrencyFee(average, gasLimit, currentCurrency, conversionRate)
: '',
feeInPrimaryCurrency: getRenderableEthFee(average, gasLimit, NUMBER_OF_DECIMALS_SM_BTNS, true),
priceInHexWei: getGasPriceInHexWei(average, true),
},
{
gasEstimateType: GAS_ESTIMATE_TYPES.FAST,
feeInSecondaryCurrency: showFiat
? getRenderableConvertedCurrencyFee(fast, gasLimit, currentCurrency, conversionRate)
: '',
feeInPrimaryCurrency: getRenderableEthFee(fast, gasLimit, NUMBER_OF_DECIMALS_SM_BTNS, true),
priceInHexWei: getGasPriceInHexWei(fast, true),
},
]
}