diff --git a/ui/pages/swaps/prepare-swap-page/review-quote.js b/ui/pages/swaps/prepare-swap-page/review-quote.js
index 496ae5ee6d9e..31cf9959f231 100644
--- a/ui/pages/swaps/prepare-swap-page/review-quote.js
+++ b/ui/pages/swaps/prepare-swap-page/review-quote.js
@@ -23,7 +23,6 @@ import { useGasFeeInputs } from '../../confirmations/hooks/useGasFeeInputs';
import { MetaMetricsContext } from '../../../contexts/metametrics';
import {
getQuotes,
- getSelectedQuote,
getApproveTxParams,
getFetchParams,
setBalanceError,
@@ -36,6 +35,7 @@ import {
getDestinationTokenInfo,
getUsedSwapsGasPrice,
getTopQuote,
+ getUsedQuote,
signAndSendTransactions,
getBackgroundSwapRouteState,
swapsQuoteSelected,
@@ -84,6 +84,7 @@ import {
decimalToHex,
decWEIToDecETH,
sumHexes,
+ hexToDecimal,
} from '../../../../shared/modules/conversion.utils';
import { getCustomTxParamsData } from '../../confirmations/confirm-approve/confirm-approve.util';
import {
@@ -113,6 +114,7 @@ import {
Size,
FlexDirection,
Severity,
+ FontStyle,
} from '../../../helpers/constants/design-system';
import {
BannerAlert,
@@ -143,11 +145,41 @@ import {
import ExchangeRateDisplay from '../exchange-rate-display';
import InfoTooltip from '../../../components/ui/info-tooltip';
import useRamps from '../../../hooks/ramps/useRamps/useRamps';
+import { getTokenFiatAmount } from '../../../helpers/utils/token-util';
+import { toChecksumHexAddress } from '../../../../shared/modules/hexstring-utils';
import ViewQuotePriceDifference from './view-quote-price-difference';
import SlippageNotificationModal from './slippage-notification-modal';
let intervalId;
+const ViewAllQuotesLink = React.memo(function ViewAllQuotesLink({
+ trackAllAvailableQuotesOpened,
+ setSelectQuotePopoverShown,
+ t,
+}) {
+ const handleClick = useCallback(() => {
+ trackAllAvailableQuotesOpened();
+ setSelectQuotePopoverShown(true);
+ }, [trackAllAvailableQuotesOpened, setSelectQuotePopoverShown]);
+
+ return (
+
+ );
+});
+
+ViewAllQuotesLink.propTypes = {
+ trackAllAvailableQuotesOpened: PropTypes.func.isRequired,
+ setSelectQuotePopoverShown: PropTypes.func.isRequired,
+ t: PropTypes.func.isRequired,
+};
+
export default function ReviewQuote({ setReceiveToAmount }) {
const history = useHistory();
const dispatch = useDispatch();
@@ -206,9 +238,8 @@ export default function ReviewQuote({ setReceiveToAmount }) {
const balanceError = useSelector(getBalanceError);
const fetchParams = useSelector(getFetchParams, isEqual);
const approveTxParams = useSelector(getApproveTxParams, shallowEqual);
- const selectedQuote = useSelector(getSelectedQuote, isEqual);
const topQuote = useSelector(getTopQuote, isEqual);
- const usedQuote = selectedQuote || topQuote;
+ const usedQuote = useSelector(getUsedQuote, isEqual);
const tradeValue = usedQuote?.trade?.value ?? '0x0';
const defaultSwapsToken = useSelector(getSwapsDefaultToken, isEqual);
const chainId = useSelector(getCurrentChainId);
@@ -229,6 +260,7 @@ export default function ReviewQuote({ setReceiveToAmount }) {
const smartTransactionFees = useSelector(getSmartTransactionFees, isEqual);
const swapsNetworkConfig = useSelector(getSwapsNetworkConfig, shallowEqual);
const unsignedTransaction = usedQuote.trade;
+ const { isGasIncludedTrade } = usedQuote;
const isSmartTransaction =
currentSmartTransactionsEnabled && smartTransactionsOptInStatus;
@@ -880,7 +912,9 @@ export default function ReviewQuote({ setReceiveToAmount }) {
]);
useEffect(() => {
- if (isSmartTransaction && !insufficientTokens) {
+ // If it's a smart transaction, has sufficient tokens, and gas is not included in the trade,
+ // set up gas fee polling.
+ if (isSmartTransaction && !insufficientTokens && !isGasIncludedTrade) {
const unsignedTx = {
from: unsignedTransaction.from,
to: unsignedTransaction.to,
@@ -923,6 +957,7 @@ export default function ReviewQuote({ setReceiveToAmount }) {
chainId,
swapsNetworkConfig.stxGetTransactionsRefreshTime,
insufficientTokens,
+ isGasIncludedTrade,
]);
useEffect(() => {
@@ -1045,6 +1080,40 @@ export default function ReviewQuote({ setReceiveToAmount }) {
}
};
+ const gasTokenFiatAmount = useMemo(() => {
+ if (!isGasIncludedTrade) {
+ return undefined;
+ }
+ const tradeTxTokenFee =
+ smartTransactionFees?.tradeTxFees?.fees?.[0]?.tokenFees?.[0];
+ if (!tradeTxTokenFee) {
+ return undefined;
+ }
+ const { token: { address, decimals, symbol } = {}, balanceNeededToken } =
+ tradeTxTokenFee;
+ const checksumAddress = toChecksumHexAddress(address);
+ const contractExchangeRate = memoizedTokenConversionRates[checksumAddress];
+ const gasTokenAmountDec = calcTokenAmount(
+ hexToDecimal(balanceNeededToken),
+ decimals,
+ ).toString(10);
+ return getTokenFiatAmount(
+ contractExchangeRate,
+ conversionRate,
+ currentCurrency,
+ gasTokenAmountDec,
+ symbol,
+ true,
+ true,
+ );
+ }, [
+ isGasIncludedTrade,
+ smartTransactionFees,
+ memoizedTokenConversionRates,
+ conversionRate,
+ currentCurrency,
+ ]);
+
return (
@@ -67,7 +67,7 @@ exports[`Token Cell should match snapshot 1`] = `
5.00
5
diff --git a/ui/components/app/confirm/info/row/currency.stories.tsx b/ui/components/app/confirm/info/row/currency.stories.tsx
index 2a520ca5bd35..ca9926e5cc6b 100644
--- a/ui/components/app/confirm/info/row/currency.stories.tsx
+++ b/ui/components/app/confirm/info/row/currency.stories.tsx
@@ -12,7 +12,7 @@ const store = configureStore({
...mockState.metamask,
preferences: {
...mockState.metamask.preferences,
- useNativeCurrencyAsPrimaryCurrency: false,
+ showNativeTokenAsMainBalance: false,
},
},
});
@@ -29,7 +29,7 @@ const ConfirmInfoRowCurrencyStory = {
control: 'text',
},
},
- decorators: [(story: any) => {story()}]
+ decorators: [(story: any) => {story()}],
};
export const DefaultStory = ({ variant, value }) => (
diff --git a/ui/components/app/confirm/info/row/currency.tsx b/ui/components/app/confirm/info/row/currency.tsx
index 82ce82c3a113..51ce1fceba28 100644
--- a/ui/components/app/confirm/info/row/currency.tsx
+++ b/ui/components/app/confirm/info/row/currency.tsx
@@ -1,6 +1,5 @@
import React from 'react';
-import { PRIMARY } from '../../../../../helpers/constants/common';
import {
AlignItems,
Display,
@@ -38,7 +37,7 @@ export const ConfirmInfoRowCurrency = ({
{currency ? (
) : (
-
+
)}
);
diff --git a/ui/components/app/modals/cancel-transaction/cancel-transaction-gas-fee/cancel-transaction-gas-fee.component.test.js b/ui/components/app/modals/cancel-transaction/cancel-transaction-gas-fee/cancel-transaction-gas-fee.component.test.js
index 05bce9e841a0..8966fa01b749 100644
--- a/ui/components/app/modals/cancel-transaction/cancel-transaction-gas-fee/cancel-transaction-gas-fee.component.test.js
+++ b/ui/components/app/modals/cancel-transaction/cancel-transaction-gas-fee/cancel-transaction-gas-fee.component.test.js
@@ -11,9 +11,7 @@ describe('CancelTransactionGasFee Component', () => {
metamask: {
...mockNetworkState({ chainId: CHAIN_IDS.MAINNET }),
currencyRates: {},
- preferences: {
- useNativeCurrencyAsPrimaryCurrency: false,
- },
+ preferences: {},
completedOnboarding: true,
internalAccounts: mockState.metamask.internalAccounts,
},
diff --git a/ui/components/app/modals/customize-nonce/__snapshots__/customize-nonce.test.js.snap b/ui/components/app/modals/customize-nonce/__snapshots__/customize-nonce.test.js.snap
index cab80e399a43..020adaa0c952 100644
--- a/ui/components/app/modals/customize-nonce/__snapshots__/customize-nonce.test.js.snap
+++ b/ui/components/app/modals/customize-nonce/__snapshots__/customize-nonce.test.js.snap
@@ -75,7 +75,7 @@ exports[`Customize Nonce should match snapshot 1`] = `
class="MuiFormControl-root MuiTextField-root MuiFormControl-marginDense MuiFormControl-fullWidth"
>
(selector) => {
} else if (selector === getCurrentNetwork) {
return { nickname: 'Ethereum Mainnet' };
} else if (selector === getPreferences) {
- return (
- opts.preferences ?? {
- useNativeCurrencyAsPrimaryCurrency: true,
- }
- );
+ return opts.preferences ?? {};
} else if (selector === getShouldShowFiat) {
return opts.shouldShowFiat ?? false;
} else if (selector === getTokens) {
diff --git a/ui/components/app/user-preferenced-currency-display/user-preferenced-currency-display.component.d.ts b/ui/components/app/user-preferenced-currency-display/user-preferenced-currency-display.component.d.ts
index 9e4ca5565733..3bf65d98d19c 100644
--- a/ui/components/app/user-preferenced-currency-display/user-preferenced-currency-display.component.d.ts
+++ b/ui/components/app/user-preferenced-currency-display/user-preferenced-currency-display.component.d.ts
@@ -12,6 +12,8 @@ export type UserPrefrencedCurrencyDisplayProps = OverridingUnion<
showFiat?: boolean;
showNative?: boolean;
showCurrencySuffix?: boolean;
+ shouldCheckShowNativeToken?: boolean;
+ isAggregatedFiatOverviewBalance?: boolean;
}
>;
diff --git a/ui/components/app/user-preferenced-currency-display/user-preferenced-currency-display.component.js b/ui/components/app/user-preferenced-currency-display/user-preferenced-currency-display.component.js
index 294e6063f0ad..4b5492091288 100644
--- a/ui/components/app/user-preferenced-currency-display/user-preferenced-currency-display.component.js
+++ b/ui/components/app/user-preferenced-currency-display/user-preferenced-currency-display.component.js
@@ -25,6 +25,7 @@ export default function UserPreferencedCurrencyDisplay({
showFiat,
showNative,
showCurrencySuffix,
+ shouldCheckShowNativeToken,
...restProps
}) {
const currentNetwork = useMultichainSelector(
@@ -42,6 +43,7 @@ export default function UserPreferencedCurrencyDisplay({
numberOfDecimals: propsNumberOfDecimals,
showFiatOverride: showFiat,
showNativeOverride: showNative,
+ shouldCheckShowNativeToken,
});
const prefixComponent = useMemo(() => {
return (
@@ -112,6 +114,7 @@ const UserPreferencedCurrencyDisplayPropTypes = {
prefixComponentWrapperProps: PropTypes.object,
textProps: PropTypes.object,
suffixProps: PropTypes.object,
+ shouldCheckShowNativeToken: PropTypes.bool,
};
UserPreferencedCurrencyDisplay.propTypes =
diff --git a/ui/components/app/user-preferenced-currency-display/user-preferenced-currency-display.test.js b/ui/components/app/user-preferenced-currency-display/user-preferenced-currency-display.test.js
index 51ee63d40c17..2a6193847fa4 100644
--- a/ui/components/app/user-preferenced-currency-display/user-preferenced-currency-display.test.js
+++ b/ui/components/app/user-preferenced-currency-display/user-preferenced-currency-display.test.js
@@ -13,9 +13,7 @@ describe('UserPreferencedCurrencyDisplay Component', () => {
...mockState.metamask,
...mockNetworkState({ chainId: CHAIN_IDS.MAINNET }),
currencyRates: {},
- preferences: {
- useNativeCurrencyAsPrimaryCurrency: true,
- },
+ preferences: {},
},
};
const mockStore = configureMockStore()(defaultState);
diff --git a/ui/components/app/user-preferenced-currency-input/user-preferenced-currency-input.component.js b/ui/components/app/user-preferenced-currency-input/user-preferenced-currency-input.component.js
index 70b232848d16..7e34a90bba27 100644
--- a/ui/components/app/user-preferenced-currency-input/user-preferenced-currency-input.component.js
+++ b/ui/components/app/user-preferenced-currency-input/user-preferenced-currency-input.component.js
@@ -2,27 +2,21 @@ import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import CurrencyInput from '../currency-input';
+// Noticed this component is not used in codebase;
+// removing usage of useNativeCurrencyAsPrimaryCurrency because its being removed in this PR
export default class UserPreferencedCurrencyInput extends PureComponent {
static propTypes = {
- useNativeCurrencyAsPrimaryCurrency: PropTypes.bool,
sendInputCurrencySwitched: PropTypes.bool,
...CurrencyInput.propTypes,
};
render() {
- const {
- useNativeCurrencyAsPrimaryCurrency,
- sendInputCurrencySwitched,
- ...restProps
- } = this.props;
+ const { sendInputCurrencySwitched, ...restProps } = this.props;
return (
);
}
diff --git a/ui/components/app/user-preferenced-currency-input/user-preferenced-currency-input.container.js b/ui/components/app/user-preferenced-currency-input/user-preferenced-currency-input.container.js
index 042b73c249ae..7bec54e5dd8f 100644
--- a/ui/components/app/user-preferenced-currency-input/user-preferenced-currency-input.container.js
+++ b/ui/components/app/user-preferenced-currency-input/user-preferenced-currency-input.container.js
@@ -1,13 +1,9 @@
import { connect } from 'react-redux';
import { toggleCurrencySwitch } from '../../../ducks/app/app';
-import { getPreferences } from '../../../selectors';
import UserPreferencedCurrencyInput from './user-preferenced-currency-input.component';
const mapStateToProps = (state) => {
- const { useNativeCurrencyAsPrimaryCurrency } = getPreferences(state);
-
return {
- useNativeCurrencyAsPrimaryCurrency,
sendInputCurrencySwitched: state.appState.sendInputCurrencySwitched,
};
};
diff --git a/ui/components/app/user-preferenced-token-input/user-preferenced-token-input.component.js b/ui/components/app/user-preferenced-token-input/user-preferenced-token-input.component.js
index a285446100ed..ee8178664564 100644
--- a/ui/components/app/user-preferenced-token-input/user-preferenced-token-input.component.js
+++ b/ui/components/app/user-preferenced-token-input/user-preferenced-token-input.component.js
@@ -3,6 +3,7 @@ import PropTypes from 'prop-types';
import TokenInput from '../../ui/token-input';
import { getTokenSymbol } from '../../../store/actions';
+// This component is not used in codebase, removing usage of useNativeCurrencyAsPrimaryCurrency in this PR
export default class UserPreferencedTokenInput extends PureComponent {
static propTypes = {
token: PropTypes.shape({
@@ -10,7 +11,6 @@ export default class UserPreferencedTokenInput extends PureComponent {
decimals: PropTypes.number,
symbol: PropTypes.string,
}).isRequired,
- useNativeCurrencyAsPrimaryCurrency: PropTypes.bool,
};
state = {
@@ -28,16 +28,10 @@ export default class UserPreferencedTokenInput extends PureComponent {
}
render() {
- const { useNativeCurrencyAsPrimaryCurrency, ...restProps } = this.props;
+ const { ...restProps } = this.props;
return (
-
+
);
}
}
diff --git a/ui/components/app/user-preferenced-token-input/user-preferenced-token-input.container.js b/ui/components/app/user-preferenced-token-input/user-preferenced-token-input.container.js
index 33afd8ce24a4..03c0c5eda7bf 100644
--- a/ui/components/app/user-preferenced-token-input/user-preferenced-token-input.container.js
+++ b/ui/components/app/user-preferenced-token-input/user-preferenced-token-input.container.js
@@ -1,15 +1,8 @@
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
-import { getPreferences } from '../../../selectors';
import UserPreferencedTokenInput from './user-preferenced-token-input.component';
-const mapStateToProps = (state) => {
- const { useNativeCurrencyAsPrimaryCurrency } = getPreferences(state);
-
- return {
- useNativeCurrencyAsPrimaryCurrency,
- };
-};
+const mapStateToProps = (state) => state;
const UserPreferencedTokenInputContainer = connect(mapStateToProps)(
UserPreferencedTokenInput,
diff --git a/ui/components/app/wallet-overview/__snapshots__/aggregated-percentage-overview.test.tsx.snap b/ui/components/app/wallet-overview/__snapshots__/aggregated-percentage-overview.test.tsx.snap
new file mode 100644
index 000000000000..59dac675d1df
--- /dev/null
+++ b/ui/components/app/wallet-overview/__snapshots__/aggregated-percentage-overview.test.tsx.snap
@@ -0,0 +1,23 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`AggregatedPercentageOverview render renders correctly 1`] = `
+
+
+
+ +$0.00
+
+
+ (+0.00%)
+
+
+
+`;
diff --git a/ui/components/app/wallet-overview/aggregated-percentage-overview.test.tsx b/ui/components/app/wallet-overview/aggregated-percentage-overview.test.tsx
new file mode 100644
index 000000000000..95e0d92fa2b8
--- /dev/null
+++ b/ui/components/app/wallet-overview/aggregated-percentage-overview.test.tsx
@@ -0,0 +1,592 @@
+import React from 'react';
+import { render, screen } from '@testing-library/react';
+import '@testing-library/jest-dom';
+import { getIntlLocale } from '../../../ducks/locale/locale';
+import {
+ getCurrentCurrency,
+ getSelectedAccount,
+ getShouldHideZeroBalanceTokens,
+ getTokensMarketData,
+} from '../../../selectors';
+import { useAccountTotalFiatBalance } from '../../../hooks/useAccountTotalFiatBalance';
+import { AggregatedPercentageOverview } from './aggregated-percentage-overview';
+
+jest.mock('react-redux', () => ({
+ useSelector: jest.fn((selector) => selector()),
+}));
+
+jest.mock('../../../ducks/locale/locale', () => ({
+ getIntlLocale: jest.fn(),
+}));
+
+jest.mock('../../../selectors', () => ({
+ getCurrentCurrency: jest.fn(),
+ getSelectedAccount: jest.fn(),
+ getShouldHideZeroBalanceTokens: jest.fn(),
+ getTokensMarketData: jest.fn(),
+}));
+
+jest.mock('../../../hooks/useAccountTotalFiatBalance', () => ({
+ useAccountTotalFiatBalance: jest.fn(),
+}));
+
+const mockGetIntlLocale = getIntlLocale as unknown as jest.Mock;
+const mockGetCurrentCurrency = getCurrentCurrency as jest.Mock;
+const mockGetSelectedAccount = getSelectedAccount as unknown as jest.Mock;
+const mockGetShouldHideZeroBalanceTokens =
+ getShouldHideZeroBalanceTokens as jest.Mock;
+
+const mockGetTokensMarketData = getTokensMarketData as jest.Mock;
+
+const selectedAccountMock = {
+ id: 'd51c0116-de36-4e77-b35b-408d4ea82d01',
+ address: '0xa259af9db8172f62ef0373d7dfa893a3e245ace9',
+ options: {},
+ methods: [
+ 'personal_sign',
+ 'eth_sign',
+ 'eth_signTransaction',
+ 'eth_signTypedData_v1',
+ 'eth_signTypedData_v3',
+ 'eth_signTypedData_v4',
+ ],
+ type: 'eip155:eoa',
+ metadata: {
+ name: 'Account 2',
+ importTime: 1725467263902,
+ lastSelected: 1725467263905,
+ keyring: {
+ type: 'Simple Key Pair',
+ },
+ },
+ balance: '0x0f7e2a03e67666',
+};
+
+const marketDataMock = {
+ '0x0000000000000000000000000000000000000000': {
+ tokenAddress: '0x0000000000000000000000000000000000000000',
+ currency: 'ETH',
+ id: 'ethereum',
+ price: 0.999893213343359,
+ pricePercentChange1d: -0.7173299395012226,
+ },
+ '0x6B175474E89094C44Da98b954EedeAC495271d0F': {
+ tokenAddress: '0x6B175474E89094C44Da98b954EedeAC495271d0F',
+ currency: 'ETH',
+ id: 'dai',
+ price: 0.00041861840136257403,
+ pricePercentChange1d: -0.0862498076183525,
+ },
+ '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48': {
+ tokenAddress: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
+ currency: 'ETH',
+ id: 'usd-coin',
+ price: 0.0004185384042093742,
+ pricePercentChange1d: -0.07612981257899307,
+ },
+ '0xdAC17F958D2ee523a2206206994597C13D831ec7': {
+ tokenAddress: '0xdAC17F958D2ee523a2206206994597C13D831ec7',
+ currency: 'ETH',
+ id: 'tether',
+ price: 0.0004183549552402562,
+ pricePercentChange1d: -0.1357979347463155,
+ },
+};
+
+const positiveMarketDataMock = {
+ '0x0000000000000000000000000000000000000000': {
+ tokenAddress: '0x0000000000000000000000000000000000000000',
+ currency: 'ETH',
+ id: 'ethereum',
+ price: 0.999893213343359,
+ pricePercentChange1d: 0.7173299395012226,
+ },
+ '0x6B175474E89094C44Da98b954EedeAC495271d0F': {
+ tokenAddress: '0x6B175474E89094C44Da98b954EedeAC495271d0F',
+ currency: 'ETH',
+ id: 'dai',
+ price: 0.00041861840136257403,
+ pricePercentChange1d: 0.0862498076183525,
+ },
+ '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48': {
+ tokenAddress: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
+ currency: 'ETH',
+ id: 'usd-coin',
+ price: 0.0004185384042093742,
+ pricePercentChange1d: 0.07612981257899307,
+ },
+ '0xdAC17F958D2ee523a2206206994597C13D831ec7': {
+ tokenAddress: '0xdAC17F958D2ee523a2206206994597C13D831ec7',
+ currency: 'ETH',
+ id: 'tether',
+ price: 0.0004183549552402562,
+ pricePercentChange1d: 0.1357979347463155,
+ },
+};
+
+const mixedMarketDataMock = {
+ '0x0000000000000000000000000000000000000000': {
+ tokenAddress: '0x0000000000000000000000000000000000000000',
+ currency: 'ETH',
+ id: 'ethereum',
+ price: 0.999893213343359,
+ pricePercentChange1d: -0.7173299395012226,
+ },
+ '0x6B175474E89094C44Da98b954EedeAC495271d0F': {
+ tokenAddress: '0x6B175474E89094C44Da98b954EedeAC495271d0F',
+ currency: 'ETH',
+ id: 'dai',
+ price: 0.00041861840136257403,
+ pricePercentChange1d: 0.0862498076183525,
+ },
+ '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48': {
+ tokenAddress: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
+ currency: 'ETH',
+ id: 'usd-coin',
+ price: 0.0004185384042093742,
+ pricePercentChange1d: -0.07612981257899307,
+ },
+ '0xdAC17F958D2ee523a2206206994597C13D831ec7': {
+ tokenAddress: '0xdAC17F958D2ee523a2206206994597C13D831ec7',
+ currency: 'ETH',
+ id: 'tether',
+ price: 0.0004183549552402562,
+ pricePercentChange1d: 0.1357979347463155,
+ },
+};
+
+describe('AggregatedPercentageOverview', () => {
+ beforeEach(() => {
+ mockGetIntlLocale.mockReturnValue('en-US');
+ mockGetCurrentCurrency.mockReturnValue('USD');
+ mockGetSelectedAccount.mockReturnValue(selectedAccountMock);
+ mockGetShouldHideZeroBalanceTokens.mockReturnValue(false);
+ mockGetTokensMarketData.mockReturnValue(marketDataMock);
+
+ jest.clearAllMocks();
+ });
+
+ describe('render', () => {
+ it('renders correctly', () => {
+ (useAccountTotalFiatBalance as jest.Mock).mockReturnValue({
+ orderedTokenList: [
+ {
+ iconUrl: './images/eth_logo.svg',
+ symbol: 'ETH',
+ fiatBalance: '0',
+ },
+ ],
+ totalFiatBalance: 0,
+ });
+ const { container } = render(
);
+ expect(container).toMatchSnapshot();
+ });
+ });
+
+ it('should display zero percentage and amount if balance is zero', () => {
+ (useAccountTotalFiatBalance as jest.Mock).mockReturnValue({
+ orderedTokenList: [
+ {
+ iconUrl: './images/eth_logo.svg',
+ symbol: 'ETH',
+ fiatBalance: '0',
+ },
+ ],
+ totalFiatBalance: 0,
+ });
+
+ render(
);
+ const percentageElement = screen.getByText('(+0.00%)');
+ const numberElement = screen.getByText('+$0.00');
+ expect(percentageElement).toBeInTheDocument();
+ expect(numberElement).toBeInTheDocument();
+ });
+
+ it('should display negative aggregated amount and percentage change with all negative market data', () => {
+ (useAccountTotalFiatBalance as jest.Mock).mockReturnValue({
+ orderedTokenList: [
+ {
+ address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
+ decimals: 6,
+ iconUrl:
+ 'https://static.cx.metamask.io/api/v1/tokenIcons/1/0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48.png',
+ name: 'USDC',
+ occurrences: 16,
+ symbol: 'USDC',
+ balance: '11754897',
+ string: '11.75489',
+ balanceError: null,
+ fiatBalance: '11.77',
+ },
+ {
+ iconUrl: './images/eth_logo.svg',
+ symbol: 'ETH',
+ fiatBalance: '10.45',
+ },
+ {
+ address: '0x6b175474e89094c44da98b954eedeac495271d0f',
+ decimals: 18,
+ iconUrl:
+ 'https://static.cx.metamask.io/api/v1/tokenIcons/1/0x6b175474e89094c44da98b954eedeac495271d0f.png',
+ name: 'Dai Stablecoin',
+ occurrences: 17,
+ symbol: 'DAI',
+ balance: '6520850325578202013',
+ string: '6.52085',
+ balanceError: null,
+ fiatBalance: '6.53',
+ },
+ {
+ address: '0xdac17f958d2ee523a2206206994597c13d831ec7',
+ decimals: 6,
+ iconUrl:
+ 'https://static.cx.metamask.io/api/v1/tokenIcons/1/0xdac17f958d2ee523a2206206994597c13d831ec7.png',
+ name: 'Tether USD',
+ occurrences: 15,
+ symbol: 'USDT',
+ balance: '3379966',
+ string: '3.37996',
+ balanceError: null,
+ fiatBalance: '3.38',
+ },
+ ],
+ totalFiatBalance: 32.13,
+ });
+ const expectedAmountChange = '-$0.09';
+ const expectedPercentageChange = '(-0.29%)';
+ render(
);
+ const percentageElement = screen.getByText(expectedPercentageChange);
+ const numberElement = screen.getByText(expectedAmountChange);
+ expect(percentageElement).toBeInTheDocument();
+ expect(numberElement).toBeInTheDocument();
+ });
+
+ it('should display positive aggregated amount and percentage change with all positive market data', () => {
+ (useAccountTotalFiatBalance as jest.Mock).mockReturnValue({
+ orderedTokenList: [
+ {
+ address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
+ decimals: 6,
+ iconUrl:
+ 'https://static.cx.metamask.io/api/v1/tokenIcons/1/0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48.png',
+ name: 'USDC',
+ occurrences: 16,
+ symbol: 'USDC',
+ balance: '11754897',
+ string: '11.75489',
+ balanceError: null,
+ fiatBalance: '11.77',
+ },
+ {
+ iconUrl: './images/eth_logo.svg',
+ symbol: 'ETH',
+ fiatBalance: '10.45',
+ },
+ {
+ address: '0x6b175474e89094c44da98b954eedeac495271d0f',
+ decimals: 18,
+ iconUrl:
+ 'https://static.cx.metamask.io/api/v1/tokenIcons/1/0x6b175474e89094c44da98b954eedeac495271d0f.png',
+ name: 'Dai Stablecoin',
+ occurrences: 17,
+ symbol: 'DAI',
+ balance: '6520850325578202013',
+ string: '6.52085',
+ balanceError: null,
+ fiatBalance: '6.53',
+ },
+ {
+ address: '0xdac17f958d2ee523a2206206994597c13d831ec7',
+ decimals: 6,
+ iconUrl:
+ 'https://static.cx.metamask.io/api/v1/tokenIcons/1/0xdac17f958d2ee523a2206206994597c13d831ec7.png',
+ name: 'Tether USD',
+ occurrences: 15,
+ symbol: 'USDT',
+ balance: '3379966',
+ string: '3.37996',
+ balanceError: null,
+ fiatBalance: '3.38',
+ },
+ ],
+ totalFiatBalance: 32.13,
+ });
+ mockGetTokensMarketData.mockReturnValue(positiveMarketDataMock);
+ const expectedAmountChange = '+$0.09';
+ const expectedPercentageChange = '(+0.29%)';
+ render(
);
+ const percentageElement = screen.getByText(expectedPercentageChange);
+ const numberElement = screen.getByText(expectedAmountChange);
+ expect(percentageElement).toBeInTheDocument();
+ expect(numberElement).toBeInTheDocument();
+ });
+
+ it('should display correct aggregated amount and percentage change with positive and negative market data', () => {
+ (useAccountTotalFiatBalance as jest.Mock).mockReturnValue({
+ orderedTokenList: [
+ {
+ address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
+ decimals: 6,
+ iconUrl:
+ 'https://static.cx.metamask.io/api/v1/tokenIcons/1/0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48.png',
+ name: 'USDC',
+ occurrences: 16,
+ symbol: 'USDC',
+ balance: '11754897',
+ string: '11.75489',
+ balanceError: null,
+ fiatBalance: '11.77',
+ },
+ {
+ iconUrl: './images/eth_logo.svg',
+ symbol: 'ETH',
+ fiatBalance: '10.45',
+ },
+ {
+ address: '0x6b175474e89094c44da98b954eedeac495271d0f',
+ decimals: 18,
+ iconUrl:
+ 'https://static.cx.metamask.io/api/v1/tokenIcons/1/0x6b175474e89094c44da98b954eedeac495271d0f.png',
+ name: 'Dai Stablecoin',
+ occurrences: 17,
+ symbol: 'DAI',
+ balance: '6520850325578202013',
+ string: '6.52085',
+ balanceError: null,
+ fiatBalance: '6.53',
+ },
+ {
+ address: '0xdac17f958d2ee523a2206206994597c13d831ec7',
+ decimals: 6,
+ iconUrl:
+ 'https://static.cx.metamask.io/api/v1/tokenIcons/1/0xdac17f958d2ee523a2206206994597c13d831ec7.png',
+ name: 'Tether USD',
+ occurrences: 15,
+ symbol: 'USDT',
+ balance: '3379966',
+ string: '3.37996',
+ balanceError: null,
+ fiatBalance: '3.38',
+ },
+ ],
+ totalFiatBalance: 32.13,
+ });
+ mockGetTokensMarketData.mockReturnValue(mixedMarketDataMock);
+ const expectedAmountChange = '-$0.07';
+ const expectedPercentageChange = '(-0.23%)';
+ render(
);
+ const percentageElement = screen.getByText(expectedPercentageChange);
+ const numberElement = screen.getByText(expectedAmountChange);
+ expect(percentageElement).toBeInTheDocument();
+ expect(numberElement).toBeInTheDocument();
+ });
+
+ it('should display correct aggregated amount and percentage when one ERC20 fiatBalance is undefined', () => {
+ (useAccountTotalFiatBalance as jest.Mock).mockReturnValue({
+ orderedTokenList: [
+ {
+ iconUrl: './images/eth_logo.svg',
+ symbol: 'ETH',
+ fiatBalance: '21.12',
+ },
+ {
+ symbol: 'USDC',
+ decimals: 6,
+ occurrences: 16,
+ iconUrl:
+ 'https://static.cx.metamask.io/api/v1/tokenIcons/1/0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48.png',
+ address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
+ name: 'USDC',
+ balance: '11411142',
+ string: '11.41114',
+ balanceError: null,
+ fiatBalance: '11.4',
+ },
+ {
+ symbol: 'DAI',
+ decimals: 18,
+ occurrences: 17,
+ iconUrl:
+ 'https://static.cx.metamask.io/api/v1/tokenIcons/1/0x6b175474e89094c44da98b954eedeac495271d0f.png',
+ address: '0x6b175474e89094c44da98b954eedeac495271d0f',
+ name: 'Dai Stablecoin',
+ balance: '3000000000000000000',
+ string: '3',
+ balanceError: null,
+ fiatBalance: '3',
+ },
+ {
+ symbol: 'OMNI',
+ decimals: 18,
+ iconUrl:
+ 'https://static.cx.metamask.io/api/v1/tokenIcons/1/0x36e66fbbce51e4cd5bd3c62b637eb411b18949d4.png',
+ address: '0x36e66fbbce51e4cd5bd3c62b637eb411b18949d4',
+ name: 'Omni Network',
+ balance: '2161382310000000000',
+ string: '2.16138',
+ balanceError: null,
+ },
+ ],
+ totalFiatBalance: 35.52,
+ });
+ mockGetTokensMarketData.mockReturnValue({
+ '0x0000000000000000000000000000000000000000': {
+ tokenAddress: '0x0000000000000000000000000000000000000000',
+ currency: 'ETH',
+ id: 'ethereum',
+ price: 0.9999598743668833,
+ marketCap: 120194359.82507178,
+ allTimeHigh: 2.070186924097962,
+ allTimeLow: 0.00018374327407907974,
+ totalVolume: 5495085.267342095,
+ high1d: 1.022994674939226,
+ low1d: 0.9882430202069277,
+ circulatingSupply: 120317181.32366,
+ dilutedMarketCap: 120194359.82507178,
+ marketCapPercentChange1d: -1.46534,
+ priceChange1d: -43.27897193472654,
+ pricePercentChange1h: 0.39406716228961414,
+ pricePercentChange1d: -1.8035792813549656,
+ },
+ '0x6B175474E89094C44Da98b954EedeAC495271d0F': {
+ tokenAddress: '0x6B175474E89094C44Da98b954EedeAC495271d0F',
+ currency: 'ETH',
+ id: 'dai',
+ price: 0.00042436994422149745,
+ marketCap: 2179091.2357524647,
+ allTimeHigh: 0.0005177313319502269,
+ allTimeLow: 0.0003742773160055919,
+ totalVolume: 25770.310026921918,
+ high1d: 0.00042564305405416193,
+ low1d: 0.000422254035679609,
+ circulatingSupply: 5131139277.03183,
+ dilutedMarketCap: 2179157.495602445,
+ marketCapPercentChange1d: -2.78163,
+ priceChange1d: -0.000450570064429501,
+ pricePercentChange1h: 0.044140824068107716,
+ pricePercentChange1d: -0.045030461437871275,
+ },
+ '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48': {
+ tokenAddress: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
+ currency: 'ETH',
+ id: 'usd-coin',
+ price: 0.00042436994422149745,
+ marketCap: 14845337.78504687,
+ allTimeHigh: 0.000496512834739152,
+ allTimeLow: 0.00037244700843616456,
+ totalVolume: 2995848.8988073817,
+ high1d: 0.0004252186841099404,
+ low1d: 0.00042304081755619566,
+ circulatingSupply: 34942418774.2545,
+ dilutedMarketCap: 14849047.51464122,
+ marketCapPercentChange1d: 0.25951,
+ priceChange1d: -0.000469409459860959,
+ },
+ });
+ const expectedAmountChange = '-$0.39';
+ const expectedPercentageChange = '(-1.08%)';
+ render(
);
+ const percentageElement = screen.getByText(expectedPercentageChange);
+ const numberElement = screen.getByText(expectedAmountChange);
+ expect(percentageElement).toBeInTheDocument();
+ expect(numberElement).toBeInTheDocument();
+ });
+ it('should display correct aggregated amount and percentage when the native fiatBalance is undefined', () => {
+ (useAccountTotalFiatBalance as jest.Mock).mockReturnValue({
+ orderedTokenList: [
+ {
+ iconUrl: './images/eth_logo.svg',
+ symbol: 'ETH',
+ },
+ {
+ symbol: 'USDC',
+ decimals: 6,
+ occurrences: 16,
+ iconUrl:
+ 'https://static.cx.metamask.io/api/v1/tokenIcons/1/0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48.png',
+ address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
+ name: 'USDC',
+ balance: '11411142',
+ string: '11.41114',
+ balanceError: null,
+ fiatBalance: '11.4',
+ },
+ {
+ symbol: 'DAI',
+ decimals: 18,
+ occurrences: 17,
+ iconUrl:
+ 'https://static.cx.metamask.io/api/v1/tokenIcons/1/0x6b175474e89094c44da98b954eedeac495271d0f.png',
+ address: '0x6b175474e89094c44da98b954eedeac495271d0f',
+ name: 'Dai Stablecoin',
+ balance: '3000000000000000000',
+ string: '3',
+ balanceError: null,
+ fiatBalance: '20',
+ },
+ ],
+ totalFiatBalance: 31.4,
+ });
+ mockGetTokensMarketData.mockReturnValue({
+ '0x0000000000000000000000000000000000000000': {
+ tokenAddress: '0x0000000000000000000000000000000000000000',
+ currency: 'ETH',
+ id: 'ethereum',
+ price: 0.9999598743668833,
+ marketCap: 120194359.82507178,
+ allTimeHigh: 2.070186924097962,
+ allTimeLow: 0.00018374327407907974,
+ totalVolume: 5495085.267342095,
+ high1d: 1.022994674939226,
+ low1d: 0.9882430202069277,
+ circulatingSupply: 120317181.32366,
+ dilutedMarketCap: 120194359.82507178,
+ marketCapPercentChange1d: -1.46534,
+ priceChange1d: -43.27897193472654,
+ pricePercentChange1h: 0.39406716228961414,
+ pricePercentChange1d: -1.8035792813549656,
+ },
+ '0x6B175474E89094C44Da98b954EedeAC495271d0F': {
+ tokenAddress: '0x6B175474E89094C44Da98b954EedeAC495271d0F',
+ currency: 'ETH',
+ id: 'dai',
+ price: 0.00042436994422149745,
+ marketCap: 2179091.2357524647,
+ allTimeHigh: 0.0005177313319502269,
+ allTimeLow: 0.0003742773160055919,
+ totalVolume: 25770.310026921918,
+ high1d: 0.00042564305405416193,
+ low1d: 0.000422254035679609,
+ circulatingSupply: 5131139277.03183,
+ dilutedMarketCap: 2179157.495602445,
+ marketCapPercentChange1d: -2.78163,
+ priceChange1d: -0.000450570064429501,
+ pricePercentChange1h: 0.044140824068107716,
+ pricePercentChange1d: -0.045030461437871275,
+ },
+ '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48': {
+ tokenAddress: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
+ currency: 'ETH',
+ id: 'usd-coin',
+ price: 0.00042436994422149745,
+ marketCap: 14845337.78504687,
+ allTimeHigh: 0.000496512834739152,
+ allTimeLow: 0.00037244700843616456,
+ totalVolume: 2995848.8988073817,
+ high1d: 0.0004252186841099404,
+ low1d: 0.00042304081755619566,
+ circulatingSupply: 34942418774.2545,
+ dilutedMarketCap: 14849047.51464122,
+ marketCapPercentChange1d: 0.25951,
+ priceChange1d: -0.000469409459860959,
+ },
+ });
+ const expectedAmountChange = '-$0.01';
+ const expectedPercentageChange = '(-0.03%)';
+ render(
);
+ const percentageElement = screen.getByText(expectedPercentageChange);
+ const numberElement = screen.getByText(expectedAmountChange);
+ expect(percentageElement).toBeInTheDocument();
+ expect(numberElement).toBeInTheDocument();
+ });
+});
diff --git a/ui/components/app/wallet-overview/aggregated-percentage-overview.tsx b/ui/components/app/wallet-overview/aggregated-percentage-overview.tsx
new file mode 100644
index 000000000000..e69ff1ed514d
--- /dev/null
+++ b/ui/components/app/wallet-overview/aggregated-percentage-overview.tsx
@@ -0,0 +1,143 @@
+import React, { useMemo } from 'react';
+import { useSelector } from 'react-redux';
+
+import { zeroAddress, toChecksumAddress } from 'ethereumjs-util';
+import {
+ getCurrentCurrency,
+ getSelectedAccount,
+ getShouldHideZeroBalanceTokens,
+ getTokensMarketData,
+} from '../../../selectors';
+
+import { useAccountTotalFiatBalance } from '../../../hooks/useAccountTotalFiatBalance';
+// TODO: Remove restricted import
+// eslint-disable-next-line import/no-restricted-paths
+import { formatValue, isValidAmount } from '../../../../app/scripts/lib/util';
+import { getIntlLocale } from '../../../ducks/locale/locale';
+import {
+ Display,
+ TextColor,
+ TextVariant,
+} from '../../../helpers/constants/design-system';
+import { Box, Text } from '../../component-library';
+import { getCalculatedTokenAmount1dAgo } from '../../../helpers/utils/util';
+
+// core already has this exported type but its not yet available in this version
+// todo remove this and use core type once available
+type MarketDataDetails = {
+ tokenAddress: string;
+ pricePercentChange1d: number;
+};
+
+export const AggregatedPercentageOverview = () => {
+ const tokensMarketData: Record
=
+ useSelector(getTokensMarketData);
+ const locale = useSelector(getIntlLocale);
+ const fiatCurrency = useSelector(getCurrentCurrency);
+ const selectedAccount = useSelector(getSelectedAccount);
+ const shouldHideZeroBalanceTokens = useSelector(
+ getShouldHideZeroBalanceTokens,
+ );
+ // Get total balance (native + tokens)
+ const { totalFiatBalance, orderedTokenList } = useAccountTotalFiatBalance(
+ selectedAccount,
+ shouldHideZeroBalanceTokens,
+ );
+
+ // Memoize the calculation to avoid recalculating unless orderedTokenList or tokensMarketData changes
+ const totalFiat1dAgo = useMemo(() => {
+ return orderedTokenList.reduce((total1dAgo, item) => {
+ if (item.address) {
+ // This is a regular ERC20 token
+ // find the relevant pricePercentChange1d in tokensMarketData
+ // Find the corresponding market data for the token by filtering the values of the tokensMarketData object
+ const found = tokensMarketData[toChecksumAddress(item.address)];
+
+ const tokenFiat1dAgo = getCalculatedTokenAmount1dAgo(
+ item.fiatBalance,
+ found?.pricePercentChange1d,
+ );
+ return total1dAgo + Number(tokenFiat1dAgo);
+ }
+ // native token
+ const nativePricePercentChange1d =
+ tokensMarketData?.[zeroAddress()]?.pricePercentChange1d;
+ const nativeFiat1dAgo = getCalculatedTokenAmount1dAgo(
+ item.fiatBalance,
+ nativePricePercentChange1d,
+ );
+ return total1dAgo + Number(nativeFiat1dAgo);
+ }, 0); // Initial total1dAgo is 0
+ }, [orderedTokenList, tokensMarketData]); // Dependencies: recalculate if orderedTokenList or tokensMarketData changes
+
+ const totalBalance: number = Number(totalFiatBalance);
+ const totalBalance1dAgo = totalFiat1dAgo;
+
+ const amountChange = totalBalance - totalBalance1dAgo;
+ const percentageChange = (amountChange / totalBalance1dAgo) * 100 || 0;
+
+ const formattedPercentChange = formatValue(
+ amountChange === 0 ? 0 : percentageChange,
+ true,
+ );
+
+ let formattedAmountChange = '';
+ if (isValidAmount(amountChange)) {
+ formattedAmountChange = (amountChange as number) >= 0 ? '+' : '';
+
+ const options = {
+ notation: 'compact',
+ compactDisplay: 'short',
+ maximumFractionDigits: 2,
+ } as const;
+
+ try {
+ // For currencies compliant with ISO 4217 Standard
+ formattedAmountChange += `${Intl.NumberFormat(locale, {
+ ...options,
+ style: 'currency',
+ currency: fiatCurrency,
+ }).format(amountChange as number)} `;
+ } catch {
+ // Non-standard Currency Codes
+ formattedAmountChange += `${Intl.NumberFormat(locale, {
+ ...options,
+ minimumFractionDigits: 2,
+ style: 'decimal',
+ }).format(amountChange as number)} `;
+ }
+ }
+
+ let color = TextColor.textDefault;
+
+ if (isValidAmount(amountChange)) {
+ if ((amountChange as number) === 0) {
+ color = TextColor.textDefault;
+ } else if ((amountChange as number) > 0) {
+ color = TextColor.successDefault;
+ } else {
+ color = TextColor.errorDefault;
+ }
+ }
+ return (
+
+
+ {formattedAmountChange}
+
+
+ {formattedPercentChange}
+
+
+ );
+};
diff --git a/ui/components/app/wallet-overview/btc-overview.test.tsx b/ui/components/app/wallet-overview/btc-overview.test.tsx
index 5adbe8dcc927..2bc93e5e54eb 100644
--- a/ui/components/app/wallet-overview/btc-overview.test.tsx
+++ b/ui/components/app/wallet-overview/btc-overview.test.tsx
@@ -24,6 +24,7 @@ const BTC_OVERVIEW_PRIMARY_CURRENCY = 'coin-overview__primary-currency';
const mockMetaMetricsId = 'deadbeef';
const mockNonEvmBalance = '1';
+const mockNonEvmBalanceUsd = '1.00';
const mockNonEvmAccount = {
address: 'bc1qwl8399fz829uqvqly9tcatgrgtwp3udnhxfq4k',
id: '542490c8-d178-433b-9f31-f680b11f45a5',
@@ -112,7 +113,7 @@ describe('BtcOverview', () => {
setBackgroundConnection({ setBridgeFeatureFlags: jest.fn() } as never);
});
- it('shows the primary balance', async () => {
+ it('shows the primary balance as BTC when showNativeTokenAsMainBalance if true', async () => {
const { queryByTestId, queryByText } = renderWithProvider(
,
getStore(),
@@ -125,6 +126,27 @@ describe('BtcOverview', () => {
expect(queryByText('*')).toBeInTheDocument();
});
+ it('shows the primary balance as fiat when showNativeTokenAsMainBalance if false', async () => {
+ const { queryByTestId, queryByText } = renderWithProvider(
+ ,
+ getStore({
+ metamask: {
+ ...mockMetamaskStore,
+ // The balances won't be available
+ preferences: {
+ showNativeTokenAsMainBalance: false,
+ },
+ },
+ }),
+ );
+
+ const primaryBalance = queryByTestId(BTC_OVERVIEW_PRIMARY_CURRENCY);
+ expect(primaryBalance).toBeInTheDocument();
+ expect(primaryBalance).toHaveTextContent(`$${mockNonEvmBalanceUsd}USD`);
+ // For now we consider balance to be always cached
+ expect(queryByText('*')).toBeInTheDocument();
+ });
+
it('shows a spinner if balance is not available', async () => {
const { container } = renderWithProvider(
,
diff --git a/ui/components/app/wallet-overview/coin-buttons.stories.js b/ui/components/app/wallet-overview/coin-buttons.stories.js
new file mode 100644
index 000000000000..40a6879673a8
--- /dev/null
+++ b/ui/components/app/wallet-overview/coin-buttons.stories.js
@@ -0,0 +1,37 @@
+import React from 'react';
+import CoinButtons from './coin-buttons';
+
+export default {
+ title: 'Components/App/WalletOverview/CoinButtons',
+ args: {
+ chainId: '1',
+ trackingLocation: 'home',
+ isSwapsChain: true,
+ isSigningEnabled: true,
+ isBridgeChain: true,
+ isBuyableChain: true,
+ defaultSwapsToken: {
+ symbol: 'ETH',
+ name: 'Ether',
+ address: '0x0000000000000000000000000000000000000000',
+ decimals: 18,
+ iconUrl: './images/eth_logo.svg',
+ balance: '3093640202103801',
+ string: '0.0031',
+ },
+ classPrefix: 'coin',
+ iconButtonClassName: '',
+ },
+ component: CoinButtons,
+ parameters: {
+ docs: {
+ description: {
+ component: 'A component that displays coin buttons',
+ },
+ },
+ },
+};
+
+const Template = (args) => ;
+
+export const Default = Template.bind({});
diff --git a/ui/components/app/wallet-overview/coin-buttons.tsx b/ui/components/app/wallet-overview/coin-buttons.tsx
index 426713f5d086..0e1947d023f3 100644
--- a/ui/components/app/wallet-overview/coin-buttons.tsx
+++ b/ui/components/app/wallet-overview/coin-buttons.tsx
@@ -60,7 +60,7 @@ import {
IconColor,
JustifyContent,
} from '../../../helpers/constants/design-system';
-import { Box, Icon, IconName } from '../../component-library';
+import { Box, Icon, IconName, IconSize } from '../../component-library';
import IconButton from '../../ui/icon-button';
///: BEGIN:ONLY_INCLUDE_IF(build-main,build-beta,build-flask)
import useRamps from '../../../hooks/ramps/useRamps/useRamps';
@@ -79,6 +79,7 @@ const CoinButtons = ({
defaultSwapsToken,
///: END:ONLY_INCLUDE_IF
classPrefix = 'coin',
+ iconButtonClassName = '',
}: {
chainId: `0x${string}` | CaipChainId | number;
trackingLocation: string;
@@ -90,6 +91,7 @@ const CoinButtons = ({
defaultSwapsToken?: SwapsEthToken;
///: END:ONLY_INCLUDE_IF
classPrefix?: string;
+ iconButtonClassName?: string;
}) => {
const t = useContext(I18nContext);
const dispatch = useDispatch();
@@ -191,15 +193,27 @@ const CoinButtons = ({
<>
}
+ iconButtonClassName={iconButtonClassName}
+ Icon={
+
+ }
label={t('stake')}
onClick={handleMmiStakingOnClick}
/>
{mmiPortfolioEnabled && (
+
}
label={t('portfolio')}
onClick={handleMmiPortfolioOnClick}
@@ -308,8 +322,13 @@ const CoinButtons = ({
///: BEGIN:ONLY_INCLUDE_IF(build-main,build-beta,build-flask)
+
}
disabled={!isBuyableChain}
data-testid={`${classPrefix}-overview-buy`}
@@ -327,9 +346,9 @@ const CoinButtons = ({
renderInstitutionalButtons()
///: END:ONLY_INCLUDE_IF
}
-
}
onClick={handleSwapOnClick}
@@ -350,10 +370,15 @@ const CoinButtons = ({
///: BEGIN:ONLY_INCLUDE_IF(build-main,build-beta,build-flask)
+
}
label={t('bridge')}
onClick={handleBridgeOnClick}
@@ -365,11 +390,13 @@ const CoinButtons = ({
}
}
disabled={!isSigningEnabled}
@@ -389,11 +416,13 @@ const CoinButtons = ({
)}
}
label={t('receive')}
diff --git a/ui/components/app/wallet-overview/coin-overview.tsx b/ui/components/app/wallet-overview/coin-overview.tsx
index 0293876539e1..c369ef0e89fd 100644
--- a/ui/components/app/wallet-overview/coin-overview.tsx
+++ b/ui/components/app/wallet-overview/coin-overview.tsx
@@ -1,17 +1,35 @@
import React, {
useContext,
+ useState,
///: BEGIN:ONLY_INCLUDE_IF(build-main,build-beta,build-flask)
useCallback,
///: END:ONLY_INCLUDE_IF
} from 'react';
-import { useSelector } from 'react-redux';
+import { useDispatch, useSelector } from 'react-redux';
import classnames from 'classnames';
import { zeroAddress } from 'ethereumjs-util';
import { CaipChainId } from '@metamask/utils';
import type { Hex } from '@metamask/utils';
+
+import {
+ Box,
+ ButtonIcon,
+ ButtonIconSize,
+ ButtonLink,
+ ButtonLinkSize,
+ IconName,
+ Popover,
+ PopoverPosition,
+ Text,
+} from '../../component-library';
+import {
+ AlignItems,
+ Display,
+ JustifyContent,
+ TextAlign,
+ TextVariant,
+} from '../../../helpers/constants/design-system';
///: BEGIN:ONLY_INCLUDE_IF(build-main,build-beta,build-flask)
-import { Icon, IconName, IconSize } from '../../component-library';
-import { IconColor } from '../../../helpers/constants/design-system';
import { getPortfolioUrl } from '../../../helpers/utils/portfolio';
import { MetaMetricsContext } from '../../../contexts/metametrics';
import {
@@ -23,10 +41,14 @@ import {
import { I18nContext } from '../../../contexts/i18n';
import Tooltip from '../../ui/tooltip';
import UserPreferencedCurrencyDisplay from '../user-preferenced-currency-display';
-import { PRIMARY, SECONDARY } from '../../../helpers/constants/common';
+import { PRIMARY } from '../../../helpers/constants/common';
import {
getPreferences,
+ getSelectedAccount,
+ getShouldHideZeroBalanceTokens,
getTokensMarketData,
+ getIsTestnet,
+ getShouldShowAggregatedBalancePopover,
///: BEGIN:ONLY_INCLUDE_IF(build-main,build-beta,build-flask)
getDataCollectionForMarketing,
getMetaMetricsId,
@@ -35,16 +57,17 @@ import {
///: END:ONLY_INCLUDE_IF
} from '../../../selectors';
import Spinner from '../../ui/spinner';
-import { useIsOriginalNativeTokenSymbol } from '../../../hooks/useIsOriginalNativeTokenSymbol';
-import { showPrimaryCurrency } from '../../../../shared/modules/currency-display.utils';
+
import { PercentageAndAmountChange } from '../../multichain/token-list-item/price/percentage-and-amount-change/percentage-and-amount-change';
-import {
- getMultichainIsEvm,
- getMultichainProviderConfig,
- getMultichainShouldShowFiat,
-} from '../../../selectors/multichain';
+import { getMultichainIsEvm } from '../../../selectors/multichain';
+import { useAccountTotalFiatBalance } from '../../../hooks/useAccountTotalFiatBalance';
+import { setAggregatedBalancePopoverShown } from '../../../store/actions';
+import { useTheme } from '../../../hooks/useTheme';
+import { getSpecificSettingsRoute } from '../../../helpers/utils/settings-search';
+import { useI18nContext } from '../../../hooks/useI18nContext';
import WalletOverview from './wallet-overview';
import CoinButtons from './coin-buttons';
+import { AggregatedPercentageOverview } from './aggregated-percentage-overview';
export type CoinOverviewProps = {
balance: string;
@@ -83,7 +106,7 @@ export const CoinOverview = ({
}
///: END:ONLY_INCLUDE_IF
- const t = useContext(I18nContext);
+ const t: ReturnType = useContext(I18nContext);
///: BEGIN:ONLY_INCLUDE_IF(build-main,build-beta,build-flask)
const trackEvent = useContext(MetaMetricsContext);
@@ -91,19 +114,61 @@ export const CoinOverview = ({
const metaMetricsId = useSelector(getMetaMetricsId);
const isMetaMetricsEnabled = useSelector(getParticipateInMetaMetrics);
const isMarketingEnabled = useSelector(getDataCollectionForMarketing);
+
///: END:ONLY_INCLUDE_IF
- const isEvm = useSelector(getMultichainIsEvm);
- const showFiat = useSelector(getMultichainShouldShowFiat);
- const { useNativeCurrencyAsPrimaryCurrency } = useSelector(getPreferences);
- const { ticker, type, rpcUrl } = useSelector(getMultichainProviderConfig);
- const isOriginalNativeSymbol = useIsOriginalNativeTokenSymbol(
- chainId,
- ticker,
- type,
- rpcUrl,
+ const showNativeTokenAsMainBalanceRoute = getSpecificSettingsRoute(
+ t,
+ t('general'),
+ t('showNativeTokenAsMainBalance'),
);
+ const theme = useTheme();
+ const dispatch = useDispatch();
+
+ const shouldShowPopover = useSelector(getShouldShowAggregatedBalancePopover);
+ const isTestnet = useSelector(getIsTestnet);
+ const { showFiatInTestnets } = useSelector(getPreferences);
+
+ const selectedAccount = useSelector(getSelectedAccount);
+ const shouldHideZeroBalanceTokens = useSelector(
+ getShouldHideZeroBalanceTokens,
+ );
+ const { totalFiatBalance, loading } = useAccountTotalFiatBalance(
+ selectedAccount,
+ shouldHideZeroBalanceTokens,
+ );
+
+ const { showNativeTokenAsMainBalance } = useSelector(getPreferences);
+
+ const isEvm = useSelector(getMultichainIsEvm);
+ const isNotAggregatedFiatBalance =
+ showNativeTokenAsMainBalance || isTestnet || !isEvm;
+ let balanceToDisplay;
+ if (isNotAggregatedFiatBalance) {
+ balanceToDisplay = balance;
+ } else if (!loading) {
+ balanceToDisplay = totalFiatBalance;
+ }
+
const tokensMarketData = useSelector(getTokensMarketData);
+ const [isOpen, setIsOpen] = useState(true);
+
+ const handleMouseEnter = () => {
+ setIsOpen(true);
+ };
+
+ const handleClick = () => {
+ setIsOpen(!isOpen);
+ dispatch(setAggregatedBalancePopoverShown());
+ };
+
+ const [referenceElement, setReferenceElement] =
+ useState(null);
+ const setBoxRef = (ref: HTMLSpanElement | null) => {
+ if (ref) {
+ setReferenceElement(ref);
+ }
+ };
///: BEGIN:ONLY_INCLUDE_IF(build-main,build-beta,build-flask)
const handlePortfolioOnClick = useCallback(() => {
@@ -126,6 +191,52 @@ export const CoinOverview = ({
}, [isMarketingEnabled, isMetaMetricsEnabled, metaMetricsId, trackEvent]);
///: END:ONLY_INCLUDE_IF
+ const renderPercentageAndAmountChange = () => {
+ if (isEvm) {
+ if (showNativeTokenAsMainBalance) {
+ return (
+
+
+ {
+ ///: BEGIN:ONLY_INCLUDE_IF(build-main,build-beta,build-flask)
+
+ {t('portfolio')}
+
+ ///: END:ONLY_INCLUDE_IF
+ }
+
+ );
+ }
+ return (
+
+
+ {
+ ///: BEGIN:ONLY_INCLUDE_IF(build-main,build-beta,build-flask)
+
+ {t('portfolio')}
+
+ ///: END:ONLY_INCLUDE_IF
+ }
+
+ );
+ }
+ return null;
+ };
+
return (
-
- {balance ? (
+
+ {balanceToDisplay ? (
) : (
@@ -168,43 +280,66 @@ export const CoinOverview = ({
)}
-
- {showFiat && isOriginalNativeSymbol && balance && (
-
- )}
- {
- ///: BEGIN:ONLY_INCLUDE_IF(build-main,build-beta,build-flask)
-
- {t('portfolio')}
-
-
- ///: END:ONLY_INCLUDE_IF
- }
-
- {isEvm && (
-
- )}
+ {shouldShowPopover &&
+ (!isTestnet || (isTestnet && showFiatInTestnets)) &&
+ !showNativeTokenAsMainBalance ? (
+
+
+
+
+ {t('yourBalanceIsAggregated')}
+
+
+
+
+
+ {t('aggregatedBalancePopover', [
+
+ {t('settings')}
+ ,
+ ])}
+
+
+
+ ) : null}
+
+ {renderPercentageAndAmountChange()}
}
@@ -221,6 +356,7 @@ export const CoinOverview = ({
defaultSwapsToken,
///: END:ONLY_INCLUDE_IF
classPrefix,
+ iconButtonClassName: `${classPrefix}-overview__icon-button`,
}}
/>
}
diff --git a/ui/components/app/wallet-overview/eth-overview.test.js b/ui/components/app/wallet-overview/eth-overview.test.js
index a30654796aa4..cea749a366db 100644
--- a/ui/components/app/wallet-overview/eth-overview.test.js
+++ b/ui/components/app/wallet-overview/eth-overview.test.js
@@ -47,7 +47,7 @@ describe('EthOverview', () => {
},
},
preferences: {
- useNativeCurrencyAsPrimaryCurrency: true,
+ showNativeTokenAsMainBalance: true,
},
useExternalServices: true,
useCurrencyRateCheck: true,
diff --git a/ui/components/app/wallet-overview/index.scss b/ui/components/app/wallet-overview/index.scss
index bbbf57075c24..4759af1ffa8c 100644
--- a/ui/components/app/wallet-overview/index.scss
+++ b/ui/components/app/wallet-overview/index.scss
@@ -3,11 +3,9 @@
.wallet-overview {
display: flex;
justify-content: space-between;
- align-items: center;
+ align-items: start;
flex: 1;
- min-height: 209px;
min-width: 0;
- padding-top: 10px;
flex-direction: column;
width: 100%;
@@ -16,30 +14,26 @@
display: flex;
gap: 4px;
flex-direction: column;
- align-items: center;
+ align-items: start;
width: 100%;
}
- &__buttons {
- display: flex;
- flex-direction: row;
- height: 68px;
- margin-bottom: 24px;
+ &__icon_button {
+ margin-top: 0 !important;
}
- &__portfolio_button {
+ &__buttons {
display: flex;
flex-direction: row;
- gap: 6px;
- cursor: pointer;
- align-items: center;
- color: var(--color-primary-default);
+ height: 100%;
+ margin-bottom: 16px;
+ padding: 0 16px;
}
&__currency-wrapper {
display: flex;
flex-direction: row;
- gap: 10px;
+ gap: 8px;
}
}
@@ -61,14 +55,17 @@
display: flex;
flex-direction: column;
min-width: 0;
- gap: 4px;
position: relative;
- align-items: center;
+ align-items: start;
margin: 16px 0;
padding: 0 16px;
max-width: 326px;
}
+ &__icon-button {
+ margin-top: 0 !important;
+ }
+
&__primary-container {
display: flex;
max-width: inherit;
@@ -80,17 +77,13 @@
@include design-system.H2;
color: var(--color-text-default);
+ font-weight: 700;
}
&__cached-star {
margin-left: 4px;
}
- &__portfolio-button {
- height: inherit;
- padding-inline-start: 16px;
- }
-
&__cached-balance,
&__cached-star {
color: var(--color-warning-default);
@@ -158,12 +151,14 @@
color: var(--color-text-alternative);
}
- &__portfolio-button {
- height: inherit;
- padding-inline-start: 16px;
- }
-
&__button:last-of-type {
margin-right: 0;
}
}
+
+.balance-popover {
+ &__container {
+ z-index: design-system.$modal-z-index;
+ margin-top: -4px;
+ }
+}
diff --git a/ui/components/institutional/interactive-replacement-token-modal/interactive-replacement-token-modal.stories.tsx b/ui/components/institutional/interactive-replacement-token-modal/interactive-replacement-token-modal.stories.tsx
index 862b98d350f3..f0327aaa227f 100644
--- a/ui/components/institutional/interactive-replacement-token-modal/interactive-replacement-token-modal.stories.tsx
+++ b/ui/components/institutional/interactive-replacement-token-modal/interactive-replacement-token-modal.stories.tsx
@@ -47,9 +47,7 @@ const customData = {
oldRefreshToken: 'abc',
url: 'https://saturn-custody-ui.dev.metamask-institutional.io',
},
- preferences: {
- useNativeCurrencyAsPrimaryCurrency: true,
- },
+ preferences: {},
},
};
diff --git a/ui/components/institutional/interactive-replacement-token-modal/interactive-replacement-token-modal.test.tsx b/ui/components/institutional/interactive-replacement-token-modal/interactive-replacement-token-modal.test.tsx
index 535b21f2e69b..97eaa364f104 100644
--- a/ui/components/institutional/interactive-replacement-token-modal/interactive-replacement-token-modal.test.tsx
+++ b/ui/components/institutional/interactive-replacement-token-modal/interactive-replacement-token-modal.test.tsx
@@ -48,9 +48,7 @@ describe('Interactive Replacement Token Modal', function () {
oldRefreshToken: 'abc',
url: 'https://saturn-custody-ui.dev.metamask-institutional.io',
},
- preferences: {
- useNativeCurrencyAsPrimaryCurrency: true,
- },
+ preferences: {},
},
};
diff --git a/ui/components/institutional/interactive-replacement-token-notification/interactive-replacement-token-notification.stories.tsx b/ui/components/institutional/interactive-replacement-token-notification/interactive-replacement-token-notification.stories.tsx
index fd169d23881f..381c4573add3 100644
--- a/ui/components/institutional/interactive-replacement-token-notification/interactive-replacement-token-notification.stories.tsx
+++ b/ui/components/institutional/interactive-replacement-token-notification/interactive-replacement-token-notification.stories.tsx
@@ -14,9 +14,7 @@ const customData = {
'81f96a88b6cbc5f50d3864122349fa9a9755833ee82a7e3cf6f268c78aab51ab',
url: 'url',
},
- preferences: {
- useNativeCurrencyAsPrimaryCurrency: true,
- },
+ preferences: {},
keyrings: [
{
type: 'Custody - Saturn',
diff --git a/ui/components/institutional/interactive-replacement-token-notification/interactive-replacement-token-notification.test.tsx b/ui/components/institutional/interactive-replacement-token-notification/interactive-replacement-token-notification.test.tsx
index 77424a95e86e..4c132ecbd414 100644
--- a/ui/components/institutional/interactive-replacement-token-notification/interactive-replacement-token-notification.test.tsx
+++ b/ui/components/institutional/interactive-replacement-token-notification/interactive-replacement-token-notification.test.tsx
@@ -72,9 +72,7 @@ describe('Interactive Replacement Token Notification', () => {
},
isUnlocked: false,
interactiveReplacementToken: { oldRefreshToken: 'abc' },
- preferences: {
- useNativeCurrencyAsPrimaryCurrency: true,
- },
+ preferences: {},
keyrings: [
{
type: KeyringType.imported,
diff --git a/ui/components/multichain/asset-picker-amount/asset-balance/asset-balance-text.test.tsx b/ui/components/multichain/asset-picker-amount/asset-balance/asset-balance-text.test.tsx
index 6613bf785b91..be9d58f23968 100644
--- a/ui/components/multichain/asset-picker-amount/asset-balance/asset-balance-text.test.tsx
+++ b/ui/components/multichain/asset-picker-amount/asset-balance/asset-balance-text.test.tsx
@@ -11,7 +11,6 @@ const store = configureStore({
...mockSendState,
metamask: {
...mockSendState.metamask,
- preferences: { useNativeCurrencyAsPrimaryCurrency: true },
},
appState: { ...mockSendState.appState, sendInputCurrencySwitched: false },
});
diff --git a/ui/components/multichain/asset-picker-amount/asset-picker-modal/AssetList.tsx b/ui/components/multichain/asset-picker-amount/asset-picker-modal/AssetList.tsx
index 1ea66e917437..9061592cf37c 100644
--- a/ui/components/multichain/asset-picker-amount/asset-picker-modal/AssetList.tsx
+++ b/ui/components/multichain/asset-picker-amount/asset-picker-modal/AssetList.tsx
@@ -1,10 +1,7 @@
import React from 'react';
import { useSelector } from 'react-redux';
import classnames from 'classnames';
-import {
- getPreferences,
- getSelectedAccountCachedBalance,
-} from '../../../../selectors';
+import { getSelectedAccountCachedBalance } from '../../../../selectors';
import { getNativeCurrency } from '../../../../ducks/metamask/metamask';
import { useUserPreferencedCurrency } from '../../../../hooks/useUserPreferencedCurrency';
import { PRIMARY, SECONDARY } from '../../../../helpers/constants/common';
@@ -46,7 +43,6 @@ export default function AssetList({
const nativeCurrency = useSelector(getNativeCurrency);
const balanceValue = useSelector(getSelectedAccountCachedBalance);
- const { useNativeCurrencyAsPrimaryCurrency } = useSelector(getPreferences);
const {
currency: primaryCurrency,
@@ -121,11 +117,7 @@ export default function AssetList({
primaryCurrencyProperties.value ??
secondaryCurrencyProperties.value
}
- tokenSymbol={
- useNativeCurrencyAsPrimaryCurrency
- ? primaryCurrency
- : secondaryCurrency
- }
+ tokenSymbol={primaryCurrency}
secondary={secondaryCurrencyDisplay}
tokenImage={token.image}
isOriginalTokenSymbol
diff --git a/ui/components/multichain/asset-picker-amount/asset-picker-modal/asset-picker-modal.test.tsx b/ui/components/multichain/asset-picker-amount/asset-picker-modal/asset-picker-modal.test.tsx
index be0eb8282258..15cc339775c9 100644
--- a/ui/components/multichain/asset-picker-amount/asset-picker-modal/asset-picker-modal.test.tsx
+++ b/ui/components/multichain/asset-picker-amount/asset-picker-modal/asset-picker-modal.test.tsx
@@ -14,7 +14,6 @@ import {
getCurrentChainId,
getCurrentCurrency,
getNativeCurrencyImage,
- getPreferences,
getSelectedAccountCachedBalance,
getSelectedInternalAccount,
getShouldHideZeroBalanceTokens,
@@ -134,9 +133,7 @@ describe('AssetPickerModal', () => {
if (selector === getTopAssets) {
return [];
}
- if (selector === getPreferences) {
- return { useNativeCurrencyAsPrimaryCurrency: false };
- }
+
if (selector === getSwapsBlockedTokens) {
return new Set(['0xtoken1']);
}
diff --git a/ui/components/multichain/asset-picker-amount/nft-input/nft-input.test.tsx b/ui/components/multichain/asset-picker-amount/nft-input/nft-input.test.tsx
index 05289c604aa3..08e4875ce149 100644
--- a/ui/components/multichain/asset-picker-amount/nft-input/nft-input.test.tsx
+++ b/ui/components/multichain/asset-picker-amount/nft-input/nft-input.test.tsx
@@ -5,15 +5,11 @@ import mockSendState from '../../../../../test/data/mock-send-state.json';
import configureStore from '../../../../store/store';
import { NFTInput } from './nft-input';
-const createStore = ({
- useNativeCurrencyAsPrimaryCurrency,
- sendInputCurrencySwitched,
-}: Record
) =>
+const createStore = ({ sendInputCurrencySwitched }: Record) =>
configureStore({
...mockSendState,
metamask: {
...mockSendState.metamask,
- preferences: { useNativeCurrencyAsPrimaryCurrency },
},
appState: { ...mockSendState.appState, sendInputCurrencySwitched },
});
@@ -25,7 +21,6 @@ describe('NFTInput', () => {
const { asFragment } = render(
@@ -39,7 +34,6 @@ describe('NFTInput', () => {
const { getByTestId } = render(
@@ -56,7 +50,6 @@ describe('NFTInput', () => {
const { queryByTestId } = render(
diff --git a/ui/components/multichain/asset-picker-amount/swappable-currency-input/swappable-currency-input.test.tsx b/ui/components/multichain/asset-picker-amount/swappable-currency-input/swappable-currency-input.test.tsx
index 693361354f91..8dadccbaf247 100644
--- a/ui/components/multichain/asset-picker-amount/swappable-currency-input/swappable-currency-input.test.tsx
+++ b/ui/components/multichain/asset-picker-amount/swappable-currency-input/swappable-currency-input.test.tsx
@@ -6,15 +6,11 @@ import mockSendState from '../../../../../test/data/mock-send-state.json';
import configureStore from '../../../../store/store';
import { SwappableCurrencyInput } from './swappable-currency-input';
-const createStore = ({
- useNativeCurrencyAsPrimaryCurrency,
- sendInputCurrencySwitched,
-}: Record) =>
+const createStore = ({ sendInputCurrencySwitched }: Record) =>
configureStore({
...mockSendState,
metamask: {
...mockSendState.metamask,
- preferences: { useNativeCurrencyAsPrimaryCurrency },
marketData: {
...mockSendState.metamask.marketData,
'0x5': {
@@ -37,7 +33,6 @@ describe('SwappableCurrencyInput', () => {
const { asFragment, getByText } = render(
@@ -68,7 +63,6 @@ describe('SwappableCurrencyInput', () => {
const { asFragment, getByText } = render(
@@ -101,7 +95,6 @@ describe('SwappableCurrencyInput', () => {
const { asFragment } = render(
@@ -134,7 +127,6 @@ describe('SwappableCurrencyInput', () => {
const { asFragment } = render(
diff --git a/ui/components/multichain/asset-picker-amount/utils.test.ts b/ui/components/multichain/asset-picker-amount/utils.test.ts
index 91f25dc33d15..c83fe3db797b 100644
--- a/ui/components/multichain/asset-picker-amount/utils.test.ts
+++ b/ui/components/multichain/asset-picker-amount/utils.test.ts
@@ -2,23 +2,18 @@ import configureStore from '../../../store/store';
import mockSendState from '../../../../test/data/mock-send-state.json';
import { getIsFiatPrimary } from './utils';
-const createStore = ({
- useNativeCurrencyAsPrimaryCurrency,
- sendInputCurrencySwitched,
-}: Record) =>
+const createStore = ({ sendInputCurrencySwitched }: Record) =>
configureStore({
...mockSendState,
metamask: {
...mockSendState.metamask,
- preferences: { useNativeCurrencyAsPrimaryCurrency },
},
appState: { ...mockSendState.appState, sendInputCurrencySwitched },
});
describe('getIsFiatPrimary selector', () => {
- it('returns true when useNativeCurrencyAsPrimaryCurrency and sendInputCurrencySwitched are both true', () => {
+ it('returns true when sendInputCurrencySwitched is true', () => {
const store = createStore({
- useNativeCurrencyAsPrimaryCurrency: true,
sendInputCurrencySwitched: true,
});
@@ -26,30 +21,11 @@ describe('getIsFiatPrimary selector', () => {
expect(getIsFiatPrimary(state as never)).toBe(true);
});
- it('returns true when useNativeCurrencyAsPrimaryCurrency and sendInputCurrencySwitched are both false', () => {
+ it('returns false when sendInputCurrencySwitched is false', () => {
const store = createStore({
- useNativeCurrencyAsPrimaryCurrency: false,
sendInputCurrencySwitched: false,
});
const state = store.getState();
- expect(getIsFiatPrimary(state as never)).toBe(true);
- });
-
- it('returns false when useNativeCurrencyAsPrimaryCurrency and sendInputCurrencySwitched have different values', () => {
- let store = createStore({
- useNativeCurrencyAsPrimaryCurrency: true,
- sendInputCurrencySwitched: false,
- });
-
- let state = store.getState();
- expect(getIsFiatPrimary(state as never)).toBe(false);
-
- store = createStore({
- useNativeCurrencyAsPrimaryCurrency: false,
- sendInputCurrencySwitched: true,
- });
-
- state = store.getState();
expect(getIsFiatPrimary(state as never)).toBe(false);
});
});
diff --git a/ui/components/multichain/asset-picker-amount/utils.ts b/ui/components/multichain/asset-picker-amount/utils.ts
index 664cba0d71f5..ed644c8a86d8 100644
--- a/ui/components/multichain/asset-picker-amount/utils.ts
+++ b/ui/components/multichain/asset-picker-amount/utils.ts
@@ -1,17 +1,14 @@
import { createSelector } from 'reselect';
+import { AppSliceState } from '../../../ducks/app/app';
-export const getIsFiatPrimary = createSelector(
- (state: {
- metamask: { preferences: { useNativeCurrencyAsPrimaryCurrency: boolean } };
- appState: { sendInputCurrencySwitched: boolean };
- }) => state.metamask.preferences,
- (state) => state.appState.sendInputCurrencySwitched,
- ({ useNativeCurrencyAsPrimaryCurrency }, sendInputCurrencySwitched) => {
- const isFiatPrimary = Boolean(
- (useNativeCurrencyAsPrimaryCurrency && sendInputCurrencySwitched) ||
- (!useNativeCurrencyAsPrimaryCurrency && !sendInputCurrencySwitched),
- );
+function getSendInputCurrencySwitched(state: AppSliceState) {
+ return state.appState.sendInputCurrencySwitched;
+}
+export const getIsFiatPrimary = createSelector(
+ getSendInputCurrencySwitched,
+ (sendInputCurrencySwitched) => {
+ const isFiatPrimary = Boolean(sendInputCurrencySwitched);
return isFiatPrimary;
},
);
diff --git a/ui/components/multichain/pages/send/send.test.js b/ui/components/multichain/pages/send/send.test.js
index cdba904090b2..5195ee15de5b 100644
--- a/ui/components/multichain/pages/send/send.test.js
+++ b/ui/components/multichain/pages/send/send.test.js
@@ -167,7 +167,6 @@ const baseStore = {
}),
tokens: [],
preferences: {
- useNativeCurrencyAsPrimaryCurrency: false,
showFiatInTestnets: true,
},
currentCurrency: 'USD',
diff --git a/ui/components/multichain/token-list-item/__snapshots__/token-list-item.test.tsx.snap b/ui/components/multichain/token-list-item/__snapshots__/token-list-item.test.tsx.snap
index 5c75df62eef1..1330a1490244 100644
--- a/ui/components/multichain/token-list-item/__snapshots__/token-list-item.test.tsx.snap
+++ b/ui/components/multichain/token-list-item/__snapshots__/token-list-item.test.tsx.snap
@@ -59,7 +59,7 @@ exports[`TokenListItem should render correctly 1`] = `
data-testid="multichain-token-list-item-secondary-value"
/>
diff --git a/ui/components/multichain/token-list-item/price/percentage-and-amount-change/__snapshots__/percentage-and-amount-change.test.tsx.snap b/ui/components/multichain/token-list-item/price/percentage-and-amount-change/__snapshots__/percentage-and-amount-change.test.tsx.snap
index e8ca2345490f..7f88ca5456ec 100644
--- a/ui/components/multichain/token-list-item/price/percentage-and-amount-change/__snapshots__/percentage-and-amount-change.test.tsx.snap
+++ b/ui/components/multichain/token-list-item/price/percentage-and-amount-change/__snapshots__/percentage-and-amount-change.test.tsx.snap
@@ -6,14 +6,14 @@ exports[`PercentageChange Component render renders correctly 1`] = `
class="mm-box mm-box--display-flex"
>
+$12.21
(+5.12%)
diff --git a/ui/components/multichain/token-list-item/price/percentage-and-amount-change/percentage-and-amount-change.test.tsx b/ui/components/multichain/token-list-item/price/percentage-and-amount-change/percentage-and-amount-change.test.tsx
index c22ff3d724f6..abff9f40da8d 100644
--- a/ui/components/multichain/token-list-item/price/percentage-and-amount-change/percentage-and-amount-change.test.tsx
+++ b/ui/components/multichain/token-list-item/price/percentage-and-amount-change/percentage-and-amount-change.test.tsx
@@ -39,7 +39,7 @@ const mockGetSelectedAccountCachedBalance =
getSelectedAccountCachedBalance as jest.Mock;
const mockGetConversionRate = getConversionRate as jest.Mock;
const mockGetNativeCurrency = getNativeCurrency as jest.Mock;
-const mockGetTOkensMarketData = getTokensMarketData as jest.Mock;
+const mockGetTokensMarketData = getTokensMarketData as jest.Mock;
describe('PercentageChange Component', () => {
beforeEach(() => {
@@ -48,7 +48,7 @@ describe('PercentageChange Component', () => {
mockGetSelectedAccountCachedBalance.mockReturnValue('0x02e8ac1ede6ade83');
mockGetConversionRate.mockReturnValue(2913.15);
mockGetNativeCurrency.mockReturnValue('ETH');
- mockGetTOkensMarketData.mockReturnValue({
+ mockGetTokensMarketData.mockReturnValue({
[zeroAddress()]: {
pricePercentChange1d: 2,
},
diff --git a/ui/components/multichain/token-list-item/price/percentage-and-amount-change/percentage-and-amount-change.tsx b/ui/components/multichain/token-list-item/price/percentage-and-amount-change/percentage-and-amount-change.tsx
index 1dbf656986f3..be9921e88793 100644
--- a/ui/components/multichain/token-list-item/price/percentage-and-amount-change/percentage-and-amount-change.tsx
+++ b/ui/components/multichain/token-list-item/price/percentage-and-amount-change/percentage-and-amount-change.tsx
@@ -5,7 +5,6 @@ import { isHexString, zeroAddress } from 'ethereumjs-util';
import { Text, Box } from '../../../../component-library';
import {
Display,
- FontWeight,
TextColor,
TextVariant,
} from '../../../../../helpers/constants/design-system';
@@ -28,7 +27,7 @@ import {
// eslint-disable-next-line import/no-restricted-paths
} from '../../../../../../app/scripts/lib/util';
-const renderPercentageWithNumber = (
+export const renderPercentageWithNumber = (
value: string,
formattedValuePrice: string,
color: TextColor,
@@ -36,8 +35,7 @@ const renderPercentageWithNumber = (
return (
+5.12%
diff --git a/ui/components/multichain/token-list-item/price/percentage-change/percentage-change.tsx b/ui/components/multichain/token-list-item/price/percentage-change/percentage-change.tsx
index 71f54d2ae5dc..616814886078 100644
--- a/ui/components/multichain/token-list-item/price/percentage-change/percentage-change.tsx
+++ b/ui/components/multichain/token-list-item/price/percentage-change/percentage-change.tsx
@@ -2,7 +2,6 @@ import React from 'react';
import { Box, Text } from '../../../../component-library';
import {
Display,
- FontWeight,
TextColor,
TextVariant,
} from '../../../../../helpers/constants/design-system';
@@ -37,8 +36,7 @@ export const PercentageChange = ({
return (
{
).toBeInTheDocument();
});
- it('should render crypto balance if useNativeCurrencyAsPrimaryCurrency is false', () => {
+ it('should render crypto balance', () => {
const store = configureMockStore()({
...state,
- preferences: {
- useNativeCurrencyAsPrimaryCurrency: false,
- },
+ preferences: {},
});
const propsToUse = {
primary: '11.9751 ETH',
diff --git a/ui/components/multichain/token-list-item/token-list-item.tsx b/ui/components/multichain/token-list-item/token-list-item.tsx
index 1198d3bdd165..a653a803dc1c 100644
--- a/ui/components/multichain/token-list-item/token-list-item.tsx
+++ b/ui/components/multichain/token-list-item/token-list-item.tsx
@@ -396,7 +396,7 @@ export const TokenListItem = ({
{primary} {isNativeCurrency ? '' : tokenSymbol}
diff --git a/ui/components/ui/currency-display/currency-display.component.js b/ui/components/ui/currency-display/currency-display.component.js
index 15b40ecd8ae5..ca9322661d79 100644
--- a/ui/components/ui/currency-display/currency-display.component.js
+++ b/ui/components/ui/currency-display/currency-display.component.js
@@ -32,6 +32,7 @@ export default function CurrencyDisplay({
prefixComponentWrapperProps = {},
textProps = {},
suffixProps = {},
+ isAggregatedFiatOverviewBalance = false,
...props
}) {
const [title, parts] = useCurrencyDisplay(value, {
@@ -43,6 +44,7 @@ export default function CurrencyDisplay({
denomination,
currency,
suffix,
+ isAggregatedFiatOverviewBalance,
});
return (
@@ -112,6 +114,7 @@ const CurrencyDisplayPropTypes = {
prefixComponentWrapperProps: PropTypes.object,
textProps: PropTypes.object,
suffixProps: PropTypes.object,
+ isAggregatedFiatOverviewBalance: PropTypes.bool,
};
CurrencyDisplay.propTypes = CurrencyDisplayPropTypes;
diff --git a/ui/components/ui/dropdown/dropdown.scss b/ui/components/ui/dropdown/dropdown.scss
index e76d7936d303..395a61b68eee 100644
--- a/ui/components/ui/dropdown/dropdown.scss
+++ b/ui/components/ui/dropdown/dropdown.scss
@@ -3,7 +3,7 @@
.dropdown {
position: relative;
display: inline-block;
- height: 36px;
+ height: 48px;
&__select {
appearance: none;
@@ -15,9 +15,9 @@
color: var(--color-text-default);
border: 1px solid var(--color-border-default);
- border-radius: 4px;
+ border-radius: 8px;
background-color: var(--color-background-default);
- padding: 8px 40px 8px 16px;
+ padding: 12px 40px 12px 16px;
width: 100%;
[dir='rtl'] & {
diff --git a/ui/components/ui/icon-button/icon-button.js b/ui/components/ui/icon-button/icon-button.js
index 69830128ebcd..30b14c0aa205 100644
--- a/ui/components/ui/icon-button/icon-button.js
+++ b/ui/components/ui/icon-button/icon-button.js
@@ -16,6 +16,7 @@ export default function IconButton(props) {
label,
tooltipRender,
className,
+ iconButtonClassName = '',
...otherProps
} = props;
const renderWrapper = tooltipRender ?? defaultRender;
@@ -31,7 +32,10 @@ export default function IconButton(props) {
>
{renderWrapper(
<>
-
+
{Icon}
{label.length > 10 ? (
@@ -66,5 +70,6 @@ IconButton.propTypes = {
label: PropTypes.string.isRequired,
tooltipRender: PropTypes.func,
className: PropTypes.string,
+ iconButtonClassName: PropTypes.string,
'data-testid': PropTypes.string,
};
diff --git a/ui/components/ui/icon-button/icon-button.scss b/ui/components/ui/icon-button/icon-button.scss
index 97529366befa..e09373b23744 100644
--- a/ui/components/ui/icon-button/icon-button.scss
+++ b/ui/components/ui/icon-button/icon-button.scss
@@ -6,11 +6,11 @@
align-items: center;
background-color: unset;
text-align: center;
- width: 60px;
+ width: 64px;
@include design-system.H7;
- font-size: 13px;
+ font-size: 12px;
cursor: pointer;
color: var(--color-primary-default);
@@ -21,9 +21,9 @@
height: 36px;
width: 36px;
background: var(--color-primary-default);
- border-radius: 18px;
+ border-radius: 99px;
margin-top: 6px;
- margin-bottom: 5px;
+ margin-bottom: 4px;
margin-inline: auto;
}
diff --git a/ui/components/ui/text-field/text-field.component.js b/ui/components/ui/text-field/text-field.component.js
index 6ed0a9bff6fb..0a74978973b3 100644
--- a/ui/components/ui/text-field/text-field.component.js
+++ b/ui/components/ui/text-field/text-field.component.js
@@ -86,13 +86,14 @@ const styles = {
border: '1px solid var(--color-border-default)',
color: 'var(--color-text-default)',
height: '48px',
- borderRadius: '6px',
padding: '0 16px',
display: 'flex',
alignItems: 'center',
'&$inputFocused': {
border: '1px solid var(--color-primary-default)',
},
+ borderRadius: '8px',
+ fontSize: '0.875rem',
},
largeInputLabel: {
...inputLabelBase,
@@ -212,6 +213,7 @@ const getBorderedThemeInputProps = ({
max,
autoComplete,
},
+ disableUnderline: 'true',
},
});
diff --git a/ui/ducks/app/app.ts b/ui/ducks/app/app.ts
index a2e553f34012..182ba426a3d7 100644
--- a/ui/ducks/app/app.ts
+++ b/ui/ducks/app/app.ts
@@ -105,7 +105,7 @@ type AppState = {
isMultiRpcOnboarding: boolean;
};
-type AppSliceState = {
+export type AppSliceState = {
appState: AppState;
};
diff --git a/ui/ducks/metamask/metamask.js b/ui/ducks/metamask/metamask.js
index 4765a87df61d..05cc6d46cb27 100644
--- a/ui/ducks/metamask/metamask.js
+++ b/ui/ducks/metamask/metamask.js
@@ -48,7 +48,6 @@ const initialState = {
showFiatInTestnets: false,
showTestNetworks: false,
smartTransactionsOptInStatus: false,
- useNativeCurrencyAsPrimaryCurrency: true,
petnamesEnabled: true,
featureNotificationsEnabled: false,
showMultiRpcModal: false,
diff --git a/ui/helpers/constants/settings.js b/ui/helpers/constants/settings.js
index f4529ed1d6ad..569999f8900e 100644
--- a/ui/helpers/constants/settings.js
+++ b/ui/helpers/constants/settings.js
@@ -34,9 +34,9 @@ const SETTINGS_CONSTANTS = [
},
{
tabMessage: (t) => t('general'),
- sectionMessage: (t) => t('primaryCurrencySetting'),
- descriptionMessage: (t) => t('primaryCurrencySettingDescription'),
- route: `${GENERAL_ROUTE}#primary-currency`,
+ sectionMessage: (t) => t('showNativeTokenAsMainBalance'),
+ descriptionMessage: (t) => t('showNativeTokenAsMainBalance'),
+ route: `${GENERAL_ROUTE}#show-native-token-as-main-balance`,
iconName: IconName.Setting,
},
{
diff --git a/ui/helpers/utils/settings-search.js b/ui/helpers/utils/settings-search.js
index 447a39901059..af13e1d71c65 100644
--- a/ui/helpers/utils/settings-search.js
+++ b/ui/helpers/utils/settings-search.js
@@ -25,6 +25,15 @@ function getFilteredSettingsRoutes(t, tabMessage) {
});
}
+export function getSpecificSettingsRoute(t, tabMessage, sectionMessage) {
+ return getSettingsRoutes().find((routeObject) => {
+ return (
+ routeObject.tabMessage(t) === tabMessage &&
+ routeObject.sectionMessage(t) === sectionMessage
+ );
+ });
+}
+
/**
* @param {Function} t - context.t function
* @param {string} tabMessage
diff --git a/ui/helpers/utils/settings-search.test.js b/ui/helpers/utils/settings-search.test.js
index 709b0354a4e7..1e440b8f0aff 100644
--- a/ui/helpers/utils/settings-search.test.js
+++ b/ui/helpers/utils/settings-search.test.js
@@ -4,6 +4,7 @@ import {
getSettingsRoutes,
getNumberOfSettingRoutesInTab,
handleSettingsRefs,
+ getSpecificSettingsRoute,
} from './settings-search';
const t = (key) => {
@@ -209,4 +210,17 @@ describe('Settings Search Utils', () => {
expect(handleSettingsRefs(t, t('general'), settingsRefs)).toBeUndefined();
});
});
+
+ describe('getSpecificSettingsRoute', () => {
+ it('should return show native token as main balance route', () => {
+ const result = getSpecificSettingsRoute(
+ t,
+ t('general'),
+ t('showNativeTokenAsMainBalance'),
+ );
+ expect(result.route).toBe(
+ '/settings/general#show-native-token-as-main-balance',
+ );
+ });
+ });
});
diff --git a/ui/helpers/utils/util.js b/ui/helpers/utils/util.js
index 01cffeea3cdc..fe01bd15f5b1 100644
--- a/ui/helpers/utils/util.js
+++ b/ui/helpers/utils/util.js
@@ -823,3 +823,18 @@ export const getFilteredSnapPermissions = (
return filteredPermissions;
};
+/**
+ * Helper function to calculate the token amount 1dAgo using price percentage a day ago.
+ *
+ * @param {*} tokenFiatBalance - current token fiat balance
+ * @param {*} tokenPricePercentChange1dAgo - price percentage 1day ago
+ * @returns token amount 1day ago
+ */
+export const getCalculatedTokenAmount1dAgo = (
+ tokenFiatBalance,
+ tokenPricePercentChange1dAgo,
+) => {
+ return tokenPricePercentChange1dAgo !== undefined && tokenFiatBalance
+ ? tokenFiatBalance / (1 + tokenPricePercentChange1dAgo / 100)
+ : tokenFiatBalance ?? 0;
+};
diff --git a/ui/helpers/utils/util.test.js b/ui/helpers/utils/util.test.js
index e10c70630dba..dd2282efa531 100644
--- a/ui/helpers/utils/util.test.js
+++ b/ui/helpers/utils/util.test.js
@@ -1226,4 +1226,37 @@ describe('util', () => {
]);
});
});
+
+ describe('getCalculatedTokenAmount1dAgo', () => {
+ it('should return successfully balance of token 1dago', () => {
+ const mockTokenFiatAmount = '10';
+ const mockTokenPercent1dAgo = 1;
+ const expectedRes = 9.900990099009901;
+ const result = util.getCalculatedTokenAmount1dAgo(
+ mockTokenFiatAmount,
+ mockTokenPercent1dAgo,
+ );
+ expect(result).toBe(expectedRes);
+ });
+
+ it('should return token balance if percentage is undefined', () => {
+ const mockTokenFiatAmount = '10';
+ const mockTokenPercent1dAgo = undefined;
+ const result = util.getCalculatedTokenAmount1dAgo(
+ mockTokenFiatAmount,
+ mockTokenPercent1dAgo,
+ );
+ expect(result).toBe(mockTokenFiatAmount);
+ });
+
+ it('should return zero if token amount is undefined', () => {
+ const mockTokenFiatAmount = undefined;
+ const mockTokenPercent1dAgo = 1;
+ const result = util.getCalculatedTokenAmount1dAgo(
+ mockTokenFiatAmount,
+ mockTokenPercent1dAgo,
+ );
+ expect(result).toBe(0);
+ });
+ });
});
diff --git a/ui/hooks/useCurrencyDisplay.js b/ui/hooks/useCurrencyDisplay.js
index a7798d5ff10e..12b2cfc06ec3 100644
--- a/ui/hooks/useCurrencyDisplay.js
+++ b/ui/hooks/useCurrencyDisplay.js
@@ -135,6 +135,7 @@ export function useCurrencyDisplay(
numberOfDecimals,
denomination,
currency,
+ isAggregatedFiatOverviewBalance,
...opts
},
) {
@@ -151,6 +152,7 @@ export function useCurrencyDisplay(
getMultichainConversionRate,
account,
);
+
const isUserPreferredCurrency = currency === currentCurrency;
const isNativeCurrency = currency === nativeCurrency;
@@ -172,6 +174,10 @@ export function useCurrencyDisplay(
});
}
+ if (isAggregatedFiatOverviewBalance) {
+ return formatCurrency(inputValue, currency);
+ }
+
return formatEthCurrencyDisplay({
isNativeCurrency,
isUserPreferredCurrency,
@@ -194,6 +200,7 @@ export function useCurrencyDisplay(
denomination,
numberOfDecimals,
currentCurrency,
+ isAggregatedFiatOverviewBalance,
]);
let suffix;
diff --git a/ui/hooks/useTransactionDisplayData.test.js b/ui/hooks/useTransactionDisplayData.test.js
index 0aa77675bd7c..68a4d829bcf8 100644
--- a/ui/hooks/useTransactionDisplayData.test.js
+++ b/ui/hooks/useTransactionDisplayData.test.js
@@ -211,7 +211,6 @@ const renderHookWithRouter = (cb, tokenAddress) => {
currentCurrency: 'ETH',
useCurrencyRateCheck: false, // to force getShouldShowFiat to return false
preferences: {
- useNativeCurrencyAsPrimaryCurrency: true,
getShowFiatInTestnets: false,
},
allNfts: [],
diff --git a/ui/hooks/useUserPreferencedCurrency.js b/ui/hooks/useUserPreferencedCurrency.js
index 732d4ec726bb..e9e8133cf9e2 100644
--- a/ui/hooks/useUserPreferencedCurrency.js
+++ b/ui/hooks/useUserPreferencedCurrency.js
@@ -6,7 +6,7 @@ import {
getMultichainShouldShowFiat,
} from '../selectors/multichain';
-import { PRIMARY, SECONDARY } from '../helpers/constants/common';
+import { PRIMARY } from '../helpers/constants/common';
import { EtherDenomination } from '../../shared/constants/common';
import { ETH_DEFAULT_DECIMALS } from '../constants';
import { useMultichainSelector } from './useMultichainSelector';
@@ -20,6 +20,8 @@ import { useMultichainSelector } from './useMultichainSelector';
* when using ETH
* @property {number} [fiatNumberOfDecimals] - Number of significant decimals to display
* when using fiat
+ * @property {boolean} [shouldCheckShowNativeToken] - Boolean to know if checking the setting
+ * show native token as main balance is needed
*/
/**
@@ -34,9 +36,10 @@ import { useMultichainSelector } from './useMultichainSelector';
* useUserPreferencedCurrency
*
* returns an object that contains what currency to use for displaying values based
- * on the user's preference settings, as well as the significant number of decimals
+ * on whether the user needs to check showNativeTokenAsMainBalance setting, as well as the significant number of decimals
* to display based on the currency
*
+ *
* @param {"PRIMARY" | "SECONDARY"} type - what display type is being rendered
* @param {UseUserPreferencedCurrencyOptions} opts - options to override default values
* @returns {UserPreferredCurrency}
@@ -49,7 +52,7 @@ export function useUserPreferencedCurrency(type, opts = {}) {
account,
);
- const { useNativeCurrencyAsPrimaryCurrency } = useSelector(
+ const { showNativeTokenAsMainBalance } = useSelector(
getPreferences,
shallowEqual,
);
@@ -74,12 +77,13 @@ export function useUserPreferencedCurrency(type, opts = {}) {
return nativeReturn;
} else if (opts.showFiatOverride) {
return fiatReturn;
+ } else if (!showFiat) {
+ return nativeReturn;
} else if (
- !showFiat ||
- (type === PRIMARY && useNativeCurrencyAsPrimaryCurrency) ||
- (type === SECONDARY && !useNativeCurrencyAsPrimaryCurrency)
+ (opts.shouldCheckShowNativeToken && showNativeTokenAsMainBalance) ||
+ !opts.shouldCheckShowNativeToken
) {
- return nativeReturn;
+ return type === PRIMARY ? nativeReturn : fiatReturn;
}
- return fiatReturn;
+ return type === PRIMARY ? fiatReturn : nativeReturn;
}
diff --git a/ui/hooks/useUserPreferencedCurrency.test.js b/ui/hooks/useUserPreferencedCurrency.test.js
index 12785d44b5ff..9421834b0e31 100644
--- a/ui/hooks/useUserPreferencedCurrency.test.js
+++ b/ui/hooks/useUserPreferencedCurrency.test.js
@@ -8,16 +8,43 @@ import { mockNetworkState } from '../../test/stub/networks';
import { CHAIN_IDS } from '../../shared/constants/network';
import { useUserPreferencedCurrency } from './useUserPreferencedCurrency';
+const renderUseUserPreferencedCurrency = (state, value, restProps) => {
+ const defaultState = {
+ ...mockState,
+ metamask: {
+ ...mockState.metamask,
+ completedOnboarding: true,
+ ...mockNetworkState({
+ chainId: state.showFiat ? CHAIN_IDS.MAINNET : CHAIN_IDS.SEPOLIA,
+ ticker: state?.nativeCurrency,
+ }),
+ currentCurrency: state.currentCurrency,
+ currencyRates: { ETH: { conversionRate: 280.45 } },
+ preferences: {
+ showFiatInTestnets: state.showFiat,
+ showNativeTokenAsMainBalance: state.showNativeTokenAsMainBalance,
+ },
+ },
+ };
+
+ const wrapper = ({ children }) => (
+
{children}
+ );
+
+ return renderHook(() => useUserPreferencedCurrency(value, restProps), {
+ wrapper,
+ });
+};
const tests = [
{
state: {
- useNativeCurrencyAsPrimaryCurrency: true,
+ showNativeTokenAsMainBalance: true,
nativeCurrency: 'ETH',
showFiat: true,
currentCurrency: 'usd',
},
params: {
- type: 'PRIMARY',
+ showNativeOverride: true,
},
result: {
currency: 'ETH',
@@ -26,13 +53,13 @@ const tests = [
},
{
state: {
- useNativeCurrencyAsPrimaryCurrency: false,
+ showNativeTokenAsMainBalance: true,
nativeCurrency: 'ETH',
showFiat: true,
currentCurrency: 'usd',
},
params: {
- type: 'PRIMARY',
+ showFiatOverride: true,
},
result: {
currency: 'usd',
@@ -41,45 +68,59 @@ const tests = [
},
{
state: {
- useNativeCurrencyAsPrimaryCurrency: true,
+ showNativeTokenAsMainBalance: true,
nativeCurrency: 'ETH',
showFiat: true,
+ currentCurrency: 'usd',
},
params: {
- type: 'SECONDARY',
- fiatNumberOfDecimals: 4,
- fiatPrefix: '-',
+ type: 'PRIMARY',
+ shouldCheckShowNativeToken: true,
},
result: {
- currency: undefined,
- numberOfDecimals: 4,
+ currency: 'ETH',
+ numberOfDecimals: 8,
},
},
{
state: {
- useNativeCurrencyAsPrimaryCurrency: false,
+ showNativeTokenAsMainBalance: false,
nativeCurrency: 'ETH',
showFiat: true,
+ currentCurrency: 'usd',
},
params: {
- type: 'SECONDARY',
- fiatNumberOfDecimals: 4,
- numberOfDecimals: 3,
- fiatPrefix: 'a',
+ type: 'PRIMARY',
},
result: {
currency: 'ETH',
- numberOfDecimals: 3,
+ numberOfDecimals: 8,
+ },
+ },
+ {
+ state: {
+ showNativeTokenAsMainBalance: false,
+ nativeCurrency: 'ETH',
+ showFiat: true,
+ currentCurrency: 'usd',
+ },
+ params: {
+ type: 'SECONDARY',
+ },
+ result: {
+ currency: 'usd',
+ numberOfDecimals: 2,
},
},
{
state: {
- useNativeCurrencyAsPrimaryCurrency: false,
+ showNativeTokenAsMainBalance: false,
nativeCurrency: 'ETH',
showFiat: false,
+ currentCurrency: 'usd',
},
params: {
- type: 'PRIMARY',
+ type: 'SECONDARY',
},
result: {
currency: 'ETH',
@@ -88,66 +129,54 @@ const tests = [
},
{
state: {
- useNativeCurrencyAsPrimaryCurrency: false,
+ showNativeTokenAsMainBalance: true,
nativeCurrency: 'ETH',
showFiat: true,
+ currentCurrency: 'usd',
},
params: {
type: 'PRIMARY',
},
result: {
- currency: undefined,
+ currency: 'ETH',
+ numberOfDecimals: 8,
+ },
+ },
+ {
+ state: {
+ showNativeTokenAsMainBalance: true,
+ nativeCurrency: 'ETH',
+ showFiat: true,
+ currentCurrency: 'usd',
+ },
+ params: {
+ type: 'SECONDARY',
+ },
+ result: {
+ currency: 'usd',
numberOfDecimals: 2,
},
},
{
state: {
- useNativeCurrencyAsPrimaryCurrency: false,
+ showNativeTokenAsMainBalance: true,
nativeCurrency: 'ETH',
showFiat: true,
+ currentCurrency: 'usd',
},
params: {
- type: 'PRIMARY',
+ type: 'SECONDARY',
+ shouldCheckShowNativeToken: true,
},
result: {
- currency: undefined,
+ currency: 'usd',
numberOfDecimals: 2,
},
},
];
-
-const renderUseUserPreferencedCurrency = (state, value, restProps) => {
- const defaultState = {
- ...mockState,
- metamask: {
- ...mockState.metamask,
- completedOnboarding: true,
- ...mockNetworkState({
- chainId: state.showFiat ? CHAIN_IDS.MAINNET : CHAIN_IDS.SEPOLIA,
- ticker: state?.nativeCurrency,
- }),
- currentCurrency: state.currentCurrency,
- currencyRates: { ETH: { conversionRate: 280.45 } },
- preferences: {
- useNativeCurrencyAsPrimaryCurrency:
- state.useNativeCurrencyAsPrimaryCurrency,
- showFiatInTestnets: state.showFiat,
- },
- },
- };
-
- const wrapper = ({ children }) => (
-
{children}
- );
-
- return renderHook(() => useUserPreferencedCurrency(value, restProps), {
- wrapper,
- });
-};
-
describe('useUserPreferencedCurrency', () => {
tests.forEach(({ params: { type, ...otherParams }, state, result }) => {
- describe(`when showFiat is ${state.showFiat}, useNativeCurrencyAsPrimary is ${state.useNativeCurrencyAsPrimaryCurrency} and type is ${type}`, () => {
+ describe(`when showFiat is ${state.showFiat}, shouldCheckShowNativeToken is ${otherParams.shouldCheckShowNativeToken}, showNativeTokenAsMainBalance is ${state.showNativeTokenAsMainBalance} and type is ${type}`, () => {
const { result: hookResult } = renderUseUserPreferencedCurrency(
state,
type,
diff --git a/ui/pages/asset/components/__snapshots__/asset-page.test.tsx.snap b/ui/pages/asset/components/__snapshots__/asset-page.test.tsx.snap
index ef6e6331d2ba..95828e3e250e 100644
--- a/ui/pages/asset/components/__snapshots__/asset-page.test.tsx.snap
+++ b/ui/pages/asset/components/__snapshots__/asset-page.test.tsx.snap
@@ -43,7 +43,7 @@ exports[`AssetPage should render a native asset 1`] = `
data-theme="light"
>
@@ -61,7 +61,7 @@ exports[`AssetPage should render a native asset 1`] = `
data-theme="light"
>
@@ -79,7 +79,7 @@ exports[`AssetPage should render a native asset 1`] = `
data-theme="light"
>
@@ -99,7 +99,7 @@ exports[`AssetPage should render a native asset 1`] = `
data-theme="light"
>