mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-23 09:52:26 +01:00
add useGasInputs hook (#11480)
This commit is contained in:
parent
809b93dd77
commit
c3e6514c35
317
ui/hooks/useGasFeeInputs.js
Normal file
317
ui/hooks/useGasFeeInputs.js
Normal file
@ -0,0 +1,317 @@
|
||||
import { addHexPrefix } from 'ethereumjs-util';
|
||||
import { useCallback, useState } from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { GAS_ESTIMATE_TYPES } from '../../shared/constants/gas';
|
||||
import { multiplyCurrencies } from '../../shared/modules/conversion.utils';
|
||||
import {
|
||||
getMaximumGasTotalInHexWei,
|
||||
getMinimumGasTotalInHexWei,
|
||||
} from '../../shared/modules/gas.utils';
|
||||
import { PRIMARY, SECONDARY } from '../helpers/constants/common';
|
||||
import {
|
||||
decGWEIToHexWEI,
|
||||
decimalToHex,
|
||||
} from '../helpers/utils/conversions.util';
|
||||
import { getShouldShowFiat } from '../selectors';
|
||||
import { useCurrencyDisplay } from './useCurrencyDisplay';
|
||||
import { useGasFeeEstimates } from './useGasFeeEstimates';
|
||||
import { useUserPreferencedCurrency } from './useUserPreferencedCurrency';
|
||||
|
||||
/**
|
||||
* Opaque string type representing a decimal (base 10) number in GWEI
|
||||
* @typedef {`${number}`} DecGweiString
|
||||
*/
|
||||
|
||||
/**
|
||||
* String value representing the active estimate level to use
|
||||
* @typedef {'low' | 'medium' | 'high'} EstimateLevel
|
||||
*/
|
||||
|
||||
/**
|
||||
* Pulls out gasPrice estimate from either of the two gasPrice estimation
|
||||
* sources, based on the gasEstimateType and current estimateToUse.
|
||||
* @param {{import(
|
||||
* '@metamask/controllers'
|
||||
* ).GasFeeState['gasFeeEstimates']}} gasFeeEstimates - estimates returned from
|
||||
* the controller
|
||||
* @param {import(
|
||||
* './useGasFeeEstimates'
|
||||
* ).GasEstimates} gasEstimateType - type of estimate returned from controller
|
||||
* @param {EstimateLevel} estimateToUse - current estimate level to use
|
||||
* @returns {[DecGweiString]} - gasPrice estimate to use or null
|
||||
*/
|
||||
function getGasPriceEstimate(gasFeeEstimates, gasEstimateType, estimateToUse) {
|
||||
if (gasEstimateType === GAS_ESTIMATE_TYPES.LEGACY) {
|
||||
return gasFeeEstimates?.[estimateToUse] ?? '0';
|
||||
} else if (gasEstimateType === GAS_ESTIMATE_TYPES.ETH_GASPRICE) {
|
||||
return gasFeeEstimates?.gasPrice ?? '0';
|
||||
}
|
||||
return '0';
|
||||
}
|
||||
|
||||
/**
|
||||
* Pulls out gas fee estimate from the estimates returned from controller,
|
||||
* based on the gasEstimateType and current estimateToUse.
|
||||
* @param {'maxFeePerGas' | 'maxPriorityFeePerGas'} field - field to select
|
||||
* @param {{import(
|
||||
* '@metamask/controllers'
|
||||
* ).GasFeeState['gasFeeEstimates']}} gasFeeEstimates - estimates returned from
|
||||
* the controller
|
||||
* @param {import(
|
||||
* './useGasFeeEstimates'
|
||||
* ).GasEstimates} gasEstimateType - type of estimate returned from controller
|
||||
* @param {EstimateLevel} estimateToUse - current estimate level to use
|
||||
* @returns {[DecGweiString]} - gas fee estimate to use or null
|
||||
*/
|
||||
function getGasFeeEstimate(
|
||||
field,
|
||||
gasFeeEstimates,
|
||||
gasEstimateType,
|
||||
estimateToUse,
|
||||
) {
|
||||
if (gasEstimateType === GAS_ESTIMATE_TYPES.FEE_MARKET) {
|
||||
return gasFeeEstimates?.[estimateToUse]?.[field] ?? '0';
|
||||
}
|
||||
return '0';
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} GasFeeInputReturnType
|
||||
* @property {DecGweiString} [maxFeePerGas] - the maxFeePerGas input value.
|
||||
* @property {string} [maxFeePerGasFiat] - the maxFeePerGas converted to the
|
||||
* user's preferred currency.
|
||||
* @property {(DecGweiString) => void} setMaxFeePerGas - state setter method to
|
||||
* update the maxFeePerGas.
|
||||
* @property {DecGweiString} [maxPriorityFeePerGas] - the maxPriorityFeePerGas
|
||||
* input value.
|
||||
* @property {string} [maxPriorityFeePerGasFiat] - the maxPriorityFeePerGas
|
||||
* converted to the user's preferred currency.
|
||||
* @property {(DecGweiString) => void} setMaxPriorityFeePerGas - state setter
|
||||
* method to update the maxPriorityFeePerGas.
|
||||
* @property {DecGweiString} [gasPrice] - the gasPrice input value.
|
||||
* @property {(DecGweiString) => void} setGasPrice - state setter method to
|
||||
* update the gasPrice.
|
||||
* @property {DecGweiString} gasLimit - the gasLimit input value.
|
||||
* @property {(DecGweiString) => void} setGasLimit - state setter method to
|
||||
* update the gasLimit.
|
||||
* @property {EstimateLevel} [estimateToUse] - the estimate level currently
|
||||
* selected. This will be null if the user has ejected from using the
|
||||
* estimates.
|
||||
* @property {([EstimateLevel]) => void} setEstimateToUse - Setter method for
|
||||
* choosing which EstimateLevel to use.
|
||||
* @property {string} [estimatedMinimumFiat] - The amount estimated to be paid
|
||||
* based on current network conditions. Expressed in user's preferred
|
||||
* currency.
|
||||
* @property {string} [estimatedMaximumFiat] - the maximum amount estimated to be
|
||||
* paid if current network transaction volume increases. Expressed in user's
|
||||
* preferred currency.
|
||||
* @property {string} [estimatedMaximumNative] - the maximum amount estimated to
|
||||
* be paid if the current network transaction volume increases. Expressed in
|
||||
* the network's native currency.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Uses gasFeeEstimates and state to keep track of user gas fee inputs.
|
||||
* Will update the gas fee state when estimates update if the user has not yet
|
||||
* modified the fields.
|
||||
* @param {EstimateLevel} defaultEstimateToUse - which estimate
|
||||
* level to default the 'estimateToUse' state variable to.
|
||||
* @returns {GasFeeInputReturnType & import(
|
||||
* './useGasFeeEstimates'
|
||||
* ).GasEstimates} - gas fee input state and the GasFeeEstimates object
|
||||
*/
|
||||
export function useGasFeeInputs(defaultEstimateToUse = 'medium') {
|
||||
// We need to know whether to show fiat conversions or not, so that we can
|
||||
// default our fiat values to empty strings if showing fiat is not wanted or
|
||||
// possible.
|
||||
const showFiat = useSelector(getShouldShowFiat);
|
||||
|
||||
// We need to know the current network's currency and its decimal precision
|
||||
// to calculate the amount to display to the user.
|
||||
const {
|
||||
currency: primaryCurrency,
|
||||
numberOfDecimals: primaryNumberOfDecimals,
|
||||
} = useUserPreferencedCurrency(PRIMARY);
|
||||
|
||||
// For calculating the value of gas fees in the user's preferred currency we
|
||||
// first have to know what that currency is and its decimal precision
|
||||
const {
|
||||
currency: fiatCurrency,
|
||||
numberOfDecimals: fiatNumberOfDecimals,
|
||||
} = useUserPreferencedCurrency(SECONDARY);
|
||||
|
||||
// This hook keeps track of a few pieces of transitional state. It is
|
||||
// transitional because it is only used to modify a transaction in the
|
||||
// metamask (background) state tree.
|
||||
const [maxFeePerGas, setMaxFeePerGas] = useState(null);
|
||||
const [maxPriorityFeePerGas, setMaxPriorityFeePerGas] = useState(null);
|
||||
const [gasPrice, setGasPrice] = useState(null);
|
||||
const [gasLimit, setGasLimit] = useState(21000);
|
||||
const [estimateToUse, setInternalEstimateToUse] = useState(
|
||||
defaultEstimateToUse,
|
||||
);
|
||||
|
||||
// We need the gas estimates from the GasFeeController in the background.
|
||||
// Calling this hooks initiates polling for new gas estimates and returns the
|
||||
// current estimate.
|
||||
const {
|
||||
gasEstimateType,
|
||||
gasFeeEstimates,
|
||||
isGasEstimatesLoading,
|
||||
estimatedGasFeeTimeBounds,
|
||||
} = useGasFeeEstimates();
|
||||
|
||||
// When a user selects an estimate level, it will wipe out what they have
|
||||
// previously put in the inputs. This returns the inputs to the estimated
|
||||
// values at the level specified.
|
||||
const setEstimateToUse = useCallback((estimateLevel) => {
|
||||
setInternalEstimateToUse(estimateLevel);
|
||||
setMaxFeePerGas(null);
|
||||
setMaxPriorityFeePerGas(null);
|
||||
setGasPrice(null);
|
||||
}, []);
|
||||
|
||||
// We specify whether to use the estimate value by checking if the state
|
||||
// value has been set. The state value is only set by user input and is wiped
|
||||
// when the user selects an estimate. Default here is '0' to avoid bignumber
|
||||
// errors in later calculations for nullish values.
|
||||
const maxFeePerGasToUse =
|
||||
maxFeePerGas ??
|
||||
getGasFeeEstimate(
|
||||
'suggestedMaxFeePerGas',
|
||||
gasFeeEstimates,
|
||||
gasEstimateType,
|
||||
estimateToUse,
|
||||
);
|
||||
|
||||
const maxPriorityFeePerGasToUse =
|
||||
maxPriorityFeePerGas ??
|
||||
getGasFeeEstimate(
|
||||
'suggestedMaxPriorityFeePerGas',
|
||||
gasFeeEstimates,
|
||||
gasEstimateType,
|
||||
estimateToUse,
|
||||
);
|
||||
|
||||
const gasPriceToUse =
|
||||
gasPrice ??
|
||||
getGasPriceEstimate(gasFeeEstimates, gasEstimateType, estimateToUse);
|
||||
|
||||
// We have two helper methods that take an object that can have either
|
||||
// gasPrice OR the EIP-1559 fields on it, plus gasLimit. This object is
|
||||
// conditionally set to the appropriate fields to compute the minimum
|
||||
// and maximum cost of a transaction given the current estimates or selected
|
||||
// gas fees.
|
||||
const gasSettings = {
|
||||
gasLimit: decimalToHex(gasLimit),
|
||||
};
|
||||
if (gasEstimateType === GAS_ESTIMATE_TYPES.FEE_MARKET) {
|
||||
gasSettings.maxFeePerGas = decGWEIToHexWEI(maxFeePerGasToUse);
|
||||
gasSettings.maxPriorityFeePerGas = decGWEIToHexWEI(
|
||||
maxPriorityFeePerGasToUse,
|
||||
);
|
||||
gasSettings.baseFeePerGas = decGWEIToHexWEI(
|
||||
gasFeeEstimates.estimatedBaseFee ?? '0',
|
||||
);
|
||||
} else if (gasEstimateType === GAS_ESTIMATE_TYPES.NONE) {
|
||||
gasSettings.gasPrice = '0x0';
|
||||
} else {
|
||||
gasSettings.gasPrice = decGWEIToHexWEI(gasPriceToUse);
|
||||
}
|
||||
|
||||
// The maximum amount this transaction will cost
|
||||
const maximumCostInHexWei = getMaximumGasTotalInHexWei(gasSettings);
|
||||
// The minimum amount this transaction will cost's
|
||||
const minimumCostInHexWei = getMinimumGasTotalInHexWei(gasSettings);
|
||||
|
||||
// We need to display the estimated fiat currency impact of the
|
||||
// maxPriorityFeePerGas field to the user. This hook calculates that amount.
|
||||
const [, { value: maxPriorityFeePerGasFiat }] = useCurrencyDisplay(
|
||||
addHexPrefix(
|
||||
multiplyCurrencies(maxPriorityFeePerGasToUse, gasLimit, {
|
||||
toNumericBase: 'hex',
|
||||
fromDenomination: 'GWEI',
|
||||
toDenomination: 'WEI',
|
||||
multiplicandBase: 10,
|
||||
multiplierBase: 10,
|
||||
}),
|
||||
),
|
||||
{
|
||||
numberOfDecimals: fiatNumberOfDecimals,
|
||||
currency: fiatCurrency,
|
||||
},
|
||||
);
|
||||
|
||||
// We need to display thee estimated fiat currency impact of the maxFeePerGas
|
||||
// field to the user. This hook calculates that amount. This also works for
|
||||
// the gasPrice amount because in legacy transactions cost is always gasPrice
|
||||
// * gasLimit.
|
||||
const [, { value: maxFeePerGasFiat }] = useCurrencyDisplay(
|
||||
maximumCostInHexWei,
|
||||
{
|
||||
numberOfDecimals: fiatNumberOfDecimals,
|
||||
currency: fiatCurrency,
|
||||
},
|
||||
);
|
||||
|
||||
// We need to display the total amount of native currency will be expended
|
||||
// given the selected gas fees.
|
||||
const [estimatedMaximumNative] = useCurrencyDisplay(maximumCostInHexWei, {
|
||||
numberOfDecimals: primaryNumberOfDecimals,
|
||||
currency: primaryCurrency,
|
||||
});
|
||||
|
||||
// We also need to display our closest estimate of the low end of estimation
|
||||
// in fiat.
|
||||
const [, { value: estimatedMinimumFiat }] = useCurrencyDisplay(
|
||||
minimumCostInHexWei,
|
||||
{
|
||||
numberOfDecimals: fiatNumberOfDecimals,
|
||||
currency: fiatCurrency,
|
||||
},
|
||||
);
|
||||
|
||||
let isMaxPriorityFeeError = false;
|
||||
let isMaxFeeError = false;
|
||||
|
||||
switch (gasEstimateType) {
|
||||
case GAS_ESTIMATE_TYPES.FEE_MARKET:
|
||||
isMaxPriorityFeeError =
|
||||
!isGasEstimatesLoading &&
|
||||
maxPriorityFeePerGasToUse <
|
||||
gasFeeEstimates?.low?.suggestedMaxPriorityFeePerGas;
|
||||
isMaxFeeError =
|
||||
!isGasEstimatesLoading &&
|
||||
maxFeePerGasToUse < gasFeeEstimates?.low?.suggestedMaxFeePerGas;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
const isGasTooLow = Boolean(isMaxPriorityFeeError || isMaxFeeError);
|
||||
|
||||
return {
|
||||
maxFeePerGas: maxFeePerGasToUse,
|
||||
maxFeePerGasFiat: showFiat ? maxFeePerGasFiat : '',
|
||||
setMaxFeePerGas,
|
||||
isMaxFeeError,
|
||||
maxPriorityFeePerGas: maxPriorityFeePerGasToUse,
|
||||
maxPriorityFeePerGasFiat: showFiat ? maxPriorityFeePerGasFiat : '',
|
||||
setMaxPriorityFeePerGas,
|
||||
isMaxPriorityFeeError,
|
||||
gasPrice: gasPriceToUse,
|
||||
setGasPrice,
|
||||
gasLimit,
|
||||
setGasLimit,
|
||||
isGasTooLow,
|
||||
estimateToUse,
|
||||
setEstimateToUse,
|
||||
estimatedMinimumFiat: showFiat ? estimatedMinimumFiat : '',
|
||||
estimatedMaximumFiat: showFiat ? maxFeePerGasFiat : '',
|
||||
estimatedMaximumNative,
|
||||
isGasEstimatesLoading,
|
||||
gasFeeEstimates,
|
||||
gasEstimateType,
|
||||
estimatedGasFeeTimeBounds,
|
||||
};
|
||||
}
|
237
ui/hooks/useGasFeeInputs.test.js
Normal file
237
ui/hooks/useGasFeeInputs.test.js
Normal file
@ -0,0 +1,237 @@
|
||||
import { act, renderHook } from '@testing-library/react-hooks';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { GAS_ESTIMATE_TYPES } from '../../shared/constants/gas';
|
||||
import { multiplyCurrencies } from '../../shared/modules/conversion.utils';
|
||||
import {
|
||||
getConversionRate,
|
||||
getNativeCurrency,
|
||||
} from '../ducks/metamask/metamask';
|
||||
import { ETH, PRIMARY } from '../helpers/constants/common';
|
||||
import { getCurrentCurrency, getShouldShowFiat } from '../selectors';
|
||||
import { useGasFeeEstimates } from './useGasFeeEstimates';
|
||||
import { useGasFeeInputs } from './useGasFeeInputs';
|
||||
import { useUserPreferencedCurrency } from './useUserPreferencedCurrency';
|
||||
|
||||
jest.mock('./useUserPreferencedCurrency', () => ({
|
||||
useUserPreferencedCurrency: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('./useGasFeeEstimates', () => ({
|
||||
useGasFeeEstimates: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('react-redux', () => {
|
||||
const actual = jest.requireActual('react-redux');
|
||||
|
||||
return {
|
||||
...actual,
|
||||
useSelector: jest.fn(),
|
||||
};
|
||||
});
|
||||
|
||||
// Why this number?
|
||||
// 20 gwei * 21000 gasLimit = 420,000 gwei
|
||||
// 420,000 gwei is 0.00042 ETH
|
||||
// 0.00042 ETH * 100000 = $42
|
||||
const MOCK_ETH_USD_CONVERSION_RATE = 100000;
|
||||
|
||||
const LEGACY_GAS_ESTIMATE_RETURN_VALUE = {
|
||||
gasEstimateType: GAS_ESTIMATE_TYPES.LEGACY,
|
||||
gasFeeEstimates: {
|
||||
low: '10',
|
||||
medium: '20',
|
||||
high: '30',
|
||||
},
|
||||
estimatedGasFeeTimeBounds: {},
|
||||
};
|
||||
|
||||
const FEE_MARKET_ESTIMATE_RETURN_VALUE = {
|
||||
gasEstimateType: GAS_ESTIMATE_TYPES.FEE_MARKET,
|
||||
gasFeeEstimates: {
|
||||
low: {
|
||||
minWaitTimeEstimate: 180000,
|
||||
maxWaitTimeEstimate: 300000,
|
||||
suggestedMaxPriorityFeePerGas: '3',
|
||||
suggestedMaxFeePerGas: '53',
|
||||
},
|
||||
medium: {
|
||||
minWaitTimeEstimate: 15000,
|
||||
maxWaitTimeEstimate: 60000,
|
||||
suggestedMaxPriorityFeePerGas: '7',
|
||||
suggestedMaxFeePerGas: '70',
|
||||
},
|
||||
high: {
|
||||
minWaitTimeEstimate: 0,
|
||||
maxWaitTimeEstimate: 15000,
|
||||
suggestedMaxPriorityFeePerGas: '10',
|
||||
suggestedMaxFeePerGas: '100',
|
||||
},
|
||||
estimatedBaseFee: '50',
|
||||
},
|
||||
estimatedGasFeeTimeBounds: {},
|
||||
};
|
||||
|
||||
const generateUseSelectorRouter = () => (selector) => {
|
||||
if (selector === getConversionRate) {
|
||||
return MOCK_ETH_USD_CONVERSION_RATE;
|
||||
}
|
||||
if (selector === getNativeCurrency) {
|
||||
return ETH;
|
||||
}
|
||||
if (selector === getCurrentCurrency) {
|
||||
return 'USD';
|
||||
}
|
||||
if (selector === getShouldShowFiat) {
|
||||
return true;
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
function getTotalCostInETH(gwei, gasLimit) {
|
||||
return multiplyCurrencies(gwei, gasLimit, {
|
||||
fromDenomination: 'GWEI',
|
||||
toDenomination: 'ETH',
|
||||
multiplicandBase: 10,
|
||||
multiplierBase: 10,
|
||||
});
|
||||
}
|
||||
|
||||
describe('useGasFeeInputs', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
useUserPreferencedCurrency.mockImplementation((type) => {
|
||||
if (type === PRIMARY) {
|
||||
return { currency: ETH, numberOfDecimals: 6 };
|
||||
}
|
||||
return { currency: 'USD', numberOfDecimals: 2 };
|
||||
});
|
||||
});
|
||||
|
||||
describe('when using gasPrice API for estimation', () => {
|
||||
beforeEach(() => {
|
||||
useGasFeeEstimates.mockImplementation(
|
||||
() => LEGACY_GAS_ESTIMATE_RETURN_VALUE,
|
||||
);
|
||||
useSelector.mockImplementation(generateUseSelectorRouter());
|
||||
});
|
||||
it('passes through the raw estimate values from useGasFeeEstimates', () => {
|
||||
const { result } = renderHook(() => useGasFeeInputs());
|
||||
expect(result.current.gasFeeEstimates).toMatchObject(
|
||||
LEGACY_GAS_ESTIMATE_RETURN_VALUE.gasFeeEstimates,
|
||||
);
|
||||
expect(result.current.gasEstimateType).toBe(
|
||||
LEGACY_GAS_ESTIMATE_RETURN_VALUE.gasEstimateType,
|
||||
);
|
||||
expect(result.current.estimatedGasFeeTimeBounds).toMatchObject({});
|
||||
});
|
||||
|
||||
it('returns gasPrice appropriately, and "0" for EIP1559 fields', () => {
|
||||
const { result } = renderHook(() => useGasFeeInputs());
|
||||
expect(result.current.gasPrice).toBe(
|
||||
LEGACY_GAS_ESTIMATE_RETURN_VALUE.gasFeeEstimates.medium,
|
||||
);
|
||||
expect(result.current.maxFeePerGas).toBe('0');
|
||||
expect(result.current.maxPriorityFeePerGas).toBe('0');
|
||||
});
|
||||
|
||||
it('updates values when user modifies gasPrice', () => {
|
||||
const { result } = renderHook(() => useGasFeeInputs());
|
||||
expect(result.current.gasPrice).toBe(
|
||||
LEGACY_GAS_ESTIMATE_RETURN_VALUE.gasFeeEstimates.medium,
|
||||
);
|
||||
let totalEthGasFee = getTotalCostInETH(
|
||||
LEGACY_GAS_ESTIMATE_RETURN_VALUE.gasFeeEstimates.medium,
|
||||
result.current.gasLimit,
|
||||
);
|
||||
let totalFiat = (
|
||||
Number(totalEthGasFee) * MOCK_ETH_USD_CONVERSION_RATE
|
||||
).toFixed(2);
|
||||
expect(result.current.estimatedMaximumNative).toBe(
|
||||
`${totalEthGasFee} ETH`,
|
||||
);
|
||||
expect(result.current.estimatedMaximumFiat).toBe(`$${totalFiat}`);
|
||||
expect(result.current.estimatedMinimumFiat).toBe(`$${totalFiat}`);
|
||||
act(() => {
|
||||
result.current.setGasPrice('30');
|
||||
});
|
||||
totalEthGasFee = getTotalCostInETH('30', result.current.gasLimit);
|
||||
totalFiat = (
|
||||
Number(totalEthGasFee) * MOCK_ETH_USD_CONVERSION_RATE
|
||||
).toFixed(2);
|
||||
expect(result.current.gasPrice).toBe('30');
|
||||
expect(result.current.estimatedMaximumNative).toBe(
|
||||
`${totalEthGasFee} ETH`,
|
||||
);
|
||||
expect(result.current.estimatedMaximumFiat).toBe(`$${totalFiat}`);
|
||||
expect(result.current.estimatedMinimumFiat).toBe(`$${totalFiat}`);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when using EIP 1559 API for estimation', () => {
|
||||
beforeEach(() => {
|
||||
useGasFeeEstimates.mockImplementation(
|
||||
() => FEE_MARKET_ESTIMATE_RETURN_VALUE,
|
||||
);
|
||||
useSelector.mockImplementation(generateUseSelectorRouter());
|
||||
});
|
||||
it('passes through the raw estimate values from useGasFeeEstimates', () => {
|
||||
const { result } = renderHook(() => useGasFeeInputs());
|
||||
expect(result.current.gasFeeEstimates).toMatchObject(
|
||||
FEE_MARKET_ESTIMATE_RETURN_VALUE.gasFeeEstimates,
|
||||
);
|
||||
expect(result.current.gasEstimateType).toBe(
|
||||
FEE_MARKET_ESTIMATE_RETURN_VALUE.gasEstimateType,
|
||||
);
|
||||
expect(result.current.estimatedGasFeeTimeBounds).toMatchObject({});
|
||||
});
|
||||
|
||||
it('returns EIP-1559 fields appropriately, and "0" for gasPrice fields', () => {
|
||||
const { result } = renderHook(() => useGasFeeInputs());
|
||||
expect(result.current.gasPrice).toBe('0');
|
||||
expect(result.current.maxFeePerGas).toBe(
|
||||
FEE_MARKET_ESTIMATE_RETURN_VALUE.gasFeeEstimates.medium
|
||||
.suggestedMaxFeePerGas,
|
||||
);
|
||||
expect(result.current.maxPriorityFeePerGas).toBe(
|
||||
FEE_MARKET_ESTIMATE_RETURN_VALUE.gasFeeEstimates.medium
|
||||
.suggestedMaxPriorityFeePerGas,
|
||||
);
|
||||
});
|
||||
|
||||
it('updates values when user modifies maxFeePerGas', () => {
|
||||
const { result } = renderHook(() => useGasFeeInputs());
|
||||
expect(result.current.maxFeePerGas).toBe(
|
||||
FEE_MARKET_ESTIMATE_RETURN_VALUE.gasFeeEstimates.medium
|
||||
.suggestedMaxFeePerGas,
|
||||
);
|
||||
let totalEthGasFee = getTotalCostInETH(
|
||||
FEE_MARKET_ESTIMATE_RETURN_VALUE.gasFeeEstimates.medium
|
||||
.suggestedMaxFeePerGas,
|
||||
result.current.gasLimit,
|
||||
);
|
||||
let totalMaxFiat = (
|
||||
Number(totalEthGasFee) * MOCK_ETH_USD_CONVERSION_RATE
|
||||
).toFixed(2);
|
||||
expect(result.current.estimatedMaximumNative).toBe(
|
||||
`${totalEthGasFee} ETH`,
|
||||
);
|
||||
expect(result.current.estimatedMaximumFiat).toBe(`$${totalMaxFiat}`);
|
||||
// TODO: test minimum fiat too
|
||||
// expect(result.current.estimatedMinimumFiat).toBe(`$${totalMaxFiat}`);
|
||||
act(() => {
|
||||
result.current.setMaxFeePerGas('90');
|
||||
});
|
||||
totalEthGasFee = getTotalCostInETH('90', result.current.gasLimit);
|
||||
totalMaxFiat = (
|
||||
Number(totalEthGasFee) * MOCK_ETH_USD_CONVERSION_RATE
|
||||
).toFixed(2);
|
||||
expect(result.current.maxFeePerGas).toBe('90');
|
||||
expect(result.current.estimatedMaximumNative).toBe(
|
||||
`${totalEthGasFee} ETH`,
|
||||
);
|
||||
expect(result.current.estimatedMaximumFiat).toBe(`$${totalMaxFiat}`);
|
||||
// TODO: test minimum fiat too
|
||||
// expect(result.current.estimatedMinimumFiat).toBe(`$${totalMaxFiat}`);
|
||||
});
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue
Block a user