mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-11-30 08:09:15 +01:00
5b5b67a985
A race condition exists where after adding an unapproved transaction, it could be mutated and then replaced when the default gas parameters are set. This happens because the transaction is added to state and broadcast before the default gas parameters are set, because calculating the default gas parameters to use takes some time. Once they've been calculated, the false assumption was made that the transaction hadn't changed. The method responsible for setting the default gas now retrieves an up-to-date copy of `txMeta`, and conditionally sets the defaults only if they haven't yet been set. This race condition was introduced in #2962, though that PR also added a loading screen that avoided this issue by preventing the user from interacting with the transaction until after the gas had been estimated. Unfortunately this loading screen was not carried forward to the new UI.
90 lines
2.9 KiB
JavaScript
90 lines
2.9 KiB
JavaScript
import EthQuery from 'ethjs-query'
|
|
import { hexToBn, BnMultiplyByFraction, bnToHex } from '../../lib/util'
|
|
import log from 'loglevel'
|
|
|
|
/**
|
|
* Result of gas analysis, including either a gas estimate for a successful analysis, or
|
|
* debug information for a failed analysis.
|
|
* @typedef {Object} GasAnalysisResult
|
|
* @property {string} blockGasLimit - The gas limit of the block used for the analysis
|
|
* @property {string} estimatedGasHex - The estimated gas, in hexidecimal
|
|
* @property {Object} simulationFails - Debug information about why an analysis failed
|
|
*/
|
|
|
|
/**
|
|
tx-gas-utils are gas utility methods for Transaction manager
|
|
its passed ethquery
|
|
and used to do things like calculate gas of a tx.
|
|
@param {Object} provider - A network provider.
|
|
*/
|
|
|
|
export default class TxGasUtil {
|
|
|
|
constructor (provider) {
|
|
this.query = new EthQuery(provider)
|
|
}
|
|
|
|
/**
|
|
@param {Object} txMeta - the txMeta object
|
|
@returns {GasAnalysisResult} The result of the gas analysis
|
|
*/
|
|
async analyzeGasUsage (txMeta) {
|
|
const block = await this.query.getBlockByNumber('latest', false)
|
|
|
|
// fallback to block gasLimit
|
|
const blockGasLimitBN = hexToBn(block.gasLimit)
|
|
const saferGasLimitBN = BnMultiplyByFraction(blockGasLimitBN, 19, 20)
|
|
let estimatedGasHex = bnToHex(saferGasLimitBN)
|
|
let simulationFails
|
|
try {
|
|
estimatedGasHex = await this.estimateTxGas(txMeta, block.gasLimit)
|
|
} catch (error) {
|
|
log.warn(error)
|
|
simulationFails = {
|
|
reason: error.message,
|
|
errorKey: error.errorKey,
|
|
debug: { blockNumber: block.number, blockGasLimit: block.gasLimit },
|
|
}
|
|
}
|
|
|
|
return { blockGasLimit: block.gasLimit, estimatedGasHex, simulationFails }
|
|
}
|
|
|
|
/**
|
|
Estimates the tx's gas usage
|
|
@param {Object} txMeta - the txMeta object
|
|
@returns {string} - the estimated gas limit as a hex string
|
|
*/
|
|
async estimateTxGas (txMeta) {
|
|
const txParams = txMeta.txParams
|
|
|
|
// estimate tx gas requirements
|
|
return await this.query.estimateGas(txParams)
|
|
}
|
|
|
|
/**
|
|
Adds a gas buffer with out exceeding the block gas limit
|
|
|
|
@param {string} initialGasLimitHex - the initial gas limit to add the buffer too
|
|
@param {string} blockGasLimitHex - the block gas limit
|
|
@returns {string} - the buffered gas limit as a hex string
|
|
*/
|
|
addGasBuffer (initialGasLimitHex, blockGasLimitHex) {
|
|
const initialGasLimitBn = hexToBn(initialGasLimitHex)
|
|
const blockGasLimitBn = hexToBn(blockGasLimitHex)
|
|
const upperGasLimitBn = blockGasLimitBn.muln(0.9)
|
|
const bufferedGasLimitBn = initialGasLimitBn.muln(1.5)
|
|
|
|
// if initialGasLimit is above blockGasLimit, dont modify it
|
|
if (initialGasLimitBn.gt(upperGasLimitBn)) {
|
|
return bnToHex(initialGasLimitBn)
|
|
}
|
|
// if bufferedGasLimit is below blockGasLimit, use bufferedGasLimit
|
|
if (bufferedGasLimitBn.lt(upperGasLimitBn)) {
|
|
return bnToHex(bufferedGasLimitBn)
|
|
}
|
|
// otherwise use blockGasLimit
|
|
return bnToHex(upperGasLimitBn)
|
|
}
|
|
}
|