Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update addTxGasDefaults and _getDefaultGasFees to work with new estimate types, and ensure we correctly handle gas price estimates when on EIP1559 networks #11615

Merged
merged 7 commits into from
Jul 29, 2021
Merged
128 changes: 120 additions & 8 deletions app/scripts/controllers/transactions/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,11 @@ import {
TRANSACTION_ENVELOPE_TYPES,
} from '../../../../shared/constants/transaction';
import { METAMASK_CONTROLLER_EVENTS } from '../../metamask-controller';
import { GAS_LIMITS } from '../../../../shared/constants/gas';
import {
GAS_LIMITS,
GAS_ESTIMATE_TYPES,
} from '../../../../shared/constants/gas';
import { decGWEIToHexWEI } from '../../../../shared/modules/conversion.utils';
import {
HARDFORKS,
MAINNET,
Expand Down Expand Up @@ -107,6 +111,7 @@ export default class TransactionController extends EventEmitter {
this.inProcessOfSigning = new Set();
this._trackMetaMetricsEvent = opts.trackMetaMetricsEvent;
this._getParticipateInMetrics = opts.getParticipateInMetrics;
this._getEIP1559GasFeeEstimates = opts.getEIP1559GasFeeEstimates;

this.memStore = new ObservableStore({});
this.query = new EthQuery(this.provider);
Expand Down Expand Up @@ -400,7 +405,13 @@ export default class TransactionController extends EventEmitter {
* @returns {Promise<object>} resolves with txMeta
*/
async addTxGasDefaults(txMeta, getCodeResponse) {
const defaultGasPrice = await this._getDefaultGasPrice(txMeta);
const eip1559Compatibility = await this.getEIP1559Compatibility();

const {
gasPrice: defaultGasPrice,
maxFeePerGas: defaultMaxFeePerGas,
maxPriorityFeePerGas: defaultMaxPriorityFeePerGas,
} = await this._getDefaultGasFees(txMeta, eip1559Compatibility);
const {
gasLimit: defaultGasLimit,
simulationFails,
Expand All @@ -411,6 +422,67 @@ export default class TransactionController extends EventEmitter {
if (simulationFails) {
txMeta.simulationFails = simulationFails;
}

if (eip1559Compatibility) {
// If the dapp has suggested a gas price, but no maxFeePerGas or maxPriorityFeePerGas
// then we set maxFeePerGas and maxPriorityFeePerGas to the suggested gasPrice.
if (
txMeta.txParams.gasPrice &&
!txMeta.txParams.maxFeePerGas &&
!txMeta.txParams.maxPriorityFeePerGas
) {
txMeta.txParams.maxFeePerGas = txMeta.txParams.gasPrice;
txMeta.txParams.maxPriorityFeePerGas = txMeta.txParams.gasPrice;
} else {
if (defaultMaxFeePerGas && !txMeta.txParams.maxFeePerGas) {
// If the dapp has not set the gasPrice or the maxFeePerGas, then we set maxFeePerGas
// with the one returned by the gasFeeController, if that is available.
txMeta.txParams.maxFeePerGas = defaultMaxFeePerGas;
}

if (
defaultMaxPriorityFeePerGas &&
!txMeta.txParams.maxPriorityFeePerGas
) {
// If the dapp has not set the gasPrice or the maxPriorityFeePerGas, then we set maxPriorityFeePerGas
// with the one returned by the gasFeeController, if that is available.
txMeta.txParams.maxPriorityFeePerGas = defaultMaxPriorityFeePerGas;
}

if (defaultGasPrice && !txMeta.txParams.maxFeePerGas) {
// If the dapp has not set the gasPrice or the maxFeePerGas, and no maxFeePerGas is available
// from the gasFeeController, then we set maxFeePerGas to the defaultGasPrice, assuming it is
// available.
txMeta.txParams.maxFeePerGas = defaultGasPrice;
}

if (
txMeta.txParams.maxFeePerGas &&
!txMeta.txParams.maxPriorityFeePerGas
) {
// If the dapp has not set the gasPrice or the maxPriorityFeePerGas, and no maxPriorityFeePerGas is
// available from the gasFeeController, then we set maxPriorityFeePerGas to
// txMeta.txParams.maxFeePerGas, which will either be the gasPrice from the controller, the maxFeePerGas
// set by the dapp, or the maxFeePerGas from the controller.
txMeta.txParams.maxPriorityFeePerGas = txMeta.txParams.maxFeePerGas;
}
}

// We remove the gasPrice param entirely when on an eip1559 compatible network

delete txMeta.txParams.gasPrice;
} else {
// We ensure that maxFeePerGas and maxPriorityFeePerGas are not in the transaction params
// when not on a EIP1559 compatible network

delete txMeta.txParams.maxPriorityFeePerGas;
delete txMeta.txParams.maxFeePerGas;
}

// If we have gotten to this point, and none of gasPrice, maxPriorityFeePerGas or maxFeePerGas are
// set on txParams, it means that either we are on a non-EIP1559 network and the dapp didn't suggest
// a gas price, or we are on an EIP1559 network, and none of gasPrice, maxPriorityFeePerGas or maxFeePerGas
// were available from either the dapp or the network.
if (
defaultGasPrice &&
!txMeta.txParams.gasPrice &&
Expand All @@ -419,27 +491,67 @@ export default class TransactionController extends EventEmitter {
) {
txMeta.txParams.gasPrice = defaultGasPrice;
}

if (defaultGasLimit && !txMeta.txParams.gas) {
txMeta.txParams.gas = defaultGasLimit;
}
return txMeta;
}

/**
* Gets default gas price, or returns `undefined` if gas price is already set
* Gets default gas fees, or returns `undefined` if gas fees are already set
* @param {Object} txMeta - The txMeta object
* @returns {Promise<string|undefined>} The default gas price
*/
async _getDefaultGasPrice(txMeta) {
async _getDefaultGasFees(txMeta, eip1559Compatibility) {
if (
txMeta.txParams.gasPrice ||
(!eip1559Compatibility && txMeta.txParams.gasPrice) ||
(txMeta.txParams.maxFeePerGas && txMeta.txParams.maxPriorityFeePerGas)
) {
return undefined;
return {};
}

try {
const {
gasFeeEstimates,
gasEstimateType,
} = await this._getEIP1559GasFeeEstimates();
if (
eip1559Compatibility &&
gasEstimateType === GAS_ESTIMATE_TYPES.FEE_MARKET
) {
const {
medium: { suggestedMaxPriorityFeePerGas, suggestedMaxFeePerGas } = {},
} = gasFeeEstimates;

if (suggestedMaxPriorityFeePerGas && suggestedMaxFeePerGas) {
return {
maxFeePerGas: decGWEIToHexWEI(suggestedMaxFeePerGas),
maxPriorityFeePerGas: decGWEIToHexWEI(
suggestedMaxPriorityFeePerGas,
),
};
}
} else if (gasEstimateType === GAS_ESTIMATE_TYPES.LEGACY) {
// The LEGACY type includes low, medium and high estimates of
// gas price values.
return {
gasPrice: decGWEIToHexWEI(gasFeeEstimates.medium),
};
} else if (gasEstimateType === GAS_ESTIMATE_TYPES.ETH_GASPRICE) {
// The ETH_GASPRICE type just includes a single gas price property,
// which we can assume was retrieved from eth_gasPrice
return {
gasPrice: decGWEIToHexWEI(gasFeeEstimates.gasPrice),
};
}
} catch (e) {
console.error(e);
}

const gasPrice = await this.query.gasPrice();

return addHexPrefix(gasPrice.toString(16));
return { gasPrice: gasPrice && addHexPrefix(gasPrice.toString(16)) };
}

/**
Expand Down Expand Up @@ -683,7 +795,7 @@ export default class TransactionController extends EventEmitter {
this.txStateManager.setTxStatusApproved(txId);
// get next nonce
const txMeta = this.txStateManager.getTransaction(txId);
console.log(txMeta);

const fromAddress = txMeta.txParams.from;
// wait for a nonce
let { customNonceValue } = txMeta;
Expand Down
Loading