diff --git a/shared/modules/conversion.utils.ts b/shared/modules/conversion.utils.ts
index e2466bcabb1a..13e5e2c7b34e 100644
--- a/shared/modules/conversion.utils.ts
+++ b/shared/modules/conversion.utils.ts
@@ -125,7 +125,7 @@ export function getValueFromWeiHex({
fromCurrency = EtherDenomination.ETH,
toCurrency,
conversionRate,
- numberOfDecimals,
+ numberOfDecimals, // 18
toDenomination = EtherDenomination.ETH,
}: {
value: NumericValue;
@@ -156,6 +156,16 @@ export function sumHexes(first: string, ...args: string[]) {
return total.toPrefixedHexString();
}
+export function sumDecimals(first: string, ...args: string[]) {
+ const firstValue = new Numeric(first, 10);
+ const total = args.reduce(
+ (acc, hexAmount) => acc.add(new Numeric(hexAmount, 10)),
+ firstValue,
+ );
+
+ return total;
+}
+
export function hexWEIToDecGWEI(value: number | string | BigNumber | BN) {
return new Numeric(value, 16, EtherDenomination.WEI)
.toBase(10)
diff --git a/ui/components/app/asset-list/asset-list.js b/ui/components/app/asset-list/asset-list.js
index 0cb8e636ced3..7b43b4cdf6f7 100644
--- a/ui/components/app/asset-list/asset-list.js
+++ b/ui/components/app/asset-list/asset-list.js
@@ -1,6 +1,7 @@
import React, { useContext, useState } from 'react';
import PropTypes from 'prop-types';
-import { useSelector } from 'react-redux';
+import { shallowEqual, useSelector } from 'react-redux';
+import { isEqual } from 'lodash';
import TokenList from '../token-list';
import { PRIMARY, SECONDARY } from '../../../helpers/constants/common';
import { useUserPreferencedCurrency } from '../../../hooks/useUserPreferencedCurrency';
@@ -10,8 +11,15 @@ import {
getNativeCurrencyImage,
getDetectedTokensInCurrentNetwork,
getIstokenDetectionInactiveOnNonMainnetSupportedNetwork,
+ getShouldHideZeroBalanceTokens,
+ getTokenExchangeRates,
+ getCurrentCurrency,
} from '../../../selectors';
-import { getNativeCurrency } from '../../../ducks/metamask/metamask';
+import {
+ getConversionRate,
+ getNativeCurrency,
+ getTokens,
+} from '../../../ducks/metamask/metamask';
import { useCurrencyDisplay } from '../../../hooks/useCurrencyDisplay';
import Box from '../../ui/box/box';
import { MetaMetricsContext } from '../../../contexts/metametrics';
@@ -26,6 +34,15 @@ import {
ImportTokenLink,
BalanceOverview,
} from '../../multichain';
+import { isEqualCaseInsensitive } from '../../../../shared/modules/string-utils';
+import { getTokenFiatAmount } from '../../../helpers/utils/token-util';
+import { formatCurrency } from '../../../helpers/utils/confirm-tx.util';
+import {
+ getValueFromWeiHex,
+ sumDecimals,
+} from '../../../../shared/modules/conversion.utils';
+import { useTokenTracker } from '../../../hooks/useTokenTracker';
+import { EtherDenomination } from '../../../../shared/constants/common';
const AssetList = ({ onClickAsset }) => {
const [showDetectedTokens, setShowDetectedTokens] = useState(false);
@@ -66,9 +83,63 @@ const AssetList = ({ onClickAsset }) => {
getIstokenDetectionInactiveOnNonMainnetSupportedNetwork,
);
+ const contractExchangeRates = useSelector(
+ getTokenExchangeRates,
+ shallowEqual,
+ );
+ const conversionRate = useSelector(getConversionRate);
+ const currentCurrency = useSelector(getCurrentCurrency);
+
+ const nativeFiat = getValueFromWeiHex({
+ value: balance,
+ toCurrency: currentCurrency,
+ conversionRate,
+ numberOfDecimals: 2,
+ });
+
+ const shouldHideZeroBalanceTokens = useSelector(
+ getShouldHideZeroBalanceTokens,
+ );
+ // use `isEqual` comparison function because the token array is serialized
+ // from the background so it has a new reference with each background update,
+ // even if the tokens haven't changed
+ const tokens = useSelector(getTokens, isEqual);
+ const { loading, tokensWithBalances } = useTokenTracker(
+ tokens,
+ true,
+ shouldHideZeroBalanceTokens,
+ );
+
+ const dollarBalances = tokensWithBalances.map((token) => {
+ const contractExchangeTokenKey = Object.keys(contractExchangeRates).find(
+ (key) => isEqualCaseInsensitive(key, token.address),
+ );
+ const tokenExchangeRate =
+ (contractExchangeTokenKey &&
+ contractExchangeRates[contractExchangeTokenKey]) ??
+ 0;
+
+ const fiat = getTokenFiatAmount(
+ tokenExchangeRate,
+ conversionRate,
+ currentCurrency,
+ token.string,
+ token.symbol,
+ false,
+ false,
+ );
+
+ return fiat;
+ });
+
+ const totalFiat = formatCurrency(
+ sumDecimals(nativeFiat, ...dollarBalances).toString(10),
+ currentCurrency,
+ );
+
return (
<>
- {process.env.MULTICHAIN ? : null}
+ {process.env.MULTICHAIN ? : null}
onClickAsset(nativeCurrency)}
title={nativeCurrency}
@@ -80,6 +151,8 @@ const AssetList = ({ onClickAsset }) => {
tokenImage={balanceIsLoading ? null : primaryTokenImage}
/>
{
onClickAsset(tokenAddress);
trackEvent({
diff --git a/ui/components/app/token-list/token-list.js b/ui/components/app/token-list/token-list.js
index 44d801cef4b3..c584eb4e184b 100644
--- a/ui/components/app/token-list/token-list.js
+++ b/ui/components/app/token-list/token-list.js
@@ -1,13 +1,7 @@
import React from 'react';
import PropTypes from 'prop-types';
-import { isEqual } from 'lodash';
-
-import { useSelector } from 'react-redux';
import TokenCell from '../token-cell';
import { useI18nContext } from '../../../hooks/useI18nContext';
-import { useTokenTracker } from '../../../hooks/useTokenTracker';
-import { getShouldHideZeroBalanceTokens } from '../../../selectors';
-import { getTokens } from '../../../ducks/metamask/metamask';
import { Box } from '../../component-library';
import {
AlignItems,
@@ -15,20 +9,9 @@ import {
JustifyContent,
} from '../../../helpers/constants/design-system';
-export default function TokenList({ onTokenClick }) {
+export default function TokenList({ onTokenClick, tokens, loading = false }) {
const t = useI18nContext();
- const shouldHideZeroBalanceTokens = useSelector(
- getShouldHideZeroBalanceTokens,
- );
- // use `isEqual` comparison function because the token array is serialized
- // from the background so it has a new reference with each background update,
- // even if the tokens haven't changed
- const tokens = useSelector(getTokens, isEqual);
- const { loading, tokensWithBalances } = useTokenTracker(
- tokens,
- true,
- shouldHideZeroBalanceTokens,
- );
+
if (loading) {
return (
- {tokensWithBalances.map((tokenData, index) => {
- return ;
- })}
+ {tokens.map((tokenData, index) => (
+
+ ))}
);
}
TokenList.propTypes = {
onTokenClick: PropTypes.func.isRequired,
+ tokens: PropTypes.array.isRequired,
+ loading: PropTypes.bool,
};
diff --git a/ui/components/multichain/balance-overview/balance-overview.js b/ui/components/multichain/balance-overview/balance-overview.js
index 7f7a5f912e63..46962d7854b2 100644
--- a/ui/components/multichain/balance-overview/balance-overview.js
+++ b/ui/components/multichain/balance-overview/balance-overview.js
@@ -1,13 +1,14 @@
import React, { useContext } from 'react';
import { useSelector } from 'react-redux';
import classnames from 'classnames';
+import PropTypes from 'prop-types';
import { useI18nContext } from '../../../hooks/useI18nContext';
import { MetaMetricsContext } from '../../../contexts/metametrics';
import {
MetaMetricsEventCategory,
MetaMetricsEventName,
} from '../../../../shared/constants/metametrics';
-import { Box, ButtonSecondary, IconName } from '../../component-library';
+import { Box, ButtonSecondary, IconName, Text } from '../../component-library';
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
import {
getMmiPortfolioEnabled,
@@ -22,12 +23,9 @@ import {
getCurrentChainId,
getMetaMetricsId,
///: END:ONLY_INCLUDE_IN
- getSelectedAccountCachedBalance,
isBalanceCached,
} from '../../../selectors';
import Spinner from '../../ui/spinner';
-import UserPreferencedCurrencyDisplay from '../../app/user-preferenced-currency-display';
-import { PRIMARY, SECONDARY } from '../../../helpers/constants/common';
import {
AlignItems,
Display,
@@ -39,7 +37,7 @@ import {
import { CURRENCY_SYMBOLS } from '../../../../shared/constants/network';
///: END:ONLY_INCLUDE_IN
-export const BalanceOverview = () => {
+export const BalanceOverview = ({ balance }) => {
const trackEvent = useContext(MetaMetricsContext);
const t = useI18nContext();
///: BEGIN:ONLY_INCLUDE_IN(build-main,build-beta,build-flask)
@@ -47,7 +45,6 @@ export const BalanceOverview = () => {
const chainId = useSelector(getCurrentChainId);
///: END:ONLY_INCLUDE_IN
const balanceIsCached = useSelector(isBalanceCached);
- const balance = useSelector(getSelectedAccountCachedBalance);
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
const mmiPortfolioEnabled = useSelector(getMmiPortfolioEnabled);
@@ -85,56 +82,25 @@ export const BalanceOverview = () => {
>
{balance ? (
-
+ {balance}
+
+ ) : (
+
+ )}
+
+ {balanceIsCached ? (
+ *
) : null}
-
- {balance ? (
-
- ) : (
-
- )}
- {balanceIsCached ? (
- *
- ) : null}
-
{
///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
@@ -172,3 +138,7 @@ export const BalanceOverview = () => {
);
};
+
+BalanceOverview.propTypes = {
+ balance: PropTypes.string.isRequired,
+};