diff --git a/test/e2e/tests/simulation-details/simulation-details.spec.ts b/test/e2e/tests/simulation-details/simulation-details.spec.ts
index 0c3e514f88ad..65e21b5d9ab2 100644
--- a/test/e2e/tests/simulation-details/simulation-details.spec.ts
+++ b/test/e2e/tests/simulation-details/simulation-details.spec.ts
@@ -114,7 +114,7 @@ describe('Simulation Details', () => {
await switchToNotificationWindow(driver);
await expectBalanceChange(driver, true, 0, '- 0.002', 'ETH');
- await expectBalanceChange(driver, false, 0, '+ 6.756291', 'DAI');
+ await expectBalanceChange(driver, false, 0, '+ 6.756', 'DAI');
});
});
diff --git a/ui/hooks/useCurrencyDisplay.js b/ui/hooks/useCurrencyDisplay.js
index e6eded343fe6..192aebf37906 100644
--- a/ui/hooks/useCurrencyDisplay.js
+++ b/ui/hooks/useCurrencyDisplay.js
@@ -1,5 +1,6 @@
import { useMemo } from 'react';
import { useSelector } from 'react-redux';
+import BigNumber from 'bignumber.js';
import { formatCurrency } from '../helpers/utils/confirm-tx.util';
import { getCurrentCurrency } from '../selectors';
import {
@@ -12,9 +13,16 @@ import { TEST_NETWORK_TICKER_MAP } from '../../shared/constants/network';
import { Numeric } from '../../shared/modules/Numeric';
import { EtherDenomination } from '../../shared/constants/common';
-export const MIN_DISPLAY_AMOUNT = '<0.000001';
+// The smallest non-zero amount that can be displayed.
+export const MIN_AMOUNT = 0.000001;
-export const DEFAULT_PRECISION_DECIMALS = 6;
+// The string to display when 0 < amount < MIN_AMOUNT.
+// TODO(dbrans): Localize this string using Intl.NumberFormatter.
+const MIN_AMOUNT_DISPLAY = `<${MIN_AMOUNT}`;
+
+// The default precision for displaying currency values.
+// It set to the number of decimal places in the minimum amount.
+export const DEFAULT_PRECISION = new BigNumber(MIN_AMOUNT).decimalPlaces();
/**
* Defines the shape of the options parameter for useCurrencyDisplay
@@ -66,12 +74,12 @@ export function useCurrencyDisplay(
) {
const ethDisplayValue = new Numeric(inputValue, 16, EtherDenomination.WEI)
.toDenomination(denomination || EtherDenomination.ETH)
- .round(numberOfDecimals || DEFAULT_PRECISION_DECIMALS)
+ .round(numberOfDecimals || DEFAULT_PRECISION)
.toBase(10)
.toString();
return ethDisplayValue === '0' && inputValue && Number(inputValue) !== 0
- ? MIN_DISPLAY_AMOUNT
+ ? MIN_AMOUNT_DISPLAY
: ethDisplayValue;
} else if (isUserPreferredCurrency && conversionRate) {
return formatCurrency(
diff --git a/ui/pages/confirmations/components/simulation-details/amount-pill.test.tsx b/ui/pages/confirmations/components/simulation-details/amount-pill.test.tsx
index d3a458400326..c35b090fda84 100644
--- a/ui/pages/confirmations/components/simulation-details/amount-pill.test.tsx
+++ b/ui/pages/confirmations/components/simulation-details/amount-pill.test.tsx
@@ -1,16 +1,23 @@
import React from 'react';
import { render } from '@testing-library/react';
+import { BigNumber } from 'bignumber.js';
import { TokenStandard } from '../../../../../shared/constants/transaction';
-import { Numeric } from '../../../../../shared/modules/Numeric';
import Tooltip from '../../../../components/ui/tooltip';
import { AmountPill } from './amount-pill';
import {
- Amount,
AssetIdentifier,
NATIVE_ASSET_IDENTIFIER,
TokenAssetIdentifier,
} from './types';
+jest.mock('react-redux', () => ({
+ useSelector: jest.fn((selector) => selector()),
+}));
+
+jest.mock('../../../../ducks/locale/locale', () => ({
+ getIntlLocale: jest.fn(() => 'en-US'),
+}));
+
jest.mock('../../../../components/ui/tooltip', () => ({
__esModule: true,
default: jest.fn(({ children }) => children),
@@ -35,7 +42,7 @@ const ERC1155_ASSET_MOCK: TokenAssetIdentifier = {
const renderAndExpect = (
asset: AssetIdentifier,
- amount: Amount,
+ amount: BigNumber,
expected: { text: string; tooltip: string },
): void => {
const { getByText } = render();
@@ -47,50 +54,48 @@ const renderAndExpect = (
};
describe('AmountPill', () => {
+ beforeEach(() => {
+ jest.clearAllMocks();
+ });
+
const nativeAndErc20Cases = [
{
- isNegative: true,
- numeric: new Numeric(-123.1234567, 10),
+ amount: new BigNumber(-123.1234567),
expected: {
- text: '- 123.123457',
+ text: '- 123.1',
tooltip: '123.1234567',
},
},
{
- isNegative: false,
- numeric: new Numeric(789.012, 10),
+ amount: new BigNumber(789.412),
expected: {
- text: '+ 789.012',
- tooltip: '789.012',
+ text: '+ 789.4',
+ tooltip: '789.412',
},
},
{
- isNegative: true,
- numeric: new Numeric(-0.000000001, 10),
+ amount: new BigNumber(-0.000000001),
expected: {
text: '- <0.000001',
tooltip: '0.000000001',
},
},
{
- isNegative: false,
- numeric: new Numeric(0.000000001, 10),
+ amount: new BigNumber(0.000000001),
expected: {
text: '+ <0.000001',
tooltip: '0.000000001',
},
},
{
- isNegative: true,
- numeric: new Numeric(0, 10),
+ amount: new BigNumber(-0),
expected: {
text: '- 0',
tooltip: '0',
},
},
{
- isNegative: false,
- numeric: new Numeric(0, 10),
+ amount: new BigNumber(0),
expected: {
text: '+ 0',
tooltip: '0',
@@ -100,26 +105,18 @@ describe('AmountPill', () => {
describe('Native', () => {
it.each(nativeAndErc20Cases)(
- 'renders the correct sign and amount for $numeric.value',
- ({ isNegative, numeric, expected }) => {
- renderAndExpect(
- NATIVE_ASSET_IDENTIFIER,
- { isNegative, numeric } as Amount,
- expected,
- );
+ 'renders the correct sign and amount for $amount',
+ ({ amount, expected }) => {
+ renderAndExpect(NATIVE_ASSET_IDENTIFIER, amount, expected);
},
);
});
describe('ERC20', () => {
it.each(nativeAndErc20Cases)(
- 'renders the correct sign and amount for $numeric.value',
- ({ isNegative, numeric, expected }) => {
- renderAndExpect(
- ERC20_ASSET_MOCK,
- { isNegative, numeric } as Amount,
- expected,
- );
+ 'renders the correct sign and amount for $amount',
+ ({ amount, expected }) => {
+ renderAndExpect(ERC20_ASSET_MOCK, amount, expected);
},
);
});
@@ -127,16 +124,14 @@ describe('AmountPill', () => {
describe('ERC721', () => {
const cases = [
{
- isNegative: true,
- numeric: new Numeric(-1, 10),
+ amount: new BigNumber(-1),
expected: {
text: '- #2748',
tooltip: '#2748',
},
},
{
- isNegative: false,
- numeric: new Numeric(1, 10),
+ amount: new BigNumber(1),
expected: {
text: '+ #2748',
tooltip: '#2748',
@@ -146,12 +141,8 @@ describe('AmountPill', () => {
it.each(cases)(
'renders the token ID with just a plus or minus for $expected.text',
- ({ isNegative, numeric, expected }) => {
- renderAndExpect(
- ERC721_ASSET_MOCK,
- { isNegative, numeric } as Amount,
- expected,
- );
+ ({ amount, expected }) => {
+ renderAndExpect(ERC721_ASSET_MOCK, amount, expected);
},
);
});
@@ -159,24 +150,21 @@ describe('AmountPill', () => {
describe('ERC1155', () => {
const cases = [
{
- isNegative: true,
- numeric: new Numeric(-3, 10),
+ amount: new BigNumber(-3),
expected: {
text: '- 3 #2748',
tooltip: '3 #2748',
},
},
{
- isNegative: false,
- numeric: new Numeric(8, 10),
+ amount: new BigNumber(8),
expected: {
text: '+ 8 #2748',
tooltip: '8 #2748',
},
},
{
- isNegative: true,
- numeric: new Numeric(-12, 10),
+ amount: new BigNumber(-12),
expected: {
text: '- 12 #2748',
tooltip: '12 #2748',
@@ -186,12 +174,8 @@ describe('AmountPill', () => {
it.each(cases)(
'renders the correct sign, amount, and token ID for $expected.text',
- ({ isNegative, numeric, expected }) => {
- renderAndExpect(
- ERC1155_ASSET_MOCK,
- { isNegative, numeric } as Amount,
- expected,
- );
+ ({ amount, expected }) => {
+ renderAndExpect(ERC1155_ASSET_MOCK, amount, expected);
},
);
});
diff --git a/ui/pages/confirmations/components/simulation-details/amount-pill.tsx b/ui/pages/confirmations/components/simulation-details/amount-pill.tsx
index a57d8cf8700d..1204eaf16bd4 100644
--- a/ui/pages/confirmations/components/simulation-details/amount-pill.tsx
+++ b/ui/pages/confirmations/components/simulation-details/amount-pill.tsx
@@ -1,4 +1,6 @@
import React from 'react';
+import { BigNumber } from 'bignumber.js';
+import { useSelector } from 'react-redux';
import { Box, Text } from '../../../../components/component-library';
import {
AlignItems,
@@ -11,21 +13,10 @@ import {
} from '../../../../helpers/constants/design-system';
import { hexToDecimal } from '../../../../../shared/modules/conversion.utils';
import { TokenStandard } from '../../../../../shared/constants/transaction';
-import {
- DEFAULT_PRECISION_DECIMALS,
- MIN_DISPLAY_AMOUNT,
-} from '../../../../hooks/useCurrencyDisplay';
import Tooltip from '../../../../components/ui/tooltip';
-import { Amount, AssetIdentifier } from './types';
-
-// Format an amount for display.
-const formatAmount = (amount: Amount): string => {
- const displayAmount = amount.numeric.abs().round(DEFAULT_PRECISION_DECIMALS);
-
- return displayAmount.isZero() && !amount.numeric.isZero()
- ? MIN_DISPLAY_AMOUNT
- : displayAmount.toString();
-};
+import { getIntlLocale } from '../../../../ducks/locale/locale';
+import { AssetIdentifier } from './types';
+import { formatAmount, formatAmountMaxPrecision } from './formatAmount';
/**
* Displays a pill with an amount and a background color indicating whether the amount
@@ -37,23 +28,25 @@ const formatAmount = (amount: Amount): string => {
*/
export const AmountPill: React.FC<{
asset: AssetIdentifier;
- amount: Amount;
+ amount: BigNumber;
}> = ({ asset, amount }) => {
- const backgroundColor = amount.isNegative
+ const locale = useSelector(getIntlLocale);
+
+ const backgroundColor = amount.isNegative()
? BackgroundColor.errorMuted
: BackgroundColor.successMuted;
- const color = amount.isNegative
+ const color = amount.isNegative()
? TextColor.errorAlternative
: TextColor.successDefault;
- const amountParts: string[] = [amount.isNegative ? '-' : '+'];
+ const amountParts: string[] = [amount.isNegative() ? '-' : '+'];
const tooltipParts: string[] = [];
- // ERC721 amounts are always 1 are not displayed.
+ // ERC721 amounts are always 1 and are not displayed.
if (asset.standard !== TokenStandard.ERC721) {
- const formattedAmount = formatAmount(amount);
- const fullPrecisionAmount = amount.numeric.abs().toString();
+ const formattedAmount = formatAmount(locale, amount.abs());
+ const fullPrecisionAmount = formatAmountMaxPrecision(locale, amount.abs());
amountParts.push(formattedAmount);
tooltipParts.push(fullPrecisionAmount);
diff --git a/ui/pages/confirmations/components/simulation-details/asset-pill.test.tsx b/ui/pages/confirmations/components/simulation-details/asset-pill.test.tsx
index 3bc179edd759..334c79f372c9 100644
--- a/ui/pages/confirmations/components/simulation-details/asset-pill.test.tsx
+++ b/ui/pages/confirmations/components/simulation-details/asset-pill.test.tsx
@@ -21,7 +21,7 @@ jest.mock('../../../../components/app/name', () => ({
}));
describe('AssetPill', () => {
- afterEach(() => {
+ beforeEach(() => {
jest.clearAllMocks();
});
diff --git a/ui/pages/confirmations/components/simulation-details/formatAmount.test.ts b/ui/pages/confirmations/components/simulation-details/formatAmount.test.ts
new file mode 100644
index 000000000000..8a226ddca4f7
--- /dev/null
+++ b/ui/pages/confirmations/components/simulation-details/formatAmount.test.ts
@@ -0,0 +1,44 @@
+import { BigNumber } from 'bignumber.js';
+import { formatAmount } from './formatAmount';
+
+describe('formatAmount', () => {
+ const locale = 'en-US';
+
+ it('returns "0" for zero amount', () => {
+ expect(formatAmount(locale, new BigNumber(0))).toBe('0');
+ });
+
+ it('returns "<0.000001" for 0 < amount < MIN_AMOUNT', () => {
+ expect(formatAmount(locale, new BigNumber(0.0000009))).toBe('<0.000001');
+ });
+
+ it.each([
+ [0.0000456, '0.000046'],
+ [0.0004567, '0.000457'],
+ [0.003456, '0.00346'],
+ [0.023456, '0.0235'],
+ [0.125456, '0.125'],
+ ])(
+ 'formats amount less than 1 with maximum significant digits (%s => %s)',
+ (amount, expected) => {
+ expect(formatAmount(locale, new BigNumber(amount))).toBe(expected);
+ },
+ );
+
+ it.each([
+ [1.0034, '1.003'],
+ [1.034, '1.034'],
+ [1.3034, '1.303'],
+ [12.0345, '12.03'],
+ [121.456, '121.5'],
+ [1034.123, '1,034'],
+ [47361034.006, '47,361,034'],
+ ['12130982923409.5', '12,130,982,923,410'],
+ ['1213098292340944.5', '1,213,098,292,340,945'],
+ ])(
+ 'formats amount greater than or equal to 1 with appropriate decimal precision (%s => %s)',
+ (amount, expected) => {
+ expect(formatAmount(locale, new BigNumber(amount))).toBe(expected);
+ },
+ );
+});
diff --git a/ui/pages/confirmations/components/simulation-details/formatAmount.ts b/ui/pages/confirmations/components/simulation-details/formatAmount.ts
new file mode 100644
index 000000000000..1314b3b5f911
--- /dev/null
+++ b/ui/pages/confirmations/components/simulation-details/formatAmount.ts
@@ -0,0 +1,86 @@
+import { BigNumber } from 'bignumber.js';
+import {
+ MIN_AMOUNT,
+ DEFAULT_PRECISION,
+} from '../../../../hooks/useCurrencyDisplay';
+
+// The number of significant decimals places to show for amounts less than 1.
+const MAX_SIGNIFICANT_DECIMAL_PLACES = 3;
+
+const ZERO_DISPLAY = '0';
+
+export function formatAmountMaxPrecision(
+ locale: string,
+ num: number | BigNumber,
+): string {
+ return new Intl.NumberFormat(locale, {
+ minimumSignificantDigits: 1,
+ }).format(new BigNumber(num.toString()).toNumber());
+}
+
+/**
+ * Formats the a token amount with variable precision and significant
+ * digits.
+ *
+ * If |amount| < 1, we display a maximum number of significant
+ * digits.
+ *
+ * If |amount| >= 1, we display all digits left of the decimal point.
+ * We also display some decimal places for smaller amounts, and
+ * gradually reduce the decimal precision as the amount
+ * gets bigger until we only show whole numbers.
+ *
+ * Examples:
+ *
+ * | Amount | Formatted |
+ * |----------------------|--------------------|
+ * | 0 | 0 |
+ * | 0.0000009 | <0.000001 |
+ * | 0.0000456 | 0.000046 |
+ * | 0.0004567 | 0.000457 |
+ * | 0.003456 | 0.00346 |
+ * | 0.023456 | 0.0235 |
+ * | 0.125456 | 0.125 |
+ * | 1.0034 | 1.003 |
+ * | 1.034 | 1.034 |
+ * | 1.3034 | 1.303 |
+ * | 12.0345 | 12.03 |
+ * | 121.456 | 121.5 |
+ * | 1,034.123 | 1,034 |
+ * | 47,361,034.006 | 47,361,034 |
+ * | 12,130,982,923,409.5 | 12,130,982,923,410 |
+ *
+ * @param locale
+ * @param amount
+ */
+export function formatAmount(locale: string, amount: BigNumber): string {
+ if (amount.isZero()) {
+ return ZERO_DISPLAY;
+ }
+
+ if (amount.abs().lessThan(MIN_AMOUNT)) {
+ return `<${formatAmountMaxPrecision(locale, MIN_AMOUNT)}`;
+ }
+
+ if (amount.abs().lessThan(1)) {
+ return new Intl.NumberFormat(locale, {
+ maximumSignificantDigits: MAX_SIGNIFICANT_DECIMAL_PLACES,
+ } as Intl.NumberFormatOptions).format(
+ amount.round(DEFAULT_PRECISION).toNumber(),
+ );
+ }
+
+ // Preserve all digits left of the decimal point.
+ // Cap the digits right of the decimal point: The more digits present
+ // on the left side of the decimal point, the less decimal places
+ // we show on the right side.
+ const digitsLeftOfDecimal = amount.abs().truncated().toString().length;
+ const maximumFractionDigits = Math.max(
+ 0,
+ MAX_SIGNIFICANT_DECIMAL_PLACES - digitsLeftOfDecimal + 1,
+ );
+
+ return new Intl.NumberFormat(locale, {
+ maximumFractionDigits,
+ } as Intl.NumberFormatOptions).format(amount.toNumber());
+}
diff --git a/ui/pages/confirmations/components/simulation-details/simulation-details.test.tsx b/ui/pages/confirmations/components/simulation-details/simulation-details.test.tsx
index d72f6ff7fd28..5971e513e3a1 100644
--- a/ui/pages/confirmations/components/simulation-details/simulation-details.test.tsx
+++ b/ui/pages/confirmations/components/simulation-details/simulation-details.test.tsx
@@ -5,6 +5,7 @@ import {
SimulationData,
SimulationErrorCode,
} from '@metamask/transaction-controller';
+import { BigNumber } from 'bignumber.js';
import { renderWithProvider } from '../../../../../test/lib/render-helpers';
import mockState from '../../../../../test/data/mock-state.json';
import { SimulationDetails } from './simulation-details';
@@ -35,6 +36,7 @@ const renderSimulationDetails = (simulationData?: Partial) =>
describe('SimulationDetails', () => {
beforeEach(() => {
+ jest.clearAllMocks();
(useBalanceChanges as jest.Mock).mockReturnValue({
pending: false,
value: [],
@@ -97,8 +99,8 @@ describe('SimulationDetails', () => {
it('passes the correct properties to BalanceChangeList components', () => {
const balanceChangesMock = [
- { amount: { isNegative: true } },
- { amount: { isNegative: false } },
+ { amount: new BigNumber(-123) },
+ { amount: new BigNumber(456) },
] as BalanceChange[];
(useBalanceChanges as jest.Mock).mockReturnValue({
diff --git a/ui/pages/confirmations/components/simulation-details/simulation-details.tsx b/ui/pages/confirmations/components/simulation-details/simulation-details.tsx
index b1c1544f6b75..fecd8540fe04 100644
--- a/ui/pages/confirmations/components/simulation-details/simulation-details.tsx
+++ b/ui/pages/confirmations/components/simulation-details/simulation-details.tsx
@@ -175,8 +175,6 @@ export const SimulationDetails: React.FC = ({
const balanceChangesResult = useBalanceChanges(simulationData);
const loading = !simulationData || balanceChangesResult.pending;
- console.log('SimulationDetails', simulationData);
-
useSimulationMetrics({
balanceChanges: balanceChangesResult.value,
loadingTime,
@@ -223,8 +221,8 @@ export const SimulationDetails: React.FC = ({
);
}
- const outgoing = balanceChanges.filter((change) => change.amount.isNegative);
- const incoming = balanceChanges.filter((change) => !change.amount.isNegative);
+ const outgoing = balanceChanges.filter((bc) => bc.amount.isNegative());
+ const incoming = balanceChanges.filter((bc) => !bc.amount.isNegative());
return (
diff --git a/ui/pages/confirmations/components/simulation-details/types.ts b/ui/pages/confirmations/components/simulation-details/types.ts
index 913873692b76..7db6a30357cd 100644
--- a/ui/pages/confirmations/components/simulation-details/types.ts
+++ b/ui/pages/confirmations/components/simulation-details/types.ts
@@ -1,6 +1,6 @@
import { Hex } from '@metamask/utils';
+import { BigNumber } from 'bignumber.js';
import { TokenStandard } from '../../../../../shared/constants/transaction';
-import { Numeric } from '../../../../../shared/modules/Numeric';
export const NATIVE_ASSET_IDENTIFIER: NativeAssetIdentifier = {
standard: TokenStandard.none,
@@ -36,57 +36,28 @@ export type AssetIdentifier = Readonly<
>;
/**
- * Represents an amount of an asset, including its magnitude and sign.
+ * Describes a change in an asset's balance to a user's wallet.
*/
-export type Amount = Readonly<{
- /**
- * Indicates whether the amount is negative (e.g., a decrease in balance).
- */
- isNegative: boolean;
-
+export type BalanceChange = Readonly<{
/**
- * The quantity of the smallest denomination of the asset (base units),
- * represented as a hexadecimal string.
- * For example: In the case of ETH, this would be the number of wei.
+ * The asset identifier for the balance change.
*/
- quantity: Hex;
+ asset: AssetIdentifier;
/**
- * The number of decimal places the associated asset supports.
+ * The quantity of asset tokens, expressed as a decimal value.
*
- * This value is the negation of the exponent used when converting
- * the quantity to the decimal amount of a token.
+ * This property represents the amount of tokens, taking into account the
+ * number of decimals supported by the asset. The value can be positive
+ * (increase) or negative (decrease).
*
- * To calculate the token amount in decimal form, use the formula:
- * `tokenAmount = hexToDecimal(quantity) / (10 ^ decimals)`
- *
- * Example: If the asset is ETH, the quantity is expressed in wei
- * (the smallest unit of ETH) and decimals would be 18. The amount
- * of ETH tokens would be: `ethAmount = quantity / (10 ^ 18)`
+ * Example: If an asset supports 18 decimals, an `amount` of 1.5 represents
+ * 1.5 tokens, or more precisely, 1.5 * 10^18 of the smallest divisible unit.
*/
- decimals: number;
-
- /**
- * The numeric representation of the amount, taking into account the
- * sign, quantity and decimals.
- */
- numeric: Numeric;
-}>;
+ amount: BigNumber;
-/**
- * Describes a change in an asset's balance to a user's wallet.
- */
-export type BalanceChange = {
- /**
- * The asset identifier for the balance change.
- */
- asset: AssetIdentifier;
- /**
- * The amount of the asset that changed.
- */
- amount: Amount;
/**
* The amount of fiat currency that corresponds to the asset amount.
*/
fiatAmount: FiatAmount;
-};
+}>;
diff --git a/ui/pages/confirmations/components/simulation-details/useBalanceChanges.test.ts b/ui/pages/confirmations/components/simulation-details/useBalanceChanges.test.ts
index 0020768a04c4..f7e7d647a213 100644
--- a/ui/pages/confirmations/components/simulation-details/useBalanceChanges.test.ts
+++ b/ui/pages/confirmations/components/simulation-details/useBalanceChanges.test.ts
@@ -4,10 +4,10 @@ import {
SimulationData,
SimulationTokenStandard,
} from '@metamask/transaction-controller';
+import { BigNumber } from 'bignumber.js';
import { TokenStandard } from '../../../../../shared/constants/transaction';
import { getConversionRate } from '../../../../ducks/metamask/metamask';
import { getTokenStandardAndDetails } from '../../../../store/actions';
-import { Numeric } from '../../../../../shared/modules/Numeric';
import { fetchTokenExchangeRates } from '../../../../helpers/utils/util';
import { useBalanceChanges } from './useBalanceChanges';
import { FIAT_UNAVAILABLE } from './types';
@@ -159,7 +159,7 @@ describe('useBalanceChanges', () => {
const { result, waitForNextUpdate } = setupHook([
{
...dummyBalanceChange,
- difference: DIFFERENCE_1_MOCK,
+ difference: '0x11',
isDecrease: true,
address: ERC20_TOKEN_ADDRESS_1_MOCK,
standard: SimulationTokenStandard.erc20,
@@ -176,16 +176,11 @@ describe('useBalanceChanges', () => {
standard: TokenStandard.ERC20,
tokenId: undefined,
},
- amount: {
- isNegative: true,
- quantity: DIFFERENCE_1_MOCK,
- decimals: 3,
- numeric: expect.any(Numeric),
- },
- fiatAmount: Number('-0.0255'),
+ amount: new BigNumber('-0.017'),
+ fiatAmount: -0.0255,
},
]);
- expect(changes[0].amount.numeric.toString()).toBe('-0.017');
+ expect(changes[0].amount.toString()).toBe('-0.017');
});
it('handles multiple token balance changes', async () => {
@@ -210,9 +205,9 @@ describe('useBalanceChanges', () => {
const changes = result.current.value;
expect(changes).toHaveLength(2);
- expect(changes[0].amount.numeric.toString()).toBe('-0.017');
+ expect(changes[0].amount.toString()).toBe('-0.017');
expect(changes[0].fiatAmount).toBe(Number('-0.0255'));
- expect(changes[1].amount.numeric.toString()).toBe('0.0002');
+ expect(changes[1].amount.toString()).toBe('0.0002');
expect(changes[1].fiatAmount).toBe(Number('0.0012'));
});
@@ -220,7 +215,7 @@ describe('useBalanceChanges', () => {
const { result, waitForNextUpdate } = setupHook([
{
...dummyBalanceChange,
- difference: DIFFERENCE_1_MOCK,
+ difference: '0x1',
isDecrease: true,
address: NFT_TOKEN_ADDRESS_MOCK,
standard: SimulationTokenStandard.erc721,
@@ -237,12 +232,7 @@ describe('useBalanceChanges', () => {
standard: TokenStandard.ERC721,
tokenId: TOKEN_ID_1_MOCK,
},
- amount: {
- isNegative: true,
- quantity: DIFFERENCE_1_MOCK,
- decimals: 0,
- numeric: expect.any(Numeric),
- },
+ amount: new BigNumber('-1'),
fiatAmount: FIAT_UNAVAILABLE,
},
]);
@@ -261,7 +251,7 @@ describe('useBalanceChanges', () => {
await waitForNextUpdate();
- expect(result.current.value[0].amount.decimals).toBe(18);
+ expect(result.current.value[0].amount.decimalPlaces()).toBe(18);
});
});
@@ -291,18 +281,10 @@ describe('useBalanceChanges', () => {
asset: {
standard: TokenStandard.none,
},
- amount: {
- isNegative: true,
- quantity: DIFFERENCE_ETH_MOCK,
- decimals: 18,
- numeric: expect.any(Numeric),
- },
+ amount: new BigNumber('-5373.003641998677469065'),
fiatAmount: Number('-16119.010925996032'),
},
]);
- expect(changes[0].amount.numeric.toString()).toBe(
- '-5373.003641998677469065',
- );
});
it('handles no native balance change', async () => {
@@ -340,14 +322,14 @@ describe('useBalanceChanges', () => {
expect(changes[0].asset).toEqual({
standard: TokenStandard.none,
});
- expect(changes[0].amount.numeric.toString()).toBe(
- '-5373.003641998677469065',
+ expect(changes[0].amount).toEqual(
+ new BigNumber('-5373.003641998677469065'),
);
expect(changes[0].fiatAmount).toBe(Number('-16119.010925996032'));
expect(changes[1].asset).toEqual({
address: ERC20_TOKEN_ADDRESS_1_MOCK,
standard: TokenStandard.ERC20,
});
- expect(changes[1].amount.numeric.toString()).toBe('0.002');
+ expect(changes[1].amount).toEqual(new BigNumber('0.002'));
});
});
diff --git a/ui/pages/confirmations/components/simulation-details/useBalanceChanges.ts b/ui/pages/confirmations/components/simulation-details/useBalanceChanges.ts
index 614ad98428c9..be9f861ebc1a 100644
--- a/ui/pages/confirmations/components/simulation-details/useBalanceChanges.ts
+++ b/ui/pages/confirmations/components/simulation-details/useBalanceChanges.ts
@@ -6,16 +6,15 @@ import {
SimulationTokenBalanceChange,
SimulationTokenStandard,
} from '@metamask/transaction-controller';
+import { BigNumber } from 'bignumber.js';
import { ContractExchangeRates } from '@metamask/assets-controllers';
import { useAsyncResultOrThrow } from '../../../../hooks/useAsyncResult';
import { getTokenStandardAndDetails } from '../../../../store/actions';
import { TokenStandard } from '../../../../../shared/constants/transaction';
-import { Numeric } from '../../../../../shared/modules/Numeric';
import { getConversionRate } from '../../../../ducks/metamask/metamask';
import { getCurrentChainId, getCurrentCurrency } from '../../../../selectors';
import { fetchTokenExchangeRates } from '../../../../helpers/utils/util';
import {
- Amount,
BalanceChange,
FIAT_UNAVAILABLE,
NATIVE_ASSET_IDENTIFIER,
@@ -44,12 +43,13 @@ function convertStandard(standard: SimulationTokenStandard) {
function getAssetAmount(
{ isDecrease: isNegative, difference: quantity }: SimulationBalanceChange,
decimals: number,
-): Amount {
- const numeric = Numeric.from(quantity, 16)
- .times(isNegative ? -1 : 1, 10)
- .toBase(10)
- .shiftedBy(decimals);
- return { isNegative, quantity, decimals, numeric };
+): BigNumber {
+ return (
+ new BigNumber(quantity, 16)
+ .times(isNegative ? -1 : 1)
+ // Shift the decimal point to the left by the number of decimals.
+ .shift(-decimals)
+ );
}
// Fetches the decimals for the given token address.
@@ -106,9 +106,7 @@ function getNativeBalanceChange(
}
const asset = NATIVE_ASSET_IDENTIFIER;
const amount = getAssetAmount(nativeBalanceChange, NATIVE_DECIMALS);
- const fiatAmount = amount.numeric
- .applyConversionRate(nativeFiatRate)
- .toNumber();
+ const fiatAmount = amount.times(nativeFiatRate).toNumber();
return { asset, amount, fiatAmount };
}
@@ -131,7 +129,7 @@ function getTokenBalanceChanges(
const fiatRate = erc20FiatRates[tokenBc.address];
const fiatAmount = fiatRate
- ? amount.numeric.applyConversionRate(fiatRate).toNumber()
+ ? amount.times(fiatRate).toNumber()
: FIAT_UNAVAILABLE;
return { asset, amount, fiatAmount };
diff --git a/ui/pages/confirmations/components/simulation-details/useSimulationMetrics.test.ts b/ui/pages/confirmations/components/simulation-details/useSimulationMetrics.test.ts
index c290a0fc9f9d..152fdf55eb56 100644
--- a/ui/pages/confirmations/components/simulation-details/useSimulationMetrics.test.ts
+++ b/ui/pages/confirmations/components/simulation-details/useSimulationMetrics.test.ts
@@ -3,6 +3,7 @@ import {
SimulationData,
SimulationErrorCode,
} from '@metamask/transaction-controller';
+import { BigNumber } from 'bignumber.js';
import { useTransactionEventFragment } from '../../hooks/useTransactionEventFragment';
import { TokenStandard } from '../../../../../shared/constants/transaction';
import {
@@ -44,7 +45,7 @@ const SYMBOL_MOCK = 'TST';
const BALANCE_CHANGE_MOCK = {
asset: { address: ADDRESS_MOCK, standard: TokenStandard.ERC20 },
- amount: { isNegative: true, quantity: '0x1', decimals: 18 },
+ amount: new BigNumber(-1),
fiatAmount: 1.23,
} as unknown as BalanceChange;
@@ -178,7 +179,7 @@ describe('useSimulationMetrics', () => {
])('with asset quantity if %s', (_, isNegative, property) => {
const balanceChange = {
...BALANCE_CHANGE_MOCK,
- amount: { ...BALANCE_CHANGE_MOCK.amount, isNegative },
+ amount: new BigNumber(isNegative ? -1 : 1),
};
expectUpdateTransactionEventFragmentCalled(
@@ -257,7 +258,7 @@ describe('useSimulationMetrics', () => {
{
...BALANCE_CHANGE_MOCK,
asset: { ...BALANCE_CHANGE_MOCK.asset, standard },
- amount: { ...BALANCE_CHANGE_MOCK.amount, isNegative },
+ amount: new BigNumber(isNegative ? -1 : 1),
} as BalanceChange,
],
},
@@ -303,10 +304,7 @@ describe('useSimulationMetrics', () => {
(_, fiatAmount, isNegative, property, expected) => {
const balanceChange = {
...BALANCE_CHANGE_MOCK,
- amount: {
- ...BALANCE_CHANGE_MOCK.amount,
- isNegative,
- },
+ amount: new BigNumber(isNegative ? -1 : 1),
fiatAmount,
};
@@ -397,10 +395,7 @@ describe('useSimulationMetrics', () => {
const balanceChange = {
...BALANCE_CHANGE_MOCK,
- amount: {
- ...BALANCE_CHANGE_MOCK.amount,
- isNegative,
- },
+ amount: new BigNumber(isNegative ? -1 : 1),
asset: { ...BALANCE_CHANGE_MOCK.asset, standard },
};
@@ -423,10 +418,7 @@ describe('useSimulationMetrics', () => {
])('with asset total value if %s', (_, isNegative, property) => {
const balanceChange1 = {
...BALANCE_CHANGE_MOCK,
- amount: {
- ...BALANCE_CHANGE_MOCK.amount,
- isNegative,
- },
+ amount: new BigNumber(isNegative ? -1 : 1),
fiatAmount: 1.23,
};
diff --git a/ui/pages/confirmations/components/simulation-details/useSimulationMetrics.ts b/ui/pages/confirmations/components/simulation-details/useSimulationMetrics.ts
index d1eb80c8dffe..433b1f145b89 100644
--- a/ui/pages/confirmations/components/simulation-details/useSimulationMetrics.ts
+++ b/ui/pages/confirmations/components/simulation-details/useSimulationMetrics.ts
@@ -81,11 +81,11 @@ export function useSimulationMetrics({
useIncompleteAssetEvent(balanceChanges, displayNamesByAddress);
const receivingAssets = balanceChanges.filter(
- (change) => !change.amount.isNegative,
+ (change) => !change.amount.isNegative(),
);
- const sendingAssets = balanceChanges.filter(
- (change) => change.amount.isNegative,
+ const sendingAssets = balanceChanges.filter((change) =>
+ change.amount.isNegative(),
);
const simulationResponse = getSimulationResponseType(simulationData);