1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-11-22 01:47:00 +01:00

Replace usages of conversion util in rest of UI folder in favor of Numeric (#17334)

This commit is contained in:
Brad Decker 2023-01-24 08:44:49 -06:00 committed by GitHub
parent dd09245ff6
commit 3ff12d70e9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 290 additions and 539 deletions

View File

@ -278,7 +278,8 @@ export class Numeric {
this.value = bnToBigNumber(value); this.value = bnToBigNumber(value);
} else if ( } else if (
isNullOrUndefined(value) || isNullOrUndefined(value) ||
(typeof value === 'number' && isNaN(value)) (typeof value === 'number' && isNaN(value)) ||
(typeof value === 'string' && value === '')
) { ) {
// There are parts of the codebase that call this method without a value, // There are parts of the codebase that call this method without a value,
// or with a 'NaN' (which is probably a bug somewhere in our tests?). // or with a 'NaN' (which is probably a bug somewhere in our tests?).

View File

@ -13,8 +13,8 @@ import {
} from '../../helpers/utils/confirm-tx.util'; } from '../../helpers/utils/confirm-tx.util';
import { import {
conversionUtil,
getValueFromWeiHex, getValueFromWeiHex,
hexToDecimal,
sumHexes, sumHexes,
} from '../../../shared/modules/conversion.utils'; } from '../../../shared/modules/conversion.utils';
import { getAveragePriceEstimateInHexWEI } from '../../selectors/custom-gas'; import { getAveragePriceEstimateInHexWEI } from '../../selectors/custom-gas';
@ -293,10 +293,7 @@ export function setTransactionToConfirm(transactionId) {
} }
if (txParams.nonce) { if (txParams.nonce) {
const nonce = conversionUtil(txParams.nonce, { const nonce = hexToDecimal(txParams.nonce);
fromNumericBase: 'hex',
toNumericBase: 'dec',
});
dispatch(updateNonce(nonce)); dispatch(updateNonce(nonce));
} }

View File

