Delete recent blocks controller (#8575)

* delete recent blocks controller

* delete percentile from direct dependencies
feature/default_network_editable
Erik Marks 5 years ago committed by GitHub
parent 0aa41e397e
commit 0470386326
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      app/scripts/background.js
  2. 175
      app/scripts/controllers/recent-blocks.js
  3. 17
      app/scripts/controllers/transactions/index.js
  4. 48
      app/scripts/metamask-controller.js
  5. 1
      app/scripts/ui.js
  6. 1
      package.json
  7. 26
      test/unit/app/controllers/metamask-controller-test.js
  8. 3
      ui/app/pages/send/send.component.js
  9. 8
      ui/app/pages/send/send.constants.js
  10. 5
      ui/app/pages/send/send.container.js
  11. 21
      ui/app/pages/send/send.utils.js
  12. 2
      ui/app/pages/send/tests/send-component.test.js
  13. 5
      ui/app/pages/send/tests/send-container.test.js
  14. 65
      ui/app/pages/send/tests/send-utils.test.js
  15. 10
      ui/app/selectors/send.js
  16. 1
      ui/app/selectors/tests/send-selectors-test-data.js
  17. 10
      ui/app/selectors/tests/send.test.js
  18. 5
      yarn.lock

@ -136,7 +136,6 @@ initialize().catch(log.error)
* @property {number} conversionRate - A number representing the current exchange rate from the user's preferred currency to Ether. * @property {number} conversionRate - A number representing the current exchange rate from the user's preferred currency to Ether.
* @property {number} conversionDate - A unix epoch date (ms) for the time the current conversion rate was last retrieved. * @property {number} conversionDate - A unix epoch date (ms) for the time the current conversion rate was last retrieved.
* @property {Object} infuraNetworkStatus - An object of infura network status checks. * @property {Object} infuraNetworkStatus - An object of infura network status checks.
* @property {Block[]} recentBlocks - An array of recent blocks, used to calculate an effective but cheap gas price.
* @property {boolean} forgottenPassword - Returns true if the user has initiated the password recovery screen, is recovering from seed phrase. * @property {boolean} forgottenPassword - Returns true if the user has initiated the password recovery screen, is recovering from seed phrase.
*/ */

@ -1,175 +0,0 @@
import ObservableStore from 'obs-store'
import EthQuery from 'eth-query'
import log from 'loglevel'
import pify from 'pify'
import { ROPSTEN, RINKEBY, KOVAN, MAINNET, GOERLI } from './network/enums'
const INFURA_PROVIDER_TYPES = [ROPSTEN, RINKEBY, KOVAN, MAINNET, GOERLI]
export default class RecentBlocksController {
/**
* Controller responsible for storing, updating and managing the recent history of blocks. Blocks are back filled
* upon the controller's construction and then the list is updated when the given block tracker gets a 'latest' event
* (indicating that there is a new block to process).
*
* @typedef {Object} RecentBlocksController
* @param {Object} opts - Contains objects necessary for tracking blocks and querying the blockchain
* @param {BlockTracker} opts.blockTracker Contains objects necessary for tracking blocks and querying the blockchain
* @param {BlockTracker} opts.provider The provider used to create a new EthQuery instance.
* @property {BlockTracker} blockTracker Points to the passed BlockTracker. On RecentBlocksController construction,
* listens for 'latest' events so that new blocks can be processed and added to storage.
* @property {EthQuery} ethQuery Points to the EthQuery instance created with the passed provider
* @property {number} historyLength The maximum length of blocks to track
* @property {object} store Stores the recentBlocks
* @property {array} store.recentBlocks Contains all recent blocks, up to a total that is equal to this.historyLength
*
*/
constructor (opts = {}) {
const { blockTracker, provider, networkController } = opts
this.blockTracker = blockTracker
this.ethQuery = new EthQuery(provider)
this.historyLength = opts.historyLength || 40
const initState = Object.assign({
recentBlocks: [],
}, opts.initState)
this.store = new ObservableStore(initState)
const blockListner = async (newBlockNumberHex) => {
try {
await this.processBlock(newBlockNumberHex)
} catch (err) {
log.error(err)
}
}
let isListening = false
const { type } = networkController.getProviderConfig()
if (!INFURA_PROVIDER_TYPES.includes(type) && type !== 'loading') {
this.blockTracker.on('latest', blockListner)
isListening = true
}
networkController.on('networkDidChange', (newType) => {
if (INFURA_PROVIDER_TYPES.includes(newType) && isListening) {
this.blockTracker.removeListener('latest', blockListner)
} else if (
!INFURA_PROVIDER_TYPES.includes(type) &&
type !== 'loading' &&
!isListening
) {
this.blockTracker.on('latest', blockListner)
}
})
this.backfill()
}
/**
* Receives a new block and modifies it with this.mapTransactionsToPrices. Then adds that block to the recentBlocks
* array in storage. If the recentBlocks array contains the maximum number of blocks, the oldest block is removed.
*
* @param {Object} newBlock - The new block to modify and add to the recentBlocks array
*
*/
async processBlock (newBlockNumberHex) {
const newBlockNumber = Number.parseInt(newBlockNumberHex, 16)
const newBlock = await this.getBlockByNumber(newBlockNumber)
if (!newBlock) {
return
}
const block = this.mapTransactionsToPrices(newBlock)
const state = this.store.getState()
state.recentBlocks.push(block)
while (state.recentBlocks.length > this.historyLength) {
state.recentBlocks.shift()
}
this.store.updateState(state)
}
/**
* Receives a new block and modifies it with this.mapTransactionsToPrices. Adds that block to the recentBlocks
* array in storage, but only if the recentBlocks array contains fewer than the maximum permitted.
*
* Unlike this.processBlock, backfillBlock adds the modified new block to the beginning of the recent block array.
*
* @param {Object} newBlock - The new block to modify and add to the beginning of the recentBlocks array
*
*/
backfillBlock (newBlock) {
const block = this.mapTransactionsToPrices(newBlock)
const state = this.store.getState()
if (state.recentBlocks.length < this.historyLength) {
state.recentBlocks.unshift(block)
}
this.store.updateState(state)
}
/**
* Receives a block and gets the gasPrice of each of its transactions. These gas prices are added to the block at a
* new property, and the block's transactions are removed.
*
* @param {Object} newBlock - The block to modify. It's transaction array will be replaced by a gasPrices array.
* @returns {Object} - The modified block.
*
*/
mapTransactionsToPrices (newBlock) {
const block = {
...newBlock,
gasPrices: newBlock.transactions.map((tx) => {
return tx.gasPrice
}),
}
delete block.transactions
return block
}
/**
* On this.blockTracker's first 'latest' event after this RecentBlocksController's instantiation, the store.recentBlocks
* array is populated with this.historyLength number of blocks. The block number of the this.blockTracker's first
* 'latest' event is used to iteratively generate all the numbers of the previous blocks, which are obtained by querying
* the blockchain. These blocks are backfilled so that the recentBlocks array is ordered from oldest to newest.
*
* Each iteration over the block numbers is delayed by 100 milliseconds.
*
* @returns {Promise<void>} - Promises undefined
*/
async backfill () {
this.blockTracker.once('latest', async (blockNumberHex) => {
const currentBlockNumber = Number.parseInt(blockNumberHex, 16)
const blocksToFetch = Math.min(currentBlockNumber, this.historyLength)
const prevBlockNumber = currentBlockNumber - 1
const targetBlockNumbers = Array(blocksToFetch).fill().map((_, index) => prevBlockNumber - index)
await Promise.all(targetBlockNumbers.map(async (targetBlockNumber) => {
try {
const newBlock = await this.getBlockByNumber(targetBlockNumber)
if (!newBlock) {
return
}
this.backfillBlock(newBlock)
} catch (e) {
log.error(e)
}
}))
})
}
/**
* Uses EthQuery to get a block that has a given block number.
*
* @param {number} number - The number of the block to get
* @returns {Promise<object>} - Promises A block with the passed number
*
*/
async getBlockByNumber (number) {
const blockNumberHex = '0x' + number.toString(16)
return await pify(this.ethQuery.getBlockByNumber).call(this.ethQuery, blockNumberHex, true)
}
}

@ -62,7 +62,6 @@ const SIMPLE_GAS_COST = '0x5208' // Hex for 21000, cost of a simple send.
@param {Object} opts.provider - A network provider. @param {Object} opts.provider - A network provider.
@param {Function} opts.signTransaction - function the signs an ethereumjs-tx @param {Function} opts.signTransaction - function the signs an ethereumjs-tx
@param {Object} opts.getPermittedAccounts - get accounts that an origin has permissions for @param {Object} opts.getPermittedAccounts - get accounts that an origin has permissions for
@param {Function} [opts.getGasPrice] - optional gas price calculator
@param {Function} opts.signTransaction - ethTx signer that returns a rawTx @param {Function} opts.signTransaction - ethTx signer that returns a rawTx
@param {number} [opts.txHistoryLimit] - number *optional* for limiting how many transactions are in state @param {number} [opts.txHistoryLimit] - number *optional* for limiting how many transactions are in state
@param {Object} opts.preferencesStore @param {Object} opts.preferencesStore
@ -77,7 +76,6 @@ export default class TransactionController extends EventEmitter {
this.getPermittedAccounts = opts.getPermittedAccounts this.getPermittedAccounts = opts.getPermittedAccounts
this.blockTracker = opts.blockTracker this.blockTracker = opts.blockTracker
this.signEthTx = opts.signTransaction this.signEthTx = opts.signTransaction
this.getGasPrice = opts.getGasPrice
this.inProcessOfSigning = new Set() this.inProcessOfSigning = new Set()
this.memStore = new ObservableStore({}) this.memStore = new ObservableStore({})
@ -291,9 +289,7 @@ export default class TransactionController extends EventEmitter {
if (txMeta.txParams.gasPrice) { if (txMeta.txParams.gasPrice) {
return return
} }
const gasPrice = this.getGasPrice const gasPrice = await this.query.gasPrice()
? this.getGasPrice()
: await this.query.gasPrice()
return ethUtil.addHexPrefix(gasPrice.toString(16)) return ethUtil.addHexPrefix(gasPrice.toString(16))
} }
@ -347,13 +343,12 @@ export default class TransactionController extends EventEmitter {
const originalTxMeta = this.txStateManager.getTx(originalTxId) const originalTxMeta = this.txStateManager.getTx(originalTxId)
const { txParams } = originalTxMeta const { txParams } = originalTxMeta
const lastGasPrice = gasPrice || originalTxMeta.txParams.gasPrice const lastGasPrice = gasPrice || originalTxMeta.txParams.gasPrice
const suggestedGasPriceBN = new ethUtil.BN(ethUtil.stripHexPrefix(this.getGasPrice()), 16)
const lastGasPriceBN = new ethUtil.BN(ethUtil.stripHexPrefix(lastGasPrice), 16) const lastGasPriceBN = new ethUtil.BN(ethUtil.stripHexPrefix(lastGasPrice), 16)
// essentially lastGasPrice * 1.1 but // essentially lastGasPrice * 1.1
// dont trust decimals so a round about way of doing that const lastGasPriceBNBumped = lastGasPriceBN
const lastGasPriceBNBumped = lastGasPriceBN.mul(new ethUtil.BN(110, 10)).div(new ethUtil.BN(100, 10)) .mul(new ethUtil.BN(110, 10))
// transactions that are being retried require a >=%10 bump or the clients will throw an error .div(new ethUtil.BN(100, 10))
txParams.gasPrice = suggestedGasPriceBN.gt(lastGasPriceBNBumped) ? `0x${suggestedGasPriceBN.toString(16)}` : `0x${lastGasPriceBNBumped.toString(16)}` txParams.gasPrice = `0x${lastGasPriceBNBumped.toString(16)}`
const txMeta = this.txStateManager.generateTxMeta({ const txMeta = this.txStateManager.generateTxMeta({
txParams: originalTxMeta.txParams, txParams: originalTxMeta.txParams,

@ -34,7 +34,6 @@ import CachedBalancesController from './controllers/cached-balances'
import AlertController from './controllers/alert' import AlertController from './controllers/alert'
import OnboardingController from './controllers/onboarding' import OnboardingController from './controllers/onboarding'
import ThreeBoxController from './controllers/threebox' import ThreeBoxController from './controllers/threebox'
import RecentBlocksController from './controllers/recent-blocks'
import IncomingTransactionsController from './controllers/incoming-transactions' import IncomingTransactionsController from './controllers/incoming-transactions'
import MessageManager from './lib/message-manager' import MessageManager from './lib/message-manager'
import DecryptMessageManager from './lib/decrypt-message-manager' import DecryptMessageManager from './lib/decrypt-message-manager'
@ -53,10 +52,8 @@ import getBuyEthUrl from './lib/buy-eth-url'
import selectChainId from './lib/select-chain-id' import selectChainId from './lib/select-chain-id'
import { Mutex } from 'await-semaphore' import { Mutex } from 'await-semaphore'
import { version } from '../manifest/_base.json' import { version } from '../manifest/_base.json'
import ethUtil, { BN } from 'ethereumjs-util' import ethUtil from 'ethereumjs-util'
const GWEI_BN = new BN('1000000000')
import percentile from 'percentile'
import seedPhraseVerifier from './lib/seed-phrase-verifier' import seedPhraseVerifier from './lib/seed-phrase-verifier'
import log from 'loglevel' import log from 'loglevel'
import TrezorKeyring from 'eth-trezor-keyring' import TrezorKeyring from 'eth-trezor-keyring'
@ -150,12 +147,6 @@ export default class MetamaskController extends EventEmitter {
preferences: this.preferencesController.store, preferences: this.preferencesController.store,
}) })
this.recentBlocksController = new RecentBlocksController({
blockTracker: this.blockTracker,
provider: this.provider,
networkController: this.networkController,
})
this.ensController = new EnsController({ this.ensController = new EnsController({
provider: this.provider, provider: this.provider,
networkStore: this.networkController.networkStore, networkStore: this.networkController.networkStore,
@ -258,7 +249,6 @@ export default class MetamaskController extends EventEmitter {
signTransaction: this.keyringController.signTransaction.bind(this.keyringController), signTransaction: this.keyringController.signTransaction.bind(this.keyringController),
provider: this.provider, provider: this.provider,
blockTracker: this.blockTracker, blockTracker: this.blockTracker,
getGasPrice: this.getGasPrice.bind(this),
}) })
this.txController.on('newUnapprovedTx', () => opts.showUnapprovedTx()) this.txController.on('newUnapprovedTx', () => opts.showUnapprovedTx())
@ -334,7 +324,6 @@ export default class MetamaskController extends EventEmitter {
TypesMessageManager: this.typedMessageManager.memStore, TypesMessageManager: this.typedMessageManager.memStore,
KeyringController: this.keyringController.memStore, KeyringController: this.keyringController.memStore,
PreferencesController: this.preferencesController.store, PreferencesController: this.preferencesController.store,
RecentBlocksController: this.recentBlocksController.store,
AddressBookController: this.addressBookController, AddressBookController: this.addressBookController,
CurrencyController: this.currencyRateController, CurrencyController: this.currencyRateController,
InfuraController: this.infuraController.store, InfuraController: this.infuraController.store,
@ -469,7 +458,6 @@ export default class MetamaskController extends EventEmitter {
setCurrentLocale: this.setCurrentLocale.bind(this), setCurrentLocale: this.setCurrentLocale.bind(this),
markPasswordForgotten: this.markPasswordForgotten.bind(this), markPasswordForgotten: this.markPasswordForgotten.bind(this),
unMarkPasswordForgotten: this.unMarkPasswordForgotten.bind(this), unMarkPasswordForgotten: this.unMarkPasswordForgotten.bind(this),
getGasPrice: (cb) => cb(null, this.getGasPrice()),
buyEth: this.buyEth.bind(this), buyEth: this.buyEth.bind(this),
// primary HD keyring management // primary HD keyring management
@ -1804,40 +1792,6 @@ export default class MetamaskController extends EventEmitter {
// MISCELLANEOUS // MISCELLANEOUS
//============================================================================= //=============================================================================
/**
* A method for estimating a good gas price at recent prices.
* Returns the lowest price that would have been included in
* 50% of recent blocks.
*
* @returns {string} - A hex representation of the suggested wei gas price.
*/
getGasPrice () {
const { recentBlocksController } = this
const { recentBlocks } = recentBlocksController.store.getState()
// Return 1 gwei if no blocks have been observed:
if (recentBlocks.length === 0) {
return '0x' + GWEI_BN.toString(16)
}
const lowestPrices = recentBlocks.map((block) => {
if (!block.gasPrices || block.gasPrices.length < 1) {
return GWEI_BN
}
return block.gasPrices
.map((hexPrefix) => hexPrefix.substr(2))
.map((hex) => new BN(hex, 16))
.sort((a, b) => {
return a.gt(b) ? 1 : -1
})[0]
})
.map((number) => number.div(GWEI_BN).toNumber())
const percentileNum = percentile(65, lowestPrices)
const percentileNumBn = new BN(percentileNum)
return '0x' + percentileNumBn.mul(GWEI_BN).toString(16)
}
/** /**
* Returns the nonce that will be associated with a transaction once approved * Returns the nonce that will be associated with a transaction once approved
* @param {string} address - The hex string address for the transaction * @param {string} address - The hex string address for the transaction

@ -45,7 +45,6 @@ async function start () {
: {} : {}
// remove unnecessary data // remove unnecessary data
delete state.localeMessages delete state.localeMessages
delete state.metamask.recentBlocks
// return state to be added to request // return state to be added to request
return state return state
} }

@ -138,7 +138,6 @@
"nonce-tracker": "^1.0.0", "nonce-tracker": "^1.0.0",
"obj-multiplex": "^1.0.0", "obj-multiplex": "^1.0.0",
"obs-store": "^4.0.3", "obs-store": "^4.0.3",
"percentile": "^1.2.0",
"pify": "^5.0.0", "pify": "^5.0.0",
"post-message-stream": "^3.0.0", "post-message-stream": "^3.0.0",
"promise-to-callback": "^1.0.0", "promise-to-callback": "^1.0.0",

@ -176,32 +176,6 @@ describe('MetaMaskController', function () {
}) })
}) })
describe('#getGasPrice', function () {
it('gives the 50th percentile lowest accepted gas price from recentBlocksController', async function () {
const realRecentBlocksController = metamaskController.recentBlocksController
metamaskController.recentBlocksController = {
store: {
getState: () => {
return {
recentBlocks: [
{ gasPrices: [ '0x3b9aca00', '0x174876e800'] },
{ gasPrices: [ '0x3b9aca00', '0x174876e800'] },
{ gasPrices: [ '0x174876e800', '0x174876e800' ] },
{ gasPrices: [ '0x174876e800', '0x174876e800' ] },
],
}
},
},
}
const gasPrice = metamaskController.getGasPrice()
assert.equal(gasPrice, '0x174876e800', 'accurately estimates 65th percentile accepted gas price')
metamaskController.recentBlocksController = realRecentBlocksController
})
})
describe('#createNewVaultAndKeychain', function () { describe('#createNewVaultAndKeychain', function () {
it('can only create new vault on keyringController once', async function () { it('can only create new vault on keyringController once', async function () {
const selectStub = sandbox.stub(metamaskController, 'selectFirstIdentity') const selectStub = sandbox.stub(metamaskController, 'selectFirstIdentity')

@ -32,7 +32,6 @@ export default class SendTransactionScreen extends Component {
history: PropTypes.object, history: PropTypes.object,
network: PropTypes.string, network: PropTypes.string,
primaryCurrency: PropTypes.string, primaryCurrency: PropTypes.string,
recentBlocks: PropTypes.array,
resetSendState: PropTypes.func.isRequired, resetSendState: PropTypes.func.isRequired,
selectedAddress: PropTypes.string, selectedAddress: PropTypes.string,
selectedToken: PropTypes.object, selectedToken: PropTypes.object,
@ -260,7 +259,6 @@ export default class SendTransactionScreen extends Component {
editingTransactionId, editingTransactionId,
gasLimit, gasLimit,
gasPrice, gasPrice,
recentBlocks,
selectedAddress, selectedAddress,
selectedToken = {}, selectedToken = {},
to: currentToAddress, to: currentToAddress,
@ -272,7 +270,6 @@ export default class SendTransactionScreen extends Component {
editingTransactionId, editingTransactionId,
gasLimit, gasLimit,
gasPrice, gasPrice,
recentBlocks,
selectedAddress, selectedAddress,
selectedToken, selectedToken,
to: getToAddressForGasUpdate(updatedToAddress, currentToAddress), to: getToAddressForGasUpdate(updatedToAddress, currentToAddress),

@ -30,13 +30,6 @@ const INVALID_RECIPIENT_ADDRESS_NOT_ETH_NETWORK_ERROR = 'invalidAddressRecipient
const REQUIRED_ERROR = 'required' const REQUIRED_ERROR = 'required'
const KNOWN_RECIPIENT_ADDRESS_ERROR = 'knownAddressRecipient' const KNOWN_RECIPIENT_ADDRESS_ERROR = 'knownAddressRecipient'
const ONE_GWEI_IN_WEI_HEX = ethUtil.addHexPrefix(conversionUtil('0x1', {
fromDenomination: 'GWEI',
toDenomination: 'WEI',
fromNumericBase: 'hex',
toNumericBase: 'hex',
}))
const SIMPLE_GAS_COST = '0x5208' // Hex for 21000, cost of a simple send. const SIMPLE_GAS_COST = '0x5208' // Hex for 21000, cost of a simple send.
const BASE_TOKEN_GAS_COST = '0x186a0' // Hex for 100000, a base estimate for token transfers. const BASE_TOKEN_GAS_COST = '0x186a0' // Hex for 100000, a base estimate for token transfers.
@ -53,7 +46,6 @@ export {
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,
SIMPLE_GAS_COST, SIMPLE_GAS_COST,
TOKEN_TRANSFER_FUNCTION_SIGNATURE, TOKEN_TRANSFER_FUNCTION_SIGNATURE,

@ -11,7 +11,6 @@ import {
getGasPrice, getGasPrice,
getGasTotal, getGasTotal,
getPrimaryCurrency, getPrimaryCurrency,
getRecentBlocks,
getSelectedToken, getSelectedToken,
getSelectedTokenContract, getSelectedTokenContract,
getSendAmount, getSendAmount,
@ -67,7 +66,6 @@ function mapStateToProps (state) {
network: getCurrentNetwork(state), network: getCurrentNetwork(state),
primaryCurrency: getPrimaryCurrency(state), primaryCurrency: getPrimaryCurrency(state),
qrCodeData: getQrCodeData(state), qrCodeData: getQrCodeData(state),
recentBlocks: getRecentBlocks(state),
selectedAddress: getSelectedAddress(state), selectedAddress: getSelectedAddress(state),
selectedToken: getSelectedToken(state), selectedToken: getSelectedToken(state),
showHexData: getSendHexDataFeatureFlagState(state), showHexData: getSendHexDataFeatureFlagState(state),
@ -86,7 +84,6 @@ function mapDispatchToProps (dispatch) {
editingTransactionId, editingTransactionId,
gasLimit, gasLimit,
gasPrice, gasPrice,
recentBlocks,
selectedAddress, selectedAddress,
selectedToken, selectedToken,
to, to,
@ -94,7 +91,7 @@ function mapDispatchToProps (dispatch) {
data, data,
}) => { }) => {
!editingTransactionId !editingTransactionId
? dispatch(updateGasData({ gasPrice, recentBlocks, selectedAddress, selectedToken, blockGasLimit, to, value, data })) ? dispatch(updateGasData({ gasPrice, selectedAddress, selectedToken, blockGasLimit, to, value, data }))
: dispatch(setGasTotal(calcGasTotal(gasLimit, gasPrice))) : dispatch(setGasTotal(calcGasTotal(gasLimit, gasPrice)))
}, },
updateSendTokenBalance: ({ selectedToken, tokenContract, address }) => { updateSendTokenBalance: ({ selectedToken, tokenContract, address }) => {

@ -15,7 +15,6 @@ import {
INSUFFICIENT_TOKENS_ERROR, INSUFFICIENT_TOKENS_ERROR,
MIN_GAS_LIMIT_HEX, MIN_GAS_LIMIT_HEX,
NEGATIVE_ETH_ERROR, NEGATIVE_ETH_ERROR,
ONE_GWEI_IN_WEI_HEX,
SIMPLE_GAS_COST, SIMPLE_GAS_COST,
TOKEN_TRANSFER_FUNCTION_SIGNATURE, TOKEN_TRANSFER_FUNCTION_SIGNATURE,
} from './send.constants' } from './send.constants'
@ -29,7 +28,6 @@ export {
calcTokenBalance, calcTokenBalance,
doesAmountErrorRequireUpdate, doesAmountErrorRequireUpdate,
estimateGas, estimateGas,
estimateGasPriceFromRecentBlocks,
generateTokenTransferData, generateTokenTransferData,
getAmountErrorObject, getAmountErrorObject,
getGasFeeErrorObject, getGasFeeErrorObject,
@ -311,25 +309,6 @@ function generateTokenTransferData ({ toAddress = '0x0', amount = '0x0', selecte
).join('') ).join('')
} }
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.reduce((currentLowest, next) => {
return parseInt(next, 16) < parseInt(currentLowest, 16) ? next : currentLowest
})
})
.sort((a, b) => (parseInt(a, 16) > parseInt(b, 16) ? 1 : -1))
return lowestPrices[Math.floor(lowestPrices.length / 2)]
}
function getToAddressForGasUpdate (...addresses) { function getToAddressForGasUpdate (...addresses) {
return [...addresses, ''].find((str) => str !== undefined && str !== null).toLowerCase() return [...addresses, ''].find((str) => str !== undefined && str !== null).toLowerCase()
} }

@ -57,7 +57,6 @@ describe('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={{ address: 'mockTokenAddress', decimals: 18, symbol: 'TST' }} selectedToken={{ address: 'mockTokenAddress', decimals: 18, symbol: 'TST' }}
showHexData showHexData
@ -331,7 +330,6 @@ describe('Send Component', function () {
editingTransactionId: 'mockEditingTransactionId', editingTransactionId: 'mockEditingTransactionId',
gasLimit: 'mockGasLimit', gasLimit: 'mockGasLimit',
gasPrice: 'mockGasPrice', gasPrice: 'mockGasPrice',
recentBlocks: ['mockBlock'],
selectedAddress: 'mockSelectedAddress', selectedAddress: 'mockSelectedAddress',
selectedToken: { address: 'mockTokenAddress', decimals: 18, symbol: 'TST' }, selectedToken: { address: 'mockTokenAddress', decimals: 18, symbol: 'TST' },
to: '', to: '',

@ -48,7 +48,6 @@ describe('send container', function () {
editingTransactionId: '0x2', editingTransactionId: '0x2',
gasLimit: '0x3', gasLimit: '0x3',
gasPrice: '0x4', gasPrice: '0x4',
recentBlocks: ['mockBlock'],
selectedAddress: '0x4', selectedAddress: '0x4',
selectedToken: { address: '0x1' }, selectedToken: { address: '0x1' },
to: 'mockTo', to: 'mockTo',
@ -66,14 +65,14 @@ describe('send container', function () {
}) })
it('should dispatch an updateGasData action when editingTransactionId is falsy', function () { it('should dispatch an updateGasData action when editingTransactionId is falsy', function () {
const { gasPrice, selectedAddress, selectedToken, recentBlocks, blockGasLimit, to, value, data } = mockProps const { gasPrice, selectedAddress, selectedToken, blockGasLimit, to, value, data } = mockProps
mapDispatchToPropsObject.updateAndSetGasLimit( mapDispatchToPropsObject.updateAndSetGasLimit(
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],
{ gasPrice, selectedAddress, selectedToken, recentBlocks, blockGasLimit, to, value, data } { gasPrice, selectedAddress, selectedToken, blockGasLimit, to, value, data }
) )
}) })
}) })

@ -3,12 +3,10 @@ import sinon from 'sinon'
import proxyquire from 'proxyquire' import proxyquire from 'proxyquire'
import { import {
BASE_TOKEN_GAS_COST, BASE_TOKEN_GAS_COST,
ONE_GWEI_IN_WEI_HEX,
SIMPLE_GAS_COST, SIMPLE_GAS_COST,
INSUFFICIENT_FUNDS_ERROR, INSUFFICIENT_FUNDS_ERROR,
INSUFFICIENT_TOKENS_ERROR, INSUFFICIENT_TOKENS_ERROR,
} from '../send.constants' } from '../send.constants'
import { addCurrencies, subtractCurrencies } from '../../../helpers/utils/conversion-util'
const stubs = { const stubs = {
addCurrencies: sinon.stub().callsFake((a, b) => { addCurrencies: sinon.stub().callsFake((a, b) => {
@ -48,7 +46,6 @@ const {
calcGasTotal, calcGasTotal,
estimateGas, estimateGas,
doesAmountErrorRequireUpdate, doesAmountErrorRequireUpdate,
estimateGasPriceFromRecentBlocks,
generateTokenTransferData, generateTokenTransferData,
getAmountErrorObject, getAmountErrorObject,
getGasFeeErrorObject, getGasFeeErrorObject,
@ -418,68 +415,6 @@ describe('send utils', function () {
}) })
}) })
describe('estimateGasPriceFromRecentBlocks', function () {
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`, function () {
assert.equal(estimateGasPriceFromRecentBlocks(), ONE_GWEI_IN_WEI_HEX)
})
it(`should return ${ONE_GWEI_IN_WEI_HEX} if recentBlocks is empty`, function () {
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`, function () {
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`, function () {
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`, function () {
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`, function () {
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')
})
})
describe('getToAddressForGasUpdate()', function () { describe('getToAddressForGasUpdate()', function () {
it('should return empty string if all params are undefined or null', function () { it('should return empty string if all params are undefined or null', function () {
assert.equal(getToAddressForGasUpdate(undefined, null), '') assert.equal(getToAddressForGasUpdate(undefined, null), '')

@ -6,7 +6,7 @@ import {
getTargetAccount, getTargetAccount,
getAveragePriceEstimateInHexWEI, getAveragePriceEstimateInHexWEI,
} from '.' } from '.'
import { estimateGasPriceFromRecentBlocks, calcGasTotal } from '../pages/send/send.utils' import { calcGasTotal } from '../pages/send/send.utils'
export function getBlockGasLimit (state) { export function getBlockGasLimit (state) {
return state.metamask.currentBlockGasLimit return state.metamask.currentBlockGasLimit
@ -32,10 +32,6 @@ export function getGasPrice (state) {
return state.metamask.send.gasPrice || getAveragePriceEstimateInHexWEI(state) return state.metamask.send.gasPrice || getAveragePriceEstimateInHexWEI(state)
} }
export function getGasPriceFromRecentBlocks (state) {
return estimateGasPriceFromRecentBlocks(state.metamask.recentBlocks)
}
export function getGasTotal (state) { export function getGasTotal (state) {
return calcGasTotal(getGasLimit(state), getGasPrice(state)) return calcGasTotal(getGasLimit(state), getGasPrice(state))
} }
@ -45,10 +41,6 @@ export function getPrimaryCurrency (state) {
return selectedToken && selectedToken.symbol return selectedToken && selectedToken.symbol
} }
export function getRecentBlocks (state) {
return state.metamask.recentBlocks
}
export function getSelectedToken (state) { export function getSelectedToken (state) {
const tokens = state.metamask.tokens || [] const tokens = state.metamask.tokens || []
const selectedTokenAddress = state.metamask.selectedTokenAddress const selectedTokenAddress = state.metamask.selectedTokenAddress

@ -191,7 +191,6 @@ export default {
}, },
}, },
'currentLocale': 'en', 'currentLocale': 'en',
recentBlocks: ['mockBlock1', 'mockBlock2', 'mockBlock3'],
}, },
'appState': { 'appState': {
'menuOpen': false, 'menuOpen': false,

@ -13,7 +13,6 @@ import {
getGasPrice, getGasPrice,
getGasTotal, getGasTotal,
getPrimaryCurrency, getPrimaryCurrency,
getRecentBlocks,
getSelectedToken, getSelectedToken,
getSelectedTokenContract, getSelectedTokenContract,
getSendAmount, getSendAmount,
@ -177,15 +176,6 @@ describe('send selectors', function () {
}) })
}) })
describe('getRecentBlocks()', function () {
it('should return the recent blocks', function () {
assert.deepEqual(
getRecentBlocks(mockState),
['mockBlock1', 'mockBlock2', 'mockBlock3']
)
})
})
describe('getSelectedToken()', function () { describe('getSelectedToken()', function () {
it('should return the currently selected token if selected', function () { it('should return the currently selected token if selected', function () {
assert.deepEqual( assert.deepEqual(

@ -21742,11 +21742,6 @@ pend@~1.2.0:
resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50"
integrity sha1-elfrVQpng/kRUzH89GY9XI4AelA= integrity sha1-elfrVQpng/kRUzH89GY9XI4AelA=
percentile@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/percentile/-/percentile-1.2.0.tgz#fa3b05c1ffd355b35228529834e5fa37f0bd465d"
integrity sha1-+jsFwf/TVbNSKFKYNOX6N/C9Rl0=
percentile@^1.2.1: percentile@^1.2.1:
version "1.2.2" version "1.2.2"
resolved "https://registry.yarnpkg.com/percentile/-/percentile-1.2.2.tgz#8966abc4bb36aaacaee91405f17095d9c881d1cb" resolved "https://registry.yarnpkg.com/percentile/-/percentile-1.2.2.tgz#8966abc4bb36aaacaee91405f17095d9c881d1cb"

Loading…
Cancel
Save