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

Refactor usages of conversion util in the app folder and shared folder in favor of Numeric (#17331)

This commit is contained in:
Brad Decker 2023-01-23 11:41:01 -06:00 committed by GitHub
parent 213240349d
commit ead1446c98
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 95 additions and 139 deletions

View File

@ -5,9 +5,7 @@ import { ObservableStore } from '@metamask/obs-store';
import { mapValues, cloneDeep } from 'lodash'; import { mapValues, cloneDeep } from 'lodash';
import abi from 'human-standard-token-abi'; import abi from 'human-standard-token-abi';
import { import {
conversionUtil,
decGWEIToHexWEI, decGWEIToHexWEI,
addCurrencies,
sumHexes, sumHexes,
} from '../../../shared/modules/conversion.utils'; } from '../../../shared/modules/conversion.utils';
import { import {
@ -40,6 +38,8 @@ import {
} from '../../../shared/lib/transactions-controller-utils'; } from '../../../shared/lib/transactions-controller-utils';
import fetchEstimatedL1Fee from '../../../ui/helpers/utils/optimism/fetchEstimatedL1Fee'; import fetchEstimatedL1Fee from '../../../ui/helpers/utils/optimism/fetchEstimatedL1Fee';
import { Numeric } from '../../../shared/modules/Numeric';
import { EtherDenomination } from '../../../shared/constants/common';
import { NETWORK_EVENTS } from './network'; import { NETWORK_EVENTS } from './network';
// The MAX_GAS_LIMIT is a number that is higher than the maximum gas costs we have observed on any aggregator // The MAX_GAS_LIMIT is a number that is higher than the maximum gas costs we have observed on any aggregator
@ -687,17 +687,22 @@ export default class SwapsController {
estimatedBaseFee, estimatedBaseFee,
} = gasFeeEstimates; } = gasFeeEstimates;
usedGasPrice = addCurrencies( const suggestedMaxPriorityFeePerGasInHexWEI = decGWEIToHexWEI(
customMaxPriorityFeePerGas || // Is already in hex WEI. suggestedMaxPriorityFeePerGas,
decGWEIToHexWEI(suggestedMaxPriorityFeePerGas),
decGWEIToHexWEI(estimatedBaseFee),
{
aBase: 16,
bBase: 16,
toNumericBase: 'hex',
numberOfDecimals: 6,
},
); );
const estimatedBaseFeeNumeric = new Numeric(
estimatedBaseFee,
10,
EtherDenomination.GWEI,
).toDenomination(EtherDenomination.WEI);
usedGasPrice = new Numeric(
customMaxPriorityFeePerGas || suggestedMaxPriorityFeePerGasInHexWEI,
16,
)
.add(estimatedBaseFeeNumeric)
.round(6)
.toString();
} else if (gasEstimateType === GAS_ESTIMATE_TYPES.LEGACY) { } else if (gasEstimateType === GAS_ESTIMATE_TYPES.LEGACY) {
usedGasPrice = customGasPrice || decGWEIToHexWEI(gasFeeEstimates.high); usedGasPrice = customGasPrice || decGWEIToHexWEI(gasFeeEstimates.high);
} else if (gasEstimateType === GAS_ESTIMATE_TYPES.ETH_GASPRICE) { } else if (gasEstimateType === GAS_ESTIMATE_TYPES.ETH_GASPRICE) {
@ -747,34 +752,25 @@ export default class SwapsController {
// It always includes any external fees charged by the quote source. In // It always includes any external fees charged by the quote source. In
// addition, if the source asset is the selected chain's default token, trade.value // addition, if the source asset is the selected chain's default token, trade.value
// includes the amount of that token. // includes the amount of that token.
const totalWeiCost = new BigNumber(gasTotalInWeiHex, 16).plus( const totalWeiCost = new Numeric(
trade.value, gasTotalInWeiHex,
16, 16,
); EtherDenomination.WEI,
).add(new Numeric(trade.value, 16, EtherDenomination.WEI));
const totalEthCost = conversionUtil(totalWeiCost, { const totalEthCost = totalWeiCost
fromCurrency: 'ETH', .toDenomination(EtherDenomination.ETH)
fromDenomination: 'WEI', .round(6).value;
toDenomination: 'ETH',
fromNumericBase: 'BN',
numberOfDecimals: 6,
});
// The total fee is aggregator/exchange fees plus gas fees. // The total fee is aggregator/exchange fees plus gas fees.
// If the swap is from the selected chain's default token, subtract // If the swap is from the selected chain's default token, subtract
// the sourceAmount from the total cost. Otherwise, the total fee // the sourceAmount from the total cost. Otherwise, the total fee
// is simply trade.value plus gas fees. // is simply trade.value plus gas fees.
const ethFee = isSwapsDefaultTokenAddress(sourceToken, chainId) const ethFee = isSwapsDefaultTokenAddress(sourceToken, chainId)
? conversionUtil( ? totalWeiCost
totalWeiCost.minus(sourceAmount, 10), // sourceAmount is in wei .minus(new Numeric(sourceAmount, 10))
{ .toDenomination(EtherDenomination.ETH)
fromCurrency: 'ETH', .round(6).value
fromDenomination: 'WEI',
toDenomination: 'ETH',
fromNumericBase: 'BN',
numberOfDecimals: 6,
},
)
: totalEthCost; : totalEthCost;
const decimalAdjustedDestinationAmount = calcTokenAmount( const decimalAdjustedDestinationAmount = calcTokenAmount(

View File

@ -35,7 +35,6 @@ import {
import { import {
bnToHex, bnToHex,
decGWEIToHexWEI, decGWEIToHexWEI,
decimalToHex,
hexWEIToDecETH, hexWEIToDecETH,
hexWEIToDecGWEI, hexWEIToDecGWEI,
} from '../../../../shared/modules/conversion.utils'; } from '../../../../shared/modules/conversion.utils';
@ -58,6 +57,7 @@ import {
getSwapsTokensReceivedFromTxMeta, getSwapsTokensReceivedFromTxMeta,
TRANSACTION_ENVELOPE_TYPE_NAMES, TRANSACTION_ENVELOPE_TYPE_NAMES,
} from '../../../../shared/lib/transactions-controller-utils'; } from '../../../../shared/lib/transactions-controller-utils';
import { Numeric } from '../../../../shared/modules/Numeric';
import TransactionStateManager from './tx-state-manager'; import TransactionStateManager from './tx-state-manager';
import TxGasUtil from './tx-gas-utils'; import TxGasUtil from './tx-gas-utils';
import PendingTransactionTracker from './pending-tx-tracker'; import PendingTransactionTracker from './pending-tx-tracker';
@ -1463,7 +1463,7 @@ export default class TransactionController extends EventEmitter {
...normalizedTxParams, ...normalizedTxParams,
type, type,
gasLimit: normalizedTxParams.gas, gasLimit: normalizedTxParams.gas,
chainId: addHexPrefix(decimalToHex(chainId)), chainId: new Numeric(chainId, 10).toPrefixedHexString(),
}; };
// sign tx // sign tx
const fromAddress = txParams.from; const fromAddress = txParams.from;

View File

@ -0,0 +1,8 @@
import { calcGasTotal } from './transactions-controller-utils';
describe('calcGasTotal()', () => {
it('should correctly compute gasTotal', () => {
const result = calcGasTotal(12, 15);
expect(result).toStrictEqual('17a');
});
});

View File

@ -1,9 +1,7 @@
import BigNumber from 'bignumber.js'; import BigNumber from 'bignumber.js';
import { EtherDenomination } from '../constants/common';
import { TransactionEnvelopeType } from '../constants/transaction'; import { TransactionEnvelopeType } from '../constants/transaction';
import { import { Numeric } from '../modules/Numeric';
multiplyCurrencies,
subtractCurrencies,
} from '../modules/conversion.utils';
import { isSwapsDefaultTokenSymbol } from '../modules/swaps.utils'; import { isSwapsDefaultTokenSymbol } from '../modules/swaps.utils';
const TOKEN_TRANSFER_LOG_TOPIC_HASH = const TOKEN_TRANSFER_LOG_TOPIC_HASH =
@ -14,11 +12,7 @@ export const TRANSACTION_NO_CONTRACT_ERROR_KEY = 'transactionErrorNoContract';
export const TEN_SECONDS_IN_MILLISECONDS = 10_000; export const TEN_SECONDS_IN_MILLISECONDS = 10_000;
export function calcGasTotal(gasLimit = '0', gasPrice = '0') { export function calcGasTotal(gasLimit = '0', gasPrice = '0') {
return multiplyCurrencies(gasLimit, gasPrice, { return new Numeric(gasLimit, 16).times(new Numeric(gasPrice, 16)).toString();
toNumericBase: 'hex',
multiplicandBase: 16,
multiplierBase: 16,
});
} }
/** /**
@ -69,13 +63,16 @@ export function getSwapsTokensReceivedFromTxMeta(
return txMeta.swapMetaData.token_to_amount; return txMeta.swapMetaData.token_to_amount;
} }
let approvalTxGasCost = '0x0'; let approvalTxGasCost = new Numeric('0x0', 16);
if (approvalTxMeta && approvalTxMeta.txReceipt) { if (approvalTxMeta && approvalTxMeta.txReceipt) {
approvalTxGasCost = calcGasTotal( approvalTxGasCost = new Numeric(
approvalTxMeta.txReceipt.gasUsed, calcGasTotal(
networkAndAccountSupports1559 approvalTxMeta.txReceipt.gasUsed,
? approvalTxMeta.txReceipt.effectiveGasPrice // Base fee + priority fee. networkAndAccountSupports1559
: approvalTxMeta.txParams.gasPrice, ? approvalTxMeta.txReceipt.effectiveGasPrice // Base fee + priority fee.
: approvalTxMeta.txParams.gasPrice,
),
16,
); );
} }
@ -85,33 +82,22 @@ export function getSwapsTokensReceivedFromTxMeta(
? txReceipt.effectiveGasPrice ? txReceipt.effectiveGasPrice
: txMeta.txParams.gasPrice, : txMeta.txParams.gasPrice,
); );
const totalGasCost = new BigNumber(gasCost, 16) const totalGasCost = new Numeric(gasCost, 16).plus(approvalTxGasCost);
.plus(approvalTxGasCost, 16)
.toString(16);
const preTxBalanceLessGasCost = subtractCurrencies( const preTxBalanceLessGasCost = new Numeric(txMeta.preTxBalance, 16).minus(
txMeta.preTxBalance,
totalGasCost, totalGasCost,
{
aBase: 16,
bBase: 16,
toNumericBase: 'hex',
},
); );
const ethReceived = subtractCurrencies( const ethReceived = new Numeric(
txMeta.postTxBalance, txMeta.postTxBalance,
preTxBalanceLessGasCost, 16,
{ EtherDenomination.WEI,
aBase: 16, )
bBase: 16, .subtract(preTxBalanceLessGasCost)
fromDenomination: 'WEI', .toDenomination(EtherDenomination.ETH)
toDenomination: 'ETH', .toBase(10)
toNumericBase: 'dec', .round(6);
numberOfDecimals: 6, return ethReceived.toString();
},
);
return ethReceived;
} }
const txReceiptLogs = txReceipt?.logs; const txReceiptLogs = txReceipt?.logs;
if (txReceiptLogs && txReceipt?.status !== '0x0') { if (txReceiptLogs && txReceipt?.status !== '0x0') {

View File

@ -1,9 +1,4 @@
import { addHexPrefix } from 'ethereumjs-util'; import { Numeric } from './Numeric';
import {
addCurrencies,
conversionGreaterThan,
multiplyCurrencies,
} from './conversion.utils';
/** /**
* Accepts an options bag containing gas fee parameters in hex format and * Accepts an options bag containing gas fee parameters in hex format and
@ -27,26 +22,19 @@ export function getMaximumGasTotalInHexWei({
maxFeePerGas, maxFeePerGas,
} = {}) { } = {}) {
if (maxFeePerGas) { if (maxFeePerGas) {
return addHexPrefix( return new Numeric(gasLimit, 16)
multiplyCurrencies(gasLimit, maxFeePerGas, { .times(new Numeric(maxFeePerGas, 16))
toNumericBase: 'hex', .toPrefixedHexString();
multiplicandBase: 16,
multiplierBase: 16,
}),
);
} }
if (!gasPrice) { if (!gasPrice) {
throw new Error( throw new Error(
'getMaximumGasTotalInHexWei requires gasPrice be provided to calculate legacy gas total', 'getMaximumGasTotalInHexWei requires gasPrice be provided to calculate legacy gas total',
); );
} }
return addHexPrefix(
multiplyCurrencies(gasLimit, gasPrice, { return new Numeric(gasLimit, 16)
toNumericBase: 'hex', .times(new Numeric(gasPrice, 16))
multiplicandBase: 16, .toPrefixedHexString();
multiplierBase: 16,
}),
);
} }
/** /**
@ -105,25 +93,14 @@ export function getMinimumGasTotalInHexWei({
if (isEIP1559Estimate === false) { if (isEIP1559Estimate === false) {
return getMaximumGasTotalInHexWei({ gasLimit, gasPrice }); return getMaximumGasTotalInHexWei({ gasLimit, gasPrice });
} }
const minimumFeePerGas = addCurrencies(baseFeePerGas, maxPriorityFeePerGas, { const minimumFeePerGas = new Numeric(baseFeePerGas, 16)
toNumericBase: 'hex', .add(new Numeric(maxPriorityFeePerGas, 16))
aBase: 16, .toString();
bBase: 16,
});
if ( if (new Numeric(minimumFeePerGas, 16).greaterThan(maxFeePerGas, 16)) {
conversionGreaterThan(
{ value: minimumFeePerGas, fromNumericBase: 'hex' },
{ value: maxFeePerGas, fromNumericBase: 'hex' },
)
) {
return getMaximumGasTotalInHexWei({ gasLimit, maxFeePerGas }); return getMaximumGasTotalInHexWei({ gasLimit, maxFeePerGas });
} }
return addHexPrefix( return new Numeric(gasLimit, 16)
multiplyCurrencies(gasLimit, minimumFeePerGas, { .times(new Numeric(minimumFeePerGas, 16))
toNumericBase: 'hex', .toPrefixedHexString();
multiplicandBase: 16,
multiplierBase: 16,
}),
);
} }

View File

@ -1,9 +1,9 @@
const { addHexPrefix } = require('ethereumjs-util'); const { addHexPrefix } = require('ethereumjs-util');
const { conversionUtil } = require('./conversion.utils');
const { const {
getMaximumGasTotalInHexWei, getMaximumGasTotalInHexWei,
getMinimumGasTotalInHexWei, getMinimumGasTotalInHexWei,
} = require('./gas.utils'); } = require('./gas.utils');
const { Numeric } = require('./Numeric');
const feesToTest = [10, 24, 90]; const feesToTest = [10, 24, 90];
const tipsToTest = [2, 10, 50]; const tipsToTest = [2, 10, 50];
@ -18,15 +18,17 @@ describe('gas utils', () => {
gasLimitsToTest.forEach((gasLimit) => { gasLimitsToTest.forEach((gasLimit) => {
const expectedResult = (gasLimit * maxFeePerGas).toString(); const expectedResult = (gasLimit * maxFeePerGas).toString();
const gasLimitHex = addHexPrefix(gasLimit.toString(16)); const gasLimitHex = addHexPrefix(gasLimit.toString(16));
const result = conversionUtil( const result = new Numeric(
getMaximumGasTotalInHexWei({ getMaximumGasTotalInHexWei({
gasLimit: gasLimitHex, gasLimit: gasLimitHex,
maxFeePerGas: addHexPrefix(maxFeePerGas.toString(16)), maxFeePerGas: addHexPrefix(maxFeePerGas.toString(16)),
}), }),
{ fromNumericBase: 'hex', toNumericBase: 'dec' }, 16,
); );
it(`returns ${expectedResult} when provided gasLimit: ${gasLimit}`, () => { it(`returns ${expectedResult} when provided gasLimit: ${gasLimit}`, () => {
expect(result).toStrictEqual(expectedResult); expect(result.toBase(10).toString()).toStrictEqual(
expectedResult,
);
}); });
}); });
}); });
@ -44,7 +46,7 @@ describe('gas utils', () => {
minimum < maximum ? minimum : maximum; minimum < maximum ? minimum : maximum;
const results = gasLimitsToTest.map((gasLimit) => { const results = gasLimitsToTest.map((gasLimit) => {
const gasLimitHex = addHexPrefix(gasLimit.toString(16)); const gasLimitHex = addHexPrefix(gasLimit.toString(16));
const result = conversionUtil( const result = new Numeric(
getMinimumGasTotalInHexWei({ getMinimumGasTotalInHexWei({
gasLimit: gasLimitHex, gasLimit: gasLimitHex,
maxFeePerGas: addHexPrefix(maxFeePerGas.toString(16)), maxFeePerGas: addHexPrefix(maxFeePerGas.toString(16)),
@ -53,9 +55,9 @@ describe('gas utils', () => {
), ),
baseFeePerGas: addHexPrefix(baseFeePerGas.toString(16)), baseFeePerGas: addHexPrefix(baseFeePerGas.toString(16)),
}), }),
{ fromNumericBase: 'hex', toNumericBase: 'dec' }, 16,
); );
return { result, gasLimit }; return { result: result.toBase(10).toString(), gasLimit };
}); });
it(`should use an effective gasPrice of ${expectedEffectiveGasPrice}`, () => { it(`should use an effective gasPrice of ${expectedEffectiveGasPrice}`, () => {
expect( expect(
@ -89,13 +91,15 @@ describe('gas utils', () => {
const gasLimitHex = addHexPrefix(gasLimit.toString(16)); const gasLimitHex = addHexPrefix(gasLimit.toString(16));
it(`returns ${expectedResult} when provided gasLimit of ${gasLimit}`, () => { it(`returns ${expectedResult} when provided gasLimit of ${gasLimit}`, () => {
expect( expect(
conversionUtil( new Numeric(
getMaximumGasTotalInHexWei({ getMaximumGasTotalInHexWei({
gasLimit: gasLimitHex, gasLimit: gasLimitHex,
gasPrice: addHexPrefix(gasPrice.toString(16)), gasPrice: addHexPrefix(gasPrice.toString(16)),
}), }),
{ fromNumericBase: 'hex', toNumericBase: 'dec' }, 16,
), )
.toBase(10)
.toString(),
).toStrictEqual(expectedResult); ).toStrictEqual(expectedResult);
}); });
}); });
@ -111,16 +115,15 @@ describe('gas utils', () => {
const gasLimitHex = addHexPrefix(gasLimit.toString(16)); const gasLimitHex = addHexPrefix(gasLimit.toString(16));
it(`returns ${expectedResult} when provided gasLimit of ${gasLimit}`, () => { it(`returns ${expectedResult} when provided gasLimit of ${gasLimit}`, () => {
expect( expect(
conversionUtil( new Numeric(
getMinimumGasTotalInHexWei({ getMinimumGasTotalInHexWei({
gasLimit: gasLimitHex, gasLimit: gasLimitHex,
gasPrice: addHexPrefix(gasPrice.toString(16)), gasPrice: addHexPrefix(gasPrice.toString(16)),
}), }),
{ 16,
fromNumericBase: 'hex', )
toNumericBase: 'dec', .toBase(10)
}, .toString(),
),
).toStrictEqual(expectedResult); ).toStrictEqual(expectedResult);
}); });
}); });

View File

@ -1,8 +1,6 @@
import { rawEncode } from 'ethereumjs-abi'; import { rawEncode } from 'ethereumjs-abi';
import { calcGasTotal } from '../../../shared/lib/transactions-controller-utils';
import { import {
multiplyCurrencies,
addCurrencies, addCurrencies,
conversionGTE, conversionGTE,
conversionUtil, conversionUtil,
@ -49,18 +47,6 @@ jest.mock('ethereumjs-abi', () => ({
})); }));
describe('send utils', () => { describe('send utils', () => {
describe('calcGasTotal()', () => {
it('should call multiplyCurrencies with the correct params and return the multiplyCurrencies return', () => {
const result = calcGasTotal(12, 15);
expect(result).toStrictEqual('12x15');
expect(multiplyCurrencies).toHaveBeenCalledWith(12, 15, {
multiplicandBase: 16,
multiplierBase: 16,
toNumericBase: 'hex',
});
});
});
describe('generateERC20TransferData()', () => { describe('generateERC20TransferData()', () => {
it('should return undefined if not passed a send token', () => { it('should return undefined if not passed a send token', () => {
expect( expect(