diff --git a/shared/constants/labels.js b/shared/constants/labels.js new file mode 100644 index 000000000..ab03c4eb0 --- /dev/null +++ b/shared/constants/labels.js @@ -0,0 +1,10 @@ +// The character limit on ENS names, nicknames and addresses before we truncate +export const TRUNCATED_NAME_CHAR_LIMIT = 11; + +// The number of characters to slice from the beginning of an address for truncated format: +// `${TRUNCATED_ADDRESS_START_CHARS}...${TRUNCATED_ADDRESS_END_CHARS}` +export const TRUNCATED_ADDRESS_START_CHARS = 5; + +// The number of characters to slice from the end of an address for truncated format: +// `${TRUNCATED_ADDRESS_START_CHARS}...${TRUNCATED_ADDRESS_END_CHARS}` +export const TRUNCATED_ADDRESS_END_CHARS = 4; diff --git a/test/e2e/tests/from-import-ui.spec.js b/test/e2e/tests/from-import-ui.spec.js index a7fba5982..ad97bb257 100644 --- a/test/e2e/tests/from-import-ui.spec.js +++ b/test/e2e/tests/from-import-ui.spec.js @@ -76,8 +76,9 @@ describe('Metamask Import UI', function () { // shows a QR code for the account const detailsModal = await driver.findVisibleElement('span .modal'); // shows the correct account address - const [address] = await driver.findElements('.readonly-input__input'); - assert.equal(await address.getAttribute('value'), testAddress); + const address = await driver.findElement('.qr-code__address'); + + assert.equal(await address.getText(), testAddress); await driver.clickElement('.account-modal__close'); await detailsModal.waitForElementState('hidden'); diff --git a/test/e2e/tests/incremental-security.spec.js b/test/e2e/tests/incremental-security.spec.js index f6e5e5066..e000e9817 100644 --- a/test/e2e/tests/incremental-security.spec.js +++ b/test/e2e/tests/incremental-security.spec.js @@ -80,8 +80,8 @@ describe('Incremental Security', function () { ); // gets the current accounts address - const addressInput = await driver.findElement('.readonly-input__input'); - const publicAddress = await addressInput.getAttribute('value'); + const address = await driver.findElement('.qr-code__address'); + const publicAddress = await address.getText(); // wait for account modal to be visible const accountModal = await driver.findVisibleElement('span .modal'); diff --git a/ui/components/app/modals/account-modal-container/index.scss b/ui/components/app/modals/account-modal-container/index.scss index bfb0c37a8..149a4de96 100644 --- a/ui/components/app/modals/account-modal-container/index.scss +++ b/ui/components/app/modals/account-modal-container/index.scss @@ -31,7 +31,7 @@ @include H1; background-color: transparent; - color: $dusty-gray; + color: $ui-black; position: absolute; cursor: pointer; top: -10px; diff --git a/ui/components/app/permission-page-container/permission-page-container-content/permission-page-container-content.component.js b/ui/components/app/permission-page-container/permission-page-container-content/permission-page-container-content.component.js index 3213e896b..7cacc40c8 100644 --- a/ui/components/app/permission-page-container/permission-page-container-content/permission-page-container-content.component.js +++ b/ui/components/app/permission-page-container/permission-page-container-content/permission-page-container-content.component.js @@ -70,12 +70,6 @@ export default class PermissionPageContainerContent extends PureComponent { ); } - getAccountDescriptor(identity) { - return `${identity.label} (...${identity.address.slice( - identity.address.length - 4, - )})`; - } - renderAccountTooltip(textContent) { const { selectedIdentities } = this.props; const { t } = this.context; @@ -90,7 +84,7 @@ export default class PermissionPageContainerContent extends PureComponent { {selectedIdentities.slice(0, 6).map((identity, index) => { return (
- {this.getAccountDescriptor(identity)} + {identity.addressLabel}
); })} @@ -126,7 +120,7 @@ export default class PermissionPageContainerContent extends PureComponent { ), ]); } - return t('connectTo', [this.getAccountDescriptor(selectedIdentities[0])]); + return t('connectTo', [selectedIdentities[0]?.addressLabel]); } render() { diff --git a/ui/components/app/selected-account/selected-account-component.test.js b/ui/components/app/selected-account/selected-account-component.test.js index d50bd34f2..bc55c7e7e 100644 --- a/ui/components/app/selected-account/selected-account-component.test.js +++ b/ui/components/app/selected-account/selected-account-component.test.js @@ -15,7 +15,7 @@ describe('SelectedAccount Component', () => { ); // Checksummed version of address is displayed expect(wrapper.find('.selected-account__address').text()).toStrictEqual( - '0x1B82...5C9D', + '0x1B8...5C9D', ); expect(wrapper.find('.selected-account__name').text()).toStrictEqual( 'testName', diff --git a/ui/components/ui/qr-code/index.scss b/ui/components/ui/qr-code/index.scss index 521075f64..c228ffeda 100644 --- a/ui/components/ui/qr-code/index.scss +++ b/ui/components/ui/qr-code/index.scss @@ -24,4 +24,11 @@ color: #f7861c; margin-bottom: 9px; } + + &__address { + @include H7; + + background-color: $ui-1; + padding: 12px; + } } diff --git a/ui/components/ui/qr-code/qr-code.js b/ui/components/ui/qr-code/qr-code.js index db0eeed2c..84f40836b 100644 --- a/ui/components/ui/qr-code/qr-code.js +++ b/ui/components/ui/qr-code/qr-code.js @@ -3,7 +3,6 @@ import React from 'react'; import qrCode from 'qrcode-generator'; import { connect } from 'react-redux'; import { isHexPrefixed } from 'ethereumjs-util'; -import ReadOnlyInput from '../readonly-input/readonly-input'; import { toChecksumHexAddress } from '../../../../shared/modules/hexstring-utils'; export default connect(mapStateToProps)(QrCodeView); @@ -47,11 +46,7 @@ function QrCodeView(props) { __html: qrImage.createTableTag(4), }} /> - +
{toChecksumHexAddress(data)}
); } diff --git a/ui/components/ui/sender-to-recipient/index.scss b/ui/components/ui/sender-to-recipient/index.scss index 5c2c3cf5e..edd50cd4a 100644 --- a/ui/components/ui/sender-to-recipient/index.scss +++ b/ui/components/ui/sender-to-recipient/index.scss @@ -178,6 +178,7 @@ overflow: hidden; text-overflow: ellipsis; white-space: nowrap; + margin-inline-start: 8px; [dir='rtl'] & { /*rtl:ignore*/ diff --git a/ui/components/ui/sender-to-recipient/sender-to-recipient.component.js b/ui/components/ui/sender-to-recipient/sender-to-recipient.component.js index 635687053..fe6655cc8 100644 --- a/ui/components/ui/sender-to-recipient/sender-to-recipient.component.js +++ b/ui/components/ui/sender-to-recipient/sender-to-recipient.component.js @@ -55,14 +55,12 @@ function SenderAddress({ } }} > - {!addressOnly && ( -
- -
- )} +
+ +
{addressOnly ? ( - {`${t('from')}: ${senderName || checksummedSenderAddress}`} + {`${t('from')}: ${ + senderName || shortenAddress(checksummedSenderAddress) + }`} ) : ( senderName @@ -132,11 +132,9 @@ function RecipientWithAddress({ } }} > - {!addressOnly && ( -
- -
- )} +
+ +
{addressOnly ? `${t('to')}: ` : ''} {addressOnly - ? recipientNickname || recipientEns || checksummedRecipientAddress + ? recipientNickname || + recipientEns || + shortenAddress(checksummedRecipientAddress) : recipientNickname || recipientEns || recipientName || @@ -225,7 +225,7 @@ export default function SenderToRecipient({ /> ) : (
- {!addressOnly && } +
{t('newContract')}
)} diff --git a/ui/helpers/utils/util.js b/ui/helpers/utils/util.js index 0cd76837e..b20e69559 100644 --- a/ui/helpers/utils/util.js +++ b/ui/helpers/utils/util.js @@ -13,6 +13,11 @@ import { ROPSTEN_CHAIN_ID, } from '../../../shared/constants/network'; import { toChecksumHexAddress } from '../../../shared/modules/hexstring-utils'; +import { + TRUNCATED_ADDRESS_START_CHARS, + TRUNCATED_NAME_CHAR_LIMIT, + TRUNCATED_ADDRESS_END_CHARS, +} from '../../../shared/constants/labels'; // formatData :: ( date: ) -> String export function formatDate(date, format = "M/d/y 'at' T") { @@ -220,11 +225,13 @@ export function exportAsFile(filename, data, type = 'text/csv') { * than 10 characters. */ export function shortenAddress(address = '') { - if (address.length < 11) { + if (address.length < TRUNCATED_NAME_CHAR_LIMIT) { return address; } - return `${address.slice(0, 6)}...${address.slice(-4)}`; + return `${address.slice(0, TRUNCATED_ADDRESS_START_CHARS)}...${address.slice( + -TRUNCATED_ADDRESS_END_CHARS, + )}`; } export function getAccountByAddress(accounts = [], targetAddress) { diff --git a/ui/hooks/useTransactionDisplayData.test.js b/ui/hooks/useTransactionDisplayData.test.js index fad81f0e0..4c35bee3b 100644 --- a/ui/hooks/useTransactionDisplayData.test.js +++ b/ui/hooks/useTransactionDisplayData.test.js @@ -28,7 +28,7 @@ const expectedResults = [ { title: 'Send', category: TRANSACTION_GROUP_CATEGORIES.SEND, - subtitle: 'To: 0xffe5...1a97', + subtitle: 'To: 0xffe...1a97', subtitleContainsOrigin: false, date: 'May 12, 2020', primaryCurrency: '-1 ETH', @@ -42,7 +42,7 @@ const expectedResults = [ { title: 'Send', category: TRANSACTION_GROUP_CATEGORIES.SEND, - subtitle: 'To: 0x0ccc...8848', + subtitle: 'To: 0x0cc...8848', subtitleContainsOrigin: false, date: 'May 12, 2020', primaryCurrency: '-2 ETH', @@ -55,7 +55,7 @@ const expectedResults = [ { title: 'Send', category: TRANSACTION_GROUP_CATEGORIES.SEND, - subtitle: 'To: 0xffe5...1a97', + subtitle: 'To: 0xffe...1a97', subtitleContainsOrigin: false, date: 'May 12, 2020', primaryCurrency: '-2 ETH', @@ -68,7 +68,7 @@ const expectedResults = [ { title: 'Receive', category: TRANSACTION_GROUP_CATEGORIES.RECEIVE, - subtitle: 'From: 0x31b9...4523', + subtitle: 'From: 0x31b...4523', subtitleContainsOrigin: false, date: 'May 12, 2020', primaryCurrency: '18.75 ETH', @@ -81,7 +81,7 @@ const expectedResults = [ { title: 'Receive', category: TRANSACTION_GROUP_CATEGORIES.RECEIVE, - subtitle: 'From: 0x9eca...a149', + subtitle: 'From: 0x9ec...a149', subtitleContainsOrigin: false, date: 'May 8, 2020', primaryCurrency: '0 ETH', @@ -94,7 +94,7 @@ const expectedResults = [ { title: 'Receive', category: TRANSACTION_GROUP_CATEGORIES.RECEIVE, - subtitle: 'From: 0xee01...febb', + subtitle: 'From: 0xee0...febb', subtitleContainsOrigin: false, date: 'May 24, 2020', primaryCurrency: '1 ETH', diff --git a/ui/pages/settings/contact-list-tab/edit-contact/edit-contact.component.js b/ui/pages/settings/contact-list-tab/edit-contact/edit-contact.component.js index 0f64dfa15..ffefd9ea3 100644 --- a/ui/pages/settings/contact-list-tab/edit-contact/edit-contact.component.js +++ b/ui/pages/settings/contact-list-tab/edit-contact/edit-contact.component.js @@ -105,7 +105,14 @@ export default class EditContact extends PureComponent { error={this.state.error} onChange={(e) => this.setState({ newAddress: e.target.value })} fullWidth + multiline + rows={3} margin="dense" + classes={{ + inputMultiline: + 'address-book__view-contact__address__text-area', + inputRoot: 'address-book__view-contact__address', + }} /> diff --git a/ui/pages/settings/contact-list-tab/index.scss b/ui/pages/settings/contact-list-tab/index.scss index 8f00641b6..085a85a3f 100644 --- a/ui/pages/settings/contact-list-tab/index.scss +++ b/ui/pages/settings/contact-list-tab/index.scss @@ -112,6 +112,14 @@ line-height: initial !important; } + &__address { + height: 60px !important; + + textarea { + padding-top: 10px !important; + } + } + &__group { display: flex; flex-flow: column nowrap; diff --git a/ui/selectors/selectors.js b/ui/selectors/selectors.js index 434a4275f..226287024 100644 --- a/ui/selectors/selectors.js +++ b/ui/selectors/selectors.js @@ -15,6 +15,8 @@ import { ALLOWED_SWAPS_CHAIN_IDS, } from '../../shared/constants/swaps'; +import { TRUNCATED_NAME_CHAR_LIMIT } from '../../shared/constants/labels'; + import { shortenAddress, getAccountByAddress, @@ -321,7 +323,11 @@ export function getAccountsWithLabels(state) { return getMetaMaskAccountsOrdered(state).map( ({ address, name, balance }) => ({ address, - addressLabel: `${name} (...${address.slice(address.length - 4)})`, + addressLabel: `${ + name.length < TRUNCATED_NAME_CHAR_LIMIT + ? name + : `${name.slice(0, TRUNCATED_NAME_CHAR_LIMIT - 1)}...` + } (${shortenAddress(address)})`, label: name, balance, }),