mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-11-30 08:09:15 +01:00
3732c5f71e
ESLint rules have been added to enforce our JSDoc conventions. These rules were introduced by updating `@metamask/eslint-config` to v9. Some of the rules have been disabled because the effort to fix all lint errors was too high. It might be easiest to enable these rules one directory at a time, or one rule at a time. Most of the changes in this PR were a result of running `yarn lint:fix`. There were a handful of manual changes that seemed obvious and simple to make. Anything beyond that and the rule was left disabled.
120 lines
4.0 KiB
JavaScript
120 lines
4.0 KiB
JavaScript
import EthQuery from 'ethjs-query';
|
|
import log from 'loglevel';
|
|
import { addHexPrefix } from 'ethereumjs-util';
|
|
import { cloneDeep } from 'lodash';
|
|
import { hexToBn, BnMultiplyByFraction, bnToHex } from '../../lib/util';
|
|
|
|
/**
|
|
* 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 hexadecimal
|
|
* @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);
|
|
} 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 = cloneDeep(txMeta.txParams);
|
|
|
|
// `eth_estimateGas` can fail if the user has insufficient balance for the
|
|
// value being sent, or for the gas cost. We don't want to check their
|
|
// balance here, we just want the gas estimate. The gas price is removed
|
|
// to skip those balance checks. We check balance elsewhere. We also delete
|
|
// maxFeePerGas and maxPriorityFeePerGas to support EIP-1559 txs.
|
|
delete txParams.gasPrice;
|
|
delete txParams.maxFeePerGas;
|
|
delete txParams.maxPriorityFeePerGas;
|
|
|
|
// 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
|
|
* @param multiplier
|
|
* @returns {string} the buffered gas limit as a hex string
|
|
*/
|
|
addGasBuffer(initialGasLimitHex, blockGasLimitHex, multiplier = 1.5) {
|
|
const initialGasLimitBn = hexToBn(initialGasLimitHex);
|
|
const blockGasLimitBn = hexToBn(blockGasLimitHex);
|
|
const upperGasLimitBn = blockGasLimitBn.muln(0.9);
|
|
const bufferedGasLimitBn = initialGasLimitBn.muln(multiplier);
|
|
|
|
// 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);
|
|
}
|
|
|
|
async getBufferedGasLimit(txMeta, multiplier) {
|
|
const {
|
|
blockGasLimit,
|
|
estimatedGasHex,
|
|
simulationFails,
|
|
} = await this.analyzeGasUsage(txMeta);
|
|
|
|
// add additional gas buffer to our estimation for safety
|
|
const gasLimit = this.addGasBuffer(
|
|
addHexPrefix(estimatedGasHex),
|
|
blockGasLimit,
|
|
multiplier,
|
|
);
|
|
return { gasLimit, simulationFails };
|
|
}
|
|
}
|