@ -1,5 +1,6 @@
import { addHexPrefix } from 'ethereumjs-util'; import { addHexPrefix } from 'ethereumjs-util';
import abi from 'human-standard-token-abi'; import abi from 'human-standard-token-abi';
import BigNumber from 'bignumber.js';
import { GAS_LIMITS, MIN_GAS_LIMIT_HEX } from '../../../shared/constants/gas'; import { GAS_LIMITS, MIN_GAS_LIMIT_HEX } from '../../../shared/constants/gas';
import { calcTokenAmount } from '../../../shared/lib/transactions-controller-utils'; import { calcTokenAmount } from '../../../shared/lib/transactions-controller-utils';
import { CHAIN_ID_TO_GAS_LIMIT_BUFFER_MAP } from '../../../shared/constants/network'; import { CHAIN_ID_TO_GAS_LIMIT_BUFFER_MAP } from '../../../shared/constants/network';
@ -8,11 +9,6 @@ import {
TransactionEnvelopeType, TransactionEnvelopeType,
} from '../../../shared/constants/transaction'; } from '../../../shared/constants/transaction';
import { readAddressAsContract } from '../../../shared/modules/contract-utils'; import { readAddressAsContract } from '../../../shared/modules/contract-utils';
import {
conversionUtil,
multiplyCurrencies,
} from '../../../shared/modules/conversion.utils';
import { ETH, GWEI } from '../../helpers/constants/common';
import { import {
addGasBuffer, addGasBuffer,
generateERC20TransferData, generateERC20TransferData,
@ -21,6 +17,7 @@ import {
} from '../../pages/send/send.utils'; } from '../../pages/send/send.utils';
import { getGasPriceInHexWei } from '../../selectors'; import { getGasPriceInHexWei } from '../../selectors';
import { estimateGas } from '../../store/actions'; import { estimateGas } from '../../store/actions';
import { Numeric } from '../../../shared/modules/Numeric';
export async function estimateGasLimitForSend({ export async function estimateGasLimitForSend({
selectedAddress, selectedAddress,
@ -109,15 +106,10 @@ export async function estimateGasLimitForSend({
if (!isSimpleSendOnNonStandardNetwork) { if (!isSimpleSendOnNonStandardNetwork) {
// If we do not yet have a gasLimit, we must call into our background // If we do not yet have a gasLimit, we must call into our background
// process to get an estimate for gasLimit based on known parameters. // process to get an estimate for gasLimit based on known parameters.
paramsForGasEstimate.gas = new Numeric(blockGasLimit, 16)
paramsForGasEstimate.gas = addHexPrefix( .times(new Numeric(0.95, 10))
multiplyCurrencies(blockGasLimit, 0.95, { .round(0, BigNumber.ROUND_DOWN)
multiplicandBase: 16, .toPrefixedHexString();
multiplierBase: 10,
roundDown: '0',
toNumericBase: 'hex',
}),
);
} }
// The buffer multipler reduces transaction failures by ensuring that the // The buffer multipler reduces transaction failures by ensuring that the
@ -268,14 +260,9 @@ export function generateTransactionParams(sendState) {
* @returns {string} * @returns {string}
*/ */
export function getRoundedGasPrice(gasPriceEstimate) { export function getRoundedGasPrice(gasPriceEstimate) {
const gasPriceInDecGwei = conversionUtil(gasPriceEstimate, { const gasPriceInDecGwei = new Numeric(gasPriceEstimate, 10)
numberOfDecimals: 9, .round(9)
toDenomination: GWEI, .toString();
fromNumericBase: 'dec',
toNumericBase: 'dec',
fromCurrency: ETH,
fromDenomination: GWEI,
});
const gasPriceAsNumber = Number(gasPriceInDecGwei); const gasPriceAsNumber = Number(gasPriceInDecGwei);
return getGasPriceInHexWei(gasPriceAsNumber); return getGasPriceInHexWei(gasPriceAsNumber);
} }

View File

@ -4,12 +4,8 @@ import { addHexPrefix } from 'ethereumjs-util';
import { debounce } from 'lodash'; import { debounce } from 'lodash';
import { v4 as uuidv4 } from 'uuid'; import { v4 as uuidv4 } from 'uuid';
import { import {
conversionGreaterThan, decimalToHex,
conversionUtil,
getValueFromWeiHex, getValueFromWeiHex,
multiplyCurrencies,
subtractCurrencies,
sumHexes,
} from '../../../shared/modules/conversion.utils'; } from '../../../shared/modules/conversion.utils';
import { GAS_ESTIMATE_TYPES, GAS_LIMITS } from '../../../shared/constants/gas'; import { GAS_ESTIMATE_TYPES, GAS_LIMITS } from '../../../shared/constants/gas';
import { import {
@ -109,6 +105,7 @@ import {
calcGasTotal, calcGasTotal,
calcTokenAmount, calcTokenAmount,
} from '../../../shared/lib/transactions-controller-utils'; } from '../../../shared/lib/transactions-controller-utils';
import { Numeric } from '../../../shared/modules/Numeric';
import { import {
estimateGasLimitForSend, estimateGasLimitForSend,
generateTransactionParams, generateTransactionParams,
@ -902,31 +899,21 @@ const slice = createSlice({
let amount = '0x0'; let amount = '0x0';
if (draftTransaction.asset.type === AssetType.token) { if (draftTransaction.asset.type === AssetType.token) {
const decimals = draftTransaction.asset.details?.decimals ?? 0; const decimals = draftTransaction.asset.details?.decimals ?? 0;
const multiplier = Math.pow(10, Number(decimals)); const multiplier = Math.pow(10, Number(decimals));
amount = multiplyCurrencies( amount = new Numeric(draftTransaction.asset.balance, 16)
draftTransaction.asset.balance, .times(multiplier, 10)
multiplier, .toString();
{
toNumericBase: 'hex',
multiplicandBase: 16,
multiplierBase: 10,
},
);
} else { } else {
const _gasTotal = sumHexes( const _gasTotal = new Numeric(
draftTransaction.gas.gasTotal || '0x0', draftTransaction.gas.gasTotal || '0x0',
state.gasTotalForLayer1 || '0x0', 16,
); ).add(new Numeric(state.gasTotalForLayer1 || '0x0', 16));
amount = subtractCurrencies(
addHexPrefix(draftTransaction.asset.balance), amount = new Numeric(draftTransaction.asset.balance, 16)
addHexPrefix(_gasTotal), .minus(_gasTotal)
{ .toString();
toNumericBase: 'hex',
aBase: 16,
bBase: 16,
},
);
} }
slice.caseReducers.updateSendAmount(state, { slice.caseReducers.updateSendAmount(state, {
payload: amount, payload: amount,
@ -1266,6 +1253,9 @@ const slice = createSlice({
validateAmountField: (state) => { validateAmountField: (state) => {
const draftTransaction = const draftTransaction =
state.draftTransactions[state.currentTransactionUUID]; state.draftTransactions[state.currentTransactionUUID];
const amountValue = new Numeric(draftTransaction.amount.value, 16);
switch (true) { switch (true) {
// set error to INSUFFICIENT_FUNDS_FOR_GAS_ERROR if the account balance is lower // set error to INSUFFICIENT_FUNDS_FOR_GAS_ERROR if the account balance is lower
// than the total price of the transaction inclusive of gas fees. // than the total price of the transaction inclusive of gas fees.
@ -1289,10 +1279,7 @@ const slice = createSlice({
break; break;
// if the amount is negative, set error to NEGATIVE_ETH_ERROR // if the amount is negative, set error to NEGATIVE_ETH_ERROR
// TODO: change this to NEGATIVE_ERROR and remove the currency bias. // TODO: change this to NEGATIVE_ERROR and remove the currency bias.
case conversionGreaterThan( case amountValue.isNegative():
{ value: 0, fromNumericBase: 'dec' },
{ value: draftTransaction.amount.value, fromNumericBase: 'hex' },
):
draftTransaction.amount.error = NEGATIVE_ETH_ERROR; draftTransaction.amount.error = NEGATIVE_ETH_ERROR;
break; break;
// If none of the above are true, set error to null // If none of the above are true, set error to null
@ -1407,28 +1394,81 @@ const slice = createSlice({
validateSendState: (state) => { validateSendState: (state) => {
const draftTransaction = const draftTransaction =
state.draftTransactions[state.currentTransactionUUID]; state.draftTransactions[state.currentTransactionUUID];
slice.caseReducers.addHistoryEntry(state, {
payload: 'Begin validating send state',
});
if (draftTransaction) { if (draftTransaction) {
switch (true) { switch (true) {
case Boolean(draftTransaction.amount.error): case Boolean(draftTransaction.amount.error):
slice.caseReducers.addHistoryEntry(state, {
payload: `Amount is in error ${draftTransaction.amount.error}`,
});
draftTransaction.status = SEND_STATUSES.INVALID;
break;
case Boolean(draftTransaction.gas.error): case Boolean(draftTransaction.gas.error):
slice.caseReducers.addHistoryEntry(state, {
payload: `Gas is in error ${draftTransaction.gas.error}`,
});
draftTransaction.status = SEND_STATUSES.INVALID;
break;
case Boolean(draftTransaction.asset.error): case Boolean(draftTransaction.asset.error):
slice.caseReducers.addHistoryEntry(state, {
payload: `Asset is in error ${draftTransaction.asset.error}`,
});
draftTransaction.status = SEND_STATUSES.INVALID;
break;
case draftTransaction.asset.type === AssetType.token && case draftTransaction.asset.type === AssetType.token &&
draftTransaction.asset.details === null: draftTransaction.asset.details === null:
slice.caseReducers.addHistoryEntry(state, {
payload: `Asset is TOKEN and token details is null`,
});
draftTransaction.status = SEND_STATUSES.INVALID;
break;
case state.stage === SEND_STAGES.ADD_RECIPIENT: case state.stage === SEND_STAGES.ADD_RECIPIENT:
slice.caseReducers.addHistoryEntry(state, {
payload: `Form is invalid because stage is ADD_RECIPIENT`,
});
draftTransaction.status = SEND_STATUSES.INVALID;
break;
case state.stage === SEND_STAGES.INACTIVE: case state.stage === SEND_STAGES.INACTIVE:
slice.caseReducers.addHistoryEntry(state, {
payload: `Form is invalid because stage is INACTIVE`,
});
draftTransaction.status = SEND_STATUSES.INVALID;
break;
case state.gasEstimateIsLoading: case state.gasEstimateIsLoading:
slice.caseReducers.addHistoryEntry(state, {
payload: `Form is invalid because gasEstimateIsLoading`,
});
draftTransaction.status = SEND_STATUSES.INVALID;
break;
case new BigNumber(draftTransaction.gas.gasLimit, 16).lessThan( case new BigNumber(draftTransaction.gas.gasLimit, 16).lessThan(
new BigNumber(state.gasLimitMinimum), new BigNumber(state.gasLimitMinimum),
): ):
slice.caseReducers.addHistoryEntry(state, {
payload: `Form is invalid because ${draftTransaction.gas.gasLimit} is lessThan ${state.gasLimitMinimum}`,
});
draftTransaction.status = SEND_STATUSES.INVALID; draftTransaction.status = SEND_STATUSES.INVALID;
break; break;
case draftTransaction.recipient.warning === 'loading': case draftTransaction.recipient.warning === 'loading':
slice.caseReducers.addHistoryEntry(state, {
payload: `Form is invalid because recipient warning is loading`,
});
draftTransaction.status = SEND_STATUSES.INVALID;
break;
case draftTransaction.recipient.warning === case draftTransaction.recipient.warning ===
KNOWN_RECIPIENT_ADDRESS_WARNING && KNOWN_RECIPIENT_ADDRESS_WARNING &&
draftTransaction.recipient.recipientWarningAcknowledged === false: draftTransaction.recipient.recipientWarningAcknowledged === false:
slice.caseReducers.addHistoryEntry(state, {
payload: `Form is invalid because recipient warning not acknolwedged`,
});
draftTransaction.status = SEND_STATUSES.INVALID; draftTransaction.status = SEND_STATUSES.INVALID;
break; break;
default: default:
slice.caseReducers.addHistoryEntry(state, {
payload: `Form is valid`,
});
draftTransaction.status = SEND_STATUSES.VALID; draftTransaction.status = SEND_STATUSES.VALID;
} }
} }
@ -1730,13 +1770,7 @@ export function editExistingTransaction(assetType, transactionId) {
const address = getTokenAddressParam(tokenData); const address = getTokenAddressParam(tokenData);
const nickname = getAddressBookEntryOrAccountName(state, address) ?? ''; const nickname = getAddressBookEntryOrAccountName(state, address) ?? '';
const tokenAmountInHex = addHexPrefix( const tokenAmountInHex = addHexPrefix(decimalToHex(tokenAmountInDec));
conversionUtil(tokenAmountInDec, {
fromNumericBase: 'dec',
toNumericBase: 'hex',
}),
);
await dispatch( await dispatch(
actions.addNewDraft({ actions.addNewDraft({
...draftTransactionInitialState, ...draftTransactionInitialState,
@ -1936,14 +1970,13 @@ export function updateSendAmount(amount) {
10, 10,
Number(draftTransaction.asset.details?.decimals || 0), Number(draftTransaction.asset.details?.decimals || 0),
); );
const decimalValueString = conversionUtil(addHexPrefix(amount), { const decimalValueString = new Numeric(addHexPrefix(amount), 16)
fromNumericBase: 'hex', .toBase(10)
toNumericBase: 'dec', .applyConversionRate(
toCurrency: draftTransaction.asset.details?.symbol, draftTransaction.asset.details?.symbol ? multiplier : 1,
conversionRate: multiplier, true,
invertConversionRate: true, )
}); .toString();
logAmount = `${Number(decimalValueString) ? decimalValueString : ''} ${ logAmount = `${Number(decimalValueString) ? decimalValueString : ''} ${
draftTransaction.asset.details?.symbol draftTransaction.asset.details?.symbol
}`; }`;

View File

@ -53,7 +53,6 @@ import {
} from '../../pages/swaps/swaps.util'; } from '../../pages/swaps/swaps.util';
import { import {
addHexes, addHexes,
conversionLessThan,
decGWEIToHexWEI, decGWEIToHexWEI,
decimalToHex, decimalToHex,
getValueFromWeiHex, getValueFromWeiHex,
@ -91,6 +90,8 @@ import {
calcGasTotal, calcGasTotal,
calcTokenAmount, calcTokenAmount,
} from '../../../shared/lib/transactions-controller-utils'; } from '../../../shared/lib/transactions-controller-utils';
import { EtherDenomination } from '../../../shared/constants/common';
import { Numeric } from '../../../shared/modules/Numeric';
export const GAS_PRICES_LOADING_STATES = { export const GAS_PRICES_LOADING_STATES = {
INITIAL: 'INITIAL', INITIAL: 'INITIAL',
@ -289,15 +290,13 @@ export function shouldShowCustomPriceTooLowWarning(state) {
return false; return false;
} }
const customPriceRisksSwapFailure = conversionLessThan( const customPriceRisksSwapFailure = new Numeric(
{ customGasPrice,
value: customGasPrice, 16,
fromNumericBase: 'hex', EtherDenomination.WEI,
fromDenomination: 'WEI', )
toDenomination: 'GWEI', .toDenomination(EtherDenomination.GWEI)
}, .greaterThan(average, 10);
{ value: average, fromNumericBase: 'dec' },
);
return customPriceRisksSwapFailure; return customPriceRisksSwapFailure;
} }

View File

@ -1,63 +1,31 @@
import currencyFormatter from 'currency-formatter'; import currencyFormatter from 'currency-formatter';
import currencies from 'currency-formatter/currencies'; import currencies from 'currency-formatter/currencies';
import BigNumber from 'bignumber.js'; import BigNumber from 'bignumber.js';
import { addHexPrefix } from '../../../app/scripts/lib/util';
import { unconfirmedTransactionsCountSelector } from '../../selectors'; import { unconfirmedTransactionsCountSelector } from '../../selectors';
import { import { Numeric } from '../../../shared/modules/Numeric';
conversionUtil, import { EtherDenomination } from '../../../shared/constants/common';
addCurrencies,
multiplyCurrencies,
conversionGreaterThan,
} from '../../../shared/modules/conversion.utils';
export function increaseLastGasPrice(lastGasPrice) { export function getHexGasTotal({ gasLimit = '0x0', gasPrice = '0x0' }) {
return addHexPrefix( return new Numeric(gasLimit, 16)
multiplyCurrencies(lastGasPrice || '0x0', 1.1, { .times(new Numeric(gasPrice, 16))
multiplicandBase: 16, .toPrefixedHexString();
multiplierBase: 10,
toNumericBase: 'hex',
}),
);
} }
export function hexGreaterThan(a, b) { export function addEth(firstValue, ...otherValues) {
return conversionGreaterThan( return otherValues
{ value: a, fromNumericBase: 'hex' }, .reduce((numericAcc, ethAmount) => {
{ value: b, fromNumericBase: 'hex' }, return numericAcc.add(new Numeric(ethAmount, 10)).round(6);
); }, new Numeric(firstValue, 10))
.toString();
} }
export function getHexGasTotal({ gasLimit, gasPrice }) { export function addFiat(firstValue, ...otherValues) {
return addHexPrefix( return otherValues
multiplyCurrencies(gasLimit || '0x0', gasPrice || '0x0', { .reduce((numericAcc, fiatAmount) => {
toNumericBase: 'hex', return numericAcc.add(new Numeric(fiatAmount, 10)).round(2);
multiplicandBase: 16, }, new Numeric(firstValue, 10))
multiplierBase: 16, .toString();
}),
);
}
export function addEth(...args) {
return args.reduce((acc, ethAmount) => {
return addCurrencies(acc, ethAmount, {
toNumericBase: 'dec',
numberOfDecimals: 6,
aBase: 10,
bBase: 10,
});
});
}
export function addFiat(...args) {
return args.reduce((acc, fiatAmount) => {
return addCurrencies(acc, fiatAmount, {
toNumericBase: 'dec',
numberOfDecimals: 2,
aBase: 10,
bBase: 10,
});
});
} }
export function getTransactionFee({ export function getTransactionFee({
@ -67,15 +35,14 @@ export function getTransactionFee({
conversionRate, conversionRate,
numberOfDecimals, numberOfDecimals,
}) { }) {
return conversionUtil(value, { let fee = new Numeric(value, 16, EtherDenomination.WEI)
fromNumericBase: 'BN', .toDenomination(EtherDenomination.ETH)
toNumericBase: 'dec', .toBase(10);
fromDenomination: 'WEI',
fromCurrency, if (fromCurrency !== toCurrency && conversionRate) {
toCurrency, fee = fee.applyConversionRate(conversionRate);
numberOfDecimals, }
conversionRate, return fee.round(numberOfDecimals).toString();
});
} }
export function formatCurrency(value, currencyCode) { export function formatCurrency(value, currencyCode) {
@ -98,14 +65,13 @@ export function convertTokenToFiat({
}) { }) {
const totalExchangeRate = conversionRate * contractExchangeRate; const totalExchangeRate = conversionRate * contractExchangeRate;
return conversionUtil(value, { let tokenInFiat = new Numeric(value, 10);
fromNumericBase: 'dec',
toNumericBase: 'dec', if (fromCurrency !== toCurrency && totalExchangeRate) {
fromCurrency, tokenInFiat = tokenInFiat.applyConversionRate(totalExchangeRate);
toCurrency, }
numberOfDecimals: 2,
conversionRate: totalExchangeRate, return tokenInFiat.round(2).toString();
});
} }
export function hasUnconfirmedTransactions(state) { export function hasUnconfirmedTransactions(state) {

View File

@ -2,36 +2,6 @@ import { GAS_LIMITS } from '../../../shared/constants/gas';
import * as utils from './confirm-tx.util'; import * as utils from './confirm-tx.util';
describe('Confirm Transaction utils', () => { describe('Confirm Transaction utils', () => {
describe('increaseLastGasPrice', () => {
it('should increase the gasPrice by 10%', () => {
const increasedGasPrice = utils.increaseLastGasPrice('0xa');
expect(increasedGasPrice).toStrictEqual('0xb');
});
it('should prefix the result with 0x', () => {
const increasedGasPrice = utils.increaseLastGasPrice('a');
expect(increasedGasPrice).toStrictEqual('0xb');
});
});
describe('hexGreaterThan', () => {
it('should return true if the first value is greater than the second value', () => {
expect(utils.hexGreaterThan('0xb', '0xa')).toStrictEqual(true);
});
it('should return false if the first value is less than the second value', () => {
expect(utils.hexGreaterThan('0xa', '0xb')).toStrictEqual(false);
});
it('should return false if the first value is equal to the second value', () => {
expect(utils.hexGreaterThan('0xa', '0xa')).toStrictEqual(false);
});
it('should correctly compare prefixed and non-prefixed hex values', () => {
expect(utils.hexGreaterThan('0xb', 'a')).toStrictEqual(true);
});
});
describe('getHexGasTotal', () => { describe('getHexGasTotal', () => {
it('should multiply the hex gasLimit and hex gasPrice values together', () => { it('should multiply the hex gasLimit and hex gasPrice values together', () => {
expect( expect(

View File

@ -1,20 +1,19 @@
import { constant, times, uniq, zip } from 'lodash'; import { constant, times, uniq, zip } from 'lodash';
import BigNumber from 'bignumber.js'; import BigNumber from 'bignumber.js';
import { addHexPrefix } from 'ethereumjs-util';
import { import {
GAS_RECOMMENDATIONS, GAS_RECOMMENDATIONS,
EDIT_GAS_MODES, EDIT_GAS_MODES,
} from '../../../shared/constants/gas'; } from '../../../shared/constants/gas';
import { import { hexWEIToDecGWEI } from '../../../shared/modules/conversion.utils';
hexWEIToDecGWEI, import { Numeric } from '../../../shared/modules/Numeric';
multiplyCurrencies,
} from '../../../shared/modules/conversion.utils';
import { import {
bnGreaterThan, bnGreaterThan,
isNullish, isNullish,
roundToDecimalPlacesRemovingExtraZeroes, roundToDecimalPlacesRemovingExtraZeroes,
} from './util'; } from './util';
const TEN_PERCENT_NUMERIC = new Numeric(1.1, 10);
export const gasEstimateGreaterThanGasUsedPlusTenPercent = ( export const gasEstimateGreaterThanGasUsedPlusTenPercent = (
gasUsed, gasUsed,
gasFeeEstimates, gasFeeEstimates,
@ -30,29 +29,6 @@ export const gasEstimateGreaterThanGasUsedPlusTenPercent = (
return bnGreaterThan(maxFeePerGasFromEstimate, maxFeePerGasInTransaction); return bnGreaterThan(maxFeePerGasFromEstimate, maxFeePerGasInTransaction);
}; };
/**
* 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 | undefined} hexStringValue - hex value in wei to be incremented
* @param conversionOptions
* @returns {string | undefined} hex value in WEI 10% higher than the param.
*/
export function addTenPercent(hexStringValue, conversionOptions = {}) {
if (hexStringValue === undefined) {
return undefined;
}
return addHexPrefix(
multiplyCurrencies(hexStringValue, 1.1, {
toNumericBase: 'hex',
multiplicandBase: 16,
multiplierBase: 10,
numberOfDecimals: 0,
...conversionOptions,
}),
);
}
/** /**
* Simple helper to save on duplication to multiply the supplied wei hex string * Simple helper to save on duplication to multiply the supplied wei hex string
* by 1.10 to get bare minimum new gas fee. * by 1.10 to get bare minimum new gas fee.
@ -61,7 +37,13 @@ export function addTenPercent(hexStringValue, conversionOptions = {}) {
* @returns {string | undefined} hex value in WEI 10% higher than the param. * @returns {string | undefined} hex value in WEI 10% higher than the param.
*/ */
export function addTenPercentAndRound(hexStringValue) { export function addTenPercentAndRound(hexStringValue) {
return addTenPercent(hexStringValue, { numberOfDecimals: 0 }); if (hexStringValue === undefined) {
return undefined;
}
return new Numeric(hexStringValue, 16)
.times(TEN_PERCENT_NUMERIC)
.round(0)
.toPrefixedHexString();
} }
export function isMetamaskSuggestedGasEstimate(estimate) { export function isMetamaskSuggestedGasEstimate(estimate) {

View File

@ -1,7 +1,6 @@
import { PRIORITY_LEVELS } from '../../../shared/constants/gas'; import { PRIORITY_LEVELS } from '../../../shared/constants/gas';
import { import {
addTenPercent,
gasEstimateGreaterThanGasUsedPlusTenPercent, gasEstimateGreaterThanGasUsedPlusTenPercent,
formatGasFeeOrFeeRange, formatGasFeeOrFeeRange,
} from './gas'; } from './gas';
@ -38,17 +37,6 @@ describe('Gas utils', () => {
}); });
}); });
describe('addTenPercent', () => {
it('should add 10% to hex value passed', () => {
const result = addTenPercent('0x59682f00');
expect(result).toStrictEqual('0x62590080');
});
it('should return undefined if undefined value is passed', () => {
const result = addTenPercent(undefined);
expect(result).toBeUndefined();
});
});
describe('formatGasFeeOrFeeRange', () => { describe('formatGasFeeOrFeeRange', () => {
describe('given a singular fee', () => { describe('given a singular fee', () => {
it('should return a string "X GWEI" where X is the fee rounded to the given precision', () => { it('should return a string "X GWEI" where X is the fee rounded to the given precision', () => {

View File

@ -1,14 +1,11 @@
import log from 'loglevel'; import log from 'loglevel';
import {
conversionUtil,
multiplyCurrencies,
} from '../../../shared/modules/conversion.utils';
import { getTokenStandardAndDetails } from '../../store/actions'; import { getTokenStandardAndDetails } from '../../store/actions';
import { isEqualCaseInsensitive } from '../../../shared/modules/string-utils'; import { isEqualCaseInsensitive } from '../../../shared/modules/string-utils';
import { parseStandardTokenTransactionData } from '../../../shared/modules/transaction.utils'; import { parseStandardTokenTransactionData } from '../../../shared/modules/transaction.utils';
import { TokenStandard } from '../../../shared/constants/transaction'; import { TokenStandard } from '../../../shared/constants/transaction';
import { getTokenValueParam } from '../../../shared/lib/metamask-controller-utils'; import { getTokenValueParam } from '../../../shared/lib/metamask-controller-utils';
import { calcTokenAmount } from '../../../shared/lib/transactions-controller-utils'; import { calcTokenAmount } from '../../../shared/lib/transactions-controller-utils';
import { Numeric } from '../../../shared/modules/Numeric';
import * as util from './util'; import * as util from './util';
import { formatCurrency } from './confirm-tx.util'; import { formatCurrency } from './confirm-tx.util';
@ -189,21 +186,19 @@ export function getTokenFiatAmount(
return undefined; return undefined;
} }
const currentTokenToFiatRate = multiplyCurrencies( const currentTokenToFiatRate = new Numeric(contractExchangeRate, 10)
contractExchangeRate, .times(new Numeric(conversionRate, 10))
conversionRate, .toString();
{
multiplicandBase: 10, let currentTokenInFiat = new Numeric(tokenAmount, 10);
multiplierBase: 10,
}, if (tokenSymbol !== currentCurrency.toUpperCase() && currentTokenToFiatRate) {
); currentTokenInFiat = currentTokenInFiat.applyConversionRate(
const currentTokenInFiat = conversionUtil(tokenAmount, { currentTokenToFiatRate,
fromNumericBase: 'dec', );
fromCurrency: tokenSymbol, }
toCurrency: currentCurrency.toUpperCase(),
numberOfDecimals: 2, currentTokenInFiat = currentTokenInFiat.round(2).toString();
conversionRate: currentTokenToFiatRate,
});
let result; let result;
if (hideCurrencySymbol) { if (hideCurrencySymbol) {
result = formatCurrency(currentTokenInFiat, currentCurrency); result = formatCurrency(currentTokenInFiat, currentCurrency);

View File

@ -15,7 +15,7 @@ import {
TRUNCATED_NAME_CHAR_LIMIT, TRUNCATED_NAME_CHAR_LIMIT,
TRUNCATED_ADDRESS_END_CHARS, TRUNCATED_ADDRESS_END_CHARS,
} from '../../../shared/constants/labels'; } from '../../../shared/constants/labels';
import { toBigNumber } from '../../../shared/modules/conversion.utils'; import { Numeric } from '../../../shared/modules/Numeric';
// formatData :: ( date: <Unix Timestamp> ) -> String // formatData :: ( date: <Unix Timestamp> ) -> String
export function formatDate(date, format = "M/d/y 'at' T") { export function formatDate(date, format = "M/d/y 'at' T") {
@ -485,9 +485,10 @@ export function roundToDecimalPlacesRemovingExtraZeroes(
if (numberish === undefined || numberish === null) { if (numberish === undefined || numberish === null) {
return ''; return '';
} }
return toBigNumber return new Numeric(
.dec(toBigNumber.dec(numberish).toFixed(numberOfDecimalPlaces)) new Numeric(numberish, 10).toFixed(numberOfDecimalPlaces),
.toNumber(); 10,
).toNumber();
} }
/** /**

View File

@ -1,10 +1,6 @@
import { useSelector } from 'react-redux'; import { useSelector } from 'react-redux';
import { GAS_ESTIMATE_TYPES } from '../../../shared/constants/gas'; import { GAS_ESTIMATE_TYPES } from '../../../shared/constants/gas';
import {
conversionUtil,
multiplyCurrencies,
} from '../../../shared/modules/conversion.utils';
import { import {
getConversionRate, getConversionRate,
getNativeCurrency, getNativeCurrency,
@ -26,6 +22,8 @@ import {
getCustomMaxFeePerGas, getCustomMaxFeePerGas,
getCustomMaxPriorityFeePerGas, getCustomMaxPriorityFeePerGas,
} from '../../ducks/swaps/swaps'; } from '../../ducks/swaps/swaps';
import { Numeric } from '../../../shared/modules/Numeric';
import { EtherDenomination } from '../../../shared/constants/common';
// Why this number? // Why this number?
// 20 gwei * 21000 gasLimit = 420,000 gwei // 20 gwei * 21000 gasLimit = 420,000 gwei
@ -148,30 +146,15 @@ export const generateUseSelectorRouter =
return undefined; return undefined;
}; };
export function getTotalCostInETH(gwei, gasLimit) {
return multiplyCurrencies(gwei, gasLimit, {
fromDenomination: 'GWEI',
toDenomination: 'ETH',
multiplicandBase: 10,
multiplierBase: 10,
});
}
export function convertFromHexToFiat(value) { export function convertFromHexToFiat(value) {
const val = conversionUtil(value, { const val = new Numeric(value, 16).toBase(10).toString();
fromNumericBase: 'hex',
toNumericBase: 'dec',
fromDenomination: 'WEI',
});
return `$${(val * MOCK_ETH_USD_CONVERSION_RATE).toFixed(2)}`; return `$${(val * MOCK_ETH_USD_CONVERSION_RATE).toFixed(2)}`;
} }
export function convertFromHexToETH(value) { export function convertFromHexToETH(value) {
const val = conversionUtil(value, { const val = new Numeric(value, 16, EtherDenomination.WEI)
fromNumericBase: 'hex', .toBase(10)
toNumericBase: 'dec', .toDenomination(EtherDenomination.ETH);
fromDenomination: 'WEI',
});
return `${val} ETH`; return `${val} ETH`;
} }

View File

@ -1,11 +1,6 @@
import { useMemo } from 'react'; import { useMemo } from 'react';
import { shallowEqual, useSelector } from 'react-redux'; import { shallowEqual, useSelector } from 'react-redux';
import { GAS_ESTIMATE_TYPES, GAS_LIMITS } from '../../../shared/constants/gas'; import { GAS_ESTIMATE_TYPES, GAS_LIMITS } from '../../../shared/constants/gas';
import {
conversionLessThan,
conversionGreaterThan,
addHexes,
} from '../../../shared/modules/conversion.utils';
import { import {
checkNetworkAndAccountSupports1559, checkNetworkAndAccountSupports1559,
getSelectedAccount, getSelectedAccount,
@ -13,13 +8,13 @@ import {
import { isLegacyTransaction } from '../../helpers/utils/transactions.util'; import { isLegacyTransaction } from '../../helpers/utils/transactions.util';
import { bnGreaterThan, bnLessThan } from '../../helpers/utils/util'; import { bnGreaterThan, bnLessThan } from '../../helpers/utils/util';
import { GAS_FORM_ERRORS } from '../../helpers/constants/gas'; import { GAS_FORM_ERRORS } from '../../helpers/constants/gas';
import { Numeric } from '../../../shared/modules/Numeric';
const HIGH_FEE_WARNING_MULTIPLIER = 1.5; const HIGH_FEE_WARNING_MULTIPLIER = 1.5;
const validateGasLimit = (gasLimit, minimumGasLimit) => { const validateGasLimit = (gasLimit, minimumGasLimit) => {
const gasLimitTooLow = conversionLessThan( const gasLimitTooLow = new Numeric(gasLimit, 10).lessThan(
{ value: gasLimit, fromNumericBase: 'dec' }, new Numeric(minimumGasLimit || GAS_LIMITS.SIMPLE, 16),
{ value: minimumGasLimit || GAS_LIMITS.SIMPLE, fromNumericBase: 'hex' },
); );
if (gasLimitTooLow) { if (gasLimitTooLow) {
@ -139,15 +134,12 @@ const hasBalanceError = (minimumCostInHexWei, transaction, ethBalance) => {
if (minimumCostInHexWei === undefined || ethBalance === undefined) { if (minimumCostInHexWei === undefined || ethBalance === undefined) {
return false; return false;
} }
const minimumTxCostInHexWei = addHexes( const minimumTxCostInHexWei = new Numeric(minimumCostInHexWei, 16).add(
minimumCostInHexWei, new Numeric(transaction?.txParams?.value || '0x0', 16),
transaction?.txParams?.value || '0x0',
); );
const ethBalanceInHexWei = new Numeric(ethBalance, 16);
return conversionGreaterThan( return minimumTxCostInHexWei.greaterThan(ethBalanceInHexWei);
{ value: minimumTxCostInHexWei, fromNumericBase: 'hex' },
{ value: ethBalance, fromNumericBase: 'hex' },
);
}; };
/** /**

View File

@ -2,10 +2,6 @@ import { useCallback } from 'react';
import { useDispatch } from 'react-redux'; import { useDispatch } from 'react-redux';
import { EDIT_GAS_MODES, PRIORITY_LEVELS } from '../../../shared/constants/gas'; import { EDIT_GAS_MODES, PRIORITY_LEVELS } from '../../../shared/constants/gas';
import {
decGWEIToHexWEI,
decimalToHex,
} from '../../../shared/modules/conversion.utils';
import { import {
addTenPercentAndRound, addTenPercentAndRound,
editGasModeIsSpeedUpOrCancel, editGasModeIsSpeedUpOrCancel,
@ -18,6 +14,10 @@ import {
updateSwapsUserFeeLevel, updateSwapsUserFeeLevel,
updateTransactionGasFees, updateTransactionGasFees,
} from '../../store/actions'; } from '../../store/actions';
import {
decGWEIToHexWEI,
decimalToHex,
} from '../../../shared/modules/conversion.utils';
/** /**
* @typedef {object} TransactionFunctionsReturnType * @typedef {object} TransactionFunctionsReturnType

View File

@ -7,11 +7,10 @@ import {
getNativeCurrency, getNativeCurrency,
} from '../ducks/metamask/metamask'; } from '../ducks/metamask/metamask';
import { import { getValueFromWeiHex } from '../../shared/modules/conversion.utils';
conversionUtil,
getValueFromWeiHex,
} from '../../shared/modules/conversion.utils';
import { TEST_NETWORK_TICKER_MAP } from '../../shared/constants/network'; import { TEST_NETWORK_TICKER_MAP } from '../../shared/constants/network';
import { Numeric } from '../../shared/modules/Numeric';
import { EtherDenomination } from '../../shared/constants/common';
/** /**
* Defines the shape of the options parameter for useCurrencyDisplay * Defines the shape of the options parameter for useCurrencyDisplay
@ -61,13 +60,11 @@ export function useCurrencyDisplay(
currency === nativeCurrency || currency === nativeCurrency ||
(!isUserPreferredCurrency && !nativeCurrency) (!isUserPreferredCurrency && !nativeCurrency)
) { ) {
return conversionUtil(inputValue, { return new Numeric(inputValue, 16, EtherDenomination.WEI)
fromNumericBase: 'hex', .toDenomination(denomination || EtherDenomination.ETH)
toNumericBase: 'dec', .round(numberOfDecimals || 2)
fromDenomination: 'WEI', .toBase(10)
numberOfDecimals: numberOfDecimals || 2, .toString();
toDenomination: denomination,
});
} else if (isUserPreferredCurrency && conversionRate) { } else if (isUserPreferredCurrency && conversionRate) {
return formatCurrency( return formatCurrency(
getValueFromWeiHex({ getValueFromWeiHex({

View File

@ -2,7 +2,7 @@ import BigNumber from 'bignumber.js';
import { useMemo } from 'react'; import { useMemo } from 'react';
import { decGWEIToHexWEI } from '../../shared/modules/conversion.utils'; import { decGWEIToHexWEI } from '../../shared/modules/conversion.utils';
import { isEIP1559Transaction } from '../../shared/modules/transaction.utils'; import { isEIP1559Transaction } from '../../shared/modules/transaction.utils';
import { addTenPercent } from '../helpers/utils/gas'; import { addTenPercentAndRound } from '../helpers/utils/gas';
import { useGasFeeEstimates } from './useGasFeeEstimates'; import { useGasFeeEstimates } from './useGasFeeEstimates';
/** /**
@ -15,7 +15,7 @@ import { useGasFeeEstimates } from './useGasFeeEstimates';
* @returns {string} hexWei value of the higher of the two inputs. * @returns {string} hexWei value of the higher of the two inputs.
*/ */
function getHighestIncrementedFee(originalFee, currentEstimate) { function getHighestIncrementedFee(originalFee, currentEstimate) {
const buffedOriginalHexWei = addTenPercent(originalFee); const buffedOriginalHexWei = addTenPercentAndRound(originalFee);
const currentEstimateHexWei = decGWEIToHexWEI(currentEstimate); const currentEstimateHexWei = decGWEIToHexWEI(currentEstimate);
return new BigNumber(buffedOriginalHexWei, 16).greaterThan( return new BigNumber(buffedOriginalHexWei, 16).greaterThan(

View File

@ -11,7 +11,8 @@ import { PageContainerFooter } from '../../components/ui/page-container';
import { EVENT } from '../../../shared/constants/metametrics'; import { EVENT } from '../../../shared/constants/metametrics';
import { SECOND } from '../../../shared/constants/time'; import { SECOND } from '../../../shared/constants/time';
import { conversionUtil } from '../../../shared/modules/conversion.utils'; import { Numeric } from '../../../shared/modules/Numeric';
import { EtherDenomination } from '../../../shared/constants/common';
export default class ConfirmDecryptMessage extends Component { export default class ConfirmDecryptMessage extends Component {
static contextTypes = { static contextTypes = {
@ -98,13 +99,14 @@ export default class ConfirmDecryptMessage extends Component {
} = this.state; } = this.state;
const { t } = this.context; const { t } = this.context;
const nativeCurrencyBalance = conversionUtil(balance, { const nativeCurrencyBalance = new Numeric(
fromNumericBase: 'hex', balance,
toNumericBase: 'dec', 16,
fromDenomination: 'WEI', EtherDenomination.WEI,
numberOfDecimals: 6, )
conversionRate, .applyConversionRate(conversionRate)
}); .round(6)
.toBase(10);
return ( return (
<div className="request-decrypt-message__balance"> <div className="request-decrypt-message__balance">

View File

@ -6,8 +6,9 @@ import Identicon from '../../components/ui/identicon';
import { PageContainerFooter } from '../../components/ui/page-container'; import { PageContainerFooter } from '../../components/ui/page-container';
import { EVENT } from '../../../shared/constants/metametrics'; import { EVENT } from '../../../shared/constants/metametrics';
import { conversionUtil } from '../../../shared/modules/conversion.utils';
import SiteOrigin from '../../components/ui/site-origin'; import SiteOrigin from '../../components/ui/site-origin';
import { Numeric } from '../../../shared/modules/Numeric';
import { EtherDenomination } from '../../../shared/constants/common';
export default class ConfirmEncryptionPublicKey extends Component { export default class ConfirmEncryptionPublicKey extends Component {
static contextTypes = { static contextTypes = {
@ -74,13 +75,14 @@ export default class ConfirmEncryptionPublicKey extends Component {
} = this.props; } = this.props;
const { t } = this.context; const { t } = this.context;
const nativeCurrencyBalance = conversionUtil(balance, { const nativeCurrencyBalance = new Numeric(
fromNumericBase: 'hex', balance,
toNumericBase: 'dec', 16,
fromDenomination: 'WEI', EtherDenomination.WEI,
numberOfDecimals: 6, )
conversionRate, .applyConversionRate(conversionRate)
}); .round(6)
.toBase(10);
return ( return (
<div className="request-encryption-public-key__balance"> <div className="request-encryption-public-key__balance">

View File

@ -67,12 +67,12 @@ import {
CHAIN_ID_TO_NETWORK_ID_MAP, CHAIN_ID_TO_NETWORK_ID_MAP,
///: END:ONLY_INCLUDE_IN ///: END:ONLY_INCLUDE_IN
} from '../../../shared/constants/network'; } from '../../../shared/constants/network';
import TransactionAlerts from '../../components/app/transaction-alerts';
import { import {
addHexes, addHexes,
hexToDecimal, hexToDecimal,
hexWEIToDecGWEI, hexWEIToDecGWEI,
} from '../../../shared/modules/conversion.utils'; } from '../../../shared/modules/conversion.utils';
import TransactionAlerts from '../../components/app/transaction-alerts';
const renderHeartBeatIfNotInTest = () => const renderHeartBeatIfNotInTest = () =>
process.env.IN_TEST ? null : <LoadingHeartBeat />; process.env.IN_TEST ? null : <LoadingHeartBeat />;

View File

@ -1,31 +1,25 @@
import {
conversionUtil,
multiplyCurrencies,
} from '../../../shared/modules/conversion.utils';
import { addHexPrefix } from '../../../app/scripts/lib/util';
import { MIN_GAS_LIMIT_HEX } from '../../../shared/constants/gas'; import { MIN_GAS_LIMIT_HEX } from '../../../shared/constants/gas';
import { Numeric } from '../../../shared/modules/Numeric';
import { EtherDenomination } from '../../../shared/constants/common';
const MIN_GAS_PRICE_DEC = '0'; const MIN_GAS_PRICE_DEC = '0';
const MIN_GAS_PRICE_HEX = parseInt(MIN_GAS_PRICE_DEC, 10).toString(16); const MIN_GAS_PRICE_HEX = parseInt(MIN_GAS_PRICE_DEC, 10).toString(16);
const MIN_GAS_LIMIT_DEC = '21000'; const MIN_GAS_LIMIT_DEC = new Numeric('21000', 10);
const MAX_GAS_LIMIT_DEC = '7920027'; const MAX_GAS_LIMIT_DEC = '7920027';
const HIGH_FEE_WARNING_MULTIPLIER = 1.5; const HIGH_FEE_WARNING_MULTIPLIER = 1.5;
const MIN_GAS_PRICE_GWEI = addHexPrefix( const MIN_GAS_PRICE_GWEI = new Numeric(
conversionUtil(MIN_GAS_PRICE_HEX, { MIN_GAS_PRICE_HEX,
fromDenomination: 'WEI', 16,
toDenomination: 'GWEI', EtherDenomination.WEI,
fromNumericBase: 'hex', )
toNumericBase: 'hex', .toDenomination(EtherDenomination.GWEI)
numberOfDecimals: 1, .round(1)
}), .toPrefixedHexString();
);
const MIN_GAS_TOTAL = multiplyCurrencies(MIN_GAS_LIMIT_HEX, MIN_GAS_PRICE_HEX, { const MIN_GAS_TOTAL = new Numeric(MIN_GAS_LIMIT_HEX, 16)
toNumericBase: 'hex', .times(new Numeric(MIN_GAS_PRICE_HEX, 16, EtherDenomination.WEI))
multiplicandBase: 16, .toPrefixedHexString();
multiplierBase: 16,
});
const TOKEN_TRANSFER_FUNCTION_SIGNATURE = '0xa9059cbb'; const TOKEN_TRANSFER_FUNCTION_SIGNATURE = '0xa9059cbb';
const COLLECTIBLE_TRANSFER_FROM_FUNCTION_SIGNATURE = '0x23b872dd'; const COLLECTIBLE_TRANSFER_FROM_FUNCTION_SIGNATURE = '0x23b872dd';

View File

@ -1,16 +1,8 @@
import abi from 'ethereumjs-abi'; import abi from 'ethereumjs-abi';
import {
addCurrencies,
conversionUtil,
conversionGTE,
multiplyCurrencies,
conversionGreaterThan,
conversionLessThan,
} from '../../../shared/modules/conversion.utils';
import { addHexPrefix } from '../../../app/scripts/lib/util'; import { addHexPrefix } from '../../../app/scripts/lib/util';
import { TokenStandard } from '../../../shared/constants/transaction'; import { TokenStandard } from '../../../shared/constants/transaction';
import { calcTokenAmount } from '../../../shared/lib/transactions-controller-utils'; import { Numeric } from '../../../shared/modules/Numeric';
import { import {
TOKEN_TRANSFER_FUNCTION_SIGNATURE, TOKEN_TRANSFER_FUNCTION_SIGNATURE,
COLLECTIBLE_TRANSFER_FROM_FUNCTION_SIGNATURE, COLLECTIBLE_TRANSFER_FROM_FUNCTION_SIGNATURE,
@ -33,46 +25,22 @@ function isBalanceSufficient({
gasTotal = '0x0', gasTotal = '0x0',
primaryCurrency, primaryCurrency,
}) { }) {
const totalAmount = addCurrencies(amount, gasTotal, { let totalAmount = new Numeric(amount, 16).add(new Numeric(gasTotal, 16));
aBase: 16, let balanceNumeric = new Numeric(balance, 16);
bBase: 16,
toNumericBase: 'hex',
});
const balanceIsSufficient = conversionGTE( if (typeof primaryCurrency !== 'undefined' && primaryCurrency !== null) {
{ totalAmount = totalAmount.applyConversionRate(conversionRate);
value: balance, balanceNumeric = balanceNumeric.applyConversionRate(conversionRate);
fromNumericBase: 'hex', }
fromCurrency: primaryCurrency,
conversionRate,
},
{
value: totalAmount,
fromNumericBase: 'hex',
conversionRate,
fromCurrency: primaryCurrency,
},
);
return balanceIsSufficient; return balanceNumeric.greaterThanOrEqualTo(totalAmount);
} }
function isTokenBalanceSufficient({ amount = '0x0', tokenBalance, decimals }) { function isTokenBalanceSufficient({ amount = '0x0', tokenBalance, decimals }) {
const amountInDec = conversionUtil(amount, { const amountNumeric = new Numeric(amount, 16).shiftedBy(decimals);
fromNumericBase: 'hex', const tokenBalanceNumeric = new Numeric(tokenBalance, 16);
});
const tokenBalanceIsSufficient = conversionGTE( return tokenBalanceNumeric.greaterThanOrEqualTo(amountNumeric);
{
value: tokenBalance,
fromNumericBase: 'hex',
},
{
value: calcTokenAmount(amountInDec, decimals),
},
);
return tokenBalanceIsSufficient;
} }
function addGasBuffer( function addGasBuffer(
@ -80,43 +48,25 @@ function addGasBuffer(
blockGasLimitHex, blockGasLimitHex,
bufferMultiplier = 1.5, bufferMultiplier = 1.5,
) { ) {
const upperGasLimit = multiplyCurrencies(blockGasLimitHex, 0.9, { const initialGasLimit = new Numeric(initialGasLimitHex, 16);
toNumericBase: 'hex', const upperGasLimit = new Numeric(blockGasLimitHex, 16)
multiplicandBase: 16, .times(new Numeric(0.9, 10))
multiplierBase: 10, .round(0);
numberOfDecimals: '0',
}); const bufferedGasLimit = initialGasLimit
const bufferedGasLimit = multiplyCurrencies( .times(new Numeric(bufferMultiplier, 10))
initialGasLimitHex, .round(0);
bufferMultiplier,
{
toNumericBase: 'hex',
multiplicandBase: 16,
multiplierBase: 10,
numberOfDecimals: '0',
},
);
// if initialGasLimit is above blockGasLimit, dont modify it // if initialGasLimit is above blockGasLimit, dont modify it
if ( if (initialGasLimit.greaterThanOrEqualTo(upperGasLimit)) {
conversionGreaterThan(
{ value: initialGasLimitHex, fromNumericBase: 'hex' },
{ value: upperGasLimit, fromNumericBase: 'hex' },
)
) {
return initialGasLimitHex; return initialGasLimitHex;
} }
// if bufferedGasLimit is below blockGasLimit, use bufferedGasLimit // if bufferedGasLimit is below blockGasLimit, use bufferedGasLimit
if ( if (bufferedGasLimit.lessThan(upperGasLimit)) {
conversionLessThan( return bufferedGasLimit.toString();
{ value: bufferedGasLimit, fromNumericBase: 'hex' },
{ value: upperGasLimit, fromNumericBase: 'hex' },
)
) {
return bufferedGasLimit;
} }
// otherwise use blockGasLimit // otherwise use blockGasLimit
return upperGasLimit; return upperGasLimit.toString();
} }
function generateERC20TransferData({ function generateERC20TransferData({

View File

@ -1,11 +1,5 @@
import { rawEncode } from 'ethereumjs-abi'; import { rawEncode } from 'ethereumjs-abi';
import {
addCurrencies,
conversionGTE,
conversionUtil,
} from '../../../shared/modules/conversion.utils';
import { import {
generateERC20TransferData, generateERC20TransferData,
isBalanceSufficient, isBalanceSufficient,
@ -13,35 +7,6 @@ import {
ellipsify, ellipsify,
} from './send.utils'; } from './send.utils';
jest.mock('../../../shared/modules/conversion.utils', () => ({
addCurrencies: jest.fn((a, b) => {
let [a1, b1] = [a, b];
if (String(a).match(/^0x.+/u)) {
a1 = Number(String(a).slice(2));
}
if (String(b).match(/^0x.+/u)) {
b1 = Number(String(b).slice(2));
}
return a1 + b1;
}),
conversionUtil: jest.fn((val) => parseInt(val, 16)),
conversionGTE: jest.fn((obj1, obj2) => obj1.value >= obj2.value),
multiplyCurrencies: jest.fn((a, b) => `${a}x${b}`),
conversionGreaterThan: (obj1, obj2) => obj1.value > obj2.value,
conversionLessThan: (obj1, obj2) => obj1.value < obj2.value,
}));
jest.mock('../../../shared/lib/transactions-controller-utils', () => {
const originalModule = jest.requireActual(
'../../../shared/lib/transactions-controller-utils',
);
return {
...originalModule,
calcTokenAmount: (a, d) => `calc:${a}${d}`,
};
});
jest.mock('ethereumjs-abi', () => ({ jest.mock('ethereumjs-abi', () => ({
rawEncode: jest.fn().mockReturnValue(16, 1100), rawEncode: jest.fn().mockReturnValue(16, 1100),
})); }));
@ -84,7 +49,7 @@ describe('send utils', () => {
}); });
describe('isBalanceSufficient()', () => { describe('isBalanceSufficient()', () => {
it('should correctly call addCurrencies and return the result of calling conversionGTE', () => { it('should correctly sum the appropriate currencies and ensure that balance is greater', () => {
const result = isBalanceSufficient({ const result = isBalanceSufficient({
amount: 15, amount: 15,
balance: 100, balance: 100,
@ -92,53 +57,29 @@ describe('send utils', () => {
gasTotal: 17, gasTotal: 17,
primaryCurrency: 'ABC', primaryCurrency: 'ABC',
}); });
expect(addCurrencies).toHaveBeenCalledWith(15, 17, {
aBase: 16,
bBase: 16,
toNumericBase: 'hex',
});
expect(conversionGTE).toHaveBeenCalledWith(
{
value: 100,
fromNumericBase: 'hex',
fromCurrency: 'ABC',
conversionRate: 3,
},
{
value: 32,
fromNumericBase: 'hex',
conversionRate: 3,
fromCurrency: 'ABC',
},
);
expect(result).toStrictEqual(true); expect(result).toStrictEqual(true);
}); });
}); });
describe('isTokenBalanceSufficient()', () => { describe('isTokenBalanceSufficient()', () => {
it('should correctly call conversionUtil and return the result of calling conversionGTE', () => { it('should return true for a sufficient balance for token spend', () => {
const result = isTokenBalanceSufficient({ const result = isTokenBalanceSufficient({
amount: '0x10', amount: '0x10',
tokenBalance: 123, tokenBalance: 123,
decimals: 10, decimals: 10,
}); });
expect(conversionUtil).toHaveBeenCalledWith('0x10', { expect(result).toStrictEqual(true);
fromNumericBase: 'hex', });
it('should return false for an insufficient balance for token spend', () => {
const result = isTokenBalanceSufficient({
amount: '0x10000',
tokenBalance: 123,
decimals: 10,
}); });
expect(conversionGTE).toHaveBeenCalledWith( expect(result).toStrictEqual(true);
{
value: 123,
fromNumericBase: 'hex',
},
{
value: 'calc:1610',
},
);
expect(result).toStrictEqual(false);
}); });
}); });

View File

@ -1,9 +1,5 @@
import { addHexPrefix } from '../../app/scripts/lib/util'; import { addHexPrefix } from '../../app/scripts/lib/util';
import { import { decEthToConvertedCurrency } from '../../shared/modules/conversion.utils';
conversionUtil,
conversionGreaterThan,
decEthToConvertedCurrency,
} from '../../shared/modules/conversion.utils';
import { formatCurrency } from '../helpers/utils/confirm-tx.util'; import { formatCurrency } from '../helpers/utils/confirm-tx.util';
import { formatETHFee } from '../helpers/utils/formatters'; import { formatETHFee } from '../helpers/utils/formatters';
@ -15,6 +11,8 @@ import {
isEIP1559Network, isEIP1559Network,
} from '../ducks/metamask/metamask'; } from '../ducks/metamask/metamask';
import { calcGasTotal } from '../../shared/lib/transactions-controller-utils'; import { calcGasTotal } from '../../shared/lib/transactions-controller-utils';
import { Numeric } from '../../shared/modules/Numeric';
import { EtherDenomination } from '../../shared/constants/common';
import { getIsMainnet } from '.'; import { getIsMainnet } from '.';
export function getCustomGasLimit(state) { export function getCustomGasLimit(state) {
@ -91,15 +89,9 @@ export function isCustomPriceSafe(state) {
return false; return false;
} }
const customPriceSafe = conversionGreaterThan( const customPriceSafe = new Numeric(customGasPrice, 16, EtherDenomination.WEI)
{ .toDenomination(EtherDenomination.GWEI)
value: customGasPrice, .greaterThan(safeLow, 10);
fromNumericBase: 'hex',
fromDenomination: 'WEI',
toDenomination: 'GWEI',
},
{ value: safeLow, fromNumericBase: 'dec' },
);
return customPriceSafe; return customPriceSafe;
} }
@ -117,15 +109,9 @@ export function isCustomPriceSafeForCustomNetwork(state) {
return false; return false;
} }
const customPriceSafe = conversionGreaterThan( const customPriceSafe = new Numeric(customGasPrice, 16, EtherDenomination.WEI)
{ .toDenomination(EtherDenomination.GWEI)
value: customGasPrice, .greaterThan(estimatedPrice, 10);
fromNumericBase: 'hex',
fromDenomination: 'WEI',
toDenomination: 'GWEI',
},
{ value: estimatedPrice, fromNumericBase: 'dec' },
);
return customPriceSafe; return customPriceSafe;
} }
@ -139,18 +125,13 @@ export function isCustomPriceExcessive(state, checkSend = false) {
} }
// Custom gas should be considered excessive when it is 1.5 times greater than the fastest estimate. // Custom gas should be considered excessive when it is 1.5 times greater than the fastest estimate.
const customPriceExcessive = conversionGreaterThan( const customPriceExcessive = new Numeric(
{ customPrice,
value: customPrice, 16,
fromNumericBase: 'hex', EtherDenomination.WEI,
fromDenomination: 'WEI', )
toDenomination: 'GWEI', .toDenomination(EtherDenomination.GWEI)
}, .greaterThan(Math.floor(fastPrice * 1.5), 10);
{
fromNumericBase: 'dec',
value: Math.floor(fastPrice * 1.5),
},
);
return customPriceExcessive; return customPriceExcessive;
} }
@ -160,12 +141,14 @@ export function basicPriceEstimateToETHTotal(
gasLimit, gasLimit,
numberOfDecimals = 9, numberOfDecimals = 9,
) { ) {
return conversionUtil(calcGasTotal(gasLimit, estimate), { return new Numeric(
fromNumericBase: 'hex', calcGasTotal(gasLimit, estimate),
toNumericBase: 'dec', 16,
fromDenomination: 'GWEI', EtherDenomination.GWEI,
numberOfDecimals, )
}); .round(numberOfDecimals)
.toBase(10)
.toString();
} }
export function getRenderableEthFee( export function getRenderableEthFee(
@ -174,10 +157,7 @@ export function getRenderableEthFee(
numberOfDecimals = 9, numberOfDecimals = 9,
nativeCurrency = 'ETH', nativeCurrency = 'ETH',
) { ) {
const value = conversionUtil(estimate, { const value = new Numeric(estimate, 10).toBase(16).toString();
fromNumericBase: 'dec',
toNumericBase: 'hex',
});
const fee = basicPriceEstimateToETHTotal(value, gasLimit, numberOfDecimals); const fee = basicPriceEstimateToETHTotal(value, gasLimit, numberOfDecimals);
return formatETHFee(fee, nativeCurrency); return formatETHFee(fee, nativeCurrency);
} }
@ -188,10 +168,7 @@ export function getRenderableConvertedCurrencyFee(
convertedCurrency, convertedCurrency,
conversionRate, conversionRate,
) { ) {
const value = conversionUtil(estimate, { const value = new Numeric(estimate, 10).toBase(16).toString();
fromNumericBase: 'dec',
toNumericBase: 'hex',
});
const fee = basicPriceEstimateToETHTotal(value, gasLimit); const fee = basicPriceEstimateToETHTotal(value, gasLimit);
const feeInCurrency = decEthToConvertedCurrency( const feeInCurrency = decEthToConvertedCurrency(
fee, fee,
@ -202,20 +179,14 @@ export function getRenderableConvertedCurrencyFee(
} }
export function priceEstimateToWei(priceEstimate) { export function priceEstimateToWei(priceEstimate) {
return conversionUtil(priceEstimate, { return new Numeric(priceEstimate, 16, EtherDenomination.GWEI)
fromNumericBase: 'hex', .toDenomination(EtherDenomination.WEI)
toNumericBase: 'hex', .round(9)
fromDenomination: 'GWEI', .toString();
toDenomination: 'WEI',
numberOfDecimals: 9,
});
} }
export function getGasPriceInHexWei(price) { export function getGasPriceInHexWei(price) {
const value = conversionUtil(price, { const value = new Numeric(price, 10).toBase(16).toString();
fromNumericBase: 'dec',
toNumericBase: 'hex',
});
return addHexPrefix(priceEstimateToWei(value)); return addHexPrefix(priceEstimateToWei(value));
} }