mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-23 09:52:26 +01:00
update speedup and cancel to make room for EIP-1559 (#11407)
* prepare for EIP1559 gas fields in speedup/cancel * Update ui/components/app/gas-customization/gas-modal-page-container/gas-modal-page-container.container.js
This commit is contained in:
parent
0ca0f1784e
commit
64adfe7b11
@ -50,6 +50,16 @@ export const TRANSACTION_EVENTS = {
|
||||
SUBMITTED: 'Transaction Submitted',
|
||||
};
|
||||
|
||||
/**
|
||||
* @typedef {Object} CustomGasSettings
|
||||
* @property {string} [gas] - The gas limit to use for the transaction
|
||||
* @property {string} [gasPrice] - The gasPrice to use for a legacy transaction
|
||||
* @property {string} [maxFeePerGas] - The maximum amount to pay per gas on a
|
||||
* EIP-1559 transaction
|
||||
* @property {string} [maxPriorityFeePerGas] - The maximum amount of paid fee
|
||||
* to be distributed to miner in an EIP-1559 transaction
|
||||
*/
|
||||
|
||||
/**
|
||||
Transaction Controller is an aggregate of sub-controllers and trackers
|
||||
composing them in a way to be exposed to the metamask controller
|
||||
@ -468,32 +478,105 @@ export default class TransactionController extends EventEmitter {
|
||||
return { gasLimit, simulationFails };
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a TransactionMeta object, generate new gas params such that if the
|
||||
* transaction was an EIP1559 transaction, it only has EIP1559 gas fields,
|
||||
* otherwise it only has gasPrice. Will use whatever custom values are
|
||||
* specified in customGasSettings, or falls back to incrementing by a percent
|
||||
* which is defined by specifying a numerator. 11 is a 10% bump, 12 would be
|
||||
* a 20% bump, and so on.
|
||||
* @param {import(
|
||||
* '../../../../shared/constants/transaction'
|
||||
* ).TransactionMeta} originalTxMeta - Original transaction to use as base
|
||||
* @param {CustomGasSettings} [customGasSettings] - overrides for the gas
|
||||
* fields to use instead of the multiplier
|
||||
* @param {number} [incrementNumerator] - Numerator from which to generate a
|
||||
* percentage bump of gas price. E.g 11 would be a 10% bump over base.
|
||||
* @returns {{ newGasParams: CustomGasSettings, previousGasParams: CustomGasSettings }}
|
||||
*/
|
||||
generateNewGasParams(
|
||||
originalTxMeta,
|
||||
customGasSettings = {},
|
||||
incrementNumerator = 11,
|
||||
) {
|
||||
const { txParams } = originalTxMeta;
|
||||
const previousGasParams = {};
|
||||
const newGasParams = {};
|
||||
if (customGasSettings.gasLimit) {
|
||||
newGasParams.gas = customGasSettings?.gas ?? GAS_LIMITS.SIMPLE;
|
||||
}
|
||||
|
||||
if (isEIP1559Transaction(originalTxMeta)) {
|
||||
previousGasParams.maxFeePerGas = txParams.maxFeePerGas;
|
||||
previousGasParams.maxPriorityFeePerGas = txParams.maxPriorityFeePerGas;
|
||||
newGasParams.maxFeePerGas =
|
||||
customGasSettings?.maxFeePerGas ||
|
||||
bnToHex(
|
||||
BnMultiplyByFraction(
|
||||
hexToBn(txParams.maxFeePerGas),
|
||||
incrementNumerator,
|
||||
10,
|
||||
),
|
||||
);
|
||||
newGasParams.maxPriorityFeePerGas =
|
||||
customGasSettings?.maxPriorityFeePerGas ||
|
||||
bnToHex(
|
||||
BnMultiplyByFraction(
|
||||
hexToBn(txParams.maxPriorityFeePerGas),
|
||||
incrementNumerator,
|
||||
10,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
previousGasParams.gasPrice = txParams.gasPrice;
|
||||
newGasParams.gasPrice =
|
||||
customGasSettings?.gasPrice ||
|
||||
bnToHex(
|
||||
BnMultiplyByFraction(
|
||||
hexToBn(txParams.gasPrice),
|
||||
incrementNumerator,
|
||||
10,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return { previousGasParams, newGasParams };
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new approved transaction to attempt to cancel a previously submitted transaction. The
|
||||
* new transaction contains the same nonce as the previous, is a basic ETH transfer of 0x value to
|
||||
* the sender's address, and has a higher gasPrice than that of the previous transaction.
|
||||
* @param {number} originalTxId - the id of the txMeta that you want to attempt to cancel
|
||||
* @param {string} [customGasPrice] - the hex value to use for the cancel transaction
|
||||
* @param {CustomGasSettings} [customGasSettings] - overrides to use for gas
|
||||
* params instead of allowing this method to generate them
|
||||
* @returns {txMeta}
|
||||
*/
|
||||
async createCancelTransaction(originalTxId, customGasPrice, customGasLimit) {
|
||||
async createCancelTransaction(originalTxId, customGasSettings) {
|
||||
const originalTxMeta = this.txStateManager.getTransaction(originalTxId);
|
||||
const { txParams } = originalTxMeta;
|
||||
const { gasPrice: lastGasPrice, from, nonce } = txParams;
|
||||
const { from, nonce } = txParams;
|
||||
|
||||
const { previousGasParams, newGasParams } = this.generateNewGasParams(
|
||||
originalTxMeta,
|
||||
{
|
||||
...customGasSettings,
|
||||
// We want to override the previous transactions gasLimit because it
|
||||
// will now be a simple send instead of whatever it was before such
|
||||
// as a token transfer or contract call.
|
||||
gasLimit: customGasSettings.gasLimit || GAS_LIMITS.SIMPLE,
|
||||
},
|
||||
);
|
||||
|
||||
const newGasPrice =
|
||||
customGasPrice ||
|
||||
bnToHex(BnMultiplyByFraction(hexToBn(lastGasPrice), 11, 10));
|
||||
const newTxMeta = this.txStateManager.generateTxMeta({
|
||||
txParams: {
|
||||
from,
|
||||
to: from,
|
||||
nonce,
|
||||
gas: customGasLimit || GAS_LIMITS.SIMPLE,
|
||||
value: '0x0',
|
||||
gasPrice: newGasPrice,
|
||||
...newGasParams,
|
||||
},
|
||||
lastGasPrice,
|
||||
previousGasParams,
|
||||
loadingDefaults: false,
|
||||
status: TRANSACTION_STATUSES.APPROVED,
|
||||
type: TRANSACTION_TYPES.CANCEL,
|
||||
@ -510,34 +593,30 @@ export default class TransactionController extends EventEmitter {
|
||||
* the same gas limit and a 10% higher gas price, though it is possible to set a custom value for
|
||||
* each instead.
|
||||
* @param {number} originalTxId - the id of the txMeta that you want to speed up
|
||||
* @param {string} [customGasPrice] - The new custom gas price, in hex
|
||||
* @param {string} [customGasLimit] - The new custom gas limt, in hex
|
||||
* @param {CustomGasSettings} [customGasSettings] - overrides to use for gas
|
||||
* params instead of allowing this method to generate them
|
||||
* @returns {txMeta}
|
||||
*/
|
||||
async createSpeedUpTransaction(originalTxId, customGasPrice, customGasLimit) {
|
||||
async createSpeedUpTransaction(originalTxId, customGasSettings) {
|
||||
const originalTxMeta = this.txStateManager.getTransaction(originalTxId);
|
||||
const { txParams } = originalTxMeta;
|
||||
const { gasPrice: lastGasPrice } = txParams;
|
||||
|
||||
const newGasPrice =
|
||||
customGasPrice ||
|
||||
bnToHex(BnMultiplyByFraction(hexToBn(lastGasPrice), 11, 10));
|
||||
const { previousGasParams, newGasParams } = this.generateNewGasParams(
|
||||
originalTxMeta,
|
||||
customGasSettings,
|
||||
);
|
||||
|
||||
const newTxMeta = this.txStateManager.generateTxMeta({
|
||||
txParams: {
|
||||
...txParams,
|
||||
gasPrice: newGasPrice,
|
||||
...newGasParams,
|
||||
},
|
||||
lastGasPrice,
|
||||
previousGasParams,
|
||||
loadingDefaults: false,
|
||||
status: TRANSACTION_STATUSES.APPROVED,
|
||||
type: TRANSACTION_TYPES.RETRY,
|
||||
});
|
||||
|
||||
if (customGasLimit) {
|
||||
newTxMeta.txParams.gas = customGasLimit;
|
||||
}
|
||||
|
||||
this.addTransaction(newTxMeta);
|
||||
await this.approveTransaction(newTxMeta.id);
|
||||
return newTxMeta;
|
||||
@ -596,9 +675,9 @@ export default class TransactionController extends EventEmitter {
|
||||
customNonceValue = Number(customNonceValue);
|
||||
nonceLock = await this.nonceTracker.getNonceLock(fromAddress);
|
||||
// add nonce to txParams
|
||||
// if txMeta has lastGasPrice then it is a retry at same nonce with higher
|
||||
// gas price transaction and their for the nonce should not be calculated
|
||||
const nonce = txMeta.lastGasPrice
|
||||
// if txMeta has previousGasParams then it is a retry at same nonce with
|
||||
// higher gas settings and therefor the nonce should not be recalculated
|
||||
const nonce = txMeta.previousGasParams
|
||||
? txMeta.txParams.nonce
|
||||
: nonceLock.nextNonce;
|
||||
const customOrNonce =
|
||||
|
@ -739,11 +739,11 @@ describe('Transaction Controller', function () {
|
||||
const addTransactionArgs = addTransactionSpy.getCall(0).args[0];
|
||||
assert.deepEqual(addTransactionArgs.txParams, expectedTxParams);
|
||||
|
||||
const { lastGasPrice, type } = addTransactionArgs;
|
||||
const { previousGasParams, type } = addTransactionArgs;
|
||||
assert.deepEqual(
|
||||
{ lastGasPrice, type },
|
||||
{ gasPrice: previousGasParams.gasPrice, type },
|
||||
{
|
||||
lastGasPrice: '0xa',
|
||||
gasPrice: '0xa',
|
||||
type: TRANSACTION_TYPES.RETRY,
|
||||
},
|
||||
);
|
||||
@ -762,11 +762,11 @@ describe('Transaction Controller', function () {
|
||||
|
||||
assert.deepEqual(result.txParams, expectedTxParams);
|
||||
|
||||
const { lastGasPrice, type } = result;
|
||||
const { previousGasParams, type } = result;
|
||||
assert.deepEqual(
|
||||
{ lastGasPrice, type },
|
||||
{ gasPrice: previousGasParams.gasPrice, type },
|
||||
{
|
||||
lastGasPrice: '0xa',
|
||||
gasPrice: '0xa',
|
||||
type: TRANSACTION_TYPES.RETRY,
|
||||
},
|
||||
);
|
||||
|
@ -1972,27 +1972,40 @@ export default class MetamaskController extends EventEmitter {
|
||||
//=============================================================================
|
||||
|
||||
/**
|
||||
* Allows a user to attempt to cancel a previously submitted transaction by creating a new
|
||||
* transaction.
|
||||
* @param {number} originalTxId - the id of the txMeta that you want to attempt to cancel
|
||||
* @param {string} [customGasPrice] - the hex value to use for the cancel transaction
|
||||
* Allows a user to attempt to cancel a previously submitted transaction
|
||||
* by creating a new transaction.
|
||||
* @param {number} originalTxId - the id of the txMeta that you want to
|
||||
* attempt to cancel
|
||||
* @param {import(
|
||||
* './controllers/transactions'
|
||||
* ).CustomGasSettings} [customGasSettings] - overrides to use for gas params
|
||||
* instead of allowing this method to generate them
|
||||
* @returns {Object} MetaMask state
|
||||
*/
|
||||
async createCancelTransaction(originalTxId, customGasPrice, customGasLimit) {
|
||||
async createCancelTransaction(originalTxId, customGasSettings) {
|
||||
await this.txController.createCancelTransaction(
|
||||
originalTxId,
|
||||
customGasPrice,
|
||||
customGasLimit,
|
||||
customGasSettings,
|
||||
);
|
||||
const state = await this.getState();
|
||||
return state;
|
||||
}
|
||||
|
||||
async createSpeedUpTransaction(originalTxId, customGasPrice, customGasLimit) {
|
||||
/**
|
||||
* Allows a user to attempt to speed up a previously submitted transaction
|
||||
* by creating a new transaction.
|
||||
* @param {number} originalTxId - the id of the txMeta that you want to
|
||||
* attempt to speed up
|
||||
* @param {import(
|
||||
* './controllers/transactions'
|
||||
* ).CustomGasSettings} [customGasSettings] - overrides to use for gas params
|
||||
* instead of allowing this method to generate them
|
||||
* @returns {Object} MetaMask state
|
||||
*/
|
||||
async createSpeedUpTransaction(originalTxId, customGasSettings) {
|
||||
await this.txController.createSpeedUpTransaction(
|
||||
originalTxId,
|
||||
customGasPrice,
|
||||
customGasLimit,
|
||||
customGasSettings,
|
||||
);
|
||||
const state = await this.getState();
|
||||
return state;
|
||||
|
@ -220,11 +220,11 @@ const mapDispatchToProps = (dispatch) => {
|
||||
dispatch(setCustomGasLimit(addHexPrefix(gasLimit.toString(16))));
|
||||
return dispatch(updateTransaction(updatedTx));
|
||||
},
|
||||
createRetryTransaction: (txId, gasPrice, gasLimit) => {
|
||||
return dispatch(createRetryTransaction(txId, gasPrice, gasLimit));
|
||||
createRetryTransaction: (txId, customGasSettings) => {
|
||||
return dispatch(createRetryTransaction(txId, customGasSettings));
|
||||
},
|
||||
createSpeedUpTransaction: (txId, gasPrice, gasLimit) => {
|
||||
return dispatch(createSpeedUpTransaction(txId, gasPrice, gasLimit));
|
||||
createSpeedUpTransaction: (txId, customGasSettings) => {
|
||||
return dispatch(createSpeedUpTransaction(txId, customGasSettings));
|
||||
},
|
||||
hideSidebar: () => dispatch(hideSidebar()),
|
||||
fetchBasicGasEstimates: () => dispatch(fetchBasicGasEstimates()),
|
||||
@ -264,7 +264,7 @@ const mergeProps = (stateProps, dispatchProps, ownProps) => {
|
||||
if (ownProps.onSubmit) {
|
||||
dispatchHideSidebar();
|
||||
dispatchCancelAndClose();
|
||||
ownProps.onSubmit(gasLimit, gasPrice);
|
||||
ownProps.onSubmit({ gasLimit, gasPrice });
|
||||
return;
|
||||
}
|
||||
if (isConfirm) {
|
||||
@ -279,11 +279,11 @@ const mergeProps = (stateProps, dispatchProps, ownProps) => {
|
||||
dispatchUpdateConfirmTxGasAndCalculate(gasLimit, gasPrice, updatedTx);
|
||||
dispatchHideModal();
|
||||
} else if (isSpeedUp) {
|
||||
dispatchCreateSpeedUpTransaction(txId, gasPrice, gasLimit);
|
||||
dispatchCreateSpeedUpTransaction(txId, { gasPrice, gasLimit });
|
||||
dispatchHideSidebar();
|
||||
dispatchCancelAndClose();
|
||||
} else if (isRetry) {
|
||||
dispatchCreateRetryTransaction(txId, gasPrice, gasLimit);
|
||||
dispatchCreateRetryTransaction(txId, { gasPrice, gasLimit });
|
||||
dispatchHideSidebar();
|
||||
dispatchCancelAndClose();
|
||||
} else {
|
||||
|
@ -10,8 +10,7 @@ const mapStateToProps = (state, ownProps) => {
|
||||
transactionId,
|
||||
originalGasPrice,
|
||||
newGasFee,
|
||||
defaultNewGasPrice,
|
||||
gasLimit,
|
||||
customGasSettings,
|
||||
} = ownProps;
|
||||
const { currentNetworkTxList } = metamask;
|
||||
const transaction = currentNetworkTxList.find(
|
||||
@ -23,18 +22,15 @@ const mapStateToProps = (state, ownProps) => {
|
||||
transactionId,
|
||||
transactionStatus,
|
||||
originalGasPrice,
|
||||
defaultNewGasPrice,
|
||||
customGasSettings,
|
||||
newGasFee,
|
||||
gasLimit,
|
||||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
createCancelTransaction: (txId, customGasPrice, customGasLimit) => {
|
||||
return dispatch(
|
||||
createCancelTransaction(txId, customGasPrice, customGasLimit),
|
||||
);
|
||||
createCancelTransaction: (txId, customGasSettings) => {
|
||||
return dispatch(createCancelTransaction(txId, customGasSettings));
|
||||
},
|
||||
showTransactionConfirmedModal: () =>
|
||||
dispatch(showModal({ name: 'TRANSACTION_CONFIRMED' })),
|
||||
@ -42,12 +38,7 @@ const mapDispatchToProps = (dispatch) => {
|
||||
};
|
||||
|
||||
const mergeProps = (stateProps, dispatchProps, ownProps) => {
|
||||
const {
|
||||
transactionId,
|
||||
defaultNewGasPrice,
|
||||
gasLimit,
|
||||
...restStateProps
|
||||
} = stateProps;
|
||||
const { transactionId, customGasSettings, ...restStateProps } = stateProps;
|
||||
// eslint-disable-next-line no-shadow
|
||||
const { createCancelTransaction, ...restDispatchProps } = dispatchProps;
|
||||
|
||||
@ -56,7 +47,7 @@ const mergeProps = (stateProps, dispatchProps, ownProps) => {
|
||||
...restDispatchProps,
|
||||
...ownProps,
|
||||
createCancelTransaction: () =>
|
||||
createCancelTransaction(transactionId, defaultNewGasPrice, gasLimit),
|
||||
createCancelTransaction(transactionId, customGasSettings),
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -1,12 +1,7 @@
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { useCallback } from 'react';
|
||||
import { addHexPrefix } from 'ethereumjs-util';
|
||||
import { showModal, showSidebar } from '../store/actions';
|
||||
import { isBalanceSufficient } from '../pages/send/send.utils';
|
||||
import {
|
||||
getHexGasTotal,
|
||||
increaseLastGasPrice,
|
||||
} from '../helpers/utils/confirm-tx.util';
|
||||
import { getSelectedAccount, getIsMainnet } from '../selectors';
|
||||
import { getConversionRate } from '../ducks/metamask/metamask';
|
||||
|
||||
@ -14,8 +9,10 @@ import {
|
||||
setCustomGasLimit,
|
||||
setCustomGasPriceForRetry,
|
||||
} from '../ducks/gas/gas.duck';
|
||||
import { multiplyCurrencies } from '../../shared/modules/conversion.utils';
|
||||
import { GAS_LIMITS } from '../../shared/constants/gas';
|
||||
import { isLegacyTransaction } from '../../shared/modules/transaction.utils';
|
||||
import { getMaximumGasTotalInHexWei } from '../../shared/modules/gas.utils';
|
||||
import { useIncrementedGasFees } from './useIncrementedGasFees';
|
||||
|
||||
/**
|
||||
* Determine whether a transaction can be cancelled and provide a method to
|
||||
@ -30,33 +27,27 @@ import { GAS_LIMITS } from '../../shared/constants/gas';
|
||||
export function useCancelTransaction(transactionGroup) {
|
||||
const { primaryTransaction } = transactionGroup;
|
||||
|
||||
const transactionGasPrice = primaryTransaction.txParams?.gasPrice;
|
||||
const gasPrice =
|
||||
transactionGasPrice === undefined || transactionGasPrice?.startsWith('-')
|
||||
? '0x0'
|
||||
: primaryTransaction.txParams?.gasPrice;
|
||||
const transaction = primaryTransaction;
|
||||
const customGasSettings = useIncrementedGasFees(transactionGroup);
|
||||
|
||||
const dispatch = useDispatch();
|
||||
const selectedAccount = useSelector(getSelectedAccount);
|
||||
const conversionRate = useSelector(getConversionRate);
|
||||
const defaultNewGasPrice = addHexPrefix(
|
||||
multiplyCurrencies(gasPrice, 1.1, {
|
||||
toNumericBase: 'hex',
|
||||
multiplicandBase: 16,
|
||||
multiplierBase: 10,
|
||||
}),
|
||||
);
|
||||
const isMainnet = useSelector(getIsMainnet);
|
||||
const hideBasic = !(isMainnet || process.env.IN_TEST);
|
||||
const cancelTransaction = useCallback(
|
||||
(event) => {
|
||||
event.stopPropagation();
|
||||
dispatch(setCustomGasLimit(GAS_LIMITS.SIMPLE));
|
||||
dispatch(setCustomGasPriceForRetry(defaultNewGasPrice));
|
||||
if (isLegacyTransaction(primaryTransaction)) {
|
||||
// To support the current process of cancelling or speeding up
|
||||
// a transaction, we have to inform the custom gas state of the new
|
||||
// gasPrice/gasLimit to start at.
|
||||
dispatch(setCustomGasPriceForRetry(customGasSettings.gasPrice));
|
||||
dispatch(setCustomGasLimit(GAS_LIMITS.SIMPLE));
|
||||
}
|
||||
const tx = {
|
||||
...transaction,
|
||||
...primaryTransaction,
|
||||
txParams: {
|
||||
...transaction.txParams,
|
||||
...primaryTransaction.txParams,
|
||||
gas: GAS_LIMITS.SIMPLE,
|
||||
value: '0x0',
|
||||
},
|
||||
@ -68,18 +59,16 @@ export function useCancelTransaction(transactionGroup) {
|
||||
props: {
|
||||
hideBasic,
|
||||
transaction: tx,
|
||||
onSubmit: (newGasLimit, newGasPrice) => {
|
||||
const userCustomizedGasTotal = getHexGasTotal({
|
||||
gasPrice: newGasPrice,
|
||||
gasLimit: newGasLimit,
|
||||
});
|
||||
onSubmit: (newGasSettings) => {
|
||||
const userCustomizedGasTotal = getMaximumGasTotalInHexWei(
|
||||
newGasSettings,
|
||||
);
|
||||
dispatch(
|
||||
showModal({
|
||||
name: 'CANCEL_TRANSACTION',
|
||||
newGasFee: userCustomizedGasTotal,
|
||||
transactionId: transaction.id,
|
||||
defaultNewGasPrice: newGasPrice,
|
||||
gasLimit: newGasLimit,
|
||||
transactionId: primaryTransaction.id,
|
||||
customGasSettings: newGasSettings,
|
||||
}),
|
||||
);
|
||||
},
|
||||
@ -87,17 +76,14 @@ export function useCancelTransaction(transactionGroup) {
|
||||
}),
|
||||
);
|
||||
},
|
||||
[dispatch, transaction, defaultNewGasPrice, hideBasic],
|
||||
[dispatch, primaryTransaction, customGasSettings, hideBasic],
|
||||
);
|
||||
|
||||
const hasEnoughCancelGas =
|
||||
primaryTransaction.txParams &&
|
||||
isBalanceSufficient({
|
||||
amount: '0x0',
|
||||
gasTotal: getHexGasTotal({
|
||||
gasPrice: increaseLastGasPrice(gasPrice),
|
||||
gasLimit: primaryTransaction.txParams.gas,
|
||||
}),
|
||||
gasTotal: getMaximumGasTotalInHexWei(customGasSettings),
|
||||
balance: selectedAccount.balance,
|
||||
conversionRate,
|
||||
});
|
||||
|
@ -77,10 +77,10 @@ describe('useCancelTransaction', function () {
|
||||
).toStrictEqual(transactionId);
|
||||
|
||||
// call onSubmit myself
|
||||
dispatchAction[dispatchAction.length - 1][0].value.props.onSubmit(
|
||||
GAS_LIMITS.SIMPLE,
|
||||
'0x1',
|
||||
);
|
||||
dispatchAction[dispatchAction.length - 1][0].value.props.onSubmit({
|
||||
gasLimit: GAS_LIMITS.SIMPLE,
|
||||
gasPrice: '0x1',
|
||||
});
|
||||
|
||||
expect(
|
||||
dispatch.calledWith(
|
||||
@ -88,8 +88,10 @@ describe('useCancelTransaction', function () {
|
||||
name: 'CANCEL_TRANSACTION',
|
||||
transactionId,
|
||||
newGasFee: GAS_LIMITS.SIMPLE,
|
||||
defaultNewGasPrice: '0x1',
|
||||
gasLimit: GAS_LIMITS.SIMPLE,
|
||||
customGasSettings: {
|
||||
gasPrice: '0x1',
|
||||
gasLimit: GAS_LIMITS.SIMPLE,
|
||||
},
|
||||
}),
|
||||
),
|
||||
).toStrictEqual(true);
|
||||
@ -147,10 +149,10 @@ describe('useCancelTransaction', function () {
|
||||
.id,
|
||||
).toStrictEqual(transactionId);
|
||||
|
||||
dispatchAction[dispatchAction.length - 1][0].value.props.onSubmit(
|
||||
GAS_LIMITS.SIMPLE,
|
||||
'0x1',
|
||||
);
|
||||
dispatchAction[dispatchAction.length - 1][0].value.props.onSubmit({
|
||||
gasLimit: GAS_LIMITS.SIMPLE,
|
||||
gasPrice: '0x1',
|
||||
});
|
||||
|
||||
expect(
|
||||
dispatch.calledWith(
|
||||
@ -158,8 +160,10 @@ describe('useCancelTransaction', function () {
|
||||
name: 'CANCEL_TRANSACTION',
|
||||
transactionId,
|
||||
newGasFee: GAS_LIMITS.SIMPLE,
|
||||
defaultNewGasPrice: '0x1',
|
||||
gasLimit: GAS_LIMITS.SIMPLE,
|
||||
customGasSettings: {
|
||||
gasPrice: '0x1',
|
||||
gasLimit: GAS_LIMITS.SIMPLE,
|
||||
},
|
||||
}),
|
||||
),
|
||||
).toStrictEqual(true);
|
||||
|
73
ui/hooks/useIncrementedGasFees.js
Normal file
73
ui/hooks/useIncrementedGasFees.js
Normal file
@ -0,0 +1,73 @@
|
||||
import { addHexPrefix } from 'ethereumjs-util';
|
||||
import { useMemo } from 'react';
|
||||
import { multiplyCurrencies } from '../../shared/modules/conversion.utils';
|
||||
import { isEIP1559Transaction } from '../../shared/modules/transaction.utils';
|
||||
|
||||
/**
|
||||
* Simple helper to save on duplication to multiply the supplied wei hex string
|
||||
* by 1.10 to get bare minimum new gas fee.
|
||||
*
|
||||
* @param {string} hexStringValue - hex value in wei to be incremented
|
||||
* @returns {string} - hex value in WEI 10% higher than the param.
|
||||
*/
|
||||
function addTenPercent(hexStringValue) {
|
||||
return addHexPrefix(
|
||||
multiplyCurrencies(hexStringValue, 1.1, {
|
||||
toNumericBase: 'hex',
|
||||
multiplicandBase: 16,
|
||||
multiplierBase: 10,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* When initializing cancellations or speed ups we need to set the baseline
|
||||
* gas fees to be 10% higher, which is the bare minimum that the network will
|
||||
* accept for transactions of the same nonce. Anything lower than this will be
|
||||
* discarded by the network to avoid DoS attacks. This hook returns an object
|
||||
* that either has gasPrice or maxFeePerGas/maxPriorityFeePerGas specified. In
|
||||
* addition the gasLimit will also be included.
|
||||
* @param {} transactionGroup
|
||||
* @returns {import(
|
||||
* '../../app/scripts/controllers/transactions'
|
||||
* ).CustomGasSettings} - Gas settings for cancellations/speed ups
|
||||
*/
|
||||
export function useIncrementedGasFees(transactionGroup) {
|
||||
const { primaryTransaction } = transactionGroup;
|
||||
|
||||
// We memoize this value so that it can be relied upon in other hooks.
|
||||
const customGasSettings = useMemo(() => {
|
||||
// This hook is called indiscriminantly on all transactions appearing in
|
||||
// the activity list. This includes transitional items such as signature
|
||||
// requests. These types of "transactions" are not really transactions and
|
||||
// do not have txParams. This is why we use optional chaining on the
|
||||
// txParams object in this hook.
|
||||
const temporaryGasSettings = {
|
||||
gasLimit: primaryTransaction.txParams?.gas,
|
||||
};
|
||||
if (isEIP1559Transaction(primaryTransaction)) {
|
||||
const transactionMaxFeePerGas = primaryTransaction.txParams?.maxFeePerGas;
|
||||
const transactionMaxPriorityFeePerGas =
|
||||
primaryTransaction.txParams?.maxPriorityFeePerGas;
|
||||
temporaryGasSettings.maxFeePerGas =
|
||||
transactionMaxFeePerGas === undefined ||
|
||||
transactionMaxFeePerGas.startsWith('-')
|
||||
? '0x0'
|
||||
: addTenPercent(transactionMaxFeePerGas);
|
||||
temporaryGasSettings.maxPriorityFeePerGas =
|
||||
transactionMaxPriorityFeePerGas === undefined ||
|
||||
transactionMaxPriorityFeePerGas.startsWith('-')
|
||||
? '0x0'
|
||||
: addTenPercent(transactionMaxPriorityFeePerGas);
|
||||
} else {
|
||||
const transactionGasPrice = primaryTransaction.txParams?.gasPrice;
|
||||
temporaryGasSettings.gasPrice =
|
||||
transactionGasPrice === undefined || transactionGasPrice.startsWith('-')
|
||||
? '0x0'
|
||||
: addTenPercent(transactionGasPrice);
|
||||
}
|
||||
return temporaryGasSettings;
|
||||
}, [primaryTransaction]);
|
||||
|
||||
return customGasSettings;
|
||||
}
|
@ -7,9 +7,10 @@ import {
|
||||
setCustomGasPriceForRetry,
|
||||
setCustomGasLimit,
|
||||
} from '../ducks/gas/gas.duck';
|
||||
import { increaseLastGasPrice } from '../helpers/utils/confirm-tx.util';
|
||||
import { getIsMainnet } from '../selectors';
|
||||
import { isLegacyTransaction } from '../../shared/modules/transaction.utils';
|
||||
import { useMetricEvent } from './useMetricEvent';
|
||||
import { useIncrementedGasFees } from './useIncrementedGasFees';
|
||||
/**
|
||||
* Provides a reusable hook that, given a transactionGroup, will return
|
||||
* a method for beginning the retry process
|
||||
@ -20,8 +21,7 @@ export function useRetryTransaction(transactionGroup) {
|
||||
const { primaryTransaction } = transactionGroup;
|
||||
const isMainnet = useSelector(getIsMainnet);
|
||||
const hideBasic = !(isMainnet || process.env.IN_TEST);
|
||||
// Signature requests do not have a txParams, but this hook is called indiscriminately
|
||||
const gasPrice = primaryTransaction.txParams?.gasPrice;
|
||||
const customGasSettings = useIncrementedGasFees(transactionGroup);
|
||||
const trackMetricsEvent = useMetricEvent({
|
||||
eventOpts: {
|
||||
category: 'Navigation',
|
||||
@ -36,24 +36,32 @@ export function useRetryTransaction(transactionGroup) {
|
||||
event.stopPropagation();
|
||||
|
||||
trackMetricsEvent();
|
||||
await dispatch(fetchBasicGasEstimates);
|
||||
const transaction = primaryTransaction;
|
||||
const increasedGasPrice = increaseLastGasPrice(gasPrice);
|
||||
await dispatch(
|
||||
setCustomGasPriceForRetry(
|
||||
increasedGasPrice || transaction.txParams.gasPrice,
|
||||
),
|
||||
);
|
||||
dispatch(setCustomGasLimit(transaction.txParams.gas));
|
||||
if (process.env.SHOW_EIP_1559_UI === true) {
|
||||
await dispatch(fetchBasicGasEstimates);
|
||||
}
|
||||
if (isLegacyTransaction(primaryTransaction)) {
|
||||
// To support the current process of cancelling or speeding up
|
||||
// a transaction, we have to inform the custom gas state of the new
|
||||
// gasPrice to start at.
|
||||
dispatch(setCustomGasPriceForRetry(customGasSettings.gasPrice));
|
||||
dispatch(setCustomGasLimit(primaryTransaction.txParams.gas));
|
||||
}
|
||||
|
||||
dispatch(
|
||||
showSidebar({
|
||||
transitionName: 'sidebar-left',
|
||||
type: 'customize-gas',
|
||||
props: { transaction, hideBasic },
|
||||
props: { transaction: primaryTransaction, hideBasic },
|
||||
}),
|
||||
);
|
||||
},
|
||||
[dispatch, trackMetricsEvent, gasPrice, primaryTransaction, hideBasic],
|
||||
[
|
||||
dispatch,
|
||||
trackMetricsEvent,
|
||||
customGasSettings,
|
||||
primaryTransaction,
|
||||
hideBasic,
|
||||
],
|
||||
);
|
||||
|
||||
return retryTransaction;
|
||||
|
@ -1324,7 +1324,7 @@ export function clearPendingTokens() {
|
||||
};
|
||||
}
|
||||
|
||||
export function createCancelTransaction(txId, customGasPrice, customGasLimit) {
|
||||
export function createCancelTransaction(txId, customGasSettings) {
|
||||
log.debug('background.cancelTransaction');
|
||||
let newTxId;
|
||||
|
||||
@ -1332,8 +1332,7 @@ export function createCancelTransaction(txId, customGasPrice, customGasLimit) {
|
||||
return new Promise((resolve, reject) => {
|
||||
background.createCancelTransaction(
|
||||
txId,
|
||||
customGasPrice,
|
||||
customGasLimit,
|
||||
customGasSettings,
|
||||
(err, newState) => {
|
||||
if (err) {
|
||||
dispatch(displayWarning(err.message));
|
||||
@ -1353,7 +1352,7 @@ export function createCancelTransaction(txId, customGasPrice, customGasLimit) {
|
||||
};
|
||||
}
|
||||
|
||||
export function createSpeedUpTransaction(txId, customGasPrice, customGasLimit) {
|
||||
export function createSpeedUpTransaction(txId, customGasSettings) {
|
||||
log.debug('background.createSpeedUpTransaction');
|
||||
let newTx;
|
||||
|
||||
@ -1361,8 +1360,7 @@ export function createSpeedUpTransaction(txId, customGasPrice, customGasLimit) {
|
||||
return new Promise((resolve, reject) => {
|
||||
background.createSpeedUpTransaction(
|
||||
txId,
|
||||
customGasPrice,
|
||||
customGasLimit,
|
||||
customGasSettings,
|
||||
(err, newState) => {
|
||||
if (err) {
|
||||
dispatch(displayWarning(err.message));
|
||||
@ -1381,16 +1379,14 @@ export function createSpeedUpTransaction(txId, customGasPrice, customGasLimit) {
|
||||
};
|
||||
}
|
||||
|
||||
export function createRetryTransaction(txId, customGasPrice, customGasLimit) {
|
||||
log.debug('background.createRetryTransaction');
|
||||
export function createRetryTransaction(txId, customGasSettings) {
|
||||
let newTx;
|
||||
|
||||
return (dispatch) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
background.createSpeedUpTransaction(
|
||||
txId,
|
||||
customGasPrice,
|
||||
customGasLimit,
|
||||
customGasSettings,
|
||||
(err, newState) => {
|
||||
if (err) {
|
||||
dispatch(displayWarning(err.message));
|
||||
|
Loading…
Reference in New Issue
Block a user