1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-11-26 20:39:08 +01:00
metamask-extension/ui/hooks/useGasFeeErrors.js

300 lines
7.6 KiB
JavaScript
Raw Normal View History

import { useMemo } from 'react';
import { useSelector } from 'react-redux';
import { GAS_ESTIMATE_TYPES, GAS_LIMITS } from '../../shared/constants/gas';
import {
conversionLessThan,
conversionGreaterThan,
} from '../../shared/modules/conversion.utils';
import {
checkNetworkAndAccountSupports1559,
getSelectedAccount,
} from '../selectors';
import { addHexes } from '../helpers/utils/conversions.util';
import { isLegacyTransaction } from '../helpers/utils/transactions.util';
import {
bnGreaterThan,
bnLessThan,
bnLessThanEqualTo,
} from '../helpers/utils/util';
import { GAS_FORM_ERRORS } from '../helpers/constants/gas';
const HIGH_FEE_WARNING_MULTIPLIER = 1.5;
const validateGasLimit = (gasLimit, minimumGasLimit) => {
const gasLimitTooLow = conversionLessThan(
{ value: gasLimit, fromNumericBase: 'dec' },
{ value: minimumGasLimit || GAS_LIMITS.SIMPLE, fromNumericBase: 'hex' },
);
if (gasLimitTooLow) {
return GAS_FORM_ERRORS.GAS_LIMIT_OUT_OF_BOUNDS;
}
return undefined;
};
const validateMaxPriorityFee = (maxPriorityFeePerGasToUse, supportsEIP1559) => {
if (supportsEIP1559 && bnLessThanEqualTo(maxPriorityFeePerGasToUse, 0)) {
return GAS_FORM_ERRORS.MAX_PRIORITY_FEE_BELOW_MINIMUM;
}
return undefined;
};
const validateMaxFee = (
maxFeePerGasToUse,
maxPriorityFeeError,
maxPriorityFeePerGasToUse,
supportsEIP1559,
) => {
if (maxPriorityFeeError) {
return undefined;
}
if (
supportsEIP1559 &&
bnGreaterThan(maxPriorityFeePerGasToUse, maxFeePerGasToUse)
) {
return GAS_FORM_ERRORS.MAX_FEE_IMBALANCE;
}
return undefined;
};
const validateGasPrice = (
isFeeMarketGasEstimate,
gasPriceToUse,
supportsEIP1559,
transaction,
) => {
if (
(!supportsEIP1559 || transaction?.txParams?.gasPrice) &&
!isFeeMarketGasEstimate &&
bnLessThanEqualTo(gasPriceToUse, 0)
) {
return GAS_FORM_ERRORS.GAS_PRICE_TOO_LOW;
}
return undefined;
};
const getMaxPriorityFeeWarning = (
gasFeeEstimates,
isFeeMarketGasEstimate,
isGasEstimatesLoading,
maxPriorityFeePerGasToUse,
supportsEIP1559,
) => {
if (!supportsEIP1559 || !isFeeMarketGasEstimate || isGasEstimatesLoading) {
return undefined;
}
if (
bnLessThan(
maxPriorityFeePerGasToUse,
gasFeeEstimates?.low?.suggestedMaxPriorityFeePerGas,
)
) {
return GAS_FORM_ERRORS.MAX_PRIORITY_FEE_TOO_LOW;
}
if (
gasFeeEstimates?.high &&
bnGreaterThan(
maxPriorityFeePerGasToUse,
gasFeeEstimates.high.suggestedMaxPriorityFeePerGas *
HIGH_FEE_WARNING_MULTIPLIER,
)
) {
return GAS_FORM_ERRORS.MAX_PRIORITY_FEE_HIGH_WARNING;
}
return undefined;
};
const getMaxFeeWarning = (
gasFeeEstimates,
isGasEstimatesLoading,
isFeeMarketGasEstimate,
maxFeeError,
maxPriorityFeeError,
maxFeePerGasToUse,
supportsEIP1559,
) => {
if (
maxPriorityFeeError ||
maxFeeError ||
!isFeeMarketGasEstimate ||
!supportsEIP1559
) {
return undefined;
}
if (
!isGasEstimatesLoading &&
bnLessThan(maxFeePerGasToUse, gasFeeEstimates?.low?.suggestedMaxFeePerGas)
) {
return GAS_FORM_ERRORS.MAX_FEE_TOO_LOW;
}
if (
gasFeeEstimates?.high &&
bnGreaterThan(
maxFeePerGasToUse,
gasFeeEstimates.high.suggestedMaxFeePerGas * HIGH_FEE_WARNING_MULTIPLIER,
)
) {
return GAS_FORM_ERRORS.MAX_FEE_HIGH_WARNING;
}
return undefined;
};
const getBalanceError = (minimumCostInHexWei, transaction, ethBalance) => {
const minimumTxCostInHexWei = addHexes(
minimumCostInHexWei,
transaction?.txParams?.value || '0x0',
);
return conversionGreaterThan(
{ value: minimumTxCostInHexWei, fromNumericBase: 'hex' },
{ value: ethBalance, fromNumericBase: 'hex' },
);
};
/**
Version v10.18.4 RC (#15643) * Version v10.18.4 * Fix default currency symbol for `wallet_addEthereumChain` + improve warnings for data that doesn't match our validation expectations (#15201) * set more appropriate default for ticker symbol when wallet_addEthereumChain is called * throw error to dapp when site suggests network with same chainId but different ticker symbol from already added network, instead of showing error and disabled notification to user * Fix Provider Tracking Metrics (#15082) * fix filetype audit (#15334) * Remove decentralized 4byte function signature registry since it contains incorrect signatures and we can't algorithmically check for best option when 4byte.directory is down (#15300) * remove decentralized 4byte function signature registry since it is griefed and we can't algorithmically check for best option when 4byte is down * add migration * remove nock of on chain registry call in getMethodDataAsync test * remove audit exclusion (#15346) * Updates `eth-lattice-keyring` to v0.10.0 (#15261) This is mainly associated with an update in GridPlus SDK and enables better strategies for fetching calldata decoder data. `eth-lattice-keyring` changes: GridPlus/eth-lattice-keyring@v0.7.3...v0.10.0 `gridplus-sdk` changes (which includes a codebase rewrite): GridPlus/gridplus-sdk@v1.2.3...v2.2.2 * Fix 'block link explorer on custom networks' (#13870) * Created a logic for the 'Add a block explorer URL' Removed unused message Message logic rollback Modified history push operation WIP: Pushing before rebasing Applied requested changes Removed unintenionally added code * Lint fix * Metrics fixed * Stop injecting provider on docs.google.com (#15459) * Fix setting of gasPrice when on non-eip 1559 networks (#15628) * Fix setting of gasPrice when on non-eip 1559 networks * Fix unit tests * Fix logic * Update ui/ducks/send/send.test.js Co-authored-by: Mark Stacey <markjstacey@gmail.com> Co-authored-by: Mark Stacey <markjstacey@gmail.com> * [GridPlus] Bumps `eth-lattice-keyring` to v0.11.0 (#15490) * [GridPlus] Bumps `gridplus-sdk` to v2.2.4 (#15561) * remove exclusions for mismatched object jsdoc type casing (#15351) * Improve `tokenId` parsing and clean up `useAssetDetails` hook (#15304) * Fix state creation in setupSentryGetStateGlobal (#15635) * filter breadcrumbs for improved clarity while debugging sentry errors (#15639) * Update v10.18.4 changelog (#15645) * Auto generated changelog * Update 10.18.4 changelog * Run lavamoat:auto * Call metrics event for wallet type selection at the right time (#15591) * Fix Sentry in LavaMoat contexts (#15672) Our Sentry setup relies upon application state, but it wasn't able to access it in LavaMoat builds because it's running in a separate Compartment. A patch has been introduced to the LavaMoat runtime to allow the root Compartment to mutate the `rootGlobals` object, which is accessible from outside the compartment as well. This lets us expose application state to our Sentry integration. * Fix Sentry deduplication of events that were never sent (#15677) The Sentry `Dedupe` integration has been filtering out our events, even when they were never sent due to our `beforeSend` handler. It was wrongly identifying them as duplicates because it has no knowledge of `beforeSend` or whether they were actually sent or not. To resolve this, the filtering we were doing in `beforeSend` has been moved to a Sentry integration. This integration is installed ahead of the `Dedupe` integration, so `Dedupe` should never find out about any events that we filter out, and thus will never consider them as sent when they were not. * Replace `lavamoat-runtime.js` patch (#15682) A patch made in #15672 was found to be unnecessary. Instead of setting a `rootGlobals` object upon construction of the root compartment, we are now creating a `sentryHooks` object in the initial top-level compartment. I hadn't realized at the time that the root compartment would inherit all properties of the initial compartment `globalThis`. This accomplishes the same goals as #15672 except without needing a patch. * Update v10.18.4 changelog * Fix lint issues * Update yarn.lock * Update `depcheck` to latest version (#15690) `depcheck` has been updated to the latest version. This version pins `@babel/parser` to v7.16.4 because of unresolved bugs in v7.16.5 that result in `depcheck` failing to parse TypeScript files correctly. We had a Yarn resolution in place to ensure `@babel/parser@7.16.4` was being used already. That resolution is no longer needed so it has been removed. This should resove the issue the dev team has been seeing lately where `yarn` and `yarn-deduplicate` disagree about the state the lockfile should be in. * Update yarn.lock * Update LavaMoat policy * deduplicate * Update LavaMoat build policy Co-authored-by: MetaMask Bot <metamaskbot@users.noreply.github.com> Co-authored-by: Alex Donesky <adonesky@gmail.com> Co-authored-by: Brad Decker <bhdecker84@gmail.com> Co-authored-by: Alex Miller <asmiller1989@gmail.com> Co-authored-by: Filip Sekulic <filip.sekulic@consensys.net> Co-authored-by: Erik Marks <25517051+rekmarks@users.noreply.github.com> Co-authored-by: Dan J Miller <danjm.com@gmail.com> Co-authored-by: Mark Stacey <markjstacey@gmail.com> Co-authored-by: seaona <54408225+seaona@users.noreply.github.com> Co-authored-by: seaona <mariona@gmx.es> Co-authored-by: PeterYinusa <peter.yinusa@consensys.net>
2022-08-24 20:57:47 +02:00
* @typedef {object} GasFeeErrorsReturnType
* @property {object} [gasErrors] - combined map of errors and warnings.
* @property {boolean} [hasGasErrors] - true if there are errors that can block submission.
Version v10.18.4 RC (#15643) * Version v10.18.4 * Fix default currency symbol for `wallet_addEthereumChain` + improve warnings for data that doesn't match our validation expectations (#15201) * set more appropriate default for ticker symbol when wallet_addEthereumChain is called * throw error to dapp when site suggests network with same chainId but different ticker symbol from already added network, instead of showing error and disabled notification to user * Fix Provider Tracking Metrics (#15082) * fix filetype audit (#15334) * Remove decentralized 4byte function signature registry since it contains incorrect signatures and we can't algorithmically check for best option when 4byte.directory is down (#15300) * remove decentralized 4byte function signature registry since it is griefed and we can't algorithmically check for best option when 4byte is down * add migration * remove nock of on chain registry call in getMethodDataAsync test * remove audit exclusion (#15346) * Updates `eth-lattice-keyring` to v0.10.0 (#15261) This is mainly associated with an update in GridPlus SDK and enables better strategies for fetching calldata decoder data. `eth-lattice-keyring` changes: GridPlus/eth-lattice-keyring@v0.7.3...v0.10.0 `gridplus-sdk` changes (which includes a codebase rewrite): GridPlus/gridplus-sdk@v1.2.3...v2.2.2 * Fix 'block link explorer on custom networks' (#13870) * Created a logic for the 'Add a block explorer URL' Removed unused message Message logic rollback Modified history push operation WIP: Pushing before rebasing Applied requested changes Removed unintenionally added code * Lint fix * Metrics fixed * Stop injecting provider on docs.google.com (#15459) * Fix setting of gasPrice when on non-eip 1559 networks (#15628) * Fix setting of gasPrice when on non-eip 1559 networks * Fix unit tests * Fix logic * Update ui/ducks/send/send.test.js Co-authored-by: Mark Stacey <markjstacey@gmail.com> Co-authored-by: Mark Stacey <markjstacey@gmail.com> * [GridPlus] Bumps `eth-lattice-keyring` to v0.11.0 (#15490) * [GridPlus] Bumps `gridplus-sdk` to v2.2.4 (#15561) * remove exclusions for mismatched object jsdoc type casing (#15351) * Improve `tokenId` parsing and clean up `useAssetDetails` hook (#15304) * Fix state creation in setupSentryGetStateGlobal (#15635) * filter breadcrumbs for improved clarity while debugging sentry errors (#15639) * Update v10.18.4 changelog (#15645) * Auto generated changelog * Update 10.18.4 changelog * Run lavamoat:auto * Call metrics event for wallet type selection at the right time (#15591) * Fix Sentry in LavaMoat contexts (#15672) Our Sentry setup relies upon application state, but it wasn't able to access it in LavaMoat builds because it's running in a separate Compartment. A patch has been introduced to the LavaMoat runtime to allow the root Compartment to mutate the `rootGlobals` object, which is accessible from outside the compartment as well. This lets us expose application state to our Sentry integration. * Fix Sentry deduplication of events that were never sent (#15677) The Sentry `Dedupe` integration has been filtering out our events, even when they were never sent due to our `beforeSend` handler. It was wrongly identifying them as duplicates because it has no knowledge of `beforeSend` or whether they were actually sent or not. To resolve this, the filtering we were doing in `beforeSend` has been moved to a Sentry integration. This integration is installed ahead of the `Dedupe` integration, so `Dedupe` should never find out about any events that we filter out, and thus will never consider them as sent when they were not. * Replace `lavamoat-runtime.js` patch (#15682) A patch made in #15672 was found to be unnecessary. Instead of setting a `rootGlobals` object upon construction of the root compartment, we are now creating a `sentryHooks` object in the initial top-level compartment. I hadn't realized at the time that the root compartment would inherit all properties of the initial compartment `globalThis`. This accomplishes the same goals as #15672 except without needing a patch. * Update v10.18.4 changelog * Fix lint issues * Update yarn.lock * Update `depcheck` to latest version (#15690) `depcheck` has been updated to the latest version. This version pins `@babel/parser` to v7.16.4 because of unresolved bugs in v7.16.5 that result in `depcheck` failing to parse TypeScript files correctly. We had a Yarn resolution in place to ensure `@babel/parser@7.16.4` was being used already. That resolution is no longer needed so it has been removed. This should resove the issue the dev team has been seeing lately where `yarn` and `yarn-deduplicate` disagree about the state the lockfile should be in. * Update yarn.lock * Update LavaMoat policy * deduplicate * Update LavaMoat build policy Co-authored-by: MetaMask Bot <metamaskbot@users.noreply.github.com> Co-authored-by: Alex Donesky <adonesky@gmail.com> Co-authored-by: Brad Decker <bhdecker84@gmail.com> Co-authored-by: Alex Miller <asmiller1989@gmail.com> Co-authored-by: Filip Sekulic <filip.sekulic@consensys.net> Co-authored-by: Erik Marks <25517051+rekmarks@users.noreply.github.com> Co-authored-by: Dan J Miller <danjm.com@gmail.com> Co-authored-by: Mark Stacey <markjstacey@gmail.com> Co-authored-by: seaona <54408225+seaona@users.noreply.github.com> Co-authored-by: seaona <mariona@gmx.es> Co-authored-by: PeterYinusa <peter.yinusa@consensys.net>
2022-08-24 20:57:47 +02:00
* @property {object} gasWarnings - map of gas warnings for EIP-1559 fields.
* @property {boolean} [balanceError] - true if user balance is less than transaction value.
* @property {boolean} [estimatesUnavailableWarning] - true if supportsEIP1559 is true and
* estimate is not of type fee-market.
*/
/**
* @param options
* @param options.transaction
* @param options.gasEstimateType
* @param options.gasFeeEstimates
* @param options.gasLimit
* @param options.gasPriceToUse
* @param options.isGasEstimatesLoading
* @param options.maxPriorityFeePerGasToUse
* @param options.maxFeePerGasToUse
* @param options.minimumCostInHexWei
* @param options.minimumGasLimit
* @returns {GasFeeErrorsReturnType}
*/
export function useGasFeeErrors({
transaction,
gasEstimateType,
gasFeeEstimates,
gasLimit,
gasPriceToUse,
isGasEstimatesLoading,
maxPriorityFeePerGasToUse,
maxFeePerGasToUse,
minimumCostInHexWei,
minimumGasLimit,
}) {
const supportsEIP1559 =
useSelector(checkNetworkAndAccountSupports1559) &&
!isLegacyTransaction(transaction?.txParams);
const isFeeMarketGasEstimate =
gasEstimateType === GAS_ESTIMATE_TYPES.FEE_MARKET;
// Get all errors
const gasLimitError = validateGasLimit(gasLimit, minimumGasLimit);
const maxPriorityFeeError = validateMaxPriorityFee(
maxPriorityFeePerGasToUse,
supportsEIP1559,
);
const maxFeeError = validateMaxFee(
maxFeePerGasToUse,
maxPriorityFeeError,
maxPriorityFeePerGasToUse,
supportsEIP1559,
);
const gasPriceError = validateGasPrice(
isFeeMarketGasEstimate,
gasPriceToUse,
supportsEIP1559,
transaction,
);
// Get all warnings
const maxPriorityFeeWarning = getMaxPriorityFeeWarning(
gasFeeEstimates,
isFeeMarketGasEstimate,
isGasEstimatesLoading,
maxPriorityFeePerGasToUse,
supportsEIP1559,
);
const maxFeeWarning = getMaxFeeWarning(
gasFeeEstimates,
isGasEstimatesLoading,
isFeeMarketGasEstimate,
maxFeeError,
maxPriorityFeeError,
maxFeePerGasToUse,
supportsEIP1559,
);
// Separating errors from warnings so we can know which value problems
// are blocking or simply useful information for the users
const gasErrors = useMemo(() => {
const errors = {};
if (gasLimitError) {
errors.gasLimit = gasLimitError;
}
if (maxPriorityFeeError) {
errors.maxPriorityFee = maxPriorityFeeError;
}
if (maxFeeError) {
errors.maxFee = maxFeeError;
}
if (gasPriceError) {
errors.gasPrice = gasPriceError;
}
return errors;
}, [gasLimitError, maxPriorityFeeError, maxFeeError, gasPriceError]);
const gasWarnings = useMemo(() => {
const warnings = {};
if (maxPriorityFeeWarning) {
warnings.maxPriorityFee = maxPriorityFeeWarning;
}
if (maxFeeWarning) {
warnings.maxFee = maxFeeWarning;
}
return warnings;
}, [maxPriorityFeeWarning, maxFeeWarning]);
const estimatesUnavailableWarning =
supportsEIP1559 && !isFeeMarketGasEstimate;
// Determine if we have any errors which should block submission
const hasGasErrors = Boolean(Object.keys(gasErrors).length);
// Combine the warnings and errors into one object for easier use within the UI.
// This object should have no effect on whether or not the user can submit the form
const errorsAndWarnings = useMemo(
() => ({
...gasWarnings,
...gasErrors,
}),
[gasErrors, gasWarnings],
);
const { balance: ethBalance } = useSelector(getSelectedAccount);
const balanceError = getBalanceError(
minimumCostInHexWei,
transaction,
ethBalance,
);
return {
gasErrors: errorsAndWarnings,
hasGasErrors,
gasWarnings,
balanceError,
estimatesUnavailableWarning,
};
}