Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: market data for native tokens with non zero addresses #28584

Merged
merged 8 commits into from
Nov 22, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@
"ci-rerun-from-failed": "tsx .circleci/scripts/rerun-ci-workflow-from-failed.ts"
},
"resolutions": {
"@metamask/assets-controllers": "patch:@metamask-previews/[email protected]#.yarn/patches/@metamask-assets-controllers-npm-44.0.0-c223d56176.patch",
Prithpal-Sooriya marked this conversation as resolved.
Show resolved Hide resolved
"chokidar": "^3.6.0",
"gridplus-sdk/elliptic": "^6.5.7",
"gridplus-sdk/secp256k1": "^5.0.1",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import React, { useMemo } from 'react';
import { useSelector } from 'react-redux';

import { zeroAddress, toChecksumAddress } from 'ethereumjs-util';
import { toChecksumAddress } from 'ethereumjs-util';
import { getNativeTokenAddress } from '@metamask/assets-controllers';
import { Hex } from '@metamask/utils';
import {
getCurrentCurrency,
getSelectedAccount,
Expand Down Expand Up @@ -89,8 +91,9 @@ export const AggregatedPercentageOverviewCrossChains = () => {
item.tokensWithBalances,
);
const nativePricePercentChange1d =
crossChainMarketData?.[item.chainId]?.[zeroAddress()]
?.pricePercentChange1d;
crossChainMarketData?.[item.chainId]?.[
getNativeTokenAddress(item.chainId as Hex)
]?.pricePercentChange1d;

const nativeFiat1dAgo = getCalculatedTokenAmount1dAgo(
item.nativeFiatValue,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
getShouldHideZeroBalanceTokens,
getTokensMarketData,
getPreferences,
getCurrentChainId,
} from '../../../selectors';
import { useAccountTotalFiatBalance } from '../../../hooks/useAccountTotalFiatBalance';
import { AggregatedPercentageOverview } from './aggregated-percentage-overview';
Expand All @@ -26,20 +27,22 @@ jest.mock('../../../selectors', () => ({
getPreferences: jest.fn(),
getShouldHideZeroBalanceTokens: jest.fn(),
getTokensMarketData: jest.fn(),
getCurrentChainId: jest.fn(),
}));

jest.mock('../../../hooks/useAccountTotalFiatBalance', () => ({
useAccountTotalFiatBalance: jest.fn(),
}));

const mockGetIntlLocale = getIntlLocale as unknown as jest.Mock;
const mockGetCurrentCurrency = getCurrentCurrency as jest.Mock;
const mockGetPreferences = getPreferences as jest.Mock;
const mockGetSelectedAccount = getSelectedAccount as unknown as jest.Mock;
const mockGetShouldHideZeroBalanceTokens =
getShouldHideZeroBalanceTokens as jest.Mock;

const mockGetIntlLocale = jest.mocked(getIntlLocale);
const mockGetCurrentCurrency = jest.mocked(getCurrentCurrency);
const mockGetPreferences = jest.mocked(getPreferences);
const mockGetSelectedAccount = jest.mocked(getSelectedAccount);
const mockGetShouldHideZeroBalanceTokens = jest.mocked(
getShouldHideZeroBalanceTokens,
);
Comment on lines +37 to +43
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TIL jest.mocked way better than casting to jest.Mock like I'm used to 👍

const mockGetTokensMarketData = getTokensMarketData as jest.Mock;
const mockGetCurrentChainId = jest.mocked(getCurrentChainId);

const selectedAccountMock = {
id: 'd51c0116-de36-4e77-b35b-408d4ea82d01',
Expand Down Expand Up @@ -166,7 +169,7 @@ describe('AggregatedPercentageOverview', () => {
mockGetSelectedAccount.mockReturnValue(selectedAccountMock);
mockGetShouldHideZeroBalanceTokens.mockReturnValue(false);
mockGetTokensMarketData.mockReturnValue(marketDataMock);

mockGetCurrentChainId.mockReturnValue('0x1');
jest.clearAllMocks();
});

Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import React, { useMemo } from 'react';
import { useSelector } from 'react-redux';

import { zeroAddress, toChecksumAddress } from 'ethereumjs-util';
import { toChecksumAddress } from 'ethereumjs-util';
import { getNativeTokenAddress } from '@metamask/assets-controllers';
import {
getCurrentCurrency,
getSelectedAccount,
getShouldHideZeroBalanceTokens,
getTokensMarketData,
getPreferences,
getCurrentChainId,
} from '../../../selectors';

import { useAccountTotalFiatBalance } from '../../../hooks/useAccountTotalFiatBalance';
Expand Down Expand Up @@ -37,6 +39,7 @@ export const AggregatedPercentageOverview = () => {
const fiatCurrency = useSelector(getCurrentCurrency);
const { privacyMode } = useSelector(getPreferences);
const selectedAccount = useSelector(getSelectedAccount);
const currentChainId = useSelector(getCurrentChainId);
const shouldHideZeroBalanceTokens = useSelector(
getShouldHideZeroBalanceTokens,
);
Expand All @@ -63,7 +66,8 @@ export const AggregatedPercentageOverview = () => {
}
// native token
const nativePricePercentChange1d =
tokensMarketData?.[zeroAddress()]?.pricePercentChange1d;
tokensMarketData?.[getNativeTokenAddress(currentChainId)]
?.pricePercentChange1d;
const nativeFiat1dAgo = getCalculatedTokenAmount1dAgo(
item.fiatBalance,
nativePricePercentChange1d,
Expand Down
7 changes: 5 additions & 2 deletions ui/components/app/wallet-overview/coin-overview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ import React, {
} from 'react';
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 { InternalAccount } from '@metamask/keyring-api';
import { getNativeTokenAddress } from '@metamask/assets-controllers';
import {
Box,
ButtonIcon,
Expand Down Expand Up @@ -231,7 +231,10 @@ export const CoinOverview = ({
return (
<Box className="wallet-overview__currency-wrapper">
<PercentageAndAmountChange
value={tokensMarketData?.[zeroAddress()]?.pricePercentChange1d}
value={
tokensMarketData?.[getNativeTokenAddress(chainId as Hex)]
?.pricePercentChange1d
}
/>
{
///: BEGIN:ONLY_INCLUDE_IF(build-main,build-beta,build-flask)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ import React from 'react';
import { render, screen } from '@testing-library/react';
import '@testing-library/jest-dom';
import { zeroAddress } from 'ethereumjs-util';
import { MarketDataDetails } from '@metamask/assets-controllers';
import { getIntlLocale } from '../../../../../ducks/locale/locale';
import {
getCurrentCurrency,
getSelectedAccountCachedBalance,
getTokensMarketData,
getCurrentChainId,
} from '../../../../../selectors';
import {
getConversionRate,
Expand All @@ -26,20 +28,23 @@ jest.mock('../../../../../selectors', () => ({
getCurrentCurrency: jest.fn(),
getSelectedAccountCachedBalance: jest.fn(),
getTokensMarketData: jest.fn(),
getCurrentChainId: jest.fn(),
}));

jest.mock('../../../../../ducks/metamask/metamask', () => ({
getConversionRate: jest.fn(),
getNativeCurrency: jest.fn(),
}));

const mockGetIntlLocale = getIntlLocale as unknown as jest.Mock;
const mockGetCurrentCurrency = getCurrentCurrency as jest.Mock;
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 mockGetIntlLocale = jest.mocked(getIntlLocale);
const mockGetCurrentCurrency = jest.mocked(getCurrentCurrency);
const mockGetSelectedAccountCachedBalance = jest.mocked(
getSelectedAccountCachedBalance,
);
const mockGetConversionRate = jest.mocked(getConversionRate);
const mockGetNativeCurrency = jest.mocked(getNativeCurrency);
const mockGetTokensMarketData = jest.mocked(getTokensMarketData);
const mockGetCurrentChainId = jest.mocked(getCurrentChainId);

describe('PercentageChange Component', () => {
beforeEach(() => {
Expand All @@ -51,9 +56,9 @@ describe('PercentageChange Component', () => {
mockGetTokensMarketData.mockReturnValue({
[zeroAddress()]: {
pricePercentChange1d: 2,
},
} as MarketDataDetails,
});

mockGetCurrentChainId.mockReturnValue('0x1');
jest.clearAllMocks();
});

Expand Down Expand Up @@ -108,4 +113,19 @@ describe('PercentageChange Component', () => {
expect(percentageElement).toBeInTheDocument();
expect(numberElement).toBeInTheDocument();
});

it('should display percentage for non-zero native tokens (MATIC)', () => {
mockGetTokensMarketData.mockReturnValue({
'0x0000000000000000000000000000000000001010': {
pricePercentChange1d: 2,
} as MarketDataDetails,
});
mockGetCurrentCurrency.mockReturnValue('POL');
mockGetCurrentChainId.mockReturnValue('0x89');
render(<PercentageAndAmountChange value={1} />);
const percentageElement = screen.getByText('(+1.00%)');
const numberElement = screen.getByText('+POL 12.21');
expect(percentageElement).toBeInTheDocument();
expect(numberElement).toBeInTheDocument();
});
});
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import React, { useMemo } from 'react';
import { useSelector } from 'react-redux';
import { BigNumber } from 'bignumber.js';
import { isHexString, zeroAddress } from 'ethereumjs-util';
import { isHexString } from 'ethereumjs-util';
import { getNativeTokenAddress } from '@metamask/assets-controllers';
import { Text, Box } from '../../../../component-library';
import {
Display,
TextColor,
TextVariant,
} from '../../../../../helpers/constants/design-system';
import {
getCurrentChainId,
getCurrentCurrency,
getSelectedAccountCachedBalance,
getTokensMarketData,
Expand Down Expand Up @@ -66,10 +68,12 @@ export const PercentageAndAmountChange = ({
const conversionRate = useSelector(getConversionRate);
const nativeCurrency = useSelector(getNativeCurrency);
const marketData = useSelector(getTokensMarketData);
const currentChainId = useSelector(getCurrentChainId);

const balanceChange = useMemo(() => {
// Extracts the 1-day percentage change in price from marketData using the zero address as a key.
const percentage1d = marketData?.[zeroAddress()]?.pricePercentChange1d;
const percentage1d =
marketData?.[getNativeTokenAddress(currentChainId)]?.pricePercentChange1d;

// Checks if the balanceValue is in hex format. This is important for cryptocurrency balances which are often represented in hex.
if (isHexString(balanceValue)) {
Expand Down
10 changes: 6 additions & 4 deletions ui/components/multichain/token-list-item/token-list-item.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import React, { useContext, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { useHistory } from 'react-router-dom';
import classnames from 'classnames';
import { zeroAddress } from 'ethereumjs-util';
import { getNativeTokenAddress } from '@metamask/assets-controllers';
import { Hex } from '@metamask/utils';
import {
AlignItems,
BackgroundColor,
Expand Down Expand Up @@ -336,13 +337,14 @@ export const TokenListItem = ({
<PercentageChange
value={
isNativeCurrency
? multiChainMarketData?.[chainId]?.[zeroAddress()]
?.pricePercentChange1d
? multiChainMarketData?.[chainId]?.[
getNativeTokenAddress(chainId as Hex)
]?.pricePercentChange1d
: tokenPercentageChange
}
address={
isNativeCurrency
? (zeroAddress() as `0x${string}`)
? getNativeTokenAddress(chainId as Hex)
: (address as `0x${string}`)
}
/>
Expand Down
4 changes: 2 additions & 2 deletions ui/pages/asset/components/asset-page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import { useHistory } from 'react-router-dom';
import { useSelector } from 'react-redux';
import { EthMethod } from '@metamask/keyring-api';
import { isEqual } from 'lodash';
import { getNativeTokenAddress } from '@metamask/assets-controllers';
import { Hex } from '@metamask/utils';
import { zeroAddress } from 'ethereumjs-util';
import {
getCurrentCurrency,
getDataCollectionForMarketing,
Expand Down Expand Up @@ -140,7 +140,7 @@ const AssetPage = ({
const address =
type === AssetType.token
? toChecksumHexAddress(asset.address)
: zeroAddress();
: getNativeTokenAddress(chainId);

const balance = calculateTokenBalance({
isNative: type === AssetType.native,
Expand Down
Loading
Loading