From c1a7f46e8f3e90f283e8f374acc27222b510ded6 Mon Sep 17 00:00:00 2001 From: David Walsh Date: Wed, 26 Jul 2023 14:37:33 -0500 Subject: [PATCH] UX: Show Checksum Addresses in Account Menu (#20135) * UX: Show Checksum Addresses in Account Menu * Checksum the account details -> export private key address copy button * Update tests --- .../multichain/account-details/account-details.test.js | 10 ++++++++++ .../__snapshots__/account-list-item.test.js.snap | 2 +- .../multichain/account-list-item/account-list-item.js | 3 ++- .../account-list-item/account-list-item.test.js | 3 ++- .../address-copy-button/address-copy-button.js | 8 ++++++-- .../address-copy-button/address-copy-button.test.js | 6 ++++-- .../multichain/menu-items/view-explorer-menu-item.js | 7 ++++++- ui/components/ui/qr-code/qr-code.js | 2 +- 8 files changed, 32 insertions(+), 9 deletions(-) diff --git a/ui/components/multichain/account-details/account-details.test.js b/ui/components/multichain/account-details/account-details.test.js index 4caed5b0f..78ae27454 100644 --- a/ui/components/multichain/account-details/account-details.test.js +++ b/ui/components/multichain/account-details/account-details.test.js @@ -1,6 +1,7 @@ import React from 'react'; import { screen, fireEvent } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; +import { toChecksumHexAddress } from '@metamask/controller-utils'; import { renderWithProvider } from '../../../../test/jest'; import configureStore from '../../../store/store'; import mockState from '../../../../test/data/mock-state.json'; @@ -10,6 +11,7 @@ import { exportAccount, hideWarning, } from '../../../store/actions'; +import { shortenAddress } from '../../../helpers/utils/util'; import { AccountDetails } from '.'; jest.mock('../../../store/actions.ts'); @@ -58,6 +60,10 @@ describe('AccountDetails', () => { const exportPrivateKeyButton = queryByText(showPrivateKey.message); fireEvent.click(exportPrivateKeyButton); + expect( + queryByText(shortenAddress(toChecksumHexAddress(address))), + ).toBeInTheDocument(); + expect(queryByText('Show private key')).toBeInTheDocument(); expect(queryByPlaceholderText('Password')).toBeInTheDocument(); }); @@ -86,6 +92,10 @@ describe('AccountDetails', () => { const exportPrivateKeyButton = queryByText(showPrivateKey.message); fireEvent.click(exportPrivateKeyButton); + expect( + queryByText(shortenAddress(toChecksumHexAddress(address))), + ).toBeInTheDocument(); + expect(queryByText(samplePrivateKey)).toBeInTheDocument(); }); }); diff --git a/ui/components/multichain/account-list-item/__snapshots__/account-list-item.test.js.snap b/ui/components/multichain/account-list-item/__snapshots__/account-list-item.test.js.snap index a3d8ef3e5..e95f45648 100644 --- a/ui/components/multichain/account-list-item/__snapshots__/account-list-item.test.js.snap +++ b/ui/components/multichain/account-list-item/__snapshots__/account-list-item.test.js.snap @@ -96,7 +96,7 @@ exports[`AccountListItem renders AccountListItem component and shows account nam

- 0x0dc...e7bc + 0x0DC...E7bc

) : null} - {shortenAddress(identity.address)} + {shortenAddress(toChecksumHexAddress(identity.address))} { const { container } = render(); expect(screen.getByText(identity.name)).toBeInTheDocument(); expect( - screen.getByText(shortenAddress(identity.address)), + screen.getByText(shortenAddress(toChecksumHexAddress(identity.address))), ).toBeInTheDocument(); expect(document.querySelector('[title="0.006 ETH"]')).toBeInTheDocument(); diff --git a/ui/components/multichain/address-copy-button/address-copy-button.js b/ui/components/multichain/address-copy-button/address-copy-button.js index a46affac0..7cf312493 100644 --- a/ui/components/multichain/address-copy-button/address-copy-button.js +++ b/ui/components/multichain/address-copy-button/address-copy-button.js @@ -1,6 +1,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import classnames from 'classnames'; +import { toChecksumHexAddress } from '@metamask/controller-utils'; import { ButtonBase, IconName } from '../../component-library'; import { BackgroundColor, @@ -22,7 +23,10 @@ export const AddressCopyButton = ({ wrap = false, onClick, }) => { - const displayAddress = shorten ? shortenAddress(address) : address; + const checksummedAddress = toChecksumHexAddress(address); + const displayAddress = shorten + ? shortenAddress(checksummedAddress) + : checksummedAddress; const [copied, handleCopy] = useCopyToClipboard(MINUTE); const t = useI18nContext(); @@ -31,7 +35,7 @@ export const AddressCopyButton = ({ { - handleCopy(address); + handleCopy(checksummedAddress); onClick?.(); }} paddingRight={4} diff --git a/ui/components/multichain/address-copy-button/address-copy-button.test.js b/ui/components/multichain/address-copy-button/address-copy-button.test.js index a885fe45d..a5f4385e0 100644 --- a/ui/components/multichain/address-copy-button/address-copy-button.test.js +++ b/ui/components/multichain/address-copy-button/address-copy-button.test.js @@ -1,5 +1,7 @@ import React from 'react'; import { fireEvent, render } from '@testing-library/react'; +import { toChecksumHexAddress } from '@metamask/controller-utils'; +import { shortenAddress } from '../../../helpers/utils/util'; import { AddressCopyButton } from '.'; const SAMPLE_ADDRESS = '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc'; @@ -10,7 +12,7 @@ describe('AccountListItem', () => { expect( document.querySelector('[data-testid="address-copy-button-text"]') .textContent, - ).toStrictEqual(SAMPLE_ADDRESS); + ).toStrictEqual(toChecksumHexAddress(SAMPLE_ADDRESS)); }); it('renders a shortened address when it should', () => { @@ -18,7 +20,7 @@ describe('AccountListItem', () => { expect( document.querySelector('[data-testid="address-copy-button-text"]') .textContent, - ).toStrictEqual('0x0dc...e7bc'); + ).toStrictEqual(shortenAddress(toChecksumHexAddress(SAMPLE_ADDRESS))); }); it('changes icon when clicked', () => { diff --git a/ui/components/multichain/menu-items/view-explorer-menu-item.js b/ui/components/multichain/menu-items/view-explorer-menu-item.js index ca99996e8..60baab1a6 100644 --- a/ui/components/multichain/menu-items/view-explorer-menu-item.js +++ b/ui/components/multichain/menu-items/view-explorer-menu-item.js @@ -3,6 +3,7 @@ import PropTypes from 'prop-types'; import { useSelector } from 'react-redux'; import { useHistory } from 'react-router-dom'; +import { toChecksumHexAddress } from '@metamask/controller-utils'; import { getAccountLink } from '@metamask/etherscan-link'; import { MenuItem } from '../../ui/menu'; @@ -34,7 +35,11 @@ export const ViewExplorerMenuItem = ({ const chainId = useSelector(getCurrentChainId); const rpcPrefs = useSelector(getRpcPrefsForCurrentProvider); - const addressLink = getAccountLink(address, chainId, rpcPrefs); + const addressLink = getAccountLink( + toChecksumHexAddress(address), + chainId, + rpcPrefs, + ); const { blockExplorerUrl } = rpcPrefs; const blockExplorerUrlSubTitle = getURLHostName(blockExplorerUrl); diff --git a/ui/components/ui/qr-code/qr-code.js b/ui/components/ui/qr-code/qr-code.js index 0e3b10cea..7a9a7d6be 100644 --- a/ui/components/ui/qr-code/qr-code.js +++ b/ui/components/ui/qr-code/qr-code.js @@ -60,7 +60,7 @@ function QrCodeView({ Qr, warning }) { { trackEvent({ category: MetaMetricsEventCategory.Accounts,