1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-12-23 09:52:26 +01:00

Simplify gas estimate actions and add local estimateGasPriceFromRecentBlocks method.

This commit is contained in:
Dan 2018-05-22 05:40:06 -02:30
parent 17909465f2
commit 166fda5877
13 changed files with 203 additions and 55 deletions

View File

@ -6,6 +6,8 @@ const {
calcGasTotal, calcGasTotal,
getParamsForGasEstimate, getParamsForGasEstimate,
calcTokenBalance, calcTokenBalance,
estimateGas,
estimateGasPriceFromRecentBlocks,
} = require('./components/send_/send.utils') } = require('./components/send_/send.utils')
const ethUtil = require('ethereumjs-util') const ethUtil = require('ethereumjs-util')
const { fetchLocale } = require('../i18n-helper') const { fetchLocale } = require('../i18n-helper')
@ -160,9 +162,6 @@ var actions = {
updateTransactionParams, updateTransactionParams,
UPDATE_TRANSACTION_PARAMS: 'UPDATE_TRANSACTION_PARAMS', UPDATE_TRANSACTION_PARAMS: 'UPDATE_TRANSACTION_PARAMS',
// send screen // send screen
estimateGas,
getGasEstimate,
getGasPrice,
UPDATE_GAS_LIMIT: 'UPDATE_GAS_LIMIT', UPDATE_GAS_LIMIT: 'UPDATE_GAS_LIMIT',
UPDATE_GAS_PRICE: 'UPDATE_GAS_PRICE', UPDATE_GAS_PRICE: 'UPDATE_GAS_PRICE',
UPDATE_GAS_TOTAL: 'UPDATE_GAS_TOTAL', UPDATE_GAS_TOTAL: 'UPDATE_GAS_TOTAL',
@ -705,22 +704,6 @@ function signTx (txData) {
} }
} }
function estimateGas (params = {}) {
return (dispatch) => {
return new Promise((resolve, reject) => {
global.ethQuery.estimateGas(params, (err, data) => {
if (err) {
dispatch(actions.displayWarning(err.message))
return reject(err)
}
dispatch(actions.hideWarning())
dispatch(actions.setGasLimit(data))
return resolve(data)
})
})
}
}
function setGasLimit (gasLimit) { function setGasLimit (gasLimit) {
return { return {
type: actions.UPDATE_GAS_LIMIT, type: actions.UPDATE_GAS_LIMIT,
@ -728,22 +711,6 @@ function setGasLimit (gasLimit) {
} }
} }
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())
dispatch(actions.setGasPrice(data))
return resolve(data)
})
})
}
}
function setGasPrice (gasPrice) { function setGasPrice (gasPrice) {
return { return {
type: actions.UPDATE_GAS_PRICE, type: actions.UPDATE_GAS_PRICE,
@ -758,22 +725,18 @@ function setGasTotal (gasTotal) {
} }
} }
function getGasEstimate ({ selectedAddress, selectedToken, data }) { function updateGasData ({ recentBlocks, selectedAddress, selectedToken, data }) {
return (dispatch) => { return (dispatch) => {
const estimateGasParams = getParamsForGasEstimate(selectedAddress, selectedToken, data) const estimateGasParams = getParamsForGasEstimate(selectedAddress, selectedToken, data)
return Promise.all([ return Promise.all([
dispatch(actions.getGasPrice()), Promise.resolve(estimateGasPriceFromRecentBlocks(recentBlocks)),
dispatch(actions.estimateGas(estimateGasParams)), estimateGas(estimateGasParams),
]) ])
.then(([gasPrice, gas]) => { .then(([gasPrice, gas]) => {
dispatch(actions.setGasPrice(gasPrice))
dispatch(actions.setGasLimit(gas))
return calcGasTotal(gas, gasPrice) return calcGasTotal(gas, gasPrice)
}) })
}
}
function updateGasData ({ selectedAddress, selectedToken, data }) {
return (dispatch) => {
return dispatch(actions.getGasEstimate({ selectedAddress, selectedToken, data }))
.then((gasEstimate) => { .then((gasEstimate) => {
dispatch(actions.setGasTotal(gasEstimate)) dispatch(actions.setGasTotal(gasEstimate))
dispatch(updateSendErrors({ gasLoadingError: null })) dispatch(updateSendErrors({ gasLoadingError: null }))

View File

@ -67,7 +67,7 @@ function mapDispatchToProps (dispatch) {
hideModal: () => dispatch(actions.hideModal()), hideModal: () => dispatch(actions.hideModal()),
setGasPrice: newGasPrice => dispatch(actions.setGasPrice(newGasPrice)), setGasPrice: newGasPrice => dispatch(actions.setGasPrice(newGasPrice)),
setGasLimit: newGasLimit => dispatch(actions.setGasLimit(newGasLimit)), setGasLimit: newGasLimit => dispatch(actions.setGasLimit(newGasLimit)),
updateGasData: newGasTotal => dispatch(actions.setGasTotal(newGasTotal)), setGasTotal: newGasTotal => dispatch(actions.setGasTotal(newGasTotal)),
updateSendAmount: newAmount => dispatch(actions.updateSendAmount(newAmount)), updateSendAmount: newAmount => dispatch(actions.updateSendAmount(newAmount)),
updateSendErrors: error => dispatch(updateSendErrors(error)), updateSendErrors: error => dispatch(updateSendErrors(error)),
} }
@ -112,7 +112,7 @@ CustomizeGasModal.prototype.save = function (gasPrice, gasLimit, gasTotal) {
setGasPrice, setGasPrice,
setGasLimit, setGasLimit,
hideModal, hideModal,
updateGasData, setGasTotal,
maxModeOn, maxModeOn,
selectedToken, selectedToken,
balance, balance,
@ -131,7 +131,7 @@ CustomizeGasModal.prototype.save = function (gasPrice, gasLimit, gasTotal) {
setGasPrice(ethUtil.addHexPrefix(gasPrice)) setGasPrice(ethUtil.addHexPrefix(gasPrice))
setGasLimit(ethUtil.addHexPrefix(gasLimit)) setGasLimit(ethUtil.addHexPrefix(gasLimit))
updateGasData(ethUtil.addHexPrefix(gasTotal)) setGasTotal(ethUtil.addHexPrefix(gasTotal))
updateSendErrors({ insufficientFunds: false }) updateSendErrors({ insufficientFunds: false })
hideModal() hideModal()
} }

View File

@ -5,6 +5,7 @@ const CurrencyInput = require('../currency-input')
const { conversionUtil, multiplyCurrencies } = require('../../conversion-util') const { conversionUtil, multiplyCurrencies } = require('../../conversion-util')
const currencyFormatter = require('currency-formatter') const currencyFormatter = require('currency-formatter')
const currencies = require('currency-formatter/currencies') const currencies = require('currency-formatter/currencies')
const ethUtil = require('ethereumjs-util')
module.exports = CurrencyDisplay module.exports = CurrencyDisplay
@ -35,18 +36,17 @@ CurrencyDisplay.prototype.getAmount = function (value) {
CurrencyDisplay.prototype.getValueToRender = function () { CurrencyDisplay.prototype.getValueToRender = function () {
const { selectedToken, conversionRate, value } = this.props const { selectedToken, conversionRate, value } = this.props
const { decimals, symbol } = selectedToken || {} const { decimals, symbol } = selectedToken || {}
const multiplier = Math.pow(10, Number(decimals || 0)) const multiplier = Math.pow(10, Number(decimals || 0))
return selectedToken return selectedToken
? conversionUtil(value, { ? conversionUtil(ethUtil.addHexPrefix(value), {
fromNumericBase: 'hex', fromNumericBase: 'hex',
toCurrency: symbol, toCurrency: symbol,
conversionRate: multiplier, conversionRate: multiplier,
invertConversionRate: true, invertConversionRate: true,
}) })
: conversionUtil(value, { : conversionUtil(ethUtil.addHexPrefix(value), {
fromNumericBase: 'hex', fromNumericBase: 'hex',
toNumericBase: 'dec', toNumericBase: 'dec',
fromDenomination: 'WEI', fromDenomination: 'WEI',

View File

@ -28,6 +28,7 @@ export default class SendTransactionScreen extends PersistentForm {
history: PropTypes.object, history: PropTypes.object,
network: PropTypes.string, network: PropTypes.string,
primaryCurrency: PropTypes.string, primaryCurrency: PropTypes.string,
recentBlocks: PropTypes.array,
selectedAddress: PropTypes.string, selectedAddress: PropTypes.string,
selectedToken: PropTypes.object, selectedToken: PropTypes.object,
tokenBalance: PropTypes.string, tokenBalance: PropTypes.string,
@ -43,6 +44,7 @@ export default class SendTransactionScreen extends PersistentForm {
editingTransactionId, editingTransactionId,
gasLimit, gasLimit,
gasPrice, gasPrice,
recentBlocks,
selectedAddress, selectedAddress,
selectedToken = {}, selectedToken = {},
updateAndSetGasTotal, updateAndSetGasTotal,
@ -53,6 +55,7 @@ export default class SendTransactionScreen extends PersistentForm {
editingTransactionId, editingTransactionId,
gasLimit, gasLimit,
gasPrice, gasPrice,
recentBlocks,
selectedAddress, selectedAddress,
selectedToken, selectedToken,
}) })

View File

@ -28,6 +28,13 @@ const NEGATIVE_ETH_ERROR = 'negativeETH'
const INVALID_RECIPIENT_ADDRESS_ERROR = 'invalidAddressRecipient' const INVALID_RECIPIENT_ADDRESS_ERROR = 'invalidAddressRecipient'
const REQUIRED_ERROR = 'required' const REQUIRED_ERROR = 'required'
const ONE_GWEI_IN_WEI_HEX = ethUtil.addHexPrefix(conversionUtil('0x1', {
fromDenomination: 'GWEI',
toDenomination: 'WEI',
fromNumericBase: 'hex',
toNumericBase: 'hex',
}))
module.exports = { module.exports = {
INSUFFICIENT_FUNDS_ERROR, INSUFFICIENT_FUNDS_ERROR,
INSUFFICIENT_TOKENS_ERROR, INSUFFICIENT_TOKENS_ERROR,
@ -39,6 +46,7 @@ module.exports = {
MIN_GAS_PRICE_HEX, MIN_GAS_PRICE_HEX,
MIN_GAS_TOTAL, MIN_GAS_TOTAL,
NEGATIVE_ETH_ERROR, NEGATIVE_ETH_ERROR,
ONE_GWEI_IN_WEI_HEX,
REQUIRED_ERROR, REQUIRED_ERROR,
TOKEN_TRANSFER_FUNCTION_SIGNATURE, TOKEN_TRANSFER_FUNCTION_SIGNATURE,
} }

View File

@ -10,6 +10,7 @@ import {
getGasPrice, getGasPrice,
getGasTotal, getGasTotal,
getPrimaryCurrency, getPrimaryCurrency,
getRecentBlocks,
getSelectedAddress, getSelectedAddress,
getSelectedToken, getSelectedToken,
getSelectedTokenContract, getSelectedTokenContract,
@ -53,6 +54,7 @@ function mapStateToProps (state) {
gasTotal: getGasTotal(state), gasTotal: getGasTotal(state),
network: getCurrentNetwork(state), network: getCurrentNetwork(state),
primaryCurrency: getPrimaryCurrency(state), primaryCurrency: getPrimaryCurrency(state),
recentBlocks: getRecentBlocks(state),
selectedAddress: getSelectedAddress(state), selectedAddress: getSelectedAddress(state),
selectedToken: getSelectedToken(state), selectedToken: getSelectedToken(state),
tokenBalance: getTokenBalance(state), tokenBalance: getTokenBalance(state),
@ -68,12 +70,12 @@ function mapDispatchToProps (dispatch) {
editingTransactionId, editingTransactionId,
gasLimit, gasLimit,
gasPrice, gasPrice,
recentBlocks,
selectedAddress, selectedAddress,
selectedToken, selectedToken,
}) => { }) => {
console.log(`editingTransactionId`, editingTransactionId)
!editingTransactionId !editingTransactionId
? dispatch(updateGasData({ selectedAddress, selectedToken, data })) ? dispatch(updateGasData({ recentBlocks, selectedAddress, selectedToken, data }))
: dispatch(setGasTotal(calcGasTotal(gasLimit, gasPrice))) : dispatch(setGasTotal(calcGasTotal(gasLimit, gasPrice)))
}, },
updateSendTokenBalance: ({ selectedToken, tokenContract, address }) => { updateSendTokenBalance: ({ selectedToken, tokenContract, address }) => {

View File

@ -3,6 +3,9 @@ const abi = require('human-standard-token-abi')
const { const {
multiplyCurrencies, multiplyCurrencies,
} = require('../../conversion-util') } = require('../../conversion-util')
const {
estimateGasPriceFromRecentBlocks,
} = require('./send.utils')
const selectors = { const selectors = {
accountsWithSendEtherInfoSelector, accountsWithSendEtherInfoSelector,
@ -18,8 +21,10 @@ const selectors = {
getForceGasMin, getForceGasMin,
getGasLimit, getGasLimit,
getGasPrice, getGasPrice,
getGasPriceFromRecentBlocks,
getGasTotal, getGasTotal,
getPrimaryCurrency, getPrimaryCurrency,
getRecentBlocks,
getSelectedAccount, getSelectedAccount,
getSelectedAddress, getSelectedAddress,
getSelectedIdentity, getSelectedIdentity,
@ -124,6 +129,10 @@ function getGasPrice (state) {
return state.metamask.send.gasPrice return state.metamask.send.gasPrice
} }
function getGasPriceFromRecentBlocks (state) {
return estimateGasPriceFromRecentBlocks(state.metamask.recentBlocks)
}
function getGasTotal (state) { function getGasTotal (state) {
return state.metamask.send.gasTotal return state.metamask.send.gasTotal
} }
@ -133,6 +142,10 @@ function getPrimaryCurrency (state) {
return selectedToken && selectedToken.symbol return selectedToken && selectedToken.symbol
} }
function getRecentBlocks (state) {
return state.metamask.recentBlocks
}
function getSelectedAccount (state) { function getSelectedAccount (state) {
const accounts = state.metamask.accounts const accounts = state.metamask.accounts
const selectedAddress = getSelectedAddress(state) const selectedAddress = getSelectedAddress(state)

View File

@ -12,12 +12,15 @@ const {
INSUFFICIENT_FUNDS_ERROR, INSUFFICIENT_FUNDS_ERROR,
INSUFFICIENT_TOKENS_ERROR, INSUFFICIENT_TOKENS_ERROR,
NEGATIVE_ETH_ERROR, NEGATIVE_ETH_ERROR,
ONE_GWEI_IN_WEI_HEX,
} = require('./send.constants') } = require('./send.constants')
const abi = require('ethereumjs-abi') const abi = require('ethereumjs-abi')
module.exports = { module.exports = {
calcGasTotal, calcGasTotal,
doesAmountErrorRequireUpdate, doesAmountErrorRequireUpdate,
estimateGas,
estimateGasPriceFromRecentBlocks,
generateTokenTransferData, generateTokenTransferData,
getAmountErrorObject, getAmountErrorObject,
getParamsForGasEstimate, getParamsForGasEstimate,
@ -179,6 +182,17 @@ function doesAmountErrorRequireUpdate ({
return amountErrorRequiresUpdate return amountErrorRequiresUpdate
} }
function estimateGas (params = {}) {
return new Promise((resolve, reject) => {
global.ethQuery.estimateGas(params, (err, data) => {
if (err) {
return reject(err)
}
return resolve(data)
})
})
}
function generateTokenTransferData (selectedAddress, selectedToken) { function generateTokenTransferData (selectedAddress, selectedToken) {
if (!selectedToken) return if (!selectedToken) return
console.log(`abi.rawEncode`, abi.rawEncode) console.log(`abi.rawEncode`, abi.rawEncode)
@ -187,3 +201,26 @@ function generateTokenTransferData (selectedAddress, selectedToken) {
x => ('00' + x.toString(16)).slice(-2) x => ('00' + x.toString(16)).slice(-2)
).join('') ).join('')
} }
function hexComparator (a, b) {
return conversionGreaterThan(
{ value: a, fromNumericBase: 'hex' },
{ value: b, fromNumericBase: 'hex' },
) ? 1 : -1
}
function estimateGasPriceFromRecentBlocks (recentBlocks) {
// Return 1 gwei if no blocks have been observed:
if (!recentBlocks || recentBlocks.length === 0) {
return ONE_GWEI_IN_WEI_HEX
}
const lowestPrices = recentBlocks.map((block) => {
if (!block.gasPrices || block.gasPrices.length < 1) {
return ONE_GWEI_IN_WEI_HEX
}
return block.gasPrices
.sort(hexComparator)[0]
})
.sort(hexComparator)
return lowestPrices[Math.floor(lowestPrices.length / 2)]
}

View File

@ -42,6 +42,7 @@ describe.only('Send Component', function () {
history={{ mockProp: 'history-abc'}} history={{ mockProp: 'history-abc'}}
network={'3'} network={'3'}
primaryCurrency={'mockPrimaryCurrency'} primaryCurrency={'mockPrimaryCurrency'}
recentBlocks={['mockBlock']}
selectedAddress={'mockSelectedAddress'} selectedAddress={'mockSelectedAddress'}
selectedToken={'mockSelectedToken'} selectedToken={'mockSelectedToken'}
tokenBalance={'mockTokenBalance'} tokenBalance={'mockTokenBalance'}
@ -211,6 +212,7 @@ describe.only('Send Component', function () {
editingTransactionId: 'mockEditingTransactionId', editingTransactionId: 'mockEditingTransactionId',
gasLimit: 'mockGasLimit', gasLimit: 'mockGasLimit',
gasPrice: 'mockGasPrice', gasPrice: 'mockGasPrice',
recentBlocks: ['mockBlock'],
selectedAddress: 'mockSelectedAddress', selectedAddress: 'mockSelectedAddress',
selectedToken: 'mockSelectedToken', selectedToken: 'mockSelectedToken',
} }

View File

@ -32,6 +32,7 @@ proxyquire('../send.container.js', {
getGasPrice: (s) => `mockGasPrice:${s}`, getGasPrice: (s) => `mockGasPrice:${s}`,
getGasTotal: (s) => `mockGasTotal:${s}`, getGasTotal: (s) => `mockGasTotal:${s}`,
getPrimaryCurrency: (s) => `mockPrimaryCurrency:${s}`, getPrimaryCurrency: (s) => `mockPrimaryCurrency:${s}`,
getRecentBlocks: (s) => `mockRecentBlocks:${s}`,
getSelectedAddress: (s) => `mockSelectedAddress:${s}`, getSelectedAddress: (s) => `mockSelectedAddress:${s}`,
getSelectedToken: (s) => `mockSelectedToken:${s}`, getSelectedToken: (s) => `mockSelectedToken:${s}`,
getSelectedTokenContract: (s) => `mockTokenContract:${s}`, getSelectedTokenContract: (s) => `mockTokenContract:${s}`,
@ -66,6 +67,7 @@ describe('send container', () => {
gasTotal: 'mockGasTotal:mockState', gasTotal: 'mockGasTotal:mockState',
network: 'mockNetwork:mockState', network: 'mockNetwork:mockState',
primaryCurrency: 'mockPrimaryCurrency:mockState', primaryCurrency: 'mockPrimaryCurrency:mockState',
recentBlocks: 'mockRecentBlocks:mockState',
selectedAddress: 'mockSelectedAddress:mockState', selectedAddress: 'mockSelectedAddress:mockState',
selectedToken: 'mockSelectedToken:mockState', selectedToken: 'mockSelectedToken:mockState',
tokenBalance: 'mockTokenBalance:mockState', tokenBalance: 'mockTokenBalance:mockState',
@ -91,6 +93,7 @@ describe('send container', () => {
editingTransactionId: '0x2', editingTransactionId: '0x2',
gasLimit: '0x3', gasLimit: '0x3',
gasPrice: '0x4', gasPrice: '0x4',
recentBlocks: ['mockBlock'],
selectedAddress: '0x4', selectedAddress: '0x4',
selectedToken: { address: '0x1' }, selectedToken: { address: '0x1' },
} }
@ -105,14 +108,14 @@ describe('send container', () => {
}) })
it('should dispatch an updateGasData action when editingTransactionId is falsy', () => { it('should dispatch an updateGasData action when editingTransactionId is falsy', () => {
const { selectedAddress, selectedToken, data } = mockProps const { selectedAddress, selectedToken, data, recentBlocks } = mockProps
mapDispatchToPropsObject.updateAndSetGasTotal( mapDispatchToPropsObject.updateAndSetGasTotal(
Object.assign(mockProps, {editingTransactionId: false}) Object.assign({}, mockProps, {editingTransactionId: false})
) )
assert(dispatchSpy.calledOnce) assert(dispatchSpy.calledOnce)
assert.deepEqual( assert.deepEqual(
actionSpies.updateGasData.getCall(0).args[0], actionSpies.updateGasData.getCall(0).args[0],
{ selectedAddress, selectedToken, data } { selectedAddress, selectedToken, data, recentBlocks }
) )
}) })
}) })

View File

@ -198,6 +198,7 @@ module.exports = {
}, },
}, },
'currentLocale': 'en', 'currentLocale': 'en',
recentBlocks: ['mockBlock1', 'mockBlock2', 'mockBlock3'],
}, },
'appState': { 'appState': {
'menuOpen': false, 'menuOpen': false,

View File

@ -17,6 +17,7 @@ const {
getGasPrice, getGasPrice,
getGasTotal, getGasTotal,
getPrimaryCurrency, getPrimaryCurrency,
getRecentBlocks,
getSelectedAccount, getSelectedAccount,
getSelectedAddress, getSelectedAddress,
getSelectedIdentity, getSelectedIdentity,
@ -239,6 +240,15 @@ describe('send selectors', () => {
}) })
}) })
describe('getRecentBlocks()', () => {
it('should return the recent blocks', () => {
assert.deepEqual(
getRecentBlocks(mockState),
['mockBlock1', 'mockBlock2', 'mockBlock3']
)
})
})
describe('getSelectedAccount()', () => { describe('getSelectedAccount()', () => {
it('should return the currently selected account', () => { it('should return the currently selected account', () => {
assert.deepEqual( assert.deepEqual(

View File

@ -1,6 +1,13 @@
import assert from 'assert' import assert from 'assert'
import sinon from 'sinon' import sinon from 'sinon'
import proxyquire from 'proxyquire' import proxyquire from 'proxyquire'
import {
ONE_GWEI_IN_WEI_HEX,
} from '../send.constants'
const {
addCurrencies,
subtractCurrencies,
} = require('../../../conversion-util')
const { const {
INSUFFICIENT_FUNDS_ERROR, INSUFFICIENT_FUNDS_ERROR,
@ -31,7 +38,9 @@ const sendUtils = proxyquire('../send.utils.js', {
const { const {
calcGasTotal, calcGasTotal,
estimateGas,
doesAmountErrorRequireUpdate, doesAmountErrorRequireUpdate,
estimateGasPriceFromRecentBlocks,
generateTokenTransferData, generateTokenTransferData,
getAmountErrorObject, getAmountErrorObject,
getParamsForGasEstimate, getParamsForGasEstimate,
@ -261,4 +270,101 @@ describe('send utils', () => {
}) })
}) })
describe('estimateGas', () => {
let tempEthQuery
beforeEach(() => {
tempEthQuery = global.ethQuery
global.ethQuery = {
estimateGas: sinon.stub().callsFake((data, cb) => {
return cb(
data.isMockErr ? 'mockErr' : null,
Object.assign(data, { estimateGasCalled: true })
)
})
}
})
afterEach(() => {
global.ethQuery = tempEthQuery
})
it('should call ethQuery.estimateGas and resolve that call\'s data', async () => {
const result = await estimateGas({ mockParam: 'someData' })
assert.equal(global.ethQuery.estimateGas.callCount, 1)
assert.deepEqual(
result,
{ mockParam: 'someData', estimateGasCalled: true }
)
})
it('should reject with ethQuery.estimateGas error', async () => {
try {
await estimateGas({ mockParam: 'someData', isMockErr: true })
} catch (err) {
assert.equal(err, 'mockErr')
}
})
})
describe('estimateGasPriceFromRecentBlocks', () => {
const ONE_GWEI_IN_WEI_HEX_PLUS_ONE = addCurrencies(ONE_GWEI_IN_WEI_HEX, '0x1', {
aBase: 16,
bBase: 16,
toNumericBase: 'hex',
})
const ONE_GWEI_IN_WEI_HEX_PLUS_TWO = addCurrencies(ONE_GWEI_IN_WEI_HEX, '0x2', {
aBase: 16,
bBase: 16,
toNumericBase: 'hex',
})
const ONE_GWEI_IN_WEI_HEX_MINUS_ONE = subtractCurrencies(ONE_GWEI_IN_WEI_HEX, '0x1', {
aBase: 16,
bBase: 16,
toNumericBase: 'hex',
})
it(`should return ${ONE_GWEI_IN_WEI_HEX} if recentBlocks is falsy`, () => {
assert.equal(estimateGasPriceFromRecentBlocks(), ONE_GWEI_IN_WEI_HEX)
})
it(`should return ${ONE_GWEI_IN_WEI_HEX} if recentBlocks is empty`, () => {
assert.equal(estimateGasPriceFromRecentBlocks([]), ONE_GWEI_IN_WEI_HEX)
})
it(`should estimate a block's gasPrice as ${ONE_GWEI_IN_WEI_HEX} if it has no gas prices`, () => {
const mockRecentBlocks = [
{ gasPrices: null },
{ gasPrices: [ ONE_GWEI_IN_WEI_HEX_PLUS_ONE ] },
{ gasPrices: [ ONE_GWEI_IN_WEI_HEX_MINUS_ONE ] },
]
assert.equal(estimateGasPriceFromRecentBlocks(mockRecentBlocks), ONE_GWEI_IN_WEI_HEX)
})
it(`should estimate a block's gasPrice as ${ONE_GWEI_IN_WEI_HEX} if it has empty gas prices`, () => {
const mockRecentBlocks = [
{ gasPrices: [] },
{ gasPrices: [ ONE_GWEI_IN_WEI_HEX_PLUS_ONE ] },
{ gasPrices: [ ONE_GWEI_IN_WEI_HEX_MINUS_ONE ] },
]
assert.equal(estimateGasPriceFromRecentBlocks(mockRecentBlocks), ONE_GWEI_IN_WEI_HEX)
})
it(`should return the middle value of all blocks lowest prices`, () => {
const mockRecentBlocks = [
{ gasPrices: [ ONE_GWEI_IN_WEI_HEX_PLUS_TWO ] },
{ gasPrices: [ ONE_GWEI_IN_WEI_HEX_MINUS_ONE ] },
{ gasPrices: [ ONE_GWEI_IN_WEI_HEX_PLUS_ONE ] },
]
assert.equal(estimateGasPriceFromRecentBlocks(mockRecentBlocks), ONE_GWEI_IN_WEI_HEX_PLUS_ONE)
})
it(`should work if a block has multiple gas prices`, () => {
const mockRecentBlocks = [
{ gasPrices: [ '0x1', '0x2', '0x3', '0x4', '0x5' ] },
{ gasPrices: [ '0x101', '0x100', '0x103', '0x104', '0x102' ] },
{ gasPrices: [ '0x150', '0x50', '0x100', '0x200', '0x5' ] },
]
assert.equal(estimateGasPriceFromRecentBlocks(mockRecentBlocks), '0x5')
})
})
}) })