mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-23 09:52:26 +01:00
Delete recent blocks controller (#8575)
* delete recent blocks controller * delete percentile from direct dependencies
This commit is contained in:
parent
0aa41e397e
commit
0470386326
@ -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} 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 {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.
|
||||
*/
|
||||
|
||||
|
@ -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 {Function} opts.signTransaction - function the signs an ethereumjs-tx
|
||||
@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 {number} [opts.txHistoryLimit] - number *optional* for limiting how many transactions are in state
|
||||
@param {Object} opts.preferencesStore
|
||||
@ -77,7 +76,6 @@ export default class TransactionController extends EventEmitter {
|
||||
this.getPermittedAccounts = opts.getPermittedAccounts
|
||||
this.blockTracker = opts.blockTracker
|
||||
this.signEthTx = opts.signTransaction
|
||||
this.getGasPrice = opts.getGasPrice
|
||||
this.inProcessOfSigning = new Set()
|
||||
|
||||
this.memStore = new ObservableStore({})
|
||||
@ -291,9 +289,7 @@ export default class TransactionController extends EventEmitter {
|
||||
if (txMeta.txParams.gasPrice) {
|
||||
return
|
||||
}
|
||||
const gasPrice = this.getGasPrice
|
||||
? this.getGasPrice()
|
||||
: await this.query.gasPrice()
|
||||
const gasPrice = await this.query.gasPrice()
|
||||
|
||||
return ethUtil.addHexPrefix(gasPrice.toString(16))
|
||||
}
|
||||
@ -347,13 +343,12 @@ export default class TransactionController extends EventEmitter {
|
||||
const originalTxMeta = this.txStateManager.getTx(originalTxId)
|
||||
const { txParams } = originalTxMeta
|
||||
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)
|
||||
// essentially lastGasPrice * 1.1 but
|
||||
// dont trust decimals so a round about way of doing that
|
||||
const lastGasPriceBNBumped = lastGasPriceBN.mul(new ethUtil.BN(110, 10)).div(new ethUtil.BN(100, 10))
|
||||
// transactions that are being retried require a >=%10 bump or the clients will throw an error
|
||||
txParams.gasPrice = suggestedGasPriceBN.gt(lastGasPriceBNBumped) ? `0x${suggestedGasPriceBN.toString(16)}` : `0x${lastGasPriceBNBumped.toString(16)}`
|
||||
// essentially lastGasPrice * 1.1
|
||||
const lastGasPriceBNBumped = lastGasPriceBN
|
||||
.mul(new ethUtil.BN(110, 10))
|
||||
.div(new ethUtil.BN(100, 10))
|
||||
txParams.gasPrice = `0x${lastGasPriceBNBumped.toString(16)}`
|
||||
|
||||
const txMeta = this.txStateManager.generateTxMeta({
|
||||
txParams: originalTxMeta.txParams,
|
||||
|
@ -34,7 +34,6 @@ import CachedBalancesController from './controllers/cached-balances'
|
||||
import AlertController from './controllers/alert'
|
||||
import OnboardingController from './controllers/onboarding'
|
||||
import ThreeBoxController from './controllers/threebox'
|
||||
import RecentBlocksController from './controllers/recent-blocks'
|
||||
import IncomingTransactionsController from './controllers/incoming-transactions'
|
||||
import MessageManager from './lib/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 { Mutex } from 'await-semaphore'
|
||||
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 log from 'loglevel'
|
||||
import TrezorKeyring from 'eth-trezor-keyring'
|
||||
@ -150,12 +147,6 @@ export default class MetamaskController extends EventEmitter {
|
||||
preferences: this.preferencesController.store,
|
||||
})
|
||||
|
||||
this.recentBlocksController = new RecentBlocksController({
|
||||
blockTracker: this.blockTracker,
|
||||
provider: this.provider,
|
||||
networkController: this.networkController,
|
||||
})
|
||||
|
||||
this.ensController = new EnsController({
|
||||
provider: this.provider,
|
||||
networkStore: this.networkController.networkStore,
|
||||
@ -258,7 +249,6 @@ export default class MetamaskController extends EventEmitter {
|
||||
signTransaction: this.keyringController.signTransaction.bind(this.keyringController),
|
||||
provider: this.provider,
|
||||
blockTracker: this.blockTracker,
|
||||
getGasPrice: this.getGasPrice.bind(this),
|
||||
})
|
||||
this.txController.on('newUnapprovedTx', () => opts.showUnapprovedTx())
|
||||
|
||||
@ -334,7 +324,6 @@ export default class MetamaskController extends EventEmitter {
|
||||
TypesMessageManager: this.typedMessageManager.memStore,
|
||||
KeyringController: this.keyringController.memStore,
|
||||
PreferencesController: this.preferencesController.store,
|
||||
RecentBlocksController: this.recentBlocksController.store,
|
||||
AddressBookController: this.addressBookController,
|
||||
CurrencyController: this.currencyRateController,
|
||||
InfuraController: this.infuraController.store,
|
||||
@ -469,7 +458,6 @@ export default class MetamaskController extends EventEmitter {
|
||||
setCurrentLocale: this.setCurrentLocale.bind(this),
|
||||
markPasswordForgotten: this.markPasswordForgotten.bind(this),
|
||||
unMarkPasswordForgotten: this.unMarkPasswordForgotten.bind(this),
|
||||
getGasPrice: (cb) => cb(null, this.getGasPrice()),
|
||||
buyEth: this.buyEth.bind(this),
|
||||
|
||||
// primary HD keyring management
|
||||
@ -1804,40 +1792,6 @@ export default class MetamaskController extends EventEmitter {
|
||||
// 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
|
||||
* @param {string} address - The hex string address for the transaction
|
||||
|
@ -45,7 +45,6 @@ async function start () {
|
||||
: {}
|
||||
// remove unnecessary data
|
||||
delete state.localeMessages
|
||||
delete state.metamask.recentBlocks
|
||||
// return state to be added to request
|
||||
return state
|
||||
}
|
||||
|
@ -138,7 +138,6 @@
|
||||
"nonce-tracker": "^1.0.0",
|
||||
"obj-multiplex": "^1.0.0",
|
||||
"obs-store": "^4.0.3",
|
||||
"percentile": "^1.2.0",
|
||||
"pify": "^5.0.0",
|
||||
"post-message-stream": "^3.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 () {
|
||||
it('can only create new vault on keyringController once', async function () {
|
||||
const selectStub = sandbox.stub(metamaskController, 'selectFirstIdentity')
|
||||
|
@ -32,7 +32,6 @@ export default class SendTransactionScreen extends Component {
|
||||
history: PropTypes.object,
|
||||
network: PropTypes.string,
|
||||
primaryCurrency: PropTypes.string,
|
||||
recentBlocks: PropTypes.array,
|
||||
resetSendState: PropTypes.func.isRequired,
|
||||
selectedAddress: PropTypes.string,
|
||||
selectedToken: PropTypes.object,
|
||||
@ -260,7 +259,6 @@ export default class SendTransactionScreen extends Component {
|
||||
editingTransactionId,
|
||||
gasLimit,
|
||||
gasPrice,
|
||||
recentBlocks,
|
||||
selectedAddress,
|
||||
selectedToken = {},
|
||||
to: currentToAddress,
|
||||
@ -272,7 +270,6 @@ export default class SendTransactionScreen extends Component {
|
||||
editingTransactionId,
|
||||
gasLimit,
|
||||
gasPrice,
|
||||
recentBlocks,
|
||||
selectedAddress,
|
||||
selectedToken,
|
||||
to: getToAddressForGasUpdate(updatedToAddress, currentToAddress),
|
||||
|
@ -30,13 +30,6 @@ const INVALID_RECIPIENT_ADDRESS_NOT_ETH_NETWORK_ERROR = 'invalidAddressRecipient
|
||||
const REQUIRED_ERROR = 'required'
|
||||
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 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_TOTAL,
|
||||
NEGATIVE_ETH_ERROR,
|
||||
ONE_GWEI_IN_WEI_HEX,
|
||||
REQUIRED_ERROR,
|
||||
SIMPLE_GAS_COST,
|
||||
TOKEN_TRANSFER_FUNCTION_SIGNATURE,
|
||||
|
@ -11,7 +11,6 @@ import {
|
||||
getGasPrice,
|
||||
getGasTotal,
|
||||
getPrimaryCurrency,
|
||||
getRecentBlocks,
|
||||
getSelectedToken,
|
||||
getSelectedTokenContract,
|
||||
getSendAmount,
|
||||
@ -67,7 +66,6 @@ function mapStateToProps (state) {
|
||||
network: getCurrentNetwork(state),
|
||||
primaryCurrency: getPrimaryCurrency(state),
|
||||
qrCodeData: getQrCodeData(state),
|
||||
recentBlocks: getRecentBlocks(state),
|
||||
selectedAddress: getSelectedAddress(state),
|
||||
selectedToken: getSelectedToken(state),
|
||||
showHexData: getSendHexDataFeatureFlagState(state),
|
||||
@ -86,7 +84,6 @@ function mapDispatchToProps (dispatch) {
|
||||
editingTransactionId,
|
||||
gasLimit,
|
||||
gasPrice,
|
||||
recentBlocks,
|
||||
selectedAddress,
|
||||
selectedToken,
|
||||
to,
|
||||
@ -94,7 +91,7 @@ function mapDispatchToProps (dispatch) {
|
||||
data,
|
||||
}) => {
|
||||
!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)))
|
||||
},
|
||||
updateSendTokenBalance: ({ selectedToken, tokenContract, address }) => {
|
||||
|
@ -15,7 +15,6 @@ import {
|
||||
INSUFFICIENT_TOKENS_ERROR,
|
||||
MIN_GAS_LIMIT_HEX,
|
||||
NEGATIVE_ETH_ERROR,
|
||||
ONE_GWEI_IN_WEI_HEX,
|
||||
SIMPLE_GAS_COST,
|
||||
TOKEN_TRANSFER_FUNCTION_SIGNATURE,
|
||||
} from './send.constants'
|
||||
@ -29,7 +28,6 @@ export {
|
||||
calcTokenBalance,
|
||||
doesAmountErrorRequireUpdate,
|
||||
estimateGas,
|
||||
estimateGasPriceFromRecentBlocks,
|
||||
generateTokenTransferData,
|
||||
getAmountErrorObject,
|
||||
getGasFeeErrorObject,
|
||||
@ -311,25 +309,6 @@ function generateTokenTransferData ({ toAddress = '0x0', amount = '0x0', selecte
|
||||
).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) {
|
||||
return [...addresses, ''].find((str) => str !== undefined && str !== null).toLowerCase()
|
||||
}
|
||||
|
@ -57,7 +57,6 @@ describe('Send Component', function () {
|
||||
history={{ mockProp: 'history-abc' }}
|
||||
network="3"
|
||||
primaryCurrency="mockPrimaryCurrency"
|
||||
recentBlocks={['mockBlock']}
|
||||
selectedAddress="mockSelectedAddress"
|
||||
selectedToken={{ address: 'mockTokenAddress', decimals: 18, symbol: 'TST' }}
|
||||
showHexData
|
||||
@ -331,7 +330,6 @@ describe('Send Component', function () {
|
||||
editingTransactionId: 'mockEditingTransactionId',
|
||||
gasLimit: 'mockGasLimit',
|
||||
gasPrice: 'mockGasPrice',
|
||||
recentBlocks: ['mockBlock'],
|
||||
selectedAddress: 'mockSelectedAddress',
|
||||
selectedToken: { address: 'mockTokenAddress', decimals: 18, symbol: 'TST' },
|
||||
to: '',
|
||||
|
@ -48,7 +48,6 @@ describe('send container', function () {
|
||||
editingTransactionId: '0x2',
|
||||
gasLimit: '0x3',
|
||||
gasPrice: '0x4',
|
||||
recentBlocks: ['mockBlock'],
|
||||
selectedAddress: '0x4',
|
||||
selectedToken: { address: '0x1' },
|
||||
to: 'mockTo',
|
||||
@ -66,14 +65,14 @@ describe('send container', 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(
|
||||
Object.assign({}, mockProps, { editingTransactionId: false })
|
||||
)
|
||||
assert(dispatchSpy.calledOnce)
|
||||
assert.deepEqual(
|
||||
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 {
|
||||
BASE_TOKEN_GAS_COST,
|
||||
ONE_GWEI_IN_WEI_HEX,
|
||||
SIMPLE_GAS_COST,
|
||||
INSUFFICIENT_FUNDS_ERROR,
|
||||
INSUFFICIENT_TOKENS_ERROR,
|
||||
} from '../send.constants'
|
||||
import { addCurrencies, subtractCurrencies } from '../../../helpers/utils/conversion-util'
|
||||
|
||||
const stubs = {
|
||||
addCurrencies: sinon.stub().callsFake((a, b) => {
|
||||
@ -48,7 +46,6 @@ const {
|
||||
calcGasTotal,
|
||||
estimateGas,
|
||||
doesAmountErrorRequireUpdate,
|
||||
estimateGasPriceFromRecentBlocks,
|
||||
generateTokenTransferData,
|
||||
getAmountErrorObject,
|
||||
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 () {
|
||||
it('should return empty string if all params are undefined or null', function () {
|
||||
assert.equal(getToAddressForGasUpdate(undefined, null), '')
|
||||
|
@ -6,7 +6,7 @@ import {
|
||||
getTargetAccount,
|
||||
getAveragePriceEstimateInHexWEI,
|
||||
} from '.'
|
||||
import { estimateGasPriceFromRecentBlocks, calcGasTotal } from '../pages/send/send.utils'
|
||||
import { calcGasTotal } from '../pages/send/send.utils'
|
||||
|
||||
export function getBlockGasLimit (state) {
|
||||
return state.metamask.currentBlockGasLimit
|
||||
@ -32,10 +32,6 @@ export function getGasPrice (state) {
|
||||
return state.metamask.send.gasPrice || getAveragePriceEstimateInHexWEI(state)
|
||||
}
|
||||
|
||||
export function getGasPriceFromRecentBlocks (state) {
|
||||
return estimateGasPriceFromRecentBlocks(state.metamask.recentBlocks)
|
||||
}
|
||||
|
||||
export function getGasTotal (state) {
|
||||
return calcGasTotal(getGasLimit(state), getGasPrice(state))
|
||||
}
|
||||
@ -45,10 +41,6 @@ export function getPrimaryCurrency (state) {
|
||||
return selectedToken && selectedToken.symbol
|
||||
}
|
||||
|
||||
export function getRecentBlocks (state) {
|
||||
return state.metamask.recentBlocks
|
||||
}
|
||||
|
||||
export function getSelectedToken (state) {
|
||||
const tokens = state.metamask.tokens || []
|
||||
const selectedTokenAddress = state.metamask.selectedTokenAddress
|
||||
|
@ -191,7 +191,6 @@ export default {
|
||||
},
|
||||
},
|
||||
'currentLocale': 'en',
|
||||
recentBlocks: ['mockBlock1', 'mockBlock2', 'mockBlock3'],
|
||||
},
|
||||
'appState': {
|
||||
'menuOpen': false,
|
||||
|
@ -13,7 +13,6 @@ import {
|
||||
getGasPrice,
|
||||
getGasTotal,
|
||||
getPrimaryCurrency,
|
||||
getRecentBlocks,
|
||||
getSelectedToken,
|
||||
getSelectedTokenContract,
|
||||
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 () {
|
||||
it('should return the currently selected token if selected', function () {
|
||||
assert.deepEqual(
|
||||
|
@ -21742,11 +21742,6 @@ pend@~1.2.0:
|
||||
resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50"
|
||||
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:
|
||||
version "1.2.2"
|
||||
resolved "https://registry.yarnpkg.com/percentile/-/percentile-1.2.2.tgz#8966abc4bb36aaacaee91405f17095d9c881d1cb"
|
||||
|
Loading…
Reference in New Issue
Block a